diff options
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r-- | net/switchdev/switchdev.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index f34e535e93bd..47f7da58a7f0 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/list.h> | 20 | #include <linux/list.h> |
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <linux/if_vlan.h> | 22 | #include <linux/if_vlan.h> |
23 | #include <linux/rtnetlink.h> | ||
23 | #include <net/ip_fib.h> | 24 | #include <net/ip_fib.h> |
24 | #include <net/switchdev.h> | 25 | #include <net/switchdev.h> |
25 | 26 | ||
@@ -345,6 +346,8 @@ static size_t switchdev_obj_size(const struct switchdev_obj *obj) | |||
345 | return sizeof(struct switchdev_obj_ipv4_fib); | 346 | return sizeof(struct switchdev_obj_ipv4_fib); |
346 | case SWITCHDEV_OBJ_ID_PORT_FDB: | 347 | case SWITCHDEV_OBJ_ID_PORT_FDB: |
347 | return sizeof(struct switchdev_obj_port_fdb); | 348 | return sizeof(struct switchdev_obj_port_fdb); |
349 | case SWITCHDEV_OBJ_ID_PORT_MDB: | ||
350 | return sizeof(struct switchdev_obj_port_mdb); | ||
348 | default: | 351 | default: |
349 | BUG(); | 352 | BUG(); |
350 | } | 353 | } |
@@ -565,7 +568,6 @@ int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, | |||
565 | } | 568 | } |
566 | EXPORT_SYMBOL_GPL(switchdev_port_obj_dump); | 569 | EXPORT_SYMBOL_GPL(switchdev_port_obj_dump); |
567 | 570 | ||
568 | static DEFINE_MUTEX(switchdev_mutex); | ||
569 | static RAW_NOTIFIER_HEAD(switchdev_notif_chain); | 571 | static RAW_NOTIFIER_HEAD(switchdev_notif_chain); |
570 | 572 | ||
571 | /** | 573 | /** |
@@ -580,9 +582,9 @@ int register_switchdev_notifier(struct notifier_block *nb) | |||
580 | { | 582 | { |
581 | int err; | 583 | int err; |
582 | 584 | ||
583 | mutex_lock(&switchdev_mutex); | 585 | rtnl_lock(); |
584 | err = raw_notifier_chain_register(&switchdev_notif_chain, nb); | 586 | err = raw_notifier_chain_register(&switchdev_notif_chain, nb); |
585 | mutex_unlock(&switchdev_mutex); | 587 | rtnl_unlock(); |
586 | return err; | 588 | return err; |
587 | } | 589 | } |
588 | EXPORT_SYMBOL_GPL(register_switchdev_notifier); | 590 | EXPORT_SYMBOL_GPL(register_switchdev_notifier); |
@@ -598,9 +600,9 @@ int unregister_switchdev_notifier(struct notifier_block *nb) | |||
598 | { | 600 | { |
599 | int err; | 601 | int err; |
600 | 602 | ||
601 | mutex_lock(&switchdev_mutex); | 603 | rtnl_lock(); |
602 | err = raw_notifier_chain_unregister(&switchdev_notif_chain, nb); | 604 | err = raw_notifier_chain_unregister(&switchdev_notif_chain, nb); |
603 | mutex_unlock(&switchdev_mutex); | 605 | rtnl_unlock(); |
604 | return err; | 606 | return err; |
605 | } | 607 | } |
606 | EXPORT_SYMBOL_GPL(unregister_switchdev_notifier); | 608 | EXPORT_SYMBOL_GPL(unregister_switchdev_notifier); |
@@ -614,16 +616,17 @@ EXPORT_SYMBOL_GPL(unregister_switchdev_notifier); | |||
614 | * Call all network notifier blocks. This should be called by driver | 616 | * Call all network notifier blocks. This should be called by driver |
615 | * when it needs to propagate hardware event. | 617 | * when it needs to propagate hardware event. |
616 | * Return values are same as for atomic_notifier_call_chain(). | 618 | * Return values are same as for atomic_notifier_call_chain(). |
619 | * rtnl_lock must be held. | ||
617 | */ | 620 | */ |
618 | int call_switchdev_notifiers(unsigned long val, struct net_device *dev, | 621 | int call_switchdev_notifiers(unsigned long val, struct net_device *dev, |
619 | struct switchdev_notifier_info *info) | 622 | struct switchdev_notifier_info *info) |
620 | { | 623 | { |
621 | int err; | 624 | int err; |
622 | 625 | ||
626 | ASSERT_RTNL(); | ||
627 | |||
623 | info->dev = dev; | 628 | info->dev = dev; |
624 | mutex_lock(&switchdev_mutex); | ||
625 | err = raw_notifier_call_chain(&switchdev_notif_chain, val, info); | 629 | err = raw_notifier_call_chain(&switchdev_notif_chain, val, info); |
626 | mutex_unlock(&switchdev_mutex); | ||
627 | return err; | 630 | return err; |
628 | } | 631 | } |
629 | EXPORT_SYMBOL_GPL(call_switchdev_notifiers); | 632 | EXPORT_SYMBOL_GPL(call_switchdev_notifiers); |
@@ -723,6 +726,7 @@ static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, | |||
723 | u32 filter_mask) | 726 | u32 filter_mask) |
724 | { | 727 | { |
725 | struct switchdev_vlan_dump dump = { | 728 | struct switchdev_vlan_dump dump = { |
729 | .vlan.obj.orig_dev = dev, | ||
726 | .vlan.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, | 730 | .vlan.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, |
727 | .skb = skb, | 731 | .skb = skb, |
728 | .filter_mask = filter_mask, | 732 | .filter_mask = filter_mask, |
@@ -757,6 +761,7 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, | |||
757 | int nlflags) | 761 | int nlflags) |
758 | { | 762 | { |
759 | struct switchdev_attr attr = { | 763 | struct switchdev_attr attr = { |
764 | .orig_dev = dev, | ||
760 | .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, | 765 | .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, |
761 | }; | 766 | }; |
762 | u16 mode = BRIDGE_MODE_UNDEF; | 767 | u16 mode = BRIDGE_MODE_UNDEF; |
@@ -778,6 +783,7 @@ static int switchdev_port_br_setflag(struct net_device *dev, | |||
778 | unsigned long brport_flag) | 783 | unsigned long brport_flag) |
779 | { | 784 | { |
780 | struct switchdev_attr attr = { | 785 | struct switchdev_attr attr = { |
786 | .orig_dev = dev, | ||
781 | .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, | 787 | .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, |
782 | }; | 788 | }; |
783 | u8 flag = nla_get_u8(nlattr); | 789 | u8 flag = nla_get_u8(nlattr); |
@@ -853,6 +859,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, | |||
853 | struct nlattr *attr; | 859 | struct nlattr *attr; |
854 | struct bridge_vlan_info *vinfo; | 860 | struct bridge_vlan_info *vinfo; |
855 | struct switchdev_obj_port_vlan vlan = { | 861 | struct switchdev_obj_port_vlan vlan = { |
862 | .obj.orig_dev = dev, | ||
856 | .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, | 863 | .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, |
857 | }; | 864 | }; |
858 | int rem; | 865 | int rem; |
@@ -975,6 +982,7 @@ int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | |||
975 | u16 vid, u16 nlm_flags) | 982 | u16 vid, u16 nlm_flags) |
976 | { | 983 | { |
977 | struct switchdev_obj_port_fdb fdb = { | 984 | struct switchdev_obj_port_fdb fdb = { |
985 | .obj.orig_dev = dev, | ||
978 | .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, | 986 | .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, |
979 | .vid = vid, | 987 | .vid = vid, |
980 | }; | 988 | }; |
@@ -1000,6 +1008,7 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], | |||
1000 | u16 vid) | 1008 | u16 vid) |
1001 | { | 1009 | { |
1002 | struct switchdev_obj_port_fdb fdb = { | 1010 | struct switchdev_obj_port_fdb fdb = { |
1011 | .obj.orig_dev = dev, | ||
1003 | .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, | 1012 | .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, |
1004 | .vid = vid, | 1013 | .vid = vid, |
1005 | }; | 1014 | }; |
@@ -1077,6 +1086,7 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | |||
1077 | struct net_device *filter_dev, int idx) | 1086 | struct net_device *filter_dev, int idx) |
1078 | { | 1087 | { |
1079 | struct switchdev_fdb_dump dump = { | 1088 | struct switchdev_fdb_dump dump = { |
1089 | .fdb.obj.orig_dev = dev, | ||
1080 | .fdb.obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, | 1090 | .fdb.obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, |
1081 | .dev = dev, | 1091 | .dev = dev, |
1082 | .skb = skb, | 1092 | .skb = skb, |
@@ -1135,6 +1145,7 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) | |||
1135 | if (!dev) | 1145 | if (!dev) |
1136 | return NULL; | 1146 | return NULL; |
1137 | 1147 | ||
1148 | attr.orig_dev = dev; | ||
1138 | if (switchdev_port_attr_get(dev, &attr)) | 1149 | if (switchdev_port_attr_get(dev, &attr)) |
1139 | return NULL; | 1150 | return NULL; |
1140 | 1151 | ||
@@ -1194,6 +1205,7 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, | |||
1194 | if (!dev) | 1205 | if (!dev) |
1195 | return 0; | 1206 | return 0; |
1196 | 1207 | ||
1208 | ipv4_fib.obj.orig_dev = dev; | ||
1197 | err = switchdev_port_obj_add(dev, &ipv4_fib.obj); | 1209 | err = switchdev_port_obj_add(dev, &ipv4_fib.obj); |
1198 | if (!err) | 1210 | if (!err) |
1199 | fi->fib_flags |= RTNH_F_OFFLOAD; | 1211 | fi->fib_flags |= RTNH_F_OFFLOAD; |
@@ -1238,6 +1250,7 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, | |||
1238 | if (!dev) | 1250 | if (!dev) |
1239 | return 0; | 1251 | return 0; |
1240 | 1252 | ||
1253 | ipv4_fib.obj.orig_dev = dev; | ||
1241 | err = switchdev_port_obj_del(dev, &ipv4_fib.obj); | 1254 | err = switchdev_port_obj_del(dev, &ipv4_fib.obj); |
1242 | if (!err) | 1255 | if (!err) |
1243 | fi->fib_flags &= ~RTNH_F_OFFLOAD; | 1256 | fi->fib_flags &= ~RTNH_F_OFFLOAD; |
@@ -1270,10 +1283,12 @@ static bool switchdev_port_same_parent_id(struct net_device *a, | |||
1270 | struct net_device *b) | 1283 | struct net_device *b) |
1271 | { | 1284 | { |
1272 | struct switchdev_attr a_attr = { | 1285 | struct switchdev_attr a_attr = { |
1286 | .orig_dev = a, | ||
1273 | .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, | 1287 | .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, |
1274 | .flags = SWITCHDEV_F_NO_RECURSE, | 1288 | .flags = SWITCHDEV_F_NO_RECURSE, |
1275 | }; | 1289 | }; |
1276 | struct switchdev_attr b_attr = { | 1290 | struct switchdev_attr b_attr = { |
1291 | .orig_dev = b, | ||
1277 | .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, | 1292 | .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, |
1278 | .flags = SWITCHDEV_F_NO_RECURSE, | 1293 | .flags = SWITCHDEV_F_NO_RECURSE, |
1279 | }; | 1294 | }; |