>-----Original Message-----
>From: Ivan Malov <ivan.ma...@arknetworks.am>
>Sent: Sunday, 4 June 2023 15:58
>To: Eli Britstein <el...@nvidia.com>
>Cc: ovs-dev@openvswitch.org; Ilya Maximets <i.maxim...@ovn.org>; Ori
>Kam <or...@nvidia.com>; David Marchand <david.march...@redhat.com>
>Subject: RE: [PATCH v4 3/3] netdev-offload-dpdk: use flow transfer proxy
>mechanism
>
>External email: Use caution opening links or attachments
>
>
>Hi Eli,
>
>Thanks for reviewing this. Please see below.
>
>On Tue, 21 Feb 2023, Eli Britstein wrote:
>
>>
>>
>>> -----Original Message-----
>>> From: Ivan Malov <ivan.ma...@arknetworks.am>
>>> Sent: Tuesday, 21 February 2023 2:41
>>> To: ovs-dev@openvswitch.org
>>> Cc: Ilya Maximets <i.maxim...@ovn.org>; Eli Britstein
>>> <el...@nvidia.com>; Ori Kam <or...@nvidia.com>; David Marchand
>>> <david.march...@redhat.com>
>>> Subject: [PATCH v4 3/3] netdev-offload-dpdk: use flow transfer proxy
>>> mechanism
>>>
>>> External email: Use caution opening links or attachments
>>>
>>>
>>> Manage "transfer" flows via the corresponding mechanism.
>>> Doing so requires that the traffic source be specified explicitly,
>>> via the corresponding pattern item.
>>>
>>> Signed-off-by: Ivan Malov <ivan.ma...@arknetworks.am>
>>> ---
>>> lib/netdev-dpdk.c | 88 +++++++++++++++++++++++++++++++--------
>>> lib/netdev-dpdk.h | 4 +-
>>> lib/netdev-offload-dpdk.c | 55 +++++++++++++++++++-----
>>> 3 files changed, 117 insertions(+), 30 deletions(-)
>>>
>>> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index
>>> 2cebc3cca..3a9c9d9a0
>>> 100644
>>> --- a/lib/netdev-dpdk.c
>>> +++ b/lib/netdev-dpdk.c
>>> @@ -434,6 +434,7 @@ enum dpdk_hw_ol_features {
>>>
>>> struct netdev_dpdk {
>>> PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE,
>cacheline0,
>>> + dpdk_port_t flow_transfer_proxy_port_id;
>> This extra field here makes it overflow one cache line.
>>> dpdk_port_t port_id;
>>>
>>> /* If true, device was attached by rte_eth_dev_attach(). */
>>> @@ -1183,6
>>> +1184,7 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev)
>>> uint32_t rx_chksm_offload_capa =
>RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
>>> RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
>>> RTE_ETH_RX_OFFLOAD_IPV4_CKSUM;
>>> + int ret;
>>>
>>> /*
>>> * Full tunnel offload requires that tunnel ID metadata be @@
>>> -1194,6
>>> +1196,24 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev)
>>> */
>>> dpdk_eth_dev_init_rx_metadata(dev);
>>>
>>> + /*
>>> + * Managing "transfer" flows requires that the user communicate them
>>> + * via a port which has the privilege to control the embedded switch.
>>> + * For some vendors, all ports in a given switching domain have
>>> + * this privilege. For other vendors, it's only one port.
>>> + *
>>> + * Get the proxy port ID and remember it for later use.
>>> + */
>>> + ret = rte_flow_pick_transfer_proxy(dev->port_id,
>>> + &dev->flow_transfer_proxy_port_id,
>>> NULL);
>>> + if (ret != 0) {
>>> + /*
>>> + * The PMD does not indicate the proxy port.
>>> + * Assume the proxy is unneeded.
>>> + */
>>> + dev->flow_transfer_proxy_port_id = dev->port_id;
>>> + }
>>> +
>>> rte_eth_dev_info_get(dev->port_id, &info);
>>>
>>> if (strstr(info.driver_name, "vf") != NULL) { @@ -3981,8 +4001,10
>>> @@ netdev_dpdk_detach(struct unixctl_conn *conn, int argc
>OVS_UNUSED,
>>> const char *argv[], void *aux OVS_UNUSED) {
>>> struct ds used_interfaces = DS_EMPTY_INITIALIZER;
>>> + struct netdev_dpdk *dev_self = NULL;
>>> struct rte_eth_dev_info dev_info;
>>> dpdk_port_t sibling_port_id;
>>> + struct netdev_dpdk *dev;
>>> dpdk_port_t port_id;
>>> bool used = false;
>>> char *response;
>>> @@ -4000,8 +4022,6 @@ netdev_dpdk_detach(struct unixctl_conn *conn,
>>> int argc OVS_UNUSED,
>>> argv[1]);
>>>
>>> RTE_ETH_FOREACH_DEV_SIBLING (sibling_port_id, port_id) {
>>> - struct netdev_dpdk *dev;
>>> -
>>> LIST_FOR_EACH (dev, list_node, &dpdk_list) {
>>> if (dev->port_id != sibling_port_id) {
>>> continue;
>>> @@ -4021,6 +4041,25 @@ netdev_dpdk_detach(struct unixctl_conn
>*conn,
>>> int argc OVS_UNUSED,
>>> }
>>> ds_destroy(&used_interfaces);
>>>
>>> + /*
>>> + * The device being detached may happen to be a flow proxy port
>>> + * for another device (still attached). If so, do not allow to
>>> + * detach. Devices dependent on this one must be detached first.
>>> + */
>>> + LIST_FOR_EACH (dev, list_node, &dpdk_list) {
>>> + if (dev->port_id == port_id) {
>>> + dev_self = dev;
>>> + } else if (dev->flow_transfer_proxy_port_id == port_id) {
>>> + response = xasprintf("Device '%s' can not be detached (flow
>proxy)",
>>> + argv[1]);
>> This is not acceptable.
>> When removing a port, we clean the offloads using
>netdev_offload_dpdk_flow_flush().
>> It should be enhanced to check if the proxy port is detached, remove the
>offloads of all the ports that used it.
>> There is a related patch proposed in [1].
>> [1]
>>
>https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatch
>>
>work.ozlabs.org%2Fproject%2Fopenvswitch%2Fpatch%2F20220905144603.358
>51
>> 05-1-
>elibr%40nvidia.com%2F&data=05%7C01%7Celibr%40nvidia.com%7Ca5083e7
>>
>6e913441830f108db64fb5c71%7C43083d15727340c1b7db39efd9ccc17a%7C0%7
>C0%7
>>
>C638214803017093453%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwM
>DAiLCJQIj
>>
>oiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=zI
>NHT8Y
>> BOxGsw%2B5FJ4kkXDdEZ9WgW%2BnPwpHz9eewqpc%3D&reserved=0
>
>I hear you. But do you want me to first wait for patch [1] to be applied and
>then send the proxy enhancement to be applied on top of it?
>Or do you believe I can do something in parallel here?
>
>As I can see, patch [1] has not been applied yet.
>Is there any problem with it?
>
>If I need to wait, then I believe I can revoke this [3/3] patch from the
>series for
>the time being and send v5.
>What's your opinion?
I don't know if there is a problem with it, I haven't received any comment
about it so far.
Yes, it can be a good idea to integrate patches 1,2 of this series first.
Another comment for this commit: in NV version of OVS we already have this, and
just discovered an issue. Doing the flush in netdev-offload-dpdk leaves the
marks associated with the flows leaked. Need to resolve that too.
>
>>
>>> + goto error;
>>> + }
>>> + }
>>> +
>>> + /* Indicate that the device being detached no longer needs a flow
>proxy.
>>> */
>>> + if (dev_self != NULL)
>>> + dev_self->flow_transfer_proxy_port_id = port_id;
>>> +
>>> rte_eth_dev_info_get(port_id, &dev_info);
>>> rte_eth_dev_close(port_id);
>>> if (rte_dev_remove(dev_info.device) < 0) { @@ -5470,7 +5509,8 @@
>>> unlock:
>>> }
>>>
>>> int
>>> -netdev_dpdk_get_port_id(struct netdev *netdev)
>>> +netdev_dpdk_get_port_id(struct netdev *netdev,
>>> + bool flow_transfer_proxy)
>>> {
>>> struct netdev_dpdk *dev;
>>> int ret = -1;
>>> @@ -5481,7 +5521,7 @@ netdev_dpdk_get_port_id(struct netdev
>*netdev)
>>>
>>> dev = netdev_dpdk_cast(netdev);
>>> ovs_mutex_lock(&dev->mutex);
>>> - ret = dev->port_id;
>>> + ret = flow_transfer_proxy ? dev->flow_transfer_proxy_port_id :
>>> + dev->port_id;
>>> ovs_mutex_unlock(&dev->mutex);
>>> out:
>>> return ret;
>>> @@ -5517,13 +5557,15 @@ out:
>>>
>>> int
>>> netdev_dpdk_rte_flow_destroy(struct netdev *netdev,
>>> - struct rte_flow *rte_flow,
>>> + bool transfer, struct rte_flow
>>> + *rte_flow,
>>> struct rte_flow_error *error) {
>>> struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
>>> int ret;
>>>
>>> - ret = rte_flow_destroy(dev->port_id, rte_flow, error);
>>> + ret = rte_flow_destroy(transfer ?
>>> + dev->flow_transfer_proxy_port_id : dev->port_id,
>>> + rte_flow, error);
>>> return ret;
>>> }
>>>
>>> @@ -5537,7 +5579,17 @@ netdev_dpdk_rte_flow_create(struct netdev
>>> *netdev,
>>> struct rte_flow *flow;
>>> struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
>>>
>>> - flow = rte_flow_create(dev->port_id, attr, items, actions, error);
>>> + if (!attr->transfer) {
>>> + /*
>>> + * The 1st item in any pattern is a traffic source one.
>>> + * It is unnecessary in the case of non-transfer rules.
>>> + */
>>> + ++(items);
>>> + }
>>> +
>>> + flow = rte_flow_create(attr->transfer ?
>>> + dev->flow_transfer_proxy_port_id : dev->port_id,
>>> + attr, items, actions, error);
>>> return flow;
>>> }
>>>
>>> @@ -5565,7 +5617,8 @@ netdev_dpdk_rte_flow_query_count(struct
>netdev
>>> *netdev,
>>> }
>>>
>>> dev = netdev_dpdk_cast(netdev);
>>> - ret = rte_flow_query(dev->port_id, rte_flow, actions, query, error);
>>> + ret = rte_flow_query(dev->flow_transfer_proxy_port_id, rte_flow,
>>> + actions, query, error);
>>> return ret;
>>> }
>>>
>>> @@ -5587,8 +5640,8 @@
>netdev_dpdk_rte_flow_tunnel_decap_set(struct
>>> netdev *netdev,
>>>
>>> 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);
>>> + ret =
>>> + rte_flow_tunnel_decap_set(dev->flow_transfer_proxy_port_id,
>>> tunnel,
>>> + actions, num_of_actions, error);
>>> ovs_mutex_unlock(&dev->mutex);
>>> return ret;
>>> }
>>> @@ -5609,8 +5662,8 @@ netdev_dpdk_rte_flow_tunnel_match(struct
>>> netdev *netdev,
>>>
>>> dev = netdev_dpdk_cast(netdev);
>>> ovs_mutex_lock(&dev->mutex);
>>> - ret = rte_flow_tunnel_match(dev->port_id, tunnel, items,
>num_of_items,
>>> - error);
>>> + ret = rte_flow_tunnel_match(dev->flow_transfer_proxy_port_id,
>tunnel,
>>> + items, num_of_items, error);
>>> ovs_mutex_unlock(&dev->mutex);
>>> return ret;
>>> }
>>> @@ -5631,7 +5684,8 @@ netdev_dpdk_rte_flow_get_restore_info(struct
>>> netdev *netdev,
>>>
>>> dev = netdev_dpdk_cast(netdev);
>>> ovs_mutex_lock(&dev->mutex);
>>> - ret = rte_flow_get_restore_info(dev->port_id, m, info, error);
>>> + ret = rte_flow_get_restore_info(dev->flow_transfer_proxy_port_id,
>>> + m, info, error);
>>> ovs_mutex_unlock(&dev->mutex);
>>> return ret;
>>> }
>>> @@ -5652,8 +5706,8 @@
>>> netdev_dpdk_rte_flow_tunnel_action_decap_release(
>>>
>>> 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);
>>> + ret = rte_flow_tunnel_action_decap_release(dev-
>>>> flow_transfer_proxy_port_id,
>>> + actions,
>>> + num_of_actions, error);
>>> ovs_mutex_unlock(&dev->mutex);
>>> return ret;
>>> }
>>> @@ -5673,8 +5727,8 @@
>netdev_dpdk_rte_flow_tunnel_item_release(struct
>>> netdev *netdev,
>>>
>>> dev = netdev_dpdk_cast(netdev);
>>> ovs_mutex_lock(&dev->mutex);
>>> - ret = rte_flow_tunnel_item_release(dev->port_id, items,
>num_of_items,
>>> - error);
>>> + ret = rte_flow_tunnel_item_release(dev-
>>flow_transfer_proxy_port_id,
>>> + items, num_of_items, error);
>>> ovs_mutex_unlock(&dev->mutex);
>>> return ret;
>>> }
>>> diff --git a/lib/netdev-dpdk.h b/lib/netdev-dpdk.h index
>>> 5cd95d00f..80b616dae 100644
>>> --- a/lib/netdev-dpdk.h
>>> +++ b/lib/netdev-dpdk.h
>>> @@ -36,7 +36,7 @@ bool netdev_dpdk_flow_api_supported(struct
>netdev
>>> *);
>>>
>>> int
>>> netdev_dpdk_rte_flow_destroy(struct netdev *netdev,
>>> - struct rte_flow *rte_flow,
>>> + bool transfer, struct rte_flow
>>> + *rte_flow,
>>> struct rte_flow_error *error); struct
>>> rte_flow * netdev_dpdk_rte_flow_create(struct netdev *netdev, @@
>>> -50,7 +50,7 @@ netdev_dpdk_rte_flow_query_count(struct netdev
>*netdev,
>>> struct rte_flow_query_count *query,
>>> struct rte_flow_error *error); int
>>> - netdev_dpdk_get_port_id(struct netdev *netdev);
>>> +netdev_dpdk_get_port_id(struct netdev *netdev, bool
>>> +flow_transfer_proxy);
>>>
>>> #ifdef ALLOW_EXPERIMENTAL_API
>>>
>>> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
>>> index
>>> 7f2598a53..890c0ada6 100644
>>> --- a/lib/netdev-offload-dpdk.c
>>> +++ b/lib/netdev-offload-dpdk.c
>>> @@ -355,8 +355,18 @@ dump_flow_pattern(struct ds *s,
>>>
>>> if (item->type == RTE_FLOW_ITEM_TYPE_END) {
>>> ds_put_cstr(s, "end ");
>>> + } else if (item->type == RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT) {
>>> + const struct rte_flow_item_ethdev *ethdev_spec = item->spec;
>>> + const struct rte_flow_item_ethdev *ethdev_mask = item->mask;
>>> +
>>> + ds_put_cstr(s, "represented_port ");
>>> +
>>> + DUMP_PATTERN_ITEM(ethdev_mask->port_id, false,
>>> "ethdev_port_id",
>>> + "%"PRIu16, ethdev_spec->port_id,
>>> + ethdev_mask->port_id, 0);
>>> } else if (flow_patterns->tnl_pmd_items_cnt &&
>>> - pattern_index < flow_patterns->tnl_pmd_items_cnt) {
>>> + pattern_index < 1 /* REPRESENTED_PORT */ +
>>> + 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; @@
>>> -882,7
>>> +892,12 @@ dump_flow(struct ds *s, struct ds *s_extra,
>>> dump_flow_attr(s, s_extra, attr, flow_patterns, flow_actions);
>>> }
>>> ds_put_cstr(s, "pattern ");
>>> - for (i = 0; i < flow_patterns->cnt; i++) {
>>> + /*
>>> + * The 1st item in any pattern is a traffic source one.
>>> + * It is skipped in the case of non-transfer rules and
>>> + * must not be indicated when printing such rules, too.
>>> + */
>>> + for (i = 1 - attr->transfer; i < flow_patterns->cnt; i++) {
>> 1 - transfer is not very clear, you can use !transfer.
>>> dump_flow_pattern(s, flow_patterns, i);
>>> }
>>> ds_put_cstr(s, "actions ");
>>> @@ -920,7 +935,8 @@ netdev_offload_dpdk_flow_create(struct netdev
>>> *netdev,
>>> 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,
>>> - netdev_dpdk_get_port_id(netdev), ds_cstr(&s));
>>> + netdev_dpdk_get_port_id(netdev, attr->transfer),
>>> + ds_cstr(&s));
>>> }
>>> } else {
>>> enum vlog_level level = VLL_WARN; @@ -935,7 +951,8 @@
>>> netdev_offload_dpdk_flow_create(struct netdev *netdev,
>>> extra_str = ds_cstr(&s_extra);
>>> VLOG_RL(&rl, level, "%s: Failed flow: %s flow create %d %s",
>>> netdev_get_name(netdev), extra_str,
>>> - netdev_dpdk_get_port_id(netdev), ds_cstr(&s));
>>> + netdev_dpdk_get_port_id(netdev, attr->transfer),
>>> + ds_cstr(&s));
>>> }
>>> }
>>> ds_destroy(&s);
>>> @@ -1028,6 +1045,10 @@ free_flow_patterns(struct flow_patterns
>>> *patterns)
>>> struct rte_flow_error error;
>>> int i;
>>>
>>> + /* REPRESENTED_PORT */
>>> + free(CONST_CAST(void *, patterns->items[0].spec));
>>> + free(CONST_CAST(void *, patterns->items[0].mask));
>>> +
>>> 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; @@
>>> -
>>> 1042,7 +1063,8 @@ free_flow_patterns(struct flow_patterns *patterns)
>>> }
>>> }
>>>
>>> - for (i = patterns->tnl_pmd_items_cnt; i < patterns->cnt; i++) {
>>> + for (i = 1 /* REPRESENTED_PORT */ + patterns->tnl_pmd_items_cnt;
>>> + i < patterns->cnt; i++) {
>> Why do we need special freeing of [0] and not keep it here?
>>> if (patterns->items[i].spec) {
>>> free(CONST_CAST(void *, patterns->items[i].spec));
>>> }
>>> @@ -1114,13 +1136,13 @@ vport_to_rte_tunnel(struct netdev *vport,
>>> 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));
>>> + netdev_dpdk_get_port_id(netdev, true));
>>> }
>>> } 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));
>>> + netdev_dpdk_get_port_id(netdev, true));
>>> }
>>> } else {
>>> VLOG_DBG_RL(&rl, "vport type '%s' is not supported", @@
>>> -1382,10
>>> +1404,19 @@ parse_flow_match(struct netdev *netdev,
>>> struct flow_patterns *patterns,
>>> struct match *match) {
>>> + struct netdev *physdev = netdev_ports_get(orig_in_port, netdev-
>>>> dpif_type);
>>> + struct rte_flow_item_ethdev *ethdev_spec = xzalloc(sizeof
>>> *ethdev_spec);
>>> + struct rte_flow_item_ethdev *ethdev_mask = xzalloc(sizeof
>>> + *ethdev_mask);
>>> struct rte_flow_item_eth *eth_spec = NULL, *eth_mask = NULL;
>>> struct flow *consumed_masks;
>>> uint8_t proto = 0;
>>>
>>> + /* Add an explicit traffic source item to the beginning of the
>>> pattern. */
>>> + ethdev_spec->port_id = netdev_dpdk_get_port_id(physdev, false);
>>> + *ethdev_mask = rte_flow_item_ethdev_mask;
>>> + add_flow_pattern(patterns,
>RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT,
>>> + ethdev_spec, ethdev_mask, NULL);
>>> +
>>> consumed_masks = &match->wc.masks;
>>>
>>> if (!flow_tnl_dst_is_set(&match->flow.tunnel)) { @@ -1782,7
>>> +1813,7 @@ add_represented_port_action(struct flow_actions *actions,
>>> struct rte_flow_action_ethdev *ethdev;
>>> int outdev_id;
>>>
>>> - outdev_id = netdev_dpdk_get_port_id(outdev);
>>> + outdev_id = netdev_dpdk_get_port_id(outdev, false);
>>> if (outdev_id < 0) {
>>> return -1;
>>> }
>>> @@ -2322,6 +2353,7 @@ netdev_offload_dpdk_flow_destroy(struct
>>> ufid_to_rte_flow_data *rte_flow_data)
>>> struct netdev *physdev;
>>> struct netdev *netdev;
>>> ovs_u128 *ufid;
>>> + bool transfer;
>>> int ret;
>>>
>>> ovs_mutex_lock(&rte_flow_data->lock);
>>> @@ -2333,12 +2365,13 @@ netdev_offload_dpdk_flow_destroy(struct
>>> ufid_to_rte_flow_data *rte_flow_data)
>>>
>>> rte_flow_data->dead = true;
>>>
>>> + transfer = rte_flow_data->actions_offloaded;
>>> rte_flow = rte_flow_data->rte_flow;
>>> physdev = rte_flow_data->physdev;
>>> netdev = rte_flow_data->netdev;
>>> ufid = &rte_flow_data->ufid;
>>>
>>> - ret = netdev_dpdk_rte_flow_destroy(physdev, rte_flow, &error);
>>> + ret = netdev_dpdk_rte_flow_destroy(physdev, transfer, rte_flow,
>>> + &error);
>>>
>>> if (ret == 0) {
>>> struct netdev_offload_dpdk_data *data; @@ -2353,12 +2386,12
>>> @@ netdev_offload_dpdk_flow_destroy(struct ufid_to_rte_flow_data
>>> *rte_flow_data)
>>> " flow destroy %d ufid " UUID_FMT,
>>> netdev_get_name(netdev), netdev_get_name(physdev),
>>> (intptr_t) rte_flow,
>>> - netdev_dpdk_get_port_id(physdev),
>>> + netdev_dpdk_get_port_id(physdev, transfer),
>>> UUID_ARGS((struct uuid *) ufid));
>>> } else {
>>> VLOG_ERR("Failed flow: %s/%s: flow destroy %d ufid " UUID_FMT,
>>> netdev_get_name(netdev), netdev_get_name(physdev),
>>> - netdev_dpdk_get_port_id(physdev),
>>> + netdev_dpdk_get_port_id(physdev, transfer),
>>> UUID_ARGS((struct uuid *) ufid));
>>> }
>>>
>>> --
>>> 2.20.1
>>
>>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev