app/testpmd: add commands for tunnel offload
Tunnel Offload API provides hardware independent, unified model to offload tunneled traffic. Key model elements are: - apply matches to both outer and inner packet headers during entire offload procedure; - restore outer header of partially offloaded packet; - model is implemented as a set of helper functions. Implementation details: * Create application tunnel: flow tunnel create <port> type <tunnel type> On success, the command creates application tunnel object and returns the tunnel descriptor. Tunnel descriptor is used in subsequent flow creation commands to reference the tunnel. * Create tunnel steering flow rule: tunnel_set <tunnel descriptor> parameter used with steering rule template. * Create tunnel matching flow rule: tunnel_match <tunnel descriptor> used with matching rule template. * If tunnel steering rule was offloaded, outer header of a partially offloaded packet is restored after miss. Example: test packet= <Ether dst=24:8a:07:8d:ae:d6 src=50:6b:4b:cc:fc:e2 type=IPv4 | <IP version=4 ihl=5 proto=udp src=1.1.1.1 dst=1.1.1.10 | <UDP sport=4789 dport=4789 len=58 chksum=0x7f7b | <VXLAN NextProtocol=Ethernet vni=0x0 | <Ether dst=24:aa:aa:aa:aa:d6 src=50:bb:bb:bb:bb:e2 type=IPv4 | <IP version=4 ihl=5 proto=icmp src=2.2.2.2 dst=2.2.2.200 | <ICMP type=echo-request code=0 chksum=0xf7ff id=0x0 seq=0x0 |>>>>>>> >>> len(packet) 92 testpmd> flow flush 0 testpmd> port 0/queue 0: received 1 packets src=50:6B:4B:CC:FC:E2 - dst=24:8A:07:8D:AE:D6 - type=0x0800 - length=92 testpmd> flow tunnel 0 type vxlan port 0: flow tunnel #1 type vxlan testpmd> flow create 0 ingress group 0 tunnel_set 1 pattern eth /ipv4 / udp dst is 4789 / vxlan / end actions jump group 0 / end Flow rule #0 created testpmd> port 0/queue 0: received 1 packets tunnel restore info: - vxlan tunnel - outer header present # <-- src=50:6B:4B:CC:FC:E2 - dst=24:8A:07:8D:AE:D6 - type=0x0800 - length=92 testpmd> flow create 0 ingress group 0 tunnel_match 1 pattern eth / ipv4 / udp dst is 4789 / vxlan / eth / ipv4 / end actions set_mac_dst mac_addr 02:CA:FE:CA:FA:80 / queue index 0 / end Flow rule #1 created testpmd> port 0/queue 0: received 1 packets src=50:BB:BB:BB:BB:E2 - dst=02:CA:FE:CA:FA:80 - type=0x0800 - length=42 * Destroy flow tunnel flow tunnel destroy <port> id <tunnel id> * Show existing flow tunnels flow tunnel list <port> Signed-off-by: Gregory Etelson <getelson@nvidia.com>
This commit is contained in:
parent
9ec0f97e02
commit
1b9f274623
@ -74,6 +74,14 @@ enum index {
|
||||
LIST,
|
||||
AGED,
|
||||
ISOLATE,
|
||||
TUNNEL,
|
||||
|
||||
/* Tunnel arguments. */
|
||||
TUNNEL_CREATE,
|
||||
TUNNEL_CREATE_TYPE,
|
||||
TUNNEL_LIST,
|
||||
TUNNEL_DESTROY,
|
||||
TUNNEL_DESTROY_ID,
|
||||
|
||||
/* Destroy arguments. */
|
||||
DESTROY_RULE,
|
||||
@ -93,6 +101,8 @@ enum index {
|
||||
INGRESS,
|
||||
EGRESS,
|
||||
TRANSFER,
|
||||
TUNNEL_SET,
|
||||
TUNNEL_MATCH,
|
||||
|
||||
/* Shared action arguments */
|
||||
SHARED_ACTION_CREATE,
|
||||
@ -713,6 +723,7 @@ struct buffer {
|
||||
} sa; /* Shared action query arguments */
|
||||
struct {
|
||||
struct rte_flow_attr attr;
|
||||
struct tunnel_ops tunnel_ops;
|
||||
struct rte_flow_item *pattern;
|
||||
struct rte_flow_action *actions;
|
||||
uint32_t pattern_n;
|
||||
@ -789,10 +800,32 @@ static const enum index next_vc_attr[] = {
|
||||
INGRESS,
|
||||
EGRESS,
|
||||
TRANSFER,
|
||||
TUNNEL_SET,
|
||||
TUNNEL_MATCH,
|
||||
PATTERN,
|
||||
ZERO,
|
||||
};
|
||||
|
||||
static const enum index tunnel_create_attr[] = {
|
||||
TUNNEL_CREATE,
|
||||
TUNNEL_CREATE_TYPE,
|
||||
END,
|
||||
ZERO,
|
||||
};
|
||||
|
||||
static const enum index tunnel_destroy_attr[] = {
|
||||
TUNNEL_DESTROY,
|
||||
TUNNEL_DESTROY_ID,
|
||||
END,
|
||||
ZERO,
|
||||
};
|
||||
|
||||
static const enum index tunnel_list_attr[] = {
|
||||
TUNNEL_LIST,
|
||||
END,
|
||||
ZERO,
|
||||
};
|
||||
|
||||
static const enum index next_destroy_attr[] = {
|
||||
DESTROY_RULE,
|
||||
END,
|
||||
@ -1643,6 +1676,9 @@ static int parse_aged(struct context *, const struct token *,
|
||||
static int parse_isolate(struct context *, const struct token *,
|
||||
const char *, unsigned int,
|
||||
void *, unsigned int);
|
||||
static int parse_tunnel(struct context *, const struct token *,
|
||||
const char *, unsigned int,
|
||||
void *, unsigned int);
|
||||
static int parse_int(struct context *, const struct token *,
|
||||
const char *, unsigned int,
|
||||
void *, unsigned int);
|
||||
@ -1844,7 +1880,8 @@ static const struct token token_list[] = {
|
||||
LIST,
|
||||
AGED,
|
||||
QUERY,
|
||||
ISOLATE)),
|
||||
ISOLATE,
|
||||
TUNNEL)),
|
||||
.call = parse_init,
|
||||
},
|
||||
/* Top-level command. */
|
||||
@ -1955,6 +1992,49 @@ static const struct token token_list[] = {
|
||||
ARGS_ENTRY(struct buffer, port)),
|
||||
.call = parse_isolate,
|
||||
},
|
||||
[TUNNEL] = {
|
||||
.name = "tunnel",
|
||||
.help = "new tunnel API",
|
||||
.next = NEXT(NEXT_ENTRY
|
||||
(TUNNEL_CREATE, TUNNEL_LIST, TUNNEL_DESTROY)),
|
||||
.call = parse_tunnel,
|
||||
},
|
||||
/* Tunnel arguments. */
|
||||
[TUNNEL_CREATE] = {
|
||||
.name = "create",
|
||||
.help = "create new tunnel object",
|
||||
.next = NEXT(tunnel_create_attr, NEXT_ENTRY(PORT_ID)),
|
||||
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
|
||||
.call = parse_tunnel,
|
||||
},
|
||||
[TUNNEL_CREATE_TYPE] = {
|
||||
.name = "type",
|
||||
.help = "create new tunnel",
|
||||
.next = NEXT(tunnel_create_attr, NEXT_ENTRY(FILE_PATH)),
|
||||
.args = ARGS(ARGS_ENTRY(struct tunnel_ops, type)),
|
||||
.call = parse_tunnel,
|
||||
},
|
||||
[TUNNEL_DESTROY] = {
|
||||
.name = "destroy",
|
||||
.help = "destroy tunel",
|
||||
.next = NEXT(tunnel_destroy_attr, NEXT_ENTRY(PORT_ID)),
|
||||
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
|
||||
.call = parse_tunnel,
|
||||
},
|
||||
[TUNNEL_DESTROY_ID] = {
|
||||
.name = "id",
|
||||
.help = "tunnel identifier to testroy",
|
||||
.next = NEXT(tunnel_destroy_attr, NEXT_ENTRY(UNSIGNED)),
|
||||
.args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)),
|
||||
.call = parse_tunnel,
|
||||
},
|
||||
[TUNNEL_LIST] = {
|
||||
.name = "list",
|
||||
.help = "list existing tunnels",
|
||||
.next = NEXT(tunnel_list_attr, NEXT_ENTRY(PORT_ID)),
|
||||
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
|
||||
.call = parse_tunnel,
|
||||
},
|
||||
/* Destroy arguments. */
|
||||
[DESTROY_RULE] = {
|
||||
.name = "rule",
|
||||
@ -2018,6 +2098,20 @@ static const struct token token_list[] = {
|
||||
.next = NEXT(next_vc_attr),
|
||||
.call = parse_vc,
|
||||
},
|
||||
[TUNNEL_SET] = {
|
||||
.name = "tunnel_set",
|
||||
.help = "tunnel steer rule",
|
||||
.next = NEXT(next_vc_attr, NEXT_ENTRY(UNSIGNED)),
|
||||
.args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)),
|
||||
.call = parse_vc,
|
||||
},
|
||||
[TUNNEL_MATCH] = {
|
||||
.name = "tunnel_match",
|
||||
.help = "tunnel match rule",
|
||||
.next = NEXT(next_vc_attr, NEXT_ENTRY(UNSIGNED)),
|
||||
.args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)),
|
||||
.call = parse_vc,
|
||||
},
|
||||
/* Validate/create pattern. */
|
||||
[PATTERN] = {
|
||||
.name = "pattern",
|
||||
@ -4495,12 +4589,28 @@ parse_vc(struct context *ctx, const struct token *token,
|
||||
return len;
|
||||
}
|
||||
ctx->objdata = 0;
|
||||
ctx->object = &out->args.vc.attr;
|
||||
switch (ctx->curr) {
|
||||
default:
|
||||
ctx->object = &out->args.vc.attr;
|
||||
break;
|
||||
case TUNNEL_SET:
|
||||
case TUNNEL_MATCH:
|
||||
ctx->object = &out->args.vc.tunnel_ops;
|
||||
break;
|
||||
}
|
||||
ctx->objmask = NULL;
|
||||
switch (ctx->curr) {
|
||||
case GROUP:
|
||||
case PRIORITY:
|
||||
return len;
|
||||
case TUNNEL_SET:
|
||||
out->args.vc.tunnel_ops.enabled = 1;
|
||||
out->args.vc.tunnel_ops.actions = 1;
|
||||
return len;
|
||||
case TUNNEL_MATCH:
|
||||
out->args.vc.tunnel_ops.enabled = 1;
|
||||
out->args.vc.tunnel_ops.items = 1;
|
||||
return len;
|
||||
case INGRESS:
|
||||
out->args.vc.attr.ingress = 1;
|
||||
return len;
|
||||
@ -6108,6 +6218,47 @@ parse_isolate(struct context *ctx, const struct token *token,
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_tunnel(struct context *ctx, const struct token *token,
|
||||
const char *str, unsigned int len,
|
||||
void *buf, unsigned int size)
|
||||
{
|
||||
struct buffer *out = buf;
|
||||
|
||||
/* Token name must match. */
|
||||
if (parse_default(ctx, token, str, len, NULL, 0) < 0)
|
||||
return -1;
|
||||
/* Nothing else to do if there is no buffer. */
|
||||
if (!out)
|
||||
return len;
|
||||
if (!out->command) {
|
||||
if (ctx->curr != TUNNEL)
|
||||
return -1;
|
||||
if (sizeof(*out) > size)
|
||||
return -1;
|
||||
out->command = ctx->curr;
|
||||
ctx->objdata = 0;
|
||||
ctx->object = out;
|
||||
ctx->objmask = NULL;
|
||||
} else {
|
||||
switch (ctx->curr) {
|
||||
default:
|
||||
break;
|
||||
case TUNNEL_CREATE:
|
||||
case TUNNEL_DESTROY:
|
||||
case TUNNEL_LIST:
|
||||
out->command = ctx->curr;
|
||||
break;
|
||||
case TUNNEL_CREATE_TYPE:
|
||||
case TUNNEL_DESTROY_ID:
|
||||
ctx->object = &out->args.vc.tunnel_ops;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse signed/unsigned integers 8 to 64-bit long.
|
||||
*
|
||||
@ -7148,11 +7299,13 @@ cmd_flow_parsed(const struct buffer *in)
|
||||
break;
|
||||
case VALIDATE:
|
||||
port_flow_validate(in->port, &in->args.vc.attr,
|
||||
in->args.vc.pattern, in->args.vc.actions);
|
||||
in->args.vc.pattern, in->args.vc.actions,
|
||||
&in->args.vc.tunnel_ops);
|
||||
break;
|
||||
case CREATE:
|
||||
port_flow_create(in->port, &in->args.vc.attr,
|
||||
in->args.vc.pattern, in->args.vc.actions);
|
||||
in->args.vc.pattern, in->args.vc.actions,
|
||||
&in->args.vc.tunnel_ops);
|
||||
break;
|
||||
case DESTROY:
|
||||
port_flow_destroy(in->port, in->args.destroy.rule_n,
|
||||
@ -7178,6 +7331,15 @@ cmd_flow_parsed(const struct buffer *in)
|
||||
case AGED:
|
||||
port_flow_aged(in->port, in->args.aged.destroy);
|
||||
break;
|
||||
case TUNNEL_CREATE:
|
||||
port_flow_tunnel_create(in->port, &in->args.vc.tunnel_ops);
|
||||
break;
|
||||
case TUNNEL_DESTROY:
|
||||
port_flow_tunnel_destroy(in->port, in->args.vc.tunnel_ops.id);
|
||||
break;
|
||||
case TUNNEL_LIST:
|
||||
port_flow_tunnel_list(in->port);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1521,6 +1521,115 @@ port_mtu_set(portid_t port_id, uint16_t mtu)
|
||||
|
||||
/* Generic flow management functions. */
|
||||
|
||||
static struct port_flow_tunnel *
|
||||
port_flow_locate_tunnel_id(struct rte_port *port, uint32_t port_tunnel_id)
|
||||
{
|
||||
struct port_flow_tunnel *flow_tunnel;
|
||||
|
||||
LIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) {
|
||||
if (flow_tunnel->id == port_tunnel_id)
|
||||
goto out;
|
||||
}
|
||||
flow_tunnel = NULL;
|
||||
|
||||
out:
|
||||
return flow_tunnel;
|
||||
}
|
||||
|
||||
const char *
|
||||
port_flow_tunnel_type(struct rte_flow_tunnel *tunnel)
|
||||
{
|
||||
const char *type;
|
||||
switch (tunnel->type) {
|
||||
default:
|
||||
type = "unknown";
|
||||
break;
|
||||
case RTE_FLOW_ITEM_TYPE_VXLAN:
|
||||
type = "vxlan";
|
||||
break;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
struct port_flow_tunnel *
|
||||
port_flow_locate_tunnel(uint16_t port_id, struct rte_flow_tunnel *tun)
|
||||
{
|
||||
struct rte_port *port = &ports[port_id];
|
||||
struct port_flow_tunnel *flow_tunnel;
|
||||
|
||||
LIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) {
|
||||
if (!memcmp(&flow_tunnel->tunnel, tun, sizeof(*tun)))
|
||||
goto out;
|
||||
}
|
||||
flow_tunnel = NULL;
|
||||
|
||||
out:
|
||||
return flow_tunnel;
|
||||
}
|
||||
|
||||
void port_flow_tunnel_list(portid_t port_id)
|
||||
{
|
||||
struct rte_port *port = &ports[port_id];
|
||||
struct port_flow_tunnel *flt;
|
||||
|
||||
LIST_FOREACH(flt, &port->flow_tunnel_list, chain) {
|
||||
printf("port %u tunnel #%u type=%s",
|
||||
port_id, flt->id, port_flow_tunnel_type(&flt->tunnel));
|
||||
if (flt->tunnel.tun_id)
|
||||
printf(" id=%" PRIu64, flt->tunnel.tun_id);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void port_flow_tunnel_destroy(portid_t port_id, uint32_t tunnel_id)
|
||||
{
|
||||
struct rte_port *port = &ports[port_id];
|
||||
struct port_flow_tunnel *flt;
|
||||
|
||||
LIST_FOREACH(flt, &port->flow_tunnel_list, chain) {
|
||||
if (flt->id == tunnel_id)
|
||||
break;
|
||||
}
|
||||
if (flt) {
|
||||
LIST_REMOVE(flt, chain);
|
||||
free(flt);
|
||||
printf("port %u: flow tunnel #%u destroyed\n",
|
||||
port_id, tunnel_id);
|
||||
}
|
||||
}
|
||||
|
||||
void port_flow_tunnel_create(portid_t port_id, const struct tunnel_ops *ops)
|
||||
{
|
||||
struct rte_port *port = &ports[port_id];
|
||||
enum rte_flow_item_type type;
|
||||
struct port_flow_tunnel *flt;
|
||||
|
||||
if (!strcmp(ops->type, "vxlan"))
|
||||
type = RTE_FLOW_ITEM_TYPE_VXLAN;
|
||||
else {
|
||||
printf("cannot offload \"%s\" tunnel type\n", ops->type);
|
||||
return;
|
||||
}
|
||||
LIST_FOREACH(flt, &port->flow_tunnel_list, chain) {
|
||||
if (flt->tunnel.type == type)
|
||||
break;
|
||||
}
|
||||
if (!flt) {
|
||||
flt = calloc(1, sizeof(*flt));
|
||||
if (!flt) {
|
||||
printf("failed to allocate port flt object\n");
|
||||
return;
|
||||
}
|
||||
flt->tunnel.type = type;
|
||||
flt->id = LIST_EMPTY(&port->flow_tunnel_list) ? 1 :
|
||||
LIST_FIRST(&port->flow_tunnel_list)->id + 1;
|
||||
LIST_INSERT_HEAD(&port->flow_tunnel_list, flt, chain);
|
||||
}
|
||||
printf("port %d: flow tunnel #%u type %s\n",
|
||||
port_id, flt->id, ops->type);
|
||||
}
|
||||
|
||||
/** Generate a port_flow entry from attributes/pattern/actions. */
|
||||
static struct port_flow *
|
||||
port_flow_new(const struct rte_flow_attr *attr,
|
||||
@ -1860,20 +1969,137 @@ port_shared_action_query(portid_t port_id, uint32_t id)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static struct port_flow_tunnel *
|
||||
port_flow_tunnel_offload_cmd_prep(portid_t port_id,
|
||||
const struct rte_flow_item *pattern,
|
||||
const struct rte_flow_action *actions,
|
||||
const struct tunnel_ops *tunnel_ops)
|
||||
{
|
||||
int ret;
|
||||
struct rte_port *port;
|
||||
struct port_flow_tunnel *pft;
|
||||
struct rte_flow_error error;
|
||||
|
||||
port = &ports[port_id];
|
||||
pft = port_flow_locate_tunnel_id(port, tunnel_ops->id);
|
||||
if (!pft) {
|
||||
printf("failed to locate port flow tunnel #%u\n",
|
||||
tunnel_ops->id);
|
||||
return NULL;
|
||||
}
|
||||
if (tunnel_ops->actions) {
|
||||
uint32_t num_actions;
|
||||
const struct rte_flow_action *aptr;
|
||||
|
||||
ret = rte_flow_tunnel_decap_set(port_id, &pft->tunnel,
|
||||
&pft->pmd_actions,
|
||||
&pft->num_pmd_actions,
|
||||
&error);
|
||||
if (ret) {
|
||||
port_flow_complain(&error);
|
||||
return NULL;
|
||||
}
|
||||
for (aptr = actions, num_actions = 1;
|
||||
aptr->type != RTE_FLOW_ACTION_TYPE_END;
|
||||
aptr++, num_actions++);
|
||||
pft->actions = malloc(
|
||||
(num_actions + pft->num_pmd_actions) *
|
||||
sizeof(actions[0]));
|
||||
if (!pft->actions) {
|
||||
rte_flow_tunnel_action_decap_release(
|
||||
port_id, pft->actions,
|
||||
pft->num_pmd_actions, &error);
|
||||
return NULL;
|
||||
}
|
||||
rte_memcpy(pft->actions, pft->pmd_actions,
|
||||
pft->num_pmd_actions * sizeof(actions[0]));
|
||||
rte_memcpy(pft->actions + pft->num_pmd_actions, actions,
|
||||
num_actions * sizeof(actions[0]));
|
||||
}
|
||||
if (tunnel_ops->items) {
|
||||
uint32_t num_items;
|
||||
const struct rte_flow_item *iptr;
|
||||
|
||||
ret = rte_flow_tunnel_match(port_id, &pft->tunnel,
|
||||
&pft->pmd_items,
|
||||
&pft->num_pmd_items,
|
||||
&error);
|
||||
if (ret) {
|
||||
port_flow_complain(&error);
|
||||
return NULL;
|
||||
}
|
||||
for (iptr = pattern, num_items = 1;
|
||||
iptr->type != RTE_FLOW_ITEM_TYPE_END;
|
||||
iptr++, num_items++);
|
||||
pft->items = malloc((num_items + pft->num_pmd_items) *
|
||||
sizeof(pattern[0]));
|
||||
if (!pft->items) {
|
||||
rte_flow_tunnel_item_release(
|
||||
port_id, pft->pmd_items,
|
||||
pft->num_pmd_items, &error);
|
||||
return NULL;
|
||||
}
|
||||
rte_memcpy(pft->items, pft->pmd_items,
|
||||
pft->num_pmd_items * sizeof(pattern[0]));
|
||||
rte_memcpy(pft->items + pft->num_pmd_items, pattern,
|
||||
num_items * sizeof(pattern[0]));
|
||||
}
|
||||
|
||||
return pft;
|
||||
}
|
||||
|
||||
static void
|
||||
port_flow_tunnel_offload_cmd_release(portid_t port_id,
|
||||
const struct tunnel_ops *tunnel_ops,
|
||||
struct port_flow_tunnel *pft)
|
||||
{
|
||||
struct rte_flow_error error;
|
||||
|
||||
if (tunnel_ops->actions) {
|
||||
free(pft->actions);
|
||||
rte_flow_tunnel_action_decap_release(
|
||||
port_id, pft->pmd_actions,
|
||||
pft->num_pmd_actions, &error);
|
||||
pft->actions = NULL;
|
||||
pft->pmd_actions = NULL;
|
||||
}
|
||||
if (tunnel_ops->items) {
|
||||
free(pft->items);
|
||||
rte_flow_tunnel_item_release(port_id, pft->pmd_items,
|
||||
pft->num_pmd_items,
|
||||
&error);
|
||||
pft->items = NULL;
|
||||
pft->pmd_items = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Validate flow rule. */
|
||||
int
|
||||
port_flow_validate(portid_t port_id,
|
||||
const struct rte_flow_attr *attr,
|
||||
const struct rte_flow_item *pattern,
|
||||
const struct rte_flow_action *actions)
|
||||
const struct rte_flow_action *actions,
|
||||
const struct tunnel_ops *tunnel_ops)
|
||||
{
|
||||
struct rte_flow_error error;
|
||||
struct port_flow_tunnel *pft = NULL;
|
||||
|
||||
/* Poisoning to make sure PMDs update it in case of error. */
|
||||
memset(&error, 0x11, sizeof(error));
|
||||
if (tunnel_ops->enabled) {
|
||||
pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern,
|
||||
actions, tunnel_ops);
|
||||
if (!pft)
|
||||
return -ENOENT;
|
||||
if (pft->items)
|
||||
pattern = pft->items;
|
||||
if (pft->actions)
|
||||
actions = pft->actions;
|
||||
}
|
||||
if (rte_flow_validate(port_id, attr, pattern, actions, &error))
|
||||
return port_flow_complain(&error);
|
||||
if (tunnel_ops->enabled)
|
||||
port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft);
|
||||
printf("Flow rule validated\n");
|
||||
return 0;
|
||||
}
|
||||
@ -1903,13 +2129,15 @@ int
|
||||
port_flow_create(portid_t port_id,
|
||||
const struct rte_flow_attr *attr,
|
||||
const struct rte_flow_item *pattern,
|
||||
const struct rte_flow_action *actions)
|
||||
const struct rte_flow_action *actions,
|
||||
const struct tunnel_ops *tunnel_ops)
|
||||
{
|
||||
struct rte_flow *flow;
|
||||
struct rte_port *port;
|
||||
struct port_flow *pf;
|
||||
uint32_t id = 0;
|
||||
struct rte_flow_error error;
|
||||
struct port_flow_tunnel *pft = NULL;
|
||||
|
||||
port = &ports[port_id];
|
||||
if (port->flow_list) {
|
||||
@ -1920,6 +2148,16 @@ port_flow_create(portid_t port_id,
|
||||
}
|
||||
id = port->flow_list->id + 1;
|
||||
}
|
||||
if (tunnel_ops->enabled) {
|
||||
pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern,
|
||||
actions, tunnel_ops);
|
||||
if (!pft)
|
||||
return -ENOENT;
|
||||
if (pft->items)
|
||||
pattern = pft->items;
|
||||
if (pft->actions)
|
||||
actions = pft->actions;
|
||||
}
|
||||
pf = port_flow_new(attr, pattern, actions, &error);
|
||||
if (!pf)
|
||||
return port_flow_complain(&error);
|
||||
@ -1935,6 +2173,8 @@ port_flow_create(portid_t port_id,
|
||||
pf->id = id;
|
||||
pf->flow = flow;
|
||||
port->flow_list = pf;
|
||||
if (tunnel_ops->enabled)
|
||||
port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft);
|
||||
printf("Flow rule #%u created\n", pf->id);
|
||||
return 0;
|
||||
}
|
||||
@ -2247,7 +2487,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group)
|
||||
pf->rule.attr->egress ? 'e' : '-',
|
||||
pf->rule.attr->transfer ? 't' : '-');
|
||||
while (item->type != RTE_FLOW_ITEM_TYPE_END) {
|
||||
if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR,
|
||||
if ((uint32_t)item->type > INT_MAX)
|
||||
name = "PMD_INTERNAL";
|
||||
else if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR,
|
||||
&name, sizeof(name),
|
||||
(void *)(uintptr_t)item->type,
|
||||
NULL) <= 0)
|
||||
@ -2258,7 +2500,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group)
|
||||
}
|
||||
printf("=>");
|
||||
while (action->type != RTE_FLOW_ACTION_TYPE_END) {
|
||||
if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,
|
||||
if ((uint32_t)action->type > INT_MAX)
|
||||
name = "PMD_INTERNAL";
|
||||
else if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,
|
||||
&name, sizeof(name),
|
||||
(void *)(uintptr_t)action->type,
|
||||
NULL) <= 0)
|
||||
|
@ -3684,6 +3684,8 @@ init_port_dcb_config(portid_t pid,
|
||||
static void
|
||||
init_port(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Configuration of Ethernet ports. */
|
||||
ports = rte_zmalloc("testpmd: ports",
|
||||
sizeof(struct rte_port) * RTE_MAX_ETHPORTS,
|
||||
@ -3693,7 +3695,8 @@ init_port(void)
|
||||
"rte_zmalloc(%d struct rte_port) failed\n",
|
||||
RTE_MAX_ETHPORTS);
|
||||
}
|
||||
|
||||
for (i = 0; i < RTE_MAX_ETHPORTS; i++)
|
||||
LIST_INIT(&ports[i].flow_tunnel_list);
|
||||
/* Initialize ports NUMA structures */
|
||||
memset(port_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
|
||||
memset(rxring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <rte_gro.h>
|
||||
#include <rte_gso.h>
|
||||
#include <cmdline.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#define RTE_PORT_ALL (~(portid_t)0x0)
|
||||
|
||||
@ -150,6 +151,26 @@ struct port_shared_action {
|
||||
struct rte_flow_shared_action *action; /**< Shared action handle. */
|
||||
};
|
||||
|
||||
struct port_flow_tunnel {
|
||||
LIST_ENTRY(port_flow_tunnel) chain;
|
||||
struct rte_flow_action *pmd_actions;
|
||||
struct rte_flow_item *pmd_items;
|
||||
uint32_t id;
|
||||
uint32_t num_pmd_actions;
|
||||
uint32_t num_pmd_items;
|
||||
struct rte_flow_tunnel tunnel;
|
||||
struct rte_flow_action *actions;
|
||||
struct rte_flow_item *items;
|
||||
};
|
||||
|
||||
struct tunnel_ops {
|
||||
uint32_t id;
|
||||
char type[16];
|
||||
uint32_t enabled:1;
|
||||
uint32_t actions:1;
|
||||
uint32_t items:1;
|
||||
};
|
||||
|
||||
/**
|
||||
* The data structure associated with each port.
|
||||
*/
|
||||
@ -182,6 +203,7 @@ struct rte_port {
|
||||
struct port_flow *flow_list; /**< Associated flows. */
|
||||
struct port_shared_action *actions_list;
|
||||
/**< Associated shared actions. */
|
||||
LIST_HEAD(, port_flow_tunnel) flow_tunnel_list;
|
||||
const struct rte_eth_rxtx_callback *rx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1];
|
||||
const struct rte_eth_rxtx_callback *tx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1];
|
||||
/**< metadata value to insert in Tx packets. */
|
||||
@ -773,11 +795,13 @@ int port_shared_action_update(portid_t port_id, uint32_t id,
|
||||
int port_flow_validate(portid_t port_id,
|
||||
const struct rte_flow_attr *attr,
|
||||
const struct rte_flow_item *pattern,
|
||||
const struct rte_flow_action *actions);
|
||||
const struct rte_flow_action *actions,
|
||||
const struct tunnel_ops *tunnel_ops);
|
||||
int port_flow_create(portid_t port_id,
|
||||
const struct rte_flow_attr *attr,
|
||||
const struct rte_flow_item *pattern,
|
||||
const struct rte_flow_action *actions);
|
||||
const struct rte_flow_action *actions,
|
||||
const struct tunnel_ops *tunnel_ops);
|
||||
int port_shared_action_query(portid_t port_id, uint32_t id);
|
||||
void update_age_action_context(const struct rte_flow_action *actions,
|
||||
struct port_flow *pf);
|
||||
@ -788,6 +812,12 @@ int port_flow_query(portid_t port_id, uint32_t rule,
|
||||
const struct rte_flow_action *action);
|
||||
void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group);
|
||||
void port_flow_aged(portid_t port_id, uint8_t destroy);
|
||||
const char *port_flow_tunnel_type(struct rte_flow_tunnel *tunnel);
|
||||
struct port_flow_tunnel *
|
||||
port_flow_locate_tunnel(uint16_t port_id, struct rte_flow_tunnel *tun);
|
||||
void port_flow_tunnel_list(portid_t port_id);
|
||||
void port_flow_tunnel_destroy(portid_t port_id, uint32_t tunnel_id);
|
||||
void port_flow_tunnel_create(portid_t port_id, const struct tunnel_ops *ops);
|
||||
int port_flow_isolate(portid_t port_id, int set);
|
||||
|
||||
void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id);
|
||||
|
@ -48,18 +48,49 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
|
||||
is_rx ? "received" : "sent",
|
||||
(unsigned int) nb_pkts);
|
||||
for (i = 0; i < nb_pkts; i++) {
|
||||
int ret;
|
||||
struct rte_flow_error error;
|
||||
struct rte_flow_restore_info info = { 0, };
|
||||
|
||||
mb = pkts[i];
|
||||
eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
|
||||
eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
|
||||
ol_flags = mb->ol_flags;
|
||||
packet_type = mb->packet_type;
|
||||
is_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);
|
||||
ret = rte_flow_get_restore_info(port_id, mb, &info, &error);
|
||||
if (!ret) {
|
||||
printf("restore info:");
|
||||
if (info.flags & RTE_FLOW_RESTORE_INFO_TUNNEL) {
|
||||
struct port_flow_tunnel *port_tunnel;
|
||||
|
||||
port_tunnel = port_flow_locate_tunnel
|
||||
(port_id, &info.tunnel);
|
||||
printf(" - tunnel");
|
||||
if (port_tunnel)
|
||||
printf(" #%u", port_tunnel->id);
|
||||
else
|
||||
printf(" %s", "-none-");
|
||||
printf(" type %s",
|
||||
port_flow_tunnel_type(&info.tunnel));
|
||||
} else {
|
||||
printf(" - no tunnel info");
|
||||
}
|
||||
if (info.flags & RTE_FLOW_RESTORE_INFO_ENCAPSULATED)
|
||||
printf(" - outer header present");
|
||||
else
|
||||
printf(" - no outer header");
|
||||
if (info.flags & RTE_FLOW_RESTORE_INFO_GROUP_ID)
|
||||
printf(" - miss group %u", info.group_id);
|
||||
else
|
||||
printf(" - no miss group");
|
||||
printf("\n");
|
||||
}
|
||||
print_ether_addr(" src=", ð_hdr->s_addr);
|
||||
print_ether_addr(" - dst=", ð_hdr->d_addr);
|
||||
printf(" - type=0x%04x - length=%u - nb_segs=%d",
|
||||
eth_type, (unsigned int) mb->pkt_len,
|
||||
(int)mb->nb_segs);
|
||||
ol_flags = mb->ol_flags;
|
||||
if (ol_flags & PKT_RX_RSS_HASH) {
|
||||
printf(" - RSS hash=0x%x", (unsigned int) mb->hash.rss);
|
||||
printf(" - RSS queue=0x%x", (unsigned int) queue);
|
||||
|
@ -3749,6 +3749,45 @@ following sections.
|
||||
|
||||
flow aged {port_id} [destroy]
|
||||
|
||||
- Tunnel offload - create a tunnel stub::
|
||||
|
||||
flow tunnel create {port_id} type {tunnel_type}
|
||||
|
||||
- Tunnel offload - destroy a tunnel stub::
|
||||
|
||||
flow tunnel destroy {port_id} id {tunnel_id}
|
||||
|
||||
- Tunnel offload - list port tunnel stubs::
|
||||
|
||||
flow tunnel list {port_id}
|
||||
|
||||
Creating a tunnel stub for offload
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``flow tunnel create`` setup a tunnel stub for tunnel offload flow rules::
|
||||
|
||||
flow tunnel create {port_id} type {tunnel_type}
|
||||
|
||||
If successful, it will return a tunnel stub ID usable with other commands::
|
||||
|
||||
port [...]: flow tunnel #[...] type [...]
|
||||
|
||||
Tunnel stub ID is relative to a port.
|
||||
|
||||
Destroying tunnel offload stub
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``flow tunnel destroy`` destroy port tunnel stub::
|
||||
|
||||
flow tunnel destroy {port_id} id {tunnel_id}
|
||||
|
||||
Listing tunnel offload stubs
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``flow tunnel list`` list port tunnel offload stubs::
|
||||
|
||||
flow tunnel list {port_id}
|
||||
|
||||
Validating flow rules
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -3795,6 +3834,7 @@ to ``rte_flow_create()``::
|
||||
|
||||
flow create {port_id}
|
||||
[group {group_id}] [priority {level}] [ingress] [egress] [transfer]
|
||||
[tunnel_set {tunnel_id}] [tunnel_match {tunnel_id}]
|
||||
pattern {item} [/ {item} [...]] / end
|
||||
actions {action} [/ {action} [...]] / end
|
||||
|
||||
@ -3809,6 +3849,7 @@ Otherwise it will show an error message of the form::
|
||||
Parameters describe in the following order:
|
||||
|
||||
- Attributes (*group*, *priority*, *ingress*, *egress*, *transfer* tokens).
|
||||
- Tunnel offload specification (tunnel_set, tunnel_match)
|
||||
- A matching pattern, starting with the *pattern* token and terminated by an
|
||||
*end* pattern item.
|
||||
- Actions, starting with the *actions* token and terminated by an *end*
|
||||
@ -3852,6 +3893,14 @@ Most rules affect RX therefore contain the ``ingress`` token::
|
||||
|
||||
testpmd> flow create 0 ingress pattern [...]
|
||||
|
||||
Tunnel offload
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Indicate tunnel offload rule type
|
||||
|
||||
- ``tunnel_set {tunnel_id}``: mark rule as tunnel offload decap_set type.
|
||||
- ``tunnel_match {tunnel_id}``: mark rule as tunel offload match type.
|
||||
|
||||
Matching pattern
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user