Skip to content

Commit f8d670b

Browse files
author
Paolo Abeni
committed
Merge branch 'bonding-fix-ns-targets-not-work-on-hardware-nic'
Hangbin Liu says: ==================== bonding: fix ns targets not work on hardware NIC The first patch fixed ns targets not work on hardware NIC when bonding set arp_validate. The second patch add a related selftest for bonding. v4: Thanks Nikolay for the comments: use bond_slave_ns_maddrs_{add/del} with clear name fix comments typos remove _slave_set_ns_maddrs underscore directly update bond_option_arp_validate_set() change logic v3: use ndisc_mc_map to convert the mcast mac address (Jay Vosburgh) v2: only add/del mcast group on backup slaves when arp_validate is set (Jay Vosburgh) arp_validate doesn't support 3ad, tlb, alb. So let's only do it on ab mode. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents dc06507 + 86fb617 commit f8d670b

File tree

4 files changed

+151
-3
lines changed

4 files changed

+151
-3
lines changed

drivers/net/bonding/bond_main.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,8 @@ static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
10081008

10091009
if (bond->dev->flags & IFF_UP)
10101010
bond_hw_addr_flush(bond->dev, old_active->dev);
1011+
1012+
bond_slave_ns_maddrs_add(bond, old_active);
10111013
}
10121014

10131015
if (new_active) {
@@ -1024,6 +1026,8 @@ static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
10241026
dev_mc_sync(new_active->dev, bond->dev);
10251027
netif_addr_unlock_bh(bond->dev);
10261028
}
1029+
1030+
bond_slave_ns_maddrs_del(bond, new_active);
10271031
}
10281032
}
10291033

@@ -2341,6 +2345,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
23412345
bond_compute_features(bond);
23422346
bond_set_carrier(bond);
23432347

2348+
/* Needs to be called before bond_select_active_slave(), which will
2349+
* remove the maddrs if the slave is selected as active slave.
2350+
*/
2351+
bond_slave_ns_maddrs_add(bond, new_slave);
2352+
23442353
if (bond_uses_primary(bond)) {
23452354
block_netpoll_tx();
23462355
bond_select_active_slave(bond);
@@ -2350,7 +2359,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
23502359
if (bond_mode_can_use_xmit_hash(bond))
23512360
bond_update_slave_arr(bond, NULL);
23522361

2353-
23542362
if (!slave_dev->netdev_ops->ndo_bpf ||
23552363
!slave_dev->netdev_ops->ndo_xdp_xmit) {
23562364
if (bond->xdp_prog) {
@@ -2548,6 +2556,12 @@ static int __bond_release_one(struct net_device *bond_dev,
25482556
if (oldcurrent == slave)
25492557
bond_change_active_slave(bond, NULL);
25502558

2559+
/* Must be called after bond_change_active_slave () as the slave
2560+
* might change from an active slave to a backup slave. Then it is
2561+
* necessary to clear the maddrs on the backup slave.
2562+
*/
2563+
bond_slave_ns_maddrs_del(bond, slave);
2564+
25512565
if (bond_is_lb(bond)) {
25522566
/* Must be called only after the slave has been
25532567
* detached from the list and the curr_active_slave

drivers/net/bonding/bond_options.c

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/sched/signal.h>
1616

1717
#include <net/bonding.h>
18+
#include <net/ndisc.h>
1819

1920
static int bond_option_active_slave_set(struct bonding *bond,
2021
const struct bond_opt_value *newval);
@@ -1234,6 +1235,68 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond,
12341235
}
12351236

12361237
#if IS_ENABLED(CONFIG_IPV6)
1238+
static bool slave_can_set_ns_maddr(const struct bonding *bond, struct slave *slave)
1239+
{
1240+
return BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
1241+
!bond_is_active_slave(slave) &&
1242+
slave->dev->flags & IFF_MULTICAST;
1243+
}
1244+
1245+
static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add)
1246+
{
1247+
struct in6_addr *targets = bond->params.ns_targets;
1248+
char slot_maddr[MAX_ADDR_LEN];
1249+
int i;
1250+
1251+
if (!slave_can_set_ns_maddr(bond, slave))
1252+
return;
1253+
1254+
for (i = 0; i < BOND_MAX_NS_TARGETS; i++) {
1255+
if (ipv6_addr_any(&targets[i]))
1256+
break;
1257+
1258+
if (!ndisc_mc_map(&targets[i], slot_maddr, slave->dev, 0)) {
1259+
if (add)
1260+
dev_mc_add(slave->dev, slot_maddr);
1261+
else
1262+
dev_mc_del(slave->dev, slot_maddr);
1263+
}
1264+
}
1265+
}
1266+
1267+
void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave)
1268+
{
1269+
if (!bond->params.arp_validate)
1270+
return;
1271+
slave_set_ns_maddrs(bond, slave, true);
1272+
}
1273+
1274+
void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave)
1275+
{
1276+
if (!bond->params.arp_validate)
1277+
return;
1278+
slave_set_ns_maddrs(bond, slave, false);
1279+
}
1280+
1281+
static void slave_set_ns_maddr(struct bonding *bond, struct slave *slave,
1282+
struct in6_addr *target, struct in6_addr *slot)
1283+
{
1284+
char target_maddr[MAX_ADDR_LEN], slot_maddr[MAX_ADDR_LEN];
1285+
1286+
if (!bond->params.arp_validate || !slave_can_set_ns_maddr(bond, slave))
1287+
return;
1288+
1289+
/* remove the previous maddr from slave */
1290+
if (!ipv6_addr_any(slot) &&
1291+
!ndisc_mc_map(slot, slot_maddr, slave->dev, 0))
1292+
dev_mc_del(slave->dev, slot_maddr);
1293+
1294+
/* add new maddr on slave if target is set */
1295+
if (!ipv6_addr_any(target) &&
1296+
!ndisc_mc_map(target, target_maddr, slave->dev, 0))
1297+
dev_mc_add(slave->dev, target_maddr);
1298+
}
1299+
12371300
static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
12381301
struct in6_addr *target,
12391302
unsigned long last_rx)
@@ -1243,8 +1306,10 @@ static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
12431306
struct slave *slave;
12441307

12451308
if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) {
1246-
bond_for_each_slave(bond, slave, iter)
1309+
bond_for_each_slave(bond, slave, iter) {
12471310
slave->target_last_arp_rx[slot] = last_rx;
1311+
slave_set_ns_maddr(bond, slave, target, &targets[slot]);
1312+
}
12481313
targets[slot] = *target;
12491314
}
12501315
}
@@ -1296,15 +1361,30 @@ static int bond_option_ns_ip6_targets_set(struct bonding *bond,
12961361
{
12971362
return -EPERM;
12981363
}
1364+
1365+
static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add) {}
1366+
1367+
void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave) {}
1368+
1369+
void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave) {}
12991370
#endif
13001371

