As a general rule, code that requires ALLOW_EXPERIMENTAL_API is not allowed on the main branch.
The exemption was granted to the tunnel offload implementation because it was a large piece of code that is hard to maintain separately and there was a hope that it will become stable in a relatively short amount of time. That was 5 years ago, so clearly that didn't work out. In the current code, even the parts that could be generic are gated by the ALLOW_EXPERIMENTAL_API macro. The reason is the noticeable performance impact packet metadata restoration API has on every packet even when the traffic is not offloaded. There was an attempt to make it faster by providing a dynamic mbuf flag, but checking dynamic flags still causes performance impact due to a series of indirect calls into DPDK per packet. We don't have test coverage for this code on main, we don't even build it in CI on main (and we shouldn't), and there is no much hope for it to become performant enough to become stable within a reasonable time frame. So, it's time to remove this code from main. It can live in the dpdk-latest branch where we have at least some compilation tests for the experimental API. And if someday it becomes stable, we can add it back to main. Though the code would likely need to be re-reviewed as it at least has some style issues. With this code removed, there are no more offload providers that implements post processing and can return EOPNOTSUPP on a per-device basis. However, calling into a separate translation unit, getting RCU-protected offload provider and checking if the method exists is still expensive if done per packet. Simple vhost-to-vhost forwarding test with offload enabled (but not supported, obviously) shows 1-1.5% performance degradation. So, the early check of the 'post_process_api_supported' before calling into dpif_offload module is still needed. Signed-off-by: Ilya Maximets <[email protected]> --- Version 2: - Restored unintentionally removed partial offload code. [Eli] Note: There will be a conflict with the partial offload fix: https://patchwork.ozlabs.org/project/openvswitch/patch/c0fc27e7c946816a3a27a21404aa6d16dcd7e8e2.1783685651.git.echau...@redhat.com/ Depending on which is applied first, there will be either a small rebase of this patch or the partial offload fix will need to be re-targeted for branch-3.7. Either way the removal will remove all the code touched by the fix, so the resulted code will not be affected by the issue. Alternative might be also to drop the fix and apply the removal to 3.7, since the code is experimental anyway and we can technically drop it in a minor release, though it wouldn't be a particularly user-friendly thing to do. Documentation/howto/dpdk.rst | 5 - NEWS | 2 + lib/dpif-offload-dpdk-netdev.c | 663 +-------------------------------- lib/dpif-offload-dpdk.c | 5 +- lib/netdev-dpdk.c | 130 ------- lib/netdev-dpdk.h | 85 ----- 6 files changed, 14 insertions(+), 876 deletions(-) diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst index c4ab0091b..e7f20f8c9 100644 --- a/Documentation/howto/dpdk.rst +++ b/Documentation/howto/dpdk.rst @@ -401,11 +401,6 @@ Supported actions for hardware offload are: - VLAN Push/Pop (push_vlan/pop_vlan). - Modification of IPv6 (set_field:<ADDR>->ipv6_src/ipv6_dst/mod_nw_ttl). - Clone/output (tnl_push/push_vlan/output) for encapsulating over a tunnel. -- Tunnel pop, for packets received on physical ports. - -.. note:: - Tunnel offloads are experimental APIs in DPDK. In order to enable it, - compile with -DALLOW_EXPERIMENTAL_API. Multiprocess ------------ diff --git a/NEWS b/NEWS index 748a294ef..2779632cd 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ Post-v3.7.0 wasting resources on unused devices. This breaks DPDK netdev ports using the "class=eth,mac=" syntax (though it can be restored via the 'dpdk-probe-at-init' config option, see ovs-vswitchd.conf.db(5)). + * Removed support for the experimental offload of the tnl_pop() action + that relied on DPDK's experimental API. * OVS validated with DPDK 25.11.2. - Linux: * For veth interfaces, the interface index of the peer veth device is diff --git a/lib/dpif-offload-dpdk-netdev.c b/lib/dpif-offload-dpdk-netdev.c index efe99065e..3dabdaab4 100644 --- a/lib/dpif-offload-dpdk-netdev.c +++ b/lib/dpif-offload-dpdk-netdev.c @@ -28,7 +28,6 @@ #include "dpif-offload.h" #include "dpif-offload-dpdk-private.h" #include "netdev-provider.h" -#include "netdev-vport.h" #include "odp-util.h" #include "openvswitch/match.h" #include "openvswitch/vlog.h" @@ -533,44 +532,21 @@ struct flow_patterns { int cnt; int current_max; struct netdev *physdev; - /* tnl_pmd_items is the opaque array of items returned by the PMD. */ - struct rte_flow_item *tnl_pmd_items; - uint32_t tnl_pmd_items_cnt; - struct ds s_tnl; }; struct flow_actions { struct rte_flow_action *actions; int cnt; int current_max; - struct netdev *tnl_netdev; - /* tnl_pmd_actions is the opaque array of actions returned by the PMD. */ - struct rte_flow_action *tnl_pmd_actions; - uint32_t tnl_pmd_actions_cnt; - /* tnl_pmd_actions_pos is where the tunnel actions starts within the - * 'actions' field. - */ - int tnl_pmd_actions_pos; - struct ds s_tnl; }; static void -dump_flow_attr(struct ds *s, struct ds *s_extra, - const struct rte_flow_attr *attr, - struct flow_patterns *flow_patterns, - struct flow_actions *flow_actions) +dump_flow_attr(struct ds *s, const struct rte_flow_attr *attr) { - if (flow_actions->tnl_pmd_actions_cnt) { - ds_clone(s_extra, &flow_actions->s_tnl); - } else if (flow_patterns->tnl_pmd_items_cnt) { - ds_clone(s_extra, &flow_patterns->s_tnl); - } - ds_put_format(s, "%s%spriority %"PRIu32" group %"PRIu32" %s%s%s", + ds_put_format(s, "%s%spriority %"PRIu32" group %"PRIu32" %s", attr->ingress ? "ingress " : "", attr->egress ? "egress " : "", attr->priority, attr->group, - attr->transfer ? "transfer " : "", - flow_actions->tnl_pmd_actions_cnt ? "tunnel_set 1 " : "", - flow_patterns->tnl_pmd_items_cnt ? "tunnel_match 1 " : ""); + attr->transfer ? "transfer " : ""); } /* Adds one pattern item 'field' with the 'mask' to dynamic string 's' using @@ -596,9 +572,6 @@ dump_flow_pattern(struct ds *s, if (item->type == RTE_FLOW_ITEM_TYPE_END) { ds_put_cstr(s, "end "); - } else if (flow_patterns->tnl_pmd_items_cnt && - pattern_index < flow_patterns->tnl_pmd_items_cnt) { - return; } else if (item->type == RTE_FLOW_ITEM_TYPE_ETH) { const struct rte_flow_item_eth *eth_spec = item->spec; const struct rte_flow_item_eth *eth_mask = item->mask; @@ -974,12 +947,6 @@ dump_flow_action(struct ds *s, struct ds *s_extra, if (actions->type == RTE_FLOW_ACTION_TYPE_END) { ds_put_cstr(s, "end"); - } else if (flow_actions->tnl_pmd_actions_cnt && - act_index >= flow_actions->tnl_pmd_actions_pos && - act_index < flow_actions->tnl_pmd_actions_pos + - flow_actions->tnl_pmd_actions_cnt) { - /* Opaque PMD tunnel actions are skipped. */ - return; } else if (actions->type == RTE_FLOW_ACTION_TYPE_MARK) { const struct rte_flow_action_mark *mark = actions->conf; @@ -1137,7 +1104,7 @@ dump_flow(struct ds *s, struct ds *s_extra, int i; if (attr) { - dump_flow_attr(s, s_extra, attr, flow_patterns, flow_actions); + dump_flow_attr(s, attr); } ds_put_cstr(s, "pattern "); for (i = 0; i < flow_patterns->cnt; i++) { @@ -1239,62 +1206,12 @@ 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_pmd_actions, - uint32_t tnl_pmd_actions_cnt) -{ - int i; - - actions->tnl_netdev = tnl_netdev; - actions->tnl_pmd_actions_pos = actions->cnt; - actions->tnl_pmd_actions = tnl_pmd_actions; - actions->tnl_pmd_actions_cnt = tnl_pmd_actions_cnt; - for (i = 0; i < tnl_pmd_actions_cnt; i++) { - add_flow_action(actions, tnl_pmd_actions[i].type, - tnl_pmd_actions[i].conf); - } -} - -static void -add_flow_tnl_items(struct flow_patterns *patterns, - struct netdev *physdev, - struct rte_flow_item *tnl_pmd_items, - uint32_t tnl_pmd_items_cnt) -{ - int i; - - patterns->physdev = physdev; - patterns->tnl_pmd_items = tnl_pmd_items; - patterns->tnl_pmd_items_cnt = tnl_pmd_items_cnt; - for (i = 0; i < tnl_pmd_items_cnt; i++) { - add_flow_pattern(patterns, tnl_pmd_items[i].type, - tnl_pmd_items[i].spec, tnl_pmd_items[i].mask, NULL); - } -} - static void free_flow_patterns(struct flow_patterns *patterns) { - struct rte_flow_error error; int i; - if (patterns->tnl_pmd_items) { - struct rte_flow_item *tnl_pmd_items = patterns->tnl_pmd_items; - uint32_t tnl_pmd_items_cnt = patterns->tnl_pmd_items_cnt; - struct netdev *physdev = patterns->physdev; - - if (netdev_dpdk_rte_flow_tunnel_item_release(physdev, tnl_pmd_items, - tnl_pmd_items_cnt, - &error)) { - VLOG_DBG_RL(&rl, "%s: netdev_dpdk_rte_flow_tunnel_item_release " - "failed: %d (%s).", netdev_get_name(physdev), - error.type, error.message); - } - } - - for (i = patterns->tnl_pmd_items_cnt; i < patterns->cnt; i++) { + for (i = 0; i < patterns->cnt; i++) { if (patterns->items[i].spec) { free(CONST_CAST(void *, patterns->items[i].spec)); } @@ -1308,325 +1225,19 @@ free_flow_patterns(struct flow_patterns *patterns) free(patterns->items); patterns->items = NULL; patterns->cnt = 0; - ds_destroy(&patterns->s_tnl); } 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->tnl_pmd_actions_cnt && - i == actions->tnl_pmd_actions_pos) { - if (netdev_dpdk_rte_flow_tunnel_action_decap_release( - actions->tnl_netdev, actions->tnl_pmd_actions, - actions->tnl_pmd_actions_cnt, &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->tnl_pmd_actions_cnt - 1; - continue; - } - if (actions->actions[i].conf) { - free(CONST_CAST(void *, actions->actions[i].conf)); - } + free(CONST_CAST(void *, actions->actions[i].conf)); } free(actions->actions); actions->actions = NULL; actions->cnt = 0; - ds_destroy(&actions->s_tnl); -} - -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); - - tnl_cfg = netdev_get_tunnel_config(vport); - if (!tnl_cfg) { - return -1; - } - - if (!IN6_IS_ADDR_V4MAPPED(&tnl_cfg->ipv6_dst)) { - tunnel->is_ipv6 = true; - } - - if (!strcmp(netdev_get_type(vport), "vxlan")) { - tunnel->type = RTE_FLOW_ITEM_TYPE_VXLAN; - 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 if (!strcmp(netdev_get_type(vport), "gre")) { - tunnel->type = RTE_FLOW_ITEM_TYPE_GRE; - if (!VLOG_DROP_DBG(&rl)) { - ds_put_format(s_tnl, "flow tunnel create %d type gre; ", - netdev_dpdk_get_port_id(netdev)); - } - } else { - VLOG_DBG_RL(&rl, "vport type '%s' is not supported", - netdev_get_type(vport)); - return -1; - } - - return 0; -} - -static int -add_vport_match(struct dpdk_offload *offload, - struct flow_patterns *patterns, - odp_port_t orig_in_port, - struct netdev *tnldev) -{ - struct rte_flow_item *tnl_pmd_items; - struct rte_flow_tunnel tunnel; - struct rte_flow_error error; - uint32_t tnl_pmd_items_cnt; - struct netdev *physdev; - int ret; - - physdev = dpdk_offload_get_netdev(offload, orig_in_port); - if (physdev == NULL) { - return -1; - } - - ret = vport_to_rte_tunnel(tnldev, &tunnel, physdev, &patterns->s_tnl); - if (ret) { - goto out; - } - ret = netdev_dpdk_rte_flow_tunnel_match(physdev, &tunnel, &tnl_pmd_items, - &tnl_pmd_items_cnt, &error); - if (ret) { - VLOG_DBG_RL(&rl, "%s: netdev_dpdk_rte_flow_tunnel_match failed: " - "%d (%s).", netdev_get_name(physdev), error.type, - error.message); - goto out; - } - add_flow_tnl_items(patterns, physdev, tnl_pmd_items, tnl_pmd_items_cnt); - -out: - return ret; -} - -static int -parse_tnl_ip_match(struct flow_patterns *patterns, - struct match *match, - uint8_t proto) -{ - struct flow *consumed_masks; - - consumed_masks = &match->wc.masks; - /* IP v4 */ - if (match->wc.masks.tunnel.ip_src || match->wc.masks.tunnel.ip_dst) { - struct rte_flow_item_ipv4 *spec, *mask; - - spec = xzalloc(sizeof *spec); - mask = xzalloc(sizeof *mask); - - spec->hdr.type_of_service = match->flow.tunnel.ip_tos; - spec->hdr.time_to_live = match->flow.tunnel.ip_ttl; - spec->hdr.next_proto_id = proto; - spec->hdr.src_addr = match->flow.tunnel.ip_src; - spec->hdr.dst_addr = match->flow.tunnel.ip_dst; - - mask->hdr.type_of_service = match->wc.masks.tunnel.ip_tos; - mask->hdr.time_to_live = match->wc.masks.tunnel.ip_ttl; - mask->hdr.next_proto_id = UINT8_MAX; - mask->hdr.src_addr = match->wc.masks.tunnel.ip_src; - mask->hdr.dst_addr = match->wc.masks.tunnel.ip_dst; - - consumed_masks->tunnel.ip_tos = 0; - consumed_masks->tunnel.ip_ttl = 0; - consumed_masks->tunnel.ip_src = 0; - consumed_masks->tunnel.ip_dst = 0; - - add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_IPV4, spec, mask, NULL); - } else if (!is_all_zeros(&match->wc.masks.tunnel.ipv6_src, - sizeof(struct in6_addr)) || - !is_all_zeros(&match->wc.masks.tunnel.ipv6_dst, - sizeof(struct in6_addr))) { - /* IP v6 */ - struct rte_flow_item_ipv6 *spec, *mask; - - spec = xzalloc(sizeof *spec); - mask = xzalloc(sizeof *mask); - - spec->hdr.proto = proto; - spec->hdr.hop_limits = match->flow.tunnel.ip_ttl; - spec->hdr.vtc_flow = htonl((uint32_t) match->flow.tunnel.ip_tos << - RTE_IPV6_HDR_TC_SHIFT); - memcpy(&spec->hdr.src_addr, &match->flow.tunnel.ipv6_src, - sizeof spec->hdr.src_addr); - memcpy(&spec->hdr.dst_addr, &match->flow.tunnel.ipv6_dst, - sizeof spec->hdr.dst_addr); - - mask->hdr.proto = UINT8_MAX; - mask->hdr.hop_limits = match->wc.masks.tunnel.ip_ttl; - mask->hdr.vtc_flow = htonl((uint32_t) match->wc.masks.tunnel.ip_tos << - RTE_IPV6_HDR_TC_SHIFT); - memcpy(&mask->hdr.src_addr, &match->wc.masks.tunnel.ipv6_src, - sizeof mask->hdr.src_addr); - memcpy(&mask->hdr.dst_addr, &match->wc.masks.tunnel.ipv6_dst, - sizeof mask->hdr.dst_addr); - - consumed_masks->tunnel.ip_tos = 0; - consumed_masks->tunnel.ip_ttl = 0; - memset(&consumed_masks->tunnel.ipv6_src, 0, - sizeof consumed_masks->tunnel.ipv6_src); - memset(&consumed_masks->tunnel.ipv6_dst, 0, - sizeof consumed_masks->tunnel.ipv6_dst); - - add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_IPV6, spec, mask, NULL); - } else { - VLOG_ERR_RL(&rl, "Tunnel L3 protocol is neither IPv4 nor IPv6"); - return -1; - } - - return 0; -} - -static void -parse_tnl_udp_match(struct flow_patterns *patterns, - struct match *match) -{ - struct flow *consumed_masks; - struct rte_flow_item_udp *spec, *mask; - - consumed_masks = &match->wc.masks; - - spec = xzalloc(sizeof *spec); - mask = xzalloc(sizeof *mask); - - spec->hdr.src_port = match->flow.tunnel.tp_src; - spec->hdr.dst_port = match->flow.tunnel.tp_dst; - - mask->hdr.src_port = match->wc.masks.tunnel.tp_src; - mask->hdr.dst_port = match->wc.masks.tunnel.tp_dst; - - consumed_masks->tunnel.tp_src = 0; - consumed_masks->tunnel.tp_dst = 0; - - add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_UDP, spec, mask, NULL); -} - -static int -parse_vxlan_match(struct flow_patterns *patterns, - struct match *match) -{ - struct rte_flow_item_vxlan *vx_spec, *vx_mask; - struct flow *consumed_masks; - int ret; - - ret = parse_tnl_ip_match(patterns, match, IPPROTO_UDP); - if (ret) { - return -1; - } - parse_tnl_udp_match(patterns, match); - - consumed_masks = &match->wc.masks; - /* VXLAN */ - vx_spec = xzalloc(sizeof *vx_spec); - vx_mask = xzalloc(sizeof *vx_mask); - - put_16aligned_be32(&ALIGNED_CAST(struct vxlanhdr *, &vx_spec->hdr)->vx_vni, - htonl(ntohll(match->flow.tunnel.tun_id) << 8)); - put_16aligned_be32(&ALIGNED_CAST(struct vxlanhdr *, &vx_mask->hdr)->vx_vni, - htonl(ntohll(match->wc.masks.tunnel.tun_id) << 8)); - - consumed_masks->tunnel.tun_id = 0; - consumed_masks->tunnel.flags = 0; - - add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_VXLAN, vx_spec, vx_mask, - NULL); - return 0; -} - -static int -parse_gre_match(struct flow_patterns *patterns, - struct match *match) -{ - struct rte_flow_item_gre *gre_spec, *gre_mask; - struct rte_gre_hdr *greh_spec, *greh_mask; - rte_be32_t *key_spec, *key_mask; - struct flow *consumed_masks; - int ret; - - - ret = parse_tnl_ip_match(patterns, match, IPPROTO_GRE); - if (ret) { - return -1; - } - - gre_spec = xzalloc(sizeof *gre_spec); - gre_mask = xzalloc(sizeof *gre_mask); - add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_GRE, gre_spec, gre_mask, - NULL); - - consumed_masks = &match->wc.masks; - - greh_spec = (struct rte_gre_hdr *) gre_spec; - greh_mask = (struct rte_gre_hdr *) gre_mask; - - if (match->wc.masks.tunnel.flags & FLOW_TNL_F_CSUM) { - greh_spec->c = !!(match->flow.tunnel.flags & FLOW_TNL_F_CSUM); - greh_mask->c = 1; - consumed_masks->tunnel.flags &= ~FLOW_TNL_F_CSUM; - } - - if (match->wc.masks.tunnel.flags & FLOW_TNL_F_KEY) { - greh_spec->k = !!(match->flow.tunnel.flags & FLOW_TNL_F_KEY); - greh_mask->k = 1; - - key_spec = xzalloc(sizeof *key_spec); - key_mask = xzalloc(sizeof *key_mask); - - *key_spec = htonl(ntohll(match->flow.tunnel.tun_id)); - *key_mask = htonl(ntohll(match->wc.masks.tunnel.tun_id)); - - consumed_masks->tunnel.tun_id = 0; - consumed_masks->tunnel.flags &= ~FLOW_TNL_F_KEY; - add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_GRE_KEY, key_spec, - key_mask, NULL); - } - - consumed_masks->tunnel.flags &= ~FLOW_TNL_F_DONT_FRAGMENT; - - return 0; -} - -static int OVS_UNUSED -parse_flow_tnl_match(struct dpdk_offload *offload, - struct netdev *tnldev, - struct flow_patterns *patterns, - odp_port_t orig_in_port, - struct match *match) -{ - int ret; - - ret = add_vport_match(offload, patterns, orig_in_port, tnldev); - if (ret) { - return ret; - } - - if (!strcmp(netdev_get_type(tnldev), "vxlan")) { - ret = parse_vxlan_match(patterns, match); - } - else if (!strcmp(netdev_get_type(tnldev), "gre")) { - ret = parse_gre_match(patterns, match); - } - - return ret; } static int @@ -1647,12 +1258,6 @@ parse_flow_match(struct dpdk_offload *offload OVS_UNUSED, } patterns->physdev = netdev; -#ifdef ALLOW_EXPERIMENTAL_API /* Packet restoration API required. */ - if (netdev_vport_is_vport_class(netdev->netdev_class) && - parse_flow_tnl_match(offload, netdev, patterns, orig_in_port, match)) { - return -1; - } -#endif memset(&consumed_masks->in_port, 0, sizeof consumed_masks->in_port); /* recirc id must be zero. */ if (match->wc.masks.recirc_id & match->flow.recirc_id) { @@ -2021,7 +1626,6 @@ dpdk_offload_mark_rss(struct flow_patterns *patterns, struct netdev *netdev, struct flow_actions actions = { .actions = NULL, .cnt = 0, - .s_tnl = DS_EMPTY_INITIALIZER, }; const struct rte_flow_attr flow_attr = { .group = 0, @@ -2393,59 +1997,6 @@ parse_clone_actions(struct dpdk_offload *offload, 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 OVS_UNUSED -add_tnl_pop_action(struct dpdk_offload *offload, - struct netdev *netdev, - struct flow_actions *actions, - const struct nlattr *nla) -{ - struct rte_flow_action *tnl_pmd_actions = NULL; - uint32_t tnl_pmd_actions_cnt = 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 = dpdk_offload_get_netdev(offload, port); - if (vport == NULL) { - return -1; - } - ret = vport_to_rte_tunnel(vport, &tunnel, netdev, &actions->s_tnl); - if (ret) { - return ret; - } - ret = netdev_dpdk_rte_flow_tunnel_decap_set(netdev, &tunnel, - &tnl_pmd_actions, - &tnl_pmd_actions_cnt, - &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_pmd_actions, - tnl_pmd_actions_cnt); - /* After decap_set, the packet processing should continue. In SW, it is - * done by recirculation (recirc_id = 0). In rte_flow, the group is - * equivalent to recirc_id, thus jump to group 0 is added to instruct the - * the HW to proceed processing. - */ - add_jump_action(actions, 0); - return 0; -} - static int parse_flow_actions(struct dpdk_offload *offload, struct netdev *netdev, @@ -2493,12 +2044,6 @@ parse_flow_actions(struct dpdk_offload *offload, clone_actions_len)) { return -1; } -#ifdef ALLOW_EXPERIMENTAL_API /* Packet restoration API required. */ - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_TUNNEL_POP) { - if (add_tnl_pop_action(offload, netdev, actions, nla)) { - return -1; - } -#endif } else { VLOG_DBG_RL(&rl, "Unsupported action type %d", nl_attr_type(nla)); return -1; @@ -2525,7 +2070,6 @@ dpdk_offload_with_actions(struct dpdk_offload *offload, struct flow_actions actions = { .actions = NULL, .cnt = 0, - .s_tnl = DS_EMPTY_INITIALIZER, }; struct rte_flow *flow = NULL; struct rte_flow_error error; @@ -2552,7 +2096,6 @@ dpdk_offload_add_flow(struct dpdk_offload *offload, struct flow_patterns patterns = { .items = NULL, .cnt = 0, - .s_tnl = DS_EMPTY_INITIALIZER, }; struct ufid_to_rte_flow_data *flows_data = NULL; bool actions_offloaded = true; @@ -2566,7 +2109,7 @@ dpdk_offload_add_flow(struct dpdk_offload *offload, flow = dpdk_offload_with_actions(offload, patterns.physdev, &patterns, nl_actions, actions_len); - if (!flow && !netdev_vport_is_vport_class(netdev->netdev_class)) { + if (!flow) { /* If we failed to offload the rule actions fallback to MARK+RSS * actions. */ @@ -2792,20 +2335,10 @@ int dpdk_netdev_offload_init(struct netdev *netdev, unsigned int offload_thread_count) { - int ret = EOPNOTSUPP; - - if (netdev_vport_is_vport_class(netdev->netdev_class) - && !strcmp(netdev_get_dpif_type(netdev), "system")) { - VLOG_DBG("%s: vport belongs to the system datapath. Skipping.", - netdev_get_name(netdev)); - return EOPNOTSUPP; - } - if (netdev_dpdk_flow_api_supported(netdev, false)) { - ret = offload_data_init(netdev, offload_thread_count); + return offload_data_init(netdev, offload_thread_count); } - - return ret; + return EOPNOTSUPP; } void @@ -2893,121 +2426,22 @@ flush_netdev_flows_in_related(struct dpdk_offload *offload, } } } -struct flush_in_vport_aux { - struct dpdk_offload *offload; - struct netdev *netdev; -}; - -static bool -flush_in_vport_cb(struct netdev *vport, - odp_port_t odp_port OVS_UNUSED, - void *aux_) -{ - struct flush_in_vport_aux *aux = aux_; - - /* Only vports are related to physical devices. */ - if (netdev_vport_is_vport_class(vport->netdev_class)) { - flush_netdev_flows_in_related(aux->offload, aux->netdev, vport); - } - - return false; -} int dpdk_netdev_flow_flush(struct dpdk_offload *offload, struct netdev *netdev) { flush_netdev_flows_in_related(offload, netdev, netdev); - - if (!netdev_vport_is_vport_class(netdev->netdev_class)) { - struct flush_in_vport_aux aux = { - .offload = offload, - .netdev = netdev - }; - - dpdk_offload_traverse_ports(offload, flush_in_vport_cb, &aux); - } - return 0; } -struct get_vport_netdev_aux { - struct rte_flow_tunnel *tunnel; - odp_port_t *odp_port; - struct netdev *vport; - const char *type; -}; - -static bool -get_vport_netdev_cb(struct netdev *netdev, - odp_port_t odp_port, - void *aux_) -{ - const struct netdev_tunnel_config *tnl_cfg; - struct get_vport_netdev_aux *aux = aux_; - - if (!aux->type || strcmp(netdev_get_type(netdev), aux->type)) { - return false; - } - if (!strcmp(netdev_get_type(netdev), "gre")) { - goto out; - } - - tnl_cfg = netdev_get_tunnel_config(netdev); - if (!tnl_cfg) { - VLOG_ERR_RL(&rl, "Cannot get a tunnel config for netdev %s", - netdev_get_name(netdev)); - return false; - } - - if (tnl_cfg->dst_port != aux->tunnel->tp_dst) { - return false; - } - -out: - /* Found the netdev. Store the results and stop the traversing. */ - aux->vport = netdev_ref(netdev); - *aux->odp_port = odp_port; - - return true; -} - -static struct netdev * -get_vport_netdev(struct dpdk_offload *offload, - struct rte_flow_tunnel *tunnel, - odp_port_t *odp_port) -{ - struct get_vport_netdev_aux aux = { - .tunnel = tunnel, - .odp_port = odp_port, - .vport = NULL, - .type = NULL, - }; - - if (tunnel->type == RTE_FLOW_ITEM_TYPE_VXLAN) { - aux.type = "vxlan"; - } else if (tunnel->type == RTE_FLOW_ITEM_TYPE_GRE) { - aux.type = "gre"; - } - dpdk_offload_traverse_ports(offload, get_vport_netdev_cb, &aux); - - return aux.vport; -} - int -dpdk_netdev_hw_miss_packet_recover(struct dpdk_offload *offload, +dpdk_netdev_hw_miss_packet_recover(struct dpdk_offload *offload OVS_UNUSED, struct netdev *netdev, unsigned pmd_id, struct dp_packet *packet, void **flow_reference) { struct pmd_id_to_flow_ref_data *pmd_data = NULL; - struct rte_flow_restore_info rte_restore_info; - struct rte_flow_tunnel *rte_tnl; - struct netdev *vport_netdev; - struct pkt_metadata *md; - struct flow_tnl *md_tnl; - odp_port_t vport_odp; uint32_t flow_mark; - int ret = 0; if (dp_packet_has_flow_mark(packet, &flow_mark)) { struct ufid_to_rte_flow_data *data; @@ -3023,82 +2457,7 @@ dpdk_netdev_hw_miss_packet_recover(struct dpdk_offload *offload, *flow_reference = NULL; } - ret = netdev_dpdk_rte_flow_get_restore_info(netdev, packet, - &rte_restore_info, NULL); - if (ret) { - if (ret == -EOPNOTSUPP) { - return -ret; - } - /* This function is called for every packet, and in most cases there - * will be no restore info from the HW, thus error is expected. - */ - return 0; - } - - if (!(rte_restore_info.flags & RTE_FLOW_RESTORE_INFO_TUNNEL)) { - return EOPNOTSUPP; - } - - rte_tnl = &rte_restore_info.tunnel; - vport_netdev = get_vport_netdev(offload, rte_tnl, &vport_odp); - if (!vport_netdev) { - VLOG_WARN_RL(&rl, "Could not find vport netdev"); - return EOPNOTSUPP; - } - - md = &packet->md; - /* For tunnel recovery (RTE_FLOW_RESTORE_INFO_TUNNEL), it is possible - * to have the packet to still be encapsulated, or not. This is reflected - * by the RTE_FLOW_RESTORE_INFO_ENCAPSULATED flag. - * In the case it is on, the packet is still encapsulated, and we do - * the pop in SW. - * In the case it is off, the packet is already decapsulated by HW, and - * the tunnel info is provided in the tunnel struct. For this case we - * take it to OVS metadata. - */ - if (rte_restore_info.flags & RTE_FLOW_RESTORE_INFO_ENCAPSULATED) { - if (!vport_netdev->netdev_class || - !vport_netdev->netdev_class->pop_header) { - VLOG_ERR_RL(&rl, "vport netdev=%s with no pop_header method", - netdev_get_name(vport_netdev)); - ret = EOPNOTSUPP; - goto close_vport_netdev; - } - parse_tcp_flags(packet, NULL, NULL, NULL); - if (vport_netdev->netdev_class->pop_header(packet) == NULL) { - /* If there is an error with popping the header, the packet is - * freed. In this case it should not continue SW processing. - */ - ret = EINVAL; - goto close_vport_netdev; - } - } else { - md_tnl = &md->tunnel; - if (rte_tnl->is_ipv6) { - memcpy(&md_tnl->ipv6_src, &rte_tnl->ipv6.src_addr, - sizeof md_tnl->ipv6_src); - memcpy(&md_tnl->ipv6_dst, &rte_tnl->ipv6.dst_addr, - sizeof md_tnl->ipv6_dst); - } else { - md_tnl->ip_src = rte_tnl->ipv4.src_addr; - md_tnl->ip_dst = rte_tnl->ipv4.dst_addr; - } - md_tnl->tun_id = htonll(rte_tnl->tun_id); - md_tnl->flags = rte_tnl->tun_flags; - md_tnl->ip_tos = rte_tnl->tos; - md_tnl->ip_ttl = rte_tnl->ttl; - md_tnl->tp_src = rte_tnl->tp_src; - } - /* Change the in_port to the vport's one, in order to continue packet - * processing in SW. - */ - md->in_port.odp_port = vport_odp; - dp_packet_reset_offload(packet); - -close_vport_netdev: - netdev_close(vport_netdev); - - return ret; + return 0; } uint64_t diff --git a/lib/dpif-offload-dpdk.c b/lib/dpif-offload-dpdk.c index 2991c24bb..293b3b8e9 100644 --- a/lib/dpif-offload-dpdk.c +++ b/lib/dpif-offload-dpdk.c @@ -786,10 +786,7 @@ static bool dpdk_can_offload(struct dpif_offload *offload OVS_UNUSED, struct netdev *netdev) { - if (netdev_vport_is_vport_class(netdev->netdev_class) - && strcmp(netdev_get_dpif_type(netdev), "netdev")) { - VLOG_DBG("%s: vport doesn't belong to the netdev datapath, skipping", - netdev_get_name(netdev)); + if (netdev_vport_is_vport_class(netdev->netdev_class)) { return false; } diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index e375275de..02cdad22f 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -1277,23 +1277,12 @@ dpdk_eth_dev_init_rx_metadata(struct netdev_dpdk *dev) /* For the fallback offload (non-"transfer" rules). */ rx_metadata |= RTE_ETH_RX_METADATA_USER_MARK; -#ifdef ALLOW_EXPERIMENTAL_API - /* For the tunnel offload. */ - rx_metadata |= RTE_ETH_RX_METADATA_TUNNEL_ID; -#endif /* ALLOW_EXPERIMENTAL_API */ - ret = rte_eth_rx_metadata_negotiate(dev->port_id, &rx_metadata); if (ret == 0) { if (!(rx_metadata & RTE_ETH_RX_METADATA_USER_MARK)) { VLOG_DBG("%s: The NIC will not provide per-packet USER_MARK", netdev_get_name(&dev->up)); } -#ifdef ALLOW_EXPERIMENTAL_API - if (!(rx_metadata & RTE_ETH_RX_METADATA_TUNNEL_ID)) { - VLOG_DBG("%s: The NIC will not provide per-packet TUNNEL_ID", - netdev_get_name(&dev->up)); - } -#endif /* ALLOW_EXPERIMENTAL_API */ } else { VLOG(ret == -ENOTSUP ? VLL_DBG : VLL_WARN, "%s: Cannot negotiate Rx metadata: %s", @@ -6545,13 +6534,6 @@ netdev_dpdk_flow_api_supported(struct netdev *netdev, bool check_only) struct netdev_dpdk *dev; bool ret = false; - if ((!strcmp(netdev_get_type(netdev), "vxlan") || - !strcmp(netdev_get_type(netdev), "gre")) && - !strcmp(netdev_get_dpif_type(netdev), "netdev")) { - ret = true; - goto out; - } - if (!is_dpdk_class(netdev->netdev_class)) { goto out; } @@ -6628,118 +6610,6 @@ netdev_dpdk_rte_flow_query_count(struct netdev *netdev, return ret; } -#ifdef ALLOW_EXPERIMENTAL_API - -int -netdev_dpdk_rte_flow_tunnel_decap_set(struct netdev *netdev, - struct rte_flow_tunnel *tunnel, - struct rte_flow_action **actions, - uint32_t *num_of_actions, - struct rte_flow_error *error) -{ - struct netdev_dpdk *dev; - int ret; - - if (!is_dpdk_class(netdev->netdev_class)) { - return -1; - } - - dev = netdev_dpdk_cast(netdev); - ovs_mutex_lock(&dev->mutex); - ret = rte_flow_tunnel_decap_set(dev->port_id, tunnel, actions, - num_of_actions, error); - ovs_mutex_unlock(&dev->mutex); - return ret; -} - -int -netdev_dpdk_rte_flow_tunnel_match(struct netdev *netdev, - struct rte_flow_tunnel *tunnel, - struct rte_flow_item **items, - uint32_t *num_of_items, - struct rte_flow_error *error) -{ - struct netdev_dpdk *dev; - int ret; - - if (!is_dpdk_class(netdev->netdev_class)) { - return -1; - } - - dev = netdev_dpdk_cast(netdev); - ovs_mutex_lock(&dev->mutex); - ret = rte_flow_tunnel_match(dev->port_id, tunnel, items, num_of_items, - error); - ovs_mutex_unlock(&dev->mutex); - return ret; -} - -int -netdev_dpdk_rte_flow_get_restore_info(struct netdev *netdev, - struct dp_packet *p, - struct rte_flow_restore_info *info, - struct rte_flow_error *error) -{ - struct rte_mbuf *m = (struct rte_mbuf *) p; - struct netdev_dpdk *dev; - int ret; - - if (!is_dpdk_class(netdev->netdev_class)) { - return -1; - } - - dev = netdev_dpdk_cast(netdev); - ovs_mutex_lock(&dev->mutex); - ret = rte_flow_get_restore_info(dev->port_id, m, info, error); - ovs_mutex_unlock(&dev->mutex); - return ret; -} - -int -netdev_dpdk_rte_flow_tunnel_action_decap_release( - struct netdev *netdev, - struct rte_flow_action *actions, - uint32_t num_of_actions, - struct rte_flow_error *error) -{ - struct netdev_dpdk *dev; - int ret; - - if (!is_dpdk_class(netdev->netdev_class)) { - return -1; - } - - dev = netdev_dpdk_cast(netdev); - ovs_mutex_lock(&dev->mutex); - ret = rte_flow_tunnel_action_decap_release(dev->port_id, actions, - num_of_actions, error); - ovs_mutex_unlock(&dev->mutex); - return ret; -} - -int -netdev_dpdk_rte_flow_tunnel_item_release(struct netdev *netdev, - struct rte_flow_item *items, - uint32_t num_of_items, - struct rte_flow_error *error) -{ - struct netdev_dpdk *dev; - int ret; - - if (!is_dpdk_class(netdev->netdev_class)) { - return -1; - } - - dev = netdev_dpdk_cast(netdev); - ovs_mutex_lock(&dev->mutex); - ret = rte_flow_tunnel_item_release(dev->port_id, items, num_of_items, - error); - ovs_mutex_unlock(&dev->mutex); - return ret; -} - -#endif /* ALLOW_EXPERIMENTAL_API */ - static void parse_mempool_config(const struct smap *ovs_other_config) { diff --git a/lib/netdev-dpdk.h b/lib/netdev-dpdk.h index 0029372ee..ede8270aa 100644 --- a/lib/netdev-dpdk.h +++ b/lib/netdev-dpdk.h @@ -67,91 +67,6 @@ set_error(struct rte_flow_error *error, enum rte_flow_error_type type) error->message = NULL; } -#ifdef ALLOW_EXPERIMENTAL_API - -int netdev_dpdk_rte_flow_tunnel_decap_set(struct netdev *, - struct rte_flow_tunnel *, - struct rte_flow_action **, - uint32_t *num_of_actions, - struct rte_flow_error *); -int netdev_dpdk_rte_flow_tunnel_match(struct netdev *, - struct rte_flow_tunnel *, - struct rte_flow_item **, - uint32_t *num_of_items, - struct rte_flow_error *); -int netdev_dpdk_rte_flow_get_restore_info(struct netdev *, - struct dp_packet *, - struct rte_flow_restore_info *, - struct rte_flow_error *); -int netdev_dpdk_rte_flow_tunnel_action_decap_release(struct netdev *, - struct rte_flow_action *, - uint32_t num_of_actions, - struct rte_flow_error *); -int netdev_dpdk_rte_flow_tunnel_item_release(struct netdev *, - struct rte_flow_item *, - uint32_t num_of_items, - struct rte_flow_error *); - -#else - -static inline int -netdev_dpdk_rte_flow_tunnel_decap_set( - struct netdev *netdev OVS_UNUSED, - struct rte_flow_tunnel *tunnel OVS_UNUSED, - struct rte_flow_action **actions OVS_UNUSED, - uint32_t *num_of_actions OVS_UNUSED, - struct rte_flow_error *error) -{ - set_error(error, RTE_FLOW_ERROR_TYPE_ACTION); - return -1; -} - -static inline int -netdev_dpdk_rte_flow_tunnel_match(struct netdev *netdev OVS_UNUSED, - struct rte_flow_tunnel *tunnel OVS_UNUSED, - struct rte_flow_item **items OVS_UNUSED, - uint32_t *num_of_items OVS_UNUSED, - struct rte_flow_error *error) -{ - set_error(error, RTE_FLOW_ERROR_TYPE_ITEM); - return -1; -} - -static inline int -netdev_dpdk_rte_flow_get_restore_info( - struct netdev *netdev OVS_UNUSED, - struct dp_packet *p OVS_UNUSED, - struct rte_flow_restore_info *info OVS_UNUSED, - struct rte_flow_error *error) -{ - set_error(error, RTE_FLOW_ERROR_TYPE_ATTR); - return -1; -} - -static inline int -netdev_dpdk_rte_flow_tunnel_action_decap_release( - struct netdev *netdev OVS_UNUSED, - struct rte_flow_action *actions OVS_UNUSED, - uint32_t num_of_actions OVS_UNUSED, - struct rte_flow_error *error) -{ - set_error(error, RTE_FLOW_ERROR_TYPE_NONE); - return 0; -} - -static inline int -netdev_dpdk_rte_flow_tunnel_item_release( - struct netdev *netdev OVS_UNUSED, - struct rte_flow_item *items OVS_UNUSED, - uint32_t num_of_items OVS_UNUSED, - struct rte_flow_error *error) -{ - set_error(error, RTE_FLOW_ERROR_TYPE_NONE); - return 0; -} - -#endif /* ALLOW_EXPERIMENTAL_API */ - #else static inline void -- 2.54.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
