If the output-port is a vhost-user port and the action is POP_VLAN, offload the action on the ingress device if it is offload capable.
Note: - With ingress partial action offload, the flow must be added to the mark-to-flow table. Otherwise, since the action (e.g, POP_VLAN) is already performed in the HW, the flow can't be located in the datapath flow tables and caches. - The mark action is offloaded implicitly to facilitate this mark-to-flow lookup. - Add a new member 'partial_actions_offloaded' to the info structure passed to the offload layer. When the offload layer successfully offloads the partial action, it indicates this to the dpif-netdev layer through this flag. This is needed by the dpif-netdev layer to distinguish partial offload (i.e, classification offload or mark,rss actions) from partial actions offload (classification + some actions, e.g vlan-pop,mark actions) in ingress direction. Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapa...@broadcom.com> --- lib/dpif-netdev.c | 114 ++++++++++++++++++++++++++++++++++++-- lib/netdev-offload-dpdk.c | 26 +++++++-- lib/netdev-offload.h | 1 + lib/odp-execute.c | 8 +-- 4 files changed, 132 insertions(+), 17 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index bfb016059..3f295ca33 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -115,6 +115,7 @@ COVERAGE_DEFINE(datapath_drop_invalid_tnl_port); COVERAGE_DEFINE(datapath_drop_rx_invalid_packet); COVERAGE_DEFINE(datapath_skip_tunnel_push); COVERAGE_DEFINE(datapath_skip_vlan_push); +COVERAGE_DEFINE(datapath_skip_vlan_pop); /* Protects against changes to 'dp_netdevs'. */ static struct ovs_mutex dp_netdev_mutex = OVS_MUTEX_INITIALIZER; @@ -2565,6 +2566,18 @@ enum num_action_attr_egress { MAX_ACTION_ATTRS_EGRESS = TUNNEL_PUSH_ATTRS }; +/* + * Maxium number of actions to be parsed while selecting a flow for ingress + * partial action offload. This number is currently based on the minimum + * number of attributes seen with the vlan pop action (vlan_pop, output). + * This number includes output action to a single vhost device (uplink) and + * does not support multiple output actions. + */ +enum num_action_attr_ingress { + VLAN_POP_ATTRS = 2, /* vlan_pop, output */ + MAX_ACTION_ATTRS_INGRESS = VLAN_POP_ATTRS +}; + /* * This function parses the list of OVS "actions" of length "actions_len", * and returns them in an array of action "attrs", of size "max_attrs". @@ -2678,6 +2691,83 @@ should_partial_offload_egress(struct netdev *in_netdev, return true; } +/* This function determines if the given flow should be partially offloaded + * on the ingress device, when the out-port is not offload-capable like a + * vhost-user port. The function currently supports offloading of only + * vlan-pop action. + */ +static bool +should_partial_offload_ingress(struct netdev *in_netdev, + struct dp_flow_offload_item *offload) +{ + const char *dpif_type_str = + dpif_normalize_type(offload->pmd->dp->class->type); + struct action_attr attrs[MAX_ACTION_ATTRS_INGRESS]; + odp_port_t out_port = ODPP_NONE; + struct netdev *out_netdev; + int num_attrs = 0; + int type; + int rc; + + /* Support ingress partial-offload only + * when the in-port supports offloads. + */ + if (!netdev_dpdk_flow_api_supported(in_netdev)) { + return false; + } + + rc = parse_nlattr_actions(offload->actions, offload->actions_len, attrs, + MAX_ACTION_ATTRS_INGRESS, &num_attrs); + if (rc == E2BIG) { + /* Action list too big; decline partial offload */ + return false; + } + + /* Minimum number of attrs expected (pop_vlan) */ + if (num_attrs < VLAN_POP_ATTRS) { + return false; + } + + if (num_attrs == VLAN_POP_ATTRS && + (attrs[0].type != OVS_ACTION_ATTR_POP_VLAN || + attrs[1].type != OVS_ACTION_ATTR_OUTPUT)) { + return false; + } + + /* Ingress partial-offload needs an output action at the end. */ + out_port = nl_attr_get_odp_port(attrs[num_attrs - 1].action); + if (out_port == ODPP_NONE) { + return false; + } + + /* Support ingress partial-offload only if out-port is vhost-user. */ + out_netdev = netdev_ports_get(out_port, dpif_type_str); + if (out_netdev && is_dpdk_vhost_netdev(out_netdev)) { + return true; + } + + return false; +} + +/* This function determines if the given flow actions can be partially + * offloaded. Partial action offload is attempted when either the in-port + * or the out-port for the flow is a vhost-user port. + */ +static bool +should_partial_offload(struct netdev *in_netdev, + struct dp_flow_offload_item *offload, + struct netdev **egress_netdev) +{ + if (should_partial_offload_ingress(in_netdev, offload)) { + return true; + } else if (should_partial_offload_egress(in_netdev, offload, + egress_netdev)) { + return true; + } else { + return false; + } +} + static int dp_netdev_alloc_flow_mark(struct dp_netdev_flow *flow, bool modification, uint32_t *markp) @@ -2752,8 +2842,9 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload) info.attr_egress = 0; info.partial_actions = 0; + info.partial_actions_offloaded = 0; - if (unlikely(should_partial_offload_egress(port, offload, &egress_port))) { + if (unlikely(should_partial_offload(port, offload, &egress_port))) { if (egress_port) { netdev_close(port); port = egress_port; @@ -2785,12 +2876,14 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload) goto err_free; } - if (unlikely(info.partial_actions && egress_port)) { + if (unlikely(info.partial_actions && info.partial_actions_offloaded)) { VLOG_DBG_RL("%s: flow: %p mega_ufid: "UUID_FMT" pmd_id: %d\n", __func__, flow, UUID_ARGS((struct uuid *)&flow->mega_ufid), flow->pmd_id); flow->partial_actions_offloaded = true; - } else if (!modification) { + } + + if (!modification && alloc_mark) { megaflow_to_mark_associate(&flow->mega_ufid, mark); mark_to_flow_associate(mark, flow); } @@ -8009,7 +8102,20 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, break; } - case OVS_ACTION_ATTR_POP_VLAN: + case OVS_ACTION_ATTR_POP_VLAN: { + struct dp_packet *packet; + + if (!dp_flow || !dp_flow->partial_actions_offloaded) { + DP_PACKET_BATCH_FOR_EACH (i, packet, packets_) { + eth_pop_vlan(packet); + } + } else { + packet_count = dp_packet_batch_size(packets_); + COVERAGE_ADD(datapath_skip_vlan_pop, packet_count); + } + break; + } + case OVS_ACTION_ATTR_PUSH_MPLS: case OVS_ACTION_ATTR_POP_MPLS: case OVS_ACTION_ATTR_SET: diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c index 6434b926d..020f9cb4c 100644 --- a/lib/netdev-offload-dpdk.c +++ b/lib/netdev-offload-dpdk.c @@ -1346,8 +1346,11 @@ parse_flow_actions(struct netdev *netdev, } NL_ATTR_FOR_EACH_UNSAFE (nla, left, nl_actions, nl_actions_len) { if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) { - if (add_output_action(netdev, actions, nla)) { - return -1; + /* add output action only if full-offload */ + if (!info->partial_actions) { + if (add_output_action(netdev, actions, nla)) { + return -1; + } } } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_DROP) { add_flow_action(actions, RTE_FLOW_ACTION_TYPE_DROP, NULL); @@ -1389,6 +1392,13 @@ parse_flow_actions(struct netdev *netdev, return -1; } + if (info->partial_actions && !info->attr_egress) { + struct rte_flow_action_mark *mark = xzalloc(sizeof *mark); + + mark->id = info->flow_mark; + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_MARK, mark); + } + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_END, NULL); return 0; } @@ -1406,9 +1416,11 @@ netdev_offload_dpdk_actions(struct netdev *netdev, struct rte_flow_error error; int ret; - if (info->attr_egress) { - flow_attr.ingress = 0; - flow_attr.egress = 1; + if (info->partial_actions) { + if (info->attr_egress) { + flow_attr.ingress = 0; + flow_attr.egress = 1; + } flow_attr.transfer = 0; } @@ -1446,11 +1458,12 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, flow = netdev_offload_dpdk_actions(netdev, &patterns, nl_actions, actions_len, info); if (flow) { - if (info->partial_actions && info->attr_egress) { + if (info->partial_actions) { /* actions_offloaded should be set to false with partial actions, * since it is still considered as partial-offload and not * full-offload. */ actions_offloaded = false; + info->partial_actions_offloaded = 1; } } else if (!(info->partial_actions && info->attr_egress)) { /* If we failed to offload the rule actions fallback to MARK+RSS @@ -1517,6 +1530,7 @@ netdev_offload_dpdk_flow_put(struct netdev *netdev, struct match *match, VLOG_DBG_RL("%s: mega_ufid: "UUID_FMT" refcnt: %d\n", __func__, UUID_ARGS((struct uuid *)ufid), rte_flow_data->refcnt); rte_flow_data->refcnt++; + info->partial_actions_offloaded = 1; return ret; } else { /* diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h index 55fcc711c..999cacbbc 100644 --- a/lib/netdev-offload.h +++ b/lib/netdev-offload.h @@ -69,6 +69,7 @@ struct offload_info { * sync with datapath recirc ids. */ uint8_t attr_egress; /* Egress direction offload */ uint8_t partial_actions; /* Partial action offload; no forward action */ + uint8_t partial_actions_offloaded; /* Success flag */ /* * The flow mark id assigened to the flow. If any pkts hit the flow, diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 412e96b82..b44b4f29f 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -802,11 +802,11 @@ requires_datapath_assistance(const struct nlattr *a) case OVS_ACTION_ATTR_CT: case OVS_ACTION_ATTR_METER: case OVS_ACTION_ATTR_PUSH_VLAN: + case OVS_ACTION_ATTR_POP_VLAN: return true; case OVS_ACTION_ATTR_SET: case OVS_ACTION_ATTR_SET_MASKED: - case OVS_ACTION_ATTR_POP_VLAN: case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_HASH: case OVS_ACTION_ATTR_PUSH_MPLS: @@ -924,12 +924,6 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, break; } - case OVS_ACTION_ATTR_POP_VLAN: - DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { - eth_pop_vlan(packet); - } - break; - case OVS_ACTION_ATTR_PUSH_MPLS: { const struct ovs_action_push_mpls *mpls = nl_attr_get(a); -- 2.25.0.rc2 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev