+
/*
* Copyright (c) 2016 Mellanox Technologies, Ltd.
*
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),
}
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;
}
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);
#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>
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];
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;
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)
uint16_t act_index = 1;
struct tc_action *action;
int i, ifindex = 0;
+ bool ingress;
offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);
{
}
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);