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 'decouple-receive-and-transmit-enablement-in-team-driver'

Marc Harvey says:

====================
Decouple receive and transmit enablement in team driver

Allow independent control over receive and transmit enablement states
for aggregated ports in the team driver.

The motivation is that IEE 802.3ad LACP "independent control" can't
be implemented for the team driver currently. This was added to the
bonding driver in commit 240fd405528b ("bonding: Add independent
control state machine").

This series also has a few patches that add tests to show that the old
coupled enablement still works and that the new decoupled enablement
works as intended (4, 5, and 10).

There are three patches with small fixes as well, with the goal of
making the final decoupling patch clearer (1, 2, and 3).

Signed-off-by: Marc Harvey <marcharvey@google.com>
====================

Link: https://patch.msgid.link/20260409-teaming-driver-internal-v7-0-f47e7589685d@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+1200 -75
+201 -40
drivers/net/team/team_core.c
··· 87 87 struct netdev_lag_lower_state_info info; 88 88 89 89 info.link_up = port->linkup; 90 - info.tx_enabled = team_port_enabled(port); 90 + info.tx_enabled = team_port_tx_enabled(port); 91 91 netdev_lower_state_changed(port->dev, &info); 92 92 } 93 93 ··· 532 532 * correct ops are always set. 533 533 */ 534 534 535 - if (!team->en_port_count || !team_is_mode_set(team) || 535 + if (!team->tx_en_port_count || !team_is_mode_set(team) || 536 536 !team->mode->ops->transmit) 537 537 team->ops.transmit = team_dummy_transmit; 538 538 else 539 539 team->ops.transmit = team->mode->ops->transmit; 540 540 541 - if (!team->en_port_count || !team_is_mode_set(team) || 541 + if (!team->rx_en_port_count || !team_is_mode_set(team) || 542 542 !team->mode->ops->receive) 543 543 team->ops.receive = team_dummy_receive; 544 544 else ··· 734 734 735 735 port = team_port_get_rcu(skb->dev); 736 736 team = port->team; 737 - if (!team_port_enabled(port)) { 737 + if (!team_port_rx_enabled(port)) { 738 738 if (is_link_local_ether_addr(eth_hdr(skb)->h_dest)) 739 739 /* link-local packets are mostly useful when stack receives them 740 740 * with the link they arrive on. ··· 831 831 return true; 832 832 if (port->priority > cur->priority) 833 833 return false; 834 - if (port->index < cur->index) 834 + if (port->tx_index < cur->tx_index) 835 835 return true; 836 836 return false; 837 837 } ··· 876 876 static void team_queue_override_port_prio_changed(struct team *team, 877 877 struct team_port *port) 878 878 { 879 - if (!port->queue_id || !team_port_enabled(port)) 879 + if (!port->queue_id || !team_port_tx_enabled(port)) 880 880 return; 881 881 __team_queue_override_port_del(team, port); 882 882 __team_queue_override_port_add(team, port); ··· 887 887 struct team_port *port, 888 888 u16 new_queue_id) 889 889 { 890 - if (team_port_enabled(port)) { 890 + if (team_port_tx_enabled(port)) { 891 891 __team_queue_override_port_del(team, port); 892 892 port->queue_id = new_queue_id; 893 893 __team_queue_override_port_add(team, port); ··· 927 927 return false; 928 928 } 929 929 930 - /* 931 - * Enable/disable port by adding to enabled port hashlist and setting 932 - * port->index (Might be racy so reader could see incorrect ifindex when 933 - * processing a flying packet, but that is not a problem). Write guarded 934 - * by RTNL. 935 - */ 936 - static void team_port_enable(struct team *team, 937 - struct team_port *port) 930 + static void __team_port_enable_rx(struct team *team, 931 + struct team_port *port) 938 932 { 939 - if (team_port_enabled(port)) 933 + team->rx_en_port_count++; 934 + WRITE_ONCE(port->rx_enabled, true); 935 + } 936 + 937 + static void __team_port_disable_rx(struct team *team, 938 + struct team_port *port) 939 + { 940 + team->rx_en_port_count--; 941 + WRITE_ONCE(port->rx_enabled, false); 942 + } 943 + 944 + static void team_port_enable_rx(struct team *team, 945 + struct team_port *port) 946 + { 947 + if (team_port_rx_enabled(port)) 940 948 return; 941 - port->index = team->en_port_count++; 942 - hlist_add_head_rcu(&port->hlist, 943 - team_port_index_hash(team, port->index)); 949 + 950 + __team_port_enable_rx(team, port); 944 951 team_adjust_ops(team); 945 - team_queue_override_port_add(team, port); 946 - if (team->ops.port_enabled) 947 - team->ops.port_enabled(team, port); 948 952 team_notify_peers(team); 949 953 team_mcast_rejoin(team); 954 + } 955 + 956 + static void team_port_disable_rx(struct team *team, 957 + struct team_port *port) 958 + { 959 + if (!team_port_rx_enabled(port)) 960 + return; 961 + 962 + __team_port_disable_rx(team, port); 963 + team_adjust_ops(team); 964 + } 965 + 966 + /* 967 + * Enable just TX on the port by adding to tx-enabled port hashlist and 968 + * setting port->tx_index (Might be racy so reader could see incorrect 969 + * ifindex when processing a flying packet, but that is not a problem). 970 + * Write guarded by RTNL. 971 + */ 972 + static void __team_port_enable_tx(struct team *team, 973 + struct team_port *port) 974 + { 975 + WRITE_ONCE(port->tx_index, team->tx_en_port_count); 976 + WRITE_ONCE(team->tx_en_port_count, team->tx_en_port_count + 1); 977 + hlist_add_head_rcu(&port->tx_hlist, 978 + team_tx_port_index_hash(team, port->tx_index)); 979 + } 980 + 981 + static void team_port_enable_tx(struct team *team, 982 + struct team_port *port) 983 + { 984 + if (team_port_tx_enabled(port)) 985 + return; 986 + 987 + __team_port_enable_tx(team, port); 988 + team_adjust_ops(team); 989 + team_queue_override_port_add(team, port); 990 + 991 + /* Don't rejoin multicast, since this port might not be receiving. */ 992 + team_notify_peers(team); 950 993 team_lower_state_changed(port); 951 994 } 952 995 953 996 static void __reconstruct_port_hlist(struct team *team, int rm_index) 954 997 { 955 - int i; 998 + struct hlist_head *tx_port_index_hash; 956 999 struct team_port *port; 1000 + int i; 957 1001 958 - for (i = rm_index + 1; i < team->en_port_count; i++) { 959 - port = team_get_port_by_index(team, i); 960 - hlist_del_rcu(&port->hlist); 961 - port->index--; 962 - hlist_add_head_rcu(&port->hlist, 963 - team_port_index_hash(team, port->index)); 1002 + for (i = rm_index + 1; i < team->tx_en_port_count; i++) { 1003 + port = team_get_port_by_tx_index(team, i); 1004 + hlist_del_rcu(&port->tx_hlist); 1005 + WRITE_ONCE(port->tx_index, port->tx_index - 1); 1006 + tx_port_index_hash = team_tx_port_index_hash(team, 1007 + port->tx_index); 1008 + hlist_add_head_rcu(&port->tx_hlist, tx_port_index_hash); 964 1009 } 1010 + } 1011 + 1012 + static void __team_port_disable_tx(struct team *team, 1013 + struct team_port *port) 1014 + { 1015 + if (team->ops.port_tx_disabled) 1016 + team->ops.port_tx_disabled(team, port); 1017 + 1018 + hlist_del_rcu(&port->tx_hlist); 1019 + __reconstruct_port_hlist(team, port->tx_index); 1020 + 1021 + WRITE_ONCE(port->tx_index, -1); 1022 + WRITE_ONCE(team->tx_en_port_count, team->tx_en_port_count - 1); 1023 + } 1024 + 1025 + static void team_port_disable_tx(struct team *team, 1026 + struct team_port *port) 1027 + { 1028 + if (!team_port_tx_enabled(port)) 1029 + return; 1030 + 1031 + __team_port_disable_tx(team, port); 1032 + 1033 + team_queue_override_port_del(team, port); 1034 + team_adjust_ops(team); 1035 + team_lower_state_changed(port); 1036 + } 1037 + 1038 + /* 1039 + * Enable TX AND RX on the port. 1040 + */ 1041 + static void team_port_enable(struct team *team, 1042 + struct team_port *port) 1043 + { 1044 + bool rx_was_enabled; 1045 + bool tx_was_enabled; 1046 + 1047 + if (team_port_enabled(port)) 1048 + return; 1049 + 1050 + rx_was_enabled = team_port_rx_enabled(port); 1051 + tx_was_enabled = team_port_tx_enabled(port); 1052 + 1053 + if (!rx_was_enabled) 1054 + __team_port_enable_rx(team, port); 1055 + if (!tx_was_enabled) 1056 + __team_port_enable_tx(team, port); 1057 + 1058 + team_adjust_ops(team); 1059 + if (!tx_was_enabled) 1060 + team_queue_override_port_add(team, port); 1061 + team_notify_peers(team); 1062 + if (!rx_was_enabled) 1063 + team_mcast_rejoin(team); 1064 + if (!tx_was_enabled) 1065 + team_lower_state_changed(port); 965 1066 } 966 1067 967 1068 static void team_port_disable(struct team *team, 968 1069 struct team_port *port) 969 1070 { 970 - if (!team_port_enabled(port)) 1071 + bool rx_was_enabled = team_port_rx_enabled(port); 1072 + bool tx_was_enabled = team_port_tx_enabled(port); 1073 + 1074 + if (!tx_was_enabled && !rx_was_enabled) 971 1075 return; 972 - if (team->ops.port_disabled) 973 - team->ops.port_disabled(team, port); 974 - hlist_del_rcu(&port->hlist); 975 - __reconstruct_port_hlist(team, port->index); 976 - port->index = -1; 977 - team->en_port_count--; 978 - team_queue_override_port_del(team, port); 1076 + 1077 + if (tx_was_enabled) { 1078 + __team_port_disable_tx(team, port); 1079 + team_queue_override_port_del(team, port); 1080 + } 1081 + if (rx_was_enabled) 1082 + __team_port_disable_rx(team, port); 1083 + 979 1084 team_adjust_ops(team); 980 - team_lower_state_changed(port); 1085 + 1086 + if (tx_was_enabled) 1087 + team_lower_state_changed(port); 981 1088 } 982 1089 983 1090 static int team_port_enter(struct team *team, struct team_port *port) ··· 1352 1245 netif_addr_unlock_bh(dev); 1353 1246 } 1354 1247 1355 - port->index = -1; 1248 + WRITE_ONCE(port->tx_index, -1); 1356 1249 list_add_tail_rcu(&port->list, &team->port_list); 1357 1250 team_port_enable(team, port); 1358 1251 netdev_compute_master_upper_features(dev, true); ··· 1537 1430 return 0; 1538 1431 } 1539 1432 1433 + static void team_port_rx_en_option_get(struct team *team, 1434 + struct team_gsetter_ctx *ctx) 1435 + { 1436 + struct team_port *port = ctx->info->port; 1437 + 1438 + ctx->data.bool_val = team_port_rx_enabled(port); 1439 + } 1440 + 1441 + static int team_port_rx_en_option_set(struct team *team, 1442 + struct team_gsetter_ctx *ctx) 1443 + { 1444 + struct team_port *port = ctx->info->port; 1445 + 1446 + if (ctx->data.bool_val) 1447 + team_port_enable_rx(team, port); 1448 + else 1449 + team_port_disable_rx(team, port); 1450 + return 0; 1451 + } 1452 + 1453 + static void team_port_tx_en_option_get(struct team *team, 1454 + struct team_gsetter_ctx *ctx) 1455 + { 1456 + struct team_port *port = ctx->info->port; 1457 + 1458 + ctx->data.bool_val = team_port_tx_enabled(port); 1459 + } 1460 + 1461 + static int team_port_tx_en_option_set(struct team *team, 1462 + struct team_gsetter_ctx *ctx) 1463 + { 1464 + struct team_port *port = ctx->info->port; 1465 + 1466 + if (ctx->data.bool_val) 1467 + team_port_enable_tx(team, port); 1468 + else 1469 + team_port_disable_tx(team, port); 1470 + return 0; 1471 + } 1472 + 1540 1473 static void team_user_linkup_option_get(struct team *team, 1541 1474 struct team_gsetter_ctx *ctx) 1542 1475 { ··· 1699 1552 .setter = team_port_en_option_set, 1700 1553 }, 1701 1554 { 1555 + .name = "rx_enabled", 1556 + .type = TEAM_OPTION_TYPE_BOOL, 1557 + .per_port = true, 1558 + .getter = team_port_rx_en_option_get, 1559 + .setter = team_port_rx_en_option_set, 1560 + }, 1561 + { 1562 + .name = "tx_enabled", 1563 + .type = TEAM_OPTION_TYPE_BOOL, 1564 + .per_port = true, 1565 + .getter = team_port_tx_en_option_get, 1566 + .setter = team_port_tx_en_option_set, 1567 + }, 1568 + { 1702 1569 .name = "user_linkup", 1703 1570 .type = TEAM_OPTION_TYPE_BOOL, 1704 1571 .per_port = true, ··· 1757 1596 return -ENOMEM; 1758 1597 1759 1598 for (i = 0; i < TEAM_PORT_HASHENTRIES; i++) 1760 - INIT_HLIST_HEAD(&team->en_port_hlist[i]); 1599 + INIT_HLIST_HEAD(&team->tx_en_port_hlist[i]); 1761 1600 INIT_LIST_HEAD(&team->port_list); 1762 1601 err = team_queue_override_init(team); 1763 1602 if (err)
+4 -4
drivers/net/team/team_mode_loadbalance.c
··· 120 120 { 121 121 int port_index = team_num_to_port_index(team, hash); 122 122 123 - return team_get_port_by_index_rcu(team, port_index); 123 + return team_get_port_by_tx_index_rcu(team, port_index); 124 124 } 125 125 126 126 /* Hash to port mapping select tx port */ ··· 380 380 381 381 list_for_each_entry(port, &team->port_list, list) { 382 382 if (ctx->data.u32_val == port->dev->ifindex && 383 - team_port_enabled(port)) { 383 + team_port_tx_enabled(port)) { 384 384 rcu_assign_pointer(LB_HTPM_PORT_BY_HASH(lb_priv, hash), 385 385 port); 386 386 return 0; ··· 655 655 free_percpu(lb_port_priv->pcpu_stats); 656 656 } 657 657 658 - static void lb_port_disabled(struct team *team, struct team_port *port) 658 + static void lb_port_tx_disabled(struct team *team, struct team_port *port) 659 659 { 660 660 lb_tx_hash_to_port_mapping_null_port(team, port); 661 661 } ··· 665 665 .exit = lb_exit, 666 666 .port_enter = lb_port_enter, 667 667 .port_leave = lb_port_leave, 668 - .port_disabled = lb_port_disabled, 668 + .port_tx_disabled = lb_port_tx_disabled, 669 669 .receive = lb_receive, 670 670 .transmit = lb_transmit, 671 671 };
+2 -2
drivers/net/team/team_mode_random.c
··· 16 16 struct team_port *port; 17 17 int port_index; 18 18 19 - port_index = get_random_u32_below(team->en_port_count); 20 - port = team_get_port_by_index_rcu(team, port_index); 19 + port_index = get_random_u32_below(READ_ONCE(team->tx_en_port_count)); 20 + port = team_get_port_by_tx_index_rcu(team, port_index); 21 21 if (unlikely(!port)) 22 22 goto drop; 23 23 port = team_get_first_port_txable_rcu(team, port);
+1 -1
drivers/net/team/team_mode_roundrobin.c
··· 27 27 28 28 port_index = team_num_to_port_index(team, 29 29 rr_priv(team)->sent_packets++); 30 - port = team_get_port_by_index_rcu(team, port_index); 30 + port = team_get_port_by_tx_index_rcu(team, port_index); 31 31 if (unlikely(!port)) 32 32 goto drop; 33 33 port = team_get_first_port_txable_rcu(team, port);
+38 -25
include/linux/if_team.h
··· 27 27 28 28 struct team_port { 29 29 struct net_device *dev; 30 - struct hlist_node hlist; /* node in enabled ports hash list */ 30 + struct hlist_node tx_hlist; /* node in tx-enabled ports hash list */ 31 31 struct list_head list; /* node in ordinary list */ 32 32 struct team *team; 33 - int index; /* index of enabled port. If disabled, it's set to -1 */ 33 + int tx_index; /* index of tx enabled port. If disabled, -1 */ 34 + bool rx_enabled; 34 35 35 36 bool linkup; /* either state.linkup or user.linkup */ 36 37 ··· 76 75 return rcu_dereference(dev->rx_handler_data); 77 76 } 78 77 78 + static inline bool team_port_rx_enabled(struct team_port *port) 79 + { 80 + return READ_ONCE(port->rx_enabled); 81 + } 82 + 83 + static inline bool team_port_tx_enabled(struct team_port *port) 84 + { 85 + return READ_ONCE(port->tx_index) != -1; 86 + } 87 + 79 88 static inline bool team_port_enabled(struct team_port *port) 80 89 { 81 - return port->index != -1; 90 + return team_port_rx_enabled(port) && team_port_tx_enabled(port); 82 91 } 83 92 84 93 static inline bool team_port_txable(struct team_port *port) 85 94 { 86 - return port->linkup && team_port_enabled(port); 95 + return port->linkup && team_port_tx_enabled(port); 87 96 } 88 97 89 98 static inline bool team_port_dev_txable(const struct net_device *port_dev) ··· 132 121 int (*port_enter)(struct team *team, struct team_port *port); 133 122 void (*port_leave)(struct team *team, struct team_port *port); 134 123 void (*port_change_dev_addr)(struct team *team, struct team_port *port); 135 - void (*port_enabled)(struct team *team, struct team_port *port); 136 - void (*port_disabled)(struct team *team, struct team_port *port); 124 + void (*port_tx_disabled)(struct team *team, struct team_port *port); 137 125 }; 138 126 139 127 extern int team_modeop_port_enter(struct team *team, struct team_port *port); ··· 201 191 const struct header_ops *header_ops_cache; 202 192 203 193 /* 204 - * List of enabled ports and their count 194 + * List of tx-enabled ports and counts of rx and tx-enabled ports. 205 195 */ 206 - int en_port_count; 207 - struct hlist_head en_port_hlist[TEAM_PORT_HASHENTRIES]; 196 + int tx_en_port_count; 197 + int rx_en_port_count; 198 + struct hlist_head tx_en_port_hlist[TEAM_PORT_HASHENTRIES]; 208 199 209 200 struct list_head port_list; /* list of all ports */ 210 201 ··· 249 238 return dev_queue_xmit(skb); 250 239 } 251 240 252 - static inline struct hlist_head *team_port_index_hash(struct team *team, 253 - int port_index) 241 + static inline struct hlist_head *team_tx_port_index_hash(struct team *team, 242 + int tx_port_index) 254 243 { 255 - return &team->en_port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)]; 244 + unsigned int list_entry = tx_port_index & (TEAM_PORT_HASHENTRIES - 1); 245 + 246 + return &team->tx_en_port_hlist[list_entry]; 256 247 } 257 248 258 - static inline struct team_port *team_get_port_by_index(struct team *team, 259 - int port_index) 249 + static inline struct team_port *team_get_port_by_tx_index(struct team *team, 250 + int tx_port_index) 260 251 { 252 + struct hlist_head *head = team_tx_port_index_hash(team, tx_port_index); 261 253 struct team_port *port; 262 - struct hlist_head *head = team_port_index_hash(team, port_index); 263 254 264 - hlist_for_each_entry(port, head, hlist) 265 - if (port->index == port_index) 255 + hlist_for_each_entry(port, head, tx_hlist) 256 + if (port->tx_index == tx_port_index) 266 257 return port; 267 258 return NULL; 268 259 } 269 260 270 261 static inline int team_num_to_port_index(struct team *team, unsigned int num) 271 262 { 272 - int en_port_count = READ_ONCE(team->en_port_count); 263 + int tx_en_port_count = READ_ONCE(team->tx_en_port_count); 273 264 274 - if (unlikely(!en_port_count)) 265 + if (unlikely(!tx_en_port_count)) 275 266 return 0; 276 - return num % en_port_count; 267 + return num % tx_en_port_count; 277 268 } 278 269 279 - static inline struct team_port *team_get_port_by_index_rcu(struct team *team, 280 - int port_index) 270 + static inline struct team_port *team_get_port_by_tx_index_rcu(struct team *team, 271 + int tx_port_index) 281 272 { 273 + struct hlist_head *head = team_tx_port_index_hash(team, tx_port_index); 282 274 struct team_port *port; 283 - struct hlist_head *head = team_port_index_hash(team, port_index); 284 275 285 - hlist_for_each_entry_rcu(port, head, hlist) 286 - if (port->index == port_index) 276 + hlist_for_each_entry_rcu(port, head, tx_hlist) 277 + if (READ_ONCE(port->tx_index) == tx_port_index) 287 278 return port; 288 279 return NULL; 289 280 }
+4
tools/testing/selftests/drivers/net/team/Makefile
··· 2 2 # Makefile for net selftests 3 3 4 4 TEST_PROGS := \ 5 + decoupled_enablement.sh \ 5 6 dev_addr_lists.sh \ 6 7 non_ether_header_ops.sh \ 7 8 options.sh \ 8 9 propagation.sh \ 9 10 refleak.sh \ 11 + teamd_activebackup.sh \ 12 + transmit_failover.sh \ 10 13 # end of TEST_PROGS 11 14 12 15 TEST_INCLUDES := \ 16 + team_lib.sh \ 13 17 ../bonding/lag_lib.sh \ 14 18 ../../../net/forwarding/lib.sh \ 15 19 ../../../net/in_netns.sh \
+4
tools/testing/selftests/drivers/net/team/config
··· 6 6 CONFIG_NET_IPGRE=y 7 7 CONFIG_NET_TEAM=y 8 8 CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=y 9 + CONFIG_NET_TEAM_MODE_BROADCAST=y 9 10 CONFIG_NET_TEAM_MODE_LOADBALANCE=y 11 + CONFIG_NET_TEAM_MODE_RANDOM=y 12 + CONFIG_NET_TEAM_MODE_ROUNDROBIN=y 13 + CONFIG_VETH=y
+249
tools/testing/selftests/drivers/net/team/decoupled_enablement.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + # These tests verify the decoupled RX and TX enablement of team driver member 5 + # interfaces. 6 + # 7 + # Topology 8 + # 9 + # +---------------------+ NS1 10 + # | test_team1 | 11 + # | | | 12 + # | eth0 | 13 + # | | | 14 + # | | | 15 + # +---------------------+ 16 + # | 17 + # +---------------------+ NS2 18 + # | | | 19 + # | | | 20 + # | eth0 | 21 + # | | | 22 + # | test_team2 | 23 + # +---------------------+ 24 + 25 + export ALL_TESTS=" 26 + team_test_tx_enablement 27 + team_test_rx_enablement 28 + " 29 + 30 + test_dir="$(dirname "$0")" 31 + # shellcheck disable=SC1091 32 + source "${test_dir}/../../../net/lib.sh" 33 + # shellcheck disable=SC1091 34 + source "${test_dir}/team_lib.sh" 35 + 36 + NS1="" 37 + NS2="" 38 + export NODAD="nodad" 39 + PREFIX_LENGTH="64" 40 + NS1_IP="fd00::1" 41 + NS2_IP="fd00::2" 42 + NS1_IP4="192.168.0.1" 43 + NS2_IP4="192.168.0.2" 44 + MEMBERS=("eth0") 45 + PING_COUNT=5 46 + PING_TIMEOUT_S=1 47 + PING_INTERVAL=0.1 48 + 49 + while getopts "4" opt; do 50 + case $opt in 51 + 4) 52 + echo "IPv4 mode selected." 53 + export NODAD= 54 + PREFIX_LENGTH="24" 55 + NS1_IP="${NS1_IP4}" 56 + NS2_IP="${NS2_IP4}" 57 + ;; 58 + \?) 59 + echo "Invalid option: -$OPTARG" >&2 60 + exit 1 61 + ;; 62 + esac 63 + done 64 + 65 + # This has to be sourced after opts are gathered... 66 + export REQUIRE_MZ=no 67 + export NUM_NETIFS=0 68 + # shellcheck disable=SC1091 69 + source "${test_dir}/../../../net/forwarding/lib.sh" 70 + 71 + # Create the network namespaces, veth pair, and team devices in the specified 72 + # mode. 73 + # Globals: 74 + # RET - Used by test infra, set by `check_err` functions. 75 + # Arguments: 76 + # mode - The team driver mode to use for the team devices. 77 + environment_create() 78 + { 79 + trap cleanup_all_ns EXIT 80 + setup_ns ns1 ns2 81 + NS1="${NS_LIST[0]}" 82 + NS2="${NS_LIST[1]}" 83 + 84 + # Create the interfaces. 85 + ip -n "${NS1}" link add eth0 type veth peer name eth0 netns "${NS2}" 86 + ip -n "${NS1}" link add test_team1 type team 87 + ip -n "${NS2}" link add test_team2 type team 88 + 89 + # Set up the receiving network namespace's team interface. 90 + setup_team "${NS2}" test_team2 roundrobin "${NS2_IP}" \ 91 + "${PREFIX_LENGTH}" "${MEMBERS[@]}" 92 + } 93 + 94 + # Set a particular option value for team or team port. 95 + # Arguments: 96 + # namespace - The namespace name that has the team. 97 + # option_name - The option name to set. 98 + # option_value - The value to set the option to. 99 + # team_name - The name of team to set the option for. 100 + # member_name - The (optional) optional name of the member port. 101 + set_option_value() 102 + { 103 + local namespace="$1" 104 + local option_name="$2" 105 + local option_value="$3" 106 + local team_name="$4" 107 + local member_name="$5" 108 + local port_flag="--port=${member_name}" 109 + 110 + ip netns exec "${namespace}" teamnl "${team_name}" setoption \ 111 + "${option_name}" "${option_value}" "${port_flag}" 112 + return $? 113 + } 114 + 115 + # Send some pings and return the ping command return value. 116 + try_ping() 117 + { 118 + ip netns exec "${NS1}" ping -i "${PING_INTERVAL}" -c "${PING_COUNT}" \ 119 + "${NS2_IP}" -W "${PING_TIMEOUT_S}" 120 + } 121 + 122 + # Checks tcpdump output from net/forwarding lib, and checks if there are any 123 + # ICMP(4 or 6) packets. 124 + # Arguments: 125 + # interface - The interface name to search for. 126 + # ip_address - The destination IP address (4 or 6) to search for. 127 + did_interface_receive_icmp() 128 + { 129 + local interface="$1" 130 + local ip_address="$2" 131 + local packet_count 132 + 133 + packet_count=$(tcpdump_show "$interface" | grep -c \ 134 + "> ${ip_address}: ICMP") 135 + echo "Packet count for ${interface} was ${packet_count}" 136 + 137 + if [[ "$packet_count" -gt 0 ]]; then 138 + true 139 + else 140 + false 141 + fi 142 + } 143 + 144 + # Test JUST tx enablement with a given mode. 145 + # Globals: 146 + # RET - Used by test infra, set by `check_err` functions. 147 + # Arguments: 148 + # mode - The mode to set the team interfaces to. 149 + team_test_mode_tx_enablement() 150 + { 151 + local mode="$1" 152 + export RET=0 153 + 154 + # Set up the sender team with the correct mode. 155 + setup_team "${NS1}" test_team1 "${mode}" "${NS1_IP}" \ 156 + "${PREFIX_LENGTH}" "${MEMBERS[@]}" 157 + check_err $? "Failed to set up sender team" 158 + 159 + ### Scenario 1: Member interface initially enabled. 160 + # Expect ping to pass 161 + try_ping 162 + check_err $? "Ping failed when TX enabled" 163 + 164 + ### Scenario 2: One tx-side interface disabled. 165 + # Expect ping to fail. 166 + set_option_value "${NS1}" tx_enabled false test_team1 eth0 167 + check_err $? "Failed to disable TX" 168 + tcpdump_start eth0 "${NS2}" 169 + try_ping 170 + check_fail $? "Ping succeeded when TX disabled" 171 + tcpdump_stop eth0 172 + # Expect no packets to be transmitted, since TX is disabled. 173 + did_interface_receive_icmp eth0 "${NS2_IP}" 174 + check_fail $? "eth0 IS transmitting when TX disabled" 175 + tcpdump_cleanup eth0 176 + 177 + ### Scenario 3: The interface has tx re-enabled. 178 + # Expect ping to pass. 179 + set_option_value "${NS1}" tx_enabled true test_team1 eth0 180 + check_err $? "Failed to reenable TX" 181 + try_ping 182 + check_err $? "Ping failed when TX reenabled" 183 + 184 + log_test "TX failover of '${mode}' test" 185 + } 186 + 187 + # Test JUST rx enablement with a given mode. 188 + # Globals: 189 + # RET - Used by test infra, set by `check_err` functions. 190 + # Arguments: 191 + # mode - The mode to set the team interfaces to. 192 + team_test_mode_rx_enablement() 193 + { 194 + local mode="$1" 195 + export RET=0 196 + 197 + # Set up the sender team with the correct mode. 198 + setup_team "${NS1}" test_team1 "${mode}" "${NS1_IP}" \ 199 + "${PREFIX_LENGTH}" "${MEMBERS[@]}" 200 + check_err $? "Failed to set up sender team" 201 + 202 + ### Scenario 1: Member interface initially enabled. 203 + # Expect ping to pass 204 + try_ping 205 + check_err $? "Ping failed when RX enabled" 206 + 207 + ### Scenario 2: One rx-side interface disabled. 208 + # Expect ping to fail. 209 + set_option_value "${NS1}" rx_enabled false test_team1 eth0 210 + check_err $? "Failed to disable RX" 211 + tcpdump_start eth0 "${NS2}" 212 + try_ping 213 + check_fail $? "Ping succeeded when RX disabled" 214 + tcpdump_stop eth0 215 + # Expect packets to be transmitted, since only RX is disabled. 216 + did_interface_receive_icmp eth0 "${NS2_IP}" 217 + check_err $? "eth0 not transmitting when RX disabled" 218 + tcpdump_cleanup eth0 219 + 220 + ### Scenario 3: The interface has rx re-enabled. 221 + # Expect ping to pass. 222 + set_option_value "${NS1}" rx_enabled true test_team1 eth0 223 + check_err $? "Failed to reenable RX" 224 + try_ping 225 + check_err $? "Ping failed when RX reenabled" 226 + 227 + log_test "RX failover of '${mode}' test" 228 + } 229 + 230 + team_test_tx_enablement() 231 + { 232 + team_test_mode_tx_enablement broadcast 233 + team_test_mode_tx_enablement roundrobin 234 + team_test_mode_tx_enablement random 235 + } 236 + 237 + team_test_rx_enablement() 238 + { 239 + team_test_mode_rx_enablement broadcast 240 + team_test_mode_rx_enablement roundrobin 241 + team_test_mode_rx_enablement random 242 + } 243 + 244 + require_command teamnl 245 + require_command tcpdump 246 + require_command ping 247 + environment_create 248 + tests_run 249 + exit "${EXIT_STATUS}"
+98 -1
tools/testing/selftests/drivers/net/team/options.sh
··· 11 11 exit $? 12 12 fi 13 13 14 - ALL_TESTS=" 14 + export ALL_TESTS=" 15 15 team_test_options 16 + team_test_enabled_implicit_changes 17 + team_test_rx_enabled_implicit_changes 18 + team_test_tx_enabled_implicit_changes 16 19 " 17 20 21 + # shellcheck disable=SC1091 18 22 source "${test_dir}/../../../net/lib.sh" 19 23 20 24 TEAM_PORT="team0" ··· 180 176 team_test_option mcast_rejoin_count 0 5 181 177 team_test_option mcast_rejoin_interval 0 5 182 178 team_test_option enabled true false "${MEMBER_PORT}" 179 + team_test_option rx_enabled true false "${MEMBER_PORT}" 180 + team_test_option tx_enabled true false "${MEMBER_PORT}" 183 181 team_test_option user_linkup true false "${MEMBER_PORT}" 184 182 team_test_option user_linkup_enabled true false "${MEMBER_PORT}" 185 183 team_test_option priority 10 20 "${MEMBER_PORT}" 186 184 team_test_option queue_id 0 1 "${MEMBER_PORT}" 187 185 } 186 + 187 + team_test_enabled_implicit_changes() 188 + { 189 + export RET=0 190 + 191 + attach_port_if_specified "${MEMBER_PORT}" 192 + check_err $? "Couldn't attach ${MEMBER_PORT} to master" 193 + 194 + # Set enabled to true. 195 + set_and_check_get enabled true "--port=${MEMBER_PORT}" 196 + check_err $? "Failed to set 'enabled' to true" 197 + 198 + # Show that both rx enabled and tx enabled are true. 199 + get_and_check_value rx_enabled true "--port=${MEMBER_PORT}" 200 + check_err $? "'Rx_enabled' wasn't implicitly set to true" 201 + get_and_check_value tx_enabled true "--port=${MEMBER_PORT}" 202 + check_err $? "'Tx_enabled' wasn't implicitly set to true" 203 + 204 + # Set enabled to false. 205 + set_and_check_get enabled false "--port=${MEMBER_PORT}" 206 + check_err $? "Failed to set 'enabled' to false" 207 + 208 + # Show that both rx enabled and tx enabled are false. 209 + get_and_check_value rx_enabled false "--port=${MEMBER_PORT}" 210 + check_err $? "'Rx_enabled' wasn't implicitly set to false" 211 + get_and_check_value tx_enabled false "--port=${MEMBER_PORT}" 212 + check_err $? "'Tx_enabled' wasn't implicitly set to false" 213 + 214 + log_test "'Enabled' implicit changes" 215 + } 216 + 217 + team_test_rx_enabled_implicit_changes() 218 + { 219 + export RET=0 220 + 221 + attach_port_if_specified "${MEMBER_PORT}" 222 + check_err $? "Couldn't attach ${MEMBER_PORT} to master" 223 + 224 + # Set enabled to true. 225 + set_and_check_get enabled true "--port=${MEMBER_PORT}" 226 + check_err $? "Failed to set 'enabled' to true" 227 + 228 + # Set rx_enabled to false. 229 + set_and_check_get rx_enabled false "--port=${MEMBER_PORT}" 230 + check_err $? "Failed to set 'rx_enabled' to false" 231 + 232 + # Show that enabled is false. 233 + get_and_check_value enabled false "--port=${MEMBER_PORT}" 234 + check_err $? "'enabled' wasn't implicitly set to false" 235 + 236 + # Set rx_enabled to true. 237 + set_and_check_get rx_enabled true "--port=${MEMBER_PORT}" 238 + check_err $? "Failed to set 'rx_enabled' to true" 239 + 240 + # Show that enabled is true. 241 + get_and_check_value enabled true "--port=${MEMBER_PORT}" 242 + check_err $? "'enabled' wasn't implicitly set to true" 243 + 244 + log_test "'Rx_enabled' implicit changes" 245 + } 246 + 247 + team_test_tx_enabled_implicit_changes() 248 + { 249 + export RET=0 250 + 251 + attach_port_if_specified "${MEMBER_PORT}" 252 + check_err $? "Couldn't attach ${MEMBER_PORT} to master" 253 + 254 + # Set enabled to true. 255 + set_and_check_get enabled true "--port=${MEMBER_PORT}" 256 + check_err $? "Failed to set 'enabled' to true" 257 + 258 + # Set tx_enabled to false. 259 + set_and_check_get tx_enabled false "--port=${MEMBER_PORT}" 260 + check_err $? "Failed to set 'tx_enabled' to false" 261 + 262 + # Show that enabled is false. 263 + get_and_check_value enabled false "--port=${MEMBER_PORT}" 264 + check_err $? "'enabled' wasn't implicitly set to false" 265 + 266 + # Set tx_enabled to true. 267 + set_and_check_get tx_enabled true "--port=${MEMBER_PORT}" 268 + check_err $? "Failed to set 'tx_enabled' to true" 269 + 270 + # Show that enabled is true. 271 + get_and_check_value enabled true "--port=${MEMBER_PORT}" 272 + check_err $? "'enabled' wasn't implicitly set to true" 273 + 274 + log_test "'Tx_enabled' implicit changes" 275 + } 276 + 188 277 189 278 require_command teamnl 190 279 setup
+1
tools/testing/selftests/drivers/net/team/settings
··· 1 + timeout=300
+174
tools/testing/selftests/drivers/net/team/team_lib.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + test_dir="$(dirname "$0")" 5 + export REQUIRE_MZ=no 6 + export NUM_NETIFS=0 7 + # shellcheck disable=SC1091 8 + source "${test_dir}/../../../net/forwarding/lib.sh" 9 + 10 + TCP_PORT="43434" 11 + 12 + # Create a team interface inside of a given network namespace with a given 13 + # mode, members, and IP address. 14 + # Arguments: 15 + # namespace - Network namespace to put the team interface into. 16 + # team - The name of the team interface to setup. 17 + # mode - The team mode of the interface. 18 + # ip_address - The IP address to assign to the team interface. 19 + # prefix_length - The prefix length for the IP address subnet. 20 + # $@ - members - The member interfaces of the aggregation. 21 + setup_team() 22 + { 23 + local namespace=$1 24 + local team=$2 25 + local mode=$3 26 + local ip_address=$4 27 + local prefix_length=$5 28 + shift 5 29 + local members=("$@") 30 + 31 + # Prerequisite: team must have no members 32 + for member in "${members[@]}"; do 33 + ip -n "${namespace}" link set "${member}" nomaster 34 + done 35 + 36 + # Prerequisite: team must have no address in order to set it 37 + # shellcheck disable=SC2086 38 + ip -n "${namespace}" addr del "${ip_address}/${prefix_length}" \ 39 + ${NODAD} dev "${team}" 40 + 41 + echo "Setting team in ${namespace} to mode ${mode}" 42 + 43 + if ! ip -n "${namespace}" link set "${team}" down; then 44 + echo "Failed to bring team device down" 45 + return 1 46 + fi 47 + if ! ip netns exec "${namespace}" teamnl "${team}" setoption mode \ 48 + "${mode}"; then 49 + echo "Failed to set ${team} mode to '${mode}'" 50 + return 1 51 + fi 52 + 53 + # Aggregate the members into teams. 54 + for member in "${members[@]}"; do 55 + ip -n "${namespace}" link set "${member}" master "${team}" 56 + done 57 + 58 + # Bring team devices up and give them addresses. 59 + if ! ip -n "${namespace}" link set "${team}" up; then 60 + echo "Failed to set ${team} up" 61 + return 1 62 + fi 63 + 64 + # shellcheck disable=SC2086 65 + if ! ip -n "${namespace}" addr add "${ip_address}/${prefix_length}" \ 66 + ${NODAD} dev "${team}"; then 67 + echo "Failed to give ${team} IP address in ${namespace}" 68 + return 1 69 + fi 70 + } 71 + 72 + # This is global used to keep track of the sender's iperf3 process, so that it 73 + # can be terminated. 74 + declare sender_pid 75 + 76 + # Start sending and receiving TCP traffic with iperf3. 77 + # Globals: 78 + # sender_pid - The process ID of the iperf3 sender process. Used to kill it 79 + # later. 80 + start_listening_and_sending() 81 + { 82 + ip netns exec "${NS2}" iperf3 -s -p "${TCP_PORT}" --logfile /dev/null & 83 + # Wait for server to become reachable before starting client. 84 + slowwait 5 ip netns exec "${NS1}" iperf3 -c "${NS2_IP}" -p \ 85 + "${TCP_PORT}" -t 1 --logfile /dev/null 86 + ip netns exec "${NS1}" iperf3 -c "${NS2_IP}" -p "${TCP_PORT}" -b 1M -l \ 87 + 1K -t 0 --logfile /dev/null & 88 + sender_pid=$! 89 + } 90 + 91 + # Stop sending TCP traffic with iperf3. 92 + # Globals: 93 + # sender_pid - The process ID of the iperf3 sender process. 94 + stop_sending_and_listening() 95 + { 96 + kill "${sender_pid}" && wait "${sender_pid}" 2>/dev/null || true 97 + } 98 + 99 + # Monitor for TCP traffic with Tcpdump, save results to temp files. 100 + # Arguments: 101 + # namespace - The network namespace to run tcpdump inside of. 102 + # $@ - interfaces - The interfaces to listen to. 103 + save_tcpdump_outputs() 104 + { 105 + local namespace=$1 106 + shift 1 107 + local interfaces=("$@") 108 + 109 + for interface in "${interfaces[@]}"; do 110 + tcpdump_start "${interface}" "${namespace}" 111 + done 112 + 113 + sleep 1 114 + 115 + for interface in "${interfaces[@]}"; do 116 + tcpdump_stop_nosleep "${interface}" 117 + done 118 + } 119 + 120 + clear_tcpdump_outputs() 121 + { 122 + local interfaces=("$@") 123 + 124 + for interface in "${interfaces[@]}"; do 125 + tcpdump_cleanup "${interface}" 126 + done 127 + } 128 + 129 + # Read Tcpdump output, determine packet counts. 130 + # Arguments: 131 + # interface - The name of the interface to count packets for. 132 + # ip_address - The destination IP address. 133 + did_interface_receive() 134 + { 135 + local interface="$1" 136 + local ip_address="$2" 137 + local packet_count 138 + 139 + packet_count=$(tcpdump_show "$interface" | grep -c \ 140 + "> ${ip_address}.${TCP_PORT}") 141 + echo "Packet count for ${interface} was ${packet_count}" 142 + 143 + if [[ "${packet_count}" -gt 0 ]]; then 144 + true 145 + else 146 + false 147 + fi 148 + } 149 + 150 + # Return true if the given interface in the given namespace does NOT receive 151 + # traffic over a 1 second period. 152 + # Arguments: 153 + # interface - The name of the interface. 154 + # ip_address - The destination IP address. 155 + # namespace - The name of the namespace that the interface is in. 156 + check_no_traffic() 157 + { 158 + local interface="$1" 159 + local ip_address="$2" 160 + local namespace="$3" 161 + local rc 162 + 163 + save_tcpdump_outputs "${namespace}" "${interface}" 164 + did_interface_receive "${interface}" "${ip_address}" 165 + rc=$? 166 + 167 + clear_tcpdump_outputs "${interface}" 168 + 169 + if [[ "${rc}" -eq 0 ]]; then 170 + return 1 171 + else 172 + return 0 173 + fi 174 + }
+246
tools/testing/selftests/drivers/net/team/teamd_activebackup.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + # These tests verify that teamd is able to enable and disable ports via the 5 + # active backup runner. 6 + # 7 + # Topology: 8 + # 9 + # +-------------------------+ NS1 10 + # | test_team1 | 11 + # | + | 12 + # | eth0 | eth1 | 13 + # | +---+---+ | 14 + # | | | | 15 + # +-------------------------+ 16 + # | | 17 + # +-------------------------+ NS2 18 + # | | | | 19 + # | +-------+ | 20 + # | eth0 | eth1 | 21 + # | + | 22 + # | test_team2 | 23 + # +-------------------------+ 24 + 25 + export ALL_TESTS="teamd_test_active_backup" 26 + 27 + test_dir="$(dirname "$0")" 28 + # shellcheck disable=SC1091 29 + source "${test_dir}/../../../net/lib.sh" 30 + # shellcheck disable=SC1091 31 + source "${test_dir}/team_lib.sh" 32 + 33 + NS1="" 34 + NS2="" 35 + export NODAD="nodad" 36 + PREFIX_LENGTH="64" 37 + NS1_IP="fd00::1" 38 + NS2_IP="fd00::2" 39 + NS1_IP4="192.168.0.1" 40 + NS2_IP4="192.168.0.2" 41 + NS1_TEAMD_CONF="" 42 + NS2_TEAMD_CONF="" 43 + NS1_TEAMD_PID="" 44 + NS2_TEAMD_PID="" 45 + 46 + while getopts "4" opt; do 47 + case $opt in 48 + 4) 49 + echo "IPv4 mode selected." 50 + export NODAD= 51 + PREFIX_LENGTH="24" 52 + NS1_IP="${NS1_IP4}" 53 + NS2_IP="${NS2_IP4}" 54 + ;; 55 + \?) 56 + echo "Invalid option: -${OPTARG}" >&2 57 + exit 1 58 + ;; 59 + esac 60 + done 61 + 62 + teamd_config_create() 63 + { 64 + local runner=$1 65 + local dev=$2 66 + local conf 67 + 68 + conf=$(mktemp) 69 + 70 + cat > "${conf}" <<-EOF 71 + { 72 + "device": "${dev}", 73 + "runner": {"name": "${runner}"}, 74 + "ports": { 75 + "eth0": {}, 76 + "eth1": {} 77 + } 78 + } 79 + EOF 80 + echo "${conf}" 81 + } 82 + 83 + # Create the network namespaces, veth pair, and team devices in the specified 84 + # runner. 85 + # Globals: 86 + # RET - Used by test infra, set by `check_err` functions. 87 + # Arguments: 88 + # runner - The Teamd runner to use for the Team devices. 89 + environment_create() 90 + { 91 + local runner=$1 92 + 93 + echo "Setting up two-link aggregation for runner ${runner}" 94 + echo "Teamd version is: $(teamd --version)" 95 + trap environment_destroy EXIT 96 + 97 + setup_ns ns1 ns2 98 + NS1="${NS_LIST[0]}" 99 + NS2="${NS_LIST[1]}" 100 + 101 + for link in $(seq 0 1); do 102 + ip -n "${NS1}" link add "eth${link}" type veth peer name \ 103 + "eth${link}" netns "${NS2}" 104 + check_err $? "Failed to create veth pair" 105 + done 106 + 107 + NS1_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team1") 108 + NS2_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team2") 109 + echo "Conf files are ${NS1_TEAMD_CONF} and ${NS2_TEAMD_CONF}" 110 + 111 + ip netns exec "${NS1}" teamd -d -f "${NS1_TEAMD_CONF}" 112 + check_err $? "Failed to create team device in ${NS1}" 113 + NS1_TEAMD_PID=$(pgrep -f "teamd -d -f ${NS1_TEAMD_CONF}") 114 + 115 + ip netns exec "${NS2}" teamd -d -f "${NS2_TEAMD_CONF}" 116 + check_err $? "Failed to create team device in ${NS2}" 117 + NS2_TEAMD_PID=$(pgrep -f "teamd -d -f ${NS2_TEAMD_CONF}") 118 + 119 + echo "Created team devices" 120 + echo "Teamd PIDs are ${NS1_TEAMD_PID} and ${NS2_TEAMD_PID}" 121 + 122 + ip -n "${NS1}" link set test_team1 up 123 + check_err $? "Failed to set test_team1 up in ${NS1}" 124 + ip -n "${NS2}" link set test_team2 up 125 + check_err $? "Failed to set test_team2 up in ${NS2}" 126 + 127 + ip -n "${NS1}" addr add "${NS1_IP}/${PREFIX_LENGTH}" "${NODAD}" dev \ 128 + test_team1 129 + check_err $? "Failed to add address to team device in ${NS1}" 130 + ip -n "${NS2}" addr add "${NS2_IP}/${PREFIX_LENGTH}" "${NODAD}" dev \ 131 + test_team2 132 + check_err $? "Failed to add address to team device in ${NS2}" 133 + 134 + slowwait 2 timeout 0.5 ip netns exec "${NS1}" ping -W 1 -c 1 "${NS2_IP}" 135 + } 136 + 137 + # Tear down the environment: kill teamd and delete network namespaces. 138 + environment_destroy() 139 + { 140 + echo "Tearing down two-link aggregation" 141 + 142 + rm "${NS1_TEAMD_CONF}" 143 + rm "${NS2_TEAMD_CONF}" 144 + 145 + # First, try graceful teamd teardown. 146 + ip netns exec "${NS1}" teamd -k -t test_team1 147 + ip netns exec "${NS2}" teamd -k -t test_team2 148 + 149 + # If teamd can't be killed gracefully, then sigkill. 150 + if kill -0 "${NS1_TEAMD_PID}" 2>/dev/null; then 151 + echo "Sending sigkill to teamd for test_team1" 152 + kill -9 "${NS1_TEAMD_PID}" 153 + rm -f /var/run/teamd/test_team1.{pid,sock} 154 + fi 155 + if kill -0 "${NS2_TEAMD_PID}" 2>/dev/null; then 156 + echo "Sending sigkill to teamd for test_team2" 157 + kill -9 "${NS2_TEAMD_PID}" 158 + rm -f /var/run/teamd/test_team2.{pid,sock} 159 + fi 160 + cleanup_all_ns 161 + } 162 + 163 + # Change the active port for an active-backup mode team. 164 + # Arguments: 165 + # namespace - The network namespace that the team is in. 166 + # team - The name of the team. 167 + # active_port - The port to make active. 168 + set_active_port() 169 + { 170 + local namespace=$1 171 + local team=$2 172 + local active_port=$3 173 + 174 + ip netns exec "${namespace}" teamdctl "${team}" state item set \ 175 + runner.active_port "${active_port}" 176 + slowwait 2 bash -c "ip netns exec ${namespace} teamdctl ${team} state \ 177 + item get runner.active_port | grep -q ${active_port}" 178 + } 179 + 180 + # Wait for an interface to stop receiving traffic. If it keeps receiving traffic 181 + # for the duration of the timeout, then return an error. 182 + # Arguments: 183 + # - namespace - The network namespace that the interface is in. 184 + # - interface - The name of the interface. 185 + wait_to_stop_receiving() 186 + { 187 + local namespace=$1 188 + local interface=$2 189 + 190 + echo "Waiting for ${interface} in ${namespace} to stop receiving" 191 + slowwait 10 check_no_traffic "${interface}" "${NS2_IP}" \ 192 + "${namespace}" 193 + } 194 + 195 + # Test that active backup runner can change active ports. 196 + # Globals: 197 + # RET - Used by test infra, set by `check_err` functions. 198 + teamd_test_active_backup() 199 + { 200 + export RET=0 201 + 202 + start_listening_and_sending 203 + 204 + ### Scenario 1: Don't manually set active port, just make sure team 205 + # works. 206 + save_tcpdump_outputs "${NS2}" test_team2 207 + did_interface_receive test_team2 "${NS2_IP}" 208 + check_err $? "Traffic did not reach team interface in NS2." 209 + clear_tcpdump_outputs test_team2 210 + 211 + ### Scenario 2: Choose active port. 212 + set_active_port "${NS1}" test_team1 eth1 213 + set_active_port "${NS2}" test_team2 eth1 214 + 215 + wait_to_stop_receiving "${NS2}" eth0 216 + save_tcpdump_outputs "${NS2}" eth0 eth1 217 + did_interface_receive eth0 "${NS2_IP}" 218 + check_fail $? "eth0 IS transmitting when inactive" 219 + did_interface_receive eth1 "${NS2_IP}" 220 + check_err $? "eth1 not transmitting when active" 221 + clear_tcpdump_outputs eth0 eth1 222 + 223 + ### Scenario 3: Change active port. 224 + set_active_port "${NS1}" test_team1 eth0 225 + set_active_port "${NS2}" test_team2 eth0 226 + 227 + wait_to_stop_receiving "${NS2}" eth1 228 + save_tcpdump_outputs "${NS2}" eth0 eth1 229 + did_interface_receive eth0 "${NS2_IP}" 230 + check_err $? "eth0 not transmitting when active" 231 + did_interface_receive eth1 "${NS2_IP}" 232 + check_fail $? "eth1 IS transmitting when inactive" 233 + clear_tcpdump_outputs eth0 eth1 234 + 235 + log_test "teamd active backup runner test" 236 + 237 + stop_sending_and_listening 238 + } 239 + 240 + require_command teamd 241 + require_command teamdctl 242 + require_command iperf3 243 + require_command tcpdump 244 + environment_create activebackup 245 + tests_run 246 + exit "${EXIT_STATUS}"
+158
tools/testing/selftests/drivers/net/team/transmit_failover.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + # These tests verify the basic failover capability of the team driver via the 5 + # `enabled` team driver option across different team driver modes. This does not 6 + # rely on teamd, and instead just uses teamnl to set the `enabled` option 7 + # directly. 8 + # 9 + # Topology: 10 + # 11 + # +-------------------------+ NS1 12 + # | test_team1 | 13 + # | + | 14 + # | eth0 | eth1 | 15 + # | +---+---+ | 16 + # | | | | 17 + # +-------------------------+ 18 + # | | 19 + # +-------------------------+ NS2 20 + # | | | | 21 + # | +-------+ | 22 + # | eth0 | eth1 | 23 + # | + | 24 + # | test_team2 | 25 + # +-------------------------+ 26 + 27 + export ALL_TESTS="team_test_failover" 28 + 29 + test_dir="$(dirname "$0")" 30 + # shellcheck disable=SC1091 31 + source "${test_dir}/../../../net/lib.sh" 32 + # shellcheck disable=SC1091 33 + source "${test_dir}/team_lib.sh" 34 + 35 + NS1="" 36 + NS2="" 37 + export NODAD="nodad" 38 + PREFIX_LENGTH="64" 39 + NS1_IP="fd00::1" 40 + NS2_IP="fd00::2" 41 + NS1_IP4="192.168.0.1" 42 + NS2_IP4="192.168.0.2" 43 + MEMBERS=("eth0" "eth1") 44 + 45 + while getopts "4" opt; do 46 + case $opt in 47 + 4) 48 + echo "IPv4 mode selected." 49 + export NODAD= 50 + PREFIX_LENGTH="24" 51 + NS1_IP="${NS1_IP4}" 52 + NS2_IP="${NS2_IP4}" 53 + ;; 54 + \?) 55 + echo "Invalid option: -$OPTARG" >&2 56 + exit 1 57 + ;; 58 + esac 59 + done 60 + 61 + # Create the network namespaces, veth pair, and team devices in the specified 62 + # mode. 63 + # Globals: 64 + # RET - Used by test infra, set by `check_err` functions. 65 + # Arguments: 66 + # mode - The team driver mode to use for the team devices. 67 + environment_create() 68 + { 69 + trap cleanup_all_ns EXIT 70 + setup_ns ns1 ns2 71 + NS1="${NS_LIST[0]}" 72 + NS2="${NS_LIST[1]}" 73 + 74 + # Create the interfaces. 75 + ip -n "${NS1}" link add eth0 type veth peer name eth0 netns "${NS2}" 76 + ip -n "${NS1}" link add eth1 type veth peer name eth1 netns "${NS2}" 77 + ip -n "${NS1}" link add test_team1 type team 78 + ip -n "${NS2}" link add test_team2 type team 79 + 80 + # Set up the receiving network namespace's team interface. 81 + setup_team "${NS2}" test_team2 roundrobin "${NS2_IP}" \ 82 + "${PREFIX_LENGTH}" "${MEMBERS[@]}" 83 + } 84 + 85 + 86 + # Check that failover works for a specific team driver mode. 87 + # Globals: 88 + # RET - Used by test infra, set by `check_err` functions. 89 + # Arguments: 90 + # mode - The mode to set the team interfaces to. 91 + team_test_mode_failover() 92 + { 93 + local mode="$1" 94 + export RET=0 95 + 96 + # Set up the sender team with the correct mode. 97 + setup_team "${NS1}" test_team1 "${mode}" "${NS1_IP}" \ 98 + "${PREFIX_LENGTH}" "${MEMBERS[@]}" 99 + check_err $? "Failed to set up sender team" 100 + 101 + start_listening_and_sending 102 + 103 + ### Scenario 1: All interfaces initially enabled. 104 + save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}" 105 + did_interface_receive eth0 "${NS2_IP}" 106 + check_err $? "eth0 not transmitting when both links enabled" 107 + did_interface_receive eth1 "${NS2_IP}" 108 + check_err $? "eth1 not transmitting when both links enabled" 109 + clear_tcpdump_outputs "${MEMBERS[@]}" 110 + 111 + ### Scenario 2: One tx-side interface disabled. 112 + ip netns exec "${NS1}" teamnl test_team1 setoption enabled false \ 113 + --port=eth1 114 + slowwait 2 bash -c "ip netns exec ${NS1} teamnl test_team1 getoption \ 115 + enabled --port=eth1 | grep -q false" 116 + 117 + save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}" 118 + did_interface_receive eth0 "${NS2_IP}" 119 + check_err $? "eth0 not transmitting when enabled" 120 + did_interface_receive eth1 "${NS2_IP}" 121 + check_fail $? "eth1 IS transmitting when disabled" 122 + clear_tcpdump_outputs "${MEMBERS[@]}" 123 + 124 + ### Scenario 3: The interface is re-enabled. 125 + ip netns exec "${NS1}" teamnl test_team1 setoption enabled true \ 126 + --port=eth1 127 + slowwait 2 bash -c "ip netns exec ${NS1} teamnl test_team1 getoption \ 128 + enabled --port=eth1 | grep -q true" 129 + 130 + save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}" 131 + did_interface_receive eth0 "${NS2_IP}" 132 + check_err $? "eth0 not transmitting when both links enabled" 133 + did_interface_receive eth1 "${NS2_IP}" 134 + check_err $? "eth1 not transmitting when both links enabled" 135 + clear_tcpdump_outputs "${MEMBERS[@]}" 136 + 137 + log_test "Failover of '${mode}' test" 138 + 139 + # Clean up 140 + stop_sending_and_listening 141 + } 142 + 143 + team_test_failover() 144 + { 145 + team_test_mode_failover broadcast 146 + team_test_mode_failover roundrobin 147 + team_test_mode_failover random 148 + # Don't test `activebackup` or `loadbalance` modes, since they are too 149 + # complicated for just setting `enabled` to work. They use more than 150 + # the `enabled` option for transmit. 151 + } 152 + 153 + require_command teamnl 154 + require_command iperf3 155 + require_command tcpdump 156 + environment_create 157 + tests_run 158 + exit "${EXIT_STATUS}"
+7 -2
tools/testing/selftests/net/forwarding/lib.sh
··· 1750 1750 sleep 1 1751 1751 } 1752 1752 1753 - tcpdump_stop() 1753 + tcpdump_stop_nosleep() 1754 1754 { 1755 1755 local if_name=$1 1756 1756 local pid=${cappid[$if_name]} 1757 1757 1758 1758 $ns_cmd kill "$pid" && wait "$pid" 1759 + } 1760 + 1761 + tcpdump_stop() 1762 + { 1763 + tcpdump_stop_nosleep "$1" 1759 1764 sleep 1 1760 1765 } 1761 1766 ··· 1775 1770 { 1776 1771 local if_name=$1 1777 1772 1778 - tcpdump -e -n -r ${capfile[$if_name]} 2>&1 1773 + tcpdump -e -nn -r ${capfile[$if_name]} 2>&1 1779 1774 } 1780 1775 1781 1776 # return 0 if the packet wasn't seen on host2_if or 1 if it was
+13
tools/testing/selftests/net/lib.sh
··· 224 224 NS_LIST+=("${ns_list[@]}") 225 225 } 226 226 227 + in_all_ns() 228 + { 229 + local ret=0 230 + local ns_list=("${NS_LIST[@]}") 231 + 232 + for ns in "${ns_list[@]}"; do 233 + ip netns exec "${ns}" "$@" 234 + (( ret = ret || $? )) 235 + done 236 + 237 + return "${ret}" 238 + } 239 + 227 240 # Create netdevsim with given id and net namespace. 228 241 create_netdevsim() { 229 242 local id="$1"