Skip to content

Commit

Permalink
ovs-tc: allow offloading of ingress mirred TC actions to datapath
Browse files Browse the repository at this point in the history
The TC datapath only permits the offload of mirred actions if they are
egress. To offload TC actions that output to OvS internal ports, ingress
mirred actions are required. At the TC layer, an ingress mirred action
passes the packet back into the network stack as if it came in the action
port rather than attempting to egress the port.

Update OvS-TC offloads to support ingress mirred actions. To ensure
packets that match these rules are properly passed into the network stack,
add a TC skbedit action along with ingress mirred that sets the pkt_type
to PACKET_HOST. This mirrors the functionality of the OvS internal port
kernel module.

Signed-off-by: John Hurley <[email protected]>
Reviewed-by: Roi Dayan <[email protected]>
Signed-off-by: Simon Horman <[email protected]>
  • Loading branch information
jahurley authored and shorman-netronome committed Apr 9, 2019
1 parent 7808b2b commit 4aa2dc0
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 11 deletions.
15 changes: 12 additions & 3 deletions lib/netdev-tc-offloads.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

/*
* Copyright (c) 2016 Mellanox Technologies, Ltd.
*
Expand Down Expand Up @@ -52,6 +53,12 @@ struct netlink_field {
int size;
};

static bool
is_internal_port(const char *type)
{
return !strcmp(type, "internal");
}

static struct netlink_field set_flower_map[][4] = {
[OVS_KEY_ATTR_IPV4] = {
{ offsetof(struct ovs_key_ipv4, ipv4_src),
Expand Down Expand Up @@ -682,8 +689,9 @@ parse_tc_flower_to_match(struct tc_flower *flower,
}
break;
case TC_ACT_OUTPUT: {
if (action->ifindex_out) {
outport = netdev_ifindex_to_odp_port(action->ifindex_out);
if (action->out.ifindex_out) {
outport =
netdev_ifindex_to_odp_port(action->out.ifindex_out);
if (!outport) {
return ENOENT;
}
Expand Down Expand Up @@ -1286,7 +1294,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
odp_port_t port = nl_attr_get_odp_port(nla);
struct netdev *outdev = netdev_ports_get(port, info->dpif_class);

action->ifindex_out = netdev_get_ifindex(outdev);
action->out.ifindex_out = netdev_get_ifindex(outdev);
action->out.ingress = is_internal_port(netdev_get_type(outdev));
action->type = TC_ACT_OUTPUT;
flower.action_count++;
netdev_close(outdev);
Expand Down
61 changes: 54 additions & 7 deletions lib/tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@

#include <errno.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/rtnetlink.h>
#include <linux/tc_act/tc_csum.h>
#include <linux/tc_act/tc_gact.h>
#include <linux/tc_act/tc_mirred.h>
#include <linux/tc_act/tc_pedit.h>
#include <linux/tc_act/tc_skbedit.h>
#include <linux/tc_act/tc_tunnel_key.h>
#include <linux/tc_act/tc_vlan.h>
#include <linux/gen_stats.h>
Expand Down Expand Up @@ -1151,14 +1153,20 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower)
mirred_parms = mirred_attrs[TCA_MIRRED_PARMS];
m = nl_attr_get_unspec(mirred_parms, sizeof *m);

if (m->eaction != TCA_EGRESS_REDIR && m->eaction != TCA_EGRESS_MIRROR) {
if (m->eaction != TCA_EGRESS_REDIR && m->eaction != TCA_EGRESS_MIRROR &&
m->eaction != TCA_INGRESS_REDIR && m->eaction != TCA_INGRESS_MIRROR) {
VLOG_ERR_RL(&error_rl, "unknown mirred action: %d, %d, %d",
m->action, m->eaction, m->ifindex);
return EINVAL;
}

action = &flower->actions[flower->action_count++];
action->ifindex_out = m->ifindex;
action->out.ifindex_out = m->ifindex;
if (m->eaction == TCA_INGRESS_REDIR || m->eaction == TCA_INGRESS_MIRROR) {
action->out.ingress = true;
} else {
action->out.ingress = false;
}
action->type = TC_ACT_OUTPUT;

mirred_tm = mirred_attrs[TCA_MIRRED_TM];
Expand Down Expand Up @@ -1301,6 +1309,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)
err = nl_parse_act_pedit(act_options, flower);
} else if (!strcmp(act_kind, "csum")) {
nl_parse_act_csum(act_options, flower);
} else if (!strcmp(act_kind, "skbedit")) {
/* Added for TC rule only (not in OvS rule) so ignore. */
} else {
VLOG_ERR_RL(&error_rl, "unknown tc action kind: %s", act_kind);
err = EINVAL;
Expand Down Expand Up @@ -1728,6 +1738,22 @@ nl_msg_put_act_drop(struct ofpbuf *request)
nl_msg_end_nested(request, offset);
}

