Skip to content

Commit f7936b7

Browse files
SandyWinterdavem330
authored andcommitted
s390/qeth: Update MACs of LEARNING_SYNC device
Update the MAC addresses that are registered with a LEARNING_SYNC qeth device with the events announced by the attached software bridge. Typically the LEARNING_SYNC qeth bridge port has an isolated sibling (the default interface of an 'HiperSockets Converged Interface' (HSCI)). Update the MACs of isolated siblings as well, to avoid unnecessary flooding in the attached virtualized switches. Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com> Signed-off-by: Karsten Graul <kgraul@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 4e20e73 commit f7936b7

File tree

1 file changed

+127
-4
lines changed

1 file changed

+127
-4
lines changed

drivers/s390/net/qeth_l2_main.c

Lines changed: 127 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,15 @@ static int qeth_l2_dev2br_an_set(struct qeth_card *card, bool enable)
717717
return rc;
718718
}
719719

720+
struct qeth_l2_br2dev_event_work {
721+
struct work_struct work;
722+
struct net_device *br_dev;
723+
struct net_device *lsync_dev;
724+
struct net_device *dst_dev;
725+
unsigned long event;
726+
unsigned char addr[ETH_ALEN];
727+
};
728+
720729
static const struct net_device_ops qeth_l2_netdev_ops;
721730

722731
static bool qeth_l2_must_learn(struct net_device *netdev,
@@ -732,6 +741,116 @@ static bool qeth_l2_must_learn(struct net_device *netdev,
732741
netdev->netdev_ops == &qeth_l2_netdev_ops);
733742
}
734743

