net/tap: support actions for different classifiers
authorOphir Munk <ophirmu@mellanox.com>
Sat, 20 Jan 2018 21:11:32 +0000 (21:11 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Sun, 21 Jan 2018 14:51:52 +0000 (15:51 +0100)
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>
drivers/net/tap/Makefile
drivers/net/tap/rte_eth_tap.h
drivers/net/tap/tap_flow.c

index fd4195f..fbf84e1 100644 (file)
@@ -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
 #
index 69a1a08..e42323f 100644 (file)
@@ -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;
index 90b2654..d2a69a7 100644 (file)
@@ -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
  *
- * @return
- *   0 if checks are alright, -1 otherwise.
- */
-static int
-add_action_gact(struct rte_flow *flow, int action)
-{
-       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)
-               return -1;
-       if (tap_nlattr_nested_start(msg, act_index++) < 0)
-               return -1;
-       tap_nlattr_add(&msg->nh, TCA_ACT_KIND, sizeof("gact"), "gact");
-       if (tap_nlattr_nested_start(msg, TCA_ACT_OPTIONS) < 0)
-               return -1;
-       tap_nlattr_add(&msg->nh, TCA_GACT_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 MIRRED action item in the provided flow for TC.
+ * @param[in, out] act_index
+ *   Pointer to action sequence number in the TC command
  *
- * @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] 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_mirred(struct rte_flow *flow, uint16_t ifindex, uint16_t action_type)
+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_mirred p = {
-               .eaction = action_type,
-               .ifindex = ifindex,
-       };
 
-       if (tap_nlattr_nested_start(msg, TCA_FLOWER_ACT) < 0)
-               return -1;
-       if (tap_nlattr_nested_start(msg, act_index++) < 0)
+       if (tap_nlattr_nested_start(msg, (*act_index)++) < 0)
                return -1;
-       tap_nlattr_add(&msg->nh, TCA_ACT_KIND, sizeof("mirred"), "mirred");
+
+       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;
-       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);
+       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 QUEUE 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] queue
- *   Queue id to use.
+ * @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_skbedit(struct rte_flow *flow, uint16_t queue)
+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_skbedit p = {
-               .action = TC_ACT_PIPE
-       };
+       int i;
 
-       if (tap_nlattr_nested_start(msg, TCA_FLOWER_ACT) < 0)
-               return -1;
-       if (tap_nlattr_nested_start(msg, act_index++) < 0)
+       if (tap_nlattr_nested_start(msg, classifier_action) < 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;
                }