+ return;
+ } else if (actions->type == RTE_FLOW_ACTION_TYPE_MARK) {
const struct rte_flow_action_mark *mark = actions->conf;
ds_put_cstr(s, "mark ");
@@ -528,6 +553,14 @@ dump_flow_action(struct ds *s, struct ds *s_extra,
ds_put_cstr(s, "vxlan_encap / ");
dump_vxlan_encap(s_extra, items);
ds_put_cstr(s_extra, ";");
+ } else if (actions->type == RTE_FLOW_ACTION_TYPE_JUMP) {
+ const struct rte_flow_action_jump *jump = actions->conf;
+
+ ds_put_cstr(s, "jump ");
+ if (jump) {
+ ds_put_format(s, "group %"PRIu32" ", jump->group);
+ }
+ ds_put_cstr(s, "/ ");
} else {
ds_put_format(s, "unknown rte flow action (%d)\n", actions->type);
}
@@ -537,20 +570,21 @@ static struct ds *
dump_flow(struct ds *s, struct ds *s_extra,
const struct rte_flow_attr *attr,
const struct rte_flow_item *items,
- const struct rte_flow_action *actions)
+ struct flow_actions *flow_actions)
{
+ int i;
+
if (attr) {
- dump_flow_attr(s, attr);
+ dump_flow_attr(s, s_extra, attr, flow_actions);
}
ds_put_cstr(s, "pattern ");
while (items && items->type != RTE_FLOW_ITEM_TYPE_END) {
dump_flow_pattern(s, items++);
}
ds_put_cstr(s, "end actions ");
- while (actions && actions->type != RTE_FLOW_ACTION_TYPE_END) {
- dump_flow_action(s, s_extra, actions++);
+ for (i = 0; i < flow_actions->cnt; i++) {
+ dump_flow_action(s, s_extra, flow_actions, i);
}
- ds_put_cstr(s, "end");
return s;
}
@@ -558,9 +592,10 @@ static struct rte_flow *
netdev_offload_dpdk_flow_create(struct netdev *netdev,
const struct rte_flow_attr *attr,
const struct rte_flow_item *items,
- const struct rte_flow_action *actions,
+ struct flow_actions *flow_actions,
struct rte_flow_error *error)
{
+ const struct rte_flow_action *actions = flow_actions->actions;
struct ds s_extra = DS_EMPTY_INITIALIZER;
struct ds s = DS_EMPTY_INITIALIZER;
struct rte_flow *flow;
@@ -569,7 +604,7 @@ netdev_offload_dpdk_flow_create(struct netdev *netdev,
flow = netdev_dpdk_rte_flow_create(netdev, attr, items, actions, error);
if (flow) {
if (!VLOG_DROP_DBG(&rl)) {
- dump_flow(&s, &s_extra, attr, items, actions);
+ dump_flow(&s, &s_extra, attr, items, flow_actions);
extra_str = ds_cstr(&s_extra);
VLOG_DBG_RL(&rl, "%s: rte_flow 0x%"PRIxPTR" %s flow create %d
%s",
netdev_get_name(netdev), (intptr_t) flow, extra_str,
@@ -584,7 +619,7 @@ netdev_offload_dpdk_flow_create(struct netdev *netdev,
VLOG_RL(&rl, level, "%s: rte_flow creation failed: %d (%s).",
netdev_get_name(netdev), error->type, error->message);
if (!vlog_should_drop(&this_module, level, &rl)) {
- dump_flow(&s, &s_extra, attr, items, actions);
+ dump_flow(&s, &s_extra, attr, items, flow_actions);
extra_str = ds_cstr(&s_extra);
VLOG_RL(&rl, level, "%s: Failed flow: %s flow create %d %s",
netdev_get_name(netdev), extra_str,
@@ -640,6 +675,23 @@ add_flow_action(struct flow_actions *actions, enum
rte_flow_action_type type,
actions->cnt++;
}
+static void
+add_flow_tnl_actions(struct flow_actions *actions,
+ struct netdev *tnl_netdev,
+ struct rte_flow_action *tnl_actions,
+ uint32_t num_of_tnl_actions)
+{
+ int i;
+
+ actions->tnl_netdev = tnl_netdev;
+ actions->tnl_actions_pos = actions->cnt;
+ actions->tnl_actions = tnl_actions;
+ actions->num_of_tnl_actions = num_of_tnl_actions;
+ for (i = 0; i < num_of_tnl_actions; i++) {
+ add_flow_action(actions, tnl_actions[i].type, tnl_actions[i].conf);
+ }
+}
+
static void
free_flow_patterns(struct flow_patterns *patterns)
{
@@ -661,9 +713,23 @@ free_flow_patterns(struct flow_patterns *patterns)
static void
free_flow_actions(struct flow_actions *actions)
{
+ struct rte_flow_error error;
int i;
for (i = 0; i < actions->cnt; i++) {
+ if (actions->num_of_tnl_actions && i == actions->tnl_actions_pos) {
+ if (netdev_dpdk_rte_flow_tunnel_action_decap_release
+ (actions->tnl_netdev, actions->tnl_actions,
+ actions->num_of_tnl_actions, &error)) {
+ VLOG_DBG_RL(&rl, "%s: "
+ "netdev_dpdk_rte_flow_tunnel_action_decap_release "
+ "failed: %d (%s).",
+ netdev_get_name(actions->tnl_netdev),
+ error.type, error.message);
+ }
+ i += actions->num_of_tnl_actions - 1;
+ continue;
+ }
if (actions->actions[i].conf) {
free(CONST_CAST(void *, actions->actions[i].conf));
}
@@ -671,6 +737,7 @@ free_flow_actions(struct flow_actions *actions)
free(actions->actions);
actions->actions = NULL;
actions->cnt = 0;
+ ds_destroy(&actions->s_tnl);
}
static int
@@ -960,7 +1027,7 @@ netdev_offload_dpdk_mark_rss(struct flow_patterns
*patterns,
add_flow_mark_rss_actions(&actions, flow_mark, netdev);
flow = netdev_offload_dpdk_flow_create(netdev, &flow_attr,
patterns->items,
- actions.actions, &error);
+ &actions, &error);
free_flow_actions(&actions);
return flow;
@@ -1307,6 +1374,78 @@ parse_clone_actions(struct netdev *netdev,
return 0;
}
+static void
+add_jump_action(struct flow_actions *actions, uint32_t group)
+{
+ struct rte_flow_action_jump *jump = xzalloc (sizeof *jump);
+
+ jump->group = group;
+ add_flow_action(actions, RTE_FLOW_ACTION_TYPE_JUMP, jump);
+}
+
+static int
+vport_to_rte_tunnel(struct netdev *vport,
+ struct rte_flow_tunnel *tunnel,
+ struct netdev *netdev,
+ struct ds *s_tnl)
+{
+ const struct netdev_tunnel_config *tnl_cfg;
+
+ memset(tunnel, 0, sizeof *tunnel);
+ if (!strcmp(netdev_get_type(vport), "vxlan")) {
+ tunnel->type = RTE_FLOW_ITEM_TYPE_VXLAN;
+ tnl_cfg = netdev_get_tunnel_config(vport);
+ if (!tnl_cfg) {
+ return -1;
+ }
+ tunnel->tp_dst = tnl_cfg->dst_port;
+ if (!VLOG_DROP_DBG(&rl)) {
+ ds_put_format(s_tnl, "flow tunnel create %d type vxlan; ",
+ netdev_dpdk_get_port_id(netdev));
+ }
+ } else {
+ OVS_NOT_REACHED();
+ }
+
+ return 0;
+}
+
+static int
+add_tnl_pop_action(struct netdev *netdev,
+ struct flow_actions *actions,
+ const struct nlattr *nla)
+{
+ struct rte_flow_action *tnl_actions = NULL;
+ uint32_t num_of_tnl_actions = 0;
+ struct rte_flow_tunnel tunnel;
+ struct rte_flow_error error;
+ struct netdev *vport;
+ odp_port_t port;
+ int ret;
+
+ port = nl_attr_get_odp_port(nla);
+ vport = netdev_ports_get(port, netdev->dpif_type);
+ if (vport == NULL) {
+ return -1;
+ }
+ ret = vport_to_rte_tunnel(vport, &tunnel, netdev, &actions->s_tnl);
+ netdev_close(vport);
+ if (ret) {
+ return ret;
+ }
+ ret = netdev_dpdk_rte_flow_tunnel_decap_set(netdev, &tunnel, &tnl_actions,
+ &num_of_tnl_actions, &error);
+ if (ret) {
+ VLOG_DBG_RL(&rl, "%s: netdev_dpdk_rte_flow_tunnel_decap_set failed: "
+ "%d (%s).", netdev_get_name(netdev), error.type,
+ error.message);
+ return ret;
+ }
+ add_flow_tnl_actions(actions, netdev, tnl_actions, num_of_tnl_actions);
+ add_jump_action(actions, 0);