diff options
author | Jiri Pirko <jpirko@redhat.com> | 2010-06-15 02:50:45 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-15 14:48:58 -0400 |
commit | f350a0a87374418635689471606454abc7beaa3a (patch) | |
tree | c8210542a9848f6b5953b58d2ba1dbfb11715f14 /net/bridge | |
parent | a35e2c1b6d90544b3c688783869817628e5f9607 (diff) |
bridge: use rx_handler_data pointer to store net_bridge_port pointer
Register net_bridge_port pointer as rx_handler data pointer. As br_port is
removed from struct net_device, another netdev priv_flag is added to indicate
the device serves as a bridge port. Also rcuized pointers are now correctly
dereferenced in br_fdb.c and in netfilter parts.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_fdb.c | 4 | ||||
-rw-r--r-- | net/bridge/br_if.c | 23 | ||||
-rw-r--r-- | net/bridge/br_input.c | 9 | ||||
-rw-r--r-- | net/bridge/br_netfilter.c | 11 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 9 | ||||
-rw-r--r-- | net/bridge/br_notify.c | 5 | ||||
-rw-r--r-- | net/bridge/br_private.h | 5 | ||||
-rw-r--r-- | net/bridge/br_stp_bpdu.c | 5 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_redirect.c | 3 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_ulog.c | 8 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 11 |
11 files changed, 55 insertions, 38 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 26637439965b..6818e609b2c0 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -242,11 +242,11 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) | |||
242 | struct net_bridge_fdb_entry *fdb; | 242 | struct net_bridge_fdb_entry *fdb; |
243 | int ret; | 243 | int ret; |
244 | 244 | ||
245 | if (!dev->br_port) | 245 | if (!br_port_exists(dev)) |
246 | return 0; | 246 | return 0; |
247 | 247 | ||
248 | rcu_read_lock(); | 248 | rcu_read_lock(); |
249 | fdb = __br_fdb_get(dev->br_port->br, addr); | 249 | fdb = __br_fdb_get(br_port_get_rcu(dev)->br, addr); |
250 | ret = fdb && fdb->dst->dev != dev && | 250 | ret = fdb && fdb->dst->dev != dev && |
251 | fdb->dst->state == BR_STATE_FORWARDING; | 251 | fdb->dst->state == BR_STATE_FORWARDING; |
252 | rcu_read_unlock(); | 252 | rcu_read_unlock(); |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 0d142ed0bbe3..c03d2c3ff03e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -147,8 +147,9 @@ static void del_nbp(struct net_bridge_port *p) | |||
147 | 147 | ||
148 | list_del_rcu(&p->list); | 148 | list_del_rcu(&p->list); |
149 | 149 | ||
150 | dev->priv_flags &= ~IFF_BRIDGE_PORT; | ||
151 | |||
150 | netdev_rx_handler_unregister(dev); | 152 | netdev_rx_handler_unregister(dev); |
151 | rcu_assign_pointer(dev->br_port, NULL); | ||
152 | 153 | ||
153 | br_multicast_del_port(p); | 154 | br_multicast_del_port(p); |
154 | 155 | ||
@@ -400,7 +401,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
400 | return -ELOOP; | 401 | return -ELOOP; |
401 | 402 | ||
402 | /* Device is already being bridged */ | 403 | /* Device is already being bridged */ |
403 | if (dev->br_port != NULL) | 404 | if (br_port_exists(dev)) |
404 | return -EBUSY; | 405 | return -EBUSY; |
405 | 406 | ||
406 | /* No bridging devices that dislike that (e.g. wireless) */ | 407 | /* No bridging devices that dislike that (e.g. wireless) */ |
@@ -431,11 +432,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
431 | if (br_netpoll_info(br) && ((err = br_netpoll_enable(p)))) | 432 | if (br_netpoll_info(br) && ((err = br_netpoll_enable(p)))) |
432 | goto err3; | 433 | goto err3; |
433 | 434 | ||
434 | rcu_assign_pointer(dev->br_port, p); | 435 | err = netdev_rx_handler_register(dev, br_handle_frame, p); |
435 | |||
436 | err = netdev_rx_handler_register(dev, br_handle_frame, NULL); | ||
437 | if (err) | 436 | if (err) |
438 | goto err4; | 437 | goto err3; |
438 | |||
439 | dev->priv_flags |= IFF_BRIDGE_PORT; | ||
439 | 440 | ||
440 | dev_disable_lro(dev); | 441 | dev_disable_lro(dev); |
441 | 442 | ||
@@ -457,8 +458,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
457 | kobject_uevent(&p->kobj, KOBJ_ADD); | 458 | kobject_uevent(&p->kobj, KOBJ_ADD); |
458 | 459 | ||
459 | return 0; | 460 | return 0; |
460 | err4: | ||
461 | rcu_assign_pointer(dev->br_port, NULL); | ||
462 | err3: | 461 | err3: |
463 | sysfs_remove_link(br->ifobj, p->dev->name); | 462 | sysfs_remove_link(br->ifobj, p->dev->name); |
464 | err2: | 463 | err2: |
@@ -477,9 +476,13 @@ put_back: | |||
477 | /* called with RTNL */ | 476 | /* called with RTNL */ |
478 | int br_del_if(struct net_bridge *br, struct net_device *dev) | 477 | int br_del_if(struct net_bridge *br, struct net_device *dev) |
479 | { | 478 | { |
480 | struct net_bridge_port *p = dev->br_port; | 479 | struct net_bridge_port *p; |
480 | |||
481 | if (!br_port_exists(dev)) | ||
482 | return -EINVAL; | ||
481 | 483 | ||
482 | if (!p || p->br != br) | 484 | p = br_port_get(dev); |
485 | if (p->br != br) | ||
483 | return -EINVAL; | 486 | return -EINVAL; |
484 | 487 | ||
485 | del_nbp(p); | 488 | del_nbp(p); |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 99647d8f95c8..f076c9d79d5e 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -41,7 +41,7 @@ static int br_pass_frame_up(struct sk_buff *skb) | |||
41 | int br_handle_frame_finish(struct sk_buff *skb) | 41 | int br_handle_frame_finish(struct sk_buff *skb) |
42 | { | 42 | { |
43 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 43 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
44 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | 44 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
45 | struct net_bridge *br; | 45 | struct net_bridge *br; |
46 | struct net_bridge_fdb_entry *dst; | 46 | struct net_bridge_fdb_entry *dst; |
47 | struct net_bridge_mdb_entry *mdst; | 47 | struct net_bridge_mdb_entry *mdst; |
@@ -111,10 +111,9 @@ drop: | |||
111 | /* note: already called with rcu_read_lock (preempt_disabled) */ | 111 | /* note: already called with rcu_read_lock (preempt_disabled) */ |
112 | static int br_handle_local_finish(struct sk_buff *skb) | 112 | static int br_handle_local_finish(struct sk_buff *skb) |
113 | { | 113 | { |
114 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | 114 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
115 | 115 | ||
116 | if (p) | 116 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source); |
117 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source); | ||
118 | return 0; /* process further */ | 117 | return 0; /* process further */ |
119 | } | 118 | } |
120 | 119 | ||
@@ -151,7 +150,7 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb) | |||
151 | if (!skb) | 150 | if (!skb) |
152 | return NULL; | 151 | return NULL; |
153 | 152 | ||
154 | p = rcu_dereference(skb->dev->br_port); | 153 | p = br_port_get_rcu(skb->dev); |
155 | 154 | ||
156 | if (unlikely(is_link_local(dest))) { | 155 | if (unlikely(is_link_local(dest))) { |
157 | /* Pause frames shouldn't be passed up by driver anyway */ | 156 | /* Pause frames shouldn't be passed up by driver anyway */ |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 0685b2558ab5..f54404ddee53 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -127,16 +127,17 @@ void br_netfilter_rtable_init(struct net_bridge *br) | |||
127 | 127 | ||
128 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) | 128 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) |
129 | { | 129 | { |
130 | struct net_bridge_port *port = rcu_dereference(dev->br_port); | 130 | if (!br_port_exists(dev)) |
131 | 131 | return NULL; | |
132 | return port ? &port->br->fake_rtable : NULL; | 132 | return &br_port_get_rcu(dev)->br->fake_rtable; |
133 | } | 133 | } |
134 | 134 | ||
135 | static inline struct net_device *bridge_parent(const struct net_device *dev) | 135 | static inline struct net_device *bridge_parent(const struct net_device *dev) |
136 | { | 136 | { |
137 | struct net_bridge_port *port = rcu_dereference(dev->br_port); | 137 | if (!br_port_exists(dev)) |
138 | return NULL; | ||
138 | 139 | ||
139 | return port ? port->br->dev : NULL; | 140 | return br_port_get_rcu(dev)->br->dev; |
140 | } | 141 | } |
141 | 142 | ||
142 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) | 143 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) |
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index fe0a79018ab2..4a6a378c84e3 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -120,10 +120,11 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
120 | idx = 0; | 120 | idx = 0; |
121 | for_each_netdev(net, dev) { | 121 | for_each_netdev(net, dev) { |
122 | /* not a bridge port */ | 122 | /* not a bridge port */ |
123 | if (dev->br_port == NULL || idx < cb->args[0]) | 123 | if (!br_port_exists(dev) || idx < cb->args[0]) |
124 | goto skip; | 124 | goto skip; |
125 | 125 | ||
126 | if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid, | 126 | if (br_fill_ifinfo(skb, br_port_get(dev), |
127 | NETLINK_CB(cb->skb).pid, | ||
127 | cb->nlh->nlmsg_seq, RTM_NEWLINK, | 128 | cb->nlh->nlmsg_seq, RTM_NEWLINK, |
128 | NLM_F_MULTI) < 0) | 129 | NLM_F_MULTI) < 0) |
129 | break; | 130 | break; |
@@ -168,9 +169,9 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
168 | if (!dev) | 169 | if (!dev) |
169 | return -ENODEV; | 170 | return -ENODEV; |
170 | 171 | ||
171 | p = dev->br_port; | 172 | if (!br_port_exists(dev)) |
172 | if (!p) | ||
173 | return -EINVAL; | 173 | return -EINVAL; |
174 | p = br_port_get(dev); | ||
174 | 175 | ||
175 | /* if kernel STP is running, don't allow changes */ | 176 | /* if kernel STP is running, don't allow changes */ |
176 | if (p->br->stp_enabled == BR_KERNEL_STP) | 177 | if (p->br->stp_enabled == BR_KERNEL_STP) |
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 717e1fd6133c..404d4e14c6a7 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c | |||
@@ -32,14 +32,15 @@ struct notifier_block br_device_notifier = { | |||
32 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) | 32 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) |
33 | { | 33 | { |
34 | struct net_device *dev = ptr; | 34 | struct net_device *dev = ptr; |
35 | struct net_bridge_port *p = dev->br_port; | 35 | struct net_bridge_port *p = br_port_get(dev); |
36 | struct net_bridge *br; | 36 | struct net_bridge *br; |
37 | int err; | 37 | int err; |
38 | 38 | ||
39 | /* not a port of a bridge */ | 39 | /* not a port of a bridge */ |
40 | if (p == NULL) | 40 | if (!br_port_exists(dev)) |
41 | return NOTIFY_DONE; | 41 | return NOTIFY_DONE; |
42 | 42 | ||
43 | p = br_port_get(dev); | ||
43 | br = p->br; | 44 | br = p->br; |
44 | 45 | ||
45 | switch (event) { | 46 | switch (event) { |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 0f5394c4f2f1..f6bc979b1135 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -150,6 +150,11 @@ struct net_bridge_port | |||
150 | #endif | 150 | #endif |
151 | }; | 151 | }; |
152 | 152 | ||
153 | #define br_port_get_rcu(dev) \ | ||
154 | ((struct net_bridge_port *) rcu_dereference(dev->rx_handler_data)) | ||
155 | #define br_port_get(dev) ((struct net_bridge_port *) dev->rx_handler_data) | ||
156 | #define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT) | ||
157 | |||
153 | struct br_cpu_netstats { | 158 | struct br_cpu_netstats { |
154 | unsigned long rx_packets; | 159 | unsigned long rx_packets; |
155 | unsigned long rx_bytes; | 160 | unsigned long rx_bytes; |
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 217bd225a42f..70aecb48fb69 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c | |||
@@ -137,12 +137,13 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, | |||
137 | struct net_device *dev) | 137 | struct net_device *dev) |
138 | { | 138 | { |
139 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 139 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
140 | struct net_bridge_port *p = rcu_dereference(dev->br_port); | 140 | struct net_bridge_port *p; |
141 | struct net_bridge *br; | 141 | struct net_bridge *br; |
142 | const unsigned char *buf; | 142 | const unsigned char *buf; |
143 | 143 | ||
144 | if (!p) | 144 | if (!br_port_exists(dev)) |
145 | goto err; | 145 | goto err; |
146 | p = br_port_get_rcu(dev); | ||
146 | 147 | ||
147 | if (!pskb_may_pull(skb, 4)) | 148 | if (!pskb_may_pull(skb, 4)) |
148 | goto err; | 149 | goto err; |
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index 9e19166ba453..46624bb6d9be 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c | |||
@@ -24,8 +24,9 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
24 | return EBT_DROP; | 24 | return EBT_DROP; |
25 | 25 | ||
26 | if (par->hooknum != NF_BR_BROUTING) | 26 | if (par->hooknum != NF_BR_BROUTING) |
27 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
27 | memcpy(eth_hdr(skb)->h_dest, | 28 | memcpy(eth_hdr(skb)->h_dest, |
28 | par->in->br_port->br->dev->dev_addr, ETH_ALEN); | 29 | br_port_get_rcu(par->in)->br->dev->dev_addr, ETH_ALEN); |
29 | else | 30 | else |
30 | memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN); | 31 | memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN); |
31 | skb->pkt_type = PACKET_HOST; | 32 | skb->pkt_type = PACKET_HOST; |
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index ae3c7cef1484..26377e96fa1c 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c | |||
@@ -177,8 +177,9 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | |||
177 | if (in) { | 177 | if (in) { |
178 | strcpy(pm->physindev, in->name); | 178 | strcpy(pm->physindev, in->name); |
179 | /* If in isn't a bridge, then physindev==indev */ | 179 | /* If in isn't a bridge, then physindev==indev */ |
180 | if (in->br_port) | 180 | if (br_port_exists(in)) |
181 | strcpy(pm->indev, in->br_port->br->dev->name); | 181 | /* rcu_read_lock()ed by nf_hook_slow */ |
182 | strcpy(pm->indev, br_port_get_rcu(in)->br->dev->name); | ||
182 | else | 183 | else |
183 | strcpy(pm->indev, in->name); | 184 | strcpy(pm->indev, in->name); |
184 | } else | 185 | } else |
@@ -187,7 +188,8 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | |||
187 | if (out) { | 188 | if (out) { |
188 | /* If out exists, then out is a bridge port */ | 189 | /* If out exists, then out is a bridge port */ |
189 | strcpy(pm->physoutdev, out->name); | 190 | strcpy(pm->physoutdev, out->name); |
190 | strcpy(pm->outdev, out->br_port->br->dev->name); | 191 | /* rcu_read_lock()ed by nf_hook_slow */ |
192 | strcpy(pm->outdev, br_port_get_rcu(out)->br->dev->name); | ||
191 | } else | 193 | } else |
192 | pm->outdev[0] = pm->physoutdev[0] = '\0'; | 194 | pm->outdev[0] = pm->physoutdev[0] = '\0'; |
193 | 195 | ||
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 59ca00e40dec..bcc102e3be4d 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -140,11 +140,14 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h, | |||
140 | return 1; | 140 | return 1; |
141 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) | 141 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) |
142 | return 1; | 142 | return 1; |
143 | if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check( | 143 | /* rcu_read_lock()ed by nf_hook_slow */ |
144 | e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN)) | 144 | if (in && br_port_exists(in) && |
145 | FWINV2(ebt_dev_check(e->logical_in, br_port_get_rcu(in)->br->dev), | ||
146 | EBT_ILOGICALIN)) | ||
145 | return 1; | 147 | return 1; |
146 | if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check( | 148 | if (out && br_port_exists(out) && |
147 | e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT)) | 149 | FWINV2(ebt_dev_check(e->logical_out, br_port_get_rcu(out)->br->dev), |
150 | EBT_ILOGICALOUT)) | ||
148 | return 1; | 151 | return 1; |
149 | 152 | ||
150 | if (e->bitmask & EBT_SOURCEMAC) { | 153 | if (e->bitmask & EBT_SOURCEMAC) { |