744+
/**
745+
* qeth_l2_br2dev_worker() - update local MACs
746+
* @work: bridge to device FDB update
747+
*
748+
* Update local MACs of a learning_sync bridgeport so it can receive
749+
* messages for a destination port.
750+
* In case of an isolated learning_sync port, also update its isolated
751+
* siblings.
752+
*/
753+
static void qeth_l2_br2dev_worker(struct work_struct *work)
754+
{
755+
struct qeth_l2_br2dev_event_work *br2dev_event_work =
756+
container_of(work, struct qeth_l2_br2dev_event_work, work);
757+
struct net_device *lsyncdev = br2dev_event_work->lsync_dev;
758+
struct net_device *dstdev = br2dev_event_work->dst_dev;
759+
struct net_device *brdev = br2dev_event_work->br_dev;
760+
unsigned long event = br2dev_event_work->event;
761+
unsigned char *addr = br2dev_event_work->addr;
762+
struct qeth_card *card = lsyncdev->ml_priv;
763+
struct net_device *lowerdev;
764+
struct list_head *iter;
765+
int err = 0;
766+
767+
kfree(br2dev_event_work);
768+
QETH_CARD_TEXT_(card, 4, "b2dw%04x", event);
769+
QETH_CARD_TEXT_(card, 4, "ma%012lx", ether_addr_to_u64(addr));
770+
771+
rcu_read_lock();
772+
/* Verify preconditions are still valid: */
773+
if (!netif_is_bridge_port(lsyncdev) ||
774+
brdev != netdev_master_upper_dev_get_rcu(lsyncdev))
775+
goto unlock;
776+
if (!qeth_l2_must_learn(lsyncdev, dstdev))
777+
goto unlock;
778+
779+
if (br_port_flag_is_set(lsyncdev, BR_ISOLATED)) {
780+
/* Update lsyncdev and its isolated sibling(s): */
781+
iter = &brdev->adj_list.lower;
782+
lowerdev = netdev_next_lower_dev_rcu(brdev, &iter);
783+
while (lowerdev) {
784+
if (br_port_flag_is_set(lowerdev, BR_ISOLATED)) {
785+
switch (event) {
786+
case SWITCHDEV_FDB_ADD_TO_DEVICE:
787+
err = dev_uc_add(lowerdev, addr);
788+
break;
789+
case SWITCHDEV_FDB_DEL_TO_DEVICE:
790+
err = dev_uc_del(lowerdev, addr);
791+
break;
792+
default:
793+
break;
794+
}
795+
if (err) {
796+
QETH_CARD_TEXT(card, 2, "b2derris");
797+
QETH_CARD_TEXT_(card, 2,
798+
"err%02x%03d", event,
799+
lowerdev->ifindex);
800+
}
801+
}
802+
lowerdev = netdev_next_lower_dev_rcu(brdev, &iter);
803+
}
804+
} else {
805+
switch (event) {
806+
case SWITCHDEV_FDB_ADD_TO_DEVICE:
807+
err = dev_uc_add(lsyncdev, addr);
808+
break;
809+
case SWITCHDEV_FDB_DEL_TO_DEVICE:
810+
err = dev_uc_del(lsyncdev, addr);
811+
break;
812+
default:
813+
break;
814+
}
815+
if (err)
816+
QETH_CARD_TEXT_(card, 2, "b2derr%02x", event);
817+
}
818+
819+
unlock:
820+
rcu_read_unlock();
821+
dev_put(brdev);
822+
dev_put(lsyncdev);
823+
dev_put(dstdev);
824+
}
825+
826+
static int qeth_l2_br2dev_queue_work(struct net_device *brdev,
827+
struct net_device *lsyncdev,
828+
struct net_device *dstdev,
829+
unsigned long event,
830+
const unsigned char *addr)
831+
{
832+
struct qeth_l2_br2dev_event_work *worker_data;
833+
struct qeth_card *card;
834+
835+
worker_data = kzalloc(sizeof(*worker_data), GFP_ATOMIC);
836+
if (!worker_data)
837+
return -ENOMEM;
838+
INIT_WORK(&worker_data->work, qeth_l2_br2dev_worker);
839+
worker_data->br_dev = brdev;
840+
worker_data->lsync_dev = lsyncdev;
841+
worker_data->dst_dev = dstdev;
842+
worker_data->event = event;
843+
ether_addr_copy(worker_data->addr, addr);
844+
845+
card = lsyncdev->ml_priv;
846+
/* Take a reference on the sw port devices and the bridge */
847+
dev_hold(brdev);
848+
dev_hold(lsyncdev);
849+
dev_hold(dstdev);
850+
queue_work(card->event_wq, &worker_data->work);
851+
return 0;
852+
}
853+
735854
/* Called under rtnl_lock */
736855
static int qeth_l2_switchdev_event(struct notifier_block *unused,
737856
unsigned long event, void *ptr)
@@ -741,6 +860,7 @@ static int qeth_l2_switchdev_event(struct notifier_block *unused,
741860
struct switchdev_notifier_info *info = ptr;
742861
struct list_head *iter;
743862
struct qeth_card *card;
863+
int rc;
744864

745865
if (!(event == SWITCHDEV_FDB_ADD_TO_DEVICE ||
746866
event == SWITCHDEV_FDB_DEL_TO_DEVICE))
@@ -759,10 +879,13 @@ static int qeth_l2_switchdev_event(struct notifier_block *unused,
759879
if (qeth_l2_must_learn(lowerdev, dstdev)) {
760880
card = lowerdev->ml_priv;
761881
QETH_CARD_TEXT_(card, 4, "b2dqw%03x", event);
762-
/* tbd: rc = qeth_l2_br2dev_queue_work(brdev, lowerdev,
763-
* dstdev, event,
764-
* fdb_info->addr);
765-
*/
882+
rc = qeth_l2_br2dev_queue_work(brdev, lowerdev,
883+
dstdev, event,
884+
fdb_info->addr);
885+
if (rc) {
886+
QETH_CARD_TEXT(card, 2, "b2dqwerr");
887+
return NOTIFY_BAD;
888+
}
766889
}
767890
lowerdev = netdev_next_lower_dev_rcu(brdev, &iter);
768891
}

0 commit comments

Comments
 (0)