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

Merge branch 'fix-changing-dsa-conduit'

Marek Behún says:

====================
Fix changing DSA conduit

This series fixes an issue in the DSA code related to host interface UC
address installed into port FDB and port conduit address database when
live-changing port conduit.

The first patch refactores/deduplicates the installation/uninstallation
of the interface's MAC address and the second patch fixes the issue.

Cover letter for v1 and v2:
https://patchwork.kernel.org/project/netdevbpf/cover/20240429163627.16031-1-kabel@kernel.org/
https://patchwork.kernel.org/project/netdevbpf/cover/20240502122922.28139-1-kabel@kernel.org/
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+94 -55
+40
net/dsa/port.c
··· 1467 1467 */ 1468 1468 dsa_user_unsync_ha(dev); 1469 1469 1470 + /* If live-changing, we also need to uninstall the user device address 1471 + * from the port FDB and the conduit interface. 1472 + */ 1473 + if (dev->flags & IFF_UP) 1474 + dsa_user_host_uc_uninstall(dev); 1475 + 1470 1476 err = dsa_port_assign_conduit(dp, conduit, extack, true); 1471 1477 if (err) 1472 1478 goto rewind_old_addrs; 1479 + 1480 + /* If the port doesn't have its own MAC address and relies on the DSA 1481 + * conduit's one, inherit it again from the new DSA conduit. 1482 + */ 1483 + if (is_zero_ether_addr(dp->mac)) 1484 + eth_hw_addr_inherit(dev, conduit); 1485 + 1486 + /* If live-changing, we need to install the user device address to the 1487 + * port FDB and the conduit interface. 1488 + */ 1489 + if (dev->flags & IFF_UP) { 1490 + err = dsa_user_host_uc_install(dev, dev->dev_addr); 1491 + if (err) { 1492 + NL_SET_ERR_MSG_MOD(extack, 1493 + "Failed to install host UC address"); 1494 + goto rewind_addr_inherit; 1495 + } 1496 + } 1473 1497 1474 1498 dsa_user_sync_ha(dev); 1475 1499 ··· 1524 1500 rewind_new_addrs: 1525 1501 dsa_user_unsync_ha(dev); 1526 1502 1503 + if (dev->flags & IFF_UP) 1504 + dsa_user_host_uc_uninstall(dev); 1505 + 1506 + rewind_addr_inherit: 1507 + if (is_zero_ether_addr(dp->mac)) 1508 + eth_hw_addr_inherit(dev, old_conduit); 1509 + 1527 1510 dsa_port_assign_conduit(dp, old_conduit, NULL, false); 1528 1511 1529 1512 /* Restore the objects on the old CPU port */ 1530 1513 rewind_old_addrs: 1514 + if (dev->flags & IFF_UP) { 1515 + tmp = dsa_user_host_uc_install(dev, dev->dev_addr); 1516 + if (tmp) { 1517 + dev_err(ds->dev, 1518 + "port %d failed to restore host UC address: %pe\n", 1519 + dp->index, ERR_PTR(tmp)); 1520 + } 1521 + } 1522 + 1531 1523 dsa_user_sync_ha(dev); 1532 1524 1533 1525 if (vlan_filtering) {
+52 -55
net/dsa/user.c
··· 355 355 return READ_ONCE(dsa_user_to_conduit(dev)->ifindex); 356 356 } 357 357 358 - static int dsa_user_open(struct net_device *dev) 358 + int dsa_user_host_uc_install(struct net_device *dev, const u8 *addr) 359 359 { 360 360 struct net_device *conduit = dsa_user_to_conduit(dev); 361 361 struct dsa_port *dp = dsa_user_to_port(dev); 362 362 struct dsa_switch *ds = dp->ds; 363 + int err; 364 + 365 + if (dsa_switch_supports_uc_filtering(ds)) { 366 + err = dsa_port_standalone_host_fdb_add(dp, addr, 0); 367 + if (err) 368 + goto out; 369 + } 370 + 371 + if (!ether_addr_equal(addr, conduit->dev_addr)) { 372 + err = dev_uc_add(conduit, addr); 373 + if (err < 0) 374 + goto del_host_addr; 375 + } 376 + 377 + return 0; 378 + 379 + del_host_addr: 380 + if (dsa_switch_supports_uc_filtering(ds)) 381 + dsa_port_standalone_host_fdb_del(dp, addr, 0); 382 + out: 383 + return err; 384 + } 385 + 386 + void dsa_user_host_uc_uninstall(struct net_device *dev) 387 + { 388 + struct net_device *conduit = dsa_user_to_conduit(dev); 389 + struct dsa_port *dp = dsa_user_to_port(dev); 390 + struct dsa_switch *ds = dp->ds; 391 + 392 + if (!ether_addr_equal(dev->dev_addr, conduit->dev_addr)) 393 + dev_uc_del(conduit, dev->dev_addr); 394 + 395 + if (dsa_switch_supports_uc_filtering(ds)) 396 + dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); 397 + } 398 + 399 + static int dsa_user_open(struct net_device *dev) 400 + { 401 + struct net_device *conduit = dsa_user_to_conduit(dev); 402 + struct dsa_port *dp = dsa_user_to_port(dev); 363 403 int err; 364 404 365 405 err = dev_open(conduit, NULL); ··· 408 368 goto out; 409 369 } 410 370 411 - if (dsa_switch_supports_uc_filtering(ds)) { 412 - err = dsa_port_standalone_host_fdb_add(dp, dev->dev_addr, 0); 413 - if (err) 414 - goto out; 415 - } 416 - 417 - if (!ether_addr_equal(dev->dev_addr, conduit->dev_addr)) { 418 - err = dev_uc_add(conduit, dev->dev_addr); 419 - if (err < 0) 420 - goto del_host_addr; 421 - } 371 + err = dsa_user_host_uc_install(dev, dev->dev_addr); 372 + if (err) 373 + goto out; 422 374 423 375 err = dsa_port_enable_rt(dp, dev->phydev); 424 376 if (err) 425 - goto del_unicast; 377 + goto out_del_host_uc; 426 378 427 379 return 0; 428 380 429 - del_unicast: 430 - if (!ether_addr_equal(dev->dev_addr, conduit->dev_addr)) 431 - dev_uc_del(conduit, dev->dev_addr); 432 - del_host_addr: 433 - if (dsa_switch_supports_uc_filtering(ds)) 434 - dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); 381 + out_del_host_uc: 382 + dsa_user_host_uc_uninstall(dev); 435 383 out: 436 384 return err; 437 385 } 438 386 439 387 static int dsa_user_close(struct net_device *dev) 440 388 { 441 - struct net_device *conduit = dsa_user_to_conduit(dev); 442 389 struct dsa_port *dp = dsa_user_to_port(dev); 443 - struct dsa_switch *ds = dp->ds; 444 390 445 391 dsa_port_disable_rt(dp); 446 392 447 - if (!ether_addr_equal(dev->dev_addr, conduit->dev_addr)) 448 - dev_uc_del(conduit, dev->dev_addr); 449 - 450 - if (dsa_switch_supports_uc_filtering(ds)) 451 - dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); 393 + dsa_user_host_uc_uninstall(dev); 452 394 453 395 return 0; 454 396 } ··· 470 448 471 449 static int dsa_user_set_mac_address(struct net_device *dev, void *a) 472 450 { 473 - struct net_device *conduit = dsa_user_to_conduit(dev); 474 451 struct dsa_port *dp = dsa_user_to_port(dev); 475 452 struct dsa_switch *ds = dp->ds; 476 453 struct sockaddr *addr = a; ··· 491 470 if (!(dev->flags & IFF_UP)) 492 471 goto out_change_dev_addr; 493 472 494 - if (dsa_switch_supports_uc_filtering(ds)) { 495 - err = dsa_port_standalone_host_fdb_add(dp, addr->sa_data, 0); 496 - if (err) 497 - return err; 498 - } 473 + err = dsa_user_host_uc_install(dev, addr->sa_data); 474 + if (err) 475 + return err; 499 476 500 - if (!ether_addr_equal(addr->sa_data, conduit->dev_addr)) { 501 - err = dev_uc_add(conduit, addr->sa_data); 502 - if (err < 0) 503 - goto del_unicast; 504 - } 505 - 506 - if (!ether_addr_equal(dev->dev_addr, conduit->dev_addr)) 507 - dev_uc_del(conduit, dev->dev_addr); 508 - 509 - if (dsa_switch_supports_uc_filtering(ds)) 510 - dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); 477 + dsa_user_host_uc_uninstall(dev); 511 478 512 479 out_change_dev_addr: 513 480 eth_hw_addr_set(dev, addr->sa_data); 514 481 515 482 return 0; 516 - 517 - del_unicast: 518 - if (dsa_switch_supports_uc_filtering(ds)) 519 - dsa_port_standalone_host_fdb_del(dp, addr->sa_data, 0); 520 - 521 - return err; 522 483 } 523 484 524 485 struct dsa_user_dump_ctx { ··· 2881 2878 "nonfatal error updating MTU with new conduit: %pe\n", 2882 2879 ERR_PTR(err)); 2883 2880 } 2884 - 2885 - /* If the port doesn't have its own MAC address and relies on the DSA 2886 - * conduit's one, inherit it again from the new DSA conduit. 2887 - */ 2888 - if (is_zero_ether_addr(dp->mac)) 2889 - eth_hw_addr_inherit(dev, conduit); 2890 2881 2891 2882 return 0; 2892 2883
+2
net/dsa/user.h
··· 42 42 int dsa_user_resume(struct net_device *user_dev); 43 43 int dsa_user_register_notifier(void); 44 44 void dsa_user_unregister_notifier(void); 45 + int dsa_user_host_uc_install(struct net_device *dev, const u8 *addr); 46 + void dsa_user_host_uc_uninstall(struct net_device *dev); 45 47 void dsa_user_sync_ha(struct net_device *dev); 46 48 void dsa_user_unsync_ha(struct net_device *dev); 47 49 void dsa_user_setup_tagger(struct net_device *user);