13011372
static int bond_option_arp_validate_set(struct bonding *bond,
13021373
const struct bond_opt_value *newval)
13031374
{
1375+
bool changed = !!bond->params.arp_validate != !!newval->value;
1376+
struct list_head *iter;
1377+
struct slave *slave;
1378+
13041379
netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n",
13051380
newval->string, newval->value);
13061381
bond->params.arp_validate = newval->value;
13071382

1383+
if (changed) {
1384+
bond_for_each_slave(bond, slave, iter)
1385+
slave_set_ns_maddrs(bond, slave, !!bond->params.arp_validate);
1386+
}
1387+
13081388
return 0;
13091389
}
13101390

include/net/bond_options.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,5 +161,7 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond);
161161
#if IS_ENABLED(CONFIG_IPV6)
162162
void bond_option_ns_ip6_targets_clear(struct bonding *bond);
163163
#endif
164+
void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave);
165+
void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave);
164166

165167
#endif /* _NET_BOND_OPTIONS_H */

tools/testing/selftests/drivers/net/bonding/bond_options.sh

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ ALL_TESTS="
1111

1212
lib_dir=$(dirname "$0")
1313
source ${lib_dir}/bond_topo_3d1c.sh
14+
c_maddr="33:33:00:00:00:10"
15+
g_maddr="33:33:00:00:02:54"
1416

1517
skip_prio()
1618
{
@@ -240,6 +242,54 @@ arp_validate_test()
240242
done
241243
}
242244

245+
# Testing correct multicast groups are added to slaves for ns targets
246+
arp_validate_mcast()
247+
{
248+
RET=0
249+
local arp_valid=$(cmd_jq "ip -n ${s_ns} -j -d link show bond0" ".[].linkinfo.info_data.arp_validate")
250+
local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
251+
252+
for i in $(seq 0 2); do
253+
maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
254+
255+
# arp_valid == 0 or active_slave should not join any maddrs
256+
if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
257+
echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
258+
RET=1
259+
check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
260+
# arp_valid != 0 and backup_slave should join both maddrs
261+
elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
262+
( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
263+
! echo "$maddr_list" | grep -q "${m_maddr}"); then
264+
RET=1
265+
check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
266+
fi
267+
done
268+
269+
# Do failover
270+
ip -n ${s_ns} link set ${active_slave} down
271+
# wait for active link change
272+
slowwait 2 active_slave_changed $active_slave
273+
active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
274+
275+
for i in $(seq 0 2); do
276+
maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
277+
278+
# arp_valid == 0 or active_slave should not join any maddrs
279+
if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
280+
echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
281+
RET=1
282+
check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
283+
# arp_valid != 0 and backup_slave should join both maddrs
284+
elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
285+
( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
286+
! echo "$maddr_list" | grep -q "${m_maddr}"); then
287+
RET=1
288+
check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
289+
fi
290+
done
291+
}
292+
243293
arp_validate_arp()
244294
{
245295
local mode=$1
@@ -261,8 +311,10 @@ arp_validate_ns()
261311
fi
262312

263313
for val in $(seq 0 6); do
264-
arp_validate_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6} arp_validate $val"
314+
arp_validate_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6},${c_ip6} arp_validate $val"
265315
log_test "arp_validate" "$mode ns_ip6_target arp_validate $val"
316+
arp_validate_mcast
317+
log_test "arp_validate" "join mcast group"
266318
done
267319
}
268320

0 commit comments

Comments
 (0)