net/sfc: support action VXLAN encap in MAE backend

Provide necessary facilities for handling this action.

Signed-off-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
This commit is contained in:
Ivan Malov 2021-03-12 14:07:43 +03:00 committed by Ferruh Yigit
parent 923a96b844
commit 1bbd1ec234
2 changed files with 573 additions and 8 deletions

View File

@ -9,7 +9,9 @@
#include <stdbool.h>
#include <rte_bitops.h>
#include <rte_common.h>
#include <rte_vxlan.h>
#include "efx.h"
@ -35,6 +37,7 @@ sfc_mae_attach(struct sfc_adapter *sa)
const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
efx_mport_sel_t entity_mport;
struct sfc_mae *mae = &sa->mae;
struct sfc_mae_bounce_eh *bounce_eh = &mae->bounce_eh;
efx_mae_limits_t limits;
int rc;
@ -80,17 +83,26 @@ sfc_mae_attach(struct sfc_adapter *sa)
if (rc != 0)
goto fail_mae_assign_switch_port;
sfc_log_init(sa, "allocate encap. header bounce buffer");
bounce_eh->buf_size = limits.eml_encap_header_size_limit;
bounce_eh->buf = rte_malloc("sfc_mae_bounce_eh",
bounce_eh->buf_size, 0);
if (bounce_eh->buf == NULL)
goto fail_mae_alloc_bounce_eh;
mae->status = SFC_MAE_STATUS_SUPPORTED;
mae->nb_outer_rule_prios_max = limits.eml_max_n_outer_prios;
mae->nb_action_rule_prios_max = limits.eml_max_n_action_prios;
mae->encap_types_supported = limits.eml_encap_types_supported;
TAILQ_INIT(&mae->outer_rules);
TAILQ_INIT(&mae->encap_headers);
TAILQ_INIT(&mae->action_sets);
sfc_log_init(sa, "done");
return 0;
fail_mae_alloc_bounce_eh:
fail_mae_assign_switch_port:
fail_mae_assign_switch_domain:
fail_mae_assign_entity_mport:
@ -117,6 +129,8 @@ sfc_mae_detach(struct sfc_adapter *sa)
if (status_prev != SFC_MAE_STATUS_SUPPORTED)
return;
rte_free(mae->bounce_eh.buf);
efx_mae_fini(sa->nic);
sfc_log_init(sa, "done");
@ -254,8 +268,165 @@ sfc_mae_outer_rule_disable(struct sfc_adapter *sa,
return 0;
}
static struct sfc_mae_encap_header *
sfc_mae_encap_header_attach(struct sfc_adapter *sa,
const struct sfc_mae_bounce_eh *bounce_eh)
{
struct sfc_mae_encap_header *encap_header;
struct sfc_mae *mae = &sa->mae;
SFC_ASSERT(sfc_adapter_is_locked(sa));
TAILQ_FOREACH(encap_header, &mae->encap_headers, entries) {
if (encap_header->size == bounce_eh->size &&
memcmp(encap_header->buf, bounce_eh->buf,
bounce_eh->size) == 0) {
++(encap_header->refcnt);
return encap_header;
}
}
return NULL;
}
static int
sfc_mae_encap_header_add(struct sfc_adapter *sa,
const struct sfc_mae_bounce_eh *bounce_eh,
struct sfc_mae_encap_header **encap_headerp)
{
struct sfc_mae_encap_header *encap_header;
struct sfc_mae *mae = &sa->mae;
SFC_ASSERT(sfc_adapter_is_locked(sa));
encap_header = rte_zmalloc("sfc_mae_encap_header",
sizeof(*encap_header), 0);
if (encap_header == NULL)
return ENOMEM;
encap_header->size = bounce_eh->size;
encap_header->buf = rte_malloc("sfc_mae_encap_header_buf",
encap_header->size, 0);
if (encap_header->buf == NULL) {
rte_free(encap_header);
return ENOMEM;
}
rte_memcpy(encap_header->buf, bounce_eh->buf, bounce_eh->size);
encap_header->refcnt = 1;
encap_header->type = bounce_eh->type;
encap_header->fw_rsrc.eh_id.id = EFX_MAE_RSRC_ID_INVALID;
TAILQ_INSERT_TAIL(&mae->encap_headers, encap_header, entries);
*encap_headerp = encap_header;
return 0;
}
static void
sfc_mae_encap_header_del(struct sfc_adapter *sa,
struct sfc_mae_encap_header *encap_header)
{
struct sfc_mae *mae = &sa->mae;
if (encap_header == NULL)
return;
SFC_ASSERT(sfc_adapter_is_locked(sa));
SFC_ASSERT(encap_header->refcnt != 0);
--(encap_header->refcnt);
if (encap_header->refcnt != 0)
return;
SFC_ASSERT(encap_header->fw_rsrc.eh_id.id == EFX_MAE_RSRC_ID_INVALID);
SFC_ASSERT(encap_header->fw_rsrc.refcnt == 0);
TAILQ_REMOVE(&mae->encap_headers, encap_header, entries);
rte_free(encap_header->buf);
rte_free(encap_header);
}
static int
sfc_mae_encap_header_enable(struct sfc_adapter *sa,
struct sfc_mae_encap_header *encap_header,
efx_mae_actions_t *action_set_spec)
{
struct sfc_mae_fw_rsrc *fw_rsrc;
int rc;
if (encap_header == NULL)
return 0;
SFC_ASSERT(sfc_adapter_is_locked(sa));
fw_rsrc = &encap_header->fw_rsrc;
if (fw_rsrc->refcnt == 0) {
SFC_ASSERT(fw_rsrc->eh_id.id == EFX_MAE_RSRC_ID_INVALID);
SFC_ASSERT(encap_header->buf != NULL);
SFC_ASSERT(encap_header->size != 0);
rc = efx_mae_encap_header_alloc(sa->nic, encap_header->type,
encap_header->buf,
encap_header->size,
&fw_rsrc->eh_id);
if (rc != 0)
return rc;
}
rc = efx_mae_action_set_fill_in_eh_id(action_set_spec,
&fw_rsrc->eh_id);
if (rc != 0) {
if (fw_rsrc->refcnt == 0) {
(void)efx_mae_encap_header_free(sa->nic,
&fw_rsrc->eh_id);
}
return rc;
}
++(fw_rsrc->refcnt);
return 0;
}
static int
sfc_mae_encap_header_disable(struct sfc_adapter *sa,
struct sfc_mae_encap_header *encap_header)
{
struct sfc_mae_fw_rsrc *fw_rsrc;
int rc;
if (encap_header == NULL)
return 0;
SFC_ASSERT(sfc_adapter_is_locked(sa));
fw_rsrc = &encap_header->fw_rsrc;
SFC_ASSERT(fw_rsrc->eh_id.id != EFX_MAE_RSRC_ID_INVALID);
SFC_ASSERT(fw_rsrc->refcnt != 0);
if (fw_rsrc->refcnt == 1) {
rc = efx_mae_encap_header_free(sa->nic, &fw_rsrc->eh_id);
if (rc != 0)
return rc;
fw_rsrc->eh_id.id = EFX_MAE_RSRC_ID_INVALID;
}
--(fw_rsrc->refcnt);
return 0;
}
static struct sfc_mae_action_set *
sfc_mae_action_set_attach(struct sfc_adapter *sa,
const struct sfc_mae_encap_header *encap_header,
const efx_mae_actions_t *spec)
{
struct sfc_mae_action_set *action_set;
@ -264,7 +435,8 @@ sfc_mae_action_set_attach(struct sfc_adapter *sa,
SFC_ASSERT(sfc_adapter_is_locked(sa));
TAILQ_FOREACH(action_set, &mae->action_sets, entries) {
if (efx_mae_action_set_specs_equal(action_set->spec, spec)) {
if (action_set->encap_header == encap_header &&
efx_mae_action_set_specs_equal(action_set->spec, spec)) {
++(action_set->refcnt);
return action_set;
}
@ -276,6 +448,7 @@ sfc_mae_action_set_attach(struct sfc_adapter *sa,
static int
sfc_mae_action_set_add(struct sfc_adapter *sa,
efx_mae_actions_t *spec,
struct sfc_mae_encap_header *encap_header,
struct sfc_mae_action_set **action_setp)
{
struct sfc_mae_action_set *action_set;
@ -289,6 +462,7 @@ sfc_mae_action_set_add(struct sfc_adapter *sa,
action_set->refcnt = 1;
action_set->spec = spec;
action_set->encap_header = encap_header;
action_set->fw_rsrc.aset_id.id = EFX_MAE_RSRC_ID_INVALID;
@ -317,6 +491,7 @@ sfc_mae_action_set_del(struct sfc_adapter *sa,
SFC_ASSERT(action_set->fw_rsrc.refcnt == 0);
efx_mae_action_set_spec_fini(sa->nic, action_set->spec);
sfc_mae_encap_header_del(sa, action_set->encap_header);
TAILQ_REMOVE(&mae->action_sets, action_set, entries);
rte_free(action_set);
}
@ -325,6 +500,7 @@ static int
sfc_mae_action_set_enable(struct sfc_adapter *sa,
struct sfc_mae_action_set *action_set)
{
struct sfc_mae_encap_header *encap_header = action_set->encap_header;
struct sfc_mae_fw_rsrc *fw_rsrc = &action_set->fw_rsrc;
int rc;
@ -334,10 +510,18 @@ sfc_mae_action_set_enable(struct sfc_adapter *sa,
SFC_ASSERT(fw_rsrc->aset_id.id == EFX_MAE_RSRC_ID_INVALID);
SFC_ASSERT(action_set->spec != NULL);
rc = efx_mae_action_set_alloc(sa->nic, action_set->spec,
&fw_rsrc->aset_id);
rc = sfc_mae_encap_header_enable(sa, encap_header,
action_set->spec);
if (rc != 0)
return rc;
rc = efx_mae_action_set_alloc(sa->nic, action_set->spec,
&fw_rsrc->aset_id);
if (rc != 0) {
(void)sfc_mae_encap_header_disable(sa, encap_header);
return rc;
}
}
++(fw_rsrc->refcnt);
@ -362,6 +546,10 @@ sfc_mae_action_set_disable(struct sfc_adapter *sa,
return rc;
fw_rsrc->aset_id.id = EFX_MAE_RSRC_ID_INVALID;
rc = sfc_mae_encap_header_disable(sa, action_set->encap_header);
if (rc != 0)
return rc;
}
--(fw_rsrc->refcnt);
@ -1936,6 +2124,307 @@ sfc_mae_rule_parse_action_of_set_vlan_pcp(
bundle->vlan_push_tci |= rte_cpu_to_be_16(vlan_tci_pcp);
}
struct sfc_mae_parsed_item {
const struct rte_flow_item *item;
size_t proto_header_ofst;
size_t proto_header_size;
};
/*
* For each 16-bit word of the given header, override
* bits enforced by the corresponding 16-bit mask.
*/
static void
sfc_mae_header_force_item_masks(uint8_t *header_buf,
const struct sfc_mae_parsed_item *parsed_items,
unsigned int nb_parsed_items)
{
unsigned int item_idx;
for (item_idx = 0; item_idx < nb_parsed_items; ++item_idx) {
const struct sfc_mae_parsed_item *parsed_item;
const struct rte_flow_item *item;
size_t proto_header_size;
size_t ofst;
parsed_item = &parsed_items[item_idx];
proto_header_size = parsed_item->proto_header_size;
item = parsed_item->item;
for (ofst = 0; ofst < proto_header_size;
ofst += sizeof(rte_be16_t)) {
rte_be16_t *wp = RTE_PTR_ADD(header_buf, ofst);
const rte_be16_t *w_maskp;
const rte_be16_t *w_specp;
w_maskp = RTE_PTR_ADD(item->mask, ofst);
w_specp = RTE_PTR_ADD(item->spec, ofst);
*wp &= ~(*w_maskp);
*wp |= (*w_specp & *w_maskp);
}
header_buf += proto_header_size;
}
}
#define SFC_IPV4_TTL_DEF 0x40
#define SFC_IPV6_VTC_FLOW_DEF 0x60000000
#define SFC_IPV6_HOP_LIMITS_DEF 0xff
#define SFC_VXLAN_FLAGS_DEF 0x08000000
static int
sfc_mae_rule_parse_action_vxlan_encap(
struct sfc_mae *mae,
const struct rte_flow_action_vxlan_encap *conf,
efx_mae_actions_t *spec,
struct rte_flow_error *error)
{
struct sfc_mae_bounce_eh *bounce_eh = &mae->bounce_eh;
struct rte_flow_item *pattern = conf->definition;
uint8_t *buf = bounce_eh->buf;
/* This array will keep track of non-VOID pattern items. */
struct sfc_mae_parsed_item parsed_items[1 /* Ethernet */ +
2 /* VLAN tags */ +
1 /* IPv4 or IPv6 */ +
1 /* UDP */ +
1 /* VXLAN */];
unsigned int nb_parsed_items = 0;
size_t eth_ethertype_ofst = offsetof(struct rte_ether_hdr, ether_type);
uint8_t dummy_buf[RTE_MAX(sizeof(struct rte_ipv4_hdr),
sizeof(struct rte_ipv6_hdr))];
struct rte_ipv4_hdr *ipv4 = (void *)dummy_buf;
struct rte_ipv6_hdr *ipv6 = (void *)dummy_buf;
struct rte_vxlan_hdr *vxlan = NULL;
struct rte_udp_hdr *udp = NULL;
unsigned int nb_vlan_tags = 0;
size_t next_proto_ofst = 0;
size_t ethertype_ofst = 0;
uint64_t exp_items;
if (pattern == NULL) {
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
"The encap. header definition is NULL");
}
bounce_eh->type = EFX_TUNNEL_PROTOCOL_VXLAN;
bounce_eh->size = 0;
/*
* Process pattern items and remember non-VOID ones.
* Defer applying masks until after the complete header
* has been built from the pattern items.
*/
exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_ETH);
for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; ++pattern) {
struct sfc_mae_parsed_item *parsed_item;
const uint64_t exp_items_extra_vlan[] = {
RTE_BIT64(RTE_FLOW_ITEM_TYPE_VLAN), 0
};
size_t proto_header_size;
rte_be16_t *ethertypep;
uint8_t *next_protop;
uint8_t *buf_cur;
if (pattern->spec == NULL) {
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
"NULL item spec in the encap. header");
}
if (pattern->mask == NULL) {
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
"NULL item mask in the encap. header");
}
if (pattern->last != NULL) {
/* This is not a match pattern, so disallow range. */
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
"Range item in the encap. header");
}
if (pattern->type == RTE_FLOW_ITEM_TYPE_VOID) {
/* Handle VOID separately, for clarity. */
continue;
}
if ((exp_items & RTE_BIT64(pattern->type)) == 0) {
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
"Unexpected item in the encap. header");
}
parsed_item = &parsed_items[nb_parsed_items];
buf_cur = buf + bounce_eh->size;
switch (pattern->type) {
case RTE_FLOW_ITEM_TYPE_ETH:
SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_ETH,
exp_items);
RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_eth,
hdr) != 0);
proto_header_size = sizeof(struct rte_ether_hdr);
ethertype_ofst = eth_ethertype_ofst;
exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_VLAN) |
RTE_BIT64(RTE_FLOW_ITEM_TYPE_IPV4) |
RTE_BIT64(RTE_FLOW_ITEM_TYPE_IPV6);
break;
case RTE_FLOW_ITEM_TYPE_VLAN:
SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_VLAN,
exp_items);
RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_vlan,
hdr) != 0);
proto_header_size = sizeof(struct rte_vlan_hdr);
ethertypep = RTE_PTR_ADD(buf, eth_ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_QINQ);
ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_VLAN);
ethertype_ofst =
bounce_eh->size +
offsetof(struct rte_vlan_hdr, eth_proto);
exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_IPV4) |
RTE_BIT64(RTE_FLOW_ITEM_TYPE_IPV6);
exp_items |= exp_items_extra_vlan[nb_vlan_tags];
++nb_vlan_tags;
break;
case RTE_FLOW_ITEM_TYPE_IPV4:
SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_IPV4,
exp_items);
RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_ipv4,
hdr) != 0);
proto_header_size = sizeof(struct rte_ipv4_hdr);
ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_IPV4);
next_proto_ofst =
bounce_eh->size +
offsetof(struct rte_ipv4_hdr, next_proto_id);
ipv4 = (struct rte_ipv4_hdr *)buf_cur;
exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_UDP);
break;
case RTE_FLOW_ITEM_TYPE_IPV6:
SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_IPV6,
exp_items);
RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_ipv6,
hdr) != 0);
proto_header_size = sizeof(struct rte_ipv6_hdr);
ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_IPV6);
next_proto_ofst = bounce_eh->size +
offsetof(struct rte_ipv6_hdr, proto);
ipv6 = (struct rte_ipv6_hdr *)buf_cur;
exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_UDP);
break;
case RTE_FLOW_ITEM_TYPE_UDP:
SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_UDP,
exp_items);
RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_udp,
hdr) != 0);
proto_header_size = sizeof(struct rte_udp_hdr);
next_protop = RTE_PTR_ADD(buf, next_proto_ofst);
*next_protop = IPPROTO_UDP;
udp = (struct rte_udp_hdr *)buf_cur;
exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_VXLAN);
break;
case RTE_FLOW_ITEM_TYPE_VXLAN:
SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_VXLAN,
exp_items);
RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_vxlan,
hdr) != 0);
proto_header_size = sizeof(struct rte_vxlan_hdr);
vxlan = (struct rte_vxlan_hdr *)buf_cur;
udp->dst_port = RTE_BE16(RTE_VXLAN_DEFAULT_PORT);
udp->dgram_len = RTE_BE16(sizeof(*udp) +
sizeof(*vxlan));
udp->dgram_cksum = 0;
exp_items = 0;
break;
default:
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
"Unknown item in the encap. header");
}
if (bounce_eh->size + proto_header_size > bounce_eh->buf_size) {
return rte_flow_error_set(error, E2BIG,
RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
"The encap. header is too big");
}
if ((proto_header_size & 1) != 0) {
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
"Odd layer size in the encap. header");
}
rte_memcpy(buf_cur, pattern->spec, proto_header_size);
bounce_eh->size += proto_header_size;
parsed_item->item = pattern;
parsed_item->proto_header_size = proto_header_size;
++nb_parsed_items;
}
if (exp_items != 0) {
/* Parsing item VXLAN would have reset exp_items to 0. */
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
"No item VXLAN in the encap. header");
}
/* One of the pointers (ipv4, ipv6) refers to a dummy area. */
ipv4->version_ihl = RTE_IPV4_VHL_DEF;
ipv4->time_to_live = SFC_IPV4_TTL_DEF;
ipv4->total_length = RTE_BE16(sizeof(*ipv4) + sizeof(*udp) +
sizeof(*vxlan));
/* The HW cannot compute this checksum. */
ipv4->hdr_checksum = 0;
ipv4->hdr_checksum = rte_ipv4_cksum(ipv4);
ipv6->vtc_flow = RTE_BE32(SFC_IPV6_VTC_FLOW_DEF);
ipv6->hop_limits = SFC_IPV6_HOP_LIMITS_DEF;
ipv6->payload_len = udp->dgram_len;
vxlan->vx_flags = RTE_BE32(SFC_VXLAN_FLAGS_DEF);
/* Take care of the masks. */
sfc_mae_header_force_item_masks(buf, parsed_items, nb_parsed_items);
return (spec != NULL) ? efx_mae_action_set_populate_encap(spec) : 0;
}
static int
sfc_mae_rule_parse_action_mark(const struct rte_flow_action_mark *conf,
efx_mae_actions_t *spec)
@ -2016,6 +2505,7 @@ sfc_mae_rule_parse_action(struct sfc_adapter *sa,
efx_mae_actions_t *spec,
struct rte_flow_error *error)
{
bool custom_error = B_FALSE;
int rc = 0;
switch (action->type) {
@ -2039,6 +2529,14 @@ sfc_mae_rule_parse_action(struct sfc_adapter *sa,
bundle->actions_mask);
sfc_mae_rule_parse_action_of_set_vlan_pcp(action->conf, bundle);
break;
case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP,
bundle->actions_mask);
rc = sfc_mae_rule_parse_action_vxlan_encap(&sa->mae,
action->conf,
spec, error);
custom_error = B_TRUE;
break;
case RTE_FLOW_ACTION_TYPE_FLAG:
SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_FLAG,
bundle->actions_mask);
@ -2080,24 +2578,49 @@ sfc_mae_rule_parse_action(struct sfc_adapter *sa,
"Unsupported action");
}
if (rc != 0) {
if (rc == 0) {
bundle->actions_mask |= (1ULL << action->type);
} else if (!custom_error) {
rc = rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION,
NULL, "Failed to request the action");
} else {
bundle->actions_mask |= (1ULL << action->type);
}
return rc;
}
static void
sfc_mae_bounce_eh_invalidate(struct sfc_mae_bounce_eh *bounce_eh)
{
bounce_eh->type = EFX_TUNNEL_PROTOCOL_NONE;
}
static int
sfc_mae_process_encap_header(struct sfc_adapter *sa,
const struct sfc_mae_bounce_eh *bounce_eh,
struct sfc_mae_encap_header **encap_headerp)
{
if (bounce_eh->type == EFX_TUNNEL_PROTOCOL_NONE) {
encap_headerp = NULL;
return 0;
}
*encap_headerp = sfc_mae_encap_header_attach(sa, bounce_eh);
if (*encap_headerp != NULL)
return 0;
return sfc_mae_encap_header_add(sa, bounce_eh, encap_headerp);
}
int
sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
const struct rte_flow_action actions[],
struct sfc_flow_spec_mae *spec_mae,
struct rte_flow_error *error)
{
struct sfc_mae_encap_header *encap_header = NULL;
struct sfc_mae_actions_bundle bundle = {0};
const struct rte_flow_action *action;
struct sfc_mae *mae = &sa->mae;
efx_mae_actions_t *spec;
int rc;
@ -2111,6 +2634,9 @@ sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
if (rc != 0)
goto fail_action_set_spec_init;
/* Cleanup after previous encap. header bounce buffer usage. */
sfc_mae_bounce_eh_invalidate(&mae->bounce_eh);
for (action = actions;
action->type != RTE_FLOW_ACTION_TYPE_END; ++action) {
rc = sfc_mae_actions_bundle_sync(action, &bundle, spec, error);
@ -2127,19 +2653,29 @@ sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
if (rc != 0)
goto fail_rule_parse_action;
spec_mae->action_set = sfc_mae_action_set_attach(sa, spec);
rc = sfc_mae_process_encap_header(sa, &mae->bounce_eh, &encap_header);
if (rc != 0)
goto fail_process_encap_header;
spec_mae->action_set = sfc_mae_action_set_attach(sa, encap_header,
spec);
if (spec_mae->action_set != NULL) {
sfc_mae_encap_header_del(sa, encap_header);
efx_mae_action_set_spec_fini(sa->nic, spec);
return 0;
}
rc = sfc_mae_action_set_add(sa, spec, &spec_mae->action_set);
rc = sfc_mae_action_set_add(sa, spec, encap_header,
&spec_mae->action_set);
if (rc != 0)
goto fail_action_set_add;
return 0;
fail_action_set_add:
sfc_mae_encap_header_del(sa, encap_header);
fail_process_encap_header:
fail_rule_parse_action:
efx_mae_action_set_spec_fini(sa->nic, spec);

View File

@ -27,6 +27,7 @@ struct sfc_mae_fw_rsrc {
union {
efx_mae_aset_id_t aset_id;
efx_mae_rule_id_t rule_id;
efx_mae_eh_id_t eh_id;
};
};
@ -41,11 +42,24 @@ struct sfc_mae_outer_rule {
TAILQ_HEAD(sfc_mae_outer_rules, sfc_mae_outer_rule);
/** Encap. header registry entry */
struct sfc_mae_encap_header {
TAILQ_ENTRY(sfc_mae_encap_header) entries;
unsigned int refcnt;
uint8_t *buf;
size_t size;
efx_tunnel_protocol_t type;
struct sfc_mae_fw_rsrc fw_rsrc;
};
TAILQ_HEAD(sfc_mae_encap_headers, sfc_mae_encap_header);
/** Action set registry entry */
struct sfc_mae_action_set {
TAILQ_ENTRY(sfc_mae_action_set) entries;
unsigned int refcnt;
efx_mae_actions_t *spec;
struct sfc_mae_encap_header *encap_header;
struct sfc_mae_fw_rsrc fw_rsrc;
};
@ -58,6 +72,17 @@ enum sfc_mae_status {
SFC_MAE_STATUS_SUPPORTED
};
/*
* Encap. header bounce buffer. It is used to store header data
* when parsing the header definition in the action VXLAN_ENCAP.
*/
struct sfc_mae_bounce_eh {
uint8_t *buf;
size_t buf_size;
size_t size;
efx_tunnel_protocol_t type;
};
struct sfc_mae {
/** Assigned switch domain identifier */
uint16_t switch_domain_id;
@ -73,8 +98,12 @@ struct sfc_mae {
uint32_t encap_types_supported;
/** Outer rule registry */
struct sfc_mae_outer_rules outer_rules;
/** Encap. header registry */
struct sfc_mae_encap_headers encap_headers;
/** Action set registry */
struct sfc_mae_action_sets action_sets;
/** Encap. header bounce buffer */
struct sfc_mae_bounce_eh bounce_eh;
};
struct sfc_adapter;