Skip to content

Commit 8eb3616

Browse files
liuhangbinPaolo Abeni
authored andcommitted
bonding: add ns target multicast address to slave device
Commit 4598380 ("bonding: fix ns validation on backup slaves") tried to resolve the issue where backup slaves couldn't be brought up when receiving IPv6 Neighbor Solicitation (NS) messages. However, this fix only worked for drivers that receive all multicast messages, such as the veth interface. For standard drivers, the NS multicast message is silently dropped because the slave device is not a member of the NS target multicast group. To address this, we need to make the slave device join the NS target multicast group, ensuring it can receive these IPv6 NS messages to validate the slave’s status properly. There are three policies before joining the multicast group: 1. All settings must be under active-backup mode (alb and tlb do not support arp_validate), with backup slaves and slaves supporting multicast. 2. We can add or remove multicast groups when arp_validate changes. 3. Other operations, such as enslaving, releasing, or setting NS targets, need to be guarded by arp_validate. Fixes: 4e24be0 ("bonding: add new parameter ns_targets") Signed-off-by: Hangbin Liu <[email protected]> Reviewed-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent dc06507 commit 8eb3616

File tree

3 files changed

+98
-2
lines changed

3 files changed

+98
-2
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 */

0 commit comments

Comments
 (0)