diff options
-rw-r--r-- | include/uapi/linux/if_vlan.h | 9 | ||||
-rw-r--r-- | net/8021q/vlan.c | 18 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 22 | ||||
-rw-r--r-- | net/8021q/vlan_netlink.c | 3 | ||||
-rw-r--r-- | net/bridge/br.c | 13 | ||||
-rw-r--r-- | net/bridge/br_private.h | 14 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 214 |
7 files changed, 272 insertions, 21 deletions
diff --git a/include/uapi/linux/if_vlan.h b/include/uapi/linux/if_vlan.h index 7a0e8bd65b6b..90a2c89afc8f 100644 --- a/include/uapi/linux/if_vlan.h +++ b/include/uapi/linux/if_vlan.h | |||
@@ -32,10 +32,11 @@ enum vlan_ioctl_cmds { | |||
32 | }; | 32 | }; |
33 | 33 | ||
34 | enum vlan_flags { | 34 | enum vlan_flags { |
35 | VLAN_FLAG_REORDER_HDR = 0x1, | 35 | VLAN_FLAG_REORDER_HDR = 0x1, |
36 | VLAN_FLAG_GVRP = 0x2, | 36 | VLAN_FLAG_GVRP = 0x2, |
37 | VLAN_FLAG_LOOSE_BINDING = 0x4, | 37 | VLAN_FLAG_LOOSE_BINDING = 0x4, |
38 | VLAN_FLAG_MVRP = 0x8, | 38 | VLAN_FLAG_MVRP = 0x8, |
39 | VLAN_FLAG_BRIDGE_BINDING = 0x10, | ||
39 | }; | 40 | }; |
40 | 41 | ||
41 | enum vlan_name_types { | 42 | enum vlan_name_types { |
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index dc4411165e43..1f99678751df 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -75,6 +75,14 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, | |||
75 | return 0; | 75 | return 0; |
76 | } | 76 | } |
77 | 77 | ||
78 | static void vlan_stacked_transfer_operstate(const struct net_device *rootdev, | ||
79 | struct net_device *dev, | ||
80 | struct vlan_dev_priv *vlan) | ||
81 | { | ||
82 | if (!(vlan->flags & VLAN_FLAG_BRIDGE_BINDING)) | ||
83 | netif_stacked_transfer_operstate(rootdev, dev); | ||
84 | } | ||
85 | |||
78 | void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | 86 | void unregister_vlan_dev(struct net_device *dev, struct list_head *head) |
79 | { | 87 | { |
80 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); | 88 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
@@ -180,7 +188,7 @@ int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack) | |||
180 | /* Account for reference in struct vlan_dev_priv */ | 188 | /* Account for reference in struct vlan_dev_priv */ |
181 | dev_hold(real_dev); | 189 | dev_hold(real_dev); |
182 | 190 | ||
183 | netif_stacked_transfer_operstate(real_dev, dev); | 191 | vlan_stacked_transfer_operstate(real_dev, dev, vlan); |
184 | linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ | 192 | linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ |
185 | 193 | ||
186 | /* So, got the sucker initialized, now lets place | 194 | /* So, got the sucker initialized, now lets place |
@@ -399,7 +407,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
399 | case NETDEV_CHANGE: | 407 | case NETDEV_CHANGE: |
400 | /* Propagate real device state to vlan devices */ | 408 | /* Propagate real device state to vlan devices */ |
401 | vlan_group_for_each_dev(grp, i, vlandev) | 409 | vlan_group_for_each_dev(grp, i, vlandev) |
402 | netif_stacked_transfer_operstate(dev, vlandev); | 410 | vlan_stacked_transfer_operstate(dev, vlandev, |
411 | vlan_dev_priv(vlandev)); | ||
403 | break; | 412 | break; |
404 | 413 | ||
405 | case NETDEV_CHANGEADDR: | 414 | case NETDEV_CHANGEADDR: |
@@ -446,7 +455,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
446 | dev_close_many(&close_list, false); | 455 | dev_close_many(&close_list, false); |
447 | 456 | ||
448 | list_for_each_entry_safe(vlandev, tmp, &close_list, close_list) { | 457 | list_for_each_entry_safe(vlandev, tmp, &close_list, close_list) { |
449 | netif_stacked_transfer_operstate(dev, vlandev); | 458 | vlan_stacked_transfer_operstate(dev, vlandev, |
459 | vlan_dev_priv(vlandev)); | ||
450 | list_del_init(&vlandev->close_list); | 460 | list_del_init(&vlandev->close_list); |
451 | } | 461 | } |
452 | list_del(&close_list); | 462 | list_del(&close_list); |
@@ -463,7 +473,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
463 | if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) | 473 | if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) |
464 | dev_change_flags(vlandev, flgs | IFF_UP, | 474 | dev_change_flags(vlandev, flgs | IFF_UP, |
465 | extack); | 475 | extack); |
466 | netif_stacked_transfer_operstate(dev, vlandev); | 476 | vlan_stacked_transfer_operstate(dev, vlandev, vlan); |
467 | } | 477 | } |
468 | break; | 478 | break; |
469 | 479 | ||
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 8d77b6ee4477..f044ae56a313 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -223,7 +223,8 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask) | |||
223 | u32 old_flags = vlan->flags; | 223 | u32 old_flags = vlan->flags; |
224 | 224 | ||
225 | if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | | 225 | if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | |
226 | VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP)) | 226 | VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP | |
227 | VLAN_FLAG_BRIDGE_BINDING)) | ||
227 | return -EINVAL; | 228 | return -EINVAL; |
228 | 229 | ||
229 | vlan->flags = (old_flags & ~mask) | (flags & mask); | 230 | vlan->flags = (old_flags & ~mask) | (flags & mask); |
@@ -296,7 +297,8 @@ static int vlan_dev_open(struct net_device *dev) | |||
296 | if (vlan->flags & VLAN_FLAG_MVRP) | 297 | if (vlan->flags & VLAN_FLAG_MVRP) |
297 | vlan_mvrp_request_join(dev); | 298 | vlan_mvrp_request_join(dev); |
298 | 299 | ||
299 | if (netif_carrier_ok(real_dev)) | 300 | if (netif_carrier_ok(real_dev) && |
301 | !(vlan->flags & VLAN_FLAG_BRIDGE_BINDING)) | ||
300 | netif_carrier_on(dev); | 302 | netif_carrier_on(dev); |
301 | return 0; | 303 | return 0; |
302 | 304 | ||
@@ -326,7 +328,8 @@ static int vlan_dev_stop(struct net_device *dev) | |||
326 | if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) | 328 | if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) |
327 | dev_uc_del(real_dev, dev->dev_addr); | 329 | dev_uc_del(real_dev, dev->dev_addr); |
328 | 330 | ||
329 | netif_carrier_off(dev); | 331 | if (!(vlan->flags & VLAN_FLAG_BRIDGE_BINDING)) |
332 | netif_carrier_off(dev); | ||
330 | return 0; | 333 | return 0; |
331 | } | 334 | } |
332 | 335 | ||
@@ -550,7 +553,8 @@ static const struct net_device_ops vlan_netdev_ops; | |||
550 | 553 | ||
551 | static int vlan_dev_init(struct net_device *dev) | 554 | static int vlan_dev_init(struct net_device *dev) |
552 | { | 555 | { |
553 | struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; | 556 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
557 | struct net_device *real_dev = vlan->real_dev; | ||
554 | 558 | ||
555 | netif_carrier_off(dev); | 559 | netif_carrier_off(dev); |
556 | 560 | ||
@@ -561,6 +565,9 @@ static int vlan_dev_init(struct net_device *dev) | |||
561 | (1<<__LINK_STATE_DORMANT))) | | 565 | (1<<__LINK_STATE_DORMANT))) | |
562 | (1<<__LINK_STATE_PRESENT); | 566 | (1<<__LINK_STATE_PRESENT); |
563 | 567 | ||
568 | if (vlan->flags & VLAN_FLAG_BRIDGE_BINDING) | ||
569 | dev->state |= (1 << __LINK_STATE_NOCARRIER); | ||
570 | |||
564 | dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | | 571 | dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | |
565 | NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | | 572 | NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | |
566 | NETIF_F_GSO_ENCAP_ALL | | 573 | NETIF_F_GSO_ENCAP_ALL | |
@@ -591,8 +598,7 @@ static int vlan_dev_init(struct net_device *dev) | |||
591 | #endif | 598 | #endif |
592 | 599 | ||
593 | dev->needed_headroom = real_dev->needed_headroom; | 600 | dev->needed_headroom = real_dev->needed_headroom; |
594 | if (vlan_hw_offload_capable(real_dev->features, | 601 | if (vlan_hw_offload_capable(real_dev->features, vlan->vlan_proto)) { |
595 | vlan_dev_priv(dev)->vlan_proto)) { | ||
596 | dev->header_ops = &vlan_passthru_header_ops; | 602 | dev->header_ops = &vlan_passthru_header_ops; |
597 | dev->hard_header_len = real_dev->hard_header_len; | 603 | dev->hard_header_len = real_dev->hard_header_len; |
598 | } else { | 604 | } else { |
@@ -606,8 +612,8 @@ static int vlan_dev_init(struct net_device *dev) | |||
606 | 612 | ||
607 | vlan_dev_set_lockdep_class(dev, vlan_dev_get_lock_subclass(dev)); | 613 | vlan_dev_set_lockdep_class(dev, vlan_dev_get_lock_subclass(dev)); |
608 | 614 | ||
609 | vlan_dev_priv(dev)->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats); | 615 | vlan->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats); |
610 | if (!vlan_dev_priv(dev)->vlan_pcpu_stats) | 616 | if (!vlan->vlan_pcpu_stats) |
611 | return -ENOMEM; | 617 | return -ENOMEM; |
612 | 618 | ||
613 | return 0; | 619 | return 0; |
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 9b60c1e399e2..a624dccf68fd 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c | |||
@@ -84,7 +84,8 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[], | |||
84 | flags = nla_data(data[IFLA_VLAN_FLAGS]); | 84 | flags = nla_data(data[IFLA_VLAN_FLAGS]); |
85 | if ((flags->flags & flags->mask) & | 85 | if ((flags->flags & flags->mask) & |
86 | ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | | 86 | ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | |
87 | VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP)) { | 87 | VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP | |
88 | VLAN_FLAG_BRIDGE_BINDING)) { | ||
88 | NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN flags"); | 89 | NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN flags"); |
89 | return -EINVAL; | 90 | return -EINVAL; |
90 | } | 91 | } |
diff --git a/net/bridge/br.c b/net/bridge/br.c index a5174e5001d8..e69fc87a13e0 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
@@ -40,10 +40,13 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v | |||
40 | bool changed_addr; | 40 | bool changed_addr; |
41 | int err; | 41 | int err; |
42 | 42 | ||
43 | /* register of bridge completed, add sysfs entries */ | 43 | if (dev->priv_flags & IFF_EBRIDGE) { |
44 | if ((dev->priv_flags & IFF_EBRIDGE) && event == NETDEV_REGISTER) { | 44 | if (event == NETDEV_REGISTER) { |
45 | br_sysfs_addbr(dev); | 45 | /* register of bridge completed, add sysfs entries */ |
46 | return NOTIFY_DONE; | 46 | br_sysfs_addbr(dev); |
47 | return NOTIFY_DONE; | ||
48 | } | ||
49 | br_vlan_bridge_event(dev, event, ptr); | ||
47 | } | 50 | } |
48 | 51 | ||
49 | /* not a port of a bridge */ | 52 | /* not a port of a bridge */ |
@@ -126,6 +129,8 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v | |||
126 | break; | 129 | break; |
127 | } | 130 | } |
128 | 131 | ||
132 | br_vlan_port_event(p, event); | ||
133 | |||
129 | /* Events that may cause spanning tree to refresh */ | 134 | /* Events that may cause spanning tree to refresh */ |
130 | if (!notified && (event == NETDEV_CHANGEADDR || event == NETDEV_UP || | 135 | if (!notified && (event == NETDEV_CHANGEADDR || event == NETDEV_UP || |
131 | event == NETDEV_CHANGE || event == NETDEV_DOWN)) | 136 | event == NETDEV_CHANGE || event == NETDEV_DOWN)) |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 4bea2f11da9b..334a8c496b50 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -321,6 +321,7 @@ enum net_bridge_opts { | |||
321 | BROPT_MTU_SET_BY_USER, | 321 | BROPT_MTU_SET_BY_USER, |
322 | BROPT_VLAN_STATS_PER_PORT, | 322 | BROPT_VLAN_STATS_PER_PORT, |
323 | BROPT_NO_LL_LEARN, | 323 | BROPT_NO_LL_LEARN, |
324 | BROPT_VLAN_BRIDGE_BINDING, | ||
324 | }; | 325 | }; |
325 | 326 | ||
326 | struct net_bridge { | 327 | struct net_bridge { |
@@ -895,6 +896,9 @@ int nbp_vlan_init(struct net_bridge_port *port, struct netlink_ext_ack *extack); | |||
895 | int nbp_get_num_vlan_infos(struct net_bridge_port *p, u32 filter_mask); | 896 | int nbp_get_num_vlan_infos(struct net_bridge_port *p, u32 filter_mask); |
896 | void br_vlan_get_stats(const struct net_bridge_vlan *v, | 897 | void br_vlan_get_stats(const struct net_bridge_vlan *v, |
897 | struct br_vlan_stats *stats); | 898 | struct br_vlan_stats *stats); |
899 | void br_vlan_port_event(struct net_bridge_port *p, unsigned long event); | ||
900 | void br_vlan_bridge_event(struct net_device *dev, unsigned long event, | ||
901 | void *ptr); | ||
898 | 902 | ||
899 | static inline struct net_bridge_vlan_group *br_vlan_group( | 903 | static inline struct net_bridge_vlan_group *br_vlan_group( |
900 | const struct net_bridge *br) | 904 | const struct net_bridge *br) |
@@ -1078,6 +1082,16 @@ static inline void br_vlan_get_stats(const struct net_bridge_vlan *v, | |||
1078 | struct br_vlan_stats *stats) | 1082 | struct br_vlan_stats *stats) |
1079 | { | 1083 | { |
1080 | } | 1084 | } |
1085 | |||
1086 | static inline void br_vlan_port_event(struct net_bridge_port *p, | ||
1087 | unsigned long event) | ||
1088 | { | ||
1089 | } | ||
1090 | |||
1091 | static inline void br_vlan_bridge_event(struct net_device *dev, | ||
1092 | unsigned long event, void *ptr) | ||
1093 | { | ||
1094 | } | ||
1081 | #endif | 1095 | #endif |
1082 | 1096 | ||
1083 | struct nf_br_ops { | 1097 | struct nf_br_ops { |
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 0a02822b5667..2db63997f313 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c | |||
@@ -7,6 +7,8 @@ | |||
7 | #include "br_private.h" | 7 | #include "br_private.h" |
8 | #include "br_private_tunnel.h" | 8 | #include "br_private_tunnel.h" |
9 | 9 | ||
10 | static void nbp_vlan_set_vlan_dev_state(struct net_bridge_port *p, u16 vid); | ||
11 | |||
10 | static inline int br_vlan_cmp(struct rhashtable_compare_arg *arg, | 12 | static inline int br_vlan_cmp(struct rhashtable_compare_arg *arg, |
11 | const void *ptr) | 13 | const void *ptr) |
12 | { | 14 | { |
@@ -293,6 +295,9 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags, | |||
293 | 295 | ||
294 | __vlan_add_list(v); | 296 | __vlan_add_list(v); |
295 | __vlan_add_flags(v, flags); | 297 | __vlan_add_flags(v, flags); |
298 | |||
299 | if (p) | ||
300 | nbp_vlan_set_vlan_dev_state(p, v->vid); | ||
296 | out: | 301 | out: |
297 | return err; | 302 | return err; |
298 | 303 | ||
@@ -357,6 +362,7 @@ static int __vlan_del(struct net_bridge_vlan *v) | |||
357 | rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, | 362 | rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, |
358 | br_vlan_rht_params); | 363 | br_vlan_rht_params); |
359 | __vlan_del_list(v); | 364 | __vlan_del_list(v); |
365 | nbp_vlan_set_vlan_dev_state(p, v->vid); | ||
360 | call_rcu(&v->rcu, nbp_vlan_rcu_free); | 366 | call_rcu(&v->rcu, nbp_vlan_rcu_free); |
361 | } | 367 | } |
362 | 368 | ||
@@ -1264,3 +1270,211 @@ int br_vlan_get_info(const struct net_device *dev, u16 vid, | |||
1264 | return 0; | 1270 | return 0; |
1265 | } | 1271 | } |
1266 | EXPORT_SYMBOL_GPL(br_vlan_get_info); | 1272 | EXPORT_SYMBOL_GPL(br_vlan_get_info); |
1273 | |||
1274 | static int br_vlan_is_bind_vlan_dev(const struct net_device *dev) | ||
1275 | { | ||
1276 | return is_vlan_dev(dev) && | ||
1277 | !!(vlan_dev_priv(dev)->flags & VLAN_FLAG_BRIDGE_BINDING); | ||
1278 | } | ||
1279 | |||
1280 | static int br_vlan_is_bind_vlan_dev_fn(struct net_device *dev, | ||
1281 | __always_unused void *data) | ||
1282 | { | ||
1283 | return br_vlan_is_bind_vlan_dev(dev); | ||
1284 | } | ||
1285 | |||
1286 | static bool br_vlan_has_upper_bind_vlan_dev(struct net_device *dev) | ||
1287 | { | ||
1288 | int found; | ||
1289 | |||
1290 | rcu_read_lock(); | ||
1291 | found = netdev_walk_all_upper_dev_rcu(dev, br_vlan_is_bind_vlan_dev_fn, | ||
1292 | NULL); | ||
1293 | rcu_read_unlock(); | ||
1294 | |||
1295 | return !!found; | ||
1296 | } | ||
1297 | |||
1298 | struct br_vlan_bind_walk_data { | ||
1299 | u16 vid; | ||
1300 | struct net_device *result; | ||
1301 | }; | ||
1302 | |||
1303 | static int br_vlan_match_bind_vlan_dev_fn(struct net_device *dev, | ||
1304 | void *data_in) | ||
1305 | { | ||
1306 | struct br_vlan_bind_walk_data *data = data_in; | ||
1307 | int found = 0; | ||
1308 | |||
1309 | if (br_vlan_is_bind_vlan_dev(dev) && | ||
1310 | vlan_dev_priv(dev)->vlan_id == data->vid) { | ||
1311 | data->result = dev; | ||
1312 | found = 1; | ||
1313 | } | ||
1314 | |||
1315 | return found; | ||
1316 | } | ||
1317 | |||
1318 | static struct net_device * | ||
1319 | br_vlan_get_upper_bind_vlan_dev(struct net_device *dev, u16 vid) | ||
1320 | { | ||
1321 | struct br_vlan_bind_walk_data data = { | ||
1322 | .vid = vid, | ||
1323 | }; | ||
1324 | |||
1325 | rcu_read_lock(); | ||
1326 | netdev_walk_all_upper_dev_rcu(dev, br_vlan_match_bind_vlan_dev_fn, | ||
1327 | &data); | ||
1328 | rcu_read_unlock(); | ||
1329 | |||
1330 | return data.result; | ||
1331 | } | ||
1332 | |||
1333 | static bool br_vlan_is_dev_up(const struct net_device *dev) | ||
1334 | { | ||
1335 | return !!(dev->flags & IFF_UP) && netif_oper_up(dev); | ||
1336 | } | ||
1337 | |||
1338 | static void br_vlan_set_vlan_dev_state(const struct net_bridge *br, | ||
1339 | struct net_device *vlan_dev) | ||
1340 | { | ||
1341 | u16 vid = vlan_dev_priv(vlan_dev)->vlan_id; | ||
1342 | struct net_bridge_vlan_group *vg; | ||
1343 | struct net_bridge_port *p; | ||
1344 | bool has_carrier = false; | ||
1345 | |||
1346 | if (!netif_carrier_ok(br->dev)) { | ||
1347 | netif_carrier_off(vlan_dev); | ||
1348 | return; | ||
1349 | } | ||
1350 | |||
1351 | list_for_each_entry(p, &br->port_list, list) { | ||
1352 | vg = nbp_vlan_group(p); | ||
1353 | if (br_vlan_find(vg, vid) && br_vlan_is_dev_up(p->dev)) { | ||
1354 | has_carrier = true; | ||
1355 | break; | ||
1356 | } | ||
1357 | } | ||
1358 | |||
1359 | if (has_carrier) | ||
1360 | netif_carrier_on(vlan_dev); | ||
1361 | else | ||
1362 | netif_carrier_off(vlan_dev); | ||
1363 | } | ||
1364 | |||
1365 | static void br_vlan_set_all_vlan_dev_state(struct net_bridge_port *p) | ||
1366 | { | ||
1367 | struct net_bridge_vlan_group *vg = nbp_vlan_group(p); | ||
1368 | struct net_bridge_vlan *vlan; | ||
1369 | struct net_device *vlan_dev; | ||
1370 | |||
1371 | list_for_each_entry(vlan, &vg->vlan_list, vlist) { | ||
1372 | vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev, | ||
1373 | vlan->vid); | ||
1374 | if (vlan_dev) { | ||
1375 | if (br_vlan_is_dev_up(p->dev)) { | ||
1376 | if (netif_carrier_ok(p->br->dev)) | ||
1377 | netif_carrier_on(vlan_dev); | ||
1378 | } else { | ||
1379 | br_vlan_set_vlan_dev_state(p->br, vlan_dev); | ||
1380 | } | ||
1381 | } | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | static void br_vlan_upper_change(struct net_device *dev, | ||
1386 | struct net_device *upper_dev, | ||
1387 | bool linking) | ||
1388 | { | ||
1389 | struct net_bridge *br = netdev_priv(dev); | ||
1390 | |||
1391 | if (!br_vlan_is_bind_vlan_dev(upper_dev)) | ||
1392 | return; | ||
1393 | |||
1394 | if (linking) { | ||
1395 | br_vlan_set_vlan_dev_state(br, upper_dev); | ||
1396 | br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING, true); | ||
1397 | } else { | ||
1398 | br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING, | ||
1399 | br_vlan_has_upper_bind_vlan_dev(dev)); | ||
1400 | } | ||
1401 | } | ||
1402 | |||
1403 | struct br_vlan_link_state_walk_data { | ||
1404 | struct net_bridge *br; | ||
1405 | }; | ||
1406 | |||
1407 | static int br_vlan_link_state_change_fn(struct net_device *vlan_dev, | ||
1408 | void *data_in) | ||
1409 | { | ||
1410 | struct br_vlan_link_state_walk_data *data = data_in; | ||
1411 | |||
1412 | if (br_vlan_is_bind_vlan_dev(vlan_dev)) | ||
1413 | br_vlan_set_vlan_dev_state(data->br, vlan_dev); | ||
1414 | |||
1415 | return 0; | ||
1416 | } | ||
1417 | |||
1418 | static void br_vlan_link_state_change(struct net_device *dev, | ||
1419 | struct net_bridge *br) | ||
1420 | { | ||
1421 | struct br_vlan_link_state_walk_data data = { | ||
1422 | .br = br | ||
1423 | }; | ||
1424 | |||
1425 | rcu_read_lock(); | ||
1426 | netdev_walk_all_upper_dev_rcu(dev, br_vlan_link_state_change_fn, | ||
1427 | &data); | ||
1428 | rcu_read_unlock(); | ||
1429 | } | ||
1430 | |||
1431 | /* Must be protected by RTNL. */ | ||
1432 | static void nbp_vlan_set_vlan_dev_state(struct net_bridge_port *p, u16 vid) | ||
1433 | { | ||
1434 | struct net_device *vlan_dev; | ||
1435 | |||
1436 | if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING)) | ||
1437 | return; | ||
1438 | |||
1439 | vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev, vid); | ||
1440 | if (vlan_dev) | ||
1441 | br_vlan_set_vlan_dev_state(p->br, vlan_dev); | ||
1442 | } | ||
1443 | |||
1444 | /* Must be protected by RTNL. */ | ||
1445 | void br_vlan_bridge_event(struct net_device *dev, unsigned long event, | ||
1446 | void *ptr) | ||
1447 | { | ||
1448 | struct netdev_notifier_changeupper_info *info; | ||
1449 | struct net_bridge *br; | ||
1450 | |||
1451 | switch (event) { | ||
1452 | case NETDEV_CHANGEUPPER: | ||
1453 | info = ptr; | ||
1454 | br_vlan_upper_change(dev, info->upper_dev, info->linking); | ||
1455 | break; | ||
1456 | |||
1457 | case NETDEV_CHANGE: | ||
1458 | case NETDEV_UP: | ||
1459 | br = netdev_priv(dev); | ||
1460 | if (!br_opt_get(br, BROPT_VLAN_BRIDGE_BINDING)) | ||
1461 | return; | ||
1462 | br_vlan_link_state_change(dev, br); | ||
1463 | break; | ||
1464 | } | ||
1465 | } | ||
1466 | |||
1467 | /* Must be protected by RTNL. */ | ||
1468 | void br_vlan_port_event(struct net_bridge_port *p, unsigned long event) | ||
1469 | { | ||
1470 | if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING)) | ||
1471 | return; | ||
1472 | |||
1473 | switch (event) { | ||
1474 | case NETDEV_CHANGE: | ||
1475 | case NETDEV_DOWN: | ||
1476 | case NETDEV_UP: | ||
1477 | br_vlan_set_all_vlan_dev_state(p); | ||
1478 | break; | ||
1479 | } | ||
1480 | } | ||