net/mlx5: add L2-L4 pattern items to switch flow rules
This enables flow rules to explicitly match supported combinations of Ethernet, IPv4, IPv6, TCP and UDP headers at the switch level. Testpmd example: - Dropping TCPv4 traffic with a specific destination on port ID 2: flow create 2 ingress transfer pattern eth / ipv4 / tcp dst is 42 / end actions drop / end Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com> Acked-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com> Acked-by: Yongseok Koh <yskoh@mellanox.com>
This commit is contained in:
parent
9b33df8e0c
commit
2bfc777e07
@ -209,6 +209,116 @@ mlx5_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh
|
|||||||
linux/pkt_cls.h \
|
linux/pkt_cls.h \
|
||||||
enum TCA_FLOWER_FLAGS \
|
enum TCA_FLOWER_FLAGS \
|
||||||
$(AUTOCONF_OUTPUT)
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_ETH_TYPE \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_ETH_TYPE \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_ETH_DST \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_ETH_DST \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_ETH_DST_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_ETH_DST_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_ETH_SRC \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_ETH_SRC \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_ETH_SRC_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_ETH_SRC_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_IP_PROTO \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_IP_PROTO \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_IPV4_SRC \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_IPV4_SRC \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_IPV4_SRC_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_IPV4_SRC_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_IPV4_DST \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_IPV4_DST \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_IPV4_DST_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_IPV4_DST_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_IPV6_SRC \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_IPV6_SRC \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_IPV6_SRC_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_IPV6_SRC_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_IPV6_DST \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_IPV6_DST \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_IPV6_DST_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_IPV6_DST_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_TCP_SRC \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_TCP_SRC \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_TCP_SRC_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_TCP_SRC_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_TCP_DST \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_TCP_DST \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_TCP_DST_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_TCP_DST_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_UDP_SRC \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_UDP_SRC \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_UDP_SRC_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_UDP_SRC_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_UDP_DST \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_UDP_DST \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
$Q sh -- '$<' '$@' \
|
||||||
|
HAVE_TCA_FLOWER_KEY_UDP_DST_MASK \
|
||||||
|
linux/pkt_cls.h \
|
||||||
|
enum TCA_FLOWER_KEY_UDP_DST_MASK \
|
||||||
|
$(AUTOCONF_OUTPUT)
|
||||||
|
|
||||||
# Create mlx5_autoconf.h or update it in case it differs from the new one.
|
# Create mlx5_autoconf.h or update it in case it differs from the new one.
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* Copyright 2018 Mellanox Technologies, Ltd
|
* Copyright 2018 Mellanox Technologies, Ltd
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <libmnl/libmnl.h>
|
#include <libmnl/libmnl.h>
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
@ -12,7 +13,9 @@
|
|||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
#include <linux/tc_act/tc_gact.h>
|
#include <linux/tc_act/tc_gact.h>
|
||||||
#include <linux/tc_act/tc_mirred.h>
|
#include <linux/tc_act/tc_mirred.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
#include <stdalign.h>
|
#include <stdalign.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -20,6 +23,7 @@
|
|||||||
|
|
||||||
#include <rte_byteorder.h>
|
#include <rte_byteorder.h>
|
||||||
#include <rte_errno.h>
|
#include <rte_errno.h>
|
||||||
|
#include <rte_ether.h>
|
||||||
#include <rte_flow.h>
|
#include <rte_flow.h>
|
||||||
|
|
||||||
#include "mlx5.h"
|
#include "mlx5.h"
|
||||||
@ -44,6 +48,72 @@
|
|||||||
#ifndef HAVE_TCA_FLOWER_FLAGS
|
#ifndef HAVE_TCA_FLOWER_FLAGS
|
||||||
#define TCA_FLOWER_FLAGS 22
|
#define TCA_FLOWER_FLAGS 22
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_ETH_TYPE
|
||||||
|
#define TCA_FLOWER_KEY_ETH_TYPE 8
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_ETH_DST
|
||||||
|
#define TCA_FLOWER_KEY_ETH_DST 4
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_ETH_DST_MASK
|
||||||
|
#define TCA_FLOWER_KEY_ETH_DST_MASK 5
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_ETH_SRC
|
||||||
|
#define TCA_FLOWER_KEY_ETH_SRC 6
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_ETH_SRC_MASK
|
||||||
|
#define TCA_FLOWER_KEY_ETH_SRC_MASK 7
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_IP_PROTO
|
||||||
|
#define TCA_FLOWER_KEY_IP_PROTO 9
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_IPV4_SRC
|
||||||
|
#define TCA_FLOWER_KEY_IPV4_SRC 10
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_IPV4_SRC_MASK
|
||||||
|
#define TCA_FLOWER_KEY_IPV4_SRC_MASK 11
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_IPV4_DST
|
||||||
|
#define TCA_FLOWER_KEY_IPV4_DST 12
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_IPV4_DST_MASK
|
||||||
|
#define TCA_FLOWER_KEY_IPV4_DST_MASK 13
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_IPV6_SRC
|
||||||
|
#define TCA_FLOWER_KEY_IPV6_SRC 14
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_IPV6_SRC_MASK
|
||||||
|
#define TCA_FLOWER_KEY_IPV6_SRC_MASK 15
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_IPV6_DST
|
||||||
|
#define TCA_FLOWER_KEY_IPV6_DST 16
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_IPV6_DST_MASK
|
||||||
|
#define TCA_FLOWER_KEY_IPV6_DST_MASK 17
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_TCP_SRC
|
||||||
|
#define TCA_FLOWER_KEY_TCP_SRC 18
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_TCP_SRC_MASK
|
||||||
|
#define TCA_FLOWER_KEY_TCP_SRC_MASK 35
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_TCP_DST
|
||||||
|
#define TCA_FLOWER_KEY_TCP_DST 19
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_TCP_DST_MASK
|
||||||
|
#define TCA_FLOWER_KEY_TCP_DST_MASK 36
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_UDP_SRC
|
||||||
|
#define TCA_FLOWER_KEY_UDP_SRC 20
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_UDP_SRC_MASK
|
||||||
|
#define TCA_FLOWER_KEY_UDP_SRC_MASK 37
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_UDP_DST
|
||||||
|
#define TCA_FLOWER_KEY_UDP_DST 21
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TCA_FLOWER_KEY_UDP_DST_MASK
|
||||||
|
#define TCA_FLOWER_KEY_UDP_DST_MASK 38
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Parser state definitions for mlx5_nl_flow_trans[]. */
|
/** Parser state definitions for mlx5_nl_flow_trans[]. */
|
||||||
enum mlx5_nl_flow_trans {
|
enum mlx5_nl_flow_trans {
|
||||||
@ -52,6 +122,11 @@ enum mlx5_nl_flow_trans {
|
|||||||
ATTR,
|
ATTR,
|
||||||
PATTERN,
|
PATTERN,
|
||||||
ITEM_VOID,
|
ITEM_VOID,
|
||||||
|
ITEM_ETH,
|
||||||
|
ITEM_IPV4,
|
||||||
|
ITEM_IPV6,
|
||||||
|
ITEM_TCP,
|
||||||
|
ITEM_UDP,
|
||||||
ACTIONS,
|
ACTIONS,
|
||||||
ACTION_VOID,
|
ACTION_VOID,
|
||||||
ACTION_PORT_ID,
|
ACTION_PORT_ID,
|
||||||
@ -73,8 +148,13 @@ static const enum mlx5_nl_flow_trans *const mlx5_nl_flow_trans[] = {
|
|||||||
[INVALID] = NULL,
|
[INVALID] = NULL,
|
||||||
[BACK] = NULL,
|
[BACK] = NULL,
|
||||||
[ATTR] = TRANS(PATTERN),
|
[ATTR] = TRANS(PATTERN),
|
||||||
[PATTERN] = TRANS(PATTERN_COMMON),
|
[PATTERN] = TRANS(ITEM_ETH, PATTERN_COMMON),
|
||||||
[ITEM_VOID] = TRANS(BACK),
|
[ITEM_VOID] = TRANS(BACK),
|
||||||
|
[ITEM_ETH] = TRANS(ITEM_IPV4, ITEM_IPV6, PATTERN_COMMON),
|
||||||
|
[ITEM_IPV4] = TRANS(ITEM_TCP, ITEM_UDP, PATTERN_COMMON),
|
||||||
|
[ITEM_IPV6] = TRANS(ITEM_TCP, ITEM_UDP, PATTERN_COMMON),
|
||||||
|
[ITEM_TCP] = TRANS(PATTERN_COMMON),
|
||||||
|
[ITEM_UDP] = TRANS(PATTERN_COMMON),
|
||||||
[ACTIONS] = TRANS(ACTIONS_FATE, ACTIONS_COMMON),
|
[ACTIONS] = TRANS(ACTIONS_FATE, ACTIONS_COMMON),
|
||||||
[ACTION_VOID] = TRANS(BACK),
|
[ACTION_VOID] = TRANS(BACK),
|
||||||
[ACTION_PORT_ID] = TRANS(ACTION_VOID, END),
|
[ACTION_PORT_ID] = TRANS(ACTION_VOID, END),
|
||||||
@ -82,6 +162,126 @@ static const enum mlx5_nl_flow_trans *const mlx5_nl_flow_trans[] = {
|
|||||||
[END] = NULL,
|
[END] = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Empty masks for known item types. */
|
||||||
|
static const union {
|
||||||
|
struct rte_flow_item_eth eth;
|
||||||
|
struct rte_flow_item_ipv4 ipv4;
|
||||||
|
struct rte_flow_item_ipv6 ipv6;
|
||||||
|
struct rte_flow_item_tcp tcp;
|
||||||
|
struct rte_flow_item_udp udp;
|
||||||
|
} mlx5_nl_flow_mask_empty;
|
||||||
|
|
||||||
|
/** Supported masks for known item types. */
|
||||||
|
static const struct {
|
||||||
|
struct rte_flow_item_eth eth;
|
||||||
|
struct rte_flow_item_ipv4 ipv4;
|
||||||
|
struct rte_flow_item_ipv6 ipv6;
|
||||||
|
struct rte_flow_item_tcp tcp;
|
||||||
|
struct rte_flow_item_udp udp;
|
||||||
|
} mlx5_nl_flow_mask_supported = {
|
||||||
|
.eth = {
|
||||||
|
.type = RTE_BE16(0xffff),
|
||||||
|
.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
|
||||||
|
.src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
|
||||||
|
},
|
||||||
|
.ipv4.hdr = {
|
||||||
|
.next_proto_id = 0xff,
|
||||||
|
.src_addr = RTE_BE32(0xffffffff),
|
||||||
|
.dst_addr = RTE_BE32(0xffffffff),
|
||||||
|
},
|
||||||
|
.ipv6.hdr = {
|
||||||
|
.proto = 0xff,
|
||||||
|
.src_addr =
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff",
|
||||||
|
.dst_addr =
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff",
|
||||||
|
},
|
||||||
|
.tcp.hdr = {
|
||||||
|
.src_port = RTE_BE16(0xffff),
|
||||||
|
.dst_port = RTE_BE16(0xffff),
|
||||||
|
},
|
||||||
|
.udp.hdr = {
|
||||||
|
.src_port = RTE_BE16(0xffff),
|
||||||
|
.dst_port = RTE_BE16(0xffff),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve mask for pattern item.
|
||||||
|
*
|
||||||
|
* This function does basic sanity checks on a pattern item in order to
|
||||||
|
* return the most appropriate mask for it.
|
||||||
|
*
|
||||||
|
* @param[in] item
|
||||||
|
* Item specification.
|
||||||
|
* @param[in] mask_default
|
||||||
|
* Default mask for pattern item as specified by the flow API.
|
||||||
|
* @param[in] mask_supported
|
||||||
|
* Mask fields supported by the implementation.
|
||||||
|
* @param[in] mask_empty
|
||||||
|
* Empty mask to return when there is no specification.
|
||||||
|
* @param[out] error
|
||||||
|
* Perform verbose error reporting if not NULL.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Either @p item->mask or one of the mask parameters on success, NULL
|
||||||
|
* otherwise and rte_errno is set.
|
||||||
|
*/
|
||||||
|
static const void *
|
||||||
|
mlx5_nl_flow_item_mask(const struct rte_flow_item *item,
|
||||||
|
const void *mask_default,
|
||||||
|
const void *mask_supported,
|
||||||
|
const void *mask_empty,
|
||||||
|
size_t mask_size,
|
||||||
|
struct rte_flow_error *error)
|
||||||
|
{
|
||||||
|
const uint8_t *mask;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* item->last and item->mask cannot exist without item->spec. */
|
||||||
|
if (!item->spec && (item->mask || item->last)) {
|
||||||
|
rte_flow_error_set
|
||||||
|
(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
|
||||||
|
"\"mask\" or \"last\" field provided without a"
|
||||||
|
" corresponding \"spec\"");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* No spec, no mask, no problem. */
|
||||||
|
if (!item->spec)
|
||||||
|
return mask_empty;
|
||||||
|
mask = item->mask ? item->mask : mask_default;
|
||||||
|
assert(mask);
|
||||||
|
/*
|
||||||
|
* Single-pass check to make sure that:
|
||||||
|
* - Mask is supported, no bits are set outside mask_supported.
|
||||||
|
* - Both item->spec and item->last are included in mask.
|
||||||
|
*/
|
||||||
|
for (i = 0; i != mask_size; ++i) {
|
||||||
|
if (!mask[i])
|
||||||
|
continue;
|
||||||
|
if ((mask[i] | ((const uint8_t *)mask_supported)[i]) !=
|
||||||
|
((const uint8_t *)mask_supported)[i]) {
|
||||||
|
rte_flow_error_set
|
||||||
|
(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM_MASK,
|
||||||
|
mask, "unsupported field found in \"mask\"");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (item->last &&
|
||||||
|
(((const uint8_t *)item->spec)[i] & mask[i]) !=
|
||||||
|
(((const uint8_t *)item->last)[i] & mask[i])) {
|
||||||
|
rte_flow_error_set
|
||||||
|
(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM_LAST,
|
||||||
|
item->last,
|
||||||
|
"range between \"spec\" and \"last\" not"
|
||||||
|
" comprised in \"mask\"");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transpose flow rule description to rtnetlink message.
|
* Transpose flow rule description to rtnetlink message.
|
||||||
*
|
*
|
||||||
@ -128,6 +328,8 @@ mlx5_nl_flow_transpose(void *buf,
|
|||||||
const struct rte_flow_action *action;
|
const struct rte_flow_action *action;
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
uint32_t act_index_cur;
|
uint32_t act_index_cur;
|
||||||
|
bool eth_type_set;
|
||||||
|
bool ip_proto_set;
|
||||||
struct nlattr *na_flower;
|
struct nlattr *na_flower;
|
||||||
struct nlattr *na_flower_act;
|
struct nlattr *na_flower_act;
|
||||||
const enum mlx5_nl_flow_trans *trans;
|
const enum mlx5_nl_flow_trans *trans;
|
||||||
@ -140,12 +342,21 @@ init:
|
|||||||
action = actions;
|
action = actions;
|
||||||
n = 0;
|
n = 0;
|
||||||
act_index_cur = 0;
|
act_index_cur = 0;
|
||||||
|
eth_type_set = false;
|
||||||
|
ip_proto_set = false;
|
||||||
na_flower = NULL;
|
na_flower = NULL;
|
||||||
na_flower_act = NULL;
|
na_flower_act = NULL;
|
||||||
trans = TRANS(ATTR);
|
trans = TRANS(ATTR);
|
||||||
back = trans;
|
back = trans;
|
||||||
trans:
|
trans:
|
||||||
switch (trans[n++]) {
|
switch (trans[n++]) {
|
||||||
|
union {
|
||||||
|
const struct rte_flow_item_eth *eth;
|
||||||
|
const struct rte_flow_item_ipv4 *ipv4;
|
||||||
|
const struct rte_flow_item_ipv6 *ipv6;
|
||||||
|
const struct rte_flow_item_tcp *tcp;
|
||||||
|
const struct rte_flow_item_udp *udp;
|
||||||
|
} spec, mask;
|
||||||
union {
|
union {
|
||||||
const struct rte_flow_action_port_id *port_id;
|
const struct rte_flow_action_port_id *port_id;
|
||||||
} conf;
|
} conf;
|
||||||
@ -235,6 +446,256 @@ trans:
|
|||||||
goto trans;
|
goto trans;
|
||||||
++item;
|
++item;
|
||||||
break;
|
break;
|
||||||
|
case ITEM_ETH:
|
||||||
|
if (item->type != RTE_FLOW_ITEM_TYPE_ETH)
|
||||||
|
goto trans;
|
||||||
|
mask.eth = mlx5_nl_flow_item_mask
|
||||||
|
(item, &rte_flow_item_eth_mask,
|
||||||
|
&mlx5_nl_flow_mask_supported.eth,
|
||||||
|
&mlx5_nl_flow_mask_empty.eth,
|
||||||
|
sizeof(mlx5_nl_flow_mask_supported.eth), error);
|
||||||
|
if (!mask.eth)
|
||||||
|
return -rte_errno;
|
||||||
|
if (mask.eth == &mlx5_nl_flow_mask_empty.eth) {
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spec.eth = item->spec;
|
||||||
|
if (mask.eth->type && mask.eth->type != RTE_BE16(0xffff))
|
||||||
|
return rte_flow_error_set
|
||||||
|
(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM_MASK,
|
||||||
|
mask.eth,
|
||||||
|
"no support for partial mask on"
|
||||||
|
" \"type\" field");
|
||||||
|
if (mask.eth->type) {
|
||||||
|
if (!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_ETH_TYPE,
|
||||||
|
spec.eth->type))
|
||||||
|
goto error_nobufs;
|
||||||
|
eth_type_set = 1;
|
||||||
|
}
|
||||||
|
if ((!is_zero_ether_addr(&mask.eth->dst) &&
|
||||||
|
(!mnl_attr_put_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_ETH_DST,
|
||||||
|
ETHER_ADDR_LEN,
|
||||||
|
spec.eth->dst.addr_bytes) ||
|
||||||
|
!mnl_attr_put_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_ETH_DST_MASK,
|
||||||
|
ETHER_ADDR_LEN,
|
||||||
|
mask.eth->dst.addr_bytes))) ||
|
||||||
|
(!is_zero_ether_addr(&mask.eth->src) &&
|
||||||
|
(!mnl_attr_put_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_ETH_SRC,
|
||||||
|
ETHER_ADDR_LEN,
|
||||||
|
spec.eth->src.addr_bytes) ||
|
||||||
|
!mnl_attr_put_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_ETH_SRC_MASK,
|
||||||
|
ETHER_ADDR_LEN,
|
||||||
|
mask.eth->src.addr_bytes))))
|
||||||
|
goto error_nobufs;
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
|
case ITEM_IPV4:
|
||||||
|
if (item->type != RTE_FLOW_ITEM_TYPE_IPV4)
|
||||||
|
goto trans;
|
||||||
|
mask.ipv4 = mlx5_nl_flow_item_mask
|
||||||
|
(item, &rte_flow_item_ipv4_mask,
|
||||||
|
&mlx5_nl_flow_mask_supported.ipv4,
|
||||||
|
&mlx5_nl_flow_mask_empty.ipv4,
|
||||||
|
sizeof(mlx5_nl_flow_mask_supported.ipv4), error);
|
||||||
|
if (!mask.ipv4)
|
||||||
|
return -rte_errno;
|
||||||
|
if (!eth_type_set &&
|
||||||
|
!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_ETH_TYPE,
|
||||||
|
RTE_BE16(ETH_P_IP)))
|
||||||
|
goto error_nobufs;
|
||||||
|
eth_type_set = 1;
|
||||||
|
if (mask.ipv4 == &mlx5_nl_flow_mask_empty.ipv4) {
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spec.ipv4 = item->spec;
|
||||||
|
if (mask.ipv4->hdr.next_proto_id &&
|
||||||
|
mask.ipv4->hdr.next_proto_id != 0xff)
|
||||||
|
return rte_flow_error_set
|
||||||
|
(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM_MASK,
|
||||||
|
mask.ipv4,
|
||||||
|
"no support for partial mask on"
|
||||||
|
" \"hdr.next_proto_id\" field");
|
||||||
|
if (mask.ipv4->hdr.next_proto_id) {
|
||||||
|
if (!mnl_attr_put_u8_check
|
||||||
|
(buf, size, TCA_FLOWER_KEY_IP_PROTO,
|
||||||
|
spec.ipv4->hdr.next_proto_id))
|
||||||
|
goto error_nobufs;
|
||||||
|
ip_proto_set = 1;
|
||||||
|
}
|
||||||
|
if ((mask.ipv4->hdr.src_addr &&
|
||||||
|
(!mnl_attr_put_u32_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IPV4_SRC,
|
||||||
|
spec.ipv4->hdr.src_addr) ||
|
||||||
|
!mnl_attr_put_u32_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IPV4_SRC_MASK,
|
||||||
|
mask.ipv4->hdr.src_addr))) ||
|
||||||
|
(mask.ipv4->hdr.dst_addr &&
|
||||||
|
(!mnl_attr_put_u32_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IPV4_DST,
|
||||||
|
spec.ipv4->hdr.dst_addr) ||
|
||||||
|
!mnl_attr_put_u32_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IPV4_DST_MASK,
|
||||||
|
mask.ipv4->hdr.dst_addr))))
|
||||||
|
goto error_nobufs;
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
|
case ITEM_IPV6:
|
||||||
|
if (item->type != RTE_FLOW_ITEM_TYPE_IPV6)
|
||||||
|
goto trans;
|
||||||
|
mask.ipv6 = mlx5_nl_flow_item_mask
|
||||||
|
(item, &rte_flow_item_ipv6_mask,
|
||||||
|
&mlx5_nl_flow_mask_supported.ipv6,
|
||||||
|
&mlx5_nl_flow_mask_empty.ipv6,
|
||||||
|
sizeof(mlx5_nl_flow_mask_supported.ipv6), error);
|
||||||
|
if (!mask.ipv6)
|
||||||
|
return -rte_errno;
|
||||||
|
if (!eth_type_set &&
|
||||||
|
!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_ETH_TYPE,
|
||||||
|
RTE_BE16(ETH_P_IPV6)))
|
||||||
|
goto error_nobufs;
|
||||||
|
eth_type_set = 1;
|
||||||
|
if (mask.ipv6 == &mlx5_nl_flow_mask_empty.ipv6) {
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spec.ipv6 = item->spec;
|
||||||
|
if (mask.ipv6->hdr.proto && mask.ipv6->hdr.proto != 0xff)
|
||||||
|
return rte_flow_error_set
|
||||||
|
(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM_MASK,
|
||||||
|
mask.ipv6,
|
||||||
|
"no support for partial mask on"
|
||||||
|
" \"hdr.proto\" field");
|
||||||
|
if (mask.ipv6->hdr.proto) {
|
||||||
|
if (!mnl_attr_put_u8_check
|
||||||
|
(buf, size, TCA_FLOWER_KEY_IP_PROTO,
|
||||||
|
spec.ipv6->hdr.proto))
|
||||||
|
goto error_nobufs;
|
||||||
|
ip_proto_set = 1;
|
||||||
|
}
|
||||||
|
if ((!IN6_IS_ADDR_UNSPECIFIED(mask.ipv6->hdr.src_addr) &&
|
||||||
|
(!mnl_attr_put_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IPV6_SRC,
|
||||||
|
sizeof(spec.ipv6->hdr.src_addr),
|
||||||
|
spec.ipv6->hdr.src_addr) ||
|
||||||
|
!mnl_attr_put_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IPV6_SRC_MASK,
|
||||||
|
sizeof(mask.ipv6->hdr.src_addr),
|
||||||
|
mask.ipv6->hdr.src_addr))) ||
|
||||||
|
(!IN6_IS_ADDR_UNSPECIFIED(mask.ipv6->hdr.dst_addr) &&
|
||||||
|
(!mnl_attr_put_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IPV6_DST,
|
||||||
|
sizeof(spec.ipv6->hdr.dst_addr),
|
||||||
|
spec.ipv6->hdr.dst_addr) ||
|
||||||
|
!mnl_attr_put_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IPV6_DST_MASK,
|
||||||
|
sizeof(mask.ipv6->hdr.dst_addr),
|
||||||
|
mask.ipv6->hdr.dst_addr))))
|
||||||
|
goto error_nobufs;
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
|
case ITEM_TCP:
|
||||||
|
if (item->type != RTE_FLOW_ITEM_TYPE_TCP)
|
||||||
|
goto trans;
|
||||||
|
mask.tcp = mlx5_nl_flow_item_mask
|
||||||
|
(item, &rte_flow_item_tcp_mask,
|
||||||
|
&mlx5_nl_flow_mask_supported.tcp,
|
||||||
|
&mlx5_nl_flow_mask_empty.tcp,
|
||||||
|
sizeof(mlx5_nl_flow_mask_supported.tcp), error);
|
||||||
|
if (!mask.tcp)
|
||||||
|
return -rte_errno;
|
||||||
|
if (!ip_proto_set &&
|
||||||
|
!mnl_attr_put_u8_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IP_PROTO,
|
||||||
|
IPPROTO_TCP))
|
||||||
|
goto error_nobufs;
|
||||||
|
if (mask.tcp == &mlx5_nl_flow_mask_empty.tcp) {
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spec.tcp = item->spec;
|
||||||
|
if ((mask.tcp->hdr.src_port &&
|
||||||
|
mask.tcp->hdr.src_port != RTE_BE16(0xffff)) ||
|
||||||
|
(mask.tcp->hdr.dst_port &&
|
||||||
|
mask.tcp->hdr.dst_port != RTE_BE16(0xffff)))
|
||||||
|
return rte_flow_error_set
|
||||||
|
(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM_MASK,
|
||||||
|
mask.tcp,
|
||||||
|
"no support for partial masks on"
|
||||||
|
" \"hdr.src_port\" and \"hdr.dst_port\""
|
||||||
|
" fields");
|
||||||
|
if ((mask.tcp->hdr.src_port &&
|
||||||
|
(!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_TCP_SRC,
|
||||||
|
spec.tcp->hdr.src_port) ||
|
||||||
|
!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_TCP_SRC_MASK,
|
||||||
|
mask.tcp->hdr.src_port))) ||
|
||||||
|
(mask.tcp->hdr.dst_port &&
|
||||||
|
(!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_TCP_DST,
|
||||||
|
spec.tcp->hdr.dst_port) ||
|
||||||
|
!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_TCP_DST_MASK,
|
||||||
|
mask.tcp->hdr.dst_port))))
|
||||||
|
goto error_nobufs;
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
|
case ITEM_UDP:
|
||||||
|
if (item->type != RTE_FLOW_ITEM_TYPE_UDP)
|
||||||
|
goto trans;
|
||||||
|
mask.udp = mlx5_nl_flow_item_mask
|
||||||
|
(item, &rte_flow_item_udp_mask,
|
||||||
|
&mlx5_nl_flow_mask_supported.udp,
|
||||||
|
&mlx5_nl_flow_mask_empty.udp,
|
||||||
|
sizeof(mlx5_nl_flow_mask_supported.udp), error);
|
||||||
|
if (!mask.udp)
|
||||||
|
return -rte_errno;
|
||||||
|
if (!ip_proto_set &&
|
||||||
|
!mnl_attr_put_u8_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_IP_PROTO,
|
||||||
|
IPPROTO_UDP))
|
||||||
|
goto error_nobufs;
|
||||||
|
if (mask.udp == &mlx5_nl_flow_mask_empty.udp) {
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spec.udp = item->spec;
|
||||||
|
if ((mask.udp->hdr.src_port &&
|
||||||
|
mask.udp->hdr.src_port != RTE_BE16(0xffff)) ||
|
||||||
|
(mask.udp->hdr.dst_port &&
|
||||||
|
mask.udp->hdr.dst_port != RTE_BE16(0xffff)))
|
||||||
|
return rte_flow_error_set
|
||||||
|
(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM_MASK,
|
||||||
|
mask.udp,
|
||||||
|
"no support for partial masks on"
|
||||||
|
" \"hdr.src_port\" and \"hdr.dst_port\""
|
||||||
|
" fields");
|
||||||
|
if ((mask.udp->hdr.src_port &&
|
||||||
|
(!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_UDP_SRC,
|
||||||
|
spec.udp->hdr.src_port) ||
|
||||||
|
!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_UDP_SRC_MASK,
|
||||||
|
mask.udp->hdr.src_port))) ||
|
||||||
|
(mask.udp->hdr.dst_port &&
|
||||||
|
(!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_UDP_DST,
|
||||||
|
spec.udp->hdr.dst_port) ||
|
||||||
|
!mnl_attr_put_u16_check(buf, size,
|
||||||
|
TCA_FLOWER_KEY_UDP_DST_MASK,
|
||||||
|
mask.udp->hdr.dst_port))))
|
||||||
|
goto error_nobufs;
|
||||||
|
++item;
|
||||||
|
break;
|
||||||
case ACTIONS:
|
case ACTIONS:
|
||||||
if (item->type != RTE_FLOW_ITEM_TYPE_END)
|
if (item->type != RTE_FLOW_ITEM_TYPE_END)
|
||||||
goto trans;
|
goto trans;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user