net/tap: support actions for different classifiers
Add a generic TC actions handling for TC actions: "mirred", "gact", "skbedit". This will be useful when introducing BPF actions, as it uses TCA_BPF_ACT instead of TCA_FLOWER_ACT Signed-off-by: Ophir Munk <ophirmu@mellanox.com> Acked-by: Pascal Mazon <pascal.mazon@6wind.com>
This commit is contained in:
parent
f81ec74843
commit
fb847dcf73
@ -12,6 +12,12 @@ EXPORT_MAP := rte_pmd_tap_version.map
|
||||
|
||||
LIBABIVER := 1
|
||||
|
||||
#
|
||||
# TAP_MAX_QUEUES must be a power of 2
|
||||
#
|
||||
ifeq ($(TAP_MAX_QUEUES),)
|
||||
TAP_MAX_QUEUES = 16
|
||||
endif
|
||||
CFLAGS += -O3
|
||||
CFLAGS += -I$(SRCDIR)
|
||||
CFLAGS += -I.
|
||||
@ -20,6 +26,8 @@ LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
|
||||
LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs -lrte_hash
|
||||
LDLIBS += -lrte_bus_vdev
|
||||
|
||||
CFLAGS += -DTAP_MAX_QUEUES=$(TAP_MAX_QUEUES)
|
||||
|
||||
#
|
||||
# all source are stored in SRCS-y
|
||||
#
|
||||
|
@ -45,7 +45,7 @@
|
||||
#include <rte_ether.h>
|
||||
|
||||
#ifdef IFF_MULTI_QUEUE
|
||||
#define RTE_PMD_TAP_MAX_QUEUES 16
|
||||
#define RTE_PMD_TAP_MAX_QUEUES TAP_MAX_QUEUES
|
||||
#else
|
||||
#define RTE_PMD_TAP_MAX_QUEUES 1
|
||||
#endif
|
||||
@ -91,6 +91,8 @@ struct pmd_internals {
|
||||
int ioctl_sock; /* socket for ioctl calls */
|
||||
int nlsk_fd; /* Netlink socket fd */
|
||||
int flow_isolate; /* 1 if flow isolation is enabled */
|
||||
int flower_support; /* 1 if kernel supports, else 0 */
|
||||
int flower_vlan_support; /* 1 if kernel supports, else 0 */
|
||||
LIST_HEAD(tap_flows, rte_flow) flows; /* rte_flow rules */
|
||||
/* implicit rte_flow rules set when a remote device is active */
|
||||
LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <rte_byteorder.h>
|
||||
@ -104,6 +105,19 @@ struct remote_rule {
|
||||
int mirred;
|
||||
};
|
||||
|
||||
struct action_data {
|
||||
char id[16];
|
||||
|
||||
union {
|
||||
struct tc_gact gact;
|
||||
struct tc_mirred mirred;
|
||||
struct skbedit {
|
||||
struct tc_skbedit skbedit;
|
||||
uint16_t queue;
|
||||
} skbedit;
|
||||
};
|
||||
};
|
||||
|
||||
static int tap_flow_create_eth(const struct rte_flow_item *item, void *data);
|
||||
static int tap_flow_create_vlan(const struct rte_flow_item *item, void *data);
|
||||
static int tap_flow_create_ipv4(const struct rte_flow_item *item, void *data);
|
||||
@ -819,111 +833,89 @@ tap_flow_item_validate(const struct rte_flow_item *item,
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a DROP/PASSTHRU action item in the provided flow for TC.
|
||||
* Configure the kernel with a TC action and its configured parameters
|
||||
* Handled actions: "gact", "mirred", "skbedit", "bpf"
|
||||
*
|
||||
* @param[in, out] flow
|
||||
* Flow to be filled.
|
||||
* @param[in] action
|
||||
* Appropriate action to be set in the TCA_GACT_PARMS structure.
|
||||
* @param[in] flow
|
||||
* Pointer to rte flow containing the netlink message
|
||||
*
|
||||
* @param[in, out] act_index
|
||||
* Pointer to action sequence number in the TC command
|
||||
*
|
||||
* @param[in] adata
|
||||
* Pointer to struct holding the action parameters
|
||||
*
|
||||
* @return
|
||||
* 0 if checks are alright, -1 otherwise.
|
||||
* -1 on failure, 0 on success
|
||||
*/
|
||||
static int
|
||||
add_action_gact(struct rte_flow *flow, int action)
|
||||
add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
|
||||
{
|
||||
struct nlmsg *msg = &flow->msg;
|
||||
size_t act_index = 1;
|
||||
struct tc_gact p = {
|
||||
.action = action
|
||||
};
|
||||
|
||||
if (tap_nlattr_nested_start(msg, TCA_FLOWER_ACT) < 0)
|
||||
if (tap_nlattr_nested_start(msg, (*act_index)++) < 0)
|
||||
return -1;
|
||||
if (tap_nlattr_nested_start(msg, act_index++) < 0)
|
||||
return -1;
|
||||
tap_nlattr_add(&msg->nh, TCA_ACT_KIND, sizeof("gact"), "gact");
|
||||
|
||||
tap_nlattr_add(&msg->nh, TCA_ACT_KIND,
|
||||
strlen(adata->id) + 1, adata->id);
|
||||
if (tap_nlattr_nested_start(msg, TCA_ACT_OPTIONS) < 0)
|
||||
return -1;
|
||||
tap_nlattr_add(&msg->nh, TCA_GACT_PARMS, sizeof(p), &p);
|
||||
if (strcmp("gact", adata->id) == 0) {
|
||||
tap_nlattr_add(&msg->nh, TCA_GACT_PARMS, sizeof(adata->gact),
|
||||
&adata->gact);
|
||||
} else if (strcmp("mirred", adata->id) == 0) {
|
||||
if (adata->mirred.eaction == TCA_EGRESS_MIRROR)
|
||||
adata->mirred.action = TC_ACT_PIPE;
|
||||
else /* REDIRECT */
|
||||
adata->mirred.action = TC_ACT_STOLEN;
|
||||
tap_nlattr_add(&msg->nh, TCA_MIRRED_PARMS,
|
||||
sizeof(adata->mirred),
|
||||
&adata->mirred);
|
||||
} else if (strcmp("skbedit", adata->id) == 0) {
|
||||
tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
|
||||
sizeof(adata->skbedit.skbedit),
|
||||
&adata->skbedit.skbedit);
|
||||
tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
|
||||
adata->skbedit.queue);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
|
||||
tap_nlattr_nested_finish(msg); /* nested act_index */
|
||||
tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a MIRRED action item in the provided flow for TC.
|
||||
* Helper function to send a serie of TC actions to the kernel
|
||||
*
|
||||
* @param[in, out] flow
|
||||
* Flow to be filled.
|
||||
* @param[in] ifindex
|
||||
* Netdevice ifindex, where to mirror/redirect packet to.
|
||||
* @param[in] action_type
|
||||
* Either TCA_EGRESS_REDIR for redirection or TCA_EGRESS_MIRROR for mirroring.
|
||||
* @param[in] flow
|
||||
* Pointer to rte flow containing the netlink message
|
||||
*
|
||||
* @param[in] nb_actions
|
||||
* Number of actions in an array of action structs
|
||||
*
|
||||
* @param[in] data
|
||||
* Pointer to an array of action structs
|
||||
*
|
||||
* @param[in] classifier_actions
|
||||
* The classifier on behave of which the actions are configured
|
||||
*
|
||||
* @return
|
||||
* 0 if checks are alright, -1 otherwise.
|
||||
* -1 on failure, 0 on success
|
||||
*/
|
||||
static int
|
||||
add_action_mirred(struct rte_flow *flow, uint16_t ifindex, uint16_t action_type)
|
||||
add_actions(struct rte_flow *flow, int nb_actions, struct action_data *data,
|
||||
int classifier_action)
|
||||
{
|
||||
struct nlmsg *msg = &flow->msg;
|
||||
size_t act_index = 1;
|
||||
struct tc_mirred p = {
|
||||
.eaction = action_type,
|
||||
.ifindex = ifindex,
|
||||
};
|
||||
int i;
|
||||
|
||||
if (tap_nlattr_nested_start(msg, TCA_FLOWER_ACT) < 0)
|
||||
if (tap_nlattr_nested_start(msg, classifier_action) < 0)
|
||||
return -1;
|
||||
if (tap_nlattr_nested_start(msg, act_index++) < 0)
|
||||
return -1;
|
||||
tap_nlattr_add(&msg->nh, TCA_ACT_KIND, sizeof("mirred"), "mirred");
|
||||
if (tap_nlattr_nested_start(msg, TCA_ACT_OPTIONS) < 0)
|
||||
return -1;
|
||||
if (action_type == TCA_EGRESS_MIRROR)
|
||||
p.action = TC_ACT_PIPE;
|
||||
else /* REDIRECT */
|
||||
p.action = TC_ACT_STOLEN;
|
||||
tap_nlattr_add(&msg->nh, TCA_MIRRED_PARMS, sizeof(p), &p);
|
||||
tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
|
||||
tap_nlattr_nested_finish(msg); /* nested act_index */
|
||||
tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a QUEUE action item in the provided flow for TC.
|
||||
*
|
||||
* @param[in, out] flow
|
||||
* Flow to be filled.
|
||||
* @param[in] queue
|
||||
* Queue id to use.
|
||||
*
|
||||
* @return
|
||||
* 0 if checks are alright, -1 otherwise.
|
||||
*/
|
||||
static int
|
||||
add_action_skbedit(struct rte_flow *flow, uint16_t queue)
|
||||
{
|
||||
struct nlmsg *msg = &flow->msg;
|
||||
size_t act_index = 1;
|
||||
struct tc_skbedit p = {
|
||||
.action = TC_ACT_PIPE
|
||||
};
|
||||
|
||||
if (tap_nlattr_nested_start(msg, TCA_FLOWER_ACT) < 0)
|
||||
return -1;
|
||||
if (tap_nlattr_nested_start(msg, act_index++) < 0)
|
||||
return -1;
|
||||
tap_nlattr_add(&msg->nh, TCA_ACT_KIND, sizeof("skbedit"), "skbedit");
|
||||
if (tap_nlattr_nested_start(msg, TCA_ACT_OPTIONS) < 0)
|
||||
return -1;
|
||||
tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS, sizeof(p), &p);
|
||||
tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, queue);
|
||||
tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
|
||||
tap_nlattr_nested_finish(msg); /* nested act_index */
|
||||
for (i = 0; i < nb_actions; i++)
|
||||
if (add_action(flow, &act_index, data + i) < 0)
|
||||
return -1;
|
||||
tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
|
||||
return 0;
|
||||
}
|
||||
@ -1056,7 +1048,12 @@ priv_flow_process(struct pmd_internals *pmd,
|
||||
}
|
||||
}
|
||||
if (mirred && flow) {
|
||||
uint16_t if_index = pmd->if_index;
|
||||
struct action_data adata = {
|
||||
.id = "mirred",
|
||||
.mirred = {
|
||||
.eaction = mirred,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* If attr->egress && mirred, then this is a special
|
||||
@ -1064,9 +1061,13 @@ priv_flow_process(struct pmd_internals *pmd,
|
||||
* redirect packets coming from the DPDK App, out
|
||||
* through the remote netdevice.
|
||||
*/
|
||||
if (attr->egress)
|
||||
if_index = pmd->remote_if_index;
|
||||
if (add_action_mirred(flow, if_index, mirred) < 0)
|
||||
adata.mirred.ifindex = attr->ingress ? pmd->if_index :
|
||||
pmd->remote_if_index;
|
||||
if (mirred == TCA_EGRESS_MIRROR)
|
||||
adata.mirred.action = TC_ACT_PIPE;
|
||||
else
|
||||
adata.mirred.action = TC_ACT_STOLEN;
|
||||
if (add_actions(flow, 1, &adata, TCA_FLOWER_ACT) < 0)
|
||||
goto exit_action_not_supported;
|
||||
else
|
||||
goto end;
|
||||
@ -1080,14 +1081,33 @@ priv_flow_process(struct pmd_internals *pmd,
|
||||
if (action)
|
||||
goto exit_action_not_supported;
|
||||
action = 1;
|
||||
if (flow)
|
||||
err = add_action_gact(flow, TC_ACT_SHOT);
|
||||
if (flow) {
|
||||
struct action_data adata = {
|
||||
.id = "gact",
|
||||
.gact = {
|
||||
.action = TC_ACT_SHOT,
|
||||
},
|
||||
};
|
||||
|
||||
err = add_actions(flow, 1, &adata,
|
||||
TCA_FLOWER_ACT);
|
||||
}
|
||||
} else if (actions->type == RTE_FLOW_ACTION_TYPE_PASSTHRU) {
|
||||
if (action)
|
||||
goto exit_action_not_supported;
|
||||
action = 1;
|
||||
if (flow)
|
||||
err = add_action_gact(flow, TC_ACT_UNSPEC);
|
||||
if (flow) {
|
||||
struct action_data adata = {
|
||||
.id = "gact",
|
||||
.gact = {
|
||||
/* continue */
|
||||
.action = TC_ACT_UNSPEC,
|
||||
},
|
||||
};
|
||||
|
||||
err = add_actions(flow, 1, &adata,
|
||||
TCA_FLOWER_ACT);
|
||||
}
|
||||
} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
|
||||
const struct rte_flow_action_queue *queue =
|
||||
(const struct rte_flow_action_queue *)
|
||||
@ -1099,22 +1119,46 @@ priv_flow_process(struct pmd_internals *pmd,
|
||||
if (!queue ||
|
||||
(queue->index > pmd->dev->data->nb_rx_queues - 1))
|
||||
goto exit_action_not_supported;
|
||||
if (flow)
|
||||
err = add_action_skbedit(flow, queue->index);
|
||||
if (flow) {
|
||||
struct action_data adata = {
|
||||
.id = "skbedit",
|
||||
.skbedit = {
|
||||
.skbedit = {
|
||||
.action = TC_ACT_PIPE,
|
||||
},
|
||||
.queue = queue->index,
|
||||
},
|
||||
};
|
||||
|
||||
err = add_actions(flow, 1, &adata,
|
||||
TCA_FLOWER_ACT);
|
||||
}
|
||||
} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
|
||||
/* Fake RSS support. */
|
||||
const struct rte_flow_action_rss *rss =
|
||||
(const struct rte_flow_action_rss *)
|
||||
actions->conf;
|
||||
|
||||
if (action)
|
||||
if (action++)
|
||||
goto exit_action_not_supported;
|
||||
action = 1;
|
||||
|
||||
if (!rss || rss->num < 1 ||
|
||||
(rss->queue[0] > pmd->dev->data->nb_rx_queues - 1))
|
||||
goto exit_action_not_supported;
|
||||
if (flow)
|
||||
err = add_action_skbedit(flow, rss->queue[0]);
|
||||
if (flow) {
|
||||
struct action_data adata = {
|
||||
.id = "skbedit",
|
||||
.skbedit = {
|
||||
.skbedit = {
|
||||
.action = TC_ACT_PIPE,
|
||||
},
|
||||
.queue = rss->queue[0],
|
||||
},
|
||||
};
|
||||
|
||||
err = add_actions(flow, 1, &adata,
|
||||
TCA_FLOWER_ACT);
|
||||
}
|
||||
} else {
|
||||
goto exit_action_not_supported;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user