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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bonding-support-aggregator-selection-based-on-port-priority'

Hangbin Liu says:

====================
bonding: support aggregator selection based on port priority

This patchset introduces a new per-port bonding option: `ad_actor_port_prio`.

It allows users to configure the actor's port priority, which can then be used
by the bonding driver for aggregator selection based on port priority.

This provides finer control over LACP aggregator choice, especially in setups
with multiple eligible aggregators over 2 switches.
====================

Link: https://patch.msgid.link/20250902064501.360822-1-liuhangbin@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+247 -33
+21 -4
Documentation/networking/bonding.rst
··· 193 193 This parameter has effect only in 802.3ad mode and is available through 194 194 SysFs interface. 195 195 196 + actor_port_prio 197 + 198 + In an AD system, this specifies the port priority. The allowed range 199 + is 1 - 65535. If the value is not specified, it takes 255 as the 200 + default value. 201 + 202 + This parameter has effect only in 802.3ad mode and is available through 203 + netlink interface. 204 + 196 205 ad_actor_system 197 206 198 207 In an AD system, this specifies the mac-address for the actor in ··· 250 241 ports (slaves). Reselection occurs as described under the 251 242 "bandwidth" setting, above. 252 243 253 - The bandwidth and count selection policies permit failover of 254 - 802.3ad aggregations when partial failure of the active aggregator 255 - occurs. This keeps the aggregator with the highest availability 256 - (either in bandwidth or in number of ports) active at all times. 244 + actor_port_prio or 3 245 + 246 + The active aggregator is chosen by the highest total sum of 247 + actor port priorities across its active ports. Note this 248 + priority is actor_port_prio, not per port prio, which is 249 + used for primary reselect. 250 + 251 + The bandwidth, count and actor_port_prio selection policies permit 252 + failover of 802.3ad aggregations when partial failure of the active 253 + aggregator occurs. This keeps the aggregator with the highest 254 + availability (either in bandwidth, number of ports, or total value 255 + of port priorities) active at all times. 257 256 258 257 This option was added in bonding version 3.4.0. 259 258
+31
drivers/net/bonding/bond_3ad.c
··· 436 436 437 437 port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr; 438 438 port->actor_system_priority = BOND_AD_INFO(bond).system.sys_priority; 439 + port->actor_port_priority = SLAVE_AD_INFO(port->slave)->port_priority; 439 440 } 440 441 441 442 /* Conversions */ ··· 745 744 } 746 745 747 746 return active; 747 + } 748 + 749 + static unsigned int __agg_ports_priority(const struct aggregator *agg) 750 + { 751 + struct port *port = agg->lag_ports; 752 + unsigned int prio = 0; 753 + 754 + for (; port; port = port->next_port_in_aggregator) 755 + if (port->is_enabled) 756 + prio += port->actor_port_priority; 757 + 758 + return prio; 748 759 } 749 760 750 761 /** ··· 1720 1707 * 4. Therefore, current and best both have partner replies or 1721 1708 * both do not, so perform selection policy: 1722 1709 * 1710 + * BOND_AD_PRIO: Select by total priority of ports. If priority 1711 + * is equal, select by count. 1712 + * 1723 1713 * BOND_AD_COUNT: Select by count of ports. If count is equal, 1724 1714 * select by bandwidth. 1725 1715 * ··· 1744 1728 return best; 1745 1729 1746 1730 switch (__get_agg_selection_mode(curr->lag_ports)) { 1731 + case BOND_AD_PRIO: 1732 + if (__agg_ports_priority(curr) > __agg_ports_priority(best)) 1733 + return curr; 1734 + 1735 + if (__agg_ports_priority(curr) < __agg_ports_priority(best)) 1736 + return best; 1737 + 1738 + fallthrough; 1747 1739 case BOND_AD_COUNT: 1748 1740 if (__agg_active_ports(curr) > __agg_active_ports(best)) 1749 1741 return curr; ··· 1814 1790 * set of slaves in the bond changes. 1815 1791 * 1816 1792 * BOND_AD_COUNT: select the aggregator with largest number of ports 1793 + * (slaves), and reselect whenever a link state change takes place or the 1794 + * set of slaves in the bond changes. 1795 + * 1796 + * BOND_AD_PRIO: select the aggregator with highest total priority of ports 1817 1797 * (slaves), and reselect whenever a link state change takes place or the 1818 1798 * set of slaves in the bond changes. 1819 1799 * ··· 2236 2208 port = &(SLAVE_AD_INFO(slave)->port); 2237 2209 2238 2210 ad_initialize_port(port, &bond->params); 2211 + 2212 + /* Port priority is initialized. Update it to slave's ad info */ 2213 + SLAVE_AD_INFO(slave)->port_priority = port->actor_port_priority; 2239 2214 2240 2215 port->slave = slave; 2241 2216 port->actor_port_number = SLAVE_AD_INFO(slave)->id;
+16
drivers/net/bonding/bond_netlink.c
··· 28 28 nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */ 29 29 nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ 30 30 nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ 31 + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ 31 32 0; 32 33 } 33 34 ··· 78 77 ad_port->partner_oper.port_state)) 79 78 goto nla_put_failure; 80 79 } 80 + 81 + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, 82 + SLAVE_AD_INFO(slave)->port_priority)) 83 + goto nla_put_failure; 81 84 } 82 85 83 86 return 0; ··· 135 130 static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { 136 131 [IFLA_BOND_SLAVE_QUEUE_ID] = { .type = NLA_U16 }, 137 132 [IFLA_BOND_SLAVE_PRIO] = { .type = NLA_S32 }, 133 + [IFLA_BOND_SLAVE_ACTOR_PORT_PRIO] = { .type = NLA_U16 }, 138 134 }; 139 135 140 136 static int bond_validate(struct nlattr *tb[], struct nlattr *data[], ··· 182 176 bond_opt_slave_initval(&newval, &slave_dev, prio); 183 177 err = __bond_opt_set(bond, BOND_OPT_PRIO, &newval, 184 178 data[IFLA_BOND_SLAVE_PRIO], extack); 179 + if (err) 180 + return err; 181 + } 182 + 183 + if (data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO]) { 184 + u16 ad_prio = nla_get_u16(data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO]); 185 + 186 + bond_opt_slave_initval(&newval, &slave_dev, ad_prio); 187 + err = __bond_opt_set(bond, BOND_OPT_ACTOR_PORT_PRIO, &newval, 188 + data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO], extack); 185 189 if (err) 186 190 return err; 187 191 }
+41 -4
drivers/net/bonding/bond_options.c
··· 79 79 const struct bond_opt_value *newval); 80 80 static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, 81 81 const struct bond_opt_value *newval); 82 + static int bond_option_actor_port_prio_set(struct bonding *bond, 83 + const struct bond_opt_value *newval); 82 84 static int bond_option_ad_actor_system_set(struct bonding *bond, 83 85 const struct bond_opt_value *newval); 84 86 static int bond_option_ad_user_port_key_set(struct bonding *bond, ··· 162 160 }; 163 161 164 162 static const struct bond_opt_value bond_ad_select_tbl[] = { 165 - { "stable", BOND_AD_STABLE, BOND_VALFLAG_DEFAULT}, 166 - { "bandwidth", BOND_AD_BANDWIDTH, 0}, 167 - { "count", BOND_AD_COUNT, 0}, 168 - { NULL, -1, 0}, 163 + { "stable", BOND_AD_STABLE, BOND_VALFLAG_DEFAULT}, 164 + { "bandwidth", BOND_AD_BANDWIDTH, 0}, 165 + { "count", BOND_AD_COUNT, 0}, 166 + { "actor_port_prio", BOND_AD_PRIO, 0}, 167 + { NULL, -1, 0}, 169 168 }; 170 169 171 170 static const struct bond_opt_value bond_num_peer_notif_tbl[] = { ··· 222 219 static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = { 223 220 { "minval", 1, BOND_VALFLAG_MIN}, 224 221 { "maxval", 65535, BOND_VALFLAG_MAX | BOND_VALFLAG_DEFAULT}, 222 + { NULL, -1, 0}, 223 + }; 224 + 225 + static const struct bond_opt_value bond_actor_port_prio_tbl[] = { 226 + { "minval", 0, BOND_VALFLAG_MIN}, 227 + { "maxval", 65535, BOND_VALFLAG_MAX}, 228 + { "default", 255, BOND_VALFLAG_DEFAULT}, 225 229 { NULL, -1, 0}, 226 230 }; 227 231 ··· 492 482 .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), 493 483 .values = bond_ad_actor_sys_prio_tbl, 494 484 .set = bond_option_ad_actor_sys_prio_set, 485 + }, 486 + [BOND_OPT_ACTOR_PORT_PRIO] = { 487 + .id = BOND_OPT_ACTOR_PORT_PRIO, 488 + .name = "actor_port_prio", 489 + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), 490 + .values = bond_actor_port_prio_tbl, 491 + .set = bond_option_actor_port_prio_set, 495 492 }, 496 493 [BOND_OPT_AD_ACTOR_SYSTEM] = { 497 494 .id = BOND_OPT_AD_ACTOR_SYSTEM, ··· 1824 1807 newval->value); 1825 1808 1826 1809 bond->params.ad_actor_sys_prio = newval->value; 1810 + bond_3ad_update_ad_actor_settings(bond); 1811 + 1812 + return 0; 1813 + } 1814 + 1815 + static int bond_option_actor_port_prio_set(struct bonding *bond, 1816 + const struct bond_opt_value *newval) 1817 + { 1818 + struct slave *slave; 1819 + 1820 + slave = bond_slave_get_rtnl(newval->slave_dev); 1821 + if (!slave) { 1822 + netdev_dbg(bond->dev, "%s called on NULL slave\n", __func__); 1823 + return -ENODEV; 1824 + } 1825 + 1826 + netdev_dbg(newval->slave_dev, "Setting actor_port_prio to %llu\n", 1827 + newval->value); 1828 + 1829 + SLAVE_AD_INFO(slave)->port_priority = newval->value; 1827 1830 bond_3ad_update_ad_actor_settings(bond); 1828 1831 1829 1832 return 0;
+2
include/net/bond_3ad.h
··· 26 26 BOND_AD_STABLE = 0, 27 27 BOND_AD_BANDWIDTH = 1, 28 28 BOND_AD_COUNT = 2, 29 + BOND_AD_PRIO = 3, 29 30 }; 30 31 31 32 /* rx machine states(43.4.11 in the 802.3ad standard) */ ··· 275 274 struct port port; /* 802.3ad port structure */ 276 275 struct bond_3ad_stats stats; 277 276 u16 id; 277 + u16 port_priority; 278 278 }; 279 279 280 280 static inline const char *bond_3ad_churn_desc(churn_state_t state)
+1
include/net/bond_options.h
··· 78 78 BOND_OPT_PRIO, 79 79 BOND_OPT_COUPLED_CONTROL, 80 80 BOND_OPT_BROADCAST_NEIGH, 81 + BOND_OPT_ACTOR_PORT_PRIO, 81 82 BOND_OPT_LAST 82 83 }; 83 84
+1
include/uapi/linux/if_link.h
··· 1564 1564 IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, 1565 1565 IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, 1566 1566 IFLA_BOND_SLAVE_PRIO, 1567 + IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, 1567 1568 __IFLA_BOND_SLAVE_MAX, 1568 1569 }; 1569 1570
+2 -1
tools/testing/selftests/drivers/net/bonding/Makefile
··· 11 11 bond_options.sh \ 12 12 bond-eth-type-change.sh \ 13 13 bond_macvlan_ipvlan.sh \ 14 - bond_passive_lacp.sh 14 + bond_passive_lacp.sh \ 15 + bond_lacp_prio.sh 15 16 16 17 TEST_FILES := \ 17 18 lag_lib.sh \
+108
tools/testing/selftests/drivers/net/bonding/bond_lacp_prio.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + # Testing if bond lacp per port priority works 5 + # 6 + # Switch (s_ns) Backup Switch (b_ns) 7 + # +-------------------------+ +-------------------------+ 8 + # | bond0 | | bond0 | 9 + # | + | | + | 10 + # | eth0 | eth1 | | eth0 | eth1 | 11 + # | +---+---+ | | +---+---+ | 12 + # | | | | | | | | 13 + # +-------------------------+ +-------------------------+ 14 + # | | | | 15 + # +-----------------------------------------------------+ 16 + # | | | | | | 17 + # | +-------+---------+---------+-------+ | 18 + # | eth0 eth1 | eth2 eth3 | 19 + # | + | 20 + # | bond0 | 21 + # +-----------------------------------------------------+ 22 + # Client (c_ns) 23 + 24 + lib_dir=$(dirname "$0") 25 + # shellcheck disable=SC1091 26 + source "$lib_dir"/../../../net/lib.sh 27 + 28 + setup_links() 29 + { 30 + # shellcheck disable=SC2154 31 + ip -n "${c_ns}" link add eth0 type veth peer name eth0 netns "${s_ns}" 32 + ip -n "${c_ns}" link add eth1 type veth peer name eth1 netns "${s_ns}" 33 + # shellcheck disable=SC2154 34 + ip -n "${c_ns}" link add eth2 type veth peer name eth0 netns "${b_ns}" 35 + ip -n "${c_ns}" link add eth3 type veth peer name eth1 netns "${b_ns}" 36 + 37 + ip -n "${c_ns}" link add bond0 type bond mode 802.3ad miimon 100 \ 38 + lacp_rate fast ad_select actor_port_prio 39 + ip -n "${s_ns}" link add bond0 type bond mode 802.3ad miimon 100 \ 40 + lacp_rate fast 41 + ip -n "${b_ns}" link add bond0 type bond mode 802.3ad miimon 100 \ 42 + lacp_rate fast 43 + 44 + ip -n "${c_ns}" link set eth0 master bond0 45 + ip -n "${c_ns}" link set eth1 master bond0 46 + ip -n "${c_ns}" link set eth2 master bond0 47 + ip -n "${c_ns}" link set eth3 master bond0 48 + ip -n "${s_ns}" link set eth0 master bond0 49 + ip -n "${s_ns}" link set eth1 master bond0 50 + ip -n "${b_ns}" link set eth0 master bond0 51 + ip -n "${b_ns}" link set eth1 master bond0 52 + 53 + ip -n "${c_ns}" link set bond0 up 54 + ip -n "${s_ns}" link set bond0 up 55 + ip -n "${b_ns}" link set bond0 up 56 + } 57 + 58 + test_port_prio_setting() 59 + { 60 + RET=0 61 + ip -n "${c_ns}" link set eth0 type bond_slave actor_port_prio 1000 62 + prio=$(cmd_jq "ip -n ${c_ns} -d -j link show eth0" \ 63 + ".[].linkinfo.info_slave_data.actor_port_prio") 64 + [ "$prio" -ne 1000 ] && RET=1 65 + ip -n "${c_ns}" link set eth2 type bond_slave actor_port_prio 10 66 + prio=$(cmd_jq "ip -n ${c_ns} -d -j link show eth2" \ 67 + ".[].linkinfo.info_slave_data.actor_port_prio") 68 + [ "$prio" -ne 10 ] && RET=1 69 + } 70 + 71 + test_agg_reselect() 72 + { 73 + local bond_agg_id slave_agg_id 74 + local expect_slave="$1" 75 + RET=0 76 + 77 + # Trigger link state change to reselect the aggregator 78 + ip -n "${c_ns}" link set eth1 down 79 + sleep 0.5 80 + ip -n "${c_ns}" link set eth1 up 81 + sleep 0.5 82 + 83 + bond_agg_id=$(cmd_jq "ip -n ${c_ns} -d -j link show bond0" \ 84 + ".[].linkinfo.info_data.ad_info.aggregator") 85 + slave_agg_id=$(cmd_jq "ip -n ${c_ns} -d -j link show $expect_slave" \ 86 + ".[].linkinfo.info_slave_data.ad_aggregator_id") 87 + # shellcheck disable=SC2034 88 + [ "${bond_agg_id}" -ne "${slave_agg_id}" ] && \ 89 + RET=1 90 + } 91 + 92 + trap cleanup_all_ns EXIT 93 + setup_ns c_ns s_ns b_ns 94 + setup_links 95 + 96 + test_port_prio_setting 97 + log_test "bond 802.3ad" "actor_port_prio setting" 98 + 99 + test_agg_reselect eth0 100 + log_test "bond 802.3ad" "actor_port_prio select" 101 + 102 + # Change the actor port prio and re-test 103 + ip -n "${c_ns}" link set eth0 type bond_slave actor_port_prio 10 104 + ip -n "${c_ns}" link set eth2 type bond_slave actor_port_prio 1000 105 + test_agg_reselect eth2 106 + log_test "bond 802.3ad" "actor_port_prio switch" 107 + 108 + exit "${EXIT_STATUS}"
-24
tools/testing/selftests/net/forwarding/lib.sh
··· 571 571 fi 572 572 } 573 573 574 - cmd_jq() 575 - { 576 - local cmd=$1 577 - local jq_exp=$2 578 - local jq_opts=$3 579 - local ret 580 - local output 581 - 582 - output="$($cmd)" 583 - # it the command fails, return error right away 584 - ret=$? 585 - if [[ $ret -ne 0 ]]; then 586 - return $ret 587 - fi 588 - output=$(echo $output | jq -r $jq_opts "$jq_exp") 589 - ret=$? 590 - if [[ $ret -ne 0 ]]; then 591 - return $ret 592 - fi 593 - echo $output 594 - # return success only in case of non-empty output 595 - [ ! -z "$output" ] 596 - } 597 - 598 574 pre_cleanup() 599 575 { 600 576 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
+24
tools/testing/selftests/net/lib.sh
··· 645 645 sleep 0.1 646 646 done 647 647 } 648 + 649 + cmd_jq() 650 + { 651 + local cmd=$1 652 + local jq_exp=$2 653 + local jq_opts=$3 654 + local ret 655 + local output 656 + 657 + output="$($cmd)" 658 + # it the command fails, return error right away 659 + ret=$? 660 + if [[ $ret -ne 0 ]]; then 661 + return $ret 662 + fi 663 + output=$(echo $output | jq -r $jq_opts "$jq_exp") 664 + ret=$? 665 + if [[ $ret -ne 0 ]]; then 666 + return $ret 667 + fi 668 + echo $output 669 + # return success only in case of non-empty output 670 + [ ! -z "$output" ] 671 + }