From patchwork Tue Apr 10 05:18:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 896484 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Kwch58mBz9s0R for ; Tue, 10 Apr 2018 15:25:56 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 7A617D07; Tue, 10 Apr 2018 05:25:03 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 78D6FCDA for ; Tue, 10 Apr 2018 05:25:01 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp1.linuxfoundation.org (Postfix) with ESMTP id 70018674 for ; Tue, 10 Apr 2018 05:24:59 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from chrism@mellanox.com) with ESMTPS (AES256-SHA encrypted); 10 Apr 2018 08:19:24 +0300 Received: from dev-r630-03.mtbc.labs.mlnx. (dev-r630-03.mtbc.labs.mlnx [10.12.205.13]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id w3A5IBJb015081; Tue, 10 Apr 2018 08:18:14 +0300 From: Chris Mi To: dev@openvswitch.org Date: Tue, 10 Apr 2018 14:18:08 +0900 Message-Id: <20180410051809.23502-2-chrism@mellanox.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180410051809.23502-1-chrism@mellanox.com> References: <20180410051809.23502-1-chrism@mellanox.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: simon.horman@netronome.com Subject: [ovs-dev] [ovs-dev 1/2] tc: Make the actions order consistent X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org When OVS DP passes the actions to TC library, we save all the actions in data structure tc_flower and each action type has its own field in tc_flower. So when TC library passes the actions to kernel, actually the actions order is lost. We add an actions array in tc_flower to keep the actions order in this patch. Issue: 1321102 Change-Id: If1d96eb3d1dc3b482667f456d2222dcddb17ac4c Signed-off-by: Chris Mi Reviewed-by: Paul Blakey Reviewed-by: Roi Dayan --- lib/netdev-tc-offloads.c | 182 +++++++++++++++++++++++++++-------------------- lib/tc.c | 158 ++++++++++++++++++++++++---------------- lib/tc.h | 57 +++++++++------ 3 files changed, 238 insertions(+), 159 deletions(-) diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c index 6db76801f..101b2ffb1 100644 --- a/lib/netdev-tc-offloads.c +++ b/lib/netdev-tc-offloads.c @@ -393,18 +393,14 @@ parse_tc_flower_to_match(struct tc_flower *flower, struct match *match, struct nlattr **actions, struct dpif_flow_stats *stats, - struct ofpbuf *buf) { + struct ofpbuf *buf) +{ size_t act_off; struct tc_flower_key *key = &flower->key; struct tc_flower_key *mask = &flower->mask; odp_port_t outport = 0; - - if (flower->ifindex_out) { - outport = netdev_ifindex_to_odp_port(flower->ifindex_out); - if (!outport) { - return ENOENT; - } - } + struct tc_action *action; + int i; ofpbuf_clear(buf); @@ -487,60 +483,71 @@ parse_tc_flower_to_match(struct tc_flower *flower, act_off = nl_msg_start_nested(buf, OVS_FLOW_ATTR_ACTIONS); { - if (flower->vlan_pop) { - nl_msg_put_flag(buf, OVS_ACTION_ATTR_POP_VLAN); - } - - if (flower->vlan_push_id || flower->vlan_push_prio) { - struct ovs_action_push_vlan *push; - push = nl_msg_put_unspec_zero(buf, OVS_ACTION_ATTR_PUSH_VLAN, - sizeof *push); - - push->vlan_tpid = htons(ETH_TYPE_VLAN); - push->vlan_tci = htons(flower->vlan_push_id - | (flower->vlan_push_prio << 13) - | VLAN_CFI); - } - - if (flower->rewrite.rewrite) { - parse_flower_rewrite_to_netlink_action(buf, flower); - } - - if (flower->set.set) { - size_t set_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_SET); - size_t tunnel_offset = - nl_msg_start_nested(buf, OVS_KEY_ATTR_TUNNEL); - - nl_msg_put_be64(buf, OVS_TUNNEL_KEY_ATTR_ID, flower->set.id); - if (flower->set.ipv4.ipv4_src) { - nl_msg_put_be32(buf, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, - flower->set.ipv4.ipv4_src); - } - if (flower->set.ipv4.ipv4_dst) { - nl_msg_put_be32(buf, OVS_TUNNEL_KEY_ATTR_IPV4_DST, - flower->set.ipv4.ipv4_dst); + action = flower->actions; + for (i = 0; i < flower->action_count; i++, action++) { + switch (action->type) { + case TC_ACT_VLAN_POP: { + nl_msg_put_flag(buf, OVS_ACTION_ATTR_POP_VLAN); } - if (!is_all_zeros(&flower->set.ipv6.ipv6_src, - sizeof flower->set.ipv6.ipv6_src)) { - nl_msg_put_in6_addr(buf, OVS_TUNNEL_KEY_ATTR_IPV6_SRC, - &flower->set.ipv6.ipv6_src); + break; + case TC_ACT_VLAN_PUSH: { + struct ovs_action_push_vlan *push; + + push = nl_msg_put_unspec_zero(buf, OVS_ACTION_ATTR_PUSH_VLAN, + sizeof *push); + push->vlan_tpid = htons(ETH_TYPE_VLAN); + push->vlan_tci = htons(action->vlan.vlan_push_id + | (action->vlan.vlan_push_prio << 13) + | VLAN_CFI); } - if (!is_all_zeros(&flower->set.ipv6.ipv6_dst, - sizeof flower->set.ipv6.ipv6_dst)) { - nl_msg_put_in6_addr(buf, OVS_TUNNEL_KEY_ATTR_IPV6_DST, - &flower->set.ipv6.ipv6_dst); + break; + case TC_ACT_PEDIT: { + parse_flower_rewrite_to_netlink_action(buf, flower); } - nl_msg_put_be16(buf, OVS_TUNNEL_KEY_ATTR_TP_DST, - flower->set.tp_dst); - - nl_msg_end_nested(buf, tunnel_offset); - nl_msg_end_nested(buf, set_offset); - } + break; + case TC_ACT_ENCAP: { + size_t set_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_SET); + size_t tunnel_offset = + nl_msg_start_nested(buf, OVS_KEY_ATTR_TUNNEL); + + nl_msg_put_be64(buf, OVS_TUNNEL_KEY_ATTR_ID, action->encap.id); + if (action->encap.ipv4.ipv4_src) { + nl_msg_put_be32(buf, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, + action->encap.ipv4.ipv4_src); + } + if (action->encap.ipv4.ipv4_dst) { + nl_msg_put_be32(buf, OVS_TUNNEL_KEY_ATTR_IPV4_DST, + action->encap.ipv4.ipv4_dst); + } + if (!is_all_zeros(&action->encap.ipv6.ipv6_src, + sizeof action->encap.ipv6.ipv6_src)) { + nl_msg_put_in6_addr(buf, OVS_TUNNEL_KEY_ATTR_IPV6_SRC, + &action->encap.ipv6.ipv6_src); + } + if (!is_all_zeros(&action->encap.ipv6.ipv6_dst, + sizeof action->encap.ipv6.ipv6_dst)) { + nl_msg_put_in6_addr(buf, OVS_TUNNEL_KEY_ATTR_IPV6_DST, + &action->encap.ipv6.ipv6_dst); + } + nl_msg_put_be16(buf, OVS_TUNNEL_KEY_ATTR_TP_DST, + action->encap.tp_dst); - if (flower->ifindex_out > 0) { - nl_msg_put_u32(buf, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(outport)); + nl_msg_end_nested(buf, tunnel_offset); + nl_msg_end_nested(buf, set_offset); + } + break; + case TC_ACT_OUTPUT: { + if (action->ifindex_out) { + outport = netdev_ifindex_to_odp_port(action->ifindex_out); + if (!outport) { + return ENOENT; + } + } + nl_msg_put_u32(buf, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(outport)); + } + break; + } } - } nl_msg_end_nested(buf, act_off); @@ -597,6 +604,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, static int parse_put_flow_set_masked_action(struct tc_flower *flower, + struct tc_action *action, const struct nlattr *set, size_t set_len, bool hasmask) @@ -649,7 +657,11 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, } if (!is_all_zeros(&flower->rewrite, sizeof flower->rewrite)) { - flower->rewrite.rewrite = true; + if (flower->rewrite.rewrite == false) { + flower->rewrite.rewrite = true; + action->type = TC_ACT_PEDIT; + flower->action_count++; + } } if (hasmask && !is_all_zeros(set_mask, size)) { @@ -664,52 +676,53 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, } static int -parse_put_flow_set_action(struct tc_flower *flower, const struct nlattr *set, - size_t set_len) +parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action, + const struct nlattr *set, size_t set_len) { const struct nlattr *tunnel; const struct nlattr *tun_attr; size_t tun_left, tunnel_len; if (nl_attr_type(set) != OVS_KEY_ATTR_TUNNEL) { - return parse_put_flow_set_masked_action(flower, set, set_len, - false); + return parse_put_flow_set_masked_action(flower, action, set, + set_len, false); } tunnel = nl_attr_get(set); tunnel_len = nl_attr_get_size(set); - flower->set.set = true; + action->type = TC_ACT_ENCAP; + flower->action_count++; NL_ATTR_FOR_EACH_UNSAFE(tun_attr, tun_left, tunnel, tunnel_len) { switch (nl_attr_type(tun_attr)) { case OVS_TUNNEL_KEY_ATTR_ID: { - flower->set.id = nl_attr_get_be64(tun_attr); + action->encap.id = nl_attr_get_be64(tun_attr); } break; case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: { - flower->set.ipv4.ipv4_src = nl_attr_get_be32(tun_attr); + action->encap.ipv4.ipv4_src = nl_attr_get_be32(tun_attr); } break; case OVS_TUNNEL_KEY_ATTR_IPV4_DST: { - flower->set.ipv4.ipv4_dst = nl_attr_get_be32(tun_attr); + action->encap.ipv4.ipv4_dst = nl_attr_get_be32(tun_attr); } break; case OVS_TUNNEL_KEY_ATTR_IPV6_SRC: { - flower->set.ipv6.ipv6_src = + action->encap.ipv6.ipv6_src = nl_attr_get_in6_addr(tun_attr); } break; case OVS_TUNNEL_KEY_ATTR_IPV6_DST: { - flower->set.ipv6.ipv6_dst = + action->encap.ipv6.ipv6_dst = nl_attr_get_in6_addr(tun_attr); } break; case OVS_TUNNEL_KEY_ATTR_TP_SRC: { - flower->set.tp_src = nl_attr_get_be16(tun_attr); + action->encap.tp_src = nl_attr_get_be16(tun_attr); } break; case OVS_TUNNEL_KEY_ATTR_TP_DST: { - flower->set.tp_dst = nl_attr_get_be16(tun_attr); + action->encap.tp_dst = nl_attr_get_be16(tun_attr); } break; } @@ -865,6 +878,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, const struct flow *key = &match->flow; struct flow *mask = &match->wc.masks; const struct flow_tnl *tnl = &match->flow.tunnel; + struct tc_action *action; struct nlattr *nla; size_t left; int prio = 0; @@ -1019,34 +1033,46 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, } NL_ATTR_FOR_EACH(nla, left, actions, actions_len) { + if (flower.action_count >= TCA_ACT_MAX_PRIO) { + VLOG_DBG_RL(&rl, "Can only support %d actions", flower.action_count); + 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, info->dpif_class); - flower.ifindex_out = netdev_get_ifindex(outdev); - flower.set.tp_dst = info->tp_dst_port; + action->ifindex_out = netdev_get_ifindex(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); - flower.vlan_push_id = vlan_tci_to_vid(vlan_push->vlan_tci); - flower.vlan_push_prio = vlan_tci_to_pcp(vlan_push->vlan_tci); + 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) { - flower.vlan_pop = 1; + action->type = TC_ACT_VLAN_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, set, set_len); + 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; + } } 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, set, set_len, - true); + err = parse_put_flow_set_masked_action(&flower, action, set, + set_len, true); if (err) { return err; } diff --git a/lib/tc.c b/lib/tc.c index 6daa44710..aeec94ac7 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -469,6 +469,7 @@ static const struct nl_policy pedit_policy[] = { static int nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower) { + struct tc_action *action; struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)]; const struct tc_pedit *pe; const struct tc_pedit_key *keys; @@ -548,7 +549,8 @@ nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower) i++; } - flower->rewrite.rewrite = true; + action = &flower->actions[flower->action_count++]; + action->type = TC_ACT_PEDIT; return 0; } @@ -575,6 +577,7 @@ nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower) struct nlattr *tun_attrs[ARRAY_SIZE(tunnel_key_policy)]; const struct nlattr *tun_parms; const struct tc_tunnel_key *tun; + struct tc_action *action; if (!nl_parse_nested(options, tunnel_key_policy, tun_attrs, ARRAY_SIZE(tunnel_key_policy))) { @@ -592,17 +595,18 @@ nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower) struct nlattr *ipv6_src = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV6_SRC]; struct nlattr *ipv6_dst = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV6_DST]; - flower->set.set = true; - flower->set.ipv4.ipv4_src = ipv4_src ? nl_attr_get_be32(ipv4_src) : 0; - flower->set.ipv4.ipv4_dst = ipv4_dst ? nl_attr_get_be32(ipv4_dst) : 0; + action = &flower->actions[flower->action_count++]; + action->type = TC_ACT_ENCAP; + action->encap.ipv4.ipv4_src = ipv4_src ? nl_attr_get_be32(ipv4_src) : 0; + action->encap.ipv4.ipv4_dst = ipv4_dst ? nl_attr_get_be32(ipv4_dst) : 0; if (ipv6_src) { - flower->set.ipv6.ipv6_src = nl_attr_get_in6_addr(ipv6_src); + action->encap.ipv6.ipv6_src = nl_attr_get_in6_addr(ipv6_src); } if (ipv6_dst) { - flower->set.ipv6.ipv6_dst = nl_attr_get_in6_addr(ipv6_dst); + action->encap.ipv6.ipv6_dst = nl_attr_get_in6_addr(ipv6_dst); } - flower->set.id = id ? be32_to_be64(nl_attr_get_be32(id)) : 0; - flower->set.tp_dst = dst_port ? nl_attr_get_be16(dst_port) : 0; + action->encap.id = id ? be32_to_be64(nl_attr_get_be32(id)) : 0; + action->encap.tp_dst = dst_port ? nl_attr_get_be16(dst_port) : 0; } else if (tun->t_action == TCA_TUNNEL_KEY_ACT_RELEASE) { flower->tunnel.tunnel = true; } else { @@ -688,6 +692,7 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower) const struct nlattr *mirred_parms; const struct tcf_t *tm; struct nlattr *mirred_tm; + struct tc_action *action; if (!nl_parse_nested(options, mirred_policy, mirred_attrs, ARRAY_SIZE(mirred_policy))) { @@ -698,13 +703,15 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower) mirred_parms = mirred_attrs[TCA_MIRRED_PARMS]; m = nl_attr_get_unspec(mirred_parms, sizeof *m); - if (m->action != TC_ACT_STOLEN || m->eaction != TCA_EGRESS_REDIR) { + if (m->eaction != TCA_EGRESS_REDIR && m->eaction != TCA_EGRESS_MIRROR) { VLOG_ERR_RL(&error_rl, "unknown mirred action: %d, %d, %d", - m->action, m->eaction, m->ifindex); + m->action, m->eaction, m->ifindex); return EINVAL; } - flower->ifindex_out = m->ifindex; + action = &flower->actions[flower->action_count++]; + action->ifindex_out = m->ifindex; + action->type = TC_ACT_OUTPUT; mirred_tm = mirred_attrs[TCA_MIRRED_TM]; tm = nl_attr_get_unspec(mirred_tm, sizeof *tm); @@ -728,6 +735,7 @@ nl_parse_act_vlan(struct nlattr *options, struct tc_flower *flower) struct nlattr *vlan_attrs[ARRAY_SIZE(vlan_policy)]; const struct tc_vlan *v; const struct nlattr *vlan_parms; + struct tc_action *action; if (!nl_parse_nested(options, vlan_policy, vlan_attrs, ARRAY_SIZE(vlan_policy))) { @@ -735,16 +743,18 @@ nl_parse_act_vlan(struct nlattr *options, struct tc_flower *flower) return EPROTO; } + action = &flower->actions[flower->action_count++]; vlan_parms = vlan_attrs[TCA_VLAN_PARMS]; v = nl_attr_get_unspec(vlan_parms, sizeof *v); if (v->v_action == TCA_VLAN_ACT_PUSH) { struct nlattr *vlan_id = vlan_attrs[TCA_VLAN_PUSH_VLAN_ID]; struct nlattr *vlan_prio = vlan_attrs[TCA_VLAN_PUSH_VLAN_PRIORITY]; - flower->vlan_push_id = nl_attr_get_u16(vlan_id); - flower->vlan_push_prio = vlan_prio ? nl_attr_get_u8(vlan_prio) : 0; + action->vlan.vlan_push_id = nl_attr_get_u16(vlan_id); + action->vlan.vlan_push_prio = vlan_prio ? nl_attr_get_u8(vlan_prio) : 0; + action->type = TC_ACT_VLAN_PUSH; } else if (v->v_action == TCA_VLAN_ACT_POP) { - flower->vlan_pop = 1; + action->type = TC_ACT_VLAN_POP; } else { VLOG_ERR_RL(&error_rl, "unknown vlan action: %d, %d", v->action, v->v_action); @@ -893,7 +903,13 @@ nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower) for (int i = TCA_ACT_MIN_PRIO; i < max_size; i++) { if (actions_orders[i]) { - int err = nl_parse_single_action(actions_orders[i], flower); + int err; + + if (flower->action_count >= TCA_ACT_MAX_PRIO) { + VLOG_DBG_RL(&error_rl, "Can only support %d actions", flower->action_count); + return EOPNOTSUPP; + } + err = nl_parse_single_action(actions_orders[i], flower); if (err) { return err; @@ -1372,64 +1388,84 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) { size_t offset; size_t act_offset; + uint16_t act_index = 1; + struct tc_action *action; + int i, ifindex = 0; offset = nl_msg_start_nested(request, TCA_FLOWER_ACT); { - uint16_t act_index = 1; int error; - if (flower->rewrite.rewrite) { + if (flower->tunnel.tunnel) { act_offset = nl_msg_start_nested(request, act_index++); - error = nl_msg_put_flower_rewrite_pedits(request, flower); - if (error) { - return error; - } + nl_msg_put_act_tunnel_key_release(request); nl_msg_end_nested(request, act_offset); + } - if (flower->csum_update_flags) { + action = flower->actions; + for (i = 0; i < flower->action_count; i++, action++) { + switch (action->type) { + case TC_ACT_PEDIT: { act_offset = nl_msg_start_nested(request, act_index++); - nl_msg_put_act_csum(request, flower->csum_update_flags); + error = nl_msg_put_flower_rewrite_pedits(request, flower); + if (error) { + return error; + } nl_msg_end_nested(request, act_offset); + + if (flower->csum_update_flags) { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_csum(request, flower->csum_update_flags); + nl_msg_end_nested(request, act_offset); + } + } + break; + case TC_ACT_ENCAP: { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_tunnel_key_set(request, action->encap.id, + action->encap.ipv4.ipv4_src, + action->encap.ipv4.ipv4_dst, + &action->encap.ipv6.ipv6_src, + &action->encap.ipv6.ipv6_dst, + action->encap.tp_dst); + nl_msg_end_nested(request, act_offset); + } + break; + case TC_ACT_VLAN_POP: { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_pop_vlan(request); + nl_msg_end_nested(request, act_offset); + } + break; + case TC_ACT_VLAN_PUSH: { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_push_vlan(request, + action->vlan.vlan_push_id, + action->vlan.vlan_push_prio); + nl_msg_end_nested(request, act_offset); + } + break; + case TC_ACT_OUTPUT: { + ifindex = action->ifindex_out; + if (ifindex < 1) { + VLOG_ERR_RL(&error_rl, "%s: invalid ifindex: %d, type: %d", + __func__, ifindex, action->type); + return EINVAL; + } + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_redirect(request, ifindex); + nl_msg_put_act_cookie(request, &flower->act_cookie); + nl_msg_end_nested(request, act_offset); + } + break; } } - if (flower->tunnel.tunnel) { - act_offset = nl_msg_start_nested(request, act_index++); - nl_msg_put_act_tunnel_key_release(request); - nl_msg_end_nested(request, act_offset); - } - if (flower->set.set) { - act_offset = nl_msg_start_nested(request, act_index++); - nl_msg_put_act_tunnel_key_set(request, flower->set.id, - flower->set.ipv4.ipv4_src, - flower->set.ipv4.ipv4_dst, - &flower->set.ipv6.ipv6_src, - &flower->set.ipv6.ipv6_dst, - flower->set.tp_dst); - nl_msg_end_nested(request, act_offset); - } - if (flower->vlan_pop) { - act_offset = nl_msg_start_nested(request, act_index++); - nl_msg_put_act_pop_vlan(request); - nl_msg_end_nested(request, act_offset); - } - if (flower->vlan_push_id) { - act_offset = nl_msg_start_nested(request, act_index++); - nl_msg_put_act_push_vlan(request, - flower->vlan_push_id, - flower->vlan_push_prio); - nl_msg_end_nested(request, act_offset); - } - if (flower->ifindex_out) { - act_offset = nl_msg_start_nested(request, act_index++); - nl_msg_put_act_redirect(request, flower->ifindex_out); - nl_msg_put_act_cookie(request, &flower->act_cookie); - nl_msg_end_nested(request, act_offset); - } else { - act_offset = nl_msg_start_nested(request, act_index++); - nl_msg_put_act_drop(request); - nl_msg_put_act_cookie(request, &flower->act_cookie); - nl_msg_end_nested(request, act_offset); - } + } + if (!ifindex) { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_drop(request); + nl_msg_put_act_cookie(request, &flower->act_cookie); + nl_msg_end_nested(request, act_offset); } nl_msg_end_nested(request, offset); diff --git a/lib/tc.h b/lib/tc.h index 4400a829e..963db54dc 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -106,6 +106,41 @@ struct tc_flower_key { } ipv6; }; +enum tc_action_type { + TC_ACT_OUTPUT, + TC_ACT_ENCAP, + TC_ACT_PEDIT, + TC_ACT_VLAN_POP, + TC_ACT_VLAN_PUSH, +}; + +struct tc_action { + union { + int ifindex_out; + + struct { + uint16_t vlan_push_id; + uint8_t vlan_push_prio; + } vlan; + + struct { + ovs_be64 id; + ovs_be16 tp_src; + ovs_be16 tp_dst; + struct { + ovs_be32 ipv4_src; + ovs_be32 ipv4_dst; + } ipv4; + struct { + struct in6_addr ipv6_src; + struct in6_addr ipv6_dst; + } ipv6; + } encap; + }; + + enum tc_action_type type; +}; + struct tc_flower { uint32_t handle; uint32_t prio; @@ -113,11 +148,8 @@ struct tc_flower { struct tc_flower_key key; struct tc_flower_key mask; - uint8_t vlan_pop; - uint16_t vlan_push_id; - uint8_t vlan_push_prio; - - int ifindex_out; + int action_count; + struct tc_action actions[TCA_ACT_MAX_PRIO]; struct ovs_flow_stats stats; uint64_t lastused; @@ -130,21 +162,6 @@ struct tc_flower { uint32_t csum_update_flags; - struct { - bool set; - ovs_be64 id; - ovs_be16 tp_src; - ovs_be16 tp_dst; - struct { - ovs_be32 ipv4_src; - ovs_be32 ipv4_dst; - } ipv4; - struct { - struct in6_addr ipv6_src; - struct in6_addr ipv6_dst; - } ipv6; - } set; - struct { bool tunnel; struct {