mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 06:15:47 +00:00
netdev-linux: monitor and offload LAG slaves to TC
A LAG slave cannot be added directly to an OvS bridge, nor can a OvS bridge port be added to a LAG dev. However, LAG masters can be added to OvS. Use TC blocks to indirectly offload slaves when their master is attached as a linux-netdev to an OvS bridge. In the kernel TC datapath, blocks link together netdevs in a similar way to LAG devices. For example, if a filter is added to a block then it is added to all block devices, or if stats are incremented on 1 device then the stats on the entire block are incremented. This mimics LAG devices in that if a rule is applied to the LAG master then it should be applied to all slaves etc. Monitor LAG slaves via the netlink socket in netdev-linux and, if their master is attached to the OvS bridge and has a block id, add the slave's qdisc to the same block. Similarly, if a slave is freed from a master, remove the qdisc from the masters block. Signed-off-by: John Hurley <john.hurley@netronome.com> Reviewed-by: Simon Horman <simon.horman@netronome.com> Reviewed-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Simon Horman <simon.horman@netronome.com>
This commit is contained in:
committed by
Simon Horman
parent
25db83be5a
commit
d22f8927c3
@@ -233,6 +233,18 @@ enum {
|
||||
VALID_FEATURES = 1 << 7,
|
||||
};
|
||||
|
||||
struct linux_lag_slave {
|
||||
uint32_t block_id;
|
||||
struct shash_node *node;
|
||||
};
|
||||
|
||||
/* Protects 'lag_shash' and the mutable members of struct linux_lag_slave. */
|
||||
static struct ovs_mutex lag_mutex = OVS_MUTEX_INITIALIZER;
|
||||
|
||||
/* All slaves whose LAG masters are network devices in OvS. */
|
||||
static struct shash lag_shash OVS_GUARDED_BY(lag_mutex)
|
||||
= SHASH_INITIALIZER(&lag_shash);
|
||||
|
||||
/* Traffic control. */
|
||||
|
||||
/* An instance of a traffic control class. Always associated with a particular
|
||||
@@ -691,6 +703,61 @@ netdev_linux_kind_is_lag(const char *kind)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
netdev_linux_update_lag(struct rtnetlink_change *change)
|
||||
OVS_REQUIRES(lag_mutex)
|
||||
{
|
||||
struct linux_lag_slave *lag;
|
||||
|
||||
if (!rtnetlink_type_is_rtnlgrp_link(change->nlmsg_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (change->slave && netdev_linux_kind_is_lag(change->slave)) {
|
||||
lag = shash_find_data(&lag_shash, change->ifname);
|
||||
|
||||
if (!lag) {
|
||||
struct netdev *master_netdev;
|
||||
char master_name[IFNAMSIZ];
|
||||
uint32_t block_id;
|
||||
int error = 0;
|
||||
|
||||
if_indextoname(change->master_ifindex, master_name);
|
||||
master_netdev = netdev_from_name(master_name);
|
||||
|
||||
if (is_netdev_linux_class(master_netdev->netdev_class)) {
|
||||
block_id = netdev_get_block_id(master_netdev);
|
||||
if (!block_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
lag = xmalloc(sizeof *lag);
|
||||
lag->block_id = block_id;
|
||||
lag->node = shash_add(&lag_shash, change->ifname, lag);
|
||||
|
||||
/* LAG master is linux netdev so add slave to same block. */
|
||||
error = tc_add_del_ingress_qdisc(change->if_index, true,
|
||||
block_id);
|
||||
if (error) {
|
||||
VLOG_WARN("failed to bind LAG slave to master's block");
|
||||
shash_delete(&lag_shash, lag->node);
|
||||
free(lag);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (change->master_ifindex == 0) {
|
||||
/* Check if this was a lag slave that has been freed. */
|
||||
lag = shash_find_data(&lag_shash, change->ifname);
|
||||
|
||||
if (lag) {
|
||||
tc_add_del_ingress_qdisc(change->if_index, false,
|
||||
lag->block_id);
|
||||
shash_delete(&lag_shash, lag->node);
|
||||
free(lag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
netdev_linux_run(const struct netdev_class *netdev_class OVS_UNUSED)
|
||||
{
|
||||
@@ -734,6 +801,12 @@ netdev_linux_run(const struct netdev_class *netdev_class OVS_UNUSED)
|
||||
netdev_linux_update(netdev, nsid, &change);
|
||||
ovs_mutex_unlock(&netdev->mutex);
|
||||
}
|
||||
else if (!netdev_ && change.ifname) {
|
||||
/* Netdev is not present in OvS but its master could be. */
|
||||
ovs_mutex_lock(&lag_mutex);
|
||||
netdev_linux_update_lag(&change);
|
||||
ovs_mutex_unlock(&lag_mutex);
|
||||
}
|
||||
netdev_close(netdev_);
|
||||
}
|
||||
} else if (error == ENOBUFS) {
|
||||
|
Reference in New Issue
Block a user