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. Keeping the generic post-processing API that is now supported by the dummy implementation, so the generic infrastructure will not get broken over time and it will be simple enough to bring support back or add different offload providers supporting post-processing for the metadata recovery. Having the dummy implementation should not be a big problem for the maintenance, as it is simple enough and it is tested in our CI. But if we won't get any non-dummy implementation of this API by the next LTS (Feb 2028), we'll remove it as well. The date is kind of arbitrary, but seems reasonable. Signed-off-by: Ilya Maximets <[email protected]> --- Documentation/howto/dpdk.rst | 5 - NEWS | 2 + lib/dpif-offload-dpdk-netdev.c | 751 +------------------------------- lib/dpif-offload-dpdk-private.h | 3 - lib/dpif-offload-dpdk.c | 17 +- lib/netdev-dpdk.c | 126 +----- lib/netdev-dpdk.h | 85 ---- 7 files changed, 17 insertions(+), 972 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 288ab8cc4..a8bd540bb 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. - The following deprecated AVX512-specific features of the userspace datapath are now removed: * AVX512-optimized DPCLS lookups. diff --git a/lib/dpif-offload-dpdk-netdev.c b/lib/dpif-offload-dpdk-netdev.c index efe99065e..02acb53a0 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" @@ -72,7 +71,6 @@ struct pmd_data { */ struct ufid_to_rte_flow_data { struct cmap_node node; - struct cmap_node mark_node; ovs_u128 ufid; struct netdev *netdev; struct rte_flow *rte_flow; @@ -88,7 +86,6 @@ struct ufid_to_rte_flow_data { struct dpdk_offload_netdev_data { struct cmap ufid_to_rte_flow; - struct cmap mark_to_rte_flow; uint64_t *rte_flow_counters; struct ovs_mutex map_lock; }; @@ -242,12 +239,10 @@ offload_data_init(struct netdev *netdev, unsigned int offload_thread_count) data = xzalloc(sizeof *data); ovs_mutex_init(&data->map_lock); cmap_init(&data->ufid_to_rte_flow); - cmap_init(&data->mark_to_rte_flow); data->rte_flow_counters = xcalloc(offload_thread_count, sizeof *data->rte_flow_counters); ovsrcu_set(&netdev->hw_info.offload_data, (void *) data); - atomic_store_relaxed(&netdev->hw_info.post_process_api_supported, true); return 0; } @@ -282,7 +277,6 @@ offload_data_destroy(struct netdev *netdev) } cmap_destroy(&data->ufid_to_rte_flow); - cmap_destroy(&data->mark_to_rte_flow); ovsrcu_postpone(offload_data_destroy__, data); ovsrcu_set(&netdev->hw_info.offload_data, NULL); @@ -327,35 +321,6 @@ offload_data_map(struct netdev *netdev) return data ? &data->ufid_to_rte_flow : NULL; } -static bool -offload_data_maps(struct netdev *netdev, struct cmap **ufid_map, - struct cmap **mark_map) -{ - struct dpdk_offload_netdev_data *data; - - data = (struct dpdk_offload_netdev_data *) - ovsrcu_get(void *, &netdev->hw_info.offload_data); - - if (!data) { - return false; - } - - *ufid_map = &data->ufid_to_rte_flow; - *mark_map = &data->mark_to_rte_flow; - return true; -} - -static struct cmap * -offload_data_mark_map(struct netdev *netdev) -{ - struct dpdk_offload_netdev_data *data; - - data = (struct dpdk_offload_netdev_data *) - ovsrcu_get(void *, &netdev->hw_info.offload_data); - - return data ? &data->mark_to_rte_flow : NULL; -} - /* Find rte_flow with @ufid. */ static struct ufid_to_rte_flow_data * ufid_to_rte_flow_data_find(struct netdev *netdev, const ovs_u128 *ufid) @@ -414,26 +379,6 @@ ufid_to_rte_flow_data_find_protected(struct netdev *netdev, return NULL; } -/* Find rte_flow with @flow_mark. */ -static struct ufid_to_rte_flow_data * -mark_to_rte_flow_data_find(struct netdev *netdev, uint32_t flow_mark) -{ - size_t hash = hash_int(flow_mark, 0); - struct ufid_to_rte_flow_data *data; - struct cmap *mark_map = offload_data_mark_map(netdev); - - if (!mark_map) { - return NULL; - } - - CMAP_FOR_EACH_WITH_HASH (data, mark_node, hash, mark_map) { - if (data->flow_mark == flow_mark) { - return data; - } - } - return NULL; -} - static inline struct ufid_to_rte_flow_data * ufid_to_rte_flow_associate(const ovs_u128 *ufid, struct netdev *netdev, struct netdev *physdev, struct rte_flow *rte_flow, @@ -441,11 +386,11 @@ ufid_to_rte_flow_associate(const ovs_u128 *ufid, struct netdev *netdev, struct pmd_data *pmd_mapping) { size_t hash = hash_bytes(ufid, sizeof *ufid, 0); + struct cmap *map = offload_data_map(netdev); struct ufid_to_rte_flow_data *data_prev; struct ufid_to_rte_flow_data *data; - struct cmap *map, *mark_map; - if (!offload_data_maps(netdev, &map, &mark_map)) { + if (!map) { return NULL; } @@ -475,8 +420,6 @@ ufid_to_rte_flow_associate(const ovs_u128 *ufid, struct netdev *netdev, ovsrcu_set(&data->pmd_mapping, pmd_mapping); cmap_insert(map, CONST_CAST(struct cmap_node *, &data->node), hash); - cmap_insert(mark_map, CONST_CAST(struct cmap_node *, &data->mark_node), - hash_int(flow_mark, 0)); offload_data_unlock(netdev); return data; @@ -498,17 +441,15 @@ ufid_to_rte_flow_disassociate(struct ufid_to_rte_flow_data *data) OVS_REQUIRES(data->lock) { size_t hash = hash_bytes(&data->ufid, sizeof data->ufid, 0); + struct cmap *map = offload_data_map(data->netdev); struct pmd_data *pmd_mapping; - struct cmap *map, *mark_map; - if (!offload_data_maps(data->netdev, &map, &mark_map)) { + if (!map) { return; } offload_data_lock(data->netdev); cmap_remove(map, CONST_CAST(struct cmap_node *, &data->node), hash); - cmap_remove(mark_map, CONST_CAST(struct cmap_node *, &data->mark_node), - hash_int(data->flow_mark, 0)); offload_data_unlock(data->netdev); if (data->netdev != data->physdev) { @@ -533,44 +474,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 +514,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 +889,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 +1046,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 +1148,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 +1167,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 +1200,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 +1568,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 +1939,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 +1986,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 +2012,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 +2038,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 +2051,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 +2277,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,214 +2368,14 @@ 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, - 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; - - data = mark_to_rte_flow_data_find(netdev, flow_mark); - if (data) { - pmd_data = pmd_data_get(data, pmd_id); - } - } - if (pmd_data) { - *flow_reference = pmd_data->flow_reference; - } else { - *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; -} - uint64_t dpdk_netdev_flow_count(struct netdev *netdev, unsigned int offload_thread_count) diff --git a/lib/dpif-offload-dpdk-private.h b/lib/dpif-offload-dpdk-private.h index d5c44f432..5c36a433f 100644 --- a/lib/dpif-offload-dpdk-private.h +++ b/lib/dpif-offload-dpdk-private.h @@ -44,9 +44,6 @@ int dpdk_netdev_flow_flush(struct dpdk_offload *, struct netdev *); uint64_t dpdk_netdev_flow_count(struct netdev *, unsigned int offload_thread_count); uint64_t dpdk_netdev_flow_count_by_thread(struct netdev *, unsigned int tid); -int dpdk_netdev_hw_miss_packet_recover(struct dpdk_offload *, struct netdev *, - unsigned pmd_id, struct dp_packet *, - void **flow_reference); int dpdk_netdev_flow_put(struct dpdk_offload *, unsigned pmd_id, void *flow_reference, struct netdev *, struct match *, struct nlattr *actions, size_t actions_len, diff --git a/lib/dpif-offload-dpdk.c b/lib/dpif-offload-dpdk.c index 2991c24bb..fcf222be4 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; } @@ -832,17 +829,6 @@ dpdk_flow_count_by_thread(struct dpdk_offload *offload, unsigned int tid) return total; } -static int -dpdk_offload_hw_post_process(const struct dpif_offload *offload_, - struct netdev *netdev, unsigned pmd_id, - struct dp_packet *packet, void **flow_reference) -{ - struct dpdk_offload *offload = dpdk_offload_cast(offload_); - - return dpdk_netdev_hw_miss_packet_recover(offload, netdev, pmd_id, packet, - flow_reference); -} - static int dpdk_flow_put(const struct dpif_offload *offload_, struct netdev *netdev OVS_UNUSED, @@ -1043,7 +1029,6 @@ struct dpif_offload_class dpif_offload_dpdk_class = { .port_del = dpdk_offload_port_del, .flow_count = dpdk_flow_count, .get_netdev = dpdk_offload_get_netdev__, - .netdev_hw_post_process = dpdk_offload_hw_post_process, .netdev_flow_put = dpdk_flow_put, .netdev_flow_del = dpdk_flow_del, .netdev_flow_stats = dpdk_flow_stats, diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index e375275de..60fd93ab9 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,8 +6534,7 @@ 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")) && + if (!netdev_vport_is_vport_class(netdev->netdev_class) && !strcmp(netdev_get_dpif_type(netdev), "netdev")) { ret = true; goto out; @@ -6628,118 +6616,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
