From: Ophir Munk <[email protected]> For virtual port (as "vxlan"), HW rules match tunnel properties (outer header) and inner packet fields, and with a decap action. The rules are placed on all uplinks as they are the potential for the origin of the traffic.
Co-authored-by: Eli Britstein <[email protected]> Signed-off-by: Ophir Munk <[email protected]> Reviewed-by: Roni Bar Yanai <[email protected]> Signed-off-by: Eli Britstein <[email protected]> --- Documentation/howto/dpdk.rst | 1 + NEWS | 1 + lib/netdev-offload-dpdk.c | 122 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 110 insertions(+), 14 deletions(-) diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst index ea00b4a94..c12941cb8 100644 --- a/Documentation/howto/dpdk.rst +++ b/Documentation/howto/dpdk.rst @@ -397,6 +397,7 @@ Supported actions for hardware offload are: - Modification of TCP/UDP (mod_tp_src/mod_tp_dst). - Clone/output (tnl_push and output) for encapsulating over a tunnel. - Tunnel pop, for changing from PF port to vport. +- Offloading VXLAN vport. Further Reading --------------- diff --git a/NEWS b/NEWS index d7f9a1e18..24366369e 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,7 @@ Post-v2.12.0 TCP/UDP ports and tunnel push-output/pop actions (experimental). * Add experimental support for TSO. * Add hardware offload support for matching IPv6 protocol. + * Add hardware offload support VXLAN vports. - RSTP: * The rstp_statistics column in Port table will only be updated every stats-update-interval configured in Open_vSwitch table. diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c index 5e8ed33f7..2fd840ed4 100644 --- a/lib/netdev-offload-dpdk.c +++ b/lib/netdev-offload-dpdk.c @@ -59,6 +59,7 @@ static struct cmap ufid_to_rte_flow = CMAP_INITIALIZER; struct act_resources { uint32_t next_table_id; + uint32_t self_table_id; uint32_t flow_miss_ctx_id; }; @@ -436,6 +437,7 @@ find_flow_miss_ctx(int flow_ctx_id, struct flow_miss_ctx *ctx) static void put_action_resources(struct act_resources *act_resources) { + put_table_id(act_resources->self_table_id); put_table_id(act_resources->next_table_id); put_flow_miss_ctx_id(act_resources->flow_miss_ctx_id); } @@ -819,6 +821,8 @@ dump_flow_action(struct ds *s, const struct rte_flow_action *actions) if (jump) { ds_put_format(s, " Jump: group=%"PRIu32"\n", jump->group); } + } else if (actions->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP) { + ds_put_cstr(s, "rte flow vxlan-decap action\n"); } else { ds_put_format(s, "unknown rte flow action (%d)\n", actions->type); } @@ -1093,7 +1097,8 @@ parse_vxlan_match(struct flow_patterns *patterns, static int parse_flow_match(struct netdev *netdev, struct flow_patterns *patterns, - struct match *match) + struct match *match, + struct act_resources *act_resources) { uint8_t *next_proto_mask = NULL; struct flow *consumed_masks; @@ -1108,6 +1113,14 @@ parse_flow_match(struct netdev *netdev, goto out; } + if (netdev_vport_is_vport_class(netdev->netdev_class)) { + ret = get_table_id(match->flow.in_port.odp_port, + &act_resources->self_table_id); + if (ret) { + goto out; + } + } + memset(&consumed_masks->in_port, 0, sizeof consumed_masks->in_port); if (match->flow.recirc_id != 0) { ret = -1; @@ -1764,6 +1777,12 @@ add_tnl_pop_action(struct flow_actions *actions, return 0; } +static void +add_vxlan_decap_action(struct flow_actions *actions) +{ + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_VXLAN_DECAP, NULL); +} + static int parse_flow_actions(struct netdev *netdev, struct flow_actions *actions, @@ -1774,6 +1793,9 @@ parse_flow_actions(struct netdev *netdev, struct nlattr *nla; size_t left; + if (!strcmp(netdev_get_type(netdev), "vxlan")) { + add_vxlan_decap_action(actions); + } add_count_action(actions); NL_ATTR_FOR_EACH_UNSAFE (nla, left, nl_actions, nl_actions_len) { if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) { @@ -1781,6 +1803,8 @@ parse_flow_actions(struct netdev *netdev, return -1; } } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_DROP) { + free_flow_actions(actions); + add_count_action(actions); add_flow_action(actions, RTE_FLOW_ACTION_TYPE_DROP, NULL); } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET || nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) { @@ -1819,16 +1843,67 @@ parse_flow_actions(struct netdev *netdev, return 0; } +static int +netdev_offload_dpdk_create_tnl_flows(struct netdev *netdev, + struct flow_patterns *patterns, + struct flow_actions *actions, + const ovs_u128 *ufid, + struct act_resources *act_resources, + struct flows_handle *flows) +{ + struct rte_flow_attr flow_attr = { .ingress = 1, .transfer = 1 }; + struct flow_item flow_item = { .devargs = NULL }; + struct netdev_flow_dump **netdev_dumps; + struct rte_flow_error error; + int num_ports = 0; + int ret; + int i; + + netdev_dumps = netdev_ports_flow_dump_create(netdev->dpif_type, + &num_ports); + flow_attr.group = act_resources->self_table_id; + for (i = 0; i < num_ports; i++) { + if (!netdev_dpdk_is_uplink_port(netdev_dumps[i]->netdev)) { + continue; + } + ret = netdev_offload_dpdk_flow_create(netdev_dumps[i]->netdev, + &flow_attr, patterns->items, + actions->actions, &error, + &flow_item); + if (ret) { + continue; + } + flow_item.devargs = + netdev_dpdk_get_port_devargs(netdev_dumps[i]->netdev); + VLOG_DBG_RL(&rl, "%s: installed flow %p by ufid "UUID_FMT"\n", + netdev_get_name(netdev), flow_item.rte_flow, + UUID_ARGS((struct uuid *)ufid)); + add_flow_item(flows, &flow_item); + } + for (i = 0; i < num_ports; i++) { + int err = netdev_flow_dump_destroy(netdev_dumps[i]); + + if (err != 0 && err != EOPNOTSUPP) { + VLOG_ERR("failed dumping netdev: %s", ovs_strerror(err)); + } + } + + ret = flows->cnt > 0 ? 0 : -1; + return ret; +} + static int netdev_offload_dpdk_actions(struct netdev *netdev, struct flow_patterns *patterns, struct nlattr *nl_actions, size_t actions_len, + const ovs_u128 *ufid, struct act_resources *act_resources, - struct flow_item *fi) + struct flows_handle *flows) { const struct rte_flow_attr flow_attr = { .ingress = 1, .transfer = 1 }; struct flow_actions actions = { .actions = NULL, .cnt = 0 }; + struct flow_item flow_item = { .devargs = NULL }; struct rte_flow_error error; int ret; @@ -1837,8 +1912,22 @@ netdev_offload_dpdk_actions(struct netdev *netdev, if (ret) { goto out; } - ret = netdev_offload_dpdk_flow_create(netdev, &flow_attr, patterns->items, - actions.actions, &error, fi); + if (netdev_vport_is_vport_class(netdev->netdev_class)) { + ret = netdev_offload_dpdk_create_tnl_flows(netdev, patterns, &actions, + ufid, act_resources, flows); + } else { + ret = netdev_offload_dpdk_flow_create(netdev, &flow_attr, + patterns->items, + actions.actions, &error, + &flow_item); + if (ret) { + goto out; + } + VLOG_DBG_RL(&rl, "%s: installed flow %p by ufid "UUID_FMT"\n", + netdev_get_name(netdev), flow_item.rte_flow, + UUID_ARGS((struct uuid *)ufid)); + add_flow_item(flows, &flow_item); + } out: free_flow_actions(&actions); return ret; @@ -1857,36 +1946,41 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, struct flow_item flow_item = { .devargs = NULL }; struct act_resources act_resources; bool actions_offloaded = true; - int ret = 0; + int ret; memset(&act_resources, 0, sizeof act_resources); - ret = parse_flow_match(netdev, &patterns, match); + ret = parse_flow_match(netdev, &patterns, match, &act_resources); if (ret) { goto out; } ret = netdev_offload_dpdk_actions(netdev, &patterns, nl_actions, - actions_len, &act_resources, &flow_item); + actions_len, ufid, &act_resources, + &flows); if (ret) { /* If we failed to offload the rule actions fallback to MARK+RSS * actions. */ - flow_item.rte_flow = netdev_offload_dpdk_mark_rss(&patterns, netdev, - info->flow_mark); - ret = flow_item.rte_flow ? 0 : -1; actions_offloaded = false; + flow_item.rte_flow = act_resources.self_table_id == 0 ? + netdev_offload_dpdk_mark_rss(&patterns, netdev, info->flow_mark) : + NULL; + ret = flow_item.rte_flow ? 0 : -1; + if (ret) { + goto out; + } + VLOG_DBG_RL(&rl, "%s: installed flow %p by ufid "UUID_FMT"\n", + netdev_get_name(netdev), flow_item.rte_flow, + UUID_ARGS((struct uuid *)ufid)); + add_flow_item(&flows, &flow_item); } if (ret) { goto out; } - add_flow_item(&flows, &flow_item); ufid_to_rte_flow_associate(ufid, &flows, actions_offloaded, &act_resources); - VLOG_DBG("%s: installed flow %p by ufid "UUID_FMT"\n", - netdev_get_name(netdev), flow_item.rte_flow, - UUID_ARGS((struct uuid *)ufid)); out: if (ret) { -- 2.14.5 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
