ipvs: IPv6 fragment handling for IPVS
Subsystems (5)
v4 cover ipvs: IPv6 fragment handling for IPVS
The following patchset implement IPv6 fragment handling for IPVS.
This work is based upon patches from Hans Schillstrom. I have taken over the patchset, in close agreement with Hans, because he don't have (gotten allocated) time to complete his work.
I have cleaned up the patchset significantly, and split the patchset up into seven patches.
The first 3 patches, are ready to be merged
Patch01: Trivial changes, use compressed IPv6 address in output
Patch02: IPv6 extend ICMPv6 handling for future types
Patch03: Use config macro IS_ENABLED()
The next 4 patches, is V4 of the patches I have submitted earlier. Where I have incorporated Julian's recent feedback.
- Notice that patch04 of patchset V3, have been dropped.
I have also tried to make the patches easier to review, by reorganizing the changes, to be more strictly split (exthdr vs. fragment handling).
I have also removed the API changes, and moved those to patch06. This is done, (1) to make it easier to review the patches, and (2) to allow easier integration of Patricks idea and my RFC patch of caching exthdr info in skb->cb[]. Thus, we can get these patches applied (and later go back and apply the caching scheme easier).
Patch04: Fix faulty IPv6 extension header handling in IPVS
Patch05: Complete IPv6 fragment handling for IPVS
Patch06: IPVS API change to avoid rescan of IPv6 exthdr
Patch07: IPVS SIP fragment handling
The SIP frag handling have been split into its own patch, as I have not been able to test this part my self.
This patchset is based upon:
Pablo's nf-next tree: git://1984.lsi.us.es/nf-next
On top of:
commit 2cbc78a29e76a2e92c172651204f3117491877d2 (netfilter: combine ipt_REDIRECT and ip6t_REDIRECT)
---
Jesper Dangaard Brouer (7):
ipvs: SIP fragment handling
ipvs: API change to avoid rescan of IPv6 exthdr
ipvs: Complete IPv6 fragment handling for IPVS
ipvs: Fix faulty IPv6 extension header handling in IPVS
ipvs: Use config macro IS_ENABLED()
ipvs: IPv6 extend ICMPv6 handling for future types
ipvs: Trivial changes, use compressed IPv6 address in output
include/net/ip_vs.h | 194 +++++++++++---- net/netfilter/ipvs/Kconfig | 7 - net/netfilter/ipvs/ip_vs_conn.c | 15 - net/netfilter/ipvs/ip_vs_core.c | 404 +++++++++++++++++-------------- net/netfilter/ipvs/ip_vs_dh.c | 2 net/netfilter/ipvs/ip_vs_lblc.c | 2 net/netfilter/ipvs/ip_vs_lblcr.c | 2 net/netfilter/ipvs/ip_vs_pe_sip.c | 21 +- net/netfilter/ipvs/ip_vs_proto.c | 6 net/netfilter/ipvs/ip_vs_proto_ah_esp.c | 9 - net/netfilter/ipvs/ip_vs_proto_sctp.c | 42 +-- net/netfilter/ipvs/ip_vs_proto_tcp.c | 40 +-- net/netfilter/ipvs/ip_vs_proto_udp.c | 41 +-- net/netfilter/ipvs/ip_vs_sched.c | 2 net/netfilter/ipvs/ip_vs_sh.c | 2 net/netfilter/ipvs/ip_vs_xmit.c | 73 +++--- net/netfilter/xt_ipvs.c | 4 17 files changed, 504 insertions(+), 362 deletions(-)
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
PATCH v4 1/7 ipvs: Trivial changes, use compressed IPv6 address in output
Have not converted the proc file output to compressed IPv6 addresses.
---
include/net/ip_vs.h | 2 +- net/netfilter/ipvs/ip_vs_core.c | 2 +- net/netfilter/ipvs/ip_vs_proto.c | 6 +++--- net/netfilter/ipvs/ip_vs_sched.c | 2 +- net/netfilter/ipvs/ip_vs_xmit.c | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-)
include/net/ip_vs.h +1 -1
@@ -165,7 +165,7 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,int len;#ifdef CONFIG_IP_VS_IPV6 if (af ==AF_INET6 ) - len =snprintf (&buf[*idx], buf_len - *idx,"[%pI6]" , + len =snprintf (&buf[*idx], buf_len - *idx,"[%pI6c]" , &addr->in6) +1 ; else#endif
net/netfilter/ipvs/ip_vs_core.c +1 -1
@@ -1487,7 +1487,7 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)if (ic ==NULL )return NF_DROP ; -IP_VS_DBG (12 ,"Incoming ICMPv6 (%d,%d) %pI6->%pI6\n" , +IP_VS_DBG (12 ,"Incoming ICMPv6 (%d,%d) %pI6c->%pI6c\n" , ic->icmp6_type,ntohs (icmpv6_id (ic)), &iph->saddr, &iph->daddr);
net/netfilter/ipvs/ip_vs_proto.c +3 -3
@@ -280,17 +280,17 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,if (ih ==NULL )sprintf (buf,"TRUNCATED" );else if (ih->nexthdr ==IPPROTO_FRAGMENT ) -sprintf (buf,"%pI6->%pI6 frag" , &ih->saddr, &ih->daddr); +sprintf (buf,"%pI6c->%pI6c frag" , &ih->saddr, &ih->daddr);else {__be16 _ports[2 ], *pptr; pptr =skb_header_pointer (skb, offset +sizeof (struct ipv6hdr ),sizeof (_ports), _ports);if (pptr ==NULL ) -sprintf (buf,"TRUNCATED %pI6->%pI6" , +sprintf (buf,"TRUNCATED %pI6c->%pI6c" , &ih->saddr, &ih->daddr);else -sprintf (buf,"%pI6:%u->%pI6:%u" , +sprintf (buf,"%pI6c:%u->%pI6c:%u" , &ih->saddr,ntohs (pptr[0 ]), &ih->daddr,ntohs (pptr[1 ])); }
net/netfilter/ipvs/ip_vs_sched.c +1 -1
@@ -159,7 +159,7 @@ void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg) svc->fwmark, msg); #ifdef CONFIG_IP_VS_IPV6 }else if (svc->af ==AF_INET6 ) { -IP_VS_ERR_RL ("%s: %s [%pI6]:%d - %s\n" , +IP_VS_ERR_RL ("%s: %s [%pI6c]:%d - %s\n" , svc->scheduler->name,ip_vs_proto_name (svc->protocol), &svc->addr.in6,ntohs (svc->port), msg);
net/netfilter/ipvs/ip_vs_xmit.c +5 -5
@@ -335,7 +335,7 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, local =__ip_vs_is_local_route6 (rt);if (!((local ?IP_VS_RT_MODE_LOCAL :IP_VS_RT_MODE_NON_LOCAL ) & rt_mode)) { -IP_VS_DBG_RL ("Stopping traffic to %s address, dest: %pI6\n" , +IP_VS_DBG_RL ("Stopping traffic to %s address, dest: %pI6c\n" , local ?"local" :"non-local" , daddr);dst_release (&rt->dst);return NULL ;
@@ -343,8 +343,8 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,if (local && !(rt_mode &IP_VS_RT_MODE_RDR ) && !((ort = (struct rt6_info *)skb_dst (skb)) &&__ip_vs_is_local_route6 (ort))) { -IP_VS_DBG_RL ("Redirect from non-local address %pI6 to local " -"requires NAT method, dest: %pI6\n" , +IP_VS_DBG_RL ("Redirect from non-local address %pI6c to local " +"requires NAT method, dest: %pI6c\n" , &ipv6_hdr (skb)->daddr, daddr);dst_release (&rt->dst);return NULL ;
@@ -352,8 +352,8 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,if (unlikely (!local && (!skb->dev || skb->dev->flags &IFF_LOOPBACK ) &&ipv6_addr_type (&ipv6_hdr (skb)->saddr) &IPV6_ADDR_LOOPBACK )) { -IP_VS_DBG_RL ("Stopping traffic from loopback address %pI6 " -"to non-local address, dest: %pI6\n" , +IP_VS_DBG_RL ("Stopping traffic from loopback address %pI6c " +"to non-local address, dest: %pI6c\n" , &ipv6_hdr (skb)->saddr, daddr);dst_release (&rt->dst);return NULL ;
PATCH v4 2/7 ipvs: IPv6 extend ICMPv6 handling for future types
In reply to Jesper Dangaard BrouerExtend handling of ICMPv6, to all none Informational Messages (via ICMPV6_INFOMSG_MASK). This actually only extend our handling to type ICMPV6_PARAMPROB (Parameter Problem), and future types.
---
This change have been pulled out the frag handling patch as it was not related to IPv6 frag handling.
net/netfilter/ipvs/ip_vs_core.c | 8 ++------ 1 files changed, 2 insertions(+), 6 deletions(-)
net/netfilter/ipvs/ip_vs_core.c +2 -6
@@ -950,9 +950,7 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related,* this means that some packets will manage to get a long way * down this stack and then be rejected, but that's life. */ -if ((ic->icmp6_type !=ICMPV6_DEST_UNREACH ) && - (ic->icmp6_type !=ICMPV6_PKT_TOOBIG ) && - (ic->icmp6_type !=ICMPV6_TIME_EXCEED )) { +if (ic->icmp6_type &ICMPV6_INFOMSG_MASK ) { *related =0 ;return NF_ACCEPT ; }
@@ -1498,9 +1496,7 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)* this means that some packets will manage to get a long way * down this stack and then be rejected, but that's life. */ -if ((ic->icmp6_type !=ICMPV6_DEST_UNREACH ) && - (ic->icmp6_type !=ICMPV6_PKT_TOOBIG ) && - (ic->icmp6_type !=ICMPV6_TIME_EXCEED )) { +if (ic->icmp6_type &ICMPV6_INFOMSG_MASK ) { *related =0 ;return NF_ACCEPT ; }
PATCH v4 3/7 ipvs: Use config macro IS_ENABLED()
In reply to Jesper Dangaard BrouerCleanup patch.
Use the IS_ENABLED macro, instead of having to check both the build and the module CONFIG_ option.
---
include/net/ip_vs.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
include/net/ip_vs.h +1 -1
@@ -22,7 +22,7 @@#include <linux/ip.h> #include <linux/ipv6.h> /* for struct ipv6hdr */ #include <net/ipv6.h> -#if defined(CONFIG_NF_CONNTRACK ) || defined(CONFIG_NF_CONNTRACK_MODULE ) +#if IS_ENABLED (CONFIG_NF_CONNTRACK )#include <net/netfilter/nf_conntrack.h> #endif #include <net/net_namespace.h> /* Netw namespace */
PATCH v4 4/7 ipvs: Fix faulty IPv6 extension header handling in IPVS
In reply to Jesper Dangaard BrouerIPv6 packets can contain extension headers, thus its wrong to assume that the transport/upper-layer header, starts right after (struct ipv6hdr) the IPv6 header. IPVS uses this false assumption, and will write SNAT & DNAT modifications at a fixed pos which will corrupt the message.
To fix this, proper header position must be found before modifying packets. Introducing ip_vs_fill_iph_skb(), which uses ipv6_find_hdr() to skip the exthdrs. It finds (1) the transport header offset, (2) the protocol, and (3) detects if the packet is a fragment.
Note, that fragments in IPv6 is represented via an exthdr. Thus, this is detected while skipping through the exthdrs.
This patch depends on commit 84018f55a:
"netfilter: ip6_tables: add flags parameter to ipv6_find_hdr()"
This also adds a dependency to ip6_tables.
Originally based on patch from: Hans Schillstrom
kABI notes:
Changing struct ip_vs_iphdr is a potential minor kABI breaker, because external modules can be compiled with another version of this struct. This should not matter, as they would most-likely be using a compiled-in version of ip_vs_fill_iphdr(). When recompiled, they will notice ip_vs_fill_iphdr() no longer exists, and they have to used ip_vs_fill_iph_skb() instead.
---
V4:
- Cleanup ip_vs_out_icmp_v6() e.g. avoid double/reuse of variable ipvsh
- Remove the skb_make_writable call in ip_vs_nat_icmp_v6()
- Fix ip_vs_in_icmp_v6() writable offset assignment
- Safer pkt skip, if ICMPv6 contained IPv6 packet is not parsable
V3:
- No big API changes (these are postpone to later patch)
- Make ip_vs_in_icmp_v6() easier to review, avoid spliting related changes across patches.
- Fix port write offset bug in ip_vs_in_icmp_v6()
- Move ip_vs_pe_sip.c changes to a seperate patch.
V2:
- Use macro IS_ENABLED(CONFIG_XXX)
- Re-add NULL pointer check in ip_vs_out_icmp_v6()
include/net/ip_vs.h | 72 ++++++++++- net/netfilter/ipvs/Kconfig | 1 net/netfilter/ipvs/ip_vs_core.c | 211 ++++++++++++++++----------------- net/netfilter/ipvs/ip_vs_dh.c | 2 net/netfilter/ipvs/ip_vs_lblc.c | 2 net/netfilter/ipvs/ip_vs_lblcr.c | 2 net/netfilter/ipvs/ip_vs_pe_sip.c | 2 net/netfilter/ipvs/ip_vs_proto_sctp.c | 22 ++- net/netfilter/ipvs/ip_vs_proto_tcp.c | 22 ++- net/netfilter/ipvs/ip_vs_proto_udp.c | 22 ++- net/netfilter/ipvs/ip_vs_sh.c | 2 net/netfilter/ipvs/ip_vs_xmit.c | 5 - net/netfilter/xt_ipvs.c | 2 13 files changed, 214 insertions(+), 153 deletions(-)
include/net/ip_vs.h +62 -10
@@ -22,6 +22,9 @@#include <linux/ip.h> #include <linux/ipv6.h> /* for struct ipv6hdr */ #include <net/ipv6.h> +#if IS_ENABLED (CONFIG_IPV6 ) +#include <linux/netfilter_ipv6/ip6_tables.h> +#endif #if IS_ENABLED (CONFIG_NF_CONNTRACK )#include <net/netfilter/nf_conntrack.h> #endif
@@ -103,30 +106,79 @@ static inline struct net *seq_file_single_net(struct seq_file *seq)/* Connections' size value needed by ip_vs_ctl.c */ extern int ip_vs_conn_tab_size; -struct ip_vs_iphdr { -int len; -__u8 protocol; +__u32 len;/* IPv4 simply where L4 starts +IPv6 where L4 Transport Header starts */ +__u16 fragoffs;/* IPv6 fragment offset, 0 if first frag (or not frag)*/ +__s16 protocol; +__s32 flags;union nf_inet_addr saddr;union nf_inet_addr daddr; };static inline void -ip_vs_fill_iphdr (int af,const void *nh,struct ip_vs_iphdr *iphdr) +ip_vs_fill_ip4hdr (const void *nh,struct ip_vs_iphdr *iphdr) +{ +const struct iphdr *iph = nh; + + iphdr->len = iph->ihl *4 ; + iphdr->fragoffs =0 ; + iphdr->protocol = iph->protocol; + iphdr->saddr.ip = iph->saddr; + iphdr->daddr.ip = iph->daddr; +} + +/* This function handles filling *ip_vs_iphdr, both for IPv4 and IPv6. +* IPv6 requires some extra work, as finding proper header position, +* depend on the IPv6 extension headers. +*/ +static inline void +ip_vs_fill_iph_skb (int af,const struct sk_buff *skb,struct ip_vs_iphdr *iphdr) {#ifdef CONFIG_IP_VS_IPV6 if (af ==AF_INET6 ) { -const struct ipv6hdr *iph = nh; - iphdr->len =sizeof (struct ipv6hdr ); - iphdr->protocol = iph->nexthdr; +const struct ipv6hdr *iph = + (struct ipv6hdr *)skb_network_header (skb); iphdr->saddr.in6 = iph->saddr; iphdr->daddr.in6 = iph->daddr; +/* ipv6_find_hdr() updates len, flags */ + iphdr->len =0 ; + iphdr->flags =0 ; + iphdr->protocol =ipv6_find_hdr (skb, &iphdr->len,-1 , + &iphdr->fragoffs, + &iphdr->flags); } else#endif { -const struct iphdr *iph = nh; - iphdr->len = iph->ihl *4 ; - iphdr->protocol = iph->protocol; +const struct iphdr *iph = + (struct iphdr *)skb_network_header (skb); + iphdr->len = iph->ihl *4 ; + iphdr->fragoffs =0 ; + iphdr->protocol = iph->protocol; + iphdr->saddr.ip = iph->saddr; + iphdr->daddr.ip = iph->daddr; + } +} + +/* This function is a faster version of ip_vs_fill_iph_skb(). +* Where we only populate {s,d}addr (and avoid calling ipv6_find_hdr()). +* This is used by the some of the ip_vs_*_schedule() functions. +* (Mostly done to avoid ABI breakage of external schedulers) +*/ +static inline void +ip_vs_fill_iph_addr_only (int af,const struct sk_buff *skb, +struct ip_vs_iphdr *iphdr) +{ +#ifdef CONFIG_IP_VS_IPV6 +if (af ==AF_INET6 ) { +const struct ipv6hdr *iph = + (struct ipv6hdr *)skb_network_header (skb); + iphdr->saddr.in6 = iph->saddr; + iphdr->daddr.in6 = iph->daddr; + }else { +#endif +const struct iphdr *iph = + (struct iphdr *)skb_network_header (skb); iphdr->saddr.ip = iph->saddr; iphdr->daddr.ip = iph->daddr; }
net/netfilter/ipvs/Kconfig +1 -0
@@ -28,6 +28,7 @@ if IP_VS config IP_VS_IPV6 bool "IPv6 support for IPVS" depends on IPV6 = y || IP_VS = IPV6 + select IP6_NF_IPTABLES ---help--- Add IPv6 support to IPVS. This is incomplete and might be dangerous.
net/netfilter/ipvs/ip_vs_core.c +103 -108
401 lines not on this page · raw message
net/netfilter/ipvs/ip_vs_dh.c +1 -1
@@ -215,7 +215,7 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)struct ip_vs_dh_bucket *tbl;struct ip_vs_iphdr iph; -ip_vs_fill_iphdr (svc->af,skb_network_header (skb), &iph); +ip_vs_fill_iph_addr_only (svc->af, skb, &iph);IP_VS_DBG (6 ,"%s(): Scheduling...\n" , __func__);
net/netfilter/ipvs/ip_vs_lblc.c +1 -1
@@ -479,7 +479,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)struct ip_vs_dest *dest =NULL ;struct ip_vs_lblc_entry *en; -ip_vs_fill_iphdr (svc->af,skb_network_header (skb), &iph); +ip_vs_fill_iph_addr_only (svc->af, skb, &iph);IP_VS_DBG (6 ,"%s(): Scheduling...\n" , __func__);
net/netfilter/ipvs/ip_vs_lblcr.c +1 -1
@@ -649,7 +649,7 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)struct ip_vs_dest *dest =NULL ;struct ip_vs_lblcr_entry *en; -ip_vs_fill_iphdr (svc->af,skb_network_header (skb), &iph); +ip_vs_fill_iph_addr_only (svc->af, skb, &iph);IP_VS_DBG (6 ,"%s(): Scheduling...\n" , __func__);
net/netfilter/ipvs/ip_vs_pe_sip.c +1 -1
@@ -73,7 +73,7 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)const char *dptr;int retc; -ip_vs_fill_iphdr (p->af,skb_network_header (skb), &iph); +ip_vs_fill_iph_skb (p->af, skb, &iph);/* Only useful with UDP */ if (iph.protocol !=IPPROTO_UDP )
net/netfilter/ipvs/ip_vs_proto_sctp.c +13 -9
@@ -18,7 +18,7 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,sctp_sctphdr_t *sh, _sctph;struct ip_vs_iphdr iph; -ip_vs_fill_iphdr (af,skb_network_header (skb), &iph); +ip_vs_fill_iph_skb (af, skb, &iph); sh =skb_header_pointer (skb, iph.len,sizeof (_sctph), &_sctph);if (sh ==NULL )
@@ -72,12 +72,14 @@ sctp_snat_handler(struct sk_buff *skb,struct sk_buff *iter;__be32 crc32; +struct ip_vs_iphdr iph; +ip_vs_fill_iph_skb (cp->af, skb, &iph); + sctphoff = iph.len; +#ifdef CONFIG_IP_VS_IPV6 -if (cp->af ==AF_INET6 ) - sctphoff =sizeof (struct ipv6hdr ); - else +if (cp->af ==AF_INET6 && iph.fragoffs) +return 1 ;#endif - sctphoff =ip_hdrlen (skb);/* csum_check requires unshared skb */ if (!skb_make_writable (skb, sctphoff +sizeof (*sctph)))
@@ -116,12 +118,14 @@ sctp_dnat_handler(struct sk_buff *skb,struct sk_buff *iter;__be32 crc32; +struct ip_vs_iphdr iph; +ip_vs_fill_iph_skb (cp->af, skb, &iph); + sctphoff = iph.len; +#ifdef CONFIG_IP_VS_IPV6 -if (cp->af ==AF_INET6 ) - sctphoff =sizeof (struct ipv6hdr ); - else +if (cp->af ==AF_INET6 && iph.fragoffs) +return 1 ;#endif - sctphoff =ip_hdrlen (skb);/* csum_check requires unshared skb */ if (!skb_make_writable (skb, sctphoff +sizeof (*sctph)))
net/netfilter/ipvs/ip_vs_proto_tcp.c +13 -9
@@ -40,7 +40,7 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,struct tcphdr _tcph, *th;struct ip_vs_iphdr iph; -ip_vs_fill_iphdr (af,skb_network_header (skb), &iph); +ip_vs_fill_iph_skb (af, skb, &iph); th =skb_header_pointer (skb, iph.len,sizeof (_tcph), &_tcph);if (th ==NULL ) {
@@ -136,12 +136,14 @@ tcp_snat_handler(struct sk_buff *skb,int oldlen;int payload_csum =0 ; +struct ip_vs_iphdr iph; +ip_vs_fill_iph_skb (cp->af, skb, &iph); + tcphoff = iph.len; +#ifdef CONFIG_IP_VS_IPV6 -if (cp->af ==AF_INET6 ) - tcphoff =sizeof (struct ipv6hdr ); - else +if (cp->af ==AF_INET6 && iph.fragoffs) +return 1 ;#endif - tcphoff =ip_hdrlen (skb); oldlen = skb->len - tcphoff;/* csum_check requires unshared skb */
@@ -216,12 +218,14 @@ tcp_dnat_handler(struct sk_buff *skb,int oldlen;int payload_csum =0 ; +struct ip_vs_iphdr iph; +ip_vs_fill_iph_skb (cp->af, skb, &iph); + tcphoff = iph.len; +#ifdef CONFIG_IP_VS_IPV6 -if (cp->af ==AF_INET6 ) - tcphoff =sizeof (struct ipv6hdr ); - else +if (cp->af ==AF_INET6 && iph.fragoffs) +return 1 ;#endif - tcphoff =ip_hdrlen (skb); oldlen = skb->len - tcphoff;/* csum_check requires unshared skb */
net/netfilter/ipvs/ip_vs_proto_udp.c +13 -9
@@ -37,7 +37,7 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,struct udphdr _udph, *uh;struct ip_vs_iphdr iph; -ip_vs_fill_iphdr (af,skb_network_header (skb), &iph); +ip_vs_fill_iph_skb (af, skb, &iph); uh =skb_header_pointer (skb, iph.len,sizeof (_udph), &_udph);if (uh ==NULL ) {
@@ -133,12 +133,14 @@ udp_snat_handler(struct sk_buff *skb,int oldlen;int payload_csum =0 ; +struct ip_vs_iphdr iph; +ip_vs_fill_iph_skb (cp->af, skb, &iph); + udphoff = iph.len; +#ifdef CONFIG_IP_VS_IPV6 -if (cp->af ==AF_INET6 ) - udphoff =sizeof (struct ipv6hdr ); - else +if (cp->af ==AF_INET6 && iph.fragoffs) +return 1 ;#endif - udphoff =ip_hdrlen (skb); oldlen = skb->len - udphoff;/* csum_check requires unshared skb */
@@ -218,12 +220,14 @@ udp_dnat_handler(struct sk_buff *skb,int oldlen;int payload_csum =0 ; +struct ip_vs_iphdr iph; +ip_vs_fill_iph_skb (cp->af, skb, &iph); + udphoff = iph.len; +#ifdef CONFIG_IP_VS_IPV6 -if (cp->af ==AF_INET6 ) - udphoff =sizeof (struct ipv6hdr ); - else +if (cp->af ==AF_INET6 && iph.fragoffs) +return 1 ;#endif - udphoff =ip_hdrlen (skb); oldlen = skb->len - udphoff;/* csum_check requires unshared skb */
net/netfilter/ipvs/ip_vs_sh.c +1 -1
@@ -228,7 +228,7 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)struct ip_vs_sh_bucket *tbl;struct ip_vs_iphdr iph; -ip_vs_fill_iphdr (svc->af,skb_network_header (skb), &iph); +ip_vs_fill_iph_addr_only (svc->af, skb, &iph);IP_VS_DBG (6 ,"ip_vs_sh_schedule(): Scheduling...\n" );
net/netfilter/ipvs/ip_vs_xmit.c +3 -2
@@ -679,14 +679,15 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,struct rt6_info *rt;/* Route to the other host */ int mtu;int local; +struct ip_vs_iphdr iph;EnterFunction (10 ); +ip_vs_fill_iph_skb (cp->af, skb, &iph);/* check if it is a connection of no-client-port */ if (unlikely (cp->flags &IP_VS_CONN_F_NO_CPORT )) {__be16 _pt, *p; - p =skb_header_pointer (skb,sizeof (struct ipv6hdr ), -sizeof (_pt), &_pt); + p =skb_header_pointer (skb, iph.len,sizeof (_pt), &_pt);if (p ==NULL ) goto tx_error;ip_vs_conn_fill_cport (cp, *p);
net/netfilter/xt_ipvs.c +1 -1
@@ -67,7 +67,7 @@ ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par) goto out; } -ip_vs_fill_iphdr (family,skb_network_header (skb), &iph); +ip_vs_fill_iph_skb (family, skb, &iph);if (data->bitmask &XT_IPVS_PROTO ) if ((iph.protocol == data->l4proto) ^
PATCH v4 5/7 ipvs: Complete IPv6 fragment handling for IPVS
In reply to Jesper Dangaard BrouerIPVS now supports fragmented packets, with support from nf_conntrack_reasm.c
Based on patch from: Hans Schillstrom.
IPVS do like conntrack i.e. use the skb->nfct_reasm (i.e. when all fragments is collected, nf_ct_frag6_output() starts a "re-play" of all fragments into the interrupted PREROUTING chain at prio -399 (NF_IP6_PRI_CONNTRACK_DEFRAG+1) with nfct_reasm pointing to the assembled packet.)
Notice, module nf_defrag_ipv6 must be loaded for this to work. Report unhandled fragments, and recommend user to load nf_defrag_ipv6.
To handle fw-mark for fragments. Add a new IPVS hook into prerouting chain at prio -99 (NF_IP6_PRI_NAT_DST+1) to catch fragments, and copy fw-mark info from the first packet with an upper layer header.
IPv6 fragment handling should be the last thing on the IPVS IPv6 missing support list.
---
V4:
- Fix style problem: do not use assignment in if condition
V3:
- In case of no nf_defrag_ipv6, second fragments could create strange conn entries, fix that.
- Report unhandled fragments, and recommend user to load nf_defrag_ipv6.
- Move ICMPv6 improvements to seperate patch
V2:
- In ip_vs_in_icmp_v6() hint that &ciph.len can be updated
- Add NULL pointer check in ip_vs_in_icmp_v6()
V1:
- Fixed refcnt bug since last.
include/net/ip_vs.h | 39 +++++++++++++ net/netfilter/ipvs/Kconfig | 6 +- net/netfilter/ipvs/ip_vs_conn.c | 2 - net/netfilter/ipvs/ip_vs_core.c | 117 ++++++++++++++++++++++++++++++++------- net/netfilter/ipvs/ip_vs_xmit.c | 36 +++++++++--- 5 files changed, 164 insertions(+), 36 deletions(-)
include/net/ip_vs.h +38 -1
@@ -109,6 +109,7 @@ extern int ip_vs_conn_tab_size;struct ip_vs_iphdr {__u32 len;/* IPv4 simply where L4 starts IPv6 where L4 Transport Header starts */ +__u32 thoff_reasm;/* Transport Header Offset in nfct_reasm skb */ __u16 fragoffs;/* IPv6 fragment offset, 0 if first frag (or not frag)*/ __s16 protocol;__s32 flags;
@@ -116,6 +117,35 @@ struct ip_vs_iphdr {union nf_inet_addr daddr; }; +/* Dependency to module: nf_defrag_ipv6 */ +#if defined(CONFIG_NF_DEFRAG_IPV6 ) || defined(CONFIG_NF_DEFRAG_IPV6_MODULE ) +static inline struct sk_buff *skb_nfct_reasm (const struct sk_buff *skb) +{ +return skb->nfct_reasm; +} +static inline void *frag_safe_skb_hp (const struct sk_buff *skb,int offset, +int len,void *buffer, +const struct ip_vs_iphdr *ipvsh) +{ +if (unlikely (ipvsh->fragoffs &&skb_nfct_reasm (skb))) +return skb_header_pointer (skb_nfct_reasm (skb), + ipvsh->thoff_reasm, len, buffer); + +return skb_header_pointer (skb, offset, len, buffer); +} +#else +static inline struct sk_buff *skb_nfct_reasm (const struct sk_buff *skb) +{ +return NULL ; +} +static inline void *frag_safe_skb_hp (const struct sk_buff *skb,int offset, +int len,void *buffer, +const struct ip_vs_iphdr *ipvsh) +{ +return skb_header_pointer (skb, offset, len, buffer); +} +#endif +static inline void ip_vs_fill_ip4hdr (const void *nh,struct ip_vs_iphdr *iphdr) {
@@ -141,12 +171,19 @@ ip_vs_fill_iph_skb(int af, const struct sk_buff *skb, struct ip_vs_iphdr *iphdr) (struct ipv6hdr *)skb_network_header (skb); iphdr->saddr.in6 = iph->saddr; iphdr->daddr.in6 = iph->daddr; -/* ipv6_find_hdr() updates len, flags */ +/* ipv6_find_hdr() updates len, flags, thoff_reasm */ + iphdr->thoff_reasm =0 ; iphdr->len =0 ; iphdr->flags =0 ; iphdr->protocol =ipv6_find_hdr (skb, &iphdr->len,-1 , &iphdr->fragoffs, &iphdr->flags); +/* get proto from re-assembled packet and it's offset */ +if (skb_nfct_reasm (skb)) + iphdr->protocol =ipv6_find_hdr (skb_nfct_reasm (skb), + &iphdr->thoff_reasm, +-1 ,NULL ,NULL ); + } else#endif {
net/netfilter/ipvs/Kconfig +2 -4
@@ -30,11 +30,9 @@ config IP_VS_IPV6 depends on IPV6 = y || IP_VS = IPV6 select IP6_NF_IPTABLES ---help--- - Add IPv6 support to IPVS. This is incomplete and might be dangerous. + Add IPv6 support to IPVS. - See http://www.mindbasket.com/ipvs for more information. - - Say N if unsure. + Say Y if unsure. config IP_VS_DEBUG bool "IP virtual server debugging"
net/netfilter/ipvs/ip_vs_conn.c +1 -1
@@ -314,7 +314,7 @@ ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,__be16 _ports[2 ], *pptr;struct net *net =skb_net (skb); - pptr =skb_header_pointer (skb, proto_off,sizeof (_ports), _ports); + pptr =frag_safe_skb_hp (skb, proto_off,sizeof (_ports), _ports, iph);if (pptr ==NULL )return 1 ;
net/netfilter/ipvs/ip_vs_core.c +96 -21
228 lines not on this page · raw message
net/netfilter/ipvs/ip_vs_xmit.c +27 -9
@@ -496,13 +496,15 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp) {struct rt6_info *rt;/* Route to the other host */ -struct ipv6hdr *iph =ipv6_hdr (skb); +struct ip_vs_iphdr iph;int mtu;EnterFunction (10 ); +ip_vs_fill_iph_skb (cp->af, skb, &iph); -if (!(rt =__ip_vs_get_out_rt_v6 (skb,NULL , &iph->daddr,NULL ,0 , -IP_VS_RT_MODE_NON_LOCAL ))) + rt =__ip_vs_get_out_rt_v6 (skb,NULL , &iph.daddr.in6,NULL ,0 , +IP_VS_RT_MODE_NON_LOCAL ); +if (!rt) goto tx_error_icmp;/* MTU checking */
@@ -513,7 +515,9 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, skb->dev = net->loopback_dev; } -icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu); +/* only send ICMP too big on first fragment */ +if (!iph.fragoffs) +icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu);dst_release (&rt->dst);IP_VS_DBG_RL ("%s(): frag needed\n" , __func__); goto tx_error;
@@ -685,7 +689,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,ip_vs_fill_iph_skb (cp->af, skb, &iph);/* check if it is a connection of no-client-port */ -if (unlikely (cp->flags &IP_VS_CONN_F_NO_CPORT )) { +if (unlikely (cp->flags &IP_VS_CONN_F_NO_CPORT && !iph.fragoffs)) {__be16 _pt, *p; p =skb_header_pointer (skb, iph.len,sizeof (_pt), &_pt);if (p ==NULL )
@@ -735,7 +739,9 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, skb->dev = net->loopback_dev; } -icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu); +/* only send ICMP too big on first fragment */ +if (!iph.fragoffs) +icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu);IP_VS_DBG_RL_PKT (0 ,AF_INET6 , pp, skb,0 ,"ip_vs_nat_xmit_v6(): frag needed for" ); goto tx_error_put;
@@ -940,8 +946,10 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,unsigned int max_headroom;/* The extra header space needed */ int mtu;int ret; +struct ip_vs_iphdr ipvsh;EnterFunction (10 ); +ip_vs_fill_iph_skb (cp->af, skb, &ipvsh); if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, &saddr, 1, (IP_VS_RT_MODE_LOCAL |
@@ -970,7 +978,9 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, skb->dev = net->loopback_dev; } -icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu); +/* only send ICMP too big on first fragment */ +if (!ipvsh.fragoffs) +icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu);IP_VS_DBG_RL ("%s(): frag needed\n" , __func__); goto tx_error_put; }
@@ -1116,8 +1126,10 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, { struct rt6_info *rt; /* Route to the other host */ int mtu; + struct ip_vs_iphdr iph; EnterFunction(10); + ip_vs_fill_iph_skb(cp->af, skb, &iph); if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, 0, (IP_VS_RT_MODE_LOCAL |
@@ -1136,7 +1148,9 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, skb->dev = net->loopback_dev; } -icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu); +/* only send ICMP too big on first fragment */ +if (!iph.fragoffs) +icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu);dst_release (&rt->dst);IP_VS_DBG_RL ("%s(): frag needed\n" , __func__); goto tx_error;
@@ -1308,8 +1322,10 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,int rc;int local;int rt_mode; +struct ip_vs_iphdr iph;EnterFunction (10 ); +ip_vs_fill_iph_skb (cp->af, skb, &iph);/* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be forwarded directly here, because there is no need to
@@ -1372,7 +1388,9 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, skb->dev = net->loopback_dev; } -icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu); +/* only send ICMP too big on first fragment */ +if (!iph.fragoffs) +icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu);IP_VS_DBG_RL ("%s(): frag needed\n" , __func__); goto tx_error_put; }
PATCH v4 6/7 ipvs: API change to avoid rescan of IPv6 exthdr
In reply to Jesper Dangaard BrouerReduce the number of times we scan/skip the IPv6 exthdrs.
This patch contains a lot of API changes. This is done, to avoid repeating the scan of finding the IPv6 headers, via ipv6_find_hdr(), which is called by ip_vs_fill_iph_skb().
Finding the IPv6 headers is done as early as possible, and passed on as a pointer "struct ip_vs_iphdr *" to the affected functions.
This patch reduce/removes 19 calls to ip_vs_fill_iph_skb().
Notice, I have choosen, not to change the API of function pointer "(*schedule)" (in struct ip_vs_scheduler) as it can be used by external schedulers, via {un,}register_ip_vs_scheduler. Only 4 out of 10 schedulers use info from ip_vs_iphdr*, and when they do, they are only interested in iph->{s,d}addr.
---
V3:
- This patch is introduced in V3, to allow easier integration of Patricks idea and my RFC patch of caching exthdr info in skb->cb[]
include/net/ip_vs.h | 81 +++++++++++----------- net/netfilter/ipvs/ip_vs_conn.c | 15 ++-- net/netfilter/ipvs/ip_vs_core.c | 116 ++++++++++++++----------------- net/netfilter/ipvs/ip_vs_proto_ah_esp.c | 9 +- net/netfilter/ipvs/ip_vs_proto_sctp.c | 42 ++++------- net/netfilter/ipvs/ip_vs_proto_tcp.c | 40 ++++------- net/netfilter/ipvs/ip_vs_proto_udp.c | 41 ++++------- net/netfilter/ipvs/ip_vs_xmit.c | 58 +++++++--------- net/netfilter/xt_ipvs.c | 2 - 9 files changed, 175 insertions(+), 229 deletions(-)
include/net/ip_vs.h +41 -40
@@ -487,27 +487,26 @@ struct ip_vs_protocol {int (*conn_schedule)(int af,struct sk_buff *skb,struct ip_vs_proto_data *pd, -int *verdict,struct ip_vs_conn **cpp); +int *verdict,struct ip_vs_conn **cpp, +struct ip_vs_iphdr *iph);struct ip_vs_conn * (*conn_in_get)(int af,const struct sk_buff *skb,const struct ip_vs_iphdr *iph, -unsigned int proto_off,int inverse);struct ip_vs_conn * (*conn_out_get)(int af,const struct sk_buff *skb,const struct ip_vs_iphdr *iph, -unsigned int proto_off,int inverse); -int (*snat_handler)(struct sk_buff *skb, -struct ip_vs_protocol *pp,struct ip_vs_conn *cp); +int (*snat_handler)(struct sk_buff *skb,struct ip_vs_protocol *pp, +struct ip_vs_conn *cp,struct ip_vs_iphdr *iph); -int (*dnat_handler)(struct sk_buff *skb, -struct ip_vs_protocol *pp,struct ip_vs_conn *cp); +int (*dnat_handler)(struct sk_buff *skb,struct ip_vs_protocol *pp, +struct ip_vs_conn *cp,struct ip_vs_iphdr *iph);int (*csum_check)(int af,struct sk_buff *skb,struct ip_vs_protocol *pp);
@@ -607,7 +606,7 @@ struct ip_vs_conn {NF_ACCEPT can be returned when destination is local. */ int (*packet_xmit)(struct sk_buff *skb,struct ip_vs_conn *cp, -struct ip_vs_protocol *pp); +struct ip_vs_protocol *pp,struct ip_vs_iphdr *iph);/* Note: we can group the following members into a structure, in order to save more space, and the following members are
@@ -858,13 +857,11 @@ struct ip_vs_app {struct ip_vs_conn * (*conn_in_get)(const struct sk_buff *skb,struct ip_vs_app *app, -const struct iphdr *iph,unsigned int proto_off, -int inverse); +const struct iphdr *iph,int inverse);struct ip_vs_conn * (*conn_out_get)(const struct sk_buff *skb,struct ip_vs_app *app, -const struct iphdr *iph,unsigned int proto_off, -int inverse); +const struct iphdr *iph,int inverse); int (*state_transition)(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb,
@@ -1163,14 +1160,12 @@ struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p);struct ip_vs_conn *ip_vs_conn_in_get_proto (int af,const struct sk_buff *skb,const struct ip_vs_iphdr *iph, -unsigned int proto_off,int inverse);struct ip_vs_conn *ip_vs_conn_out_get (const struct ip_vs_conn_param *p);struct ip_vs_conn *ip_vs_conn_out_get_proto (int af,const struct sk_buff *skb,const struct ip_vs_iphdr *iph, -unsigned int proto_off,int inverse);/* put back the conn without restarting its timer */
@@ -1343,9 +1338,10 @@ extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name);extern void ip_vs_scheduler_put (struct ip_vs_scheduler *scheduler);extern struct ip_vs_conn *ip_vs_schedule (struct ip_vs_service *svc,struct sk_buff *skb, -struct ip_vs_proto_data *pd,int *ignored); +struct ip_vs_proto_data *pd,int *ignored, +struct ip_vs_iphdr *iph);extern int ip_vs_leave (struct ip_vs_service *svc,struct sk_buff *skb, -struct ip_vs_proto_data *pd); +struct ip_vs_proto_data *pd,struct ip_vs_iphdr *iph);extern void ip_vs_scheduler_err (struct ip_vs_service *svc,const char *msg);
@@ -1404,33 +1400,38 @@ extern void ip_vs_read_estimator(struct ip_vs_stats_user *dst,/* * Various IPVS packet transmitters (from ip_vs_xmit.c) */ -extern int ip_vs_null_xmit -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp); -extern int ip_vs_bypass_xmit -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp); -extern int ip_vs_nat_xmit -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp); -extern int ip_vs_tunnel_xmit -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp); -extern int ip_vs_dr_xmit -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp); -extern int ip_vs_icmp_xmit -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp, -int offset,unsigned int hooknum); +extern int ip_vs_null_xmit (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp,struct ip_vs_iphdr *iph); +extern int ip_vs_bypass_xmit (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp, +struct ip_vs_iphdr *iph); +extern int ip_vs_nat_xmit (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp,struct ip_vs_iphdr *iph); +extern int ip_vs_tunnel_xmit (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp, +struct ip_vs_iphdr *iph); +extern int ip_vs_dr_xmit (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp,struct ip_vs_iphdr *iph); +extern int ip_vs_icmp_xmit (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp,int offset, +unsigned int hooknum,struct ip_vs_iphdr *iph);extern void ip_vs_dst_reset (struct ip_vs_dest *dest);#ifdef CONFIG_IP_VS_IPV6 -extern int ip_vs_bypass_xmit_v6 -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp); -extern int ip_vs_nat_xmit_v6 -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp); -extern int ip_vs_tunnel_xmit_v6 -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp); -extern int ip_vs_dr_xmit_v6 -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp); -extern int ip_vs_icmp_xmit_v6 -(struct sk_buff *skb,struct ip_vs_conn *cp,struct ip_vs_protocol *pp, -int offset,unsigned int hooknum); +extern int ip_vs_bypass_xmit_v6 (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp, +struct ip_vs_iphdr *iph); +extern int ip_vs_nat_xmit_v6 (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp, +struct ip_vs_iphdr *iph); +extern int ip_vs_tunnel_xmit_v6 (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp, +struct ip_vs_iphdr *iph); +extern int ip_vs_dr_xmit_v6 (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp,struct ip_vs_iphdr *iph); +extern int ip_vs_icmp_xmit_v6 (struct sk_buff *skb,struct ip_vs_conn *cp, +struct ip_vs_protocol *pp,int offset, +unsigned int hooknum,struct ip_vs_iphdr *iph);#endif #ifdef CONFIG_SYSCTL
net/netfilter/ipvs/ip_vs_conn.c +6 -9
@@ -308,13 +308,12 @@ struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p)static int ip_vs_conn_fill_param_proto (int af,const struct sk_buff *skb,const struct ip_vs_iphdr *iph, -unsigned int proto_off,int inverse, -struct ip_vs_conn_param *p) +int inverse,struct ip_vs_conn_param *p) {__be16 _ports[2 ], *pptr;struct net *net =skb_net (skb); - pptr =frag_safe_skb_hp (skb, proto_off,sizeof (_ports), _ports, iph); + pptr =frag_safe_skb_hp (skb, iph->len,sizeof (_ports), _ports, iph);if (pptr ==NULL )return 1 ;
@@ -329,12 +328,11 @@ ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,struct ip_vs_conn *ip_vs_conn_in_get_proto (int af,const struct sk_buff *skb, -const struct ip_vs_iphdr *iph, -unsigned int proto_off,int inverse) +const struct ip_vs_iphdr *iph,int inverse) {struct ip_vs_conn_param p; -if (ip_vs_conn_fill_param_proto (af, skb, iph, proto_off, inverse, &p)) +if (ip_vs_conn_fill_param_proto (af, skb, iph, inverse, &p))return NULL ;return ip_vs_conn_in_get (&p);
@@ -432,12 +430,11 @@ struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p)struct ip_vs_conn *ip_vs_conn_out_get_proto (int af,const struct sk_buff *skb, -const struct ip_vs_iphdr *iph, -unsigned int proto_off,int inverse) +const struct ip_vs_iphdr *iph,int inverse) {struct ip_vs_conn_param p; -if (ip_vs_conn_fill_param_proto (af, skb, iph, proto_off, inverse, &p)) +if (ip_vs_conn_fill_param_proto (af, skb, iph, inverse, &p))return NULL ;return ip_vs_conn_out_get (&p);
net/netfilter/ipvs/ip_vs_core.c +51 -65
354 lines not on this page · raw message
net/netfilter/ipvs/ip_vs_proto_ah_esp.c +4 -5
@@ -57,7 +57,7 @@ ah_esp_conn_fill_param_proto(struct net *net, int af,static struct ip_vs_conn *ah_esp_conn_in_get (int af,const struct sk_buff *skb, -const struct ip_vs_iphdr *iph,unsigned int proto_off, +const struct ip_vs_iphdr *iph,int inverse) {struct ip_vs_conn *cp;
@@ -85,9 +85,7 @@ ah_esp_conn_in_get(int af, const struct sk_buff *skb,static struct ip_vs_conn *ah_esp_conn_out_get (int af,const struct sk_buff *skb, -const struct ip_vs_iphdr *iph, -unsigned int proto_off, -int inverse) +const struct ip_vs_iphdr *iph,int inverse) {struct ip_vs_conn *cp;struct ip_vs_conn_param p;
@@ -110,7 +108,8 @@ ah_esp_conn_out_get(int af, const struct sk_buff *skb,static int ah_esp_conn_schedule (int af,struct sk_buff *skb,struct ip_vs_proto_data *pd, -int *verdict,struct ip_vs_conn **cpp) +int *verdict,struct ip_vs_conn **cpp, +struct ip_vs_iphdr *iph) {/* * AH/ESP is only related traffic. Pass the packet to IP stack.
net/netfilter/ipvs/ip_vs_proto_sctp.c +16 -26
94 lines not on this page · raw message
net/netfilter/ipvs/ip_vs_proto_tcp.c +15 -25
@@ -33,16 +33,14 @@static int tcp_conn_schedule (int af,struct sk_buff *skb,struct ip_vs_proto_data *pd, -int *verdict,struct ip_vs_conn **cpp) +int *verdict,struct ip_vs_conn **cpp, +struct ip_vs_iphdr *iph) {struct net *net;struct ip_vs_service *svc;struct tcphdr _tcph, *th; -struct ip_vs_iphdr iph; -ip_vs_fill_iph_skb (af, skb, &iph); - - th =skb_header_pointer (skb, iph.len,sizeof (_tcph), &_tcph); + th =skb_header_pointer (skb, iph->len,sizeof (_tcph), &_tcph);if (th ==NULL ) { *verdict =NF_DROP ;return 0 ;
@@ -50,8 +48,8 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, net =skb_net (skb);/* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */ if (th->syn && - (svc =ip_vs_service_get (net, af, skb->mark, iph.protocol, - &iph.daddr, th->dest))) { + (svc =ip_vs_service_get (net, af, skb->mark, iph->protocol, + &iph->daddr, th->dest))) {int ignored;if (ip_vs_todrop (net_ipvs (net))) {
@@ -68,10 +66,10 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,* Let the virtual server select a real server for the * incoming connection, and create a connection entry. */ - *cpp =ip_vs_schedule (svc, skb, pd, &ignored); + *cpp =ip_vs_schedule (svc, skb, pd, &ignored, iph);if (!*cpp && ignored <=0 ) {if (!ignored) - *verdict =ip_vs_leave (svc, skb, pd); + *verdict =ip_vs_leave (svc, skb, pd, iph);else {ip_vs_service_put (svc); *verdict =NF_DROP ;
@@ -128,20 +126,16 @@ tcp_partial_csum_update(int af, struct tcphdr *tcph,static int -tcp_snat_handler (struct sk_buff *skb, -struct ip_vs_protocol *pp,struct ip_vs_conn *cp) +tcp_snat_handler (struct sk_buff *skb,struct ip_vs_protocol *pp, +struct ip_vs_conn *cp,struct ip_vs_iphdr *iph) {struct tcphdr *tcph; -unsigned int tcphoff; +unsigned int tcphoff = iph->len;int oldlen;int payload_csum =0 ; -struct ip_vs_iphdr iph; -ip_vs_fill_iph_skb (cp->af, skb, &iph); - tcphoff = iph.len; -#ifdef CONFIG_IP_VS_IPV6 -if (cp->af ==AF_INET6 && iph.fragoffs) +if (cp->af ==AF_INET6 && iph->fragoffs)return 1 ;#endif oldlen = skb->len - tcphoff;
@@ -210,20 +204,16 @@ tcp_snat_handler(struct sk_buff *skb,static int -tcp_dnat_handler (struct sk_buff *skb, -struct ip_vs_protocol *pp,struct ip_vs_conn *cp) +tcp_dnat_handler (struct sk_buff *skb,struct ip_vs_protocol *pp, +struct ip_vs_conn *cp,struct ip_vs_iphdr *iph) {struct tcphdr *tcph; -unsigned int tcphoff; +unsigned int tcphoff = iph->len;int oldlen;int payload_csum =0 ; -struct ip_vs_iphdr iph; -ip_vs_fill_iph_skb (cp->af, skb, &iph); - tcphoff = iph.len; -#ifdef CONFIG_IP_VS_IPV6 -if (cp->af ==AF_INET6 && iph.fragoffs) +if (cp->af ==AF_INET6 && iph->fragoffs)return 1 ;#endif oldlen = skb->len - tcphoff;
net/netfilter/ipvs/ip_vs_proto_udp.c +16 -25
89 lines not on this page · raw message
net/netfilter/ipvs/ip_vs_xmit.c +25 -33
214 lines not on this page · raw message
net/netfilter/xt_ipvs.c +1 -1
@@ -85,7 +85,7 @@ ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par)/* * Check if the packet belongs to an existing entry */ - cp = pp->conn_out_get (family, skb, &iph, iph.len,1 /* inverse */ ); + cp = pp->conn_out_get (family, skb, &iph,1 /* inverse */ );if (unlikely (cp ==NULL )) { match = false; goto out;
PATCH v4 7/7 ipvs: SIP fragment handling
In reply to Jesper Dangaard BrouerUse the nfct_reasm SKB if available.
Based on part of a patch from: Hans Schillstrom I have left Hans'es comment in the patch (marked /HS)
---
V3:
- I have split out the SIP fragment handling into a seperate patch. As I have not been able to test this part.
- Change the strange SKB swapping reasm = skb, reverse logic to minimize patch
net/netfilter/ipvs/ip_vs_pe_sip.c | 19 +++++++++++++++---- 1 files changed, 15 insertions(+), 4 deletions(-)
net/netfilter/ipvs/ip_vs_pe_sip.c +15 -4
@@ -68,6 +68,7 @@ static int get_callid(const char *dptr, unsigned int dataoff,static int ip_vs_sip_fill_param (struct ip_vs_conn_param *p,struct sk_buff *skb) { +struct sk_buff *reasm =skb_nfct_reasm (skb);struct ip_vs_iphdr iph;unsigned int dataoff, datalen, matchoff, matchlen;const char *dptr;
@@ -78,13 +79,23 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)/* Only useful with UDP */ if (iph.protocol !=IPPROTO_UDP )return -EINVAL ; +/* +* todo: IPv6 fragments: +* I think this only should be done for the first fragment. /HS +*/ +if (reasm) { + skb = reasm; + dataoff = iph.thoff_reasm +sizeof (struct udphdr ); + }else + dataoff = iph.len +sizeof (struct udphdr ); -/* No Data ? */ - dataoff = iph.len +sizeof (struct udphdr );if (dataoff >= skb->len)return -EINVAL ; - -if ((retc=skb_linearize (skb)) <0 ) +/* +* todo: Check if this will mess-up the reasm skb !!! /HS +*/ + retc =skb_linearize (skb); +if (retc <0 )return retc; dptr = skb->data + dataoff; datalen = skb->len - dataoff;
Simon Horman
maintainerRe: [PATCH V4 7/7] ipvs: SIP fragment handling
Quoted 14 lines · Jesper Dangaard Brouer
Use the
nfct_reasmSKB if available.Based on part of a patch from: Hans Schillstrom I have left Hans'es comment in the patch (marked /HS)
Signed-off-by Jesper Dangaard Brouer <[email protected]>---
V3:
- I have split out the SIP fragment handling into a seperate patch. As I have not been able to test this part.
- Change the strange SKB swapping reasm = skb, reverse logic to minimize patch
Quoted 2 lines
net/netfilter/ipvs/ip_vs_pe_sip.c | 19 +++++++++++++++---- 1 files changed, 15 insertions(+), 4 deletions(-)
I realise that the commenting style used inside net/netfilter/ipvs/ is wildly inconsistent, but I think it is worth using the preffered style for network code where possible.
I intend to include the follwowing changes in my tree.
Quoted 14 lines
net/netfilter/ipvs/ip_vs_pe_sip.c +1
-0@@ -68,6 +68,7 @@ static int get_callid(const char *dptr, unsigned int dataoff,static int ip_vs_sip_fill_param (struct ip_vs_conn_param *p,struct sk_buff *skb) { +struct sk_buff *reasm =skb_nfct_reasm (skb);struct ip_vs_iphdr iph;unsigned int dataoff, datalen, matchoff, matchlen;const char *dptr;
net/netfilter/ipvs/ip_vs_pe_sip.c ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb) · line 85
Quoted 7 lines
net/netfilter/ipvs/ip_vs_pe_sip.c +4
-0@@ -78,13 +79,23 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)/* Only useful with UDP */ if (iph.protocol !=IPPROTO_UDP )return -EINVAL ; +/* +* todo: IPv6 fragments: +* I think this only should be done for the first fragment. /HS +*/
/* todo: IPv6 fragments: * I think this only should be done for the first fragment. /HS */
Quoted 5 lines
net/netfilter/ipvs/ip_vs_pe_sip.c +5
-0+if (reasm) { + skb = reasm; + dataoff = iph.thoff_reasm +sizeof (struct udphdr ); + }else + dataoff = iph.len +sizeof (struct udphdr );
net/netfilter/ipvs/ip_vs_pe_sip.c ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb) · line 96
Quoted 10 lines
net/netfilter/ipvs/ip_vs_pe_sip.c +3
-4-/* No Data ? */ - dataoff = iph.len +sizeof (struct udphdr );if (dataoff >= skb->len)return -EINVAL ; - -if ((retc=skb_linearize (skb)) <0 ) +/* +* todo: Check if this will mess-up the reasm skb !!! /HS +*/
/* todo: Check if this will mess-up the reasm skb !!! /HS */
Quoted 6 lines
net/netfilter/ipvs/ip_vs_pe_sip.c +2
-0+ retc =skb_linearize (skb); +if (retc <0 )return retc; dptr = skb->data + dataoff; datalen = skb->len - dataoff;
Hello,
Quoted 46 lines · Jesper Dangaard Brouer
The following patchset implement IPv6 fragment handling for IPVS.
This work is based upon patches from Hans Schillstrom. I have taken over the patchset, in close agreement with Hans, because he don't have (gotten allocated) time to complete his work.
I have cleaned up the patchset significantly, and split the patchset up into seven patches.
The first 3 patches, are ready to be merged
Patch01: Trivial changes, use compressed IPv6 address in output
Patch02: IPv6 extend ICMPv6 handling for future types
Patch03: Use config macroIS_ENABLED()The next 4 patches, is V4 of the patches I have submitted earlier. Where I have incorporated Julian's recent feedback.
- Notice that patch04 of patchset V3, have been dropped.
I have also tried to make the patches easier to review, by reorganizing the changes, to be more strictly split (exthdr vs. fragment handling).
I have also removed the API changes, and moved those to patch06. This is done, (1) to make it easier to review the patches, and (2) to allow easier integration of Patricks idea and my RFC patch of caching exthdr info in skb->cb[]. Thus, we can get these patches applied (and later go back and apply the caching scheme easier).
Patch04: Fix faulty IPv6 extension header handling in IPVS
Patch05: Complete IPv6 fragment handling for IPVS
Patch06: IPVS API change to avoid rescan of IPv6 exthdr
Patch07: IPVS SIP fragment handlingThe SIP frag handling have been split into its own patch, as I have not been able to test this part my self.
This patchset is based upon:
Pablo's nf-next tree:git://1984.lsi.us.es/nf-next
On top of:
commit2cbc78a29e76a2e92c172651204f3117491877d2(netfilter: combineipt_REDIRECTandip6t_REDIRECT)---
Quoted 8 lines
Jesper Dangaard Brouer (7):
ipvs: SIP fragment handling
ipvs: API change to avoid rescan of IPv6 exthdr
ipvs: Complete IPv6 fragment handling for IPVS
ipvs: Fix faulty IPv6 extension header handling in IPVS
ipvs: Use config macroIS_ENABLED()
ipvs: IPv6 extend ICMPv6 handling for future types
ipvs: Trivial changes, use compressed IPv6 address in output
All 7 patches look good to me. Thanks!
Quoted 20 lines
include/net/ip_vs.h | 194 +++++++++++---- net/netfilter/ipvs/Kconfig | 7 - net/netfilter/ipvs/ip_vs_conn.c | 15 - net/netfilter/ipvs/ip_vs_core.c | 404 +++++++++++++++++-------------- net/netfilter/ipvs/ip_vs_dh.c | 2 net/netfilter/ipvs/ip_vs_lblc.c | 2 net/netfilter/ipvs/ip_vs_lblcr.c | 2 net/netfilter/ipvs/ip_vs_pe_sip.c | 21 +- net/netfilter/ipvs/ip_vs_proto.c | 6 net/netfilter/ipvs/ip_vs_proto_ah_esp.c | 9 - net/netfilter/ipvs/ip_vs_proto_sctp.c | 42 +-- net/netfilter/ipvs/ip_vs_proto_tcp.c | 40 +-- net/netfilter/ipvs/ip_vs_proto_udp.c | 41 +-- net/netfilter/ipvs/ip_vs_sched.c | 2 net/netfilter/ipvs/ip_vs_sh.c | 2 net/netfilter/ipvs/ip_vs_xmit.c | 73 +++--- net/netfilter/xt_ipvs.c | 4 17 files changed, 504 insertions(+), 362 deletions(-)
Quoted 6 lines
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
Regards
--
Julian Anastasov <[email protected]>
Simon Horman
maintainerQuoted 60 lines · Julian Anastasov
Hello,
Quoted 46 lines · Jesper Dangaard Brouer
The following patchset implement IPv6 fragment handling for IPVS.
This work is based upon patches from Hans Schillstrom. I have taken over the patchset, in close agreement with Hans, because he don't have (gotten allocated) time to complete his work.
I have cleaned up the patchset significantly, and split the patchset up into seven patches.
The first 3 patches, are ready to be merged
Patch01: Trivial changes, use compressed IPv6 address in output
Patch02: IPv6 extend ICMPv6 handling for future types
Patch03: Use config macroIS_ENABLED()The next 4 patches, is V4 of the patches I have submitted earlier. Where I have incorporated Julian's recent feedback.
- Notice that patch04 of patchset V3, have been dropped.
I have also tried to make the patches easier to review, by reorganizing the changes, to be more strictly split (exthdr vs. fragment handling).
I have also removed the API changes, and moved those to patch06. This is done, (1) to make it easier to review the patches, and (2) to allow easier integration of Patricks idea and my RFC patch of caching exthdr info in skb->cb[]. Thus, we can get these patches applied (and later go back and apply the caching scheme easier).
Patch04: Fix faulty IPv6 extension header handling in IPVS
Patch05: Complete IPv6 fragment handling for IPVS
Patch06: IPVS API change to avoid rescan of IPv6 exthdr
Patch07: IPVS SIP fragment handlingThe SIP frag handling have been split into its own patch, as I have not been able to test this part my self.
This patchset is based upon:
Pablo's nf-next tree:git://1984.lsi.us.es/nf-next
On top of:
commit2cbc78a29e76a2e92c172651204f3117491877d2(netfilter: combineipt_REDIRECTandip6t_REDIRECT)---
Quoted 8 lines
Jesper Dangaard Brouer (7):
ipvs: SIP fragment handling
ipvs: API change to avoid rescan of IPv6 exthdr
ipvs: Complete IPv6 fragment handling for IPVS
ipvs: Fix faulty IPv6 extension header handling in IPVS
ipvs: Use config macroIS_ENABLED()
ipvs: IPv6 extend ICMPv6 handling for future types
ipvs: Trivial changes, use compressed IPv6 address in output
Quoted 3 lines
All 7 patches look good to me. Thanks!
Acked-by Julian Anastasov <[email protected]>
Thanks, I aim to review these tomorrow.