Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: make cross-chip notifiers more efficient for host events

To determine whether a given port should react to the port targeted by
the notifier, dsa_port_host_vlan_match() and dsa_port_host_address_match()
look at the positioning of the switch port currently executing the
notifier relative to the switch port for which the notifier was emitted.

To maintain stylistic compatibility with the other match functions from
switch.c, the host address and host VLAN match functions take the
notifier information about targeted port, switch and tree indices as
argument. However, these functions only use that information to retrieve
the struct dsa_port *targeted_dp, which is an invariant for the outer
loop that calls them. So it makes more sense to calculate the targeted
dp only once, and pass it to them as argument.

But furthermore, the targeted dp is actually known at the time the call
to dsa_port_notify() is made. It is just that we decide to only save the
indices of the port, switch and tree in the notifier structure, just to
retrace our steps and find the dp again using dsa_switch_find() and
dsa_to_port().

But both the above functions are relatively expensive, since they need
to iterate through lists. It appears more straightforward to make all
notifiers just pass the targeted dp inside their info structure, and
have the code that needs the indices to look at info->dp->index instead
of info->port, or info->dp->ds->index instead of info->sw_index, or
info->dp->ds->dst->index instead of info->tree_index.

For the sake of consistency, all cross-chip notifiers are converted to
pass the "dp" directly.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vladimir Oltean and committed by
David S. Miller
726816a1 8e9e678e

+76 -140
+7 -17
net/dsa/dsa_priv.h
··· 54 54 55 55 /* DSA_NOTIFIER_BRIDGE_* */ 56 56 struct dsa_notifier_bridge_info { 57 + const struct dsa_port *dp; 57 58 struct dsa_bridge bridge; 58 - int tree_index; 59 - int sw_index; 60 - int port; 61 59 bool tx_fwd_offload; 62 60 struct netlink_ext_ack *extack; 63 61 }; 64 62 65 63 /* DSA_NOTIFIER_FDB_* */ 66 64 struct dsa_notifier_fdb_info { 67 - int sw_index; 68 - int port; 65 + const struct dsa_port *dp; 69 66 const unsigned char *addr; 70 67 u16 vid; 71 68 struct dsa_db db; ··· 78 81 79 82 /* DSA_NOTIFIER_MDB_* */ 80 83 struct dsa_notifier_mdb_info { 84 + const struct dsa_port *dp; 81 85 const struct switchdev_obj_port_mdb *mdb; 82 - int sw_index; 83 - int port; 84 86 struct dsa_db db; 85 87 }; 86 88 87 89 /* DSA_NOTIFIER_LAG_* */ 88 90 struct dsa_notifier_lag_info { 91 + const struct dsa_port *dp; 89 92 struct dsa_lag lag; 90 - int sw_index; 91 - int port; 92 - 93 93 struct netdev_lag_upper_info *info; 94 94 }; 95 95 96 96 /* DSA_NOTIFIER_VLAN_* */ 97 97 struct dsa_notifier_vlan_info { 98 + const struct dsa_port *dp; 98 99 const struct switchdev_obj_port_vlan *vlan; 99 - int sw_index; 100 - int port; 101 100 struct netlink_ext_ack *extack; 102 101 }; 103 102 104 103 /* DSA_NOTIFIER_MTU */ 105 104 struct dsa_notifier_mtu_info { 105 + const struct dsa_port *dp; 106 106 bool targeted_match; 107 - int sw_index; 108 - int port; 109 107 int mtu; 110 108 }; 111 109 ··· 111 119 112 120 /* DSA_NOTIFIER_TAG_8021Q_VLAN_* */ 113 121 struct dsa_notifier_tag_8021q_vlan_info { 114 - int tree_index; 115 - int sw_index; 116 - int port; 122 + const struct dsa_port *dp; 117 123 u16 vid; 118 124 }; 119 125
+20 -44
net/dsa/port.c
··· 459 459 struct netlink_ext_ack *extack) 460 460 { 461 461 struct dsa_notifier_bridge_info info = { 462 - .tree_index = dp->ds->dst->index, 463 - .sw_index = dp->ds->index, 464 - .port = dp->index, 462 + .dp = dp, 465 463 .extack = extack, 466 464 }; 467 465 struct net_device *dev = dp->slave; ··· 528 530 void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) 529 531 { 530 532 struct dsa_notifier_bridge_info info = { 531 - .tree_index = dp->ds->dst->index, 532 - .sw_index = dp->ds->index, 533 - .port = dp->index, 533 + .dp = dp, 534 534 }; 535 535 int err; 536 536 ··· 558 562 struct netdev_lag_lower_state_info *linfo) 559 563 { 560 564 struct dsa_notifier_lag_info info = { 561 - .sw_index = dp->ds->index, 562 - .port = dp->index, 565 + .dp = dp, 563 566 }; 564 567 bool tx_enabled; 565 568 ··· 627 632 struct netlink_ext_ack *extack) 628 633 { 629 634 struct dsa_notifier_lag_info info = { 630 - .sw_index = dp->ds->index, 631 - .port = dp->index, 635 + .dp = dp, 632 636 .info = uinfo, 633 637 }; 634 638 struct net_device *bridge_dev; ··· 672 678 { 673 679 struct net_device *br = dsa_port_bridge_dev_get(dp); 674 680 struct dsa_notifier_lag_info info = { 675 - .sw_index = dp->ds->index, 676 - .port = dp->index, 681 + .dp = dp, 677 682 }; 678 683 int err; 679 684 ··· 934 941 bool targeted_match) 935 942 { 936 943 struct dsa_notifier_mtu_info info = { 937 - .sw_index = dp->ds->index, 944 + .dp = dp, 938 945 .targeted_match = targeted_match, 939 - .port = dp->index, 940 946 .mtu = new_mtu, 941 947 }; 942 948 ··· 946 954 u16 vid) 947 955 { 948 956 struct dsa_notifier_fdb_info info = { 949 - .sw_index = dp->ds->index, 950 - .port = dp->index, 957 + .dp = dp, 951 958 .addr = addr, 952 959 .vid = vid, 953 960 .db = { ··· 969 978 u16 vid) 970 979 { 971 980 struct dsa_notifier_fdb_info info = { 972 - .sw_index = dp->ds->index, 973 - .port = dp->index, 981 + .dp = dp, 974 982 .addr = addr, 975 983 .vid = vid, 976 984 .db = { ··· 989 999 struct dsa_db db) 990 1000 { 991 1001 struct dsa_notifier_fdb_info info = { 992 - .sw_index = dp->ds->index, 993 - .port = dp->index, 1002 + .dp = dp, 994 1003 .addr = addr, 995 1004 .vid = vid, 996 1005 .db = db, ··· 1040 1051 struct dsa_db db) 1041 1052 { 1042 1053 struct dsa_notifier_fdb_info info = { 1043 - .sw_index = dp->ds->index, 1044 - .port = dp->index, 1054 + .dp = dp, 1045 1055 .addr = addr, 1046 1056 .vid = vid, 1047 1057 .db = db, ··· 1135 1147 const struct switchdev_obj_port_mdb *mdb) 1136 1148 { 1137 1149 struct dsa_notifier_mdb_info info = { 1138 - .sw_index = dp->ds->index, 1139 - .port = dp->index, 1150 + .dp = dp, 1140 1151 .mdb = mdb, 1141 1152 .db = { 1142 1153 .type = DSA_DB_BRIDGE, ··· 1153 1166 const struct switchdev_obj_port_mdb *mdb) 1154 1167 { 1155 1168 struct dsa_notifier_mdb_info info = { 1156 - .sw_index = dp->ds->index, 1157 - .port = dp->index, 1169 + .dp = dp, 1158 1170 .mdb = mdb, 1159 1171 .db = { 1160 1172 .type = DSA_DB_BRIDGE, ··· 1172 1186 struct dsa_db db) 1173 1187 { 1174 1188 struct dsa_notifier_mdb_info info = { 1175 - .sw_index = dp->ds->index, 1176 - .port = dp->index, 1189 + .dp = dp, 1177 1190 .mdb = mdb, 1178 1191 .db = db, 1179 1192 }; ··· 1216 1231 struct dsa_db db) 1217 1232 { 1218 1233 struct dsa_notifier_mdb_info info = { 1219 - .sw_index = dp->ds->index, 1220 - .port = dp->index, 1234 + .dp = dp, 1221 1235 .mdb = mdb, 1222 1236 .db = db, 1223 1237 }; ··· 1260 1276 struct netlink_ext_ack *extack) 1261 1277 { 1262 1278 struct dsa_notifier_vlan_info info = { 1263 - .sw_index = dp->ds->index, 1264 - .port = dp->index, 1279 + .dp = dp, 1265 1280 .vlan = vlan, 1266 1281 .extack = extack, 1267 1282 }; ··· 1272 1289 const struct switchdev_obj_port_vlan *vlan) 1273 1290 { 1274 1291 struct dsa_notifier_vlan_info info = { 1275 - .sw_index = dp->ds->index, 1276 - .port = dp->index, 1292 + .dp = dp, 1277 1293 .vlan = vlan, 1278 1294 }; 1279 1295 ··· 1284 1302 struct netlink_ext_ack *extack) 1285 1303 { 1286 1304 struct dsa_notifier_vlan_info info = { 1287 - .sw_index = dp->ds->index, 1288 - .port = dp->index, 1305 + .dp = dp, 1289 1306 .vlan = vlan, 1290 1307 .extack = extack, 1291 1308 }; ··· 1304 1323 const struct switchdev_obj_port_vlan *vlan) 1305 1324 { 1306 1325 struct dsa_notifier_vlan_info info = { 1307 - .sw_index = dp->ds->index, 1308 - .port = dp->index, 1326 + .dp = dp, 1309 1327 .vlan = vlan, 1310 1328 }; 1311 1329 struct dsa_port *cpu_dp = dp->cpu_dp; ··· 1723 1743 int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast) 1724 1744 { 1725 1745 struct dsa_notifier_tag_8021q_vlan_info info = { 1726 - .tree_index = dp->ds->dst->index, 1727 - .sw_index = dp->ds->index, 1728 - .port = dp->index, 1746 + .dp = dp, 1729 1747 .vid = vid, 1730 1748 }; 1731 1749 ··· 1736 1758 void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast) 1737 1759 { 1738 1760 struct dsa_notifier_tag_8021q_vlan_info info = { 1739 - .tree_index = dp->ds->dst->index, 1740 - .sw_index = dp->ds->index, 1741 - .port = dp->index, 1761 + .dp = dp, 1742 1762 .vid = vid, 1743 1763 }; 1744 1764 int err;
+48 -70
net/dsa/switch.c
··· 49 49 static bool dsa_port_mtu_match(struct dsa_port *dp, 50 50 struct dsa_notifier_mtu_info *info) 51 51 { 52 - if (dp->ds->index == info->sw_index && dp->index == info->port) 52 + if (dp == info->dp) 53 53 return true; 54 54 55 55 /* Do not propagate to other switches in the tree if the notifier was ··· 88 88 static int dsa_switch_bridge_join(struct dsa_switch *ds, 89 89 struct dsa_notifier_bridge_info *info) 90 90 { 91 - struct dsa_switch_tree *dst = ds->dst; 92 91 int err; 93 92 94 - if (dst->index == info->tree_index && ds->index == info->sw_index) { 93 + if (info->dp->ds == ds) { 95 94 if (!ds->ops->port_bridge_join) 96 95 return -EOPNOTSUPP; 97 96 98 - err = ds->ops->port_bridge_join(ds, info->port, info->bridge, 97 + err = ds->ops->port_bridge_join(ds, info->dp->index, 98 + info->bridge, 99 99 &info->tx_fwd_offload, 100 100 info->extack); 101 101 if (err) 102 102 return err; 103 103 } 104 104 105 - if ((dst->index != info->tree_index || ds->index != info->sw_index) && 106 - ds->ops->crosschip_bridge_join) { 107 - err = ds->ops->crosschip_bridge_join(ds, info->tree_index, 108 - info->sw_index, 109 - info->port, info->bridge, 105 + if (info->dp->ds != ds && ds->ops->crosschip_bridge_join) { 106 + err = ds->ops->crosschip_bridge_join(ds, 107 + info->dp->ds->dst->index, 108 + info->dp->ds->index, 109 + info->dp->index, 110 + info->bridge, 110 111 info->extack); 111 112 if (err) 112 113 return err; ··· 119 118 static int dsa_switch_bridge_leave(struct dsa_switch *ds, 120 119 struct dsa_notifier_bridge_info *info) 121 120 { 122 - struct dsa_switch_tree *dst = ds->dst; 121 + if (info->dp->ds == ds && ds->ops->port_bridge_leave) 122 + ds->ops->port_bridge_leave(ds, info->dp->index, info->bridge); 123 123 124 - if (dst->index == info->tree_index && ds->index == info->sw_index && 125 - ds->ops->port_bridge_leave) 126 - ds->ops->port_bridge_leave(ds, info->port, info->bridge); 127 - 128 - if ((dst->index != info->tree_index || ds->index != info->sw_index) && 129 - ds->ops->crosschip_bridge_leave) 130 - ds->ops->crosschip_bridge_leave(ds, info->tree_index, 131 - info->sw_index, info->port, 124 + if (info->dp->ds != ds && ds->ops->crosschip_bridge_leave) 125 + ds->ops->crosschip_bridge_leave(ds, info->dp->ds->dst->index, 126 + info->dp->ds->index, 127 + info->dp->index, 132 128 info->bridge); 133 129 134 130 return 0; ··· 136 138 * emitted and its dedicated CPU port. 137 139 */ 138 140 static bool dsa_port_host_address_match(struct dsa_port *dp, 139 - int info_sw_index, int info_port) 141 + const struct dsa_port *targeted_dp) 140 142 { 141 - struct dsa_port *targeted_dp, *cpu_dp; 142 - struct dsa_switch *targeted_ds; 143 + struct dsa_port *cpu_dp = targeted_dp->cpu_dp; 143 144 144 - targeted_ds = dsa_switch_find(dp->ds->dst->index, info_sw_index); 145 - targeted_dp = dsa_to_port(targeted_ds, info_port); 146 - cpu_dp = targeted_dp->cpu_dp; 147 - 148 - if (dsa_switch_is_upstream_of(dp->ds, targeted_ds)) 145 + if (dsa_switch_is_upstream_of(dp->ds, targeted_dp->ds)) 149 146 return dp->index == dsa_towards_port(dp->ds, cpu_dp->ds->index, 150 147 cpu_dp->index); 151 148 ··· 408 415 return -EOPNOTSUPP; 409 416 410 417 dsa_switch_for_each_port(dp, ds) { 411 - if (dsa_port_host_address_match(dp, info->sw_index, 412 - info->port)) { 418 + if (dsa_port_host_address_match(dp, info->dp)) { 413 419 err = dsa_port_do_fdb_add(dp, info->addr, info->vid, 414 420 info->db); 415 421 if (err) ··· 429 437 return -EOPNOTSUPP; 430 438 431 439 dsa_switch_for_each_port(dp, ds) { 432 - if (dsa_port_host_address_match(dp, info->sw_index, 433 - info->port)) { 440 + if (dsa_port_host_address_match(dp, info->dp)) { 434 441 err = dsa_port_do_fdb_del(dp, info->addr, info->vid, 435 442 info->db); 436 443 if (err) ··· 443 452 static int dsa_switch_fdb_add(struct dsa_switch *ds, 444 453 struct dsa_notifier_fdb_info *info) 445 454 { 446 - int port = dsa_towards_port(ds, info->sw_index, info->port); 455 + int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index); 447 456 struct dsa_port *dp = dsa_to_port(ds, port); 448 457 449 458 if (!ds->ops->port_fdb_add) ··· 455 464 static int dsa_switch_fdb_del(struct dsa_switch *ds, 456 465 struct dsa_notifier_fdb_info *info) 457 466 { 458 - int port = dsa_towards_port(ds, info->sw_index, info->port); 467 + int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index); 459 468 struct dsa_port *dp = dsa_to_port(ds, port); 460 469 461 470 if (!ds->ops->port_fdb_del) ··· 503 512 static int dsa_switch_lag_change(struct dsa_switch *ds, 504 513 struct dsa_notifier_lag_info *info) 505 514 { 506 - if (ds->index == info->sw_index && ds->ops->port_lag_change) 507 - return ds->ops->port_lag_change(ds, info->port); 515 + if (info->dp->ds == ds && ds->ops->port_lag_change) 516 + return ds->ops->port_lag_change(ds, info->dp->index); 508 517 509 - if (ds->index != info->sw_index && ds->ops->crosschip_lag_change) 510 - return ds->ops->crosschip_lag_change(ds, info->sw_index, 511 - info->port); 518 + if (info->dp->ds != ds && ds->ops->crosschip_lag_change) 519 + return ds->ops->crosschip_lag_change(ds, info->dp->ds->index, 520 + info->dp->index); 512 521 513 522 return 0; 514 523 } ··· 516 525 static int dsa_switch_lag_join(struct dsa_switch *ds, 517 526 struct dsa_notifier_lag_info *info) 518 527 { 519 - if (ds->index == info->sw_index && ds->ops->port_lag_join) 520 - return ds->ops->port_lag_join(ds, info->port, info->lag, 528 + if (info->dp->ds == ds && ds->ops->port_lag_join) 529 + return ds->ops->port_lag_join(ds, info->dp->index, info->lag, 521 530 info->info); 522 531 523 - if (ds->index != info->sw_index && ds->ops->crosschip_lag_join) 524 - return ds->ops->crosschip_lag_join(ds, info->sw_index, 525 - info->port, info->lag, 532 + if (info->dp->ds != ds && ds->ops->crosschip_lag_join) 533 + return ds->ops->crosschip_lag_join(ds, info->dp->ds->index, 534 + info->dp->index, info->lag, 526 535 info->info); 527 536 528 537 return -EOPNOTSUPP; ··· 531 540 static int dsa_switch_lag_leave(struct dsa_switch *ds, 532 541 struct dsa_notifier_lag_info *info) 533 542 { 534 - if (ds->index == info->sw_index && ds->ops->port_lag_leave) 535 - return ds->ops->port_lag_leave(ds, info->port, info->lag); 543 + if (info->dp->ds == ds && ds->ops->port_lag_leave) 544 + return ds->ops->port_lag_leave(ds, info->dp->index, info->lag); 536 545 537 - if (ds->index != info->sw_index && ds->ops->crosschip_lag_leave) 538 - return ds->ops->crosschip_lag_leave(ds, info->sw_index, 539 - info->port, info->lag); 546 + if (info->dp->ds != ds && ds->ops->crosschip_lag_leave) 547 + return ds->ops->crosschip_lag_leave(ds, info->dp->ds->index, 548 + info->dp->index, info->lag); 540 549 541 550 return -EOPNOTSUPP; 542 551 } ··· 544 553 static int dsa_switch_mdb_add(struct dsa_switch *ds, 545 554 struct dsa_notifier_mdb_info *info) 546 555 { 547 - int port = dsa_towards_port(ds, info->sw_index, info->port); 556 + int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index); 548 557 struct dsa_port *dp = dsa_to_port(ds, port); 549 558 550 559 if (!ds->ops->port_mdb_add) ··· 556 565 static int dsa_switch_mdb_del(struct dsa_switch *ds, 557 566 struct dsa_notifier_mdb_info *info) 558 567 { 559 - int port = dsa_towards_port(ds, info->sw_index, info->port); 568 + int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index); 560 569 struct dsa_port *dp = dsa_to_port(ds, port); 561 570 562 571 if (!ds->ops->port_mdb_del) ··· 575 584 return -EOPNOTSUPP; 576 585 577 586 dsa_switch_for_each_port(dp, ds) { 578 - if (dsa_port_host_address_match(dp, info->sw_index, 579 - info->port)) { 587 + if (dsa_port_host_address_match(dp, info->dp)) { 580 588 err = dsa_port_do_mdb_add(dp, info->mdb, info->db); 581 589 if (err) 582 590 break; ··· 595 605 return -EOPNOTSUPP; 596 606 597 607 dsa_switch_for_each_port(dp, ds) { 598 - if (dsa_port_host_address_match(dp, info->sw_index, 599 - info->port)) { 608 + if (dsa_port_host_address_match(dp, info->dp)) { 600 609 err = dsa_port_do_mdb_del(dp, info->mdb, info->db); 601 610 if (err) 602 611 break; ··· 609 620 static bool dsa_port_vlan_match(struct dsa_port *dp, 610 621 struct dsa_notifier_vlan_info *info) 611 622 { 612 - if (dp->ds->index == info->sw_index && dp->index == info->port) 613 - return true; 614 - 615 - if (dsa_port_is_dsa(dp)) 616 - return true; 617 - 618 - return false; 623 + return dsa_port_is_dsa(dp) || dp == info->dp; 619 624 } 620 625 621 626 /* Host VLANs match on the targeted port's CPU port, and on all DSA ports 622 627 * (upstream and downstream) of that switch and its upstream switches. 623 628 */ 624 629 static bool dsa_port_host_vlan_match(struct dsa_port *dp, 625 - struct dsa_notifier_vlan_info *info) 630 + const struct dsa_port *targeted_dp) 626 631 { 627 - struct dsa_port *targeted_dp, *cpu_dp; 628 - struct dsa_switch *targeted_ds; 632 + struct dsa_port *cpu_dp = targeted_dp->cpu_dp; 629 633 630 - targeted_ds = dsa_switch_find(dp->ds->dst->index, info->sw_index); 631 - targeted_dp = dsa_to_port(targeted_ds, info->port); 632 - cpu_dp = targeted_dp->cpu_dp; 633 - 634 - if (dsa_switch_is_upstream_of(dp->ds, targeted_ds)) 634 + if (dsa_switch_is_upstream_of(dp->ds, targeted_dp->ds)) 635 635 return dsa_port_is_dsa(dp) || dp == cpu_dp; 636 636 637 637 return false; ··· 778 800 return -EOPNOTSUPP; 779 801 780 802 dsa_switch_for_each_port(dp, ds) { 781 - if (dsa_port_host_vlan_match(dp, info)) { 803 + if (dsa_port_host_vlan_match(dp, info->dp)) { 782 804 err = dsa_port_do_vlan_add(dp, info->vlan, 783 805 info->extack); 784 806 if (err) ··· 799 821 return -EOPNOTSUPP; 800 822 801 823 dsa_switch_for_each_port(dp, ds) { 802 - if (dsa_port_host_vlan_match(dp, info)) { 824 + if (dsa_port_host_vlan_match(dp, info->dp)) { 803 825 err = dsa_port_do_vlan_del(dp, info->vlan); 804 826 if (err) 805 827 return err;
+1 -9
net/dsa/tag_8021q.c
··· 196 196 dsa_port_tag_8021q_vlan_match(struct dsa_port *dp, 197 197 struct dsa_notifier_tag_8021q_vlan_info *info) 198 198 { 199 - struct dsa_switch *ds = dp->ds; 200 - 201 - if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp)) 202 - return true; 203 - 204 - if (ds->dst->index == info->tree_index && ds->index == info->sw_index) 205 - return dp->index == info->port; 206 - 207 - return false; 199 + return dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp) || dp == info->dp; 208 200 } 209 201 210 202 int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,