static void
nl_msg_put_act_skbedit_to_host(struct ofpbuf *request)
{
size_t offset;

nl_msg_put_string(request, TCA_ACT_KIND, "skbedit");
offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
{
struct tc_skbedit s = { .action = TC_ACT_PIPE };

nl_msg_put_unspec(request, TCA_SKBEDIT_PARMS, &s, sizeof s);
nl_msg_put_be16(request, TCA_SKBEDIT_PTYPE, PACKET_HOST);
}
nl_msg_end_nested(request, offset);
}

static void
nl_msg_put_act_mirred(struct ofpbuf *request, int ifindex, int action,
int eaction)
Expand Down Expand Up @@ -1916,6 +1942,7 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
uint16_t act_index = 1;
struct tc_action *action;
int i, ifindex = 0;
bool ingress;

offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);
{
Expand Down Expand Up @@ -1977,19 +2004,39 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
}
break;
case TC_ACT_OUTPUT: {
ifindex = action->ifindex_out;
ingress = action->out.ingress;
ifindex = action->out.ifindex_out;
if (ifindex < 1) {
VLOG_ERR_RL(&error_rl, "%s: invalid ifindex: %d, type: %d",
__func__, ifindex, action->type);
return EINVAL;
}

if (ingress) {
/* If redirecting to ingress (internal port) ensure
* pkt_type on skb is set to PACKET_HOST. */
act_offset = nl_msg_start_nested(request, act_index++);
nl_msg_put_act_skbedit_to_host(request);
nl_msg_end_nested(request, act_offset);
}

act_offset = nl_msg_start_nested(request, act_index++);
if (i == flower->action_count - 1) {
nl_msg_put_act_mirred(request, ifindex, TC_ACT_STOLEN,
TCA_EGRESS_REDIR);
if (ingress) {
nl_msg_put_act_mirred(request, ifindex, TC_ACT_STOLEN,
TCA_INGRESS_REDIR);
} else {
nl_msg_put_act_mirred(request, ifindex, TC_ACT_STOLEN,
TCA_EGRESS_REDIR);
}
} else {
nl_msg_put_act_mirred(request, ifindex, TC_ACT_PIPE,
TCA_EGRESS_MIRROR);
if (ingress) {
nl_msg_put_act_mirred(request, ifindex, TC_ACT_PIPE,
TCA_INGRESS_MIRROR);
} else {
nl_msg_put_act_mirred(request, ifindex, TC_ACT_PIPE,
TCA_EGRESS_MIRROR);
}
}
nl_msg_put_act_cookie(request, &flower->act_cookie);
nl_msg_end_nested(request, act_offset);
Expand Down
5 changes: 4 additions & 1 deletion lib/tc.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,10 @@ enum tc_action_type {

struct tc_action {
union {
int ifindex_out;
struct {
int ifindex_out;
bool ingress;
} out;

struct {
ovs_be16 vlan_push_tpid;
Expand Down

0 comments on commit 4aa2dc0

Please sign in to comment.