2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-30 22:05:19 +00:00

tc: allow offloading of block ids

Blocks, in tc classifiers, allow the grouping of multiple qdiscs with an
associated block id. Whenever a filter is added to/removed from this
block, the filter is added to/removed from all associated qdiscs.

Extend TC offload functions to take a block id as a parameter. If the id
is zero then the dqisc is not considered part of a 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:02 +01:00
committed by Simon Horman
parent e461481330
commit 093c9458fb
4 changed files with 98 additions and 42 deletions

View File

@@ -2275,7 +2275,7 @@ netdev_linux_set_policing(struct netdev *netdev_,
COVERAGE_INC(netdev_set_policing);
/* Remove any existing ingress qdisc. */
error = tc_add_del_ingress_qdisc(ifindex, false);
error = tc_add_del_ingress_qdisc(ifindex, false, 0);
if (error) {
VLOG_WARN_RL(&rl, "%s: removing policing failed: %s",
netdev_name, ovs_strerror(error));
@@ -2283,7 +2283,7 @@ netdev_linux_set_policing(struct netdev *netdev_,
}
if (kbits_rate) {
error = tc_add_del_ingress_qdisc(ifindex, true);
error = tc_add_del_ingress_qdisc(ifindex, true, 0);
if (error) {
VLOG_WARN_RL(&rl, "%s: adding policing qdisc failed: %s",
netdev_name, ovs_strerror(error));

View File

@@ -44,6 +44,7 @@ static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);
static struct hmap ufid_tc = HMAP_INITIALIZER(&ufid_tc);
static bool multi_mask_per_prio = false;
static bool block_support = false;
struct netlink_field {
int offset;
@@ -307,6 +308,7 @@ int
netdev_tc_flow_flush(struct netdev *netdev)
{
int ifindex = netdev_get_ifindex(netdev);
uint32_t block_id = 0;
if (ifindex < 0) {
VLOG_ERR_RL(&error_rl, "flow_flush: failed to get ifindex for %s: %s",
@@ -314,7 +316,7 @@ netdev_tc_flow_flush(struct netdev *netdev)
return -ifindex;
}
return tc_flush(ifindex);
return tc_flush(ifindex, block_id);
}
int
@@ -322,6 +324,7 @@ netdev_tc_flow_dump_create(struct netdev *netdev,
struct netdev_flow_dump **dump_out)
{
struct netdev_flow_dump *dump;
uint32_t block_id = 0;
int ifindex;
ifindex = netdev_get_ifindex(netdev);
@@ -334,7 +337,7 @@ netdev_tc_flow_dump_create(struct netdev *netdev,
dump = xzalloc(sizeof *dump);
dump->nl_dump = xzalloc(sizeof *dump->nl_dump);
dump->netdev = netdev_ref(netdev);
tc_dump_flower_start(ifindex, dump->nl_dump);
tc_dump_flower_start(ifindex, dump->nl_dump, block_id);
*dump_out = dump;
@@ -890,6 +893,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
struct flow *mask = &match->wc.masks;
const struct flow_tnl *tnl = &match->flow.tunnel;
struct tc_action *action;
uint32_t block_id = 0;
struct nlattr *nla;
size_t left;
int prio = 0;
@@ -1097,7 +1101,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
handle = get_ufid_tc_mapping(ufid, &prio, NULL);
if (handle && prio) {
VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d", handle, prio);
tc_del_filter(ifindex, prio, handle);
tc_del_filter(ifindex, prio, handle, block_id);
}
if (!prio) {
@@ -1111,7 +1115,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
flower.act_cookie.data = ufid;
flower.act_cookie.len = sizeof *ufid;
err = tc_replace_flower(ifindex, prio, handle, &flower);
err = tc_replace_flower(ifindex, prio, handle, &flower, block_id);
if (!err) {
add_ufid_tc_mapping(ufid, flower.prio, flower.handle, netdev, ifindex);
}
@@ -1131,6 +1135,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED,
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
struct netdev *dev;
struct tc_flower flower;
uint32_t block_id = 0;
odp_port_t in_port;
int prio = 0;
int ifindex;
@@ -1152,7 +1157,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED,
VLOG_DBG_RL(&rl, "flow get (dev %s prio %d handle %d)",
netdev_get_name(dev), prio, handle);
err = tc_get_flower(ifindex, prio, handle, &flower);
err = tc_get_flower(ifindex, prio, handle, &flower, block_id);
netdev_close(dev);
if (err) {
VLOG_ERR_RL(&error_rl, "flow get failed (dev %s prio %d handle %d): %s",
@@ -1175,6 +1180,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
struct dpif_flow_stats *stats)
{
struct tc_flower flower;
uint32_t block_id = 0;
struct netdev *dev;
int prio = 0;
int ifindex;
@@ -1196,14 +1202,14 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
if (stats) {
memset(stats, 0, sizeof *stats);
if (!tc_get_flower(ifindex, prio, handle, &flower)) {
if (!tc_get_flower(ifindex, prio, handle, &flower, block_id)) {
stats->n_packets = get_32aligned_u64(&flower.stats.n_packets);
stats->n_bytes = get_32aligned_u64(&flower.stats.n_bytes);
stats->used = flower.lastused;
}
}
error = tc_del_filter(ifindex, prio, handle);
error = tc_del_filter(ifindex, prio, handle, block_id);
del_ufid_tc_mapping(ufid);
netdev_close(dev);
@@ -1212,7 +1218,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
}
static void
probe_multi_mask_per_prio(int ifindex)
probe_multi_mask_per_prio(int ifindex, uint32_t block_id)
{
struct tc_flower flower;
int error;
@@ -1224,7 +1230,7 @@ probe_multi_mask_per_prio(int ifindex)
memset(&flower.key.dst_mac, 0x11, sizeof flower.key.dst_mac);
memset(&flower.mask.dst_mac, 0xff, sizeof flower.mask.dst_mac);
error = tc_replace_flower(ifindex, 1, 1, &flower);
error = tc_replace_flower(ifindex, 1, 1, &flower, block_id);
if (error) {
return;
}
@@ -1232,23 +1238,42 @@ probe_multi_mask_per_prio(int ifindex)
memset(&flower.key.src_mac, 0x11, sizeof flower.key.src_mac);
memset(&flower.mask.src_mac, 0xff, sizeof flower.mask.src_mac);
error = tc_replace_flower(ifindex, 1, 2, &flower);
tc_del_filter(ifindex, 1, 1);
error = tc_replace_flower(ifindex, 1, 2, &flower, block_id);
tc_del_filter(ifindex, 1, 1, block_id);
if (error) {
return;
}
tc_del_filter(ifindex, 1, 2);
tc_del_filter(ifindex, 1, 2, block_id);
multi_mask_per_prio = true;
VLOG_INFO("probe tc: multiple masks on single tc prio is supported.");
}
static void
probe_tc_block_support(int ifindex)
{
uint32_t block_id = 1;
int error;
error = tc_add_del_ingress_qdisc(ifindex, true, block_id);
if (error) {
return;
}
tc_add_del_ingress_qdisc(ifindex, false, block_id);
block_support = true;
VLOG_INFO("probe tc: block offload is supported.");
}
int
netdev_tc_init_flow_api(struct netdev *netdev)
{
static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
static struct ovsthread_once multi_mask_once = OVSTHREAD_ONCE_INITIALIZER;
static struct ovsthread_once block_once = OVSTHREAD_ONCE_INITIALIZER;
uint32_t block_id = 0;
int ifindex;
int error;
@@ -1259,7 +1284,12 @@ netdev_tc_init_flow_api(struct netdev *netdev)
return -ifindex;
}
error = tc_add_del_ingress_qdisc(ifindex, true);
if (ovsthread_once_start(&block_once)) {
probe_tc_block_support(ifindex);
ovsthread_once_done(&block_once);
}
error = tc_add_del_ingress_qdisc(ifindex, true, block_id);
if (error && error != EEXIST) {
VLOG_ERR("failed adding ingress qdisc required for offloading: %s",
@@ -1269,9 +1299,9 @@ netdev_tc_init_flow_api(struct netdev *netdev)
VLOG_INFO("added ingress qdisc to %s", netdev_get_name(netdev));
if (ovsthread_once_start(&once)) {
probe_multi_mask_per_prio(ifindex);
ovsthread_once_done(&once);
if (ovsthread_once_start(&multi_mask_once)) {
probe_multi_mask_per_prio(ifindex, block_id);
ovsthread_once_done(&multi_mask_once);
}
return 0;

View File

@@ -43,6 +43,14 @@
#define MAX_PEDIT_OFFSETS 32
#ifndef TCM_IFINDEX_MAGIC_BLOCK
#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
#endif
#if TCA_MAX < 14
#define TCA_INGRESS_BLOCK 13
#endif
VLOG_DEFINE_THIS_MODULE(tc);
static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);
@@ -173,10 +181,14 @@ tc_transact(struct ofpbuf *request, struct ofpbuf **replyp)
* The configuration and stats may be seen with the following command:
* /sbin/tc -s qdisc show dev <devname>
*
* If block_id is greater than 0, then the ingress qdisc is added to a block.
* In this case, it is equivalent to running (when 'add' is true):
* /sbin/tc qdisc add dev <devname> ingress_block <block_id> ingress
*
* Returns 0 if successful, otherwise a positive errno value.
*/
int
tc_add_del_ingress_qdisc(int ifindex, bool add)
tc_add_del_ingress_qdisc(int ifindex, bool add, uint32_t block_id)
{
struct ofpbuf request;
struct tcmsg *tcmsg;
@@ -189,6 +201,9 @@ tc_add_del_ingress_qdisc(int ifindex, bool add)
tcmsg->tcm_parent = TC_H_INGRESS;
nl_msg_put_string(&request, TCA_KIND, "ingress");
nl_msg_put_unspec(&request, TCA_OPTIONS, NULL, 0);
if (block_id) {
nl_msg_put_u32(&request, TCA_INGRESS_BLOCK, block_id);
}
error = tc_transact(&request, NULL);
if (error) {
@@ -1007,13 +1022,15 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_flower *flower)
}
int
tc_dump_flower_start(int ifindex, struct nl_dump *dump)
tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id)
{
struct ofpbuf request;
struct tcmsg *tcmsg;
int index;
tcmsg = tc_make_request(ifindex, RTM_GETTFILTER, NLM_F_DUMP, &request);
tcmsg->tcm_parent = TC_INGRESS_PARENT;
index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex;
tcmsg = tc_make_request(index, RTM_GETTFILTER, NLM_F_DUMP, &request);
tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT;
tcmsg->tcm_info = TC_H_UNSPEC;
tcmsg->tcm_handle = 0;
@@ -1024,28 +1041,32 @@ tc_dump_flower_start(int ifindex, struct nl_dump *dump)
}
int
tc_flush(int ifindex)
tc_flush(int ifindex, uint32_t block_id)
{
struct ofpbuf request;
struct tcmsg *tcmsg;
int index;
tcmsg = tc_make_request(ifindex, RTM_DELTFILTER, NLM_F_ACK, &request);
tcmsg->tcm_parent = TC_INGRESS_PARENT;
index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex;
tcmsg = tc_make_request(index, RTM_DELTFILTER, NLM_F_ACK, &request);
tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT;
tcmsg->tcm_info = TC_H_UNSPEC;
return tc_transact(&request, NULL);
}
int
tc_del_filter(int ifindex, int prio, int handle)
tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id)
{
struct ofpbuf request;
struct tcmsg *tcmsg;
struct ofpbuf *reply;
int error;
int index;
tcmsg = tc_make_request(ifindex, RTM_DELTFILTER, NLM_F_ECHO, &request);
tcmsg->tcm_parent = TC_INGRESS_PARENT;
index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex;
tcmsg = tc_make_request(index, RTM_DELTFILTER, NLM_F_ECHO, &request);
tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT;
tcmsg->tcm_info = tc_make_handle(prio, 0);
tcmsg->tcm_handle = handle;
@@ -1057,15 +1078,18 @@ tc_del_filter(int ifindex, int prio, int handle)
}
int
tc_get_flower(int ifindex, int prio, int handle, struct tc_flower *flower)
tc_get_flower(int ifindex, int prio, int handle, struct tc_flower *flower,
uint32_t block_id)
{
struct ofpbuf request;
struct tcmsg *tcmsg;
struct ofpbuf *reply;
int error;
int index;
tcmsg = tc_make_request(ifindex, RTM_GETTFILTER, NLM_F_ECHO, &request);
tcmsg->tcm_parent = TC_INGRESS_PARENT;
index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex;
tcmsg = tc_make_request(index, RTM_GETTFILTER, NLM_F_ECHO, &request);
tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT;
tcmsg->tcm_info = tc_make_handle(prio, 0);
tcmsg->tcm_handle = handle;
@@ -1625,7 +1649,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
int
tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,
struct tc_flower *flower)
struct tc_flower *flower, uint32_t block_id)
{
struct ofpbuf request;
struct tcmsg *tcmsg;
@@ -1633,10 +1657,12 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,
int error = 0;
size_t basic_offset;
uint16_t eth_type = (OVS_FORCE uint16_t) flower->key.eth_type;
int index;
tcmsg = tc_make_request(ifindex, RTM_NEWTFILTER,
NLM_F_CREATE | NLM_F_ECHO, &request);
tcmsg->tcm_parent = TC_INGRESS_PARENT;
index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex;
tcmsg = tc_make_request(index, RTM_NEWTFILTER, NLM_F_CREATE | NLM_F_ECHO,
&request);
tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT;
tcmsg->tcm_info = tc_make_handle(prio, eth_type);
tcmsg->tcm_handle = handle;

View File

@@ -63,7 +63,7 @@ tc_get_minor(unsigned int handle)
struct tcmsg *tc_make_request(int ifindex, int type,
unsigned int flags, struct ofpbuf *);
int tc_transact(struct ofpbuf *request, struct ofpbuf **replyp);
int tc_add_del_ingress_qdisc(int ifindex, bool add);
int tc_add_del_ingress_qdisc(int ifindex, bool add, uint32_t block_id);
struct tc_cookie {
const void *data;
@@ -198,12 +198,12 @@ BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite)
+ sizeof(uint32_t) - 2 < sizeof(struct tc_flower));
int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,
struct tc_flower *flower);
int tc_del_filter(int ifindex, int prio, int handle);
struct tc_flower *flower, uint32_t block_id);
int tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id);
int tc_get_flower(int ifindex, int prio, int handle,
struct tc_flower *flower);
int tc_flush(int ifindex);
int tc_dump_flower_start(int ifindex, struct nl_dump *dump);
struct tc_flower *flower, uint32_t block_id);
int tc_flush(int ifindex, uint32_t block_id);
int tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id);
int parse_netlink_to_tc_flower(struct ofpbuf *reply,
struct tc_flower *flower);
void tc_set_policy(const char *policy);