bridge-netfilter: fix refragmenting IP traffic encapsulated in PPPoE traffic
Subsystems (4)
PATCH 3/3 bridge-netfilter: fix refragmenting IP traffic encapsulated in PPPoE traffic
bridge-netfilter: fix refragmenting IP traffic encapsulated in PPPoE traffic
The MTU for IP traffic encapsulated inside PPPoE traffic is smaller than the MTU of the Ethernet device (1500). Connection tracking gathers all IP packets and sometimes will refragment them in ip_fragment(). We then need to subtract the length of the encapsulating header from the mtu used in ip_fragment(). The check in br_nf_dev_queue_xmit() which determines if ip_fragment() has to be called is also updated for the PPPoE-encapsulated packets. nf_bridge_copy_header() is also updated to make sure the PPPoE data length field has the correct value.
net/bridge/br_netfilter.c renamed from net/bridge/br_netfilter.c.ori3 +3 -1
@@ -221,6 +221,8 @@ int nf_bridge_copy_header(struct sk_buffskb_copy_to_linear_data_offset (skb, -header_size, skb->nf_bridge->data, header_size);__skb_push (skb,nf_bridge_encap_header_len (skb)); +if (unlikely (skb->protocol ==htons (ETH_P_PPP_SES ))) + ((struct pppoe_hdr *)skb->data)->length =htons (skb->len-sizeof (struct pppoe_hdr ));return 0 ; }
@@ -744,7 +746,7 @@ static unsigned int br_nf_forward_arp(unstatic int br_nf_dev_queue_xmit (struct sk_buff *skb) {if (skb->nfct !=NULL && skb->protocol ==htons (ETH_P_IP ) && - skb->len > skb->dev->mtu && + skb->len + ((skb->nf_bridge->mask & BRNF_PPPoE) ?PPPOE_SES_HLEN :0 ) > skb->dev->mtu && !skb_is_gso (skb))return ip_fragment (skb, br_dev_queue_push_xmit);else
net/ipv4/ip_output.c renamed from net/ipv4/ip_output.c.ori +4 -0
@@ -468,6 +468,10 @@ int ip_fragment(struct sk_buff *skb, int hlen = iph->ihl *4 ; mtu =dst_mtu (&rt->u.dst) - hlen;/* Size of data space */ +#ifdef CONFIG_BRIDGE_NETFILTER +if (unlikely (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_PPPoE))) + mtu -=PPPOE_SES_HLEN ; +#endif IPCB (skb)->flags |=IPSKB_FRAG_COMPLETE ;/* When frag_list is given, use it. First, check its validity:
Signature · 2 lines
Bart De Schuymer www.artinalgorithms.be
Quoted 38 lines · Bart De Schuymer
bridge-netfilter: fix refragmenting IP traffic encapsulated in PPPoE traffic
The MTU for IP traffic encapsulated inside PPPoE traffic is smaller than the MTU of the Ethernet device (1500). Connection tracking gathers all IP packets and sometimes will refragment them in
ip_fragment(). We then need to subtract the length of the encapsulating header from the mtu used inip_fragment(). The check inbr_nf_dev_queue_xmit()which determines ifip_fragment()has to be called is also updated for the PPPoE-encapsulated packets.nf_bridge_copy_header()is also updated to make sure the PPPoE data length field has the correct value.Signed-off-by Bart De Schuymer <[email protected]>net/bridge/br_netfilter.c renamed from net/bridge/br_netfilter.c.ori3 +3
-1@@ -221,6 +221,8 @@ int nf_bridge_copy_header(struct sk_buffskb_copy_to_linear_data_offset (skb, -header_size, skb->nf_bridge->data, header_size);__skb_push (skb,nf_bridge_encap_header_len (skb)); +if (unlikely (skb->protocol ==htons (ETH_P_PPP_SES ))) + ((struct pppoe_hdr *)skb->data)->length =htons (skb->len-sizeof (struct pppoe_hdr ));return 0 ; }@@ -744,7 +746,7 @@ static unsigned int br_nf_forward_arp(unstatic int br_nf_dev_queue_xmit (struct sk_buff *skb) {if (skb->nfct !=NULL && skb->protocol ==htons (ETH_P_IP ) && - skb->len > skb->dev->mtu && + skb->len + ((skb->nf_bridge->mask & BRNF_PPPoE) ?PPPOE_SES_HLEN :0 ) > skb->dev->mtu && !skb_is_gso (skb))return ip_fragment (skb, br_dev_queue_push_xmit);else
net/ipv4/ip_output.c int ip_fragment(struct sk_buff *skb, int · line 474
Quoted 7 lines
net/ipv4/ip_output.c renamed from net/ipv4/ip_output.c.ori +4
-0@@ -468,6 +468,10 @@ int ip_fragment(struct sk_buff *skb, int hlen = iph->ihl *4 ; mtu =dst_mtu (&rt->u.dst) - hlen;/* Size of data space */ +#ifdef CONFIG_BRIDGE_NETFILTER +if (unlikely (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_PPPoE))) + mtu -=PPPOE_SES_HLEN ; +#endif
I think it would be nice to encapsulate this in a small inline function, perhaps nf_bridge_adjust_mtu(skb, mtu) or something like that.
Please also fix the overly long lines.
Quoted 9 lines · Patrick McHardy
Quoted 2 lines · Bart De Schuymer
bridge-netfilter: fix refragmenting IP traffic encapsulated in PPPoE traffic
I think it would be nice to encapsulate this in a small inline function, perhaps
nf_bridge_adjust_mtu(skb, mtu)or something like that.Please also fix the overly long lines.
Done, see below.
bridge-netfilter: fix refragmenting IP traffic encapsulated in PPPoE traffic
The MTU for IP traffic encapsulated inside PPPoE traffic is smaller than the MTU of the Ethernet device (1500). Connection tracking gathers all IP packets and sometimes will refragment them in ip_fragment(). We then need to subtract the length of the encapsulating header from the mtu used in ip_fragment(). The check in br_nf_dev_queue_xmit() which determines if ip_fragment() has to be called is also updated for the PPPoE-encapsulated packets. nf_bridge_copy_header() is also updated to make sure the PPPoE data length field has the correct value.
include/linux/netfilter_bridge.h renamed from include/linux/netfilter_bridge.h.ori3 +7 -0
@@ -68,6 +68,13 @@ static inline unsigned int nf_bridge_enc } } +static inline unsigned int nf_bridge_mtu_reduction (const struct sk_buff *skb) +{ +if (unlikely (skb->nf_bridge->mask & BRNF_PPPoE)) +return PPPOE_SES_HLEN ; +return 0 ; +} +extern int br_handle_frame_finish (struct sk_buff *skb);/* Only used in br_device.c */ static inline int br_nf_pre_routing_finish_bridge_slow (struct sk_buff *skb)
net/ipv4/ip_output.c renamed from net/ipv4/ip_output.c.ori +4 -0
@@ -468,6 +468,10 @@ int ip_fragment(struct sk_buff *skb, int hlen = iph->ihl *4 ; mtu =dst_mtu (&rt->u.dst) - hlen;/* Size of data space */ +#ifdef CONFIG_BRIDGE_NETFILTER +if (skb->nf_bridge) + mtu -=nf_bridge_mtu_reduction (skb); +#endif IPCB (skb)->flags |=IPSKB_FRAG_COMPLETE ;/* When frag_list is given, use it. First, check its validity:
net/bridge/br_netfilter.c renamed from net/bridge/br_netfilter.c.ori3 +1 -1
@@ -744,7 +744,7 @@ static unsigned int br_nf_forward_arp(unstatic int br_nf_dev_queue_xmit (struct sk_buff *skb) {if (skb->nfct !=NULL && skb->protocol ==htons (ETH_P_IP ) && - skb->len > skb->dev->mtu && + skb->len +nf_bridge_mtu_reduction (skb) > skb->dev->mtu && !skb_is_gso (skb))return ip_fragment (skb, br_dev_queue_push_xmit);else
Signature · 2 lines
Bart De Schuymer www.artinalgorithms.be
Patrick McHardy
AppliedQuoted 12 lines · Bart De Schuymer
bridge-netfilter: fix refragmenting IP traffic encapsulated in PPPoE traffic
The MTU for IP traffic encapsulated inside PPPoE traffic is smaller than the MTU of the Ethernet device (1500). Connection tracking gathers all IP packets and sometimes will refragment them in
ip_fragment(). We then need to subtract the length of the encapsulating header from the mtu used inip_fragment(). The check inbr_nf_dev_queue_xmit()which determines ifip_fragment()has to be called is also updated for the PPPoE-encapsulated packets.nf_bridge_copy_header()is also updated to make sure the PPPoE data length field has the correct value.
Applied, thanks Bart.