aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorSimon Wunderlich <siwu@hrz.tu-chemnitz.de>2008-07-30 19:27:55 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-30 19:27:55 -0400
commit4adf0af6818f3ea52421dc0bae836cfaf20ef72a (patch)
tree480835bbc913896cd726e3f90d20ce8c859636f7 /net/bridge
parente62112c53acfefc67ccfbdc1895eebccf866bc1b (diff)
bridge: send correct MTU value in PMTU (revised)
When bridging interfaces with different MTUs, the bridge correctly chooses the minimum of the MTUs of the physical devices as the bridges MTU. But when a frame is passed which fits through the incoming, but not through the outgoing interface, a "Fragmentation Needed" packet is generated. However, the propagated MTU is hardcoded to 1500, which is wrong in this situation. The sender will repeat the packet again with the same frame size, and the same problem will occur again. Instead of sending 1500, the (correct) MTU value of the bridge is now sent via PMTU. To achieve this, the corresponding rtable structure is stored in its net_bridge structure. Modified to get rid of fake_net_device as well. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_device.c9
-rw-r--r--net/bridge/br_if.c3
-rw-r--r--net/bridge/br_netfilter.c63
-rw-r--r--net/bridge/br_private.h6
4 files changed, 51 insertions, 30 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index d9449df7cad5..9b58d70b0e7d 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -68,10 +68,17 @@ static int br_dev_stop(struct net_device *dev)
68 68
69static int br_change_mtu(struct net_device *dev, int new_mtu) 69static int br_change_mtu(struct net_device *dev, int new_mtu)
70{ 70{
71 if (new_mtu < 68 || new_mtu > br_min_mtu(netdev_priv(dev))) 71 struct net_bridge *br = netdev_priv(dev);
72 if (new_mtu < 68 || new_mtu > br_min_mtu(br))
72 return -EINVAL; 73 return -EINVAL;
73 74
74 dev->mtu = new_mtu; 75 dev->mtu = new_mtu;
76
77#ifdef CONFIG_BRIDGE_NETFILTER
78 /* remember the MTU in the rtable for PMTU */
79 br->fake_rtable.u.dst.metrics[RTAX_MTU - 1] = new_mtu;
80#endif
81
75 return 0; 82 return 0;
76} 83}
77 84
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index a072ea5ca6f5..63c18aacde8c 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -202,6 +202,9 @@ static struct net_device *new_bridge_dev(const char *name)
202 br->topology_change = 0; 202 br->topology_change = 0;
203 br->topology_change_detected = 0; 203 br->topology_change_detected = 0;
204 br->ageing_time = 300 * HZ; 204 br->ageing_time = 300 * HZ;
205
206 br_netfilter_rtable_init(br);
207
205 INIT_LIST_HEAD(&br->age_list); 208 INIT_LIST_HEAD(&br->age_list);
206 209
207 br_stp_timer_init(br); 210 br_stp_timer_init(br);
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index bb90cd7bace3..6e280a8a31ee 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -101,33 +101,30 @@ static inline __be16 pppoe_proto(const struct sk_buff *skb)
101 pppoe_proto(skb) == htons(PPP_IPV6) && \ 101 pppoe_proto(skb) == htons(PPP_IPV6) && \
102 brnf_filter_pppoe_tagged) 102 brnf_filter_pppoe_tagged)
103 103
104/* We need these fake structures to make netfilter happy -- 104/*
105 * lots of places assume that skb->dst != NULL, which isn't 105 * Initialize bogus route table used to keep netfilter happy.
106 * all that unreasonable.
107 *
108 * Currently, we fill in the PMTU entry because netfilter 106 * Currently, we fill in the PMTU entry because netfilter
109 * refragmentation needs it, and the rt_flags entry because 107 * refragmentation needs it, and the rt_flags entry because
110 * ipt_REJECT needs it. Future netfilter modules might 108 * ipt_REJECT needs it. Future netfilter modules might
111 * require us to fill additional fields. */ 109 * require us to fill additional fields.
112static struct net_device __fake_net_device = { 110 */
113 .hard_header_len = ETH_HLEN, 111void br_netfilter_rtable_init(struct net_bridge *br)
114#ifdef CONFIG_NET_NS 112{
115 .nd_net = &init_net, 113 struct rtable *rt = &br->fake_rtable;
116#endif
117};
118 114
119static struct rtable __fake_rtable = { 115 atomic_set(&rt->u.dst.__refcnt, 1);
120 .u = { 116 rt->u.dst.dev = &br->dev;
121 .dst = { 117 rt->u.dst.path = &rt->u.dst;
122 .__refcnt = ATOMIC_INIT(1), 118 rt->u.dst.metrics[RTAX_MTU - 1] = 1500;
123 .dev = &__fake_net_device, 119 rt->u.dst.flags = DST_NOXFRM;
124 .path = &__fake_rtable.u.dst, 120}
125 .metrics = {[RTAX_MTU - 1] = 1500}, 121
126 .flags = DST_NOXFRM, 122static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
127 } 123{
128 }, 124 struct net_bridge_port *port = rcu_dereference(dev->br_port);
129 .rt_flags = 0, 125
130}; 126 return port ? &port->br->fake_rtable : NULL;
127}
131 128
132static inline struct net_device *bridge_parent(const struct net_device *dev) 129static inline struct net_device *bridge_parent(const struct net_device *dev)
133{ 130{
@@ -226,8 +223,12 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
226 } 223 }
227 nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; 224 nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
228 225
229 skb->rtable = &__fake_rtable; 226 skb->rtable = bridge_parent_rtable(nf_bridge->physindev);
230 dst_hold(&__fake_rtable.u.dst); 227 if (!skb->rtable) {
228 kfree_skb(skb);
229 return 0;
230 }
231 dst_hold(&skb->rtable->u.dst);
231 232
232 skb->dev = nf_bridge->physindev; 233 skb->dev = nf_bridge->physindev;
233 nf_bridge_push_encap_header(skb); 234 nf_bridge_push_encap_header(skb);
@@ -391,8 +392,12 @@ bridged_dnat:
391 skb->pkt_type = PACKET_HOST; 392 skb->pkt_type = PACKET_HOST;
392 } 393 }
393 } else { 394 } else {
394 skb->rtable = &__fake_rtable; 395 skb->rtable = bridge_parent_rtable(nf_bridge->physindev);
395 dst_hold(&__fake_rtable.u.dst); 396 if (!skb->rtable) {
397 kfree_skb(skb);
398 return 0;
399 }
400 dst_hold(&skb->rtable->u.dst);
396 } 401 }
397 402
398 skb->dev = nf_bridge->physindev; 403 skb->dev = nf_bridge->physindev;
@@ -611,8 +616,8 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb,
611 const struct net_device *out, 616 const struct net_device *out,
612 int (*okfn)(struct sk_buff *)) 617 int (*okfn)(struct sk_buff *))
613{ 618{
614 if (skb->rtable == &__fake_rtable) { 619 if (skb->rtable && skb->rtable == bridge_parent_rtable(in)) {
615 dst_release(&__fake_rtable.u.dst); 620 dst_release(&skb->rtable->u.dst);
616 skb->rtable = NULL; 621 skb->rtable = NULL;
617 } 622 }
618 623
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 815ed38925b2..c3dc18ddc043 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -15,6 +15,7 @@
15 15
16#include <linux/netdevice.h> 16#include <linux/netdevice.h>
17#include <linux/if_bridge.h> 17#include <linux/if_bridge.h>
18#include <net/route.h>
18 19
19#define BR_HASH_BITS 8 20#define BR_HASH_BITS 8
20#define BR_HASH_SIZE (1 << BR_HASH_BITS) 21#define BR_HASH_SIZE (1 << BR_HASH_BITS)
@@ -92,6 +93,9 @@ struct net_bridge
92 struct hlist_head hash[BR_HASH_SIZE]; 93 struct hlist_head hash[BR_HASH_SIZE];
93 struct list_head age_list; 94 struct list_head age_list;
94 unsigned long feature_mask; 95 unsigned long feature_mask;
96#ifdef CONFIG_BRIDGE_NETFILTER
97 struct rtable fake_rtable;
98#endif
95 unsigned long flags; 99 unsigned long flags;
96#define BR_SET_MAC_ADDR 0x00000001 100#define BR_SET_MAC_ADDR 0x00000001
97 101
@@ -197,9 +201,11 @@ extern int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __us
197#ifdef CONFIG_BRIDGE_NETFILTER 201#ifdef CONFIG_BRIDGE_NETFILTER
198extern int br_netfilter_init(void); 202extern int br_netfilter_init(void);
199extern void br_netfilter_fini(void); 203extern void br_netfilter_fini(void);
204extern void br_netfilter_rtable_init(struct net_bridge *);
200#else 205#else
201#define br_netfilter_init() (0) 206#define br_netfilter_init() (0)
202#define br_netfilter_fini() do { } while(0) 207#define br_netfilter_fini() do { } while(0)
208#define br_netfilter_rtable_init(x)
203#endif 209#endif
204 210
205/* br_stp.c */ 211/* br_stp.c */