2
0
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:
John Hurley
2018-06-28 17:03:07 +01:00
committed by Simon Horman
parent 25db83be5a
commit d22f8927c3

View File

@@ -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) {