Move handling of the individual actions in the netdev_tc_flow_put() function to a separate function that will make recursive action handling easier.
Signed-off-by: Eelco Chaudron <echau...@redhat.com> Acked-by: Mike Pattrick <m...@redhat.com> --- lib/netdev-offload-tc.c | 255 +++++++++++++++++++++++++---------------------- 1 file changed, 138 insertions(+), 117 deletions(-) diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index a41b62758..3c2e8f510 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -1564,6 +1564,139 @@ parse_match_ct_state_to_flower(struct tc_flower *flower, struct match *match) } } +static int +netdev_tc_parse_nl_actions(struct netdev *netdev, struct tc_flower *flower, + struct offload_info *info, + const struct nlattr *actions, size_t actions_len, + bool *recirc_act) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + const struct nlattr *nla; + size_t left; + + NL_ATTR_FOR_EACH (nla, left, actions, actions_len) { + struct tc_action *action; + int err; + + if (flower->action_count >= TCA_ACT_MAX_NUM) { + VLOG_DBG_RL(&rl, "Can only support %d actions", TCA_ACT_MAX_NUM); + return EOPNOTSUPP; + } + + action = &flower->actions[flower->action_count]; + + if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) { + odp_port_t port = nl_attr_get_odp_port(nla); + struct netdev *outdev = netdev_ports_get( + port, netdev_get_dpif_type(netdev)); + + if (!outdev) { + VLOG_DBG_RL(&rl, "Can't find netdev for output port %d", port); + return ENODEV; + } + + if (!netdev_flow_api_equals(netdev, outdev)) { + VLOG_DBG_RL(&rl, + "Flow API provider mismatch between ingress (%s) " + "and egress (%s) ports", + netdev_get_name(netdev), netdev_get_name(outdev)); + netdev_close(outdev); + return EOPNOTSUPP; + } + + action->out.ifindex_out = netdev_get_ifindex(outdev); + if (action->out.ifindex_out < 0) { + VLOG_DBG_RL(&rl, + "Can't find ifindex for output port %s, error %d", + netdev_get_name(outdev), action->out.ifindex_out); + netdev_close(outdev); + return -action->out.ifindex_out; + } + + action->out.ingress = is_internal_port(netdev_get_type(outdev)); + action->type = TC_ACT_OUTPUT; + flower->action_count++; + netdev_close(outdev); + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_PUSH_VLAN) { + const struct ovs_action_push_vlan *vlan_push = nl_attr_get(nla); + + action->vlan.vlan_push_tpid = vlan_push->vlan_tpid; + action->vlan.vlan_push_id = vlan_tci_to_vid(vlan_push->vlan_tci); + action->vlan.vlan_push_prio = vlan_tci_to_pcp(vlan_push->vlan_tci); + action->type = TC_ACT_VLAN_PUSH; + flower->action_count++; + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_VLAN) { + action->type = TC_ACT_VLAN_POP; + flower->action_count++; + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_PUSH_MPLS) { + const struct ovs_action_push_mpls *mpls_push = nl_attr_get(nla); + + action->mpls.proto = mpls_push->mpls_ethertype; + action->mpls.label = mpls_lse_to_label(mpls_push->mpls_lse); + action->mpls.tc = mpls_lse_to_tc(mpls_push->mpls_lse); + action->mpls.ttl = mpls_lse_to_ttl(mpls_push->mpls_lse); + action->mpls.bos = mpls_lse_to_bos(mpls_push->mpls_lse); + action->type = TC_ACT_MPLS_PUSH; + flower->action_count++; + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_MPLS) { + action->mpls.proto = nl_attr_get_be16(nla); + action->type = TC_ACT_MPLS_POP; + flower->action_count++; + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET) { + const struct nlattr *set = nl_attr_get(nla); + const size_t set_len = nl_attr_get_size(nla); + + err = parse_put_flow_set_action(flower, action, set, set_len); + if (err) { + return err; + } + if (action->type == TC_ACT_ENCAP) { + action->encap.tp_dst = info->tp_dst_port; + action->encap.no_csum = !info->tunnel_csum_on; + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) { + const struct nlattr *set = nl_attr_get(nla); + const size_t set_len = nl_attr_get_size(nla); + + err = parse_put_flow_set_masked_action(flower, action, set, + set_len, true); + if (err) { + return err; + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) { + const struct nlattr *ct = nl_attr_get(nla); + const size_t ct_len = nl_attr_get_size(nla); + + if (!ct_state_support) { + return -EOPNOTSUPP; + } + + err = parse_put_flow_ct_action(flower, action, ct, ct_len); + if (err) { + return err; + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT_CLEAR) { + action->type = TC_ACT_CT; + action->ct.clear = true; + flower->action_count++; + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) { + action->type = TC_ACT_GOTO; + action->chain = nl_attr_get_u32(nla); + flower->action_count++; + *recirc_act = true; + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_DROP) { + action->type = TC_ACT_GOTO; + action->chain = 0; /* 0 is reserved and not used by recirc. */ + flower->action_count++; + } else { + VLOG_DBG_RL(&rl, "unsupported put action type: %d", + nl_attr_type(nla)); + return EOPNOTSUPP; + } + } + return 0; +} + static int netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct nlattr *actions, size_t actions_len, @@ -1577,13 +1710,10 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct flow *mask = &match->wc.masks; const struct flow_tnl *tnl = &match->flow.tunnel; const struct flow_tnl *tnl_mask = &mask->tunnel; - struct tc_action *action; bool recirc_act = false; uint32_t block_id = 0; - struct nlattr *nla; struct tcf_id id; uint32_t chain; - size_t left; int prio = 0; int ifindex; int err; @@ -1828,120 +1958,11 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, return err; } - NL_ATTR_FOR_EACH(nla, left, actions, actions_len) { - if (flower.action_count >= TCA_ACT_MAX_NUM) { - VLOG_DBG_RL(&rl, "Can only support %d actions", TCA_ACT_MAX_NUM); - return EOPNOTSUPP; - } - action = &flower.actions[flower.action_count]; - if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) { - odp_port_t port = nl_attr_get_odp_port(nla); - struct netdev *outdev = netdev_ports_get( - port, netdev_get_dpif_type(netdev)); - - if (!outdev) { - VLOG_DBG_RL(&rl, "Can't find netdev for output port %d", port); - return ENODEV; - } - - if (!netdev_flow_api_equals(netdev, outdev)) { - VLOG_DBG_RL(&rl, - "Flow API provider mismatch between ingress (%s) " - "and egress (%s) ports", - netdev_get_name(netdev), netdev_get_name(outdev)); - netdev_close(outdev); - return EOPNOTSUPP; - } - - action->out.ifindex_out = netdev_get_ifindex(outdev); - if (action->out.ifindex_out < 0) { - VLOG_DBG_RL(&rl, - "Can't find ifindex for output port %s, error %d", - netdev_get_name(outdev), action->out.ifindex_out); - netdev_close(outdev); - return -action->out.ifindex_out; - } - - action->out.ingress = is_internal_port(netdev_get_type(outdev)); - action->type = TC_ACT_OUTPUT; - flower.action_count++; - netdev_close(outdev); - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_PUSH_VLAN) { - const struct ovs_action_push_vlan *vlan_push = nl_attr_get(nla); - - action->vlan.vlan_push_tpid = vlan_push->vlan_tpid; - action->vlan.vlan_push_id = vlan_tci_to_vid(vlan_push->vlan_tci); - action->vlan.vlan_push_prio = vlan_tci_to_pcp(vlan_push->vlan_tci); - action->type = TC_ACT_VLAN_PUSH; - flower.action_count++; - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_VLAN) { - action->type = TC_ACT_VLAN_POP; - flower.action_count++; - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_PUSH_MPLS) { - const struct ovs_action_push_mpls *mpls_push = nl_attr_get(nla); - - action->mpls.proto = mpls_push->mpls_ethertype; - action->mpls.label = mpls_lse_to_label(mpls_push->mpls_lse); - action->mpls.tc = mpls_lse_to_tc(mpls_push->mpls_lse); - action->mpls.ttl = mpls_lse_to_ttl(mpls_push->mpls_lse); - action->mpls.bos = mpls_lse_to_bos(mpls_push->mpls_lse); - action->type = TC_ACT_MPLS_PUSH; - flower.action_count++; - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_MPLS) { - action->mpls.proto = nl_attr_get_be16(nla); - action->type = TC_ACT_MPLS_POP; - flower.action_count++; - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET) { - const struct nlattr *set = nl_attr_get(nla); - const size_t set_len = nl_attr_get_size(nla); - - err = parse_put_flow_set_action(&flower, action, set, set_len); - if (err) { - return err; - } - if (action->type == TC_ACT_ENCAP) { - action->encap.tp_dst = info->tp_dst_port; - action->encap.no_csum = !info->tunnel_csum_on; - } - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) { - const struct nlattr *set = nl_attr_get(nla); - const size_t set_len = nl_attr_get_size(nla); - - err = parse_put_flow_set_masked_action(&flower, action, set, - set_len, true); - if (err) { - return err; - } - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) { - const struct nlattr *ct = nl_attr_get(nla); - const size_t ct_len = nl_attr_get_size(nla); - - if (!ct_state_support) { - return -EOPNOTSUPP; - } - - err = parse_put_flow_ct_action(&flower, action, ct, ct_len); - if (err) { - return err; - } - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT_CLEAR) { - action->type = TC_ACT_CT; - action->ct.clear = true; - flower.action_count++; - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) { - action->type = TC_ACT_GOTO; - action->chain = nl_attr_get_u32(nla); - flower.action_count++; - recirc_act = true; - } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_DROP) { - action->type = TC_ACT_GOTO; - action->chain = 0; /* 0 is reserved and not used by recirc. */ - flower.action_count++; - } else { - VLOG_DBG_RL(&rl, "unsupported put action type: %d", - nl_attr_type(nla)); - return EOPNOTSUPP; - } + /* Parse all (nested) actions. */ + err = netdev_tc_parse_nl_actions(netdev, &flower, info, + actions, actions_len, &recirc_act); + if (err) { + return err; } if ((chain || recirc_act) && !info->recirc_id_shared_with_tc) { _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev