Add the ability to match basic fields from IPv4 and IPv6 headers (source
and destination addresses only).

Signed-off-by: Adrien Mazarguil <adrien.mazarguil at 6wind.com>
---
 app/test-pmd/cmdline_flow.c | 177 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 177 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index f2bd405..75096df 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -38,6 +38,7 @@
 #include <errno.h>
 #include <ctype.h>
 #include <string.h>
+#include <arpa/inet.h>

 #include <rte_common.h>
 #include <rte_ethdev.h>
@@ -61,6 +62,8 @@ enum index {
        BOOLEAN,
        STRING,
        MAC_ADDR,
+       IPV4_ADDR,
+       IPV6_ADDR,
        RULE_ID,
        PORT_ID,
        GROUP_ID,
@@ -124,6 +127,12 @@ enum index {
        ITEM_VLAN,
        ITEM_VLAN_TPID,
        ITEM_VLAN_TCI,
+       ITEM_IPV4,
+       ITEM_IPV4_SRC,
+       ITEM_IPV4_DST,
+       ITEM_IPV6,
+       ITEM_IPV6_SRC,
+       ITEM_IPV6_DST,

        /* Validate/create actions. */
        ACTIONS,
@@ -349,6 +358,8 @@ static const enum index next_item[] = {
        ITEM_RAW,
        ITEM_ETH,
        ITEM_VLAN,
+       ITEM_IPV4,
+       ITEM_IPV6,
        0,
 };

@@ -396,6 +407,20 @@ static const enum index item_vlan[] = {
        0,
 };

+static const enum index item_ipv4[] = {
+       ITEM_IPV4_SRC,
+       ITEM_IPV4_DST,
+       ITEM_NEXT,
+       0,
+};
+
+static const enum index item_ipv6[] = {
+       ITEM_IPV6_SRC,
+       ITEM_IPV6_DST,
+       ITEM_NEXT,
+       0,
+};
+
 static const enum index next_action[] = {
        ACTION_END,
        ACTION_VOID,
@@ -441,6 +466,12 @@ static int parse_string(struct context *, const struct 
token *,
 static int parse_mac_addr(struct context *, const struct token *,
                          const char *, unsigned int,
                          void *, unsigned int);
+static int parse_ipv4_addr(struct context *, const struct token *,
+                          const char *, unsigned int,
+                          void *, unsigned int);
+static int parse_ipv6_addr(struct context *, const struct token *,
+                          const char *, unsigned int,
+                          void *, unsigned int);
 static int parse_port(struct context *, const struct token *,
                      const char *, unsigned int,
                      void *, unsigned int);
@@ -511,6 +542,20 @@ static const struct token token_list[] = {
                .call = parse_mac_addr,
                .comp = comp_none,
        },
+       [IPV4_ADDR] = {
+               .name = "{IPv4 address}",
+               .type = "IPV4 ADDRESS",
+               .help = "standard IPv4 address notation",
+               .call = parse_ipv4_addr,
+               .comp = comp_none,
+       },
+       [IPV6_ADDR] = {
+               .name = "{IPv6 address}",
+               .type = "IPV6 ADDRESS",
+               .help = "standard IPv6 address notation",
+               .call = parse_ipv6_addr,
+               .comp = comp_none,
+       },
        [RULE_ID] = {
                .name = "{rule id}",
                .type = "RULE ID",
@@ -849,6 +894,48 @@ static const struct token token_list[] = {
                .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
                .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
        },
+       [ITEM_IPV4] = {
+               .name = "ipv4",
+               .help = "match IPv4 header",
+               .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
+               .next = NEXT(item_ipv4),
+               .call = parse_vc,
+       },
+       [ITEM_IPV4_SRC] = {
+               .name = "src",
+               .help = "source address",
+               .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+                                            hdr.src_addr)),
+       },
+       [ITEM_IPV4_DST] = {
+               .name = "dst",
+               .help = "destination address",
+               .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+                                            hdr.dst_addr)),
+       },
+       [ITEM_IPV6] = {
+               .name = "ipv6",
+               .help = "match IPv6 header",
+               .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
+               .next = NEXT(item_ipv6),
+               .call = parse_vc,
+       },
+       [ITEM_IPV6_SRC] = {
+               .name = "src",
+               .help = "source address",
+               .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+                                            hdr.src_addr)),
+       },
+       [ITEM_IPV6_DST] = {
+               .name = "dst",
+               .help = "destination address",
+               .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+                                            hdr.dst_addr)),
+       },
        /* Validate/create actions. */
        [ACTIONS] = {
                .name = "actions",
@@ -1520,6 +1607,96 @@ parse_mac_addr(struct context *ctx, const struct token 
*token,
        return -1;
 }

+/**
+ * Parse an IPv4 address.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_ipv4_addr(struct context *ctx, const struct token *token,
+               const char *str, unsigned int len,
+               void *buf, unsigned int size)
+{
+       const struct arg *arg = pop_args(ctx);
+       char str2[len + 1];
+       struct in_addr tmp;
+       int ret;
+
+       /* Argument is expected. */
+       if (!arg)
+               return -1;
+       size = arg->size;
+       /* Bit-mask fill is not supported. */
+       if (arg->mask || size != sizeof(tmp))
+               goto error;
+       /* Only network endian is supported. */
+       if (!arg->hton)
+               goto error;
+       memcpy(str2, str, len);
+       str2[len] = '\0';
+       ret = inet_pton(AF_INET, str2, &tmp);
+       if (ret != 1) {
+               /* Attempt integer parsing. */
+               push_args(ctx, arg);
+               return parse_int(ctx, token, str, len, buf, size);
+       }
+       if (!ctx->object)
+               return len;
+       buf = (uint8_t *)ctx->object + arg->offset;
+       memcpy(buf, &tmp, size);
+       if (ctx->objmask)
+               memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
+       return len;
+error:
+       push_args(ctx, arg);
+       return -1;
+}
+
+/**
+ * Parse an IPv6 address.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_ipv6_addr(struct context *ctx, const struct token *token,
+               const char *str, unsigned int len,
+               void *buf, unsigned int size)
+{
+       const struct arg *arg = pop_args(ctx);
+       char str2[len + 1];
+       struct in6_addr tmp;
+       int ret;
+
+       (void)token;
+       /* Argument is expected. */
+       if (!arg)
+               return -1;
+       size = arg->size;
+       /* Bit-mask fill is not supported. */
+       if (arg->mask || size != sizeof(tmp))
+               goto error;
+       /* Only network endian is supported. */
+       if (!arg->hton)
+               goto error;
+       memcpy(str2, str, len);
+       str2[len] = '\0';
+       ret = inet_pton(AF_INET6, str2, &tmp);
+       if (ret != 1)
+               goto error;
+       if (!ctx->object)
+               return len;
+       buf = (uint8_t *)ctx->object + arg->offset;
+       memcpy(buf, &tmp, size);
+       if (ctx->objmask)
+               memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
+       return len;
+error:
+       push_args(ctx, arg);
+       return -1;
+}
+
 /** Boolean values (even indices stand for false). */
 static const char *const boolean_name[] = {
        "0", "1",
-- 
2.1.4

Reply via email to