From patchwork Wed May 17 11:02:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244684 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3C08D171B0 for ; Wed, 17 May 2023 11:03:55 +0000 (UTC) Received: from mail-qt1-x82a.google.com (mail-qt1-x82a.google.com [IPv6:2607:f8b0:4864:20::82a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 914B930F8 for ; Wed, 17 May 2023 04:03:15 -0700 (PDT) Received: by mail-qt1-x82a.google.com with SMTP id d75a77b69052e-3f443080ef7so4017281cf.1 for ; Wed, 17 May 2023 04:03:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321356; x=1686913356; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=peThC93R7SZPguQGzbXZwhmlyhHY0h2P0J/fFOI9LCk=; b=kA2ZuIuq0NONy+/7i4aLStZSbplspuPJQ6reO8snyCXRkoGCfrL3yAE3PAMjwwpzhJ sf8aK6fL9F1h6Ht7UW9n8KIzjHvHWol3+y7aLMUHnCgQLhuSJpk3W4ytLuJHn/MzMjSI y05sY+KU1mi6CCAaZ8AyWHSuxiLi0GJH3cUSVl//UOK6jW3e07VU4WYbFc9ldb6+m+Y1 OUK/jr1c2k4HMP3aEaDbED7Ja11811Rb1/qkShRjhfITj/Eh6e3ZPEP9xFLI9zu0Epr1 grM6Y8A/ZNiDyybD2cuDR2Fiqy8V8KWQgEhjNsHvVJlUbNqeYtAskh+HfaVdsfV1jrnw nZaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321356; x=1686913356; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=peThC93R7SZPguQGzbXZwhmlyhHY0h2P0J/fFOI9LCk=; b=VkvCdWfIo4z8VxlXQ8cxm5fHkDWoIB5HFnfDpR1lUVrw0tKxlqIDu5A+S8tnXlIU99 WNwjzB4ylNV9HWKGBq4/um3Hon/A8BizGzy7TqLLq0dGhDc0wuvfpLKygdyeWdcAbokm 4+MGLcyIEqdDojt8aDPKB3gco3kYAd5DMjIiP3MZaEJH6AgcF6CFGX2Au0+oTmeiQ0P1 zwyp3qEDaweLdroa6mwJhc8koxwZh32sOs5gaWzCmz7ddZHKXSfyYOEUcfNW0VeoVScO ZnConaQyFl/fnMPbjWdJL4Pn04gr6UWbqCy9KnPMIXMK5vxuPOMjU/vVFzJAL5/JR4Rz vj/A== X-Gm-Message-State: AC+VfDww6vBpiV1t7kokiKxfhypKjYMdM9eOWBXiyjcDm5em0EcRNjgf LqHt+PgiAQvZeKak01LEQphi/cpshr9KspHzuYo= X-Google-Smtp-Source: ACHHUZ4GYt+gileB6XL8fu+HDLQifzjtpiPJ8r25inGbSuFC5m8ayPXFJofqPEJvSrhnWubzP+iG2g== X-Received: by 2002:ac8:7fd6:0:b0:3f5:3f9e:ffce with SMTP id b22-20020ac87fd6000000b003f53f9effcemr8766248qtk.43.1684321355614; Wed, 17 May 2023 04:02:35 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id k3-20020ac80203000000b003e39106bdb2sm7034660qtg.31.2023.05.17.04.02.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:02:35 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 01/28] net: sched: act_api: Add dynamic actions IDR Date: Wed, 17 May 2023 07:02:05 -0400 Message-Id: <20230517110232.29349-1-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Kernel native actions kinds, such as gact, etc, have a predefined action ID that is statically defined; example TCA_ID_GACT (0x2) for gact. In P4 we would require to generate new actions "on the fly" based on the P4 program requirement. Doing this in a list, like act_base does, would require us to us to reimplement all of the ID generation that we get for free with IDRs, so we chose to stick with an IDR for this. We could've simply converted act_base into an IDR and used the same structure to store kernel native and dynamic actions. However dynamic action kinds, like the pipeline they are attached to, must be per net namespace, as opposed to native action kinds which are global. For that reason, we chose to create a separate structure to store dynamic actions. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/act_api.h | 6 +- include/uapi/linux/pkt_cls.h | 1 + net/sched/act_api.c | 129 +++++++++++++++++++++++++++++++---- net/sched/cls_api.c | 2 +- 4 files changed, 123 insertions(+), 15 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index 4ae0580b63ca..54754deed15e 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -198,8 +198,10 @@ int tcf_idr_check_alloc(struct tc_action_net *tn, u32 *index, int tcf_idr_release(struct tc_action *a, bool bind); int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops); +int tcf_register_dyn_action(struct net *net, struct tc_action_ops *act); int tcf_unregister_action(struct tc_action_ops *a, struct pernet_operations *ops); +int tcf_unregister_dyn_action(struct net *net, struct tc_action_ops *act); int tcf_action_destroy(struct tc_action *actions[], int bind); int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, int nr_actions, struct tcf_result *res); @@ -207,8 +209,8 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, struct nlattr *est, struct tc_action *actions[], int init_res[], size_t *attr_size, u32 flags, u32 fl_flags, struct netlink_ext_ack *extack); -struct tc_action_ops *tc_action_load_ops(struct nlattr *nla, bool police, - bool rtnl_held, +struct tc_action_ops *tc_action_load_ops(struct net *net, struct nlattr *nla, + bool police, bool rtnl_held, struct netlink_ext_ack *extack); struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, struct nlattr *nla, struct nlattr *est, diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 648a82f32666..4d716841ca05 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -139,6 +139,7 @@ enum tca_id { TCA_ID_MPLS, TCA_ID_CT, TCA_ID_GATE, + TCA_ID_DYN, /* other actions go here */ __TCA_ID_MAX = 255 }; diff --git a/net/sched/act_api.c b/net/sched/act_api.c index f7887f42d542..3cd686d0094e 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -57,6 +57,43 @@ static void tcf_free_cookie_rcu(struct rcu_head *p) kfree(cookie); } +static unsigned int dyn_act_net_id; + +struct tcf_dyn_act_net { + struct idr act_base; + rwlock_t act_mod_lock; +}; + +static __net_init int tcf_dyn_act_base_init_net(struct net *net) +{ + struct tcf_dyn_act_net *dyn_base_net = net_generic(net, dyn_act_net_id); + rwlock_t _act_mod_lock = __RW_LOCK_UNLOCKED(_act_mod_lock); + + idr_init(&dyn_base_net->act_base); + dyn_base_net->act_mod_lock = _act_mod_lock; + return 0; +} + +static void __net_exit tcf_dyn_act_base_exit_net(struct net *net) +{ + struct tcf_dyn_act_net *dyn_base_net = net_generic(net, dyn_act_net_id); + struct tc_action_ops *ops; + unsigned long opid, tmp; + + idr_for_each_entry_ul(&dyn_base_net->act_base, ops, tmp, opid) { + idr_remove(&dyn_base_net->act_base, ops->id); + } + + idr_destroy(&dyn_base_net->act_base); +} + +static struct pernet_operations tcf_dyn_act_base_net_ops = { + .init = tcf_dyn_act_base_init_net, + .exit = tcf_dyn_act_base_exit_net, + .id = &dyn_act_net_id, + .size = sizeof(struct tc_action_ops), +}; + static void tcf_set_action_cookie(struct tc_cookie __rcu **old_cookie, struct tc_cookie *new_cookie) { @@ -941,6 +978,28 @@ static void tcf_pernet_del_id_list(unsigned int id) mutex_unlock(&act_id_mutex); } +int tcf_register_dyn_action(struct net *net, struct tc_action_ops *act) +{ + struct tcf_dyn_act_net *dyn_base_net = net_generic(net, dyn_act_net_id); + int ret; + + write_lock(&dyn_base_net->act_mod_lock); + + act->id = TCA_ID_DYN; + + ret = idr_alloc_u32(&dyn_base_net->act_base, act, &act->id, + TCA_ID_MAX, GFP_ATOMIC); + if (ret < 0) + goto err_out; + write_unlock(&dyn_base_net->act_mod_lock); + + return 0; + +err_out: + write_unlock(&dyn_base_net->act_mod_lock); + return ret; +} + int tcf_register_action(struct tc_action_ops *act, struct pernet_operations *ops) { @@ -1010,40 +1069,84 @@ int tcf_unregister_action(struct tc_action_ops *act, } EXPORT_SYMBOL(tcf_unregister_action); +int tcf_unregister_dyn_action(struct net *net, struct tc_action_ops *act) +{ + struct tcf_dyn_act_net *dyn_base_net = net_generic(net, dyn_act_net_id); + int err = 0; + + write_lock(&dyn_base_net->act_mod_lock); + if (!idr_remove(&dyn_base_net->act_base, act->id)) + err = -EINVAL; + + write_unlock(&dyn_base_net->act_mod_lock); + + return err; +} +EXPORT_SYMBOL(tcf_unregister_dyn_action); + /* lookup by name */ -static struct tc_action_ops *tc_lookup_action_n(char *kind) +static struct tc_action_ops *tc_lookup_action_n(struct net *net, char *kind) { + struct tcf_dyn_act_net *dyn_base_net = net_generic(net, dyn_act_net_id); struct tc_action_ops *a, *res = NULL; if (kind) { + unsigned long tmp, id; + read_lock(&act_mod_lock); list_for_each_entry(a, &act_base, head) { + if (strcmp(kind, a->kind) == 0) { + if (try_module_get(a->owner)) { + read_unlock(&act_mod_lock); + return a; + } + } + } + read_unlock(&act_mod_lock); + + read_lock(&dyn_base_net->act_mod_lock); + idr_for_each_entry_ul(&dyn_base_net->act_base, a, tmp, id) { if (strcmp(kind, a->kind) == 0) { if (try_module_get(a->owner)) res = a; break; } } - read_unlock(&act_mod_lock); + read_unlock(&dyn_base_net->act_mod_lock); } return res; } /* lookup by nlattr */ -static struct tc_action_ops *tc_lookup_action(struct nlattr *kind) +static struct tc_action_ops *tc_lookup_action(struct net *net, + struct nlattr *kind) { + struct tcf_dyn_act_net *dyn_base_net = net_generic(net, dyn_act_net_id); struct tc_action_ops *a, *res = NULL; if (kind) { + unsigned long tmp, id; + read_lock(&act_mod_lock); list_for_each_entry(a, &act_base, head) { + if (nla_strcmp(kind, a->kind) == 0) { + if (try_module_get(a->owner)) { + read_unlock(&act_mod_lock); + return a; + } + } + } + read_unlock(&act_mod_lock); + + read_lock(&dyn_base_net->act_mod_lock); + idr_for_each_entry_ul(&dyn_base_net->act_base, a, tmp, id) { if (nla_strcmp(kind, a->kind) == 0) { if (try_module_get(a->owner)) res = a; break; } } - read_unlock(&act_mod_lock); + read_unlock(&dyn_base_net->act_mod_lock); } return res; } @@ -1294,8 +1397,8 @@ void tcf_idr_insert_many(struct tc_action *actions[]) } } -struct tc_action_ops *tc_action_load_ops(struct nlattr *nla, bool police, - bool rtnl_held, +struct tc_action_ops *tc_action_load_ops(struct net *net, struct nlattr *nla, + bool police, bool rtnl_held, struct netlink_ext_ack *extack) { struct nlattr *tb[TCA_ACT_MAX + 1]; @@ -1326,7 +1429,7 @@ struct tc_action_ops *tc_action_load_ops(struct nlattr *nla, bool police, } } - a_o = tc_lookup_action_n(act_name); + a_o = tc_lookup_action_n(net, act_name); if (a_o == NULL) { #ifdef CONFIG_MODULES if (rtnl_held) @@ -1335,7 +1438,7 @@ struct tc_action_ops *tc_action_load_ops(struct nlattr *nla, bool police, if (rtnl_held) rtnl_lock(); - a_o = tc_lookup_action_n(act_name); + a_o = tc_lookup_action_n(net, act_name); /* We dropped the RTNL semaphore in order to * perform the module load. So, even if we @@ -1445,7 +1548,8 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { struct tc_action_ops *a_o; - a_o = tc_action_load_ops(tb[i], flags & TCA_ACT_FLAGS_POLICE, + a_o = tc_action_load_ops(net, tb[i], + flags & TCA_ACT_FLAGS_POLICE, !(flags & TCA_ACT_FLAGS_NO_RTNL), extack); if (IS_ERR(a_o)) { @@ -1655,7 +1759,7 @@ static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla, index = nla_get_u32(tb[TCA_ACT_INDEX]); err = -EINVAL; - ops = tc_lookup_action(tb[TCA_ACT_KIND]); + ops = tc_lookup_action(net, tb[TCA_ACT_KIND]); if (!ops) { /* could happen in batch of actions */ NL_SET_ERR_MSG(extack, "Specified TC action kind not found"); goto err_out; @@ -1703,7 +1807,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, err = -EINVAL; kind = tb[TCA_ACT_KIND]; - ops = tc_lookup_action(kind); + ops = tc_lookup_action(net, kind); if (!ops) { /*some idjot trying to flush unknown action */ NL_SET_ERR_MSG(extack, "Cannot flush unknown TC action"); goto err_out; @@ -2109,7 +2213,7 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) return 0; } - a_o = tc_lookup_action(kind); + a_o = tc_lookup_action(net, kind); if (a_o == NULL) return 0; @@ -2176,6 +2280,7 @@ static int __init tc_action_init(void) rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action, 0); + register_pernet_subsys(&tcf_dyn_act_base_net_ops); return 0; } diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 2621550bfddc..4af48f76fe55 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -3271,7 +3271,7 @@ int tcf_exts_validate_ex(struct net *net, struct tcf_proto *tp, struct nlattr ** if (exts->police && tb[exts->police]) { struct tc_action_ops *a_o; - a_o = tc_action_load_ops(tb[exts->police], true, + a_o = tc_action_load_ops(net, tb[exts->police], true, !(flags & TCA_ACT_FLAGS_NO_RTNL), extack); if (IS_ERR(a_o)) From patchwork Wed May 17 11:02:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244685 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 35A0C171B0 for ; Wed, 17 May 2023 11:03:58 +0000 (UTC) Received: from mail-qk1-x735.google.com (mail-qk1-x735.google.com [IPv6:2607:f8b0:4864:20::735]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8AC2D3C32 for ; Wed, 17 May 2023 04:03:23 -0700 (PDT) Received: by mail-qk1-x735.google.com with SMTP id af79cd13be357-7577ef2fa31so631732585a.0 for ; Wed, 17 May 2023 04:03:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321363; x=1686913363; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=iOsAgtFnUv40z8ltHKypmFjRPulCrmNdD97YCaR01n0=; b=nUIqHJgkagnqJRjNbgVDcZUEwRfOGGCNGMRQNOpAMnxViQcfMFbYC2DbU6vhM+PuoO rekxJ427eEpPQ2ghHZ/+lVCNK6Sm8GexXjKGXA8E0zvgCEziUdhmvOtT637YTqyPiahx I67g8XE1d4Ve1q3Gm0mTw61eK9BUt48qQNm5+sRjnCjJR5L5iKoiJQcnxInERbSkKSz/ As+vjRJtFks9E0hT/a7ILSR+yDKXhGwQjrbNnfyGf/Xrq7iMPuQsqwWkV/LV1J7hT/0s ot/pUTkD9jkMRvRD3RP1viWaXIqcKgypxU8lsJi1OYe45EXfEGjhlBejslCwPn/SRkIX mzPQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321363; x=1686913363; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=iOsAgtFnUv40z8ltHKypmFjRPulCrmNdD97YCaR01n0=; b=UyTTwwYPYDg9mNRjn+WNdCV1A8kd1HkHH+/4iZAgzV+poqq+Rjs1sSPiTRlXQVOO9U jZuWz/ic1bpHCZ+qU8wFIPYQF1IN7/fOZNZ2zHAKU9ImuAaydkkn93+ZVcY5fz6MJZUT Biuvrz3VSCL2N+7NH4T6QAK8ZJOqsgcFM12kEE0TyBE6ASA+4BW2vSp/iP6JWgIT5ofT QbdtHZcDiuynEf1lfZf5sYpjM+hbYJvLqG/N9VINMQ6B6uG5Zd4rpp9q+xhdZ/9giPQo M0hOF82BI85Kl5Uo0kIM96MWSrw7Fhtn4N2PEpqwpqvGDRJREE757Ei4vQiAqhbH5ht4 1QCw== X-Gm-Message-State: AC+VfDwkgx7tlttgKe1VFEEV8gjYiWaPAWWufDvsoGvVvRcZqw5UwdT4 2ASbYDdAug8zr4ISM/z0wbTRsIDv5vc88WBdECQ= X-Google-Smtp-Source: ACHHUZ6RCABbHP32O4GsEBCdS4yqn45CWc+ewF0fgEDfRYMRf2uwVyZIMlgO1ZKRFBJy1a0m/lAjdQ== X-Received: by 2002:a05:622a:1997:b0:3f4:d3a7:9827 with SMTP id u23-20020a05622a199700b003f4d3a79827mr2537390qtc.25.1684321362995; Wed, 17 May 2023 04:02:42 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id p11-20020ae9f30b000000b0074df8eefe2dsm520109qkg.98.2023.05.17.04.02.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:02:42 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 02/28] net/sched: act_api: increase action kind string length Date: Wed, 17 May 2023 07:02:06 -0400 Message-Id: <20230517110232.29349-2-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Increase action kind string length from IFNAMSIZ to 64 The new P4TC dynamic actions, created via templates, will have longer names of format: "pipeline_name/act_name". IFNAMSIZ is currently 16 and is most of the times undersized for the above format. So, to conform to this new format, we increase the maximum name length to account for this extra string (pipeline name) and the '/' character. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/act_api.h | 2 +- include/uapi/linux/pkt_cls.h | 1 + net/sched/act_api.c | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index 54754deed15e..a414c0f94ff1 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -105,7 +105,7 @@ typedef void (*tc_action_priv_destructor)(void *priv); struct tc_action_ops { struct list_head head; - char kind[IFNAMSIZ]; + char kind[ACTNAMSIZ]; enum tca_id id; /* identifier should match kind */ unsigned int net_id; size_t size; diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 4d716841ca05..5b66df3ec332 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -6,6 +6,7 @@ #include #define TC_COOKIE_MAX_SIZE 16 +#define ACTNAMSIZ 64 /* Action attributes */ enum { diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 3cd686d0094e..bc4e178873e4 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -479,7 +479,7 @@ static size_t tcf_action_shared_attrs_size(const struct tc_action *act) rcu_read_unlock(); return nla_total_size(0) /* action number nested */ - + nla_total_size(IFNAMSIZ) /* TCA_ACT_KIND */ + + nla_total_size(ACTNAMSIZ) /* TCA_ACT_KIND */ + cookie_len /* TCA_ACT_COOKIE */ + nla_total_size(sizeof(struct nla_bitfield32)) /* TCA_ACT_HW_STATS */ + nla_total_size(0) /* TCA_ACT_STATS nested */ @@ -1403,7 +1403,7 @@ struct tc_action_ops *tc_action_load_ops(struct net *net, struct nlattr *nla, { struct nlattr *tb[TCA_ACT_MAX + 1]; struct tc_action_ops *a_o; - char act_name[IFNAMSIZ]; + char act_name[ACTNAMSIZ]; struct nlattr *kind; int err; @@ -1418,7 +1418,7 @@ struct tc_action_ops *tc_action_load_ops(struct net *net, struct nlattr *nla, NL_SET_ERR_MSG(extack, "TC action kind must be specified"); return ERR_PTR(err); } - if (nla_strscpy(act_name, kind, IFNAMSIZ) < 0) { + if (nla_strscpy(act_name, kind, ACTNAMSIZ) < 0) { NL_SET_ERR_MSG(extack, "TC action name too long"); return ERR_PTR(err); } From patchwork Wed May 17 11:02:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244686 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF778182A5 for ; Wed, 17 May 2023 11:04:00 +0000 (UTC) Received: from mail-yb1-xb2b.google.com (mail-yb1-xb2b.google.com [IPv6:2607:f8b0:4864:20::b2b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 996E335AE for ; Wed, 17 May 2023 04:03:27 -0700 (PDT) Received: by mail-yb1-xb2b.google.com with SMTP id 3f1490d57ef6-ba841216e92so755055276.1 for ; Wed, 17 May 2023 04:03:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321371; x=1686913371; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BqfjnIXqJfXZ89QrntS0b/0XB83XXdfHUZ3LMpbBoq0=; b=A/iGFnkxqZlOnFJsNunWT4kUoNk/bIArEKOHXCQUaBXOdA4XTB+cuM4UK3K0fO5j0T aQo/UxE5vyVUPVsXpAaeenEx9EpsIeEmiYAvRQlYc2MwLE+7dDUJhHmfs1zYWRHil+kr v4pZ0p69huatEBky9gW9awEgbUE+JIlowHSvhyGI4Z9rACDDsAYVTz18bDx4a7sT6bx8 yr6SIwaK5AhHARZPAxyZNdq3L1iI2WaNxGUmJRvR8y17kX+sFTc2f7yYxHkK6G8Aw1+x bCKr+OIxFYzZXwUSzAxEPDC+rOnVoNADeCJ5gOmrocUy4it+f73G1W51fEzv6NmlTUw4 ZhqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321371; x=1686913371; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BqfjnIXqJfXZ89QrntS0b/0XB83XXdfHUZ3LMpbBoq0=; b=D5Rhg5vvjhzrUw4qb7Z91P9TKtviyZqyI6PIDSPhrKy6SMIjGUfpL2RvUCWiBEcsaO KSz4AxsHuSnc1GYPVLwO7i4XQ5u+o8kE5rlkaP7J2Iu/UDnqudRQrUJzka1e66hGPx6G pkIp8Y+Iz1Pr8s6D4rU/7e0OnQ/exkhx3V+BBj2ApHnoeuLPekxsJXjNTSpPGnh+aoRV LkYdJMk0QCcszYh99sR84p5naVb4yfQTCmqnRU/Tz5ulZ305NybJKrp1CpcD8VXObuqO MxMgWL5vYzIwewTaK2yEGSnUL4/nccgKMqaRoUIBrfyndG/zeFBuCJE9IoKkHAFfKwSd DJuA== X-Gm-Message-State: AC+VfDwJdKYmhN5M83fFPU2BfnzEgQSNlMJFudMaCiObcZ+iTVuvh773 SLl+ATrzoDGqqobQa5xAovltVRyAFqP/A2mupQI= X-Google-Smtp-Source: ACHHUZ69Gq93TzaVnb4+uk6mlV82eiT8WtWZ63J3h/v11udtAMe843E8EqAnSMGR9tuzQmH/OtQlFA== X-Received: by 2002:a25:21d7:0:b0:ba6:f4fd:181a with SMTP id h206-20020a2521d7000000b00ba6f4fd181amr14454692ybh.42.1684321370911; Wed, 17 May 2023 04:02:50 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id w13-20020a05620a128d00b0075785052e97sm519882qki.95.2023.05.17.04.02.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:02:49 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 03/28] net/sched: act_api: increase TCA_ID_MAX Date: Wed, 17 May 2023 07:02:07 -0400 Message-Id: <20230517110232.29349-3-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Increase TCA_ID_MAX from 255 to 1023 Given P4TC dynamic actions required new IDs (dynamically) and 30 of those are already taken by the standard actions (such as gact, mirred and ife) we are left with 225 actions to create, which seems like a small number. Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim Suggested-by: Vlad Buslov --- include/uapi/linux/pkt_cls.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 5b66df3ec332..337411949ad0 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -140,9 +140,9 @@ enum tca_id { TCA_ID_MPLS, TCA_ID_CT, TCA_ID_GATE, - TCA_ID_DYN, + TCA_ID_DYN = 256, /* other actions go here */ - __TCA_ID_MAX = 255 + __TCA_ID_MAX = 1023 }; #define TCA_ID_MAX __TCA_ID_MAX From patchwork Wed May 17 11:02:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244687 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AEBC31DDD2 for ; Wed, 17 May 2023 11:04:09 +0000 (UTC) Received: from mail-qv1-xf35.google.com (mail-qv1-xf35.google.com [IPv6:2607:f8b0:4864:20::f35]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2E4E86186 for ; Wed, 17 May 2023 04:03:34 -0700 (PDT) Received: by mail-qv1-xf35.google.com with SMTP id 6a1803df08f44-6216a09ec38so2595206d6.3 for ; Wed, 17 May 2023 04:03:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321378; x=1686913378; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=j8rj5+UCTfweWcOpgfYjBAg1E/WAhjyZhZiEuFMhPCM=; b=hvK03K/ZII253uMj4S35YdyFPCJYmmUCMORDySI01hssL1ZMD5QNGCDWBYsFcmI2bH NzWBS/UFn4tIyy+2E2ZeE8gtxYTgUDWO9/6vvoZ7TYxGpE9rCgOv6GuPyJfo5eL/5RIW qBO+c7nE8UAGLIvhmPiAIGLPuNcSA1tAia5YorCsErEqlEjKVUbvdG9qo7QQLv7tHKAg Vp3tS79OCpw2XBVg1WF8eZi8m4XEh2S6ui9Sh+kqt8Gzah2AeKlDIC4CLaGCDRhju0FP C3/L0UUoDB5/8JCo/1LAZOw7uG6NMdYJ1zJ7KFSKDU/wfvuMyaS0O/qJbyA7Y/MRbq5q hOaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321378; x=1686913378; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=j8rj5+UCTfweWcOpgfYjBAg1E/WAhjyZhZiEuFMhPCM=; b=k8x9vJznzjjibKJHgDBhcTX4fXCF336sGh+1N1vUbNLxko9cNqzZm3d/tAtnPwFZG5 y19GhmvEatrWorBBlUCNBVEY0P55ouJjsTnXUhf2Qa6U8heP0j0eB/AlkR3PAsiEyJhc A2TEDKAgepsyiix3Br4OEEFGlZPqmAs3ReA9DuGQ3FbOTrIiEHx0jWFeN1gpihlV5A8u uxt6wjip5l2nd9L0l3pDT9J7xl5pcF7/7AnoCW1B1XpsEOwSAOPwehY/TDcmcsa6BnwE 83olF9Gfv2kmN20YpOGisGw2xPKJG2iK0M+FXUmQNU88BxThhyv8aTG9HQaI2wJlx2kc QSBg== X-Gm-Message-State: AC+VfDwAnpkkUDH204bfFiAoD17fm6PUHTCSaBwTp9zUzlMmcWba9UsX giwmv7qngimWubtuWV3J4W9xWYt4bklBuywV/Fo= X-Google-Smtp-Source: ACHHUZ5dn1QoZ+RkCBGjnp3LSVDxjgrZ0k9FIxE809OPbIGdHmiQUvXuR3bhWrQ8aWrj6BuT6CwqXg== X-Received: by 2002:ad4:5ae9:0:b0:5cd:1adc:30e2 with SMTP id c9-20020ad45ae9000000b005cd1adc30e2mr65442308qvh.11.1684321378100; Wed, 17 May 2023 04:02:58 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id t9-20020a0cef09000000b0061b2a2f949bsm6212183qvr.61.2023.05.17.04.02.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:02:57 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 04/28] net/sched: act_api: add init_ops to struct tc_action_op Date: Wed, 17 May 2023 07:02:08 -0400 Message-Id: <20230517110232.29349-4-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC The initialisation of P4TC action instances require access to a struct p4tc_act (which appears in later patches) to help us to retrieve information like the dynamic action parameters etc. In order to retrieve struct p4tc_act we need the pipeline name or id and the action name or id. Also recall that P4TC action IDs are dynamic and are net namespace specific. The init callback from tc_action_ops parameters had no way of supplying us that information. To solve this issue, we decided to create a new tc_action_ops callback (init_ops), that provides us with the tc_action_ops struct which then provides us with the pipeline and action name. In addition we add a new refcount to struct tc_action_ops called dyn_ref, which accounts for how many action instances we have of a specific dynamic action. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/act_api.h | 6 ++++++ net/sched/act_api.c | 11 ++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index a414c0f94ff1..363f7f8b5586 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -108,6 +108,7 @@ struct tc_action_ops { char kind[ACTNAMSIZ]; enum tca_id id; /* identifier should match kind */ unsigned int net_id; + refcount_t dyn_ref; size_t size; struct module *owner; int (*act)(struct sk_buff *, const struct tc_action *, @@ -119,6 +120,11 @@ struct tc_action_ops { struct nlattr *est, struct tc_action **act, struct tcf_proto *tp, u32 flags, struct netlink_ext_ack *extack); + /* This should be merged with the original init action */ + int (*init_ops)(struct net *net, struct nlattr *nla, + struct nlattr *est, struct tc_action **act, + struct tcf_proto *tp, struct tc_action_ops *ops, + u32 flags, struct netlink_ext_ack *extack); int (*walk)(struct net *, struct sk_buff *, struct netlink_callback *, int, const struct tc_action_ops *, diff --git a/net/sched/act_api.c b/net/sched/act_api.c index bc4e178873e4..0ba5a4b5db6f 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1006,7 +1006,7 @@ int tcf_register_action(struct tc_action_ops *act, struct tc_action_ops *a; int ret; - if (!act->act || !act->dump || !act->init) + if (!act->act || !act->dump || (!act->init && !act->init_ops)) return -EINVAL; /* We have to register pernet ops before making the action ops visible, @@ -1494,8 +1494,13 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, } } - err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, tp, - userflags.value | flags, extack); + if (a_o->init) + err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, tp, + userflags.value | flags, extack); + else if (a_o->init_ops) + err = a_o->init_ops(net, tb[TCA_ACT_OPTIONS], est, &a, + tp, a_o, userflags.value | flags, + extack); } else { err = a_o->init(net, nla, est, &a, tp, userflags.value | flags, extack); From patchwork Wed May 17 11:02:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244688 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 004291DDD2 for ; Wed, 17 May 2023 11:04:10 +0000 (UTC) Received: from mail-qv1-xf2d.google.com (mail-qv1-xf2d.google.com [IPv6:2607:f8b0:4864:20::f2d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 964D06E91 for ; Wed, 17 May 2023 04:03:34 -0700 (PDT) Received: by mail-qv1-xf2d.google.com with SMTP id 6a1803df08f44-6238b15d298so1261226d6.0 for ; Wed, 17 May 2023 04:03:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321385; x=1686913385; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=gSwJ90KGk9t7LlTjCVS+Q76hji8RHtbhCmgk4rEJoeU=; b=s9xH/LIb2eH59Ih+TDJkNanq+0DBoUapmqDs+HV/ZBTGKYYVe+PNj9uzy7E9cd3guh DbL3bGr9pcln4y1mAw5k3lAyQ0h9BVuYgRpJif3LbB4G1W7CgwvyP31ZgaPwUtbn54Kv NkvUCuIGibi9eVmFGyCbP+XhOiHTBCuiXHLiADrmNI8IwS9iMIl1ZXMrbtRqbufOot8n P6yFJswC9vT1XSS1Vcm8fN/qtghmLgZnGMPBQHxoLuyLIqmDl4omVVSrtP10sB+H6Dnl A4TSoiwYRTIbBsMnebMinL27a5R73NcBf86u5pdNrwCPAkcNhc7f0LLMcevYSAAAmTI7 eMRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321385; x=1686913385; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=gSwJ90KGk9t7LlTjCVS+Q76hji8RHtbhCmgk4rEJoeU=; b=bzBXN/BMA21L6NC3VNwNKtOzYeQK9dYkjXy2wm0+7+VKVjyiTK3XfYCT6umCInteSm TkIOO6Ud6YHeOvIKiWjmBYSnXs5/iTa+qLykNZz6maetbs9FG0JEUOhTr4KLun3iD1Y4 akf2L4MeIwLWLdAQacan7Fzd9rMEtOJpc8X8+cFKHEBY8sM2lq5R26wDhrVtupia9Lqf AEMETrk3ywc7xFkqbmEB6flV2SmHKma7mLXNihx6iiOk80vCZVX65fFziA0GK2+i3eU9 JtxyEhncgbmQ75Q8d5WWSg6d1kOLCdwXTxlCR2C+yjYmfs5qTolWTthWzioFH/uaO3kA NfLg== X-Gm-Message-State: AC+VfDz6D0qemXkVBLPc/FX4f7AWwV7bJzn3eJ7s7t8Y1l/2CYFpSuxa BFzfX7YrUSKWZ3o3+fbTIKVYDuF2Lb99adpPbzM= X-Google-Smtp-Source: ACHHUZ4vMrtw1oSM54OEhycYaO2j7vDoNGV7WGZfwmbus7ag8J6KsUkOrJNfbmeNc7Xm9I415e0KVg== X-Received: by 2002:ad4:5964:0:b0:622:7b7f:ed46 with SMTP id eq4-20020ad45964000000b006227b7fed46mr28143165qvb.7.1684321385010; Wed, 17 May 2023 04:03:05 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id w20-20020a0cdf94000000b006237c66ae3dsm933447qvl.62.2023.05.17.04.03.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:03:04 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 05/28] net/sched: act_api: introduce tc_lookup_action_byid() Date: Wed, 17 May 2023 07:02:09 -0400 Message-Id: <20230517110232.29349-5-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Introduce a lookup helper to retrieve the tc_action_ops instance given its action id. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/act_api.h | 1 + net/sched/act_api.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/net/act_api.h b/include/net/act_api.h index 363f7f8b5586..34b9a9ff05ee 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -205,6 +205,7 @@ int tcf_idr_release(struct tc_action *a, bool bind); int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops); int tcf_register_dyn_action(struct net *net, struct tc_action_ops *act); +struct tc_action_ops *tc_lookup_action_byid(struct net *net, u32 act_id); int tcf_unregister_action(struct tc_action_ops *a, struct pernet_operations *ops); int tcf_unregister_dyn_action(struct net *net, struct tc_action_ops *act); diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 0ba5a4b5db6f..101c6debf356 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1084,6 +1084,41 @@ int tcf_unregister_dyn_action(struct net *net, struct tc_action_ops *act) } EXPORT_SYMBOL(tcf_unregister_dyn_action); +/* lookup by ID */ +struct tc_action_ops *tc_lookup_action_byid(struct net *net, u32 act_id) +{ + struct tcf_dyn_act_net *base_net; + struct tc_action_ops *a, *res = NULL; + + if (!act_id) + return NULL; + + read_lock(&act_mod_lock); + + list_for_each_entry(a, &act_base, head) { + if (a->id == act_id) { + if (try_module_get(a->owner)) { + read_unlock(&act_mod_lock); + return a; + } + break; + } + } + read_unlock(&act_mod_lock); + + read_lock(&base_net->act_mod_lock); + + base_net = net_generic(net, dyn_act_net_id); + a = idr_find(&base_net->act_base, act_id); + if (a && try_module_get(a->owner)) + res = a; + + read_unlock(&base_net->act_mod_lock); + + return res; +} +EXPORT_SYMBOL(tc_lookup_action_byid); + /* lookup by name */ static struct tc_action_ops *tc_lookup_action_n(struct net *net, char *kind) { From patchwork Wed May 17 11:02:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244689 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0FFC51DDD2 for ; Wed, 17 May 2023 11:04:12 +0000 (UTC) Received: from mail-qt1-x833.google.com (mail-qt1-x833.google.com [IPv6:2607:f8b0:4864:20::833]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DDEB3FE for ; Wed, 17 May 2023 04:03:36 -0700 (PDT) Received: by mail-qt1-x833.google.com with SMTP id d75a77b69052e-3f4f47336bcso3941681cf.3 for ; Wed, 17 May 2023 04:03:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321392; x=1686913392; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=6ftpqq5gYPC2d4GxsLutQJxqbX8zDHS3zETPrp3Oo54=; b=2vT/tsv8MDGxjyk08tK+V9R9RRqE+gk0caHzUlHxMySsVmcymyjkeO0QgSlbHr+HxV Uj97H3RgEux6uACs9czlj15QVUtIZyPjuSh7j7Y7NKJEk451svE/uzXaTew7EGhDAa7G zrf2fbvuebDMcEnRdHfknKdguDp2pQBLbdinGCEdk8wSr7exSXb2LKL1a5JSn7LfiqIL sYB/ucy18dCVFAQjDerQ1H7KMUEKFTqsIlCo1nVjQZyS/0eeISpxlqIUB6kBMFK7Fr2e qvSL54lC/YVTG0+z5gFnCKZKTO/64gMOttXFPuAglQ5R4qsEblzaGygBxp38HWHZ6H5K ebRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321392; x=1686913392; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6ftpqq5gYPC2d4GxsLutQJxqbX8zDHS3zETPrp3Oo54=; b=UtMqpGp1f3TpyIUFSmO825cjR2ZYGFpekrkAbC7TZuEcdToRxHBUOeNwBNxGKxqvTx NXVYbVKYAqnCBQTi9HgwlmiRgBSl0xNimJMBK9ram6A5IzXiprVTyDLSCaY+T9m9VTPu pJP9lk1w9JyyA5HxSGu/Mq9UOdfqK4gQ1bwjXUoTSpoET4O2OBlA3GbOrOE7xAV6fVhB YHe8KDmsuAcebMjlgGPYMeMsC7Cm/vvRE7EkI8CvjOY4QvmJl/UVUlPYLaj9e2+iCRjm r7+kw0aL04/i+a8OJTLn+t06UtI7YqXyZ7SiKRZsugfuAxAIeyQZQUKrAPbsWTXsA0Sb z6XA== X-Gm-Message-State: AC+VfDxhpHXnKMXfBZNgCl7trBstPAD9VMyhdk9i1V8yQoIIqcyU3WjL mrj+OFUDhASzTZlMsavdQ2XK77OI38P4m+6Z5lU= X-Google-Smtp-Source: ACHHUZ7EI5rm5DDi6djx45RkmjWHPWR08NyCLQCWL3DFW8rmDn17wwcOFK+PehwpdQBbndWvFg8evw== X-Received: by 2002:a05:622a:144a:b0:3f5:aa8e:cae0 with SMTP id v10-20020a05622a144a00b003f5aa8ecae0mr3591244qtx.61.1684321391944; Wed, 17 May 2023 04:03:11 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id m9-20020ac84449000000b003f68223f7d7sm225925qtn.8.2023.05.17.04.03.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:03:11 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 06/28] net/sched: act_api: export generic tc action searcher Date: Wed, 17 May 2023 07:02:10 -0400 Message-Id: <20230517110232.29349-6-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC In P4TC we need to query the tc actions directly in a net namespace. Therefore export __tcf_idr_search(). Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/act_api.h | 2 ++ net/sched/act_api.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index 34b9a9ff05ee..cc392b994844 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -190,6 +190,8 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb, const struct tc_action_ops *ops, struct netlink_ext_ack *extack); int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index); +int __tcf_idr_search(struct net *net, const struct tc_action_ops *ops, + struct tc_action **a, u32 index); int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, struct tc_action **a, const struct tc_action_ops *ops, int bind, bool cpustats, u32 flags); diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 101c6debf356..ba0315e686bf 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -722,9 +722,8 @@ static int __tcf_generic_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int __tcf_idr_search(struct net *net, - const struct tc_action_ops *ops, - struct tc_action **a, u32 index) +int __tcf_idr_search(struct net *net, const struct tc_action_ops *ops, + struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, ops->net_id); @@ -733,6 +732,7 @@ static int __tcf_idr_search(struct net *net, return tcf_idr_search(tn, a, index); } +EXPORT_SYMBOL(__tcf_idr_search); static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index) { From patchwork Wed May 17 11:02:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244690 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 913331DDD2 for ; Wed, 17 May 2023 11:04:13 +0000 (UTC) Received: from mail-yb1-xb2f.google.com (mail-yb1-xb2f.google.com [IPv6:2607:f8b0:4864:20::b2f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8D4FE198 for ; Wed, 17 May 2023 04:03:37 -0700 (PDT) Received: by mail-yb1-xb2f.google.com with SMTP id 3f1490d57ef6-ba829e17aacso799382276.0 for ; Wed, 17 May 2023 04:03:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321399; x=1686913399; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=S+26kp6BBlBA/n28soCu1j/nI6xVz9eGfj+7N+7l2YI=; b=wHYOqKxF/IzjExrl10BWrpJ6sZ5WhmW5Y+PG8B31YFKv2qJbbXkBlmey2E05rRXvJ/ VBOqajAGiZ7yr74j+k1dqTQqfEbUy9K7BKEKrunKwprpXSY0rrayygYAuUdVpv4j9TjK A0IwzElYfGNDTCpMZs7U+4fG9kJ/pVuHcgvu3Xk2CdMkg/z3/BmpWZ1NIFeWx5XpKgdL NJkJ2Gciu/8vRj8LdJUj2lHlwfBTDGwB1goikPczZmmU85fm+TcI2+vQtJu7ATNS+4BA cwQnQ3nUzggWLUbjcdj43QWdm341TNojS1vhmRyg27z/4yeooSB3lloANZA6A0/d8Zx2 zwnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321399; x=1686913399; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=S+26kp6BBlBA/n28soCu1j/nI6xVz9eGfj+7N+7l2YI=; b=c27V4mUgmh53DxqXKdnYz91D+/L5EDwaag3o4NyFuVMCHjCX3FswzSGVhc/+Go/jxN Wh6bleE75C4VzIkOIxVj1S64vWZHDCoy5zpABrG1iHcPPC7AyupbxBEGNUfxAGBtuma3 QAJ6bVTLr4UEqG/YVx77sJQXRUXVQqNeJ7a4a28aLu9qEH3pwFuPM5gwgu/KeB7y7gOC QlWNZ9QdDdsw2im3s5NpDM1OHYLOxGOMG1hs50tmBPtpth8W1iexFQnBG3KSPoHnLPuV 4qznFCiX7roxsriWYuYfrH5wY8uO/8J5su5B+A6yn6ghIMn7le7I95olw5Sowpf4SyU4 VTsw== X-Gm-Message-State: AC+VfDzmt0EkrnOXUnERa63ZwLWJVhSKG+JFxEXVDbUZ5kXhJ5tXRINX 5y1Kz8D6z09PV0s+J8jUW92fK8ejJwVG5uEhaNA= X-Google-Smtp-Source: ACHHUZ6UIAmjwPS0y8VBNeQnQYxqczaHk7IG6xBqXABBxm4aQ4eXkGqmZQRW8SxCnO5l0Of6idGmXw== X-Received: by 2002:a25:3486:0:b0:ba6:7d34:2b54 with SMTP id b128-20020a253486000000b00ba67d342b54mr17698596yba.31.1684321399048; Wed, 17 May 2023 04:03:19 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id c22-20020a05620a135600b00758ae50d7ebsm516370qkl.123.2023.05.17.04.03.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:03:18 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 07/28] net/sched: act_api: add struct p4tc_action_ops as a parameter to lookup callback Date: Wed, 17 May 2023 07:02:11 -0400 Message-Id: <20230517110232.29349-7-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC For P4TC dynamic actions, we require information from struct tc_action_ops, specifically the action kind, to find and locate the dynamic action information for the lookup operation. Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/act_api.h | 3 ++- net/sched/act_api.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index cc392b994844..a0f443990f27 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -115,7 +115,8 @@ struct tc_action_ops { struct tcf_result *); /* called under RCU BH lock*/ int (*dump)(struct sk_buff *, struct tc_action *, int, int); void (*cleanup)(struct tc_action *); - int (*lookup)(struct net *net, struct tc_action **a, u32 index); + int (*lookup)(struct net *net, const struct tc_action_ops *ops, + struct tc_action **a, u32 index); int (*init)(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **act, struct tcf_proto *tp, diff --git a/net/sched/act_api.c b/net/sched/act_api.c index ba0315e686bf..788127329d96 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -728,7 +728,7 @@ int __tcf_idr_search(struct net *net, const struct tc_action_ops *ops, struct tc_action_net *tn = net_generic(net, ops->net_id); if (unlikely(ops->lookup)) - return ops->lookup(net, a, index); + return ops->lookup(net, ops, a, index); return tcf_idr_search(tn, a, index); } From patchwork Wed May 17 11:02:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244691 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7A984168D8 for ; Wed, 17 May 2023 11:04:15 +0000 (UTC) Received: from mail-qv1-xf2b.google.com (mail-qv1-xf2b.google.com [IPv6:2607:f8b0:4864:20::f2b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 61F5D5FE6 for ; Wed, 17 May 2023 04:03:45 -0700 (PDT) Received: by mail-qv1-xf2b.google.com with SMTP id 6a1803df08f44-62382464ca3so2708616d6.1 for ; Wed, 17 May 2023 04:03:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321406; x=1686913406; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=xk52L0V25AupBGI2GjyEtBqD739kGIecliMY3ZyLU6I=; b=Afin7OhygdT8qU2n7X43OTh8CWyAsm6mbCmI9Rg56444oMswOa7xA+sQpnhdBYnXme X0KMVWwUu/sB5+k1LHx0RuznaQVay/XesCXZgmswXzN6NNFU8Ia0ESxuo58NqBzf5GMH 5BA6E74x5M7QpbGfXtSnuydTcOFsULtew6CokPmcTjrOLihuR5pBWJjlnUOu/3Z+O5Nz W7G3nM7flBkJxiKm+wzNk2E4v0k2B7J2/E+9dQsvMztZA688NBMwFqSRKaXzLJSxv4/8 LkuIDcoJNXmvwwu9R+5Sg1UIFborvANlmJuL7nd4xF6H1zQ0sMx33xIniRlx1qTVMvFi zlQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321406; x=1686913406; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=xk52L0V25AupBGI2GjyEtBqD739kGIecliMY3ZyLU6I=; b=TRm05l0dm7IRsw3MscTDOgK/liLoVAfPHHm7fYsl12p/bIn8PcLSPSHSeKkq91mGE3 pIS9h4UqkyN19qe6ArTLfMuEqT48L4kcc0MpMVIlUMW5nstW91osNMgziMf2hfytkHet /epo3eSmYG4LeJ4/In8PQ+2K15+MpsXVS4PQrYVam0PtDMvqxXZ0SEeH1fcAW5lfCEMw ere84/EQ0LuKBJf0lJ/LMbdzM6dIk8IENPcfXqGKthZsZh7ZdmEgH3hgf2D9o+txegt0 pH0wm9D3RVWlIGXOfd81Voj+k8BDSCv9g0kbhaIhH2cezdUZ3MwDo20WV5g1qE4XglHU ohLg== X-Gm-Message-State: AC+VfDyUeOd30GBQAbwR69bM6yZzc+Ocb1UiVtDmt3D355Z7lTDQrios vjKw/NzpXsb2LDD8GVg3NMw8gJ1cPcT2jI5bgLQ= X-Google-Smtp-Source: ACHHUZ55ygTMQAJq6MidV3oNZ6NGtFmO/znKxxXeQ/dmz9q26WsAqVqZJ4lN6XsPbB+fb2RmnTHklg== X-Received: by 2002:a05:6214:c6b:b0:623:66ee:79b2 with SMTP id t11-20020a0562140c6b00b0062366ee79b2mr15388432qvj.36.1684321406342; Wed, 17 May 2023 04:03:26 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id i11-20020a0cfd2b000000b0061b73e331b2sm6323913qvs.30.2023.05.17.04.03.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:03:25 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 08/28] net: introduce rcu_replace_pointer_rtnl Date: Wed, 17 May 2023 07:02:12 -0400 Message-Id: <20230517110232.29349-8-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC We use rcu_replace_pointer(rcu_ptr, ptr, lockdep_rtnl_is_held()) throughout the P4TC infrastructure code. It may be useful for other use cases, so we create a helper. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/linux/rtnetlink.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 3d6cf306cd55..971055e6633f 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -62,6 +62,18 @@ static inline bool lockdep_rtnl_is_held(void) #define rcu_dereference_rtnl(p) \ rcu_dereference_check(p, lockdep_rtnl_is_held()) +/** + * rcu_replace_pointer_rtnl - replace an RCU pointer under rtnl_lock, returning + * its old value + * @rcu_ptr: RCU pointer, whose old value is returned + * @ptr: regular pointer + * + * Perform a replacement under rtnl_lock, where @rcu_ptr is an RCU-annotated + * pointer. The old value of @rcu_ptr is returned, and @rcu_ptr is set to @ptr + */ +#define rcu_replace_pointer_rtnl(rcu_ptr, ptr) \ + rcu_replace_pointer(rcu_ptr, ptr, lockdep_rtnl_is_held()) + /** * rtnl_dereference - fetch RCU pointer when updates are prevented by RTNL * @p: The pointer to read, prior to dereferencing From patchwork Wed May 17 11:02:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244692 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B38CC168D8 for ; Wed, 17 May 2023 11:04:22 +0000 (UTC) Received: from mail-qk1-x736.google.com (mail-qk1-x736.google.com [IPv6:2607:f8b0:4864:20::736]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AE6AEF3 for ; Wed, 17 May 2023 04:03:49 -0700 (PDT) Received: by mail-qk1-x736.google.com with SMTP id af79cd13be357-757942bd912so36746085a.2 for ; Wed, 17 May 2023 04:03:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321414; x=1686913414; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=E2icZgj75N7YHEh5BHv7MRh1AjkwPp1BwTBEW4VCGug=; b=Lpc3Ytk2zlKdGyvgWHZ3DgZWG9VVvYJDf/BShs7hM1CiBzT5peIQ5Kq2+x4WRaLzS0 +VipnsEaVYbz5+pYbpW6T3ZvvN8qy4Wir141ukyUTwlbCcqsEQD6nT3WAhWRRo9zuDdt FAVehl76qw5pMFajuasMH3mDCBFqAaHV1P+hTRRJowcAI4nhMCxZMc2nNwBVwHpBuZDF Yms4fg1OrE3tZ3QQ4HdiO6xYL4Voy7EERKQgUUqvD0qqoQoDB/1fPD2woalR8Z8fJU6x YTkQvsd6tcnUJMaTSi/fbnYvWf0iUQSkiZdK4WGqa4E969cfvGFKrj1cBZoa5PuZJcC6 HzNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321414; x=1686913414; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=E2icZgj75N7YHEh5BHv7MRh1AjkwPp1BwTBEW4VCGug=; b=dYsBZ2I3cc+aJis0W+I+URvWmEjJe9mveKYylJOG+BgTmVVwM9wtIjTfCgvYwmRfpf +PBF8pDoVHmbCjhTEq5higYmnnL2norAmnWDLqCrKeZnJnhZBVqAJdj16DitCM/JFPXI YZaTrWqro67gqe4oOX2q5AnIkFlHwTy9LIEihFT7o70qqJcUlA76a/BmA1Bd9z4j0xFA JuIKdHYBz2009c+lFlB/hEP+1KXqcGdENj9mExqSZHCeMFBGUgCDdrVX1mdMetN8YroF oVHkFazEPtWjU864UfbaHYVgnFBFBQ3k8fJhIqi3OqxzzHomOUM1/F7H9A1NR3pg3n0F Ga2Q== X-Gm-Message-State: AC+VfDwe+sPS/OLQm+h2PLGZmLsueXkfclGIGnj3j9bLcOX8jPhmdWq+ bxZeqo1jw8vn5xNbxwfFJQAl1mObeU7zt0f/Ctg= X-Google-Smtp-Source: ACHHUZ7gNvnqy13AzdXy9LAVsME56oNoauCxVzzAN6a0U3bjZpJIONLRADLM6V2daCI3Q773ScdZaQ== X-Received: by 2002:a05:6214:c8d:b0:5e3:d150:3168 with SMTP id r13-20020a0562140c8d00b005e3d1503168mr57854382qvr.18.1684321414053; Wed, 17 May 2023 04:03:34 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id g6-20020a05620a13c600b0075772c756e0sm525089qkl.101.2023.05.17.04.03.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:03:32 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 09/28] p4tc: add P4 data types Date: Wed, 17 May 2023 07:02:13 -0400 Message-Id: <20230517110232.29349-9-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Introduce abstraction that represents P4 data types. This also introduces the Kconfig and Makefile which later patches use. Types could be little, host or big endian definitions. The abstraction also supports defining: a) bitstrings using annotations in control that look like "bitX" where X is the number of bits defined in a type b) bitslices such that one can define in control bit8[0-3] and bit16[0-9]. A 4-bit slice from bits 0-3 and a 10-bit slice from bits 0-9 respectively. Each type has a bitsize, a name (for debugging purposes), an ID and methods/ops. The P4 types will be used by metadata, headers, dynamic actions and other part of P4TC. Each type has four ops: - validate_p4t: Which validates if a given value of a specific type meets valid boundary conditions. - create_bitops: Which, given a bitsize, bitstart and bitend allocates and returns a mask and a shift value. For example, if we have type bit8[3-3] meaning bitstart = 3 and bitend = 3, we'll create a mask which would only give us the fourth bit of a bit8 value, that is, 0x08. Since we are interested in the fourth bit, the bit shift value will be 3. - host_read : Which reads the value of a given type and transforms it to host order - host_write : Which writes a provided host order value and transforms it to the type's native order Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/p4tc_types.h | 87 +++ include/uapi/linux/p4tc.h | 40 ++ net/sched/Kconfig | 8 + net/sched/Makefile | 2 + net/sched/p4tc/Makefile | 3 + net/sched/p4tc/p4tc_types.c | 1354 +++++++++++++++++++++++++++++++++++ 6 files changed, 1494 insertions(+) create mode 100644 include/net/p4tc_types.h create mode 100644 include/uapi/linux/p4tc.h create mode 100644 net/sched/p4tc/Makefile create mode 100644 net/sched/p4tc/p4tc_types.c diff --git a/include/net/p4tc_types.h b/include/net/p4tc_types.h new file mode 100644 index 000000000000..26594c0b0298 --- /dev/null +++ b/include/net/p4tc_types.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NET_P4TYPES_H +#define __NET_P4TYPES_H + +#include +#include +#include + +#include + +#define P4T_MAX_BITSZ 128 + +struct p4tc_type_mask_shift { + void *mask; + u8 shift; +}; + +struct p4tc_type; +struct p4tc_type_ops { + int (*validate_p4t)(struct p4tc_type *container, void *value, u16 startbit, + u16 endbit, struct netlink_ext_ack *extack); + struct p4tc_type_mask_shift *(*create_bitops)(u16 bitsz, + u16 bitstart, + u16 bitend, + struct netlink_ext_ack *extack); + int (*host_read)(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval); + int (*host_write)(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval); + void (*print)(struct net *net, struct p4tc_type *container, + const char *prefix, void *val); +}; + +#define P4T_MAX_STR_SZ 32 +struct p4tc_type { + char name[P4T_MAX_STR_SZ]; + const struct p4tc_type_ops *ops; + size_t container_bitsz; + size_t bitsz; + int typeid; +}; + +struct p4tc_type *p4type_find_byid(int id); +bool p4tc_type_unsigned(int typeid); + +int p4t_copy(struct p4tc_type_mask_shift *dst_mask_shift, + struct p4tc_type *dst_t, void *dstv, + struct p4tc_type_mask_shift *src_mask_shift, + struct p4tc_type *src_t, void *srcv); +int p4t_cmp(struct p4tc_type_mask_shift *dst_mask_shift, + struct p4tc_type *dst_t, void *dstv, + struct p4tc_type_mask_shift *src_mask_shift, + struct p4tc_type *src_t, void *srcv); +void p4t_release(struct p4tc_type_mask_shift *mask_shift); + +int p4tc_register_types(void); +void p4tc_unregister_types(void); + +#ifdef CONFIG_RETPOLINE +int __p4tc_type_host_read(const struct p4tc_type_ops *ops, + struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval); +int __p4tc_type_host_write(const struct p4tc_type_ops *ops, + struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval); +#else +static inline int __p4tc_type_host_read(const struct p4tc_type_ops *ops, + struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, + void *sval, void *dval) +{ + return ops->host_read(container, mask_shift, sval, dval); +} +static inline int __p4tc_type_host_write(const struct p4tc_type_ops *ops, + struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, + void *sval, void *dval) +{ + return ops->host_write(container, mask_shift, sval, dval); +} +#endif + +#endif diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h new file mode 100644 index 000000000000..2b6f126dbeb5 --- /dev/null +++ b/include/uapi/linux/p4tc.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_P4TC_H +#define __LINUX_P4TC_H + +#define P4TC_MAX_KEYSZ 512 + +enum { + P4T_UNSPEC, + P4T_U8 = 1, /* NLA_U8 */ + P4T_U16 = 2, /* NLA_U16 */ + P4T_U32 = 3, /* NLA_U32 */ + P4T_U64 = 4, /* NLA_U64 */ + P4T_STRING = 5, /* NLA_STRING */ + P4T_FLAG = 6, /* NLA_FLAG */ + P4T_MSECS = 7, /* NLA_MSECS */ + P4T_NESTED = 8, /* NLA_NESTED */ + P4T_NESTED_ARRAY = 9, /* NLA_NESTED_ARRAY */ + P4T_NUL_STRING = 10, /* NLA_NUL_STRING */ + P4T_BINARY = 11, /* NLA_BINARY */ + P4T_S8 = 12, /* NLA_S8 */ + P4T_S16 = 13, /* NLA_S16 */ + P4T_S32 = 14, /* NLA_S32 */ + P4T_S64 = 15, /* NLA_S64 */ + P4T_BITFIELD32 = 16, /* NLA_BITFIELD32 */ + P4T_MACADDR = 17, /* NLA_REJECT */ + P4T_IPV4ADDR, + P4T_BE16, + P4T_BE32, + P4T_BE64, + P4T_U128, + P4T_S128, + P4T_PATH, + P4T_BOOL, + P4T_DEV, + P4T_KEY, + __P4T_MAX, +}; +#define P4T_MAX (__P4T_MAX - 1) + +#endif diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 4b95cb1ac435..ea57a4c7b205 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -676,6 +676,14 @@ config NET_EMATCH_IPT To compile this code as a module, choose M here: the module will be called em_ipt. +config NET_P4_TC + bool "P4 TC support" + select NET_CLS_ACT + help + Say Y here if you want to use P4 features on top of TC. + The concept of Pipelines, Tables, metadata will be enabled + with this option. + config NET_CLS_ACT bool "Actions" select NET_CLS diff --git a/net/sched/Makefile b/net/sched/Makefile index b5fd49641d91..937b8f8a90ce 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -82,3 +82,5 @@ obj-$(CONFIG_NET_EMATCH_TEXT) += em_text.o obj-$(CONFIG_NET_EMATCH_CANID) += em_canid.o obj-$(CONFIG_NET_EMATCH_IPSET) += em_ipset.o obj-$(CONFIG_NET_EMATCH_IPT) += em_ipt.o + +obj-$(CONFIG_NET_P4_TC) += p4tc/ diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile new file mode 100644 index 000000000000..dd1358c9e802 --- /dev/null +++ b/net/sched/p4tc/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y := p4tc_types.o diff --git a/net/sched/p4tc/p4tc_types.c b/net/sched/p4tc/p4tc_types.c new file mode 100644 index 000000000000..3a6d643d453d --- /dev/null +++ b/net/sched/p4tc/p4tc_types.c @@ -0,0 +1,1354 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_types.c - P4 datatypes + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_IDR(p4tc_types_idr); + +static void p4tc_types_put(void) +{ + unsigned long tmp, typeid; + struct p4tc_type *type; + + idr_for_each_entry_ul(&p4tc_types_idr, type, tmp, typeid) { + idr_remove(&p4tc_types_idr, typeid); + kfree(type); + } +} + +struct p4tc_type *p4type_find_byid(int typeid) +{ + return idr_find(&p4tc_types_idr, typeid); +} + +static struct p4tc_type *p4type_find_byname(const char *name) +{ + struct p4tc_type *type; + unsigned long tmp, typeid; + + idr_for_each_entry_ul(&p4tc_types_idr, type, tmp, typeid) { + if (!strncmp(type->name, name, P4T_MAX_STR_SZ)) + return type; + } + + return NULL; +} + +bool p4tc_type_unsigned(int typeid) +{ + switch (typeid) { + case P4T_U8: + case P4T_U16: + case P4T_U32: + case P4T_U64: + case P4T_U128: + case P4T_BOOL: + return true; + default: + return false; + } +} + +int p4t_copy(struct p4tc_type_mask_shift *dst_mask_shift, + struct p4tc_type *dst_t, void *dstv, + struct p4tc_type_mask_shift *src_mask_shift, + struct p4tc_type *src_t, void *srcv) +{ + u64 readval[BITS_TO_U64(P4TC_MAX_KEYSZ)] = {0}; + const struct p4tc_type_ops *srco, *dsto; + + dsto = dst_t->ops; + srco = src_t->ops; + + __p4tc_type_host_read(srco, src_t, src_mask_shift, srcv, + &readval); + __p4tc_type_host_write(dsto, dst_t, dst_mask_shift, &readval, + dstv); + + return 0; +} + +int p4t_cmp(struct p4tc_type_mask_shift *dst_mask_shift, + struct p4tc_type *dst_t, void *dstv, + struct p4tc_type_mask_shift *src_mask_shift, + struct p4tc_type *src_t, void *srcv) +{ + u64 a[BITS_TO_U64(P4TC_MAX_KEYSZ)] = {0}; + u64 b[BITS_TO_U64(P4TC_MAX_KEYSZ)] = {0}; + const struct p4tc_type_ops *srco, *dsto; + + dsto = dst_t->ops; + srco = src_t->ops; + + __p4tc_type_host_read(dsto, dst_t, dst_mask_shift, dstv, a); + __p4tc_type_host_read(srco, src_t, src_mask_shift, srcv, b); + + return memcmp(a, b, sizeof(a)); +} + +void p4t_release(struct p4tc_type_mask_shift *mask_shift) +{ + kfree(mask_shift->mask); + kfree(mask_shift); +} + +static int p4t_validate_bitpos(u16 bitstart, u16 bitend, u16 maxbitstart, + u16 maxbitend, struct netlink_ext_ack *extack) +{ + if (bitstart > maxbitstart) { + NL_SET_ERR_MSG_MOD(extack, "bitstart too high"); + return -EINVAL; + } + if (bitend > maxbitend) { + NL_SET_ERR_MSG_MOD(extack, "bitend too high"); + return -EINVAL; + } + + return 0; +} + +//XXX: Latter immedv will be 64 bits +static int p4t_u32_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + u32 container_maxsz = U32_MAX; + u32 *val = value; + size_t maxval; + int ret; + + ret = p4t_validate_bitpos(bitstart, bitend, 31, 31, extack); + if (ret < 0) + return ret; + + maxval = GENMASK(bitend, 0); + if (val && (*val > container_maxsz || *val > maxval)) { + NL_SET_ERR_MSG_MOD(extack, "U32 value out of range"); + return -EINVAL; + } + + return 0; +} + +static struct p4tc_type_mask_shift * +p4t_u32_bitops(u16 bitsiz, u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + u32 mask = GENMASK(bitend, bitstart); + struct p4tc_type_mask_shift *mask_shift; + u32 *cmask; + + mask_shift = kzalloc(sizeof(*mask_shift), GFP_KERNEL); + if (!mask_shift) + return ERR_PTR(-ENOMEM); + + cmask = kzalloc(sizeof(u32), GFP_KERNEL); + if (!cmask) { + kfree(mask_shift); + return ERR_PTR(-ENOMEM); + } + + *cmask = mask; + + mask_shift->mask = cmask; + mask_shift->shift = bitstart; + + return mask_shift; +} + +static int p4t_u32_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u32 *dst = dval; + u32 *src = sval; + u32 maskedst = 0; + u8 shift = 0; + + if (mask_shift) { + u32 *dmask = mask_shift->mask; + + maskedst = *dst & ~*dmask; + shift = mask_shift->shift; + } + + *dst = maskedst | (*src << shift); + + return 0; +} + +static void p4t_u32_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + u32 *v = val; + + pr_info("%s 0x%x\n", prefix, *v); +} + +static int p4t_u32_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u32 *dst = dval; + u32 *src = sval; + + if (mask_shift) { + u32 *smask = mask_shift->mask; + u8 shift = mask_shift->shift; + + *dst = (*src & *smask) >> shift; + } else { + *dst = *src; + } + + return 0; +} + +/*XXX: future converting immedv to 64 bits */ +static int p4t_s32_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + s32 minsz = S32_MIN, maxsz = S32_MAX; + s32 *val = value; + + if (val && (*val > maxsz || *val < minsz)) { + NL_SET_ERR_MSG_MOD(extack, "S32 value out of range"); + return -EINVAL; + } + + return 0; +} + +static int p4t_s32_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + s32 *dst = dval; + s32 *src = sval; + + *dst = *src; + + return 0; +} + +static int p4t_s32_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + s32 *dst = dval; + s32 *src = sval; + + *dst = *src; + + return 0; +} + +static void p4t_s32_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + s32 *v = val; + + pr_info("%s %x\n", prefix, *v); +} + +static void p4t_s64_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + s64 *v = val; + + pr_info("%s 0x%llx\n", prefix, *v); +} + +static int p4t_be32_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + size_t container_maxsz = U32_MAX; + __u32 *val_u32 = value; + __be32 val = 0; + size_t maxval; + int ret; + + ret = p4t_validate_bitpos(bitstart, bitend, 31, 31, extack); + if (ret < 0) + return ret; + + if (value) + val = (__be32)(be32_to_cpu(*val_u32)); + + maxval = GENMASK(bitend, 0); + if (val && (val > container_maxsz || val > maxval)) { + NL_SET_ERR_MSG_MOD(extack, "BE32 value out of range"); + return -EINVAL; + } + + return 0; +} + +static int p4t_be32_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u32 *dst = dval; + u32 *src = sval; + u32 readval = be32_to_cpu(*src); + + if (mask_shift) { + u32 *smask = mask_shift->mask; + u8 shift = mask_shift->shift; + + readval = (readval & *smask) >> shift; + } + + *dst = readval; + + return 0; +} + +static int p4t_be32_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + __be32 *dst = dval; + u32 maskedst = 0; + u32 *src = sval; + u8 shift = 0; + + if (mask_shift) { + u32 *dmask = (u32 *)mask_shift->mask; + + maskedst = *dst & ~*dmask; + shift = mask_shift->shift; + } + + *dst = cpu_to_be32(maskedst | (*src << shift)); + + return 0; +} + +static void p4t_be32_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + __be32 *v = val; + + pr_info("%s 0x%x\n", prefix, *v); +} + +static int p4t_be64_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u64 *dst = dval; + u64 *src = sval; + u64 readval = be64_to_cpu(*src); + + if (mask_shift) { + u64 *smask = mask_shift->mask; + u8 shift = mask_shift->shift; + + readval = (readval & *smask) >> shift; + } + + *dst = readval; + + return 0; +} + +static int p4t_be64_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + __be64 *dst = dval; + u64 maskedst = 0; + u64 *src = sval; + u8 shift = 0; + + if (mask_shift) { + u64 *dmask = (u64 *)mask_shift->mask; + + maskedst = *dst & ~*dmask; + shift = mask_shift->shift; + } + + *dst = cpu_to_be64(maskedst | (*src << shift)); + + return 0; +} + +static void p4t_be64_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + __be64 *v = val; + + pr_info("%s 0x%llx\n", prefix, *v); +} + +static int p4t_u16_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + u16 container_maxsz = U16_MAX; + u16 *val = value; + u16 maxval; + int ret; + + ret = p4t_validate_bitpos(bitstart, bitend, 15, 15, extack); + if (ret < 0) + return ret; + + maxval = GENMASK(bitend, 0); + if (val && (*val > container_maxsz || *val > maxval)) { + NL_SET_ERR_MSG_MOD(extack, "U16 value out of range"); + return -EINVAL; + } + + return 0; +} + +static struct p4tc_type_mask_shift * +p4t_u16_bitops(u16 bitsiz, u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + u16 mask = GENMASK(bitend, bitstart); + struct p4tc_type_mask_shift *mask_shift; + u16 *cmask; + + mask_shift = kzalloc(sizeof(*mask_shift), GFP_KERNEL); + if (!mask_shift) + return ERR_PTR(-ENOMEM); + + cmask = kzalloc(sizeof(u16), GFP_KERNEL); + if (!cmask) { + kfree(mask_shift); + return ERR_PTR(-ENOMEM); + } + + *cmask = mask; + + mask_shift->mask = cmask; + mask_shift->shift = bitstart; + + return mask_shift; +} + +static int p4t_u16_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u16 *dst = dval; + u16 *src = sval; + u16 maskedst = 0; + u8 shift = 0; + + if (mask_shift) { + u16 *dmask = mask_shift->mask; + + maskedst = *dst & ~*dmask; + shift = mask_shift->shift; + } + + *dst = maskedst | (*src << shift); + + return 0; +} + +static void p4t_u16_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + u16 *v = val; + + pr_info("%s 0x%x\n", prefix, *v); +} + +static int p4t_u16_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u16 *dst = dval; + u16 *src = sval; + + if (mask_shift) { + u16 *smask = mask_shift->mask; + u8 shift = mask_shift->shift; + + *dst = (*src & *smask) >> shift; + } else { + *dst = *src; + } + + return 0; +} + +static int p4t_s16_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + s16 minsz = S16_MIN, maxsz = S16_MAX; + s16 *val = value; + + if (val && (*val > maxsz || *val < minsz)) { + NL_SET_ERR_MSG_MOD(extack, "S16 value out of range"); + return -EINVAL; + } + + return 0; +} + +static int p4t_s16_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + s16 *dst = dval; + s16 *src = sval; + + *dst = *src; + + return 0; +} + +static int p4t_s16_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + s16 *dst = dval; + s16 *src = sval; + + *src = *dst; + + return 0; +} + +static void p4t_s16_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + s16 *v = val; + + pr_info("%s %d\n", prefix, *v); +} + +static int p4t_be16_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + __be16 container_maxsz = U16_MAX; + __u16 *val_u16 = value; + __be16 val = 0; + size_t maxval; + int ret; + + ret = p4t_validate_bitpos(bitstart, bitend, 15, 15, extack); + if (ret < 0) + return ret; + + if (value) + val = (__be16)(be16_to_cpu(*val_u16)); + + maxval = GENMASK(bitend, 0); + if (val && (val > container_maxsz || val > maxval)) { + NL_SET_ERR_MSG_MOD(extack, "BE16 value out of range"); + return -EINVAL; + } + + return 0; +} + +static int p4t_be16_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u16 *dst = dval; + u16 *src = sval; + u16 readval = be16_to_cpu(*src); + + if (mask_shift) { + u16 *smask = mask_shift->mask; + u8 shift = mask_shift->shift; + + readval = (readval & *smask) >> shift; + } + + *dst = readval; + + return 0; +} + +static int p4t_be16_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + __be16 *dst = dval; + u16 maskedst = 0; + u16 *src = sval; + u8 shift = 0; + + if (mask_shift) { + u16 *dmask = (u16 *)mask_shift->mask; + + maskedst = *dst & ~*dmask; + shift = mask_shift->shift; + } + + *dst = cpu_to_be16(maskedst | (*src << shift)); + + return 0; +} + +static void p4t_be16_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + __be16 *v = val; + + pr_info("%s 0x%x\n", prefix, *v); +} + +static int p4t_u8_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + u8 *val = value; + size_t container_maxsz = U8_MAX; + u8 maxval; + int ret; + + ret = p4t_validate_bitpos(bitstart, bitend, 7, 7, extack); + if (ret < 0) + return ret; + + maxval = GENMASK(bitend, 0); + if (val && (*val > container_maxsz || *val > maxval)) { + NL_SET_ERR_MSG_MOD(extack, "U8 value out of range"); + return -EINVAL; + } + + return 0; +} + +static struct p4tc_type_mask_shift * +p4t_u8_bitops(u16 bitsiz, u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + u8 mask = GENMASK(bitend, bitstart); + struct p4tc_type_mask_shift *mask_shift; + u8 *cmask; + + mask_shift = kzalloc(sizeof(*mask_shift), GFP_KERNEL); + if (!mask_shift) + return ERR_PTR(-ENOMEM); + + cmask = kzalloc(sizeof(u8), GFP_KERNEL); + if (!cmask) { + kfree(mask_shift); + return ERR_PTR(-ENOMEM); + } + + *cmask = mask; + + mask_shift->mask = cmask; + mask_shift->shift = bitstart; + + return mask_shift; +} + +static int p4t_u8_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u8 *dst = dval; + u8 *src = sval; + u8 maskedst = 0; + u8 shift = 0; + + if (mask_shift) { + u8 *dmask = (u8 *)mask_shift->mask; + + maskedst = *dst & ~*dmask; + shift = mask_shift->shift; + } + + *dst = maskedst | (*src << shift); + + return 0; +} + +static void p4t_u8_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + u8 *v = val; + + pr_info("%s 0x%x\n", prefix, *v); +} + +static int p4t_u8_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u8 *dst = dval; + u8 *src = sval; + + if (mask_shift) { + u8 *smask = mask_shift->mask; + u8 shift = mask_shift->shift; + + *dst = (*src & *smask) >> shift; + } else { + *dst = *src; + } + + return 0; +} + +static int p4t_s8_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + s8 minsz = S8_MIN, maxsz = S8_MAX; + s8 *val = value; + + if (val && (*val > maxsz || *val < minsz)) { + NL_SET_ERR_MSG_MOD(extack, "S8 value out of range"); + return -EINVAL; + } + + return 0; +} + +static int p4t_s8_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + s8 *dst = dval; + s8 *src = sval; + + *dst = *src; + + return 0; +} + +static void p4t_s8_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + s8 *v = val; + + pr_info("%s %d\n", prefix, *v); +} + +static int p4t_u64_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + u64 container_maxsz = U64_MAX; + u8 *val = value; + u64 maxval; + int ret; + + ret = p4t_validate_bitpos(bitstart, bitend, 63, 63, extack); + if (ret < 0) + return ret; + + maxval = GENMASK_ULL(bitend, 0); + if (val && (*val > container_maxsz || *val > maxval)) { + NL_SET_ERR_MSG_MOD(extack, "U64 value out of range"); + return -EINVAL; + } + + return 0; +} + +static struct p4tc_type_mask_shift * +p4t_u64_bitops(u16 bitsiz, u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + u64 mask = GENMASK(bitend, bitstart); + struct p4tc_type_mask_shift *mask_shift; + u64 *cmask; + + mask_shift = kzalloc(sizeof(*mask_shift), GFP_KERNEL); + if (!mask_shift) + return ERR_PTR(-ENOMEM); + + cmask = kzalloc(sizeof(u64), GFP_KERNEL); + if (!cmask) { + kfree(mask_shift); + return ERR_PTR(-ENOMEM); + } + + *cmask = mask; + + mask_shift->mask = cmask; + mask_shift->shift = bitstart; + + return mask_shift; +} + +static int p4t_u64_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u64 *dst = dval; + u64 *src = sval; + u64 maskedst = 0; + u8 shift = 0; + + if (mask_shift) { + u64 *dmask = (u64 *)mask_shift->mask; + + maskedst = *dst & ~*dmask; + shift = mask_shift->shift; + } + + *dst = maskedst | (*src << shift); + + return 0; +} + +static void p4t_u64_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + u64 *v = val; + + pr_info("%s 0x%llx\n", prefix, *v); +} + +static int p4t_u64_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u64 *dst = dval; + u64 *src = sval; + + if (mask_shift) { + u64 *smask = mask_shift->mask; + u8 shift = mask_shift->shift; + + *dst = (*src & *smask) >> shift; + } else { + *dst = *src; + } + + return 0; +} + +/* As of now, we are not allowing bitops for u128 */ +static int p4t_u128_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + if (bitstart != 0 || bitend != 127) { + NL_SET_ERR_MSG_MOD(extack, + "Only valid bit type larger than bit64 is bit128"); + return -EINVAL; + } + + return 0; +} + +static int p4t_u128_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + memcpy(sval, dval, sizeof(__u64) * 2); + + return 0; +} + +static int p4t_u128_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + memcpy(sval, dval, sizeof(__u64) * 2); + + return 0; +} + +static void p4t_u128_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + u64 *v = val; + + pr_info("%s[0-63] %16llx", prefix, v[0]); + pr_info("%s[64-127] %16llx", prefix, v[1]); +} + +static int p4t_ipv4_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + /* Not allowing bit-slices for now */ + if (bitstart != 0 || bitend != 31) { + NL_SET_ERR_MSG_MOD(extack, "Invalid bitstart or bitend"); + return -EINVAL; + } + + return 0; +} + +static void p4t_ipv4_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + u32 *v32 = val; + u8 *v = val; + + *v32 = cpu_to_be32(*v32); + + pr_info("%s %u.%u.%u.%u\n", prefix, v[0], v[1], v[2], v[3]); +} + +static int p4t_mac_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + if (bitstart != 0 || bitend != 47) { + NL_SET_ERR_MSG_MOD(extack, "Invalid bitstart or bitend"); + return -EINVAL; + } + + return 0; +} + +static void p4t_mac_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + u8 *v = val; + + pr_info("%s %02X:%02x:%02x:%02x:%02x:%02x\n", prefix, v[0], v[1], v[2], + v[3], v[4], v[5]); +} + +static int p4t_dev_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + if (bitstart != 0 || bitend != 31) { + NL_SET_ERR_MSG_MOD(extack, "Invalid start or endbit values"); + return -EINVAL; + } + + return 0; +} + +static int p4t_dev_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u32 *src = sval; + u32 *dst = dval; + + *dst = *src; + + return 0; +} + +static int p4t_dev_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + u32 *src = sval; + u32 *dst = dval; + + *dst = *src; + + return 0; +} + +static void p4t_dev_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + const u32 *ifindex = val; + struct net_device *dev = dev_get_by_index_rcu(net, *ifindex); + + pr_info("%s %s\n", prefix, dev->name); +} + +static int p4t_key_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + memcpy(dval, sval, BITS_TO_BYTES(container->bitsz)); + + return 0; +} + +static int p4t_key_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + memcpy(dval, sval, BITS_TO_BYTES(container->bitsz)); + + return 0; +} + +static void p4t_key_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + u64 *v = val; + u16 bitstart = 0, bitend = 63; + int i; + + for (i = 0; i < BITS_TO_U64(container->bitsz); i++) { + pr_info("%s[%u-%u] %16llx\n", prefix, bitstart, bitend, v[i]); + bitstart += 64; + bitend += 64; + } +} + +static int p4t_key_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + if (p4t_validate_bitpos(bitstart, bitend, 0, P4TC_MAX_KEYSZ, extack)) + return -EINVAL; + + return 0; +} + +static int p4t_bool_validate(struct p4tc_type *container, void *value, + u16 bitstart, u16 bitend, + struct netlink_ext_ack *extack) +{ + bool *val = value; + int ret; + + ret = p4t_validate_bitpos(bitstart, bitend, 31, 31, extack); + if (ret < 0) + return ret; + + if (*val == true || *val == false) + return 0; + + return -EINVAL; +} + +static int p4t_bool_hread(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + bool *dst = dval; + bool *src = sval; + + *dst = *src; + + return 0; +} + +static int p4t_bool_write(struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + bool *dst = dval; + bool *src = sval; + + *dst = *src; + + return 0; +} + +static void p4t_bool_print(struct net *net, struct p4tc_type *container, + const char *prefix, void *val) +{ + bool *v = val; + + pr_info("%s %s", prefix, *v ? "true" : "false"); +} + +static const struct p4tc_type_ops u8_ops = { + .validate_p4t = p4t_u8_validate, + .create_bitops = p4t_u8_bitops, + .host_read = p4t_u8_hread, + .host_write = p4t_u8_write, + .print = p4t_u8_print, +}; + +static const struct p4tc_type_ops u16_ops = { + .validate_p4t = p4t_u16_validate, + .create_bitops = p4t_u16_bitops, + .host_read = p4t_u16_hread, + .host_write = p4t_u16_write, + .print = p4t_u16_print, +}; + +static const struct p4tc_type_ops u32_ops = { + .validate_p4t = p4t_u32_validate, + .create_bitops = p4t_u32_bitops, + .host_read = p4t_u32_hread, + .host_write = p4t_u32_write, + .print = p4t_u32_print, +}; + +static const struct p4tc_type_ops u64_ops = { + .validate_p4t = p4t_u64_validate, + .create_bitops = p4t_u64_bitops, + .host_read = p4t_u64_hread, + .host_write = p4t_u64_write, + .print = p4t_u64_print, +}; + +static const struct p4tc_type_ops u128_ops = { + .validate_p4t = p4t_u128_validate, + .host_read = p4t_u128_hread, + .host_write = p4t_u128_write, + .print = p4t_u128_print, +}; + +static const struct p4tc_type_ops s8_ops = { + .validate_p4t = p4t_s8_validate, + .host_read = p4t_s8_hread, + .print = p4t_s8_print, +}; + +static const struct p4tc_type_ops s16_ops = { + .validate_p4t = p4t_s16_validate, + .host_read = p4t_s16_hread, + .host_write = p4t_s16_write, + .print = p4t_s16_print, +}; + +static const struct p4tc_type_ops s32_ops = { + .validate_p4t = p4t_s32_validate, + .host_read = p4t_s32_hread, + .host_write = p4t_s32_write, + .print = p4t_s32_print, +}; + +static const struct p4tc_type_ops s64_ops = { + .print = p4t_s64_print, +}; + +static const struct p4tc_type_ops s128_ops = {}; + +static const struct p4tc_type_ops be16_ops = { + .validate_p4t = p4t_be16_validate, + .create_bitops = p4t_u16_bitops, + .host_read = p4t_be16_hread, + .host_write = p4t_be16_write, + .print = p4t_be16_print, +}; + +static const struct p4tc_type_ops be32_ops = { + .validate_p4t = p4t_be32_validate, + .create_bitops = p4t_u32_bitops, + .host_read = p4t_be32_hread, + .host_write = p4t_be32_write, + .print = p4t_be32_print, +}; + +static const struct p4tc_type_ops be64_ops = { + .validate_p4t = p4t_u64_validate, + .host_read = p4t_be64_hread, + .host_write = p4t_be64_write, + .print = p4t_be64_print, +}; + +static const struct p4tc_type_ops string_ops = {}; +static const struct p4tc_type_ops nullstring_ops = {}; + +static const struct p4tc_type_ops flag_ops = {}; +static const struct p4tc_type_ops path_ops = {}; +static const struct p4tc_type_ops msecs_ops = {}; +static const struct p4tc_type_ops mac_ops = { + .validate_p4t = p4t_mac_validate, + .create_bitops = p4t_u64_bitops, + .host_read = p4t_u64_hread, + .host_write = p4t_u64_write, + .print = p4t_mac_print, +}; + +static const struct p4tc_type_ops ipv4_ops = { + .validate_p4t = p4t_ipv4_validate, + .host_read = p4t_be32_hread, + .host_write = p4t_be32_write, + .print = p4t_ipv4_print, +}; + +static const struct p4tc_type_ops bool_ops = { + .validate_p4t = p4t_bool_validate, + .host_read = p4t_bool_hread, + .host_write = p4t_bool_write, + .print = p4t_bool_print, +}; + +static const struct p4tc_type_ops dev_ops = { + .validate_p4t = p4t_dev_validate, + .host_read = p4t_dev_hread, + .host_write = p4t_dev_write, + .print = p4t_dev_print, +}; + +static const struct p4tc_type_ops key_ops = { + .validate_p4t = p4t_key_validate, + .host_read = p4t_key_hread, + .host_write = p4t_key_write, + .print = p4t_key_print, +}; + +#ifdef CONFIG_RETPOLINE +int __p4tc_type_host_read(const struct p4tc_type_ops *ops, + struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + #define HREAD(cops) \ + if (ops == &cops) \ + return cops.host_read(container, mask_shift, sval, dval) + + HREAD(u8_ops); + HREAD(u16_ops); + HREAD(u32_ops); + HREAD(u64_ops); + HREAD(u128_ops); + HREAD(s8_ops); + HREAD(s16_ops); + HREAD(s32_ops); + HREAD(be16_ops); + HREAD(be32_ops); + HREAD(mac_ops); + HREAD(ipv4_ops); + HREAD(bool_ops); + HREAD(dev_ops); + HREAD(key_ops); + + return ops->host_read(container, mask_shift, sval, dval); +} + +int __p4tc_type_host_write(const struct p4tc_type_ops *ops, + struct p4tc_type *container, + struct p4tc_type_mask_shift *mask_shift, void *sval, + void *dval) +{ + #define HWRITE(cops) \ + if (ops == &cops) \ + return cops.host_write(container, mask_shift, sval, dval) + + HWRITE(u8_ops); + HWRITE(u16_ops); + HWRITE(u32_ops); + HWRITE(u64_ops); + HWRITE(u128_ops); + HWRITE(s16_ops); + HWRITE(s32_ops); + HWRITE(be16_ops); + HWRITE(be32_ops); + HWRITE(mac_ops); + HWRITE(ipv4_ops); + HWRITE(bool_ops); + HWRITE(dev_ops); + HWRITE(key_ops); + + return ops->host_write(container, mask_shift, sval, dval); +} +#endif + +static int __p4tc_do_regtype(int typeid, size_t bitsz, size_t container_bitsz, + const char *t_name, + const struct p4tc_type_ops *ops) +{ + struct p4tc_type *type; + int err; + + if (typeid > P4T_MAX) + return -EINVAL; + + if (p4type_find_byid(typeid) || p4type_find_byname(t_name)) + return -EEXIST; + + if (bitsz > P4T_MAX_BITSZ) + return -E2BIG; + + if (container_bitsz > P4T_MAX_BITSZ) + return -E2BIG; + + type = kzalloc(sizeof(*type), GFP_ATOMIC); + if (!type) + return -ENOMEM; + + err = idr_alloc_u32(&p4tc_types_idr, type, &typeid, typeid, GFP_ATOMIC); + if (err < 0) + return err; + + strscpy(type->name, t_name, P4T_MAX_STR_SZ); + type->typeid = typeid; + type->bitsz = bitsz; + type->container_bitsz = container_bitsz; + type->ops = ops; + + return 0; +} + +static inline int __p4tc_register_type(int typeid, size_t bitsz, + size_t container_bitsz, + const char *t_name, + const struct p4tc_type_ops *ops) +{ + if (__p4tc_do_regtype(typeid, bitsz, container_bitsz, t_name, ops) < + 0) { + pr_err("Unable to allocate p4 type %s\n", t_name); + p4tc_types_put(); + return -1; + } + + return 0; +} + +#define p4tc_register_type(...) \ + do { \ + if (__p4tc_register_type(__VA_ARGS__) < 0) \ + return -1; \ + } while (0) + +int p4tc_register_types(void) +{ + p4tc_register_type(P4T_U8, 8, 8, "u8", &u8_ops); + p4tc_register_type(P4T_U16, 16, 16, "u16", &u16_ops); + p4tc_register_type(P4T_U32, 32, 32, "u32", &u32_ops); + p4tc_register_type(P4T_U64, 64, 64, "u64", &u64_ops); + p4tc_register_type(P4T_U128, 128, 128, "u128", &u128_ops); + p4tc_register_type(P4T_S8, 8, 8, "s8", &s8_ops); + p4tc_register_type(P4T_BE16, 16, 16, "be16", &be16_ops); + p4tc_register_type(P4T_BE32, 32, 32, "be32", &be32_ops); + p4tc_register_type(P4T_BE64, 64, 64, "be64", &be64_ops); + p4tc_register_type(P4T_S16, 16, 16, "s16", &s16_ops); + p4tc_register_type(P4T_S32, 32, 32, "s32", &s32_ops); + p4tc_register_type(P4T_S64, 64, 64, "s64", &s64_ops); + p4tc_register_type(P4T_S128, 128, 128, "s128", &s128_ops); + p4tc_register_type(P4T_STRING, P4T_MAX_STR_SZ * 4, P4T_MAX_STR_SZ * 4, + "string", &string_ops); + p4tc_register_type(P4T_NUL_STRING, P4T_MAX_STR_SZ * 4, + P4T_MAX_STR_SZ * 4, "nullstr", &nullstring_ops); + p4tc_register_type(P4T_FLAG, 32, 32, "flag", &flag_ops); + p4tc_register_type(P4T_PATH, 0, 0, "path", &path_ops); + p4tc_register_type(P4T_MSECS, 0, 0, "msecs", &msecs_ops); + p4tc_register_type(P4T_MACADDR, 48, 64, "mac", &mac_ops); + p4tc_register_type(P4T_IPV4ADDR, 32, 32, "ipv4", &ipv4_ops); + p4tc_register_type(P4T_BOOL, 32, 32, "bool", &bool_ops); + p4tc_register_type(P4T_DEV, 32, 32, "dev", &dev_ops); + p4tc_register_type(P4T_KEY, P4TC_MAX_KEYSZ, P4TC_MAX_KEYSZ, "key", + &key_ops); + + return 0; +} + +void p4tc_unregister_types(void) +{ + p4tc_types_put(); +} From patchwork Wed May 17 11:02:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244695 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BAE162098E for ; Wed, 17 May 2023 11:04:26 +0000 (UTC) Received: from mail-qv1-xf32.google.com (mail-qv1-xf32.google.com [IPv6:2607:f8b0:4864:20::f32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 493D7E5D for ; Wed, 17 May 2023 04:03:55 -0700 (PDT) Received: by mail-qv1-xf32.google.com with SMTP id 6a1803df08f44-6235aac00edso5863596d6.1 for ; Wed, 17 May 2023 04:03:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321423; x=1686913423; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RJVQAF19u0xbYocJpbRmHEhOBLEZo5vNQ5qJBiZAcLI=; b=b4DsZvt8kYB2h0X1xC8Zd/yzsMdjGQMx3KMo1x7xCnpVbn61SBlN3i1J2khMhb1ojm XXYHSQqPQid33J+4w5z6lLX96JNrDjOvSX38WIFwJ+6u0in8idYTVQFxQKrbf0TJZ7/k 4tEMF5ykmcVB09lqUO5Jf41862cSxQwcLDxRhf0J3EzU0BxxJZC/iWEte2dD3npoVFzd /vtF89iAqZq3w64sOp328fmhluH8H37GoRMO7csAOiLyzWe1KPeUmYYm73QjvG+aJYUG c6kScH9aj7MSe+DWTImqKmRdoRYiZXgdTQyUNR7HHRjfdQxHswGs4awOyveU9gfd3BKI O8+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321423; x=1686913423; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RJVQAF19u0xbYocJpbRmHEhOBLEZo5vNQ5qJBiZAcLI=; b=IzgE7pH/lKcizMUmgbZelCKjzyUpmK19C+8pVKomuBJuD/jrwKlCCtpysOG1tcl5s+ QEx5XSdpdSXrWl9NepSUiowI8LqQ9P3q0z5IiwreWusl9UOdRYWSiowHd8LO65OPsta3 teY3dFLQzDYNmAbmH/ovtsZT88wjtaBbKo5ZkbA1KQIozE0PDJvjID/1ylv20MtuGWPM vY/3nYnpC9xqwXQwPv6BzqocWYfVeTuTWhsR5WIYO6wKkLefkqqljDm9+uPXH2UlJAFt jCmgMuwRwcJk5ecXKjaHe7ldoT3lNyDPpfOF3r8GFtp1AEPYsMnLwx/EnCK4VLILw6ut 7xzw== X-Gm-Message-State: AC+VfDwGRnA6Zwtl84tQD0kGweSJWUczUFCZHeTuu6cZhaTg6rYjclpw 3vPbGmjet/kFD16+MBnaKWcZvzBXyO1jC84nkQ0= X-Google-Smtp-Source: ACHHUZ7OKq9x0qgmT8qrnzvGPO6WB1cw2wtr63DAXtB2szJoyt39sCWGL+1NVoOr+kQ3bWOG+7NpTQ== X-Received: by 2002:a05:6214:2421:b0:5a2:abf1:7d33 with SMTP id gy1-20020a056214242100b005a2abf17d33mr67738824qvb.50.1684321421549; Wed, 17 May 2023 04:03:41 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id pr2-20020a056214140200b006238c00c0eesm23930qvb.50.2023.05.17.04.03.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:03:40 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 10/28] p4tc: add pipeline create, get, update, delete Date: Wed, 17 May 2023 07:02:14 -0400 Message-Id: <20230517110232.29349-10-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC __Introducing P4 TC Pipeline__ This commit introduces P4 TC pipelines, which emulate the semantics of a P4 program/pipeline using the TC infrastructure. One can refer to P4 programs/pipelines using their names or their specific pipeline ids (pipeid) CRUD (Create, Read/get, Update and Delete) commands apply on a pipeline. As an example, to create a P4 program/pipeline named aP4proggie with a single table in its pipeline, one would use the following command from user space tc: tc p4template create pipeline/aP4proggie numtables 1 Note that, in the above command, the numtables is set as 1; the default is 0 because it is feasible to have a P4 program with no tables at all. The kernel issues each pipeline a pipeline ID which could be referenced. The control plane can specify an ID of choice, for example: tc p4template create pipeline/aP4proggie pipeid 1 numtables 1 Typically there is no good reason to specify the pipeid, but the choice is offered to the user. To Read pipeline aP4proggie attributes, one would retrieve those details as follows: tc p4template get pipeline/[aP4proggie] [pipeid 1] To Update aP4proggie pipeline from 1 to 10 tables, one would use the following command: tc p4template update pipeline/[aP4proggie] [pipeid 1] numtables 10 Note that, in the above command, one could use the P4 program/pipeline name, id or both to specify which P4 program/pipeline to update. To Delete a P4 program/pipeline named aP4proggie with a pipeid of 1, one would use the following command: tc p4template del pipeline/[aP4proggie] [pipeid 1] Note that, in the above command, one could use the P4 program/pipeline name, id or both to specify which P4 program/pipeline to delete If one wished to dump all the created P4 programs/pipelines, one would use the following command: tc p4template get pipeline/ __Pipeline Lifetime__ After Create is issued, one can Read/get, Update and Delete; however the pipeline can only be put to only after it is "sealed". To seal a pipeline, one would issue the following command: tc p4template update pipeline/aP4proggie state ready Once the pipeline is sealed it cannot updated. It can be deleted and read. After a pipeline is sealed it can be put to use via the TC P4 classifier. For example: tc filter add dev $DEV ingress protocol any prio 6 p4 pname aP4proggie Instantiates aP4proggie in the ingress of $DEV. One could also attach it to a block of ports (example tc block 22) as such: tc filter add block 22 ingress protocol any prio 6 p4 pname aP4proggie Once the pipeline is attached to a device or block it cannot be deleted. It becomes Read-only from the control plane/user space. The pipeline can be deleted when there are no longer any users left. __Packet Flow___ Pipelines have pre and post actions which are defined by the template. Pipeline Preactions are actions which will be executed when a packet arrives at the P4TC pipeline. Post actions are tc actions which will be executed at the very end of the pipeline and will, usually, execute part of the verdict decided by the pipeline processing, such as redirecting, mirroring, drop, etc. A P4 pipeline is instantiated via the tc filter known as "p4", for example: tc filter add dev $DEV ingress protocol ip prio 6 p4 pname myprog When a packet arrives at the filter it will first hit the pipeline preaction. Typically the pipeline preaction will execute the "apply" stanza of the P4 program. For example, the following apply logic: apply { if (meta.common.direction == ingress && hdrs.ipv4.isValid()) { mytable.apply(); } } Maps to: tc p4template create action/myprog/PPREA \ cmd beq metadata.kernel.direction constant.bit1.1 \ control pipe / jump endif \ cmd beq hdrfield.myprog.parser1.ipv4.isValid constant.bit1.1 \ control pipe / jump endif \ cmd tableapply table.myprog.cb/mytable \ cmd label endif Then bind it tc p4template update pipeline/myprog preactions action myprog/PPREA A post action is invoked after all the tables (if any) have been "applied" by Pipeline Preaction. Example of postaction: tc p4template create action/myprog/PPOA \ cmd beq metadata.myprog.global/drop constant.bit1.1 control drop / pipe \ cmd send_port_egress metadata.myprog.output_port tc p4template update pipeline/myprog postactions action myprog/PPOA Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/p4tc.h | 131 ++++++ include/uapi/linux/p4tc.h | 68 +++ include/uapi/linux/rtnetlink.h | 7 + net/sched/p4tc/Makefile | 2 +- net/sched/p4tc/p4tc_pipeline.c | 756 +++++++++++++++++++++++++++++++++ net/sched/p4tc/p4tc_tmpl_api.c | 562 ++++++++++++++++++++++++ security/selinux/nlmsgtab.c | 5 +- 7 files changed, 1529 insertions(+), 2 deletions(-) create mode 100644 include/net/p4tc.h create mode 100644 net/sched/p4tc/p4tc_pipeline.c create mode 100644 net/sched/p4tc/p4tc_tmpl_api.c diff --git a/include/net/p4tc.h b/include/net/p4tc.h new file mode 100644 index 000000000000..178bbdf68719 --- /dev/null +++ b/include/net/p4tc.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NET_P4TC_H +#define __NET_P4TC_H + +#include +#include +#include +#include +#include +#include +#include + +#define P4TC_DEFAULT_NUM_TABLES P4TC_MINTABLES_COUNT +#define P4TC_DEFAULT_MAX_RULES 1 +#define P4TC_PATH_MAX 3 + +#define P4TC_KERNEL_PIPEID 0 + +#define P4TC_PID_IDX 0 + +struct p4tc_dump_ctx { + u32 ids[P4TC_PATH_MAX]; +}; + +struct p4tc_template_common; + +/* Redefine these macros to avoid -Wenum-compare warnings */ + +#define __P4T_IS_UINT_TYPE(tp) \ + (tp == P4T_U8 || tp == P4T_U16 || tp == P4T_U32 || tp == P4T_U64) + +#define P4T_ENSURE_UINT_OR_BINARY_TYPE(tp) \ + (__NLA_ENSURE(__P4T_IS_UINT_TYPE(tp) || tp == P4T_MSECS || \ + tp == P4T_BINARY) + \ + tp) + +#define P4T_POLICY_RANGE(tp, _min, _max) \ + { \ + .type = P4T_ENSURE_UINT_OR_BINARY_TYPE(tp), \ + .validation_type = NLA_VALIDATE_RANGE, .min = _min, \ + .max = _max, \ + } + +struct p4tc_nl_pname { + char *data; + bool passed; +}; + +struct p4tc_template_ops { + void (*init)(void); + struct p4tc_template_common *(*cu)(struct net *net, struct nlmsghdr *n, + struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, + u32 *ids, + struct netlink_ext_ack *extack); + int (*put)(struct net *net, struct p4tc_template_common *tmpl, + bool unconditional_purge, struct netlink_ext_ack *extack); + int (*gd)(struct net *net, struct sk_buff *skb, struct nlmsghdr *n, + struct nlattr *nla, struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack); + int (*fill_nlmsg)(struct net *net, struct sk_buff *skb, + struct p4tc_template_common *tmpl, + struct netlink_ext_ack *extack); + int (*dump)(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, + struct nlattr *nla, char **p_name, u32 *ids, + struct netlink_ext_ack *extack); + int (*dump_1)(struct sk_buff *skb, struct p4tc_template_common *common); +}; + +struct p4tc_template_common { + char name[TEMPLATENAMSZ]; + struct p4tc_template_ops *ops; + u32 p_id; + u32 PAD0; +}; + +extern const struct p4tc_template_ops p4tc_pipeline_ops; + +struct p4tc_pipeline { + struct p4tc_template_common common; + struct rcu_head rcu; + struct net *net; + struct tc_action **preacts; + int num_preacts; + struct tc_action **postacts; + int num_postacts; + u32 max_rules; + refcount_t p_ref; + refcount_t p_ctrl_ref; + u16 num_tables; + u16 curr_tables; + u8 p_state; +}; + +struct p4tc_pipeline_net { + struct idr pipeline_idr; +}; + +int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, + struct idr *idr, int idx, + struct netlink_ext_ack *extack); + +struct p4tc_pipeline *tcf_pipeline_find_byany(struct net *net, + const char *p_name, + const u32 pipeid, + struct netlink_ext_ack *extack); +struct p4tc_pipeline *tcf_pipeline_find_byid(struct net *net, const u32 pipeid); +struct p4tc_pipeline *tcf_pipeline_get(struct net *net, const char *p_name, + const u32 pipeid, + struct netlink_ext_ack *extack); +void __tcf_pipeline_put(struct p4tc_pipeline *pipeline); +struct p4tc_pipeline * +tcf_pipeline_find_byany_unsealed(struct net *net, const char *p_name, + const u32 pipeid, + struct netlink_ext_ack *extack); + +static inline int p4tc_action_destroy(struct tc_action **acts) +{ + int ret = 0; + + if (acts) { + ret = tcf_action_destroy(acts, TCA_ACT_UNBIND); + kfree(acts); + } + + return ret; +} + +#define to_pipeline(t) ((struct p4tc_pipeline *)t) + +#endif diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h index 2b6f126dbeb5..739c0fe18e95 100644 --- a/include/uapi/linux/p4tc.h +++ b/include/uapi/linux/p4tc.h @@ -2,8 +2,73 @@ #ifndef __LINUX_P4TC_H #define __LINUX_P4TC_H +#include +#include + +/* pipeline header */ +struct p4tcmsg { + __u32 pipeid; + __u32 obj; +}; + +#define P4TC_MAXPIPELINE_COUNT 32 +#define P4TC_MAXRULES_LIMIT 512 +#define P4TC_MAXTABLES_COUNT 32 +#define P4TC_MINTABLES_COUNT 0 +#define P4TC_MAXPARSE_KEYS 16 +#define P4TC_MAXMETA_SZ 128 +#define P4TC_MSGBATCH_SIZE 16 + #define P4TC_MAX_KEYSZ 512 +#define TEMPLATENAMSZ 256 +#define PIPELINENAMSIZ TEMPLATENAMSZ + +/* Root attributes */ +enum { + P4TC_ROOT_UNSPEC, + P4TC_ROOT, /* nested messages */ + P4TC_ROOT_PNAME, /* string */ + __P4TC_ROOT_MAX, +}; +#define P4TC_ROOT_MAX __P4TC_ROOT_MAX + +/* PIPELINE attributes */ +enum { + P4TC_PIPELINE_UNSPEC, + P4TC_PIPELINE_MAXRULES, /* u32 */ + P4TC_PIPELINE_NUMTABLES, /* u16 */ + P4TC_PIPELINE_STATE, /* u8 */ + P4TC_PIPELINE_PREACTIONS, /* nested preactions */ + P4TC_PIPELINE_POSTACTIONS, /* nested postactions */ + P4TC_PIPELINE_NAME, /* string only used for pipeline dump */ + __P4TC_PIPELINE_MAX +}; +#define P4TC_PIPELINE_MAX __P4TC_PIPELINE_MAX + +/* P4 Object types */ +enum { + P4TC_OBJ_UNSPEC, + P4TC_OBJ_PIPELINE, + __P4TC_OBJ_MAX, +}; +#define P4TC_OBJ_MAX __P4TC_OBJ_MAX + +/* P4 attributes */ +enum { + P4TC_UNSPEC, + P4TC_PATH, + P4TC_PARAMS, + __P4TC_MAX, +}; +#define P4TC_MAX __P4TC_MAX + +/* PIPELINE states */ +enum { + P4TC_STATE_NOT_READY, + P4TC_STATE_READY, +}; + enum { P4T_UNSPEC, P4T_U8 = 1, /* NLA_U8 */ @@ -37,4 +102,7 @@ enum { }; #define P4T_MAX (__P4T_MAX - 1) +#define P4TC_RTA(r) \ + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct p4tcmsg)))) + #endif diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 51c13cf9c5ae..41a4046e7958 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -194,6 +194,13 @@ enum { RTM_GETTUNNEL, #define RTM_GETTUNNEL RTM_GETTUNNEL + RTM_CREATEP4TEMPLATE = 124, +#define RTM_CREATEP4TEMPLATE RTM_CREATEP4TEMPLATE + RTM_DELP4TEMPLATE, +#define RTM_DELP4TEMPLATE RTM_DELP4TEMPLATE + RTM_GETP4TEMPLATE, +#define RTM_GETP4TEMPLATE RTM_GETP4TEMPLATE + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index dd1358c9e802..0881a7563646 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y := p4tc_types.o +obj-y := p4tc_types.o p4tc_tmpl_api.o p4tc_pipeline.o diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c new file mode 100644 index 000000000000..776a8d37b615 --- /dev/null +++ b/net/sched/p4tc/p4tc_pipeline.c @@ -0,0 +1,756 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_pipeline.c P4 TC PIPELINE + * + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int pipeline_net_id; +static struct p4tc_pipeline *root_pipeline; + +static __net_init int pipeline_init_net(struct net *net) +{ + struct p4tc_pipeline_net *pipe_net = net_generic(net, pipeline_net_id); + + idr_init(&pipe_net->pipeline_idr); + + return 0; +} + +static int tcf_pipeline_put(struct net *net, + struct p4tc_template_common *template, + bool unconditional_purgeline, + struct netlink_ext_ack *extack); + +static void __net_exit pipeline_exit_net(struct net *net) +{ + struct p4tc_pipeline_net *pipe_net; + struct p4tc_pipeline *pipeline; + unsigned long pipeid, tmp; + + rtnl_lock(); + pipe_net = net_generic(net, pipeline_net_id); + idr_for_each_entry_ul(&pipe_net->pipeline_idr, pipeline, tmp, pipeid) { + tcf_pipeline_put(net, &pipeline->common, true, NULL); + } + idr_destroy(&pipe_net->pipeline_idr); + rtnl_unlock(); +} + +static struct pernet_operations pipeline_net_ops = { + .init = pipeline_init_net, + .pre_exit = pipeline_exit_net, + .id = &pipeline_net_id, + .size = sizeof(struct p4tc_pipeline_net), +}; + +static const struct nla_policy tc_pipeline_policy[P4TC_PIPELINE_MAX + 1] = { + [P4TC_PIPELINE_MAXRULES] = + NLA_POLICY_RANGE(NLA_U32, 1, P4TC_MAXRULES_LIMIT), + [P4TC_PIPELINE_NUMTABLES] = + NLA_POLICY_RANGE(NLA_U16, P4TC_MINTABLES_COUNT, P4TC_MAXTABLES_COUNT), + [P4TC_PIPELINE_STATE] = { .type = NLA_U8 }, + [P4TC_PIPELINE_PREACTIONS] = { .type = NLA_NESTED }, + [P4TC_PIPELINE_POSTACTIONS] = { .type = NLA_NESTED }, +}; + +static void tcf_pipeline_destroy(struct p4tc_pipeline *pipeline, + bool free_pipeline) +{ + if (free_pipeline) + kfree(pipeline); +} + +static void tcf_pipeline_destroy_rcu(struct rcu_head *head) +{ + struct p4tc_pipeline *pipeline; + struct net *net; + + pipeline = container_of(head, struct p4tc_pipeline, rcu); + + net = pipeline->net; + tcf_pipeline_destroy(pipeline, true); + put_net(net); +} + +static int tcf_pipeline_put(struct net *net, + struct p4tc_template_common *template, + bool unconditional_purgeline, + struct netlink_ext_ack *extack) +{ + struct p4tc_pipeline_net *pipe_net = net_generic(net, pipeline_net_id); + struct p4tc_pipeline *pipeline = to_pipeline(template); + struct net *pipeline_net = maybe_get_net(net); + + if (pipeline_net && !refcount_dec_if_one(&pipeline->p_ref)) { + NL_SET_ERR_MSG(extack, "Can't delete referenced pipeline"); + return -EBUSY; + } + + idr_remove(&pipe_net->pipeline_idr, pipeline->common.p_id); + + /* XXX: The action fields are only accessed in the control path + * since they will be copied to the filter, where the data path + * will use them. So there is no need to free them in the rcu + * callback. We can just free them here + */ + p4tc_action_destroy(pipeline->preacts); + p4tc_action_destroy(pipeline->postacts); + + if (pipeline_net) + call_rcu(&pipeline->rcu, tcf_pipeline_destroy_rcu); + else + tcf_pipeline_destroy(pipeline, + refcount_read(&pipeline->p_ref) == 1); + + return 0; +} + +static inline int pipeline_try_set_state_ready(struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + if (pipeline->curr_tables != pipeline->num_tables) { + NL_SET_ERR_MSG(extack, + "Must have all table defined to update state to ready"); + return -EINVAL; + } + + if (!pipeline->preacts) { + NL_SET_ERR_MSG(extack, + "Must specify pipeline preactions before sealing"); + return -EINVAL; + } + + if (!pipeline->postacts) { + NL_SET_ERR_MSG(extack, + "Must specify pipeline postactions before sealing"); + return -EINVAL; + } + + pipeline->p_state = P4TC_STATE_READY; + return true; +} + +static inline bool pipeline_sealed(struct p4tc_pipeline *pipeline) +{ + return pipeline->p_state == P4TC_STATE_READY; +} + +static int p4tc_action_init(struct net *net, struct nlattr *nla, + struct tc_action *acts[], u32 pipeid, u32 flags, + struct netlink_ext_ack *extack) +{ + int init_res[TCA_ACT_MAX_PRIO]; + size_t attrs_size; + int ret; + + /* If action was already created, just bind to existing one*/ + flags = TCA_ACT_FLAGS_BIND; + ret = tcf_action_init(net, NULL, nla, NULL, acts, init_res, &attrs_size, + flags, 0, extack); + + return ret; +} + +struct p4tc_pipeline *tcf_pipeline_find_byid(struct net *net, const u32 pipeid) +{ + struct p4tc_pipeline_net *pipe_net; + + if (pipeid == P4TC_KERNEL_PIPEID) + return root_pipeline; + + pipe_net = net_generic(net, pipeline_net_id); + + return idr_find(&pipe_net->pipeline_idr, pipeid); +} + +static struct p4tc_pipeline *tcf_pipeline_find_byname(struct net *net, + const char *name) +{ + struct p4tc_pipeline_net *pipe_net = net_generic(net, pipeline_net_id); + struct p4tc_pipeline *pipeline; + unsigned long tmp, id; + + idr_for_each_entry_ul(&pipe_net->pipeline_idr, pipeline, tmp, id) { + /* Don't show kernel pipeline */ + if (id == P4TC_KERNEL_PIPEID) + continue; + if (strncmp(pipeline->common.name, name, PIPELINENAMSIZ) == 0) + return pipeline; + } + + return NULL; +} + +static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, + struct nlmsghdr *n, + struct nlattr *nla, + const char *p_name, u32 pipeid, + struct netlink_ext_ack *extack) +{ + struct p4tc_pipeline_net *pipe_net = net_generic(net, pipeline_net_id); + int ret = 0; + struct nlattr *tb[P4TC_PIPELINE_MAX + 1]; + struct p4tc_pipeline *pipeline; + + ret = nla_parse_nested(tb, P4TC_PIPELINE_MAX, nla, tc_pipeline_policy, + extack); + + if (ret < 0) + return ERR_PTR(ret); + + pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); + if (!pipeline) + return ERR_PTR(-ENOMEM); + + if (!p_name || p_name[0] == '\0') { + NL_SET_ERR_MSG(extack, "Must specify pipeline name"); + ret = -EINVAL; + goto err; + } + + if (pipeid != P4TC_KERNEL_PIPEID && + tcf_pipeline_find_byid(net, pipeid)) { + NL_SET_ERR_MSG(extack, "Pipeline was already created"); + ret = -EEXIST; + goto err; + } + + if (tcf_pipeline_find_byname(net, p_name)) { + NL_SET_ERR_MSG(extack, "Pipeline was already created"); + ret = -EEXIST; + goto err; + } + + strscpy(pipeline->common.name, p_name, PIPELINENAMSIZ); + + if (pipeid) { + ret = idr_alloc_u32(&pipe_net->pipeline_idr, pipeline, &pipeid, + pipeid, GFP_KERNEL); + } else { + pipeid = 1; + ret = idr_alloc_u32(&pipe_net->pipeline_idr, pipeline, &pipeid, + UINT_MAX, GFP_KERNEL); + } + + if (ret < 0) { + NL_SET_ERR_MSG(extack, "Unable to allocate pipeline id"); + goto err; + } + + pipeline->common.p_id = pipeid; + + if (tb[P4TC_PIPELINE_MAXRULES]) + pipeline->max_rules = + nla_get_u32(tb[P4TC_PIPELINE_MAXRULES]); + else + pipeline->max_rules = P4TC_DEFAULT_MAX_RULES; + + if (tb[P4TC_PIPELINE_NUMTABLES]) + pipeline->num_tables = + nla_get_u16(tb[P4TC_PIPELINE_NUMTABLES]); + else + pipeline->num_tables = P4TC_DEFAULT_NUM_TABLES; + + if (tb[P4TC_PIPELINE_PREACTIONS]) { + pipeline->preacts = kcalloc(TCA_ACT_MAX_PRIO, + sizeof(struct tc_action *), + GFP_KERNEL); + if (!pipeline->preacts) { + ret = -ENOMEM; + goto idr_rm; + } + + ret = p4tc_action_init(net, tb[P4TC_PIPELINE_PREACTIONS], + pipeline->preacts, pipeid, 0, extack); + if (ret < 0) { + kfree(pipeline->preacts); + goto idr_rm; + } + pipeline->num_preacts = ret; + } else { + pipeline->preacts = NULL; + pipeline->num_preacts = 0; + } + + if (tb[P4TC_PIPELINE_POSTACTIONS]) { + pipeline->postacts = kcalloc(TCA_ACT_MAX_PRIO, + sizeof(struct tc_action *), + GFP_KERNEL); + if (!pipeline->postacts) { + ret = -ENOMEM; + goto preactions_destroy; + } + + ret = p4tc_action_init(net, tb[P4TC_PIPELINE_POSTACTIONS], + pipeline->postacts, pipeid, 0, extack); + if (ret < 0) { + kfree(pipeline->postacts); + goto preactions_destroy; + } + pipeline->num_postacts = ret; + } else { + pipeline->postacts = NULL; + pipeline->num_postacts = 0; + } + + pipeline->p_state = P4TC_STATE_NOT_READY; + + pipeline->net = net; + + refcount_set(&pipeline->p_ref, 1); + + pipeline->common.ops = (struct p4tc_template_ops *)&p4tc_pipeline_ops; + + return pipeline; + +preactions_destroy: + p4tc_action_destroy(pipeline->preacts); + +idr_rm: + idr_remove(&pipe_net->pipeline_idr, pipeid); + +err: + kfree(pipeline); + return ERR_PTR(ret); +} + +static struct p4tc_pipeline * +__tcf_pipeline_find_byany(struct net *net, const char *p_name, const u32 pipeid, + struct netlink_ext_ack *extack) +{ + struct p4tc_pipeline *pipeline = NULL; + int err; + + if (pipeid) { + pipeline = tcf_pipeline_find_byid(net, pipeid); + if (!pipeline) { + NL_SET_ERR_MSG(extack, "Unable to find pipeline by id"); + err = -EINVAL; + goto out; + } + } else { + if (p_name) { + pipeline = tcf_pipeline_find_byname(net, p_name); + if (!pipeline) { + NL_SET_ERR_MSG(extack, + "Pipeline name not found"); + err = -EINVAL; + goto out; + } + } + } + + return pipeline; + +out: + return ERR_PTR(err); +} + +struct p4tc_pipeline *tcf_pipeline_find_byany(struct net *net, + const char *p_name, + const u32 pipeid, + struct netlink_ext_ack *extack) +{ + struct p4tc_pipeline *pipeline = + __tcf_pipeline_find_byany(net, p_name, pipeid, extack); + if (!pipeline) { + NL_SET_ERR_MSG(extack, "Must specify pipeline name or id"); + return ERR_PTR(-EINVAL); + } + + return pipeline; +} + +struct p4tc_pipeline *tcf_pipeline_get(struct net *net, const char *p_name, + const u32 pipeid, + struct netlink_ext_ack *extack) +{ + struct p4tc_pipeline *pipeline = + __tcf_pipeline_find_byany(net, p_name, pipeid, extack); + if (!pipeline) { + NL_SET_ERR_MSG(extack, "Must specify pipeline name or id"); + return ERR_PTR(-EINVAL); + } else if (IS_ERR(pipeline)) { + return pipeline; + } + + /* Should never happen */ + WARN_ON(!refcount_inc_not_zero(&pipeline->p_ref)); + + return pipeline; +} +EXPORT_SYMBOL_GPL(tcf_pipeline_get); + +void __tcf_pipeline_put(struct p4tc_pipeline *pipeline) +{ + struct net *net = maybe_get_net(pipeline->net); + + if (net) { + refcount_dec(&pipeline->p_ref); + put_net(net); + /* If netns is going down, we already deleted the pipeline objects in + * the pre_exit net op + */ + } else { + kfree(pipeline); + } +} +EXPORT_SYMBOL_GPL(__tcf_pipeline_put); + +struct p4tc_pipeline * +tcf_pipeline_find_byany_unsealed(struct net *net, const char *p_name, + const u32 pipeid, + struct netlink_ext_ack *extack) +{ + struct p4tc_pipeline *pipeline = + tcf_pipeline_find_byany(net, p_name, pipeid, extack); + if (IS_ERR(pipeline)) + return pipeline; + + if (pipeline_sealed(pipeline)) { + NL_SET_ERR_MSG(extack, "Pipeline is sealed"); + return ERR_PTR(-EINVAL); + } + + return pipeline; +} + +static struct p4tc_pipeline * +tcf_pipeline_update(struct net *net, struct nlmsghdr *n, struct nlattr *nla, + const char *p_name, const u32 pipeid, + struct netlink_ext_ack *extack) +{ + struct tc_action **preacts = NULL; + struct tc_action **postacts = NULL; + u16 num_tables = 0; + u16 max_rules = 0; + int ret = 0; + struct nlattr *tb[P4TC_PIPELINE_MAX + 1]; + struct p4tc_pipeline *pipeline; + int num_preacts, num_postacts; + + ret = nla_parse_nested(tb, P4TC_PIPELINE_MAX, nla, tc_pipeline_policy, + extack); + + if (ret < 0) + goto out; + + pipeline = + tcf_pipeline_find_byany_unsealed(net, p_name, pipeid, extack); + if (IS_ERR(pipeline)) + return pipeline; + + if (tb[P4TC_PIPELINE_NUMTABLES]) + num_tables = nla_get_u16(tb[P4TC_PIPELINE_NUMTABLES]); + + if (tb[P4TC_PIPELINE_MAXRULES]) + max_rules = nla_get_u32(tb[P4TC_PIPELINE_MAXRULES]); + + if (tb[P4TC_PIPELINE_PREACTIONS]) { + preacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), + GFP_KERNEL); + if (!preacts) { + ret = -ENOMEM; + goto out; + } + + ret = p4tc_action_init(net, tb[P4TC_PIPELINE_PREACTIONS], + preacts, pipeline->common.p_id, 0, + extack); + if (ret < 0) { + kfree(preacts); + goto out; + } + num_preacts = ret; + } + + if (tb[P4TC_PIPELINE_POSTACTIONS]) { + postacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), + GFP_KERNEL); + if (!postacts) { + ret = -ENOMEM; + goto preactions_destroy; + } + + ret = p4tc_action_init(net, tb[P4TC_PIPELINE_POSTACTIONS], + postacts, pipeline->common.p_id, 0, + extack); + if (ret < 0) { + kfree(postacts); + goto preactions_destroy; + } + num_postacts = ret; + } + + if (tb[P4TC_PIPELINE_STATE]) { + ret = pipeline_try_set_state_ready(pipeline, extack); + if (ret < 0) + goto postactions_destroy; + } + + if (max_rules) + pipeline->max_rules = max_rules; + if (num_tables) + pipeline->num_tables = num_tables; + if (preacts) { + p4tc_action_destroy(pipeline->preacts); + pipeline->preacts = preacts; + pipeline->num_preacts = num_preacts; + } + if (postacts) { + p4tc_action_destroy(pipeline->postacts); + pipeline->postacts = postacts; + pipeline->num_postacts = num_postacts; + } + + return pipeline; + +postactions_destroy: + p4tc_action_destroy(postacts); + +preactions_destroy: + p4tc_action_destroy(preacts); +out: + return ERR_PTR(ret); +} + +static struct p4tc_template_common * +tcf_pipeline_cu(struct net *net, struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + u32 pipeid = ids[P4TC_PID_IDX]; + struct p4tc_pipeline *pipeline; + + if (n->nlmsg_flags & NLM_F_REPLACE) + pipeline = tcf_pipeline_update(net, n, nla, nl_pname->data, + pipeid, extack); + else + pipeline = tcf_pipeline_create(net, n, nla, nl_pname->data, + pipeid, extack); + + if (IS_ERR(pipeline)) + goto out; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + +out: + return (struct p4tc_template_common *)pipeline; +} + +static int _tcf_pipeline_fill_nlmsg(struct sk_buff *skb, + const struct p4tc_pipeline *pipeline) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct nlattr *nest, *preacts, *postacts; + + nest = nla_nest_start(skb, P4TC_PARAMS); + if (!nest) + goto out_nlmsg_trim; + if (nla_put_u32(skb, P4TC_PIPELINE_MAXRULES, pipeline->max_rules)) + goto out_nlmsg_trim; + + if (nla_put_u16(skb, P4TC_PIPELINE_NUMTABLES, pipeline->num_tables)) + goto out_nlmsg_trim; + if (nla_put_u8(skb, P4TC_PIPELINE_STATE, pipeline->p_state)) + goto out_nlmsg_trim; + + if (pipeline->preacts) { + preacts = nla_nest_start(skb, P4TC_PIPELINE_PREACTIONS); + if (tcf_action_dump(skb, pipeline->preacts, 0, 0, false) < 0) + goto out_nlmsg_trim; + nla_nest_end(skb, preacts); + } + + if (pipeline->postacts) { + postacts = nla_nest_start(skb, P4TC_PIPELINE_POSTACTIONS); + if (tcf_action_dump(skb, pipeline->postacts, 0, 0, false) < 0) + goto out_nlmsg_trim; + nla_nest_end(skb, postacts); + } + + nla_nest_end(skb, nest); + + return skb->len; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -1; +} + +static int tcf_pipeline_fill_nlmsg(struct net *net, struct sk_buff *skb, + struct p4tc_template_common *template, + struct netlink_ext_ack *extack) +{ + const struct p4tc_pipeline *pipeline = to_pipeline(template); + + if (_tcf_pipeline_fill_nlmsg(skb, pipeline) <= 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for pipeline"); + return -EINVAL; + } + + return 0; +} + +static int tcf_pipeline_del_one(struct net *net, + struct p4tc_template_common *tmpl, + struct netlink_ext_ack *extack) +{ + return tcf_pipeline_put(net, tmpl, false, extack); +} + +static int tcf_pipeline_gd(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + unsigned char *b = nlmsg_get_pos(skb); + u32 pipeid = ids[P4TC_PID_IDX]; + struct p4tc_template_common *tmpl; + struct p4tc_pipeline *pipeline; + int ret = 0; + + if (n->nlmsg_type == RTM_DELP4TEMPLATE && + (n->nlmsg_flags & NLM_F_ROOT)) { + NL_SET_ERR_MSG(extack, "Pipeline flush not supported"); + return -EOPNOTSUPP; + } + + pipeline = tcf_pipeline_find_byany(net, nl_pname->data, pipeid, extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + + tmpl = (struct p4tc_template_common *)pipeline; + if (tcf_pipeline_fill_nlmsg(net, skb, tmpl, extack) < 0) + return -1; + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (n->nlmsg_type == RTM_DELP4TEMPLATE) { + ret = tcf_pipeline_del_one(net, tmpl, extack); + if (ret < 0) + goto out_nlmsg_trim; + } + + return ret; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_pipeline_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, + struct nlattr *nla, char **p_name, u32 *ids, + struct netlink_ext_ack *extack) +{ + struct net *net = sock_net(skb->sk); + struct p4tc_pipeline_net *pipe_net = net_generic(net, pipeline_net_id); + + return tcf_p4_tmpl_generic_dump(skb, ctx, &pipe_net->pipeline_idr, + P4TC_PID_IDX, extack); +} + +static int tcf_pipeline_dump_1(struct sk_buff *skb, + struct p4tc_template_common *common) +{ + struct p4tc_pipeline *pipeline = to_pipeline(common); + unsigned char *b = nlmsg_get_pos(skb); + struct nlattr *param; + + /* Don't show kernel pipeline in dump */ + if (pipeline->common.p_id == P4TC_KERNEL_PIPEID) + return 1; + + param = nla_nest_start(skb, P4TC_PARAMS); + if (!param) + goto out_nlmsg_trim; + if (nla_put_string(skb, P4TC_PIPELINE_NAME, pipeline->common.name)) + goto out_nlmsg_trim; + + nla_nest_end(skb, param); + + return 0; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -ENOMEM; +} + +static int register_pipeline_pernet(void) +{ + return register_pernet_subsys(&pipeline_net_ops); +} + +static void __tcf_pipeline_init(void) +{ + int pipeid = P4TC_KERNEL_PIPEID; + + root_pipeline = kzalloc(sizeof(*root_pipeline), GFP_ATOMIC); + if (!root_pipeline) { + pr_err("Unable to register kernel pipeline\n"); + return; + } + + strscpy(root_pipeline->common.name, "kernel", PIPELINENAMSIZ); + + root_pipeline->common.ops = + (struct p4tc_template_ops *)&p4tc_pipeline_ops; + + root_pipeline->common.p_id = pipeid; + + root_pipeline->p_state = P4TC_STATE_READY; +} + +static void tcf_pipeline_init(void) +{ + if (register_pipeline_pernet() < 0) + pr_err("Failed to register per net pipeline IDR"); + + if (p4tc_register_types() < 0) + pr_err("Failed to register P4 types"); + + __tcf_pipeline_init(); +} + +const struct p4tc_template_ops p4tc_pipeline_ops = { + .init = tcf_pipeline_init, + .cu = tcf_pipeline_cu, + .fill_nlmsg = tcf_pipeline_fill_nlmsg, + .gd = tcf_pipeline_gd, + .put = tcf_pipeline_put, + .dump = tcf_pipeline_dump, + .dump_1 = tcf_pipeline_dump_1, +}; diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c new file mode 100644 index 000000000000..a936ec84841d --- /dev/null +++ b/net/sched/p4tc/p4tc_tmpl_api.c @@ -0,0 +1,562 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_api.c P4 TC API + * + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const struct nla_policy p4tc_root_policy[P4TC_ROOT_MAX + 1] = { + [P4TC_ROOT] = { .type = NLA_NESTED }, + [P4TC_ROOT_PNAME] = { .type = NLA_STRING, .len = PIPELINENAMSIZ }, +}; + +const struct nla_policy p4tc_policy[P4TC_MAX + 1] = { + [P4TC_PATH] = { .type = NLA_BINARY, + .len = P4TC_PATH_MAX * sizeof(u32) }, + [P4TC_PARAMS] = { .type = NLA_NESTED }, +}; + +static bool obj_is_valid(u32 obj) +{ + switch (obj) { + case P4TC_OBJ_PIPELINE: + return true; + default: + return false; + } +} + +static const struct p4tc_template_ops *p4tc_ops[P4TC_OBJ_MAX] = { + [P4TC_OBJ_PIPELINE] = &p4tc_pipeline_ops, +}; + +int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, + struct idr *idr, int idx, + struct netlink_ext_ack *extack) +{ + unsigned char *b = nlmsg_get_pos(skb); + unsigned long id = 0; + int i = 0; + struct p4tc_template_common *common; + unsigned long tmp; + + id = ctx->ids[idx]; + + idr_for_each_entry_continue_ul(idr, common, tmp, id) { + struct nlattr *count; + int ret; + + if (i == P4TC_MSGBATCH_SIZE) + break; + + count = nla_nest_start(skb, i + 1); + if (!count) + goto out_nlmsg_trim; + ret = common->ops->dump_1(skb, common); + if (ret < 0) { + goto out_nlmsg_trim; + } else if (ret) { + nla_nest_cancel(skb, count); + continue; + } + nla_nest_end(skb, count); + + i++; + } + + if (i == 0) { + if (!ctx->ids[idx]) + NL_SET_ERR_MSG(extack, + "There are no pipeline components"); + return 0; + } + + ctx->ids[idx] = id; + + return skb->len; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -ENOMEM; +} + +static int tc_ctl_p4_tmpl_gd_1(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, struct nlattr *arg, + struct p4tc_nl_pname *nl_pname, + struct netlink_ext_ack *extack) +{ + struct p4tcmsg *t = (struct p4tcmsg *)nlmsg_data(n); + u32 ids[P4TC_PATH_MAX] = {}; + struct nlattr *tb[P4TC_MAX + 1]; + struct p4tc_template_ops *op; + int ret; + + if (!obj_is_valid(t->obj)) { + NL_SET_ERR_MSG(extack, "Invalid object type"); + return -EINVAL; + } + + ret = nla_parse_nested(tb, P4TC_MAX, arg, p4tc_policy, extack); + if (ret < 0) + return ret; + + ids[P4TC_PID_IDX] = t->pipeid; + + op = (struct p4tc_template_ops *)p4tc_ops[t->obj]; + + ret = op->gd(net, skb, n, tb[P4TC_PARAMS], nl_pname, ids, extack); + if (ret < 0) + return ret; + + if (!t->pipeid) + t->pipeid = ids[P4TC_PID_IDX]; + + return ret; +} + +static int tc_ctl_p4_tmpl_gd_n(struct sk_buff *skb, struct nlmsghdr *n, + char *p_name, struct nlattr *nla, int event, + struct netlink_ext_ack *extack) +{ + struct p4tcmsg *t = (struct p4tcmsg *)nlmsg_data(n); + struct net *net = sock_net(skb->sk); + u32 portid = NETLINK_CB(skb).portid; + int ret = 0; + struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1]; + struct p4tc_nl_pname nl_pname; + struct sk_buff *new_skb; + struct p4tcmsg *t_new; + struct nlmsghdr *nlh; + struct nlattr *pnatt; + struct nlattr *root; + int i; + + ret = nla_parse_nested(tb, P4TC_MSGBATCH_SIZE, nla, NULL, extack); + if (ret < 0) + return ret; + + new_skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!new_skb) + return -ENOMEM; + + nlh = nlmsg_put(new_skb, portid, n->nlmsg_seq, event, sizeof(*t), + n->nlmsg_flags); + if (!nlh) { + ret = -ENOMEM; + goto out; + } + + t_new = nlmsg_data(nlh); + t_new->pipeid = t->pipeid; + t_new->obj = t->obj; + + pnatt = nla_reserve(new_skb, P4TC_ROOT_PNAME, PIPELINENAMSIZ); + if (!pnatt) { + ret = -ENOMEM; + goto out; + } + + nl_pname.data = nla_data(pnatt); + if (!p_name) { + /* Filled up by the operation or forced failure */ + memset(nl_pname.data, 0, PIPELINENAMSIZ); + nl_pname.passed = false; + } else { + strscpy(nl_pname.data, p_name, PIPELINENAMSIZ); + nl_pname.passed = true; + } + + root = nla_nest_start(new_skb, P4TC_ROOT); + for (i = 1; i < P4TC_MSGBATCH_SIZE + 1 && tb[i]; i++) { + struct nlattr *nest = nla_nest_start(new_skb, i); + + ret = tc_ctl_p4_tmpl_gd_1(net, new_skb, nlh, tb[i], &nl_pname, + extack); + if (n->nlmsg_flags & NLM_F_ROOT && event == RTM_DELP4TEMPLATE) { + if (ret <= 0) + goto out; + } else { + if (ret < 0) + goto out; + } + nla_nest_end(new_skb, nest); + } + nla_nest_end(new_skb, root); + + nlmsg_end(new_skb, nlh); + + if (event == RTM_GETP4TEMPLATE) + return rtnl_unicast(new_skb, net, portid); + + return rtnetlink_send(new_skb, net, portid, RTNLGRP_TC, + n->nlmsg_flags & NLM_F_ECHO); +out: + kfree_skb(new_skb); + return ret; +} + +static int tc_ctl_p4_tmpl_get(struct sk_buff *skb, struct nlmsghdr *n, + struct netlink_ext_ack *extack) +{ + char *p_name = NULL; + struct nlattr *tb[P4TC_ROOT_MAX + 1]; + int ret; + + ret = nlmsg_parse(n, sizeof(struct p4tcmsg), tb, P4TC_ROOT_MAX, + p4tc_root_policy, extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(extack, NULL, tb, P4TC_ROOT)) { + NL_SET_ERR_MSG(extack, + "Netlink P4TC template attributes missing"); + return -EINVAL; + } + + if (tb[P4TC_ROOT_PNAME]) + p_name = nla_data(tb[P4TC_ROOT_PNAME]); + + return tc_ctl_p4_tmpl_gd_n(skb, n, p_name, tb[P4TC_ROOT], + RTM_GETP4TEMPLATE, extack); +} + +static int tc_ctl_p4_tmpl_delete(struct sk_buff *skb, struct nlmsghdr *n, + struct netlink_ext_ack *extack) +{ + char *p_name = NULL; + struct nlattr *tb[P4TC_ROOT_MAX + 1]; + int ret; + + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + + ret = nlmsg_parse(n, sizeof(struct p4tcmsg), tb, P4TC_ROOT_MAX, + p4tc_root_policy, extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(extack, NULL, tb, P4TC_ROOT)) { + NL_SET_ERR_MSG(extack, + "Netlink P4TC template attributes missing"); + return -EINVAL; + } + + if (tb[P4TC_ROOT_PNAME]) + p_name = nla_data(tb[P4TC_ROOT_PNAME]); + + return tc_ctl_p4_tmpl_gd_n(skb, n, p_name, tb[P4TC_ROOT], + RTM_DELP4TEMPLATE, extack); +} + +static struct p4tc_template_common * +tcf_p4_tmpl_cu_1(struct sk_buff *skb, struct net *net, struct nlmsghdr *n, + struct p4tc_nl_pname *nl_pname, struct nlattr *nla, + struct netlink_ext_ack *extack) +{ + struct p4tcmsg *t = (struct p4tcmsg *)nlmsg_data(n); + u32 ids[P4TC_PATH_MAX] = {}; + struct nlattr *tb[P4TC_MAX + 1]; + struct p4tc_template_common *tmpl; + struct p4tc_template_ops *op; + int ret; + + if (!obj_is_valid(t->obj)) { + NL_SET_ERR_MSG(extack, "Invalid object type"); + ret = -EINVAL; + goto out; + } + + ret = nla_parse_nested(tb, P4TC_MAX, nla, p4tc_policy, extack); + if (ret < 0) + goto out; + + if (NL_REQ_ATTR_CHECK(extack, nla, tb, P4TC_PARAMS)) { + NL_SET_ERR_MSG(extack, "Must specify object attributes"); + ret = -EINVAL; + goto out; + } + + ids[P4TC_PID_IDX] = t->pipeid; + + op = (struct p4tc_template_ops *)p4tc_ops[t->obj]; + tmpl = op->cu(net, n, tb[P4TC_PARAMS], nl_pname, ids, extack); + if (IS_ERR(tmpl)) + return tmpl; + + ret = op->fill_nlmsg(net, skb, tmpl, extack); + if (ret < 0) + goto put; + + if (!t->pipeid) + t->pipeid = ids[P4TC_PID_IDX]; + + return tmpl; + +put: + op->put(net, tmpl, false, extack); + +out: + return ERR_PTR(ret); +} + +static int tcf_p4_tmpl_cu_n(struct sk_buff *skb, struct nlmsghdr *n, + struct nlattr *nla, char *p_name, + struct netlink_ext_ack *extack) +{ + struct p4tcmsg *t = (struct p4tcmsg *)nlmsg_data(n); + struct net *net = sock_net(skb->sk); + u32 portid = NETLINK_CB(skb).portid; + struct p4tc_template_common *tmpls[P4TC_MSGBATCH_SIZE]; + struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1]; + struct p4tc_nl_pname nl_pname; + struct sk_buff *new_skb; + struct p4tcmsg *t_new; + struct nlmsghdr *nlh; + struct nlattr *pnatt; + struct nlattr *root; + int ret; + int i; + + ret = nla_parse_nested(tb, P4TC_MSGBATCH_SIZE, nla, NULL, extack); + if (ret < 0) + return ret; + + new_skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!new_skb) + return -ENOMEM; + + nlh = nlmsg_put(new_skb, portid, n->nlmsg_seq, RTM_CREATEP4TEMPLATE, + sizeof(*t), n->nlmsg_flags); + if (!nlh) + goto out; + + t_new = nlmsg_data(nlh); + if (!t_new) { + NL_SET_ERR_MSG(extack, "Message header is missing"); + ret = -EINVAL; + goto out; + } + t_new->pipeid = t->pipeid; + t_new->obj = t->obj; + + pnatt = nla_reserve(new_skb, P4TC_ROOT_PNAME, PIPELINENAMSIZ); + if (!pnatt) { + ret = -ENOMEM; + goto out; + } + + nl_pname.data = nla_data(pnatt); + if (!p_name) { + /* Filled up by the operation or forced failure */ + memset(nl_pname.data, 0, PIPELINENAMSIZ); + nl_pname.passed = false; + } else { + strscpy(nl_pname.data, p_name, PIPELINENAMSIZ); + nl_pname.passed = true; + } + + root = nla_nest_start(new_skb, P4TC_ROOT); + if (!root) { + ret = -ENOMEM; + goto out; + } + + /* XXX: See if we can use NLA_NESTED_ARRAY here */ + for (i = 0; i < P4TC_MSGBATCH_SIZE && tb[i + 1]; i++) { + struct nlattr *nest = nla_nest_start(new_skb, i + 1); + + tmpls[i] = tcf_p4_tmpl_cu_1(new_skb, net, nlh, &nl_pname, + tb[i + 1], extack); + if (IS_ERR(tmpls[i])) { + ret = PTR_ERR(tmpls[i]); + goto undo_prev; + } + + nla_nest_end(new_skb, nest); + } + nla_nest_end(new_skb, root); + + if (!t_new->pipeid) + t_new->pipeid = ret; + + nlmsg_end(new_skb, nlh); + + return rtnetlink_send(new_skb, net, portid, RTNLGRP_TC, + n->nlmsg_flags & NLM_F_ECHO); + +undo_prev: + if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) { + while (--i > 0) { + struct p4tc_template_common *tmpl = tmpls[i - 1]; + + tmpl->ops->put(net, tmpl, false, extack); + } + } + +out: + kfree_skb(new_skb); + return ret; +} + +static int tc_ctl_p4_tmpl_cu(struct sk_buff *skb, struct nlmsghdr *n, + struct netlink_ext_ack *extack) +{ + char *p_name = NULL; + int ret = 0; + struct nlattr *tb[P4TC_ROOT_MAX + 1]; + + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + + ret = nlmsg_parse(n, sizeof(struct p4tcmsg), tb, P4TC_ROOT_MAX, + p4tc_root_policy, extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(extack, NULL, tb, P4TC_ROOT)) { + NL_SET_ERR_MSG(extack, + "Netlink P4TC template attributes missing"); + return -EINVAL; + } + + if (tb[P4TC_ROOT_PNAME]) + p_name = nla_data(tb[P4TC_ROOT_PNAME]); + + return tcf_p4_tmpl_cu_n(skb, n, tb[P4TC_ROOT], p_name, extack); +} + +static int tc_ctl_p4_tmpl_dump_1(struct sk_buff *skb, struct nlattr *arg, + char *p_name, struct netlink_callback *cb) +{ + struct p4tc_dump_ctx *ctx = (void *)cb->ctx; + struct netlink_ext_ack *extack = cb->extack; + u32 portid = NETLINK_CB(cb->skb).portid; + const struct nlmsghdr *n = cb->nlh; + u32 ids[P4TC_PATH_MAX] = {}; + struct nlattr *tb[P4TC_MAX + 1]; + struct p4tc_template_ops *op; + struct p4tcmsg *t_new; + struct nlmsghdr *nlh; + struct nlattr *root; + struct p4tcmsg *t; + int ret; + + ret = nla_parse_nested_deprecated(tb, P4TC_MAX, arg, p4tc_policy, + extack); + if (ret < 0) + return ret; + + t = (struct p4tcmsg *)nlmsg_data(n); + if (!obj_is_valid(t->obj)) { + NL_SET_ERR_MSG(extack, "Invalid object type"); + return -EINVAL; + } + + nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_GETP4TEMPLATE, + sizeof(*t), n->nlmsg_flags); + if (!nlh) + return -ENOSPC; + + t_new = nlmsg_data(nlh); + t_new->pipeid = t->pipeid; + t_new->obj = t->obj; + + root = nla_nest_start(skb, P4TC_ROOT); + + ids[P4TC_PID_IDX] = t->pipeid; + + op = (struct p4tc_template_ops *)p4tc_ops[t->obj]; + ret = op->dump(skb, ctx, tb[P4TC_PARAMS], &p_name, ids, extack); + if (ret <= 0) + goto out; + nla_nest_end(skb, root); + + if (p_name) { + if (nla_put_string(skb, P4TC_ROOT_PNAME, p_name)) { + ret = -1; + goto out; + } + } + + if (!t_new->pipeid) + t_new->pipeid = ids[P4TC_PID_IDX]; + + nlmsg_end(skb, nlh); + + return ret; + +out: + nlmsg_cancel(skb, nlh); + return ret; +} + +static int tc_ctl_p4_tmpl_dump(struct sk_buff *skb, struct netlink_callback *cb) +{ + char *p_name = NULL; + struct nlattr *tb[P4TC_ROOT_MAX + 1]; + int ret; + + ret = nlmsg_parse(cb->nlh, sizeof(struct p4tcmsg), tb, P4TC_ROOT_MAX, + p4tc_root_policy, cb->extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(cb->extack, NULL, tb, P4TC_ROOT)) { + NL_SET_ERR_MSG(cb->extack, + "Netlink P4TC template attributes missing"); + return -EINVAL; + } + + if (tb[P4TC_ROOT_PNAME]) + p_name = nla_data(tb[P4TC_ROOT_PNAME]); + + return tc_ctl_p4_tmpl_dump_1(skb, tb[P4TC_ROOT], p_name, cb); +} + +static int __init p4tc_template_init(void) +{ + u32 obj; + + rtnl_register(PF_UNSPEC, RTM_CREATEP4TEMPLATE, tc_ctl_p4_tmpl_cu, NULL, + 0); + rtnl_register(PF_UNSPEC, RTM_DELP4TEMPLATE, tc_ctl_p4_tmpl_delete, NULL, + 0); + rtnl_register(PF_UNSPEC, RTM_GETP4TEMPLATE, tc_ctl_p4_tmpl_get, + tc_ctl_p4_tmpl_dump, 0); + + for (obj = P4TC_OBJ_PIPELINE; obj < P4TC_OBJ_MAX; obj++) { + const struct p4tc_template_ops *op = p4tc_ops[obj]; + + if (!obj_is_valid(obj)) + continue; + + if (op->init) + op->init(); + } + + return 0; +} + +subsys_initcall(p4tc_template_init); diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 2ee7b4ed43ef..0a8daf2f8f2a 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -94,6 +94,9 @@ static const struct nlmsg_perm nlmsg_route_perms[] = { { RTM_NEWTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_DELTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_GETTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_CREATEP4TEMPLATE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELP4TEMPLATE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETP4TEMPLATE, NETLINK_ROUTE_SOCKET__NLMSG_READ }, }; static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = { @@ -176,7 +179,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) * structures at the top of this file with the new mappings * before updating the BUILD_BUG_ON() macro! */ - BUILD_BUG_ON(RTM_MAX != (RTM_NEWTUNNEL + 3)); + BUILD_BUG_ON(RTM_MAX != (RTM_CREATEP4TEMPLATE + 3)); err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms, sizeof(nlmsg_route_perms)); break; From patchwork Wed May 17 11:02:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244693 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C00211F196 for ; Wed, 17 May 2023 11:04:25 +0000 (UTC) Received: from mail-qt1-x82d.google.com (mail-qt1-x82d.google.com [IPv6:2607:f8b0:4864:20::82d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 46723198D for ; Wed, 17 May 2023 04:03:57 -0700 (PDT) Received: by mail-qt1-x82d.google.com with SMTP id d75a77b69052e-3f610c11472so2397791cf.0 for ; Wed, 17 May 2023 04:03:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321430; x=1686913430; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=DZr/tLbS7sYwjBRnl1fxcTCcUhSxUlDqNLBHEjNidIY=; b=OJXDI3BJfcIllohmeUC+Y8ihJzE4XnQvf++INbzXtMXDKt2kTL5jVW++zJ7ZYYH2dJ O6fdi1NzCHkZzNiFDybV2XNw5Blg5ImBncrhgczcpGsfkJykgHAq17g6tj/w91QAN/Zs lX02kS30JjHJypcYqWlktiF4+Hgx7twNbUkRGF0T62OKiodZ9DwVsda24HvaFjWrrTkS fIlScoxQ2tdc2HlUh4f92IfQ7joJMsv6w3yZEzAlOMadUwOcQ2meR/meKTPejoKmSspk jQynO00aSbsVG3Q7AHHoRl1j9HPgYkyJEhBdmglkvmR+0DAwiBcf9sZ4HNoEjVGBkipw N0Nw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321430; x=1686913430; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=DZr/tLbS7sYwjBRnl1fxcTCcUhSxUlDqNLBHEjNidIY=; b=LJUbgwsg3xHnW/NnNUYq93wBVWmscY3NYdKKnW98bdhEuru4Kd3VZHZihvtBtVVLKq SXM1iHXPMZk2B9LOecRj2aJa4HJHu+T15s8jkWIlIj7sOGQJvzXlTYu4m0xrrwZYoNHe ZOcwOn/cXNvqRCE04oohrp28O8RSZL+tEQfUrHHe8BLVkMIkuOobhdXszBOItbDnKkCn f5yu9Miul+K4lxR0NPrKvQiHJk12RggBw1j591TYa2R8wRnCnQWlj4csT8o8V1K7Vb7D 3zcHeSKD2NWVye4oM5eGDVX/phgSehJKgZUdWOtnIkFIQtaLaqAZcxxvbNZNtOsJsT9V dPhQ== X-Gm-Message-State: AC+VfDzbj2NCJwnp2xlV24CGm77FuZcyd8/oZCjVli8D4esXbqPb/3jQ krb0K9/E9D1E7HT5oS2c4GEyMeS4UiOgienTjsM= X-Google-Smtp-Source: ACHHUZ5G+r256R8A0cQGcHdbmuFh9OC1DjjmKg344e51TdqmD//mLwK+qIiyCyJaUpFw1VVPKFm2Xw== X-Received: by 2002:a05:622a:8:b0:3f5:c257:9f10 with SMTP id x8-20020a05622a000800b003f5c2579f10mr3081103qtw.22.1684321429313; Wed, 17 May 2023 04:03:49 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id e4-20020ac84904000000b003f1f87814a4sm6415909qtq.84.2023.05.17.04.03.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:03:48 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 11/28] p4tc: add metadata create, update, delete, get, flush and dump Date: Wed, 17 May 2023 07:02:15 -0400 Message-Id: <20230517110232.29349-11-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This commit allows users to create, update, delete and get a P4 pipeline's metadatum. It also allows users to flush and dump all of the P4 pipeline's metadata. As an example, if one were to create a metadatum named mname in a pipeline named ptables with a type of 8 bits, one would use the following command: tc p4template create metadata/ptables/mname [mid 1] type bit8 Note that, in the above command, the metadatum id is optional. If one does not specify a metadatum id, the kernel will assign one. If one were to update a metadatum named mname in a pipeline named ptables with an mid of 1, one would use the following command: tc p4template update metadata/ptables/[mname] [mid 1] type bit4 Note that, in the above command, the metadatum's id and the metadatum's name are optional. That is, one may specify only the metadatum's name, only the metadatum's id, or both. If one were to delete a metadatum named mname from a pipeline named ptables with an mid of 1, one would use the following command: tc p4template del metadata/ptables/[mname] [mid 1] Note that, in the above command, the metadatum's id and the metadatum's name are optional. That is, one may specify only the metadatum's name, only the metadatum's id, or both. If one were to flush all the metadata from a pipeline named ptables, one would use the following command: tc p4template del metadata/ptables/ If one were to get a metadatum named mname from a pipeline named ptables with an mid of 1, one would use the following command: tc p4template get metadata/ptables/[mname] [mid 1] Note that, in the above command, the metadatum's id and the metadatum's name are optional. That is, one may specify only the metadatum's name, only the metadatum's id, or both. If one were to dump all the metadata from a pipeline named ptables, one would use the following command: tc p4template get metadata/ptables/ Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/p4tc.h | 44 ++ include/uapi/linux/p4tc.h | 51 ++ net/sched/p4tc/Makefile | 2 +- net/sched/p4tc/p4tc_meta.c | 819 +++++++++++++++++++++++++++++++++ net/sched/p4tc/p4tc_pipeline.c | 23 +- net/sched/p4tc/p4tc_tmpl_api.c | 19 + 6 files changed, 952 insertions(+), 6 deletions(-) create mode 100644 net/sched/p4tc/p4tc_meta.c diff --git a/include/net/p4tc.h b/include/net/p4tc.h index 178bbdf68719..6e3c4681c1d6 100644 --- a/include/net/p4tc.h +++ b/include/net/p4tc.h @@ -12,11 +12,23 @@ #define P4TC_DEFAULT_NUM_TABLES P4TC_MINTABLES_COUNT #define P4TC_DEFAULT_MAX_RULES 1 +#define P4TC_MAXMETA_OFFSET 512 #define P4TC_PATH_MAX 3 #define P4TC_KERNEL_PIPEID 0 #define P4TC_PID_IDX 0 +#define P4TC_MID_IDX 1 + +struct p4tc_percpu_scratchpad { + u32 keysz; + u32 maskid; + u8 key[BITS_TO_BYTES(P4TC_MAX_KEYSZ)]; + u8 hdrs[BITS_TO_BYTES(HEADER_MAX_LEN)]; + u8 metadata[BITS_TO_BYTES(META_MAX_LEN)]; +}; + +DECLARE_PER_CPU(struct p4tc_percpu_scratchpad, p4tc_percpu_scratchpad); struct p4tc_dump_ctx { u32 ids[P4TC_PATH_MAX]; @@ -78,6 +90,7 @@ extern const struct p4tc_template_ops p4tc_pipeline_ops; struct p4tc_pipeline { struct p4tc_template_common common; + struct idr p_meta_idr; struct rcu_head rcu; struct net *net; struct tc_action **preacts; @@ -85,6 +98,7 @@ struct p4tc_pipeline { struct tc_action **postacts; int num_postacts; u32 max_rules; + u32 p_meta_offset; refcount_t p_ref; refcount_t p_ctrl_ref; u16 num_tables; @@ -126,6 +140,36 @@ static inline int p4tc_action_destroy(struct tc_action **acts) return ret; } +static inline bool pipeline_sealed(struct p4tc_pipeline *pipeline) +{ + return pipeline->p_state == P4TC_STATE_READY; +} + +struct p4tc_metadata { + struct p4tc_template_common common; + struct rcu_head rcu; + u32 m_id; + u32 m_skb_off; + refcount_t m_ref; + u16 m_sz; + u16 m_startbit; /* Relative to its container */ + u16 m_endbit; /* Relative to its container */ + u8 m_datatype; /* T_XXX */ + bool m_read_only; +}; + +extern const struct p4tc_template_ops p4tc_meta_ops; + +struct p4tc_metadata *tcf_meta_find_byid(struct p4tc_pipeline *pipeline, + u32 m_id); +void tcf_meta_fill_user_offsets(struct p4tc_pipeline *pipeline); +void tcf_meta_init(struct p4tc_pipeline *root_pipe); +struct p4tc_metadata *tcf_meta_get(struct p4tc_pipeline *pipeline, + const char *mname, const u32 m_id, + struct netlink_ext_ack *extack); +void tcf_meta_put_ref(struct p4tc_metadata *meta); + #define to_pipeline(t) ((struct p4tc_pipeline *)t) +#define to_meta(t) ((struct p4tc_metadata *)t) #endif diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h index 739c0fe18e95..8934c032dc87 100644 --- a/include/uapi/linux/p4tc.h +++ b/include/uapi/linux/p4tc.h @@ -18,11 +18,15 @@ struct p4tcmsg { #define P4TC_MAXPARSE_KEYS 16 #define P4TC_MAXMETA_SZ 128 #define P4TC_MSGBATCH_SIZE 16 +#define P4TC_MAX_KEYSZ 512 +#define HEADER_MAX_LEN 512 +#define META_MAX_LEN 512 #define P4TC_MAX_KEYSZ 512 #define TEMPLATENAMSZ 256 #define PIPELINENAMSIZ TEMPLATENAMSZ +#define METANAMSIZ TEMPLATENAMSZ /* Root attributes */ enum { @@ -50,6 +54,7 @@ enum { enum { P4TC_OBJ_UNSPEC, P4TC_OBJ_PIPELINE, + P4TC_OBJ_META, __P4TC_OBJ_MAX, }; #define P4TC_OBJ_MAX __P4TC_OBJ_MAX @@ -59,6 +64,7 @@ enum { P4TC_UNSPEC, P4TC_PATH, P4TC_PARAMS, + P4TC_COUNT, __P4TC_MAX, }; #define P4TC_MAX __P4TC_MAX @@ -102,6 +108,51 @@ enum { }; #define P4T_MAX (__P4T_MAX - 1) +/* Details all the info needed to find out metadata size and layout inside cb + * datastructure + */ +struct p4tc_meta_size_params { + __u16 startbit; + __u16 endbit; + __u8 datatype; /* T_XXX */ +}; + +/* Metadata attributes */ +enum { + P4TC_META_UNSPEC, + P4TC_META_NAME, /* string */ + P4TC_META_SIZE, /* struct p4tc_meta_size_params */ + __P4TC_META_MAX +}; +#define P4TC_META_MAX __P4TC_META_MAX + +/* Linux system metadata */ +enum { + P4TC_KERNEL_META_UNSPEC, + P4TC_KERNEL_META_PKTLEN, /* u32 */ + P4TC_KERNEL_META_DATALEN, /* u32 */ + P4TC_KERNEL_META_SKBMARK, /* u32 */ + P4TC_KERNEL_META_TCINDEX, /* u16 */ + P4TC_KERNEL_META_SKBHASH, /* u32 */ + P4TC_KERNEL_META_SKBPRIO, /* u32 */ + P4TC_KERNEL_META_IFINDEX, /* s32 */ + P4TC_KERNEL_META_SKBIIF, /* s32 */ + P4TC_KERNEL_META_PROTOCOL, /* be16 */ + P4TC_KERNEL_META_PKTYPE, /* u8:3 */ + P4TC_KERNEL_META_IDF, /* u8:1 */ + P4TC_KERNEL_META_IPSUM, /* u8:2 */ + P4TC_KERNEL_META_OOOK, /* u8:1 */ + P4TC_KERNEL_META_FCLONE, /* u8:2 */ + P4TC_KERNEL_META_PEEKED, /* u8:1 */ + P4TC_KERNEL_META_QMAP, /* u16 */ + P4TC_KERNEL_META_PTYPEOFF, /* u8 */ + P4TC_KERNEL_META_CLONEOFF, /* u8 */ + P4TC_KERNEL_META_PTCLNOFF, /* u16 */ + P4TC_KERNEL_META_DIRECTION, /* u8:1 */ + __P4TC_KERNEL_META_MAX +}; +#define P4TC_KERNEL_META_MAX (__P4TC_KERNEL_META_MAX - 1) + #define P4TC_RTA(r) \ ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct p4tcmsg)))) diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index 0881a7563646..d523e668cbe5 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y := p4tc_types.o p4tc_tmpl_api.o p4tc_pipeline.o +obj-y := p4tc_types.o p4tc_tmpl_api.o p4tc_pipeline.o p4tc_meta.o diff --git a/net/sched/p4tc/p4tc_meta.c b/net/sched/p4tc/p4tc_meta.c new file mode 100644 index 000000000000..21a5477ab0c6 --- /dev/null +++ b/net/sched/p4tc/p4tc_meta.c @@ -0,0 +1,819 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_meta.c P4 TC API METADATA + * + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define START_META_OFFSET 0 + +static const struct nla_policy p4tc_meta_policy[P4TC_META_MAX + 1] = { + [P4TC_META_NAME] = { .type = NLA_STRING, .len = METANAMSIZ }, + [P4TC_META_SIZE] = { .type = NLA_BINARY, + .len = sizeof(struct p4tc_meta_size_params) }, +}; + +static int _tcf_meta_put(struct p4tc_pipeline *pipeline, + struct p4tc_metadata *meta, bool unconditional_purge, + struct netlink_ext_ack *extack) +{ + if (!unconditional_purge && !refcount_dec_if_one(&meta->m_ref)) + return -EBUSY; + + pipeline->p_meta_offset -= BITS_TO_U32(meta->m_sz) * sizeof(u32); + idr_remove(&pipeline->p_meta_idr, meta->m_id); + + kfree_rcu(meta, rcu); + + return 0; +} + +static int tcf_meta_put(struct net *net, struct p4tc_template_common *template, + bool unconditional_purge, + struct netlink_ext_ack *extack) +{ + struct p4tc_pipeline *pipeline = + tcf_pipeline_find_byid(net, template->p_id); + struct p4tc_metadata *meta = to_meta(template); + int ret; + + ret = _tcf_meta_put(pipeline, meta, unconditional_purge, extack); + if (ret < 0) + NL_SET_ERR_MSG(extack, "Unable to delete referenced metadatum"); + + return ret; +} + +struct p4tc_metadata *tcf_meta_find_byid(struct p4tc_pipeline *pipeline, + u32 m_id) +{ + return idr_find(&pipeline->p_meta_idr, m_id); +} + +static struct p4tc_metadata * +tcf_meta_find_byname(const char *m_name, struct p4tc_pipeline *pipeline) +{ + struct p4tc_metadata *meta; + unsigned long tmp, id; + + idr_for_each_entry_ul(&pipeline->p_meta_idr, meta, tmp, id) + if (strncmp(meta->common.name, m_name, METANAMSIZ) == 0) + return meta; + + return NULL; +} + +static inline struct p4tc_metadata * +tcf_meta_find_byname_attr(struct nlattr *name_attr, + struct p4tc_pipeline *pipeline) +{ + return tcf_meta_find_byname(nla_data(name_attr), pipeline); +} + +static struct p4tc_metadata *tcf_meta_find_byany(struct p4tc_pipeline *pipeline, + const char *mname, + const u32 m_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_metadata *meta; + int err; + + if (m_id) { + meta = tcf_meta_find_byid(pipeline, m_id); + if (!meta) { + NL_SET_ERR_MSG(extack, + "Unable to find metadatum by id"); + err = -EINVAL; + goto out; + } + } else { + if (mname) { + meta = tcf_meta_find_byname(mname, pipeline); + if (!meta) { + NL_SET_ERR_MSG(extack, + "Metadatum name not found"); + err = -EINVAL; + goto out; + } + } else { + NL_SET_ERR_MSG(extack, + "Must specify metadatum name or id"); + err = -EINVAL; + goto out; + } + } + + return meta; +out: + return ERR_PTR(err); +} + +struct p4tc_metadata *tcf_meta_get(struct p4tc_pipeline *pipeline, + const char *mname, const u32 m_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_metadata *meta; + + meta = tcf_meta_find_byany(pipeline, mname, m_id, extack); + if (IS_ERR(meta)) + return meta; + + /* Should never be zero */ + WARN_ON(!refcount_inc_not_zero(&meta->m_ref)); + return meta; +} + +void tcf_meta_put_ref(struct p4tc_metadata *meta) +{ + WARN_ON(!refcount_dec_not_one(&meta->m_ref)); +} + +static struct p4tc_metadata * +tcf_meta_find_byanyattr(struct p4tc_pipeline *pipeline, + struct nlattr *name_attr, const u32 m_id, + struct netlink_ext_ack *extack) +{ + char *mname = NULL; + + if (name_attr) + mname = nla_data(name_attr); + + return tcf_meta_find_byany(pipeline, mname, m_id, extack); +} + +static int p4tc_check_meta_size(struct p4tc_meta_size_params *sz_params, + struct p4tc_type *type, + struct netlink_ext_ack *extack) +{ + int new_bitsz; + + if (sz_params->startbit > P4T_MAX_BITSZ || + sz_params->startbit > type->bitsz) { + NL_SET_ERR_MSG(extack, "Startbit value too big"); + return -EINVAL; + } + + if (sz_params->endbit > P4T_MAX_BITSZ || + sz_params->endbit > type->bitsz) { + NL_SET_ERR_MSG(extack, "Endbit value too big"); + return -EINVAL; + } + + if (sz_params->endbit < sz_params->startbit) { + NL_SET_ERR_MSG(extack, "Endbit value smaller than startbit"); + return -EINVAL; + } + + new_bitsz = (sz_params->endbit - sz_params->startbit + 1); + if (new_bitsz == 0) { + NL_SET_ERR_MSG(extack, "Bit size can't be zero"); + return -EINVAL; + } + + if (new_bitsz > P4T_MAX_BITSZ || new_bitsz > type->bitsz) { + NL_SET_ERR_MSG(extack, "Bit size too big"); + return -EINVAL; + } + + return new_bitsz; +} + +void tcf_meta_fill_user_offsets(struct p4tc_pipeline *pipeline) +{ + u32 meta_off = START_META_OFFSET; + struct p4tc_metadata *meta; + unsigned long tmp, id; + + idr_for_each_entry_ul(&pipeline->p_meta_idr, meta, tmp, id) { + /* Offsets are multiples of 4 for alignment purposes */ + meta->m_skb_off = meta_off; + meta_off += BITS_TO_U32(meta->m_sz) * sizeof(u32); + } +} + +static struct p4tc_metadata * +__tcf_meta_create(struct p4tc_pipeline *pipeline, u32 m_id, const char *m_name, + struct p4tc_meta_size_params *sz_params, gfp_t alloc_flag, + bool read_only, struct netlink_ext_ack *extack) +{ + u32 p_meta_offset = 0; + bool kmeta; + struct p4tc_metadata *meta; + struct p4tc_type *datatype; + u32 sz_bytes; + int sz_bits; + int ret; + + kmeta = pipeline->common.p_id == P4TC_KERNEL_PIPEID; + + meta = kzalloc(sizeof(*meta), alloc_flag); + if (!meta) { + if (kmeta) + pr_err("Unable to allocate kernel metadatum"); + else + NL_SET_ERR_MSG(extack, + "Unable to allocate user metadatum"); + ret = -ENOMEM; + goto out; + } + + meta->common.p_id = pipeline->common.p_id; + + datatype = p4type_find_byid(sz_params->datatype); + if (!datatype) { + if (kmeta) + pr_err("Invalid data type for kernel metadataum %u\n", + sz_params->datatype); + else + NL_SET_ERR_MSG(extack, + "Invalid data type for user metdatum"); + ret = -EINVAL; + goto free; + } + + sz_bits = p4tc_check_meta_size(sz_params, datatype, extack); + if (sz_bits < 0) { + ret = sz_bits; + goto free; + } + + sz_bytes = BITS_TO_U32(datatype->bitsz) * sizeof(u32); + if (!kmeta) { + p_meta_offset = pipeline->p_meta_offset + sz_bytes; + if (p_meta_offset > BITS_TO_BYTES(P4TC_MAXMETA_OFFSET)) { + NL_SET_ERR_MSG(extack, "Metadata max offset exceeded"); + ret = -EINVAL; + goto free; + } + } + + meta->m_datatype = datatype->typeid; + meta->m_startbit = sz_params->startbit; + meta->m_endbit = sz_params->endbit; + meta->m_sz = sz_bits; + meta->m_read_only = read_only; + + if (m_id) { + ret = idr_alloc_u32(&pipeline->p_meta_idr, meta, &m_id, m_id, + alloc_flag); + if (ret < 0) { + if (kmeta) + pr_err("Unable to alloc kernel metadatum id %u\n", + m_id); + else + NL_SET_ERR_MSG(extack, + "Unable to alloc user metadatum id"); + goto free; + } + + meta->m_id = m_id; + } else { + meta->m_id = 1; + + ret = idr_alloc_u32(&pipeline->p_meta_idr, meta, &meta->m_id, + UINT_MAX, alloc_flag); + if (ret < 0) { + if (kmeta) + pr_err("Unable to alloc kernel metadatum id %u\n", + meta->m_id); + else + NL_SET_ERR_MSG(extack, + "Unable to alloc metadatum id"); + goto free; + } + } + + if (!kmeta) + pipeline->p_meta_offset = p_meta_offset; + + strscpy(meta->common.name, m_name, METANAMSIZ); + meta->common.ops = (struct p4tc_template_ops *)&p4tc_meta_ops; + + refcount_set(&meta->m_ref, 1); + + return meta; + +free: + kfree(meta); +out: + return ERR_PTR(ret); +} + +struct p4tc_metadata *tcf_meta_create(struct nlmsghdr *n, struct nlattr *nla, + u32 m_id, struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + int ret = 0; + struct p4tc_meta_size_params *sz_params; + struct nlattr *tb[P4TC_META_MAX + 1]; + char *m_name; + + ret = nla_parse_nested(tb, P4TC_META_MAX, nla, p4tc_meta_policy, + extack); + if (ret < 0) + goto out; + + if (tcf_meta_find_byname_attr(tb[P4TC_META_NAME], pipeline) || + tcf_meta_find_byid(pipeline, m_id)) { + NL_SET_ERR_MSG(extack, "Metadatum already exists"); + ret = -EEXIST; + goto out; + } + + if (tb[P4TC_META_NAME]) { + m_name = nla_data(tb[P4TC_META_NAME]); + } else { + NL_SET_ERR_MSG(extack, "Must specify metadatum name"); + ret = -ENOENT; + goto out; + } + + if (tb[P4TC_META_SIZE]) { + sz_params = nla_data(tb[P4TC_META_SIZE]); + } else { + NL_SET_ERR_MSG(extack, "Must specify metadatum size params"); + ret = -ENOENT; + goto out; + } + + return __tcf_meta_create(pipeline, m_id, m_name, sz_params, GFP_KERNEL, + false, extack); + +out: + return ERR_PTR(ret); +} + +static struct p4tc_metadata *tcf_meta_update(struct nlmsghdr *n, + struct nlattr *nla, u32 m_id, + struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_META_MAX + 1]; + struct p4tc_metadata *meta; + int ret; + + ret = nla_parse_nested(tb, P4TC_META_MAX, nla, p4tc_meta_policy, + extack); + + if (ret < 0) + goto out; + + meta = tcf_meta_find_byanyattr(pipeline, tb[P4TC_META_NAME], m_id, + extack); + if (IS_ERR(meta)) + return meta; + + if (tb[P4TC_META_SIZE]) { + struct p4tc_type *new_datatype, *curr_datatype; + struct p4tc_meta_size_params *sz_params; + u32 new_bytesz, curr_bytesz; + int new_bitsz; + u32 p_meta_offset; + int diff; + + sz_params = nla_data(tb[P4TC_META_SIZE]); + new_datatype = p4type_find_byid(sz_params->datatype); + if (!new_datatype) { + NL_SET_ERR_MSG(extack, "Invalid data type"); + ret = -EINVAL; + goto out; + } + + new_bitsz = + p4tc_check_meta_size(sz_params, new_datatype, extack); + if (new_bitsz < 0) { + ret = new_bitsz; + goto out; + } + + new_bytesz = BITS_TO_U32(new_datatype->bitsz) * sizeof(u32); + + curr_datatype = p4type_find_byid(meta->m_datatype); + curr_bytesz = BITS_TO_U32(curr_datatype->bitsz) * sizeof(u32); + + diff = new_bytesz - curr_bytesz; + p_meta_offset = pipeline->p_meta_offset + diff; + if (p_meta_offset > BITS_TO_BYTES(P4TC_MAXMETA_OFFSET)) { + NL_SET_ERR_MSG(extack, "Metadata max offset exceeded"); + ret = -EINVAL; + goto out; + } + + pipeline->p_meta_offset = p_meta_offset; + + meta->m_datatype = new_datatype->typeid; + meta->m_startbit = sz_params->startbit; + meta->m_endbit = sz_params->endbit; + meta->m_sz = new_bitsz; + } + + return meta; + +out: + return ERR_PTR(ret); +} + +static struct p4tc_template_common * +tcf_meta_cu(struct net *net, struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + u32 pipeid = ids[P4TC_PID_IDX], m_id = ids[P4TC_MID_IDX]; + struct p4tc_pipeline *pipeline; + struct p4tc_metadata *meta; + + pipeline = tcf_pipeline_find_byany_unsealed(net, nl_pname->data, pipeid, + extack); + if (IS_ERR(pipeline)) + return (void *)pipeline; + + if (n->nlmsg_flags & NLM_F_REPLACE) + meta = tcf_meta_update(n, nla, m_id, pipeline, extack); + else + meta = tcf_meta_create(n, nla, m_id, pipeline, extack); + + if (IS_ERR(meta)) + goto out; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + +out: + return (struct p4tc_template_common *)meta; +} + +static int _tcf_meta_fill_nlmsg(struct sk_buff *skb, + const struct p4tc_metadata *meta) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_meta_size_params sz_params; + struct nlattr *nest; + + if (nla_put_u32(skb, P4TC_PATH, meta->m_id)) + goto out_nlmsg_trim; + + nest = nla_nest_start(skb, P4TC_PARAMS); + if (!nest) + goto out_nlmsg_trim; + + sz_params.datatype = meta->m_datatype; + sz_params.startbit = meta->m_startbit; + sz_params.endbit = meta->m_endbit; + + if (nla_put_string(skb, P4TC_META_NAME, meta->common.name)) + goto out_nlmsg_trim; + if (nla_put(skb, P4TC_META_SIZE, sizeof(sz_params), &sz_params)) + goto out_nlmsg_trim; + + nla_nest_end(skb, nest); + + return skb->len; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -1; +} + +static int tcf_meta_fill_nlmsg(struct net *net, struct sk_buff *skb, + struct p4tc_template_common *template, + struct netlink_ext_ack *extack) +{ + const struct p4tc_metadata *meta = to_meta(template); + + if (_tcf_meta_fill_nlmsg(skb, meta) <= 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for metadatum"); + return -EINVAL; + } + + return 0; +} + +static int tcf_meta_flush(struct sk_buff *skb, struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + struct p4tc_metadata *meta; + unsigned long tmp, m_id; + unsigned char *b = nlmsg_get_pos(skb); + int ret = 0; + int i = 0; + + if (nla_put_u32(skb, P4TC_PATH, 0)) + goto out_nlmsg_trim; + + if (idr_is_empty(&pipeline->p_meta_idr)) { + NL_SET_ERR_MSG(extack, "There is not metadata to flush"); + ret = 0; + goto out_nlmsg_trim; + } + + idr_for_each_entry_ul(&pipeline->p_meta_idr, meta, tmp, m_id) { + if (_tcf_meta_put(pipeline, meta, false, extack) < 0) { + ret = -EBUSY; + continue; + } + i++; + } + + nla_put_u32(skb, P4TC_COUNT, i); + + if (ret < 0) { + if (i == 0) { + NL_SET_ERR_MSG(extack, "Unable to flush any metadata"); + goto out_nlmsg_trim; + } else { + NL_SET_ERR_MSG(extack, "Unable to flush all metadata"); + } + } + + return i; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_meta_gd(struct net *net, struct sk_buff *skb, struct nlmsghdr *n, + struct nlattr *nla, struct p4tc_nl_pname *nl_pname, + u32 *ids, struct netlink_ext_ack *extack) +{ + u32 pipeid = ids[P4TC_PID_IDX], m_id = ids[P4TC_MID_IDX]; + struct nlattr *tb[P4TC_META_MAX + 1] = {}; + unsigned char *b = nlmsg_get_pos(skb); + int ret = 0; + struct p4tc_pipeline *pipeline; + struct p4tc_metadata *meta; + + if (n->nlmsg_type == RTM_DELP4TEMPLATE) + pipeline = tcf_pipeline_find_byany_unsealed(net, nl_pname->data, + pipeid, extack); + else + pipeline = tcf_pipeline_find_byany(net, nl_pname->data, pipeid, + extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + + if (nla) { + ret = nla_parse_nested(tb, P4TC_META_MAX, nla, p4tc_meta_policy, + extack); + + if (ret < 0) + return ret; + } + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (n->nlmsg_type == RTM_DELP4TEMPLATE && (n->nlmsg_flags & NLM_F_ROOT)) + return tcf_meta_flush(skb, pipeline, extack); + + meta = tcf_meta_find_byanyattr(pipeline, tb[P4TC_META_NAME], m_id, + extack); + if (IS_ERR(meta)) + return PTR_ERR(meta); + + if (_tcf_meta_fill_nlmsg(skb, meta) < 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for metadatum"); + return -EINVAL; + } + + if (n->nlmsg_type == RTM_DELP4TEMPLATE) { + ret = _tcf_meta_put(pipeline, meta, false, extack); + if (ret < 0) { + NL_SET_ERR_MSG(extack, + "Unable to delete referenced metadatum"); + goto out_nlmsg_trim; + } + } + + return ret; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_meta_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, + struct nlattr *nla, char **p_name, u32 *ids, + struct netlink_ext_ack *extack) +{ + unsigned char *b = nlmsg_get_pos(skb); + const u32 pipeid = ids[P4TC_PID_IDX]; + struct net *net = sock_net(skb->sk); + unsigned long m_id = 0; + int i = 0; + struct p4tc_pipeline *pipeline; + struct p4tc_metadata *meta; + unsigned long tmp; + + if (!ctx->ids[P4TC_PID_IDX]) { + pipeline = + tcf_pipeline_find_byany(net, *p_name, pipeid, extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + ctx->ids[P4TC_PID_IDX] = pipeline->common.p_id; + } else { + pipeline = tcf_pipeline_find_byid(net, ctx->ids[P4TC_PID_IDX]); + } + + m_id = ctx->ids[P4TC_MID_IDX]; + + idr_for_each_entry_continue_ul(&pipeline->p_meta_idr, meta, tmp, m_id) { + struct nlattr *count, *param; + + if (i == P4TC_MSGBATCH_SIZE) + break; + + count = nla_nest_start(skb, i + 1); + if (!count) + goto out_nlmsg_trim; + + param = nla_nest_start(skb, P4TC_PARAMS); + if (!param) + goto out_nlmsg_trim; + if (nla_put_string(skb, P4TC_META_NAME, meta->common.name)) + goto out_nlmsg_trim; + + nla_nest_end(skb, param); + nla_nest_end(skb, count); + + i++; + } + + if (i == 0) { + if (!ctx->ids[P4TC_MID_IDX]) + NL_SET_ERR_MSG(extack, "There is no metadata to dump"); + return 0; + } + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!(*p_name)) + *p_name = pipeline->common.name; + + ctx->ids[P4TC_MID_IDX] = m_id; + + return skb->len; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -ENOMEM; +} + +static int __p4tc_register_kmeta(struct p4tc_pipeline *pipeline, u32 m_id, + const char *m_name, u8 startbit, u8 endbit, + bool read_only, u32 datatype) +{ + struct p4tc_meta_size_params sz_params = { + .startbit = startbit, + .endbit = endbit, + .datatype = datatype, + }; + struct p4tc_metadata *meta; + + meta = __tcf_meta_create(pipeline, m_id, m_name, &sz_params, GFP_ATOMIC, + read_only, NULL); + if (IS_ERR(meta)) { + pr_err("Failed to register metadata %s %ld\n", m_name, + PTR_ERR(meta)); + return PTR_ERR(meta); + } + + pr_debug("Registered kernel metadata %s with id %u\n", m_name, m_id); + + return 0; +} + +#define p4tc_register_kmeta(...) \ + do { \ + if (__p4tc_register_kmeta(__VA_ARGS__) < 0) \ + return; \ + } while (0) + +void tcf_meta_init(struct p4tc_pipeline *root_pipe) +{ + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_PKTLEN, "pktlen", 0, 31, + false, P4T_U32); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_DATALEN, "datalen", 0, + 31, false, P4T_U32); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_SKBMARK, "skbmark", 0, + 31, false, P4T_U32); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_TCINDEX, "tcindex", 0, + 15, false, P4T_U16); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_SKBHASH, "skbhash", 0, + 31, false, P4T_U32); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_SKBPRIO, "skbprio", 0, + 31, false, P4T_U32); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_IFINDEX, "ifindex", 0, + 31, false, P4T_S32); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_SKBIIF, "iif", 0, 31, + true, P4T_DEV); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_PROTOCOL, "skbproto", 0, + 15, false, P4T_BE16); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_PTYPEOFF, "ptypeoff", 0, + 7, false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_CLONEOFF, "cloneoff", 0, + 7, false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_PTCLNOFF, "ptclnoff", 0, + 15, false, P4T_U16); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_QMAP, "skbqmap", 0, 15, + false, P4T_U16); + +#if defined(__LITTLE_ENDIAN_BITFIELD) + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_PKTYPE, "skbptype", 0, + 2, false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_IDF, "skbidf", 3, 3, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_IPSUM, "skbipsum", 5, 6, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_OOOK, "skboook", 7, 7, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_FCLONE, "fclone", 2, 3, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_PEEKED, "skbpeek", 4, 4, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_DIRECTION, "direction", + 7, 7, false, P4T_U8); +#elif defined(__BIG_ENDIAN_BITFIELD) + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_PKTYPE, "skbptype", 5, + 7, false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_IDF, "skbidf", 4, 4, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_IPSUM, "skbipsum", 1, 2, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_OOOK, "skboook", 0, 0, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_FCLONE, "fclone", 4, 5, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_PEEKED, "skbpeek", 3, 3, + false, P4T_U8); + + p4tc_register_kmeta(root_pipe, P4TC_KERNEL_META_DIRECTION, "direction", + 0, 0, false, P4T_U8); +#else +#error "Please fix " +#endif +} + +const struct p4tc_template_ops p4tc_meta_ops = { + .cu = tcf_meta_cu, + .fill_nlmsg = tcf_meta_fill_nlmsg, + .gd = tcf_meta_gd, + .put = tcf_meta_put, + .dump = tcf_meta_dump, +}; diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c index 776a8d37b615..56b4f7be8d17 100644 --- a/net/sched/p4tc/p4tc_pipeline.c +++ b/net/sched/p4tc/p4tc_pipeline.c @@ -80,6 +80,8 @@ static const struct nla_policy tc_pipeline_policy[P4TC_PIPELINE_MAX + 1] = { static void tcf_pipeline_destroy(struct p4tc_pipeline *pipeline, bool free_pipeline) { + idr_destroy(&pipeline->p_meta_idr); + if (free_pipeline) kfree(pipeline); } @@ -104,6 +106,8 @@ static int tcf_pipeline_put(struct net *net, struct p4tc_pipeline_net *pipe_net = net_generic(net, pipeline_net_id); struct p4tc_pipeline *pipeline = to_pipeline(template); struct net *pipeline_net = maybe_get_net(net); + struct p4tc_metadata *meta; + unsigned long m_id, tmp; if (pipeline_net && !refcount_dec_if_one(&pipeline->p_ref)) { NL_SET_ERR_MSG(extack, "Can't delete referenced pipeline"); @@ -112,6 +116,9 @@ static int tcf_pipeline_put(struct net *net, idr_remove(&pipe_net->pipeline_idr, pipeline->common.p_id); + idr_for_each_entry_ul(&pipeline->p_meta_idr, meta, tmp, m_id) + meta->common.ops->put(net, &meta->common, true, extack); + /* XXX: The action fields are only accessed in the control path * since they will be copied to the filter, where the data path * will use them. So there is no need to free them in the rcu @@ -154,11 +161,6 @@ static inline int pipeline_try_set_state_ready(struct p4tc_pipeline *pipeline, return true; } -static inline bool pipeline_sealed(struct p4tc_pipeline *pipeline) -{ - return pipeline->p_state == P4TC_STATE_READY; -} - static int p4tc_action_init(struct net *net, struct nlattr *nla, struct tc_action *acts[], u32 pipeid, u32 flags, struct netlink_ext_ack *extack) @@ -317,6 +319,9 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, pipeline->num_postacts = 0; } + idr_init(&pipeline->p_meta_idr); + pipeline->p_meta_offset = 0; + pipeline->p_state = P4TC_STATE_NOT_READY; pipeline->net = net; @@ -510,6 +515,7 @@ tcf_pipeline_update(struct net *net, struct nlmsghdr *n, struct nlattr *nla, ret = pipeline_try_set_state_ready(pipeline, extack); if (ret < 0) goto postactions_destroy; + tcf_meta_fill_user_offsets(pipeline); } if (max_rules) @@ -726,12 +732,16 @@ static void __tcf_pipeline_init(void) strscpy(root_pipeline->common.name, "kernel", PIPELINENAMSIZ); + idr_init(&root_pipeline->p_meta_idr); + root_pipeline->common.ops = (struct p4tc_template_ops *)&p4tc_pipeline_ops; root_pipeline->common.p_id = pipeid; root_pipeline->p_state = P4TC_STATE_READY; + + tcf_meta_init(root_pipeline); } static void tcf_pipeline_init(void) @@ -745,6 +755,9 @@ static void tcf_pipeline_init(void) __tcf_pipeline_init(); } +DEFINE_PER_CPU(struct p4tc_percpu_scratchpad, p4tc_percpu_scratchpad); +EXPORT_PER_CPU_SYMBOL_GPL(p4tc_percpu_scratchpad); + const struct p4tc_template_ops p4tc_pipeline_ops = { .init = tcf_pipeline_init, .cu = tcf_pipeline_cu, diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c index a936ec84841d..19dd6f41a3a4 100644 --- a/net/sched/p4tc/p4tc_tmpl_api.c +++ b/net/sched/p4tc/p4tc_tmpl_api.c @@ -42,6 +42,7 @@ static bool obj_is_valid(u32 obj) { switch (obj) { case P4TC_OBJ_PIPELINE: + case P4TC_OBJ_META: return true; default: return false; @@ -50,6 +51,7 @@ static bool obj_is_valid(u32 obj) static const struct p4tc_template_ops *p4tc_ops[P4TC_OBJ_MAX] = { [P4TC_OBJ_PIPELINE] = &p4tc_pipeline_ops, + [P4TC_OBJ_META] = &p4tc_meta_ops, }; int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, @@ -124,6 +126,12 @@ static int tc_ctl_p4_tmpl_gd_1(struct net *net, struct sk_buff *skb, ids[P4TC_PID_IDX] = t->pipeid; + if (tb[P4TC_PATH]) { + const u32 *arg_ids = nla_data(tb[P4TC_PATH]); + + memcpy(&ids[P4TC_MID_IDX], arg_ids, nla_len(tb[P4TC_PATH])); + } + op = (struct p4tc_template_ops *)p4tc_ops[t->obj]; ret = op->gd(net, skb, n, tb[P4TC_PARAMS], nl_pname, ids, extack); @@ -300,6 +308,12 @@ tcf_p4_tmpl_cu_1(struct sk_buff *skb, struct net *net, struct nlmsghdr *n, ids[P4TC_PID_IDX] = t->pipeid; + if (tb[P4TC_PATH]) { + const u32 *arg_ids = nla_data(tb[P4TC_PATH]); + + memcpy(&ids[P4TC_MID_IDX], arg_ids, nla_len(tb[P4TC_PATH])); + } + op = (struct p4tc_template_ops *)p4tc_ops[t->obj]; tmpl = op->cu(net, n, tb[P4TC_PARAMS], nl_pname, ids, extack); if (IS_ERR(tmpl)) @@ -486,6 +500,11 @@ static int tc_ctl_p4_tmpl_dump_1(struct sk_buff *skb, struct nlattr *arg, root = nla_nest_start(skb, P4TC_ROOT); ids[P4TC_PID_IDX] = t->pipeid; + if (tb[P4TC_PATH]) { + const u32 *arg_ids = nla_data(tb[P4TC_PATH]); + + memcpy(&ids[P4TC_MID_IDX], arg_ids, nla_len(tb[P4TC_PATH])); + } op = (struct p4tc_template_ops *)p4tc_ops[t->obj]; ret = op->dump(skb, ctx, tb[P4TC_PARAMS], &p_name, ids, extack); From patchwork Wed May 17 11:02:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244694 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1FEEF200AF for ; Wed, 17 May 2023 11:04:26 +0000 (UTC) Received: from mail-yb1-xb33.google.com (mail-yb1-xb33.google.com [IPv6:2607:f8b0:4864:20::b33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 67202213B for ; Wed, 17 May 2023 04:03:58 -0700 (PDT) Received: by mail-yb1-xb33.google.com with SMTP id 3f1490d57ef6-ba82059eec9so838871276.3 for ; Wed, 17 May 2023 04:03:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321437; x=1686913437; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=3ZBqqa1ZEDZMlqU6RJOcdpv4AzGFV4O0mpFRkpUOxGY=; b=x0jRA80z9MFP1g7lopoSHN7tHgqRy9BOWh5Cl1lzP41kfQsYhO4lbV2P7aJdu+VHBC lR4yY8tYNuQcV1co81L3nxSqEG5iQtKttBqZ1OHIuG+7az9meZzhVlR5V9/a7gup2Yc2 lH9CtvnaUIsbMUU2ZdaLBDEaITxXBWNHerfD/rXYPXupU7ggWCCk2dySnXVB3VUyLK4Y sMlPjQC9Few9TOjFCl7/zYCXHJt7zyTtsP+nm51jGolwaGNwd37h/9EPjawIbZB83w6Z 2B9whpL2KiofGG4bYyvZp6hpnvp9+B283vh4JIduwPBOrpL/JDTis25upzxA9Pps3G/O AUXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321437; x=1686913437; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=3ZBqqa1ZEDZMlqU6RJOcdpv4AzGFV4O0mpFRkpUOxGY=; b=kbSHt7t/jKKuiuPIYwNg+jAvIp5Rt1w94VvXVwO3jRJlLhLk4BDRKFqkU/pL3HlML0 GFoqRzmvayy+0nklskpYMdqshnXgtYkg/i8WxKaw+plmbvbVXSqNjOGpoB7Gl73qOAM6 V3pGGtQCHvubzjNwbTD65primkKTPIKlEI0z0ZY6+B+Yv2JFDN54Gd0mkbR2+Kd/Bato teDzrr6qPUuV2TF5yd8WjJ9TFd40zaIJONkoOuDW+eZG1J7VZx0bK0+LYYpuUiF7ldwO GiCitI/atwN1Fa8OpKbx4L1PFpI/VTzV/aSIim42+XiL842sYOhhWe+107R57NTvxdGq wAgA== X-Gm-Message-State: AC+VfDwUDP1iu1lwnyXlcXBqU3bhN8jWXPNMfaE1EMODXD+ebqBtYLOt Z9k1JingaXQ9MsxiUUFM2FefXb/8cy5yEIbZs18= X-Google-Smtp-Source: ACHHUZ5w/7DHbH8iLZQi5SeZrUFD1XUz2270s+L+5Czqx4R82/rKJbl1ez/FYtQqbu5R6K1AkyfBqQ== X-Received: by 2002:a25:31d4:0:b0:ba8:6499:c19a with SMTP id x203-20020a2531d4000000b00ba86499c19amr713722ybx.13.1684321436657; Wed, 17 May 2023 04:03:56 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id p7-20020a05620a112700b007579371d70esm532679qkk.46.2023.05.17.04.03.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:03:56 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 12/28] p4tc: add header field create, get, delete, flush and dump Date: Wed, 17 May 2023 07:02:16 -0400 Message-Id: <20230517110232.29349-12-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This commit allows control to create, get, delete, flush and dump header field objects. The created header fields are retrieved at runtime by the parser. From a control plane interaction, a header field can only be created once the appropriate parser is instantiated. At runtime, existing header fields can be referenced for computation reasons from metact: metact will use header fields to either create lookup keys or edit the header fields. Header fields are part of a pipeline and a parser instance and header fields can only be created in an unsealed pipeline. To create a header field, the user must issue the equivalent of the following command: tc p4template create hdrfield/myprog/myparser/ipv4/dstAddr hdrfieldid 4 \ type ipv4 where myprog is the name of a pipeline, myparser is a name of a parser instance, ipv4/dstAddr is the name of header field which is of type ipv4. To delete a header field, the user must issue the equivalent of the following command: tc p4template delete hdrfield/myprog/myparser/ipv4/dstAddr where myprog is the name of pipeline, myparser is a name of a parser instance, ipv4/dstAddr is the name of header field to be deleted. To retrieve meta-information from a header field, such as length, position and type, the user must issue the equivalent of the following command: tc p4template get hdrfield/myprog/myparser/ipv4/dstAddr where myprog is the name of pipeline, myparser is a name of a parser instance, ipv4/dstAddr is the name of header field to be deleted. The user can also dump all the header fields available in a parser instance using the equivalent of the following command: tc p4template get hdrfield/myprog/myparser/ With that, the user will get all the header field names available in a specific parser instance. The user can also flush all the header fields available in a parser instance using the equivalent of the following command: tc p4template del hdrfield/myprog/myparser/ Header fields do not support update operations. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/p4tc.h | 54 +++ include/uapi/linux/p4tc.h | 19 + net/sched/p4tc/Makefile | 3 +- net/sched/p4tc/p4tc_hdrfield.c | 616 +++++++++++++++++++++++++++++++ net/sched/p4tc/p4tc_parser_api.c | 146 ++++++++ net/sched/p4tc/p4tc_pipeline.c | 4 + net/sched/p4tc/p4tc_tmpl_api.c | 2 + 7 files changed, 843 insertions(+), 1 deletion(-) create mode 100644 net/sched/p4tc/p4tc_hdrfield.c create mode 100644 net/sched/p4tc/p4tc_parser_api.c diff --git a/include/net/p4tc.h b/include/net/p4tc.h index 6e3c4681c1d6..096f52c4320e 100644 --- a/include/net/p4tc.h +++ b/include/net/p4tc.h @@ -19,6 +19,10 @@ #define P4TC_PID_IDX 0 #define P4TC_MID_IDX 1 +#define P4TC_PARSEID_IDX 1 +#define P4TC_HDRFIELDID_IDX 2 + +#define P4TC_HDRFIELD_IS_VALIDITY_BIT 0x1 struct p4tc_percpu_scratchpad { u32 keysz; @@ -93,6 +97,7 @@ struct p4tc_pipeline { struct idr p_meta_idr; struct rcu_head rcu; struct net *net; + struct p4tc_parser *parser; struct tc_action **preacts; int num_preacts; struct tc_action **postacts; @@ -160,6 +165,27 @@ struct p4tc_metadata { extern const struct p4tc_template_ops p4tc_meta_ops; +struct p4tc_parser { + char parser_name[PARSERNAMSIZ]; + struct idr hdr_fields_idr; + refcount_t parser_ref; + u32 parser_inst_id; +}; + +struct p4tc_hdrfield { + struct p4tc_template_common common; + struct p4tc_parser *parser; + u32 parser_inst_id; + u32 hdrfield_id; + refcount_t hdrfield_ref; + u16 startbit; + u16 endbit; + u8 datatype; /* T_XXX */ + u8 flags; /* P4TC_HDRFIELD_FLAGS_* */ +}; + +extern const struct p4tc_template_ops p4tc_hdrfield_ops; + struct p4tc_metadata *tcf_meta_find_byid(struct p4tc_pipeline *pipeline, u32 m_id); void tcf_meta_fill_user_offsets(struct p4tc_pipeline *pipeline); @@ -169,7 +195,35 @@ struct p4tc_metadata *tcf_meta_get(struct p4tc_pipeline *pipeline, struct netlink_ext_ack *extack); void tcf_meta_put_ref(struct p4tc_metadata *meta); +struct p4tc_parser *tcf_parser_create(struct p4tc_pipeline *pipeline, + const char *parser_name, + u32 parser_inst_id, + struct netlink_ext_ack *extack); + +struct p4tc_parser *tcf_parser_find_byid(struct p4tc_pipeline *pipeline, + const u32 parser_inst_id); +struct p4tc_parser *tcf_parser_find_byany(struct p4tc_pipeline *pipeline, + const char *parser_name, + u32 parser_inst_id, + struct netlink_ext_ack *extack); +int tcf_parser_del(struct net *net, struct p4tc_pipeline *pipeline, + struct p4tc_parser *parser, struct netlink_ext_ack *extack); + +struct p4tc_hdrfield *tcf_hdrfield_find_byid(struct p4tc_parser *parser, + const u32 hdrfield_id); +struct p4tc_hdrfield *tcf_hdrfield_find_byany(struct p4tc_parser *parser, + const char *hdrfield_name, + u32 hdrfield_id, + struct netlink_ext_ack *extack); +void *tcf_hdrfield_fetch(struct sk_buff *skb, struct p4tc_hdrfield *hdrfield); +struct p4tc_hdrfield *tcf_hdrfield_get(struct p4tc_parser *parser, + const char *hdrfield_name, + u32 hdrfield_id, + struct netlink_ext_ack *extack); +void tcf_hdrfield_put_ref(struct p4tc_hdrfield *hdrfield); + #define to_pipeline(t) ((struct p4tc_pipeline *)t) #define to_meta(t) ((struct p4tc_metadata *)t) +#define to_hdrfield(t) ((struct p4tc_hdrfield *)t) #endif diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h index 8934c032dc87..72714df9e74f 100644 --- a/include/uapi/linux/p4tc.h +++ b/include/uapi/linux/p4tc.h @@ -27,6 +27,8 @@ struct p4tcmsg { #define TEMPLATENAMSZ 256 #define PIPELINENAMSIZ TEMPLATENAMSZ #define METANAMSIZ TEMPLATENAMSZ +#define PARSERNAMSIZ TEMPLATENAMSZ +#define HDRFIELDNAMSIZ TEMPLATENAMSZ /* Root attributes */ enum { @@ -55,6 +57,7 @@ enum { P4TC_OBJ_UNSPEC, P4TC_OBJ_PIPELINE, P4TC_OBJ_META, + P4TC_OBJ_HDR_FIELD, __P4TC_OBJ_MAX, }; #define P4TC_OBJ_MAX __P4TC_OBJ_MAX @@ -153,6 +156,22 @@ enum { }; #define P4TC_KERNEL_META_MAX (__P4TC_KERNEL_META_MAX - 1) +struct p4tc_hdrfield_ty { + __u16 startbit; + __u16 endbit; + __u8 datatype; /* P4T_* */ +}; + +/* Header field attributes */ +enum { + P4TC_HDRFIELD_UNSPEC, + P4TC_HDRFIELD_DATA, + P4TC_HDRFIELD_NAME, + P4TC_HDRFIELD_PARSER_NAME, + __P4TC_HDRFIELD_MAX +}; +#define P4TC_HDRFIELD_MAX (__P4TC_HDRFIELD_MAX - 1) + #define P4TC_RTA(r) \ ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct p4tcmsg)))) diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index d523e668cbe5..add22c909be6 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y := p4tc_types.o p4tc_tmpl_api.o p4tc_pipeline.o p4tc_meta.o +obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.o p4tc_meta.o \ + p4tc_parser_api.o p4tc_hdrfield.o diff --git a/net/sched/p4tc/p4tc_hdrfield.c b/net/sched/p4tc/p4tc_hdrfield.c new file mode 100644 index 000000000000..d5dd9b5c885d --- /dev/null +++ b/net/sched/p4tc/p4tc_hdrfield.c @@ -0,0 +1,616 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_hdrfield.c P4 TC HEADER FIELD + * + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct nla_policy tc_hdrfield_policy[P4TC_HDRFIELD_MAX + 1] = { + [P4TC_HDRFIELD_DATA] = { .type = NLA_BINARY, + .len = sizeof(struct p4tc_hdrfield_ty) }, + [P4TC_HDRFIELD_NAME] = { .type = NLA_STRING, .len = HDRFIELDNAMSIZ }, + [P4TC_HDRFIELD_PARSER_NAME] = { .type = NLA_STRING, + .len = PARSERNAMSIZ }, +}; + +static int _tcf_hdrfield_put(struct p4tc_pipeline *pipeline, + struct p4tc_parser *parser, + struct p4tc_hdrfield *hdrfield, + bool unconditional_purge, + struct netlink_ext_ack *extack) +{ + if (!refcount_dec_if_one(&hdrfield->hdrfield_ref) && + !unconditional_purge) { + NL_SET_ERR_MSG(extack, + "Unable to delete referenced header field"); + return -EBUSY; + } + idr_remove(&parser->hdr_fields_idr, hdrfield->hdrfield_id); + + WARN_ON(!refcount_dec_not_one(&parser->parser_ref)); + kfree(hdrfield); + + return 0; +} + +static int tcf_hdrfield_put(struct net *net, struct p4tc_template_common *tmpl, + bool unconditional_purge, + struct netlink_ext_ack *extack) +{ + struct p4tc_hdrfield *hdrfield; + struct p4tc_pipeline *pipeline; + struct p4tc_parser *parser; + + pipeline = tcf_pipeline_find_byid(net, tmpl->p_id); + + hdrfield = to_hdrfield(tmpl); + parser = pipeline->parser; + + return _tcf_hdrfield_put(pipeline, parser, hdrfield, + unconditional_purge, extack); +} + +static struct p4tc_hdrfield *hdrfield_find_name(struct p4tc_parser *parser, + const char *hdrfield_name) +{ + struct p4tc_hdrfield *hdrfield; + unsigned long tmp, id; + + idr_for_each_entry_ul(&parser->hdr_fields_idr, hdrfield, tmp, id) + if (hdrfield->common.name[0] && + strncmp(hdrfield->common.name, hdrfield_name, + HDRFIELDNAMSIZ) == 0) + return hdrfield; + + return NULL; +} + +struct p4tc_hdrfield *tcf_hdrfield_find_byid(struct p4tc_parser *parser, + const u32 hdrfield_id) +{ + return idr_find(&parser->hdr_fields_idr, hdrfield_id); +} + +struct p4tc_hdrfield *tcf_hdrfield_find_byany(struct p4tc_parser *parser, + const char *hdrfield_name, + u32 hdrfield_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_hdrfield *hdrfield; + int err; + + if (hdrfield_id) { + hdrfield = tcf_hdrfield_find_byid(parser, hdrfield_id); + if (!hdrfield) { + NL_SET_ERR_MSG(extack, "Unable to find hdrfield by id"); + err = -EINVAL; + goto out; + } + } else { + if (hdrfield_name) { + hdrfield = hdrfield_find_name(parser, hdrfield_name); + if (!hdrfield) { + NL_SET_ERR_MSG(extack, + "Header field name not found"); + err = -EINVAL; + goto out; + } + } else { + NL_SET_ERR_MSG(extack, + "Must specify hdrfield name or id"); + err = -EINVAL; + goto out; + } + } + + return hdrfield; + +out: + return ERR_PTR(err); +} + +struct p4tc_hdrfield *tcf_hdrfield_get(struct p4tc_parser *parser, + const char *hdrfield_name, + u32 hdrfield_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_hdrfield *hdrfield; + + hdrfield = tcf_hdrfield_find_byany(parser, hdrfield_name, hdrfield_id, + extack); + if (IS_ERR(hdrfield)) + return hdrfield; + + /* Should never happen */ + WARN_ON(!refcount_inc_not_zero(&hdrfield->hdrfield_ref)); + + return hdrfield; +} + +void tcf_hdrfield_put_ref(struct p4tc_hdrfield *hdrfield) +{ + WARN_ON(!refcount_dec_not_one(&hdrfield->hdrfield_ref)); +} + +static struct p4tc_hdrfield * +tcf_hdrfield_find_byanyattr(struct p4tc_parser *parser, + struct nlattr *name_attr, u32 hdrfield_id, + struct netlink_ext_ack *extack) +{ + char *hdrfield_name = NULL; + + if (name_attr) + hdrfield_name = nla_data(name_attr); + + return tcf_hdrfield_find_byany(parser, hdrfield_name, hdrfield_id, + extack); +} + +void *tcf_hdrfield_fetch(struct sk_buff *skb, struct p4tc_hdrfield *hdrfield) +{ + size_t hdr_offset_len = sizeof(u16); + struct p4tc_percpu_scratchpad *pad; + u16 *hdr_offset_bits, hdr_offset; + u16 hdr_offset_index; + + pad = this_cpu_ptr(&p4tc_percpu_scratchpad); + + hdr_offset_index = (hdrfield->hdrfield_id - 1) * hdr_offset_len; + if (hdrfield->flags & P4TC_HDRFIELD_IS_VALIDITY_BIT) + return &pad->hdrs[hdr_offset_index]; + + hdr_offset_bits = (u16 *)&pad->hdrs[hdr_offset_index]; + hdr_offset = BITS_TO_BYTES(*hdr_offset_bits); + + return skb_mac_header(skb) + hdr_offset; +} + +static struct p4tc_hdrfield *tcf_hdrfield_create(struct nlmsghdr *n, + struct nlattr *nla, + struct p4tc_pipeline *pipeline, + u32 *ids, + struct netlink_ext_ack *extack) +{ + u32 parser_id = ids[P4TC_PARSEID_IDX]; + char *hdrfield_name = NULL; + const char *parser_name = NULL; + u32 hdrfield_id = 0; + struct nlattr *tb[P4TC_HDRFIELD_MAX + 1]; + struct p4tc_hdrfield_ty *hdr_arg; + struct p4tc_hdrfield *hdrfield; + struct p4tc_parser *parser; + char *s; + int ret; + + ret = nla_parse_nested(tb, P4TC_HDRFIELD_MAX, nla, tc_hdrfield_policy, + extack); + if (ret < 0) + return ERR_PTR(ret); + + hdrfield_id = ids[P4TC_HDRFIELDID_IDX]; + if (!hdrfield_id) { + NL_SET_ERR_MSG(extack, "Must specify header field id"); + return ERR_PTR(-EINVAL); + } + + if (NL_REQ_ATTR_CHECK(extack, nla, tb, P4TC_HDRFIELD_DATA)) { + NL_SET_ERR_MSG(extack, "Must supply header field data"); + return ERR_PTR(-EINVAL); + } + hdr_arg = nla_data(tb[P4TC_HDRFIELD_DATA]); + + if (tb[P4TC_HDRFIELD_PARSER_NAME]) + parser_name = nla_data(tb[P4TC_HDRFIELD_PARSER_NAME]); + + rcu_read_lock(); + parser = tcf_parser_find_byany(pipeline, parser_name, parser_id, NULL); + if (IS_ERR(parser)) { + rcu_read_unlock(); + if (!parser_name) { + NL_SET_ERR_MSG(extack, "Must supply parser name"); + return ERR_PTR(-EINVAL); + } + + /* If the parser instance wasn't created, let's create it here */ + parser = tcf_parser_create(pipeline, parser_name, parser_id, + extack); + + if (IS_ERR(parser)) + return (void *)parser; + rcu_read_lock(); + } + + if (!refcount_inc_not_zero(&parser->parser_ref)) { + NL_SET_ERR_MSG(extack, "Parser is stale"); + rcu_read_unlock(); + return ERR_PTR(-EBUSY); + } + rcu_read_unlock(); + + if (tb[P4TC_HDRFIELD_NAME]) + hdrfield_name = nla_data(tb[P4TC_HDRFIELD_NAME]); + + if ((hdrfield_name && hdrfield_find_name(parser, hdrfield_name)) || + tcf_hdrfield_find_byid(parser, hdrfield_id)) { + NL_SET_ERR_MSG(extack, + "Header field with same id or name was already inserted"); + ret = -EEXIST; + goto refcount_dec_parser; + } + + if (hdr_arg->startbit > hdr_arg->endbit) { + NL_SET_ERR_MSG(extack, "Header field startbit > endbit"); + ret = -EINVAL; + goto refcount_dec_parser; + } + + hdrfield = kzalloc(sizeof(*hdrfield), GFP_KERNEL); + if (!hdrfield) { + NL_SET_ERR_MSG(extack, "Failed to allocate hdrfield"); + ret = -ENOMEM; + goto refcount_dec_parser; + } + + hdrfield->hdrfield_id = hdrfield_id; + + s = strnchr(hdrfield_name, HDRFIELDNAMSIZ, '/'); + if (s++ && strncmp(s, "isValid", HDRFIELDNAMSIZ) == 0) { + if (hdr_arg->datatype != P4T_U8 || hdr_arg->startbit != 0 || + hdr_arg->endbit != 0) { + NL_SET_ERR_MSG(extack, + "isValid data type must be bit1"); + ret = -EINVAL; + goto free_hdr; + } + hdrfield->datatype = hdr_arg->datatype; + hdrfield->flags = P4TC_HDRFIELD_IS_VALIDITY_BIT; + } else { + if (!p4type_find_byid(hdr_arg->datatype)) { + NL_SET_ERR_MSG(extack, "Invalid hdrfield data type"); + ret = -EINVAL; + goto free_hdr; + } + hdrfield->datatype = hdr_arg->datatype; + } + + hdrfield->startbit = hdr_arg->startbit; + hdrfield->endbit = hdr_arg->endbit; + hdrfield->parser_inst_id = parser->parser_inst_id; + + ret = idr_alloc_u32(&parser->hdr_fields_idr, hdrfield, &hdrfield_id, + hdrfield_id, GFP_KERNEL); + if (ret < 0) { + NL_SET_ERR_MSG(extack, "Unable to allocate ID for hdrfield"); + goto free_hdr; + } + + hdrfield->common.p_id = pipeline->common.p_id; + hdrfield->common.ops = (struct p4tc_template_ops *)&p4tc_hdrfield_ops; + hdrfield->parser = parser; + refcount_set(&hdrfield->hdrfield_ref, 1); + + if (hdrfield_name) + strscpy(hdrfield->common.name, hdrfield_name, HDRFIELDNAMSIZ); + + return hdrfield; + +free_hdr: + kfree(hdrfield); + +refcount_dec_parser: + WARN_ON(!refcount_dec_not_one(&parser->parser_ref)); + return ERR_PTR(ret); +} + +static struct p4tc_template_common * +tcf_hdrfield_cu(struct net *net, struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + u32 pipeid = ids[P4TC_PID_IDX]; + struct p4tc_hdrfield *hdrfield; + struct p4tc_pipeline *pipeline; + + if (n->nlmsg_flags & NLM_F_REPLACE) { + NL_SET_ERR_MSG(extack, "Header field update not supported"); + return ERR_PTR(-EOPNOTSUPP); + } + + pipeline = tcf_pipeline_find_byany_unsealed(net, nl_pname->data, pipeid, + extack); + if (IS_ERR(pipeline)) + return (void *)pipeline; + + hdrfield = tcf_hdrfield_create(n, nla, pipeline, ids, extack); + if (IS_ERR(hdrfield)) + goto out; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + +out: + return (struct p4tc_template_common *)hdrfield; +} + +static int _tcf_hdrfield_fill_nlmsg(struct sk_buff *skb, + struct p4tc_hdrfield *hdrfield) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_hdrfield_ty hdr_arg; + struct nlattr *nest; + /* Parser instance id + header field id */ + u32 ids[2]; + + ids[0] = hdrfield->parser_inst_id; + ids[1] = hdrfield->hdrfield_id; + + if (nla_put(skb, P4TC_PATH, sizeof(ids), ids)) + goto out_nlmsg_trim; + + nest = nla_nest_start(skb, P4TC_PARAMS); + if (!nest) + goto out_nlmsg_trim; + + hdr_arg.datatype = hdrfield->datatype; + hdr_arg.startbit = hdrfield->startbit; + hdr_arg.endbit = hdrfield->endbit; + + if (hdrfield->common.name[0]) { + if (nla_put_string(skb, P4TC_HDRFIELD_NAME, + hdrfield->common.name)) + goto out_nlmsg_trim; + } + + if (nla_put(skb, P4TC_HDRFIELD_DATA, sizeof(hdr_arg), &hdr_arg)) + goto out_nlmsg_trim; + + nla_nest_end(skb, nest); + + return skb->len; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -1; +} + +static int tcf_hdrfield_fill_nlmsg(struct net *net, struct sk_buff *skb, + struct p4tc_template_common *template, + struct netlink_ext_ack *extack) +{ + struct p4tc_hdrfield *hdrfield = to_hdrfield(template); + + if (_tcf_hdrfield_fill_nlmsg(skb, hdrfield) <= 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for pipeline"); + return -EINVAL; + } + + return 0; +} + +static int tcf_hdrfield_flush(struct sk_buff *skb, + struct p4tc_pipeline *pipeline, + struct p4tc_parser *parser, + struct netlink_ext_ack *extack) +{ + unsigned char *b = nlmsg_get_pos(skb); + int ret = 0; + int i = 0; + struct p4tc_hdrfield *hdrfield; + u32 path[2]; + unsigned long tmp, hdrfield_id; + + path[0] = parser->parser_inst_id; + path[1] = 0; + + if (nla_put(skb, P4TC_PATH, sizeof(path), path)) + goto out_nlmsg_trim; + + if (idr_is_empty(&parser->hdr_fields_idr)) { + NL_SET_ERR_MSG(extack, "There are no header fields to flush"); + goto out_nlmsg_trim; + } + + idr_for_each_entry_ul(&parser->hdr_fields_idr, hdrfield, tmp, hdrfield_id) { + if (_tcf_hdrfield_put(pipeline, parser, hdrfield, false, extack) < 0) { + ret = -EBUSY; + continue; + } + i++; + } + + nla_put_u32(skb, P4TC_COUNT, i); + + if (ret < 0) { + if (i == 0) { + NL_SET_ERR_MSG(extack, + "Unable to flush any table instance"); + goto out_nlmsg_trim; + } else { + NL_SET_ERR_MSG(extack, + "Unable to flush all table instances"); + } + } + + return i; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return 0; +} + +static int tcf_hdrfield_gd(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + unsigned char *b = nlmsg_get_pos(skb); + u32 pipeid = ids[P4TC_PID_IDX]; + u32 parser_inst_id = ids[P4TC_PARSEID_IDX]; + u32 hdrfield_id = ids[P4TC_HDRFIELDID_IDX]; + struct nlattr *tb[P4TC_HDRFIELD_MAX + 1]; + struct p4tc_hdrfield *hdrfield; + struct p4tc_pipeline *pipeline; + struct p4tc_parser *parser; + char *parser_name; + int ret; + + pipeline = tcf_pipeline_find_byany(net, nl_pname->data, pipeid, extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + + ret = nla_parse_nested(tb, P4TC_HDRFIELD_MAX, nla, tc_hdrfield_policy, + extack); + if (ret < 0) + return ret; + + parser_name = tb[P4TC_HDRFIELD_PARSER_NAME] ? + nla_data(tb[P4TC_HDRFIELD_PARSER_NAME]) : NULL; + + parser = tcf_parser_find_byany(pipeline, parser_name, parser_inst_id, + extack); + if (IS_ERR(parser)) + return PTR_ERR(parser); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (n->nlmsg_type == RTM_DELP4TEMPLATE && n->nlmsg_flags & NLM_F_ROOT) + return tcf_hdrfield_flush(skb, pipeline, parser, extack); + + hdrfield = tcf_hdrfield_find_byanyattr(parser, tb[P4TC_HDRFIELD_NAME], + hdrfield_id, extack); + if (IS_ERR(hdrfield)) + return PTR_ERR(hdrfield); + + ret = _tcf_hdrfield_fill_nlmsg(skb, hdrfield); + if (ret < 0) + return -ENOMEM; + + if (n->nlmsg_type == RTM_DELP4TEMPLATE) { + ret = _tcf_hdrfield_put(pipeline, parser, hdrfield, false, + extack); + if (ret < 0) + goto out_nlmsg_trim; + } + + return 0; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_hdrfield_dump_1(struct sk_buff *skb, + struct p4tc_template_common *common) +{ + struct p4tc_hdrfield *hdrfield = to_hdrfield(common); + struct nlattr *param = nla_nest_start(skb, P4TC_PARAMS); + unsigned char *b = nlmsg_get_pos(skb); + u32 path[2]; + + if (!param) + goto out_nlmsg_trim; + + if (hdrfield->common.name[0] && + nla_put_string(skb, P4TC_HDRFIELD_NAME, hdrfield->common.name)) + goto out_nlmsg_trim; + + nla_nest_end(skb, param); + + path[0] = hdrfield->parser_inst_id; + path[1] = hdrfield->hdrfield_id; + if (nla_put(skb, P4TC_PATH, sizeof(path), path)) + goto out_nlmsg_trim; + + return 0; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -ENOMEM; +} + +static int tcf_hdrfield_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, + struct nlattr *nla, char **p_name, u32 *ids, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_HDRFIELD_MAX + 1] = { NULL }; + const u32 pipeid = ids[P4TC_PID_IDX]; + struct net *net = sock_net(skb->sk); + struct p4tc_pipeline *pipeline; + struct p4tc_parser *parser; + int ret; + + if (!ctx->ids[P4TC_PID_IDX]) { + pipeline = + tcf_pipeline_find_byany(net, *p_name, pipeid, extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + ctx->ids[P4TC_PID_IDX] = pipeline->common.p_id; + } else { + pipeline = tcf_pipeline_find_byid(net, ctx->ids[P4TC_PID_IDX]); + } + + if (!ctx->ids[P4TC_PARSEID_IDX]) { + if (nla) { + ret = nla_parse_nested(tb, P4TC_HDRFIELD_MAX, nla, + tc_hdrfield_policy, extack); + if (ret < 0) + return ret; + } + + parser = tcf_parser_find_byany(pipeline, + nla_data(tb[P4TC_HDRFIELD_PARSER_NAME]), + ids[P4TC_PARSEID_IDX], extack); + if (IS_ERR(parser)) + return PTR_ERR(parser); + + ctx->ids[P4TC_PARSEID_IDX] = parser->parser_inst_id; + } else { + parser = pipeline->parser; + } + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!(*p_name)) + *p_name = pipeline->common.name; + + return tcf_p4_tmpl_generic_dump(skb, ctx, &parser->hdr_fields_idr, + P4TC_HDRFIELDID_IDX, extack); +} + +const struct p4tc_template_ops p4tc_hdrfield_ops = { + .init = NULL, + .cu = tcf_hdrfield_cu, + .fill_nlmsg = tcf_hdrfield_fill_nlmsg, + .gd = tcf_hdrfield_gd, + .put = tcf_hdrfield_put, + .dump = tcf_hdrfield_dump, + .dump_1 = tcf_hdrfield_dump_1, +}; diff --git a/net/sched/p4tc/p4tc_parser_api.c b/net/sched/p4tc/p4tc_parser_api.c new file mode 100644 index 000000000000..4af715f86aad --- /dev/null +++ b/net/sched/p4tc/p4tc_parser_api.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_parser_api.c P4 TC PARSER API + * + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct p4tc_parser *parser_find_name(struct p4tc_pipeline *pipeline, + const char *parser_name) +{ + if (unlikely(!pipeline->parser)) + return NULL; + + if (!strncmp(pipeline->parser->parser_name, parser_name, PARSERNAMSIZ)) + return pipeline->parser; + + return NULL; +} + +struct p4tc_parser *tcf_parser_find_byid(struct p4tc_pipeline *pipeline, + const u32 parser_inst_id) +{ + if (unlikely(!pipeline->parser)) + return NULL; + + if (parser_inst_id == pipeline->parser->parser_inst_id) + return pipeline->parser; + + return NULL; +} + +static struct p4tc_parser *__parser_find(struct p4tc_pipeline *pipeline, + const char *parser_name, + u32 parser_inst_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_parser *parser; + int err; + + if (parser_inst_id) { + parser = tcf_parser_find_byid(pipeline, parser_inst_id); + if (!parser) { + if (extack) + NL_SET_ERR_MSG(extack, + "Unable to find parser by id"); + err = -EINVAL; + goto out; + } + } else { + if (parser_name) { + parser = parser_find_name(pipeline, parser_name); + if (!parser) { + if (extack) + NL_SET_ERR_MSG(extack, + "Parser name not found"); + err = -EINVAL; + goto out; + } + } else { + if (extack) + NL_SET_ERR_MSG(extack, + "Must specify parser name or id"); + err = -EINVAL; + goto out; + } + } + + return parser; + +out: + return ERR_PTR(err); +} + +struct p4tc_parser *tcf_parser_find_byany(struct p4tc_pipeline *pipeline, + const char *parser_name, + u32 parser_inst_id, + struct netlink_ext_ack *extack) +{ + return __parser_find(pipeline, parser_name, parser_inst_id, extack); +} + +struct p4tc_parser * +tcf_parser_create(struct p4tc_pipeline *pipeline, const char *parser_name, + u32 parser_inst_id, struct netlink_ext_ack *extack) +{ + struct p4tc_parser *parser; + + if (pipeline->parser) { + NL_SET_ERR_MSG(extack, + "Can only have one parser instance per pipeline"); + return ERR_PTR(-EEXIST); + } + + parser = kzalloc(sizeof(*parser), GFP_KERNEL); + if (!parser) + return ERR_PTR(-ENOMEM); + + if (parser_inst_id) + parser->parser_inst_id = parser_inst_id; + else + parser->parser_inst_id = 1; + + strscpy(parser->parser_name, parser_name, PARSERNAMSIZ); + + refcount_set(&parser->parser_ref, 1); + + idr_init(&parser->hdr_fields_idr); + + pipeline->parser = parser; + + return parser; +} + +int tcf_parser_del(struct net *net, struct p4tc_pipeline *pipeline, + struct p4tc_parser *parser, struct netlink_ext_ack *extack) +{ + struct p4tc_hdrfield *hdrfield; + unsigned long hdr_field_id, tmp; + + idr_for_each_entry_ul(&parser->hdr_fields_idr, hdrfield, tmp, hdr_field_id) + hdrfield->common.ops->put(net, &hdrfield->common, true, extack); + + idr_destroy(&parser->hdr_fields_idr); + + pipeline->parser = NULL; + + kfree(parser); + + return 0; +} diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c index 56b4f7be8d17..ed924059cb6a 100644 --- a/net/sched/p4tc/p4tc_pipeline.c +++ b/net/sched/p4tc/p4tc_pipeline.c @@ -115,6 +115,8 @@ static int tcf_pipeline_put(struct net *net, } idr_remove(&pipe_net->pipeline_idr, pipeline->common.p_id); + if (pipeline->parser) + tcf_parser_del(net, pipeline, pipeline->parser, extack); idr_for_each_entry_ul(&pipeline->p_meta_idr, meta, tmp, m_id) meta->common.ops->put(net, &meta->common, true, extack); @@ -319,6 +321,8 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, pipeline->num_postacts = 0; } + pipeline->parser = NULL; + idr_init(&pipeline->p_meta_idr); pipeline->p_meta_offset = 0; diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c index 19dd6f41a3a4..7a3f5c0c3af1 100644 --- a/net/sched/p4tc/p4tc_tmpl_api.c +++ b/net/sched/p4tc/p4tc_tmpl_api.c @@ -43,6 +43,7 @@ static bool obj_is_valid(u32 obj) switch (obj) { case P4TC_OBJ_PIPELINE: case P4TC_OBJ_META: + case P4TC_OBJ_HDR_FIELD: return true; default: return false; @@ -52,6 +53,7 @@ static bool obj_is_valid(u32 obj) static const struct p4tc_template_ops *p4tc_ops[P4TC_OBJ_MAX] = { [P4TC_OBJ_PIPELINE] = &p4tc_pipeline_ops, [P4TC_OBJ_META] = &p4tc_meta_ops, + [P4TC_OBJ_HDR_FIELD] = &p4tc_hdrfield_ops, }; int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, From patchwork Wed May 17 11:02:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244696 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 26D15171BC for ; Wed, 17 May 2023 11:04:44 +0000 (UTC) Received: from mail-qv1-xf2b.google.com (mail-qv1-xf2b.google.com [IPv6:2607:f8b0:4864:20::f2b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C663910D8 for ; Wed, 17 May 2023 04:04:16 -0700 (PDT) Received: by mail-qv1-xf2b.google.com with SMTP id 6a1803df08f44-6238417112aso2638106d6.2 for ; Wed, 17 May 2023 04:04:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321445; x=1686913445; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=uozZ7wnqOWXy8C0w/gU5k36K6Xw5xGL8KRXHjOefN9A=; b=qDcWxviezN3N41vKMFtha5rcO+NPc44EIyA839EZuLGbrTQ+EqIMIk5EDzZtvFLRlY 8nMas7JoYh3tsb9pIPb0Q9hHr6IGmO9XiFwHcdGLDV+nNerUE7wXHgzldGVLpagCMVbd eAf4ZjuaGlzG+sFqLkcjOz4+U/p0FuGN5sLpAEED/lLQZ5MZdfnQITHsfvyOxmxqJ2WL R9FBL0YoMwjXXV5up051RIrQOvCelJCDzZuoNlLl5uXi/p4QXoSAjQRezdQHv6dVykYy LE4aLDFlxCY5zBnUAfLRjvwlvLxgk/zw9W0zdydK/iyxbIiV1b2pQIkeM1YbR1f0Zl5v zfkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321445; x=1686913445; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=uozZ7wnqOWXy8C0w/gU5k36K6Xw5xGL8KRXHjOefN9A=; b=Tz11NL/zMQZeA5UiLOXIuUBhDn1jYibJUhFn4ituZ4ta/8mVEM/2RmB3IUS0EULBEy gdY7Q/OXK+6p7sDdrcO9wKxoMdmRpQmDCnpVsvNAggGrskeTCxgmLscbhMgEV/qLw9Z6 wkYYMNHrQn3i3CtmCm6ecFBeJHnV3ps/mABDz+3I6qIi5BtIEBuoxlkOerjcsz0J5zo4 pPUQRpmt8bW2Hs07GIW5iilTwvYFz3NM8gLJNrSnAg4GDGleA/agBT/6+Lf2eZGOdTEg qPOaEElapwfAeSiqWnirnh1ZeWEIrZeXY/21GJ2eFSnxrS1Gdgw3AdWK6RQqNGFPUo36 iPFA== X-Gm-Message-State: AC+VfDwY1bbjbGutdaVg21Z5GxhBm0AlJ1lhU/F1H9P4ipPo5IusKpGL kquSoJfujinXRO82CR92NQbbHofPlTMZFcc95QQ= X-Google-Smtp-Source: ACHHUZ61wUWhSC8ihhVg1lXAh1rb6qZ8Z+Dy6q4xkA/gL8vgW/K0HQ0LlLoTBW6ENpWBILYtlwcWkw== X-Received: by 2002:a05:6214:20e2:b0:61a:281b:9a5d with SMTP id 2-20020a05621420e200b0061a281b9a5dmr56918964qvk.5.1684321444253; Wed, 17 May 2023 04:04:04 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id j7-20020a0ce007000000b0062168714c8fsm4314441qvk.120.2023.05.17.04.04.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:04:03 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 13/28] p4tc: add action template create, update, delete, get, flush and dump Date: Wed, 17 May 2023 07:02:17 -0400 Message-Id: <20230517110232.29349-13-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This commit allows users to create, update, delete, get, flush and dump dynamic actions based on P4 action definition. At the moment dynamic actions are tied to P4 programs only and cannot be used outside of a P4 program definition. Visualize the following action in a P4 program: action ipv4_forward(bit<48> dstAddr, bit<8> port) { standard_metadata.egress_spec = port; hdr.ethernet.srcAddr = hdr.ethernet.dstAddr; hdr.ethernet.dstAddr = dstAddr; hdr.ipv4.ttl = hdr.ipv4.ttl - 1; } which is invoked on a P4 table match as such: table mytable { key = { hdr.ipv4.dstAddr: lpm; } actions = { ipv4_forward; drop; NoAction; } size = 1024; } We don't have an equivalent built in "ipv4_forward" action in TC. So we create this action dynamically. The mechanics of dynamic actions follow the CRUD semantics. ___DYNAMIC CREATION___ In this stage we issue the creation command for the dynamic action which specifies the action name, its ID, parameters and the parameter types. So for the ipv4_forward action, the creation would look something like this: tc p4template create action/aP4proggie/ipv4_forward \ param dstAddr type macaddr id 1 param port type dev id 2 Note1: Although the P4 program defined dstAddr as type bit48 we use our type called macaddr (likewise for port) - see commit on p4 types for details. Note that in the template creation op we usually just specify the action name, the parameters and their respective types. Also see that we specify a pipeline name during the template creation command. As an example, the above command creates an action template that is bounded to pipeline/program named aP4proggie. Also, below is an example of how one would specify an ID to the action template created in the above command. When the create doesn't specify the action template ID, the kernel assigns a new one for us. Also, if the action template ID specified in the command is already in use, the kernel will reject the command. tc p4template create action/aP4proggie/ipv4_forward actid 1 \ param dstAddr type macaddr id 1 param port type dev id 2 The compiler (for example P4C) will always define the actid. Per the P4 specification, actions might be contained in a control block. ___OPS_DESCRIPTION___ In the next stage (ops description), we need to specify which operations this action uses. As example, if we were to specify the operations for the ipv4_forward action, we'd update the created action and issue the following command: tc p4template update action/aP4proggie/ipv4_forward \ cmd set metadata.aP4proggie.temp hdrfield.aP4proggie.parser1.ethernet.dstAddr \ cmd set hdrfield.P4proggie.parser1.ethernet.dstAddr hdrfield.P4proggie.parser1.ethernet.srcAddr \ cmd set hdrfield.P4proggie.parser1.ethernet.srcAddr metadata.aP4proggie.temp \ cmd set metadata.calc.egress_spec param.port \ cmd decr hdrfield.P4proggie.parser1.ipv4.ttl As you can see, we refer to the argument values in the ipv4_forward action using "param" prefix. So, for example, when referring to the argument port in a ipv4_forward, we use "param.port". Of course the two steps could be combined as so when creating the action: tc p4template create action/aP4proggie/ipv4_forward actid 1 \ param dstAddr type macaddr id 1 param port type dev id 2 \ cmd set metadata.aP4proggie.temp hdrfield.aP4proggie.parser1.ethernet.dstAddr \ cmd set hdrfield.P4proggie.parser1.ethernet.dstAddr hdrfield.P4proggie.parser1.ethernet.srcAddr \ cmd set hdrfield.P4proggie.parser1.ethernet.srcAddr metadata.aP4proggie.temp \ cmd set metadata.calc.egress_spec param.port \ cmd decr hdrfield.P4proggie.parser1.ipv4.ttl ___ACTION_ACTIVATION___ Once we provided all the necessary information for the new dynamic action, we can go to the final stage, which is action activation. In this stage, we activate the dynamic action and make it available for instantiation. To activate the action template, we issue the following command: tc p4template update action aP4proggie/ipv4_forward state active After the above the command, the action is ready to be instantiated. ___RUNTIME___ This next section deals with the runtime part of action templates, which handle action template instantiation and binding. To instantiate a new action from a template, we use the following command: tc actions add action aP4proggie/ipv4_forward \ param dstAddr AA:BB:CC:DD:EE:FF param port eth0 index 1 Observe these are the same semantics as what tc today already provides with a caveat that we have a keyword "param" to precede the appropriate parameters - as such specifying the index is optional (kernel provides one when unspecified). As previously stated, we refer to the action by it's "full name" (pipeline_name/action_name). Here we are creating an instance of the ipv4_forward action specifying as parameter values AA:BB:CC:DD:EE:FF for dstAddr and eth0 for port. We can create as many instances for action templates as we wish. To bind the above instantiated action to a table entry, you can do use the same approach used to bind ordinary actions to filter, for example: tc p4runtime create aP4proggie/table/mycontrol/mytable srcAddr 10.10.10.0/24 \ action ipv4_forward index 1 The above command will bind our newly instantiated action to a table entry which is executed if there's a match. Of course one could have created the table entry as: tc p4runtime create aP4proggie/table/mycontrol/mytable srcAddr 10.10.10.0/24 \ action ipv4_forward param dstAddr AA:BB:CC:DD:EE:FF param port eth0 Actions from other control blocks might be referenced as the action index is per pipeline. ___OTHER_CONTROL_COMMANDS___ The lifetime of the dynamic action is tied to its pipeline. As with all pipeline components, write operations to action templates, such as create, update and delete, can only be executed if the pipeline is not sealed. Read/get can be issued even after the pipeline is sealed. If, after we are done with our action template we want to delete it, we should issue the following command: tc p4template del action/aP4proggie/ipv4_forward Note that we could also not specify the action name and use the ID instead, which would transform the above command into the following: tc p4template del action/aP4proggie actid 1 If we had created more action templates and wanted to flush all of the action templates from pipeline aP4proggie, one would use the following command: tc p4template del action/aP4proggie/ After creating or updating a dynamic actions, if one wishes to verify that the dynamic action was created correctly, one would use the following command: tc p4template get action/aP4proggie/ipv4_forward As with the del operation, when can also specify the action id instead of the action name: tc p4template get action/aP4proggie actid 1 The above command will display the relevant data for the action, such as parameter names, types, etc. If one wanted to check which action templates were associated to a specific pipeline, one could use the following command: tc p4template get action/aP4proggie/ Note that this command will only display the name of these action templates. To verify their specific details, one should use the get command, which was previously described. Tested-by: "Khan, Mohd Arif" Tested-by: "Pottimurthy, Sathya Narayana" Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/act_api.h | 1 + include/net/p4tc.h | 177 +++ include/net/sch_generic.h | 5 + include/net/tc_act/p4tc.h | 27 + include/uapi/linux/p4tc.h | 46 + net/sched/p4tc/Makefile | 2 +- net/sched/p4tc/p4tc_action.c | 1840 ++++++++++++++++++++++++++++++++ net/sched/p4tc/p4tc_meta.c | 61 ++ net/sched/p4tc/p4tc_pipeline.c | 274 ++++- net/sched/p4tc/p4tc_tmpl_api.c | 2 + 10 files changed, 2409 insertions(+), 26 deletions(-) create mode 100644 include/net/tc_act/p4tc.h create mode 100644 net/sched/p4tc/p4tc_action.c diff --git a/include/net/act_api.h b/include/net/act_api.h index a0f443990f27..f631c0e2da1b 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -68,6 +68,7 @@ struct tc_action { #define TCA_ACT_FLAGS_REPLACE (1U << (TCA_ACT_FLAGS_USER_BITS + 2)) #define TCA_ACT_FLAGS_NO_RTNL (1U << (TCA_ACT_FLAGS_USER_BITS + 3)) #define TCA_ACT_FLAGS_AT_INGRESS (1U << (TCA_ACT_FLAGS_USER_BITS + 4)) +#define TCA_ACT_FLAGS_FROM_P4TC (1U << (TCA_ACT_FLAGS_USER_BITS + 5)) /* Update lastuse only if needed, to avoid dirtying a cache line. * We use a temp variable to avoid fetching jiffies twice. diff --git a/include/net/p4tc.h b/include/net/p4tc.h index 096f52c4320e..6111566b05eb 100644 --- a/include/net/p4tc.h +++ b/include/net/p4tc.h @@ -9,6 +9,8 @@ #include #include #include +#include +#include #define P4TC_DEFAULT_NUM_TABLES P4TC_MINTABLES_COUNT #define P4TC_DEFAULT_MAX_RULES 1 @@ -19,6 +21,7 @@ #define P4TC_PID_IDX 0 #define P4TC_MID_IDX 1 +#define P4TC_AID_IDX 1 #define P4TC_PARSEID_IDX 1 #define P4TC_HDRFIELDID_IDX 2 @@ -36,6 +39,7 @@ DECLARE_PER_CPU(struct p4tc_percpu_scratchpad, p4tc_percpu_scratchpad); struct p4tc_dump_ctx { u32 ids[P4TC_PATH_MAX]; + struct rhashtable_iter *iter; }; struct p4tc_template_common; @@ -92,9 +96,21 @@ struct p4tc_template_common { extern const struct p4tc_template_ops p4tc_pipeline_ops; +struct p4tc_act_dep_edge_node { + struct list_head head; + u32 act_id; +}; + +struct p4tc_act_dep_node { + struct list_head incoming_egde_list; + struct list_head head; + u32 act_id; +}; + struct p4tc_pipeline { struct p4tc_template_common common; struct idr p_meta_idr; + struct idr p_act_idr; struct rcu_head rcu; struct net *net; struct p4tc_parser *parser; @@ -102,13 +118,17 @@ struct p4tc_pipeline { int num_preacts; struct tc_action **postacts; int num_postacts; + struct list_head act_dep_graph; + struct list_head act_topological_order; u32 max_rules; u32 p_meta_offset; + u32 num_created_acts; refcount_t p_ref; refcount_t p_ctrl_ref; u16 num_tables; u16 curr_tables; u8 p_state; + refcount_t p_hdrs_used; }; struct p4tc_pipeline_net { @@ -149,6 +169,18 @@ static inline bool pipeline_sealed(struct p4tc_pipeline *pipeline) { return pipeline->p_state == P4TC_STATE_READY; } +void tcf_pipeline_add_dep_edge(struct p4tc_pipeline *pipeline, + struct p4tc_act_dep_edge_node *edge_node, + u32 vertex_id); +bool tcf_pipeline_check_act_backedge(struct p4tc_pipeline *pipeline, + struct p4tc_act_dep_edge_node *edge_node, + u32 vertex_id); +int determine_act_topological_order(struct p4tc_pipeline *pipeline, + bool copy_dep_graph); + +struct p4tc_act; +void tcf_pipeline_delete_from_dep_graph(struct p4tc_pipeline *pipeline, + struct p4tc_act *act); struct p4tc_metadata { struct p4tc_template_common common; @@ -165,6 +197,68 @@ struct p4tc_metadata { extern const struct p4tc_template_ops p4tc_meta_ops; +struct p4tc_ipv4_param_value { + u32 value; + u32 mask; +}; + +#define P4TC_ACT_PARAM_FLAGS_ISDYN BIT(0) + +struct p4tc_act_param { + char name[ACTPARAMNAMSIZ]; + struct list_head head; + struct rcu_head rcu; + void *value; + void *mask; + struct p4tc_type *type; + u32 id; + u32 index; + u8 flags; +}; + +struct p4tc_act_param_ops { + int (*init_value)(struct net *net, struct p4tc_act_param_ops *op, + struct p4tc_act_param *nparam, struct nlattr **tb, + struct netlink_ext_ack *extack); + int (*dump_value)(struct sk_buff *skb, struct p4tc_act_param_ops *op, + struct p4tc_act_param *param); + void (*free)(struct p4tc_act_param *param); + u32 len; + u32 alloc_len; +}; + +struct p4tc_label_key { + char *label; + u32 labelsz; +}; + +struct p4tc_label_node { + struct rhash_head ht_node; + struct p4tc_label_key key; + int cmd_offset; +}; + +struct p4tc_act { + struct p4tc_template_common common; + struct tc_action_ops ops; + struct rhashtable *labels; + struct list_head cmd_operations; + struct tc_action_net *tn; + struct p4tc_pipeline *pipeline; + struct idr params_idr; + struct tcf_exts exts; + struct list_head head; + u32 a_id; + u32 num_params; + bool active; + refcount_t a_ref; +}; + +extern const struct p4tc_template_ops p4tc_act_ops; +extern const struct rhashtable_params p4tc_label_ht_params; +extern const struct rhashtable_params acts_params; +void p4tc_label_ht_destroy(void *ptr, void *arg); + struct p4tc_parser { char parser_name[PARSERNAMSIZ]; struct idr hdr_fields_idr; @@ -194,6 +288,69 @@ struct p4tc_metadata *tcf_meta_get(struct p4tc_pipeline *pipeline, const char *mname, const u32 m_id, struct netlink_ext_ack *extack); void tcf_meta_put_ref(struct p4tc_metadata *meta); +void *tcf_meta_fetch(struct sk_buff *skb, struct p4tc_metadata *meta); + +static inline int p4tc_action_init(struct net *net, struct nlattr *nla, + struct tc_action *acts[], u32 pipeid, + u32 flags, struct netlink_ext_ack *extack) +{ + int init_res[TCA_ACT_MAX_PRIO]; + size_t attrs_size; + int ret; + int i; + + /* If action was already created, just bind to existing one*/ + flags |= TCA_ACT_FLAGS_BIND; + flags |= TCA_ACT_FLAGS_FROM_P4TC; + ret = tcf_action_init(net, NULL, nla, NULL, acts, init_res, &attrs_size, + flags, 0, extack); + + /* Check if we are trying to bind to dynamic action from different pipe */ + for (i = 0; i < TCA_ACT_MAX_PRIO && acts[i]; i++) { + struct tc_action *a = acts[i]; + struct tcf_p4act *p; + + if (a->ops->id < TCA_ID_DYN) + continue; + + p = to_p4act(a); + if (p->p_id != pipeid) { + NL_SET_ERR_MSG(extack, + "Unable to bind to dynact from different pipeline"); + ret = -EPERM; + goto destroy_acts; + } + } + + return ret; + +destroy_acts: + tcf_action_destroy(acts, TCA_ACT_FLAGS_BIND); + return ret; +} + +struct p4tc_act *tcf_action_find_byid(struct p4tc_pipeline *pipeline, + const u32 a_id); +struct p4tc_act *tcf_action_find_byname(const char *act_name, + struct p4tc_pipeline *pipeline); +struct p4tc_act *tcf_action_find_byany(struct p4tc_pipeline *pipeline, + const char *act_name, const u32 a_id, + struct netlink_ext_ack *extack); +struct p4tc_act *tcf_action_get(struct p4tc_pipeline *pipeline, + const char *act_name, const u32 a_id, + struct netlink_ext_ack *extack); +void tcf_action_put(struct p4tc_act *act); +int tcf_p4_dyna_template_init(struct net *net, struct tc_action **a, + struct p4tc_act *act, + struct list_head *params_list, + struct tc_act_dyna *parm, u32 flags, + struct netlink_ext_ack *extack); +struct p4tc_act_param *tcf_param_find_byid(struct idr *params_idr, + const u32 param_id); +struct p4tc_act_param *tcf_param_find_byany(struct p4tc_act *act, + const char *param_name, + const u32 param_id, + struct netlink_ext_ack *extack); struct p4tc_parser *tcf_parser_create(struct p4tc_pipeline *pipeline, const char *parser_name, @@ -222,8 +379,28 @@ struct p4tc_hdrfield *tcf_hdrfield_get(struct p4tc_parser *parser, struct netlink_ext_ack *extack); void tcf_hdrfield_put_ref(struct p4tc_hdrfield *hdrfield); +int p4tc_init_net_ops(struct net *net, unsigned int id); +void p4tc_exit_net_ops(struct list_head *net_list, unsigned int id); +int tcf_p4_act_init_params(struct net *net, struct tcf_p4act_params *params, + struct p4tc_act *act, struct nlattr *nla, + struct netlink_ext_ack *extack); +void tcf_p4_act_params_destroy(struct tcf_p4act_params *params); +int p4_act_init(struct p4tc_act *act, struct nlattr *nla, + struct p4tc_act_param *params[], + struct netlink_ext_ack *extack); +void p4_put_many_params(struct idr *params_idr, struct p4tc_act_param *params[], + int params_count); +void tcf_p4_act_params_destroy_rcu(struct rcu_head *head); +int p4_act_init_params(struct p4tc_act *act, struct nlattr *nla, + struct p4tc_act_param *params[], bool update, + struct netlink_ext_ack *extack); +extern const struct p4tc_act_param_ops param_ops[P4T_MAX + 1]; +int generic_dump_param_value(struct sk_buff *skb, struct p4tc_type *type, + struct p4tc_act_param *param); + #define to_pipeline(t) ((struct p4tc_pipeline *)t) #define to_meta(t) ((struct p4tc_metadata *)t) #define to_hdrfield(t) ((struct p4tc_hdrfield *)t) +#define to_act(t) ((struct p4tc_act *)t) #endif diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index fab5ba3e61b7..1b3b12b1ba59 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -326,6 +326,11 @@ struct tcf_result { }; const struct tcf_proto *goto_tp; + struct { + bool hit; + bool miss; + int action_run_id; + }; }; }; diff --git a/include/net/tc_act/p4tc.h b/include/net/tc_act/p4tc.h new file mode 100644 index 000000000000..8526559c74dc --- /dev/null +++ b/include/net/tc_act/p4tc.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NET_TC_ACT_P4_H +#define __NET_TC_ACT_P4_H + +#include +#include + +struct tcf_p4act_params { + struct tcf_exts exts; + struct idr params_idr; + struct p4tc_act_param **params_array; + struct rcu_head rcu; + u32 num_params; +}; + +struct tcf_p4act { + struct tc_action common; + /* list of operations */ + struct list_head cmd_operations; + /* Params IDR reference passed during runtime */ + struct tcf_p4act_params __rcu *params; + u32 p_id; + u32 act_id; +}; +#define to_p4act(a) ((struct tcf_p4act *)a) + +#endif /* __NET_TC_ACT_P4_H */ diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h index 72714df9e74f..15876c471266 100644 --- a/include/uapi/linux/p4tc.h +++ b/include/uapi/linux/p4tc.h @@ -4,6 +4,7 @@ #include #include +#include /* pipeline header */ struct p4tcmsg { @@ -29,6 +30,9 @@ struct p4tcmsg { #define METANAMSIZ TEMPLATENAMSZ #define PARSERNAMSIZ TEMPLATENAMSZ #define HDRFIELDNAMSIZ TEMPLATENAMSZ +#define ACTPARAMNAMSIZ TEMPLATENAMSZ + +#define LABELNAMSIZ 32 /* Root attributes */ enum { @@ -58,6 +62,7 @@ enum { P4TC_OBJ_PIPELINE, P4TC_OBJ_META, P4TC_OBJ_HDR_FIELD, + P4TC_OBJ_ACT, __P4TC_OBJ_MAX, }; #define P4TC_OBJ_MAX __P4TC_OBJ_MAX @@ -172,6 +177,47 @@ enum { }; #define P4TC_HDRFIELD_MAX (__P4TC_HDRFIELD_MAX - 1) +/* Action attributes */ +enum { + P4TC_ACT_UNSPEC, + P4TC_ACT_NAME, /* string */ + P4TC_ACT_PARMS, /* nested params */ + P4TC_ACT_OPT, /* action opt */ + P4TC_ACT_TM, /* action tm */ + P4TC_ACT_CMDS_LIST, /* command list */ + P4TC_ACT_ACTIVE, /* u8 */ + P4TC_ACT_PAD, + __P4TC_ACT_MAX +}; +#define P4TC_ACT_MAX __P4TC_ACT_MAX + +#define P4TC_CMDS_LIST_MAX 32 + +/* Action params attributes */ +enum { + P4TC_ACT_PARAMS_VALUE_UNSPEC, + P4TC_ACT_PARAMS_VALUE_RAW, /* binary */ + P4TC_ACT_PARAMS_VALUE_OPND, /* struct p4tc_u_operand */ + __P4TC_ACT_PARAMS_VALUE_MAX +}; +#define P4TC_ACT_VALUE_PARAMS_MAX __P4TC_ACT_PARAMS_VALUE_MAX + +/* Action params attributes */ +enum { + P4TC_ACT_PARAMS_UNSPEC, + P4TC_ACT_PARAMS_NAME, /* string */ + P4TC_ACT_PARAMS_ID, /* u32 */ + P4TC_ACT_PARAMS_VALUE, /* bytes */ + P4TC_ACT_PARAMS_MASK, /* bytes */ + P4TC_ACT_PARAMS_TYPE, /* u32 */ + __P4TC_ACT_PARAMS_MAX +}; +#define P4TC_ACT_PARAMS_MAX __P4TC_ACT_PARAMS_MAX + +struct tc_act_dyna { + tc_gen; +}; + #define P4TC_RTA(r) \ ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct p4tcmsg)))) diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index add22c909be6..3f7267366827 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.o p4tc_meta.o \ - p4tc_parser_api.o p4tc_hdrfield.o + p4tc_parser_api.o p4tc_hdrfield.o p4tc_action.o diff --git a/net/sched/p4tc/p4tc_action.c b/net/sched/p4tc/p4tc_action.c new file mode 100644 index 000000000000..617aed297a58 --- /dev/null +++ b/net/sched/p4tc/p4tc_action.c @@ -0,0 +1,1840 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_action.c P4 TC ACTION TEMPLATES + * + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static LIST_HEAD(dynact_list); + +#define SEPARATOR "/" + +static u32 label_hash_fn(const void *data, u32 len, u32 seed) +{ + const struct p4tc_label_key *key = data; + + return jhash(key->label, key->labelsz, seed); +} + +static int label_hash_cmp(struct rhashtable_compare_arg *arg, const void *ptr) +{ + const struct p4tc_label_key *label_arg = arg->key; + const struct p4tc_label_node *node = ptr; + + return strncmp(label_arg->label, node->key.label, node->key.labelsz); +} + +static u32 label_obj_hash_fn(const void *data, u32 len, u32 seed) +{ + const struct p4tc_label_node *node = data; + + return label_hash_fn(&node->key, 0, seed); +} + +void p4tc_label_ht_destroy(void *ptr, void *arg) +{ + struct p4tc_label_node *node = ptr; + + kfree(node->key.label); + kfree(node); +} + +const struct rhashtable_params p4tc_label_ht_params = { + .obj_cmpfn = label_hash_cmp, + .obj_hashfn = label_obj_hash_fn, + .hashfn = label_hash_fn, + .head_offset = offsetof(struct p4tc_label_node, ht_node), + .key_offset = offsetof(struct p4tc_label_node, key), + .automatic_shrinking = true, +}; + +static void set_param_indices(struct p4tc_act *act) +{ + struct p4tc_act_param *param; + unsigned long tmp, id; + int i = 0; + + idr_for_each_entry_ul(&act->params_idr, param, tmp, id) { + param->index = i; + i++; + } +} + +static int __tcf_p4_dyna_init(struct net *net, struct nlattr *est, + struct p4tc_act *act, struct tc_act_dyna *parm, + struct tc_action **a, struct tcf_proto *tp, + struct tc_action_ops *a_o, + struct tcf_chain **goto_ch, u32 flags, + struct netlink_ext_ack *extack) +{ + bool bind = flags & TCA_ACT_FLAGS_BIND; + bool exists = false; + int ret = 0; + struct p4tc_pipeline *pipeline; + u32 index; + int err; + + index = parm->index; + + err = tcf_idr_check_alloc(act->tn, &index, a, bind); + if (err < 0) + return err; + + exists = err; + if (!exists) { + struct tcf_p4act *p; + + ret = tcf_idr_create(act->tn, index, est, a, a_o, bind, true, + flags); + if (ret) { + tcf_idr_cleanup(act->tn, index); + return ret; + } + + /* dyn_ref here should never be 0, because if we are here, it + * means that a template action of this kind was created. Thus + * dyn_ref should be at least 1. Also since this operation and + * others that add or delete action templates run with + * rtnl_lock held, we cannot do this op and a deletion op in + * parallel. + */ + WARN_ON(!refcount_inc_not_zero(&a_o->dyn_ref)); + + pipeline = act->pipeline; + + p = to_p4act(*a); + p->p_id = pipeline->common.p_id; + p->act_id = act->a_id; + INIT_LIST_HEAD(&p->cmd_operations); + + ret = ACT_P_CREATED; + } else { + if (bind) /* dont override defaults */ + return 0; + if (!(flags & TCA_ACT_FLAGS_REPLACE)) { + tcf_idr_cleanup(act->tn, index); + return -EEXIST; + } + } + + err = tcf_action_check_ctrlact(parm->action, tp, goto_ch, extack); + if (err < 0) { + tcf_idr_release(*a, bind); + return err; + } + + return ret; +} + +static int __tcf_p4_dyna_init_set(struct p4tc_act *act, struct tc_action **a, + struct tcf_p4act_params *params, + struct tcf_chain *goto_ch, + struct tc_act_dyna *parm, bool exists, + struct netlink_ext_ack *extack) +{ + struct tcf_p4act_params *params_old; + struct tcf_p4act *p; + int err = 0; + + p = to_p4act(*a); + + if (exists) + spin_lock_bh(&p->tcf_lock); + + goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); + + params_old = rcu_replace_pointer(p->params, params, 1); + if (exists) + spin_unlock_bh(&p->tcf_lock); + + if (goto_ch) + tcf_chain_put_by_act(goto_ch); + + if (params_old) + call_rcu(¶ms_old->rcu, tcf_p4_act_params_destroy_rcu); + + return err; +} + +static struct p4tc_act *tcf_p4_find_act(struct net *net, + const struct tc_action_ops *a_o) +{ + char *act_name_clone, *act_name, *p_name; + struct p4tc_pipeline *pipeline; + struct p4tc_act *act; + int err; + + act_name_clone = act_name = kstrdup(a_o->kind, GFP_KERNEL); + if (!act_name) + return ERR_PTR(-ENOMEM); + + p_name = strsep(&act_name, SEPARATOR); + pipeline = tcf_pipeline_find_byany(net, p_name, 0, NULL); + if (IS_ERR(pipeline)) { + err = -ENOENT; + goto free_act_name; + } + + act = tcf_action_find_byname(act_name, pipeline); + if (!act) { + err = -ENOENT; + goto free_act_name; + } + kfree(act_name_clone); + + return act; + +free_act_name: + kfree(act_name_clone); + return ERR_PTR(err); +} + +static int tcf_p4_dyna_init(struct net *net, struct nlattr *nla, + struct nlattr *est, struct tc_action **a, + struct tcf_proto *tp, struct tc_action_ops *a_o, + u32 flags, struct netlink_ext_ack *extack) +{ + bool bind = flags & TCA_ACT_FLAGS_BIND; + struct tcf_chain *goto_ch = NULL; + bool exists = false; + int ret = 0; + struct nlattr *tb[P4TC_ACT_MAX + 1]; + struct tcf_p4act_params *params; + struct tc_act_dyna *parm; + struct p4tc_act *act; + int err; + + if (flags & TCA_ACT_FLAGS_BIND && + !(flags & TCA_ACT_FLAGS_FROM_P4TC)) { + NL_SET_ERR_MSG(extack, + "Can only bind to dynamic action from P4TC objects"); + return -EPERM; + } + + if (!nla) { + NL_SET_ERR_MSG(extack, + "Must specify action netlink attributes"); + return -EINVAL; + } + + err = nla_parse_nested(tb, P4TC_ACT_MAX, nla, NULL, extack); + if (err < 0) + return err; + + if (!tb[P4TC_ACT_OPT]) { + NL_SET_ERR_MSG(extack, + "Must specify option netlink attributes"); + return -EINVAL; + } + + act = tcf_p4_find_act(net, a_o); + if (IS_ERR(act)) + return PTR_ERR(act); + + if (!act->active) { + NL_SET_ERR_MSG(extack, + "Dynamic action must be active to create instance"); + return -EINVAL; + } + + parm = nla_data(tb[P4TC_ACT_OPT]); + + ret = __tcf_p4_dyna_init(net, est, act, parm, a, tp, a_o, &goto_ch, + flags, extack); + if (ret < 0) + return ret; + if (bind && !ret) + return 0; + + err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); + if (err < 0) + goto release_idr; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + err = -ENOMEM; + goto release_idr; + } + + idr_init(¶ms->params_idr); + if (tb[P4TC_ACT_PARMS]) { + err = tcf_p4_act_init_params(net, params, act, + tb[P4TC_ACT_PARMS], extack); + if (err < 0) + goto release_params; + } else { + if (!idr_is_empty(&act->params_idr)) { + NL_SET_ERR_MSG(extack, + "Must specify action parameters"); + err = -EINVAL; + goto release_params; + } + } + + exists = ret != ACT_P_CREATED; + err = __tcf_p4_dyna_init_set(act, a, params, goto_ch, parm, exists, + extack); + if (err < 0) + goto release_params; + + return ret; + +release_params: + tcf_p4_act_params_destroy(params); + +release_idr: + tcf_idr_release(*a, bind); + return err; +} + +static const struct nla_policy p4tc_act_params_value_policy[P4TC_ACT_VALUE_PARAMS_MAX + 1] = { + [P4TC_ACT_PARAMS_VALUE_RAW] = { .type = NLA_BINARY }, + [P4TC_ACT_PARAMS_VALUE_OPND] = { .type = NLA_NESTED }, +}; + +static int dev_init_param_value(struct net *net, struct p4tc_act_param_ops *op, + struct p4tc_act_param *nparam, + struct nlattr **tb, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb_value[P4TC_ACT_VALUE_PARAMS_MAX + 1]; + u32 value_len; + u32 *ifindex; + int err; + + if (!tb[P4TC_ACT_PARAMS_VALUE]) { + NL_SET_ERR_MSG(extack, "Must specify param value"); + return -EINVAL; + } + err = nla_parse_nested(tb_value, P4TC_ACT_VALUE_PARAMS_MAX, + tb[P4TC_ACT_PARAMS_VALUE], + p4tc_act_params_value_policy, extack); + if (err < 0) + return err; + + value_len = nla_len(tb_value[P4TC_ACT_PARAMS_VALUE_RAW]); + if (value_len != sizeof(u32)) { + NL_SET_ERR_MSG(extack, "Value length differs from template's"); + return -EINVAL; + } + + ifindex = nla_data(tb_value[P4TC_ACT_PARAMS_VALUE_RAW]); + rcu_read_lock(); + if (!dev_get_by_index_rcu(net, *ifindex)) { + NL_SET_ERR_MSG(extack, "Invalid ifindex"); + rcu_read_unlock(); + return -EINVAL; + } + rcu_read_unlock(); + + nparam->value = kzalloc(sizeof(*ifindex), GFP_KERNEL); + if (!nparam->value) + return -EINVAL; + + memcpy(nparam->value, ifindex, sizeof(*ifindex)); + + return 0; +} + +static int dev_dump_param_value(struct sk_buff *skb, + struct p4tc_act_param_ops *op, + struct p4tc_act_param *param) +{ + struct nlattr *nest; + int ret; + + nest = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE); + if (param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN) { + struct nlattr *nla_opnd; + + nla_opnd = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE_OPND); + nla_nest_end(skb, nla_opnd); + } else { + const u32 *ifindex = param->value; + + if (nla_put_u32(skb, P4TC_ACT_PARAMS_VALUE_RAW, *ifindex)) { + ret = -EINVAL; + goto out_nla_cancel; + } + } + nla_nest_end(skb, nest); + + return 0; + +out_nla_cancel: + nla_nest_cancel(skb, nest); + return ret; +} + +static void dev_free_param_value(struct p4tc_act_param *param) +{ + if (!(param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN)) + kfree(param->value); +} + +static int generic_init_param_value(struct p4tc_act_param *nparam, + struct p4tc_type *type, struct nlattr **tb, + struct netlink_ext_ack *extack) +{ + const u32 alloc_len = BITS_TO_BYTES(type->container_bitsz); + const u32 len = BITS_TO_BYTES(type->bitsz); + struct nlattr *tb_value[P4TC_ACT_VALUE_PARAMS_MAX + 1]; + void *value; + int err; + + if (!tb[P4TC_ACT_PARAMS_VALUE]) { + NL_SET_ERR_MSG(extack, "Must specify param value"); + return -EINVAL; + } + + err = nla_parse_nested(tb_value, P4TC_ACT_VALUE_PARAMS_MAX, + tb[P4TC_ACT_PARAMS_VALUE], + p4tc_act_params_value_policy, extack); + if (err < 0) + return err; + + value = nla_data(tb_value[P4TC_ACT_PARAMS_VALUE_RAW]); + if (type->ops->validate_p4t) { + err = type->ops->validate_p4t(type, value, 0, type->bitsz - 1, + extack); + if (err < 0) + return err; + } + + if (nla_len(tb_value[P4TC_ACT_PARAMS_VALUE_RAW]) != len) + return -EINVAL; + + nparam->value = kzalloc(alloc_len, GFP_KERNEL); + if (!nparam->value) + return -ENOMEM; + + memcpy(nparam->value, value, len); + + if (tb[P4TC_ACT_PARAMS_MASK]) { + const void *mask = nla_data(tb[P4TC_ACT_PARAMS_MASK]); + + if (nla_len(tb[P4TC_ACT_PARAMS_MASK]) != len) { + NL_SET_ERR_MSG(extack, + "Mask length differs from template's"); + err = -EINVAL; + goto free_value; + } + + nparam->mask = kzalloc(alloc_len, GFP_KERNEL); + if (!nparam->mask) { + err = -ENOMEM; + goto free_value; + } + + memcpy(nparam->mask, mask, len); + } + + return 0; + +free_value: + kfree(nparam->value); + return err; +} + +const struct p4tc_act_param_ops param_ops[P4T_MAX + 1] = { + [P4T_DEV] = { + .init_value = dev_init_param_value, + .dump_value = dev_dump_param_value, + .free = dev_free_param_value, + }, +}; + +static void generic_free_param_value(struct p4tc_act_param *param) +{ + if (!(param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN)) { + kfree(param->value); + kfree(param->mask); + } +} + +int tcf_p4_act_init_params_list(struct tcf_p4act_params *params, + struct list_head *params_list) +{ + struct p4tc_act_param *nparam, *tmp; + int err; + + list_for_each_entry_safe(nparam, tmp, params_list, head) { + err = idr_alloc_u32(¶ms->params_idr, nparam, &nparam->id, + nparam->id, GFP_KERNEL); + if (err < 0) + return err; + list_del(&nparam->head); + params->num_params++; + } + + return 0; +} + +/* This is the action instantiation that is invoked from the template code, + * specifically when there is a command act with runtime parameters. + * It is assumed that the action kind that is being instantiated here was + * already created. This functions is analogous to tcf_p4_dyna_init. + */ +int tcf_p4_dyna_template_init(struct net *net, struct tc_action **a, + struct p4tc_act *act, + struct list_head *params_list, + struct tc_act_dyna *parm, u32 flags, + struct netlink_ext_ack *extack) +{ + bool bind = flags & TCA_ACT_FLAGS_BIND; + struct tc_action_ops *a_o = &act->ops; + struct tcf_chain *goto_ch = NULL; + bool exists = false; + struct tcf_p4act_params *params; + int ret; + int err; + + if (!act->active) { + NL_SET_ERR_MSG(extack, + "Dynamic action must be active to create instance"); + return -EINVAL; + } + + ret = __tcf_p4_dyna_init(net, NULL, act, parm, a, NULL, a_o, &goto_ch, + flags, extack); + if (ret < 0) + return ret; + + err = tcf_action_check_ctrlact(parm->action, NULL, &goto_ch, extack); + if (err < 0) + goto release_idr; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + err = -ENOMEM; + goto release_idr; + } + + idr_init(¶ms->params_idr); + if (params_list) { + err = tcf_p4_act_init_params_list(params, params_list); + if (err < 0) + goto release_params; + } else { + if (!idr_is_empty(&act->params_idr)) { + NL_SET_ERR_MSG(extack, + "Must specify action parameters"); + err = -EINVAL; + goto release_params; + } + } + + exists = ret != ACT_P_CREATED; + err = __tcf_p4_dyna_init_set(act, a, params, goto_ch, parm, exists, + extack); + if (err < 0) + goto release_params; + + return err; + +release_params: + tcf_p4_act_params_destroy(params); + +release_idr: + tcf_idr_release(*a, bind); + return err; +} + +static int tcf_p4_dyna_act(struct sk_buff *skb, const struct tc_action *a, + struct tcf_result *res) +{ + struct tcf_p4act *dynact = to_p4act(a); + int ret = 0; + + tcf_lastuse_update(&dynact->tcf_tm); + tcf_action_update_bstats(&dynact->common, skb); + + return ret; +} + +static int tcf_p4_dyna_dump(struct sk_buff *skb, struct tc_action *a, int bind, + int ref) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct tcf_p4act *dynact = to_p4act(a); + struct tc_act_dyna opt = { + .index = dynact->tcf_index, + .refcnt = refcount_read(&dynact->tcf_refcnt) - ref, + .bindcnt = atomic_read(&dynact->tcf_bindcnt) - bind, + }; + int i = 1; + struct tcf_p4act_params *params; + struct p4tc_act_param *parm; + struct nlattr *nest_parms; + struct nlattr *nest; + struct tcf_t t; + int id; + + spin_lock_bh(&dynact->tcf_lock); + + opt.action = dynact->tcf_action; + if (nla_put(skb, P4TC_ACT_OPT, sizeof(opt), &opt)) + goto nla_put_failure; + + nest = nla_nest_start(skb, P4TC_ACT_CMDS_LIST); + nla_nest_end(skb, nest); + + if (nla_put_string(skb, P4TC_ACT_NAME, a->ops->kind)) + goto nla_put_failure; + + tcf_tm_dump(&t, &dynact->tcf_tm); + if (nla_put_64bit(skb, P4TC_ACT_TM, sizeof(t), &t, P4TC_ACT_PAD)) + goto nla_put_failure; + + nest_parms = nla_nest_start(skb, P4TC_ACT_PARMS); + if (!nest_parms) + goto nla_put_failure; + + params = rcu_dereference_protected(dynact->params, 1); + if (params) { + idr_for_each_entry(¶ms->params_idr, parm, id) { + struct p4tc_act_param_ops *op; + struct nlattr *nest_count; + + nest_count = nla_nest_start(skb, i); + if (!nest_count) + goto nla_put_failure; + + if (nla_put_string(skb, P4TC_ACT_PARAMS_NAME, + parm->name)) + goto nla_put_failure; + + if (nla_put_u32(skb, P4TC_ACT_PARAMS_ID, parm->id)) + goto nla_put_failure; + + op = (struct p4tc_act_param_ops *)¶m_ops[parm->type->typeid]; + if (op->dump_value) { + if (op->dump_value(skb, op, parm) < 0) + goto nla_put_failure; + } else { + if (generic_dump_param_value(skb, parm->type, parm)) + goto nla_put_failure; + } + + if (nla_put_u32(skb, P4TC_ACT_PARAMS_TYPE, parm->type->typeid)) + goto nla_put_failure; + + nla_nest_end(skb, nest_count); + i++; + } + } + nla_nest_end(skb, nest_parms); + + spin_unlock_bh(&dynact->tcf_lock); + + return skb->len; + +nla_put_failure: + spin_unlock_bh(&dynact->tcf_lock); + nlmsg_trim(skb, b); + return -1; +} + +static int tcf_p4_dyna_lookup(struct net *net, const struct tc_action_ops *ops, + struct tc_action **a, u32 index) +{ + struct p4tc_act *act; + + act = tcf_p4_find_act(net, ops); + if (IS_ERR(act)) + return PTR_ERR(act); + + return tcf_idr_search(act->tn, a, index); +} + +static int tcf_p4_dyna_walker(struct net *net, struct sk_buff *skb, + struct netlink_callback *cb, int type, + const struct tc_action_ops *ops, + struct netlink_ext_ack *extack) +{ + struct p4tc_act *act; + + act = tcf_p4_find_act(net, ops); + if (IS_ERR(act)) + return PTR_ERR(act); + + return tcf_generic_walker(act->tn, skb, cb, type, ops, extack); +} + +static void tcf_p4_dyna_cleanup(struct tc_action *a) +{ + struct tc_action_ops *ops = (struct tc_action_ops *)a->ops; + struct tcf_p4act *m = to_p4act(a); + struct tcf_p4act_params *params; + + params = rcu_dereference_protected(m->params, 1); + + if (refcount_read(&ops->dyn_ref) > 1) + refcount_dec(&ops->dyn_ref); + + if (params) + call_rcu(¶ms->rcu, tcf_p4_act_params_destroy_rcu); +} + +int generic_dump_param_value(struct sk_buff *skb, struct p4tc_type *type, + struct p4tc_act_param *param) +{ + const u32 bytesz = BITS_TO_BYTES(type->container_bitsz); + unsigned char *b = nlmsg_get_pos(skb); + struct nlattr *nla_value; + + nla_value = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE); + if (param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN) { + struct nlattr *nla_opnd; + + nla_opnd = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE_OPND); + nla_nest_end(skb, nla_opnd); + } else { + if (nla_put(skb, P4TC_ACT_PARAMS_VALUE_RAW, bytesz, + param->value)) + goto out_nlmsg_trim; + } + nla_nest_end(skb, nla_value); + + if (param->mask && + nla_put(skb, P4TC_ACT_PARAMS_MASK, bytesz, param->mask)) + goto out_nlmsg_trim; + + return 0; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -1; +} + +void tcf_p4_act_params_destroy(struct tcf_p4act_params *params) +{ + struct p4tc_act_param *param; + unsigned long param_id, tmp; + + idr_for_each_entry_ul(¶ms->params_idr, param, tmp, param_id) { + struct p4tc_act_param_ops *op; + + idr_remove(¶ms->params_idr, param_id); + op = (struct p4tc_act_param_ops *)¶m_ops[param->type->typeid]; + if (op->free) + op->free(param); + else + generic_free_param_value(param); + kfree(param); + } + + kfree(params->params_array); + idr_destroy(¶ms->params_idr); + + kfree(params); +} + +void tcf_p4_act_params_destroy_rcu(struct rcu_head *head) +{ + struct tcf_p4act_params *params; + + params = container_of(head, struct tcf_p4act_params, rcu); + tcf_p4_act_params_destroy(params); +} + +static const struct nla_policy p4tc_act_params_policy[P4TC_ACT_PARAMS_MAX + 1] = { + [P4TC_ACT_PARAMS_NAME] = { .type = NLA_STRING, .len = ACTPARAMNAMSIZ }, + [P4TC_ACT_PARAMS_ID] = { .type = NLA_U32 }, + [P4TC_ACT_PARAMS_VALUE] = { .type = NLA_NESTED }, + [P4TC_ACT_PARAMS_MASK] = { .type = NLA_BINARY }, + [P4TC_ACT_PARAMS_TYPE] = { .type = NLA_U32 }, +}; + +static struct p4tc_act_param *param_find_byname(struct idr *params_idr, + const char *param_name) +{ + struct p4tc_act_param *param; + unsigned long tmp, id; + + idr_for_each_entry_ul(params_idr, param, tmp, id) { + if (param == ERR_PTR(-EBUSY)) + continue; + if (strncmp(param->name, param_name, ACTPARAMNAMSIZ) == 0) + return param; + } + + return NULL; +} + +struct p4tc_act_param *tcf_param_find_byid(struct idr *params_idr, + const u32 param_id) +{ + return idr_find(params_idr, param_id); +} + +struct p4tc_act_param *tcf_param_find_byany(struct p4tc_act *act, + const char *param_name, + const u32 param_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_act_param *param; + int err; + + if (param_id) { + param = tcf_param_find_byid(&act->params_idr, param_id); + if (!param) { + NL_SET_ERR_MSG(extack, "Unable to find param by id"); + err = -EINVAL; + goto out; + } + } else { + if (param_name) { + param = param_find_byname(&act->params_idr, param_name); + if (!param) { + NL_SET_ERR_MSG(extack, "Param name not found"); + err = -EINVAL; + goto out; + } + } else { + NL_SET_ERR_MSG(extack, "Must specify param name or id"); + err = -EINVAL; + goto out; + } + } + + return param; + +out: + return ERR_PTR(err); +} + +static struct p4tc_act_param * +tcf_param_find_byanyattr(struct p4tc_act *act, struct nlattr *name_attr, + const u32 param_id, struct netlink_ext_ack *extack) +{ + char *param_name = NULL; + + if (name_attr) + param_name = nla_data(name_attr); + + return tcf_param_find_byany(act, param_name, param_id, extack); +} + +static int tcf_p4_act_init_param(struct net *net, + struct tcf_p4act_params *params, + struct p4tc_act *act, struct nlattr *nla, + struct netlink_ext_ack *extack) +{ + u32 param_id = 0; + struct nlattr *tb[P4TC_ACT_PARAMS_MAX + 1]; + struct p4tc_act_param *param, *nparam; + struct p4tc_act_param_ops *op; + int err; + + err = nla_parse_nested(tb, P4TC_ACT_PARAMS_MAX, nla, + p4tc_act_params_policy, extack); + if (err < 0) + return err; + + if (tb[P4TC_ACT_PARAMS_ID]) + param_id = nla_get_u32(tb[P4TC_ACT_PARAMS_ID]); + + param = tcf_param_find_byanyattr(act, tb[P4TC_ACT_PARAMS_NAME], + param_id, extack); + if (IS_ERR(param)) + return PTR_ERR(param); + + if (tb[P4TC_ACT_PARAMS_TYPE]) { + u32 typeid = nla_get_u32(tb[P4TC_ACT_PARAMS_TYPE]); + + if (param->type->typeid != typeid) { + NL_SET_ERR_MSG(extack, + "Param type differs from template"); + return -EINVAL; + } + } else { + NL_SET_ERR_MSG(extack, "Must specify param type"); + return -EINVAL; + } + + nparam = kzalloc(sizeof(*nparam), GFP_KERNEL); + if (!nparam) + return -ENOMEM; + + strscpy(nparam->name, param->name, ACTPARAMNAMSIZ); + nparam->type = param->type; + + op = (struct p4tc_act_param_ops *)¶m_ops[param->type->typeid]; + if (op->init_value) + err = op->init_value(net, op, nparam, tb, extack); + else + err = generic_init_param_value(nparam, nparam->type, tb, extack); + + if (err < 0) + goto free; + + nparam->id = param->id; + nparam->index = param->index; + + err = idr_alloc_u32(¶ms->params_idr, nparam, &nparam->id, + nparam->id, GFP_KERNEL); + if (err < 0) + goto free_val; + + params->params_array[param->index] = nparam; + + return 0; + +free_val: + if (op->free) + op->free(nparam); + else + generic_free_param_value(nparam); + +free: + kfree(nparam); + return err; +} + +int tcf_p4_act_init_params(struct net *net, struct tcf_p4act_params *params, + struct p4tc_act *act, struct nlattr *nla, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1]; + int err; + int i; + + err = nla_parse_nested(tb, P4TC_MSGBATCH_SIZE, nla, NULL, NULL); + if (err < 0) + return err; + + params->params_array = kcalloc(act->num_params, + sizeof(struct p4tc_act_param *), + GFP_KERNEL); + if (!params->params_array) + return -ENOMEM; + + for (i = 1; i < P4TC_MSGBATCH_SIZE + 1 && tb[i]; i++) { + err = tcf_p4_act_init_param(net, params, act, tb[i], extack); + if (err < 0) + return err; + } + + return 0; +} + +struct p4tc_act *tcf_action_find_byname(const char *act_name, + struct p4tc_pipeline *pipeline) +{ + char full_act_name[ACTPARAMNAMSIZ]; + struct p4tc_act *act; + unsigned long tmp, id; + + snprintf(full_act_name, ACTNAMSIZ, "%s/%s", pipeline->common.name, + act_name); + idr_for_each_entry_ul(&pipeline->p_act_idr, act, tmp, id) + if (strncmp(act->common.name, full_act_name, ACTNAMSIZ) == 0) + return act; + + return NULL; +} + +struct p4tc_act *tcf_action_find_byid(struct p4tc_pipeline *pipeline, + const u32 a_id) +{ + return idr_find(&pipeline->p_act_idr, a_id); +} + +struct p4tc_act *tcf_action_find_byany(struct p4tc_pipeline *pipeline, + const char *act_name, const u32 a_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_act *act; + int err; + + if (a_id) { + act = tcf_action_find_byid(pipeline, a_id); + if (!act) { + NL_SET_ERR_MSG(extack, "Unable to find action by id"); + err = -ENOENT; + goto out; + } + } else { + if (act_name) { + act = tcf_action_find_byname(act_name, pipeline); + if (!act) { + NL_SET_ERR_MSG(extack, "Action name not found"); + err = -ENOENT; + goto out; + } + } else { + NL_SET_ERR_MSG(extack, + "Must specify action name or id"); + err = -EINVAL; + goto out; + } + } + + return act; + +out: + return ERR_PTR(err); +} + +struct p4tc_act *tcf_action_get(struct p4tc_pipeline *pipeline, + const char *act_name, const u32 a_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_act *act; + + act = tcf_action_find_byany(pipeline, act_name, a_id, extack); + if (IS_ERR(act)) + return act; + + WARN_ON(!refcount_inc_not_zero(&act->a_ref)); + return act; +} + +void tcf_action_put(struct p4tc_act *act) +{ + WARN_ON(!refcount_dec_not_one(&act->a_ref)); +} + +static struct p4tc_act * +tcf_action_find_byanyattr(struct nlattr *act_name_attr, const u32 a_id, + struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + char *act_name = NULL; + + if (act_name_attr) + act_name = nla_data(act_name_attr); + + return tcf_action_find_byany(pipeline, act_name, a_id, extack); +} + +static void p4_put_param(struct idr *params_idr, struct p4tc_act_param *param) +{ + kfree(param); +} + +void p4_put_many_params(struct idr *params_idr, struct p4tc_act_param *params[], + int params_count) +{ + int i; + + for (i = 0; i < params_count; i++) + p4_put_param(params_idr, params[i]); +} + +static struct p4tc_act_param *p4_create_param(struct p4tc_act *act, + struct nlattr **tb, u32 param_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_act_param *param; + char *name; + int ret; + + if (tb[P4TC_ACT_PARAMS_NAME]) { + name = nla_data(tb[P4TC_ACT_PARAMS_NAME]); + } else { + NL_SET_ERR_MSG(extack, "Must specify param name"); + ret = -EINVAL; + goto out; + } + + param = kmalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + if (tcf_param_find_byid(&act->params_idr, param_id) || + param_find_byname(&act->params_idr, name)) { + NL_SET_ERR_MSG(extack, "Param already exists"); + ret = -EEXIST; + goto free; + } + + if (tb[P4TC_ACT_PARAMS_TYPE]) { + u32 typeid; + + typeid = nla_get_u32(tb[P4TC_ACT_PARAMS_TYPE]); + param->type = p4type_find_byid(typeid); + if (!param->type) { + NL_SET_ERR_MSG(extack, "Param type is invalid"); + ret = -EINVAL; + goto free; + } + } else { + NL_SET_ERR_MSG(extack, "Must specify param type"); + ret = -EINVAL; + goto free; + } + + if (param_id) { + ret = idr_alloc_u32(&act->params_idr, param, ¶m_id, + param_id, GFP_KERNEL); + if (ret < 0) { + NL_SET_ERR_MSG(extack, "Unable to allocate param id"); + goto free; + } + param->id = param_id; + } else { + param->id = 1; + + ret = idr_alloc_u32(&act->params_idr, param, ¶m->id, + UINT_MAX, GFP_KERNEL); + if (ret < 0) { + NL_SET_ERR_MSG(extack, "Unable to allocate param id"); + goto free; + } + } + + strscpy(param->name, name, ACTPARAMNAMSIZ); + + return param; + +free: + kfree(param); + +out: + return ERR_PTR(ret); +} + +static struct p4tc_act_param *p4_update_param(struct p4tc_act *act, + struct nlattr **tb, + const u32 param_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_act_param *param_old, *param; + int ret; + + param_old = tcf_param_find_byanyattr(act, tb[P4TC_ACT_PARAMS_NAME], + param_id, extack); + if (IS_ERR(param_old)) + return param_old; + + param = kmalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + strscpy(param->name, param_old->name, ACTPARAMNAMSIZ); + param->id = param_old->id; + + if (tb[P4TC_ACT_PARAMS_TYPE]) { + u32 typeid; + + typeid = nla_get_u32(tb[P4TC_ACT_PARAMS_TYPE]); + param->type = p4type_find_byid(typeid); + if (!param->type) { + NL_SET_ERR_MSG(extack, "Param type is invalid"); + ret = -EINVAL; + goto free; + } + } else { + NL_SET_ERR_MSG(extack, "Must specify param type"); + ret = -EINVAL; + goto free; + } + + return param; + +free: + kfree(param); +out: + return ERR_PTR(ret); +} + +static struct p4tc_act_param *p4_act_init_param(struct p4tc_act *act, + struct nlattr *nla, bool update, + struct netlink_ext_ack *extack) +{ + u32 param_id = 0; + struct nlattr *tb[P4TC_ACT_PARAMS_MAX + 1]; + int ret; + + ret = nla_parse_nested(tb, P4TC_ACT_PARAMS_MAX, nla, NULL, extack); + if (ret < 0) { + ret = -EINVAL; + goto out; + } + + if (tb[P4TC_ACT_PARAMS_ID]) + param_id = nla_get_u32(tb[P4TC_ACT_PARAMS_ID]); + + if (update) + return p4_update_param(act, tb, param_id, extack); + else + return p4_create_param(act, tb, param_id, extack); + +out: + return ERR_PTR(ret); +} + +int p4_act_init_params(struct p4tc_act *act, struct nlattr *nla, + struct p4tc_act_param *params[], bool update, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1]; + int ret; + int i; + + ret = nla_parse_nested(tb, P4TC_MSGBATCH_SIZE, nla, NULL, extack); + if (ret < 0) + return -EINVAL; + + for (i = 1; i < P4TC_MSGBATCH_SIZE + 1 && tb[i]; i++) { + struct p4tc_act_param *param; + + param = p4_act_init_param(act, tb[i], update, extack); + if (IS_ERR(param)) { + ret = PTR_ERR(param); + goto params_del; + } + params[i - 1] = param; + } + + return i - 1; + +params_del: + p4_put_many_params(&act->params_idr, params, i - 1); + return ret; +} + +int p4_act_init(struct p4tc_act *act, struct nlattr *nla, + struct p4tc_act_param *params[], struct netlink_ext_ack *extack) +{ + int num_params = 0; + int ret; + + idr_init(&act->params_idr); + + if (nla) { + num_params = + p4_act_init_params(act, nla, params, false, extack); + if (num_params < 0) { + ret = num_params; + goto idr_destroy; + } + } + + return num_params; + +idr_destroy: + p4_put_many_params(&act->params_idr, params, num_params); + idr_destroy(&act->params_idr); + return ret; +} + +static const struct nla_policy p4tc_act_policy[P4TC_ACT_MAX + 1] = { + [P4TC_ACT_NAME] = { .type = NLA_STRING, .len = ACTNAMSIZ }, + [P4TC_ACT_PARMS] = { .type = NLA_NESTED }, + [P4TC_ACT_OPT] = { .type = NLA_BINARY, + .len = sizeof(struct tc_act_dyna) }, + [P4TC_ACT_CMDS_LIST] = { .type = NLA_NESTED }, + [P4TC_ACT_ACTIVE] = { .type = NLA_U8 }, +}; + +static inline void p4tc_action_net_exit(struct tc_action_net *tn) +{ + tcf_idrinfo_destroy(tn->ops, tn->idrinfo); + kfree(tn->idrinfo); + kfree(tn); +} + +static int __tcf_act_put(struct net *net, struct p4tc_pipeline *pipeline, + struct p4tc_act *act, bool unconditional_purge, + struct netlink_ext_ack *extack) +{ + struct p4tc_act_param *act_param; + unsigned long param_id, tmp; + struct tc_action_net *tn; + struct idr *idr; + int ret; + + if (!unconditional_purge && (refcount_read(&act->ops.dyn_ref) > 1 || + refcount_read(&act->a_ref) > 1)) { + NL_SET_ERR_MSG(extack, + "Unable to delete referenced action template"); + return -EBUSY; + } + + tn = net_generic(net, act->ops.net_id); + idr = &tn->idrinfo->action_idr; + + idr_for_each_entry_ul(&act->params_idr, act_param, tmp, param_id) { + idr_remove(&act->params_idr, param_id); + kfree(act_param); + } + + ret = tcf_unregister_dyn_action(net, &act->ops); + if (ret < 0) { + NL_SET_ERR_MSG(extack, + "Unable to unregister new action template"); + return ret; + } + p4tc_action_net_exit(act->tn); + + if (act->labels) { + rhashtable_free_and_destroy(act->labels, p4tc_label_ht_destroy, + NULL); + kfree(act->labels); + } + + idr_remove(&pipeline->p_act_idr, act->a_id); + + if (!unconditional_purge) + tcf_pipeline_delete_from_dep_graph(pipeline, act); + + list_del(&act->head); + + kfree(act); + + pipeline->num_created_acts--; + + return 0; +} + +static int _tcf_act_fill_nlmsg(struct net *net, struct sk_buff *skb, + struct p4tc_act *act) +{ + unsigned char *b = nlmsg_get_pos(skb); + int i = 1; + struct nlattr *nest, *parms, *cmds; + struct p4tc_act_param *param; + unsigned long param_id, tmp; + + if (nla_put_u32(skb, P4TC_PATH, act->a_id)) + goto out_nlmsg_trim; + + nest = nla_nest_start(skb, P4TC_PARAMS); + if (!nest) + goto out_nlmsg_trim; + + if (nla_put_string(skb, P4TC_ACT_NAME, act->common.name)) + goto out_nlmsg_trim; + + parms = nla_nest_start(skb, P4TC_ACT_PARMS); + if (!parms) + goto out_nlmsg_trim; + + idr_for_each_entry_ul(&act->params_idr, param, tmp, param_id) { + struct nlattr *nest_count; + + nest_count = nla_nest_start(skb, i); + if (!nest_count) + goto out_nlmsg_trim; + + if (nla_put_string(skb, P4TC_ACT_PARAMS_NAME, param->name)) + goto out_nlmsg_trim; + + if (nla_put_u32(skb, P4TC_ACT_PARAMS_ID, param->id)) + goto out_nlmsg_trim; + + if (nla_put_u32(skb, P4TC_ACT_PARAMS_TYPE, param->type->typeid)) + goto out_nlmsg_trim; + + nla_nest_end(skb, nest_count); + i++; + } + nla_nest_end(skb, parms); + + cmds = nla_nest_start(skb, P4TC_ACT_CMDS_LIST); + nla_nest_end(skb, cmds); + + nla_nest_end(skb, nest); + + return skb->len; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -1; +} + +static int tcf_act_fill_nlmsg(struct net *net, struct sk_buff *skb, + struct p4tc_template_common *tmpl, + struct netlink_ext_ack *extack) +{ + return _tcf_act_fill_nlmsg(net, skb, to_act(tmpl)); +} + +static int tcf_act_flush(struct sk_buff *skb, struct net *net, + struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_act *act; + unsigned long tmp, act_id; + int ret = 0; + int i = 0; + + if (nla_put_u32(skb, P4TC_PATH, 0)) + goto out_nlmsg_trim; + + if (idr_is_empty(&pipeline->p_act_idr)) { + NL_SET_ERR_MSG(extack, + "There are not action templates to flush"); + goto out_nlmsg_trim; + } + + idr_for_each_entry_ul(&pipeline->p_act_idr, act, tmp, act_id) { + if (__tcf_act_put(net, pipeline, act, false, extack) < 0) { + ret = -EBUSY; + continue; + } + i++; + } + + nla_put_u32(skb, P4TC_COUNT, i); + + if (ret < 0) { + if (i == 0) { + NL_SET_ERR_MSG(extack, + "Unable to flush any action template"); + goto out_nlmsg_trim; + } else { + NL_SET_ERR_MSG(extack, + "Unable to flush all action templates"); + } + } + + return i; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_act_gd(struct net *net, struct sk_buff *skb, struct nlmsghdr *n, + struct nlattr *nla, struct p4tc_nl_pname *nl_pname, + u32 *ids, struct netlink_ext_ack *extack) +{ + const u32 pipeid = ids[P4TC_PID_IDX], a_id = ids[P4TC_AID_IDX]; + struct nlattr *tb[P4TC_ACT_MAX + 1] = { NULL }; + unsigned char *b = nlmsg_get_pos(skb); + int ret = 0; + struct p4tc_pipeline *pipeline; + struct p4tc_act *act; + + if (n->nlmsg_type == RTM_DELP4TEMPLATE) + pipeline = tcf_pipeline_find_byany_unsealed(net, nl_pname->data, + pipeid, extack); + else + pipeline = tcf_pipeline_find_byany(net, nl_pname->data, pipeid, + extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + + if (nla) { + ret = nla_parse_nested(tb, P4TC_ACT_MAX, nla, p4tc_act_policy, + extack); + if (ret < 0) + return ret; + } + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (n->nlmsg_type == RTM_DELP4TEMPLATE && (n->nlmsg_flags & NLM_F_ROOT)) + return tcf_act_flush(skb, net, pipeline, extack); + + act = tcf_action_find_byanyattr(tb[P4TC_ACT_NAME], a_id, pipeline, + extack); + if (IS_ERR(act)) + return PTR_ERR(act); + + if (_tcf_act_fill_nlmsg(net, skb, act) < 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for template action"); + return -EINVAL; + } + + if (n->nlmsg_type == RTM_DELP4TEMPLATE) { + ret = __tcf_act_put(net, pipeline, act, false, extack); + if (ret < 0) + goto out_nlmsg_trim; + } + + return 0; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_act_put(struct net *net, struct p4tc_template_common *tmpl, + bool unconditional_purge, struct netlink_ext_ack *extack) +{ + struct p4tc_act *act = to_act(tmpl); + struct p4tc_pipeline *pipeline; + + pipeline = tcf_pipeline_find_byid(net, tmpl->p_id); + + return __tcf_act_put(net, pipeline, act, unconditional_purge, extack); +} + +static void p4tc_params_replace_many(struct idr *params_idr, + struct p4tc_act_param *params[], + int params_count) +{ + int i; + + for (i = 0; i < params_count; i++) { + struct p4tc_act_param *param = params[i]; + + param = idr_replace(params_idr, param, param->id); + kfree(param); + } +} + +static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, + struct p4tc_pipeline *pipeline, u32 *ids, + struct netlink_ext_ack *extack) +{ + struct p4tc_act_param *params[P4TC_MSGBATCH_SIZE] = { NULL }; + u32 a_id = ids[P4TC_AID_IDX]; + int num_params = 0; + int ret = 0; + struct p4tc_act_dep_node *dep_node; + struct p4tc_act *act; + char *act_name; + + if (tb[P4TC_ACT_NAME]) { + act_name = nla_data(tb[P4TC_ACT_NAME]); + } else { + NL_SET_ERR_MSG(extack, "Must supply action name"); + return ERR_PTR(-EINVAL); + } + + if ((tcf_action_find_byname(act_name, pipeline))) { + NL_SET_ERR_MSG(extack, "Action already exists with same name"); + return ERR_PTR(-EEXIST); + } + + if (tcf_action_find_byid(pipeline, a_id)) { + NL_SET_ERR_MSG(extack, "Action already exists with same id"); + return ERR_PTR(-EEXIST); + } + + act = kzalloc(sizeof(*act), GFP_KERNEL); + if (!act) + return ERR_PTR(-ENOMEM); + + act->ops.owner = THIS_MODULE; + act->ops.act = tcf_p4_dyna_act; + act->ops.dump = tcf_p4_dyna_dump; + act->ops.cleanup = tcf_p4_dyna_cleanup; + act->ops.init_ops = tcf_p4_dyna_init; + act->ops.lookup = tcf_p4_dyna_lookup; + act->ops.walk = tcf_p4_dyna_walker; + act->ops.size = sizeof(struct tcf_p4act); + INIT_LIST_HEAD(&act->head); + + act->tn = kzalloc(sizeof(*act->tn), GFP_KERNEL); + if (!act->tn) { + ret = -ENOMEM; + goto free_act_ops; + } + + ret = tc_action_net_init(net, act->tn, &act->ops); + if (ret < 0) { + kfree(act->tn); + goto free_act_ops; + } + act->tn->ops = &act->ops; + + snprintf(act->ops.kind, ACTNAMSIZ, "%s/%s", pipeline->common.name, + act_name); + + if (a_id) { + ret = idr_alloc_u32(&pipeline->p_act_idr, act, &a_id, a_id, + GFP_KERNEL); + if (ret < 0) { + NL_SET_ERR_MSG(extack, "Unable to alloc action id"); + goto free_action_net; + } + + act->a_id = a_id; + } else { + act->a_id = 1; + + ret = idr_alloc_u32(&pipeline->p_act_idr, act, &act->a_id, + UINT_MAX, GFP_KERNEL); + if (ret < 0) { + NL_SET_ERR_MSG(extack, "Unable to alloc action id"); + goto free_action_net; + } + } + + dep_node = kzalloc(sizeof(*dep_node), GFP_KERNEL); + if (!dep_node) { + ret = -ENOMEM; + goto idr_rm; + } + dep_node->act_id = act->a_id; + INIT_LIST_HEAD(&dep_node->incoming_egde_list); + list_add_tail(&dep_node->head, &pipeline->act_dep_graph); + + refcount_set(&act->ops.dyn_ref, 1); + ret = tcf_register_dyn_action(net, &act->ops); + if (ret < 0) { + NL_SET_ERR_MSG(extack, + "Unable to register new action template"); + goto free_dep_node; + } + + num_params = p4_act_init(act, tb[P4TC_ACT_PARMS], params, extack); + if (num_params < 0) { + ret = num_params; + goto unregister; + } + act->num_params = num_params; + + set_param_indices(act); + + INIT_LIST_HEAD(&act->cmd_operations); + act->pipeline = pipeline; + + pipeline->num_created_acts++; + + ret = determine_act_topological_order(pipeline, true); + if (ret < 0) { + pipeline->num_created_acts--; + goto uninit; + } + + act->common.p_id = pipeline->common.p_id; + snprintf(act->common.name, ACTNAMSIZ, "%s/%s", pipeline->common.name, + act_name); + act->common.ops = (struct p4tc_template_ops *)&p4tc_act_ops; + + refcount_set(&act->a_ref, 1); + + list_add_tail(&act->head, &dynact_list); + + return act; + +uninit: + p4_put_many_params(&act->params_idr, params, num_params); + idr_destroy(&act->params_idr); + +unregister: + rtnl_unlock(); + tcf_unregister_dyn_action(net, &act->ops); + rtnl_lock(); + +free_dep_node: + list_del(&dep_node->head); + kfree(dep_node); + +idr_rm: + idr_remove(&pipeline->p_act_idr, act->a_id); + +free_action_net: + p4tc_action_net_exit(act->tn); + +free_act_ops: + kfree(act); + + return ERR_PTR(ret); +} + +static struct p4tc_act *tcf_act_update(struct net *net, struct nlattr **tb, + struct p4tc_pipeline *pipeline, u32 *ids, + u32 flags, + struct netlink_ext_ack *extack) +{ + struct p4tc_act_param *params[P4TC_MSGBATCH_SIZE] = { NULL }; + const u32 a_id = ids[P4TC_AID_IDX]; + int num_params = 0; + s8 active = -1; + int ret = 0; + struct p4tc_act *act; + + act = tcf_action_find_byanyattr(tb[P4TC_ACT_NAME], a_id, pipeline, + extack); + if (IS_ERR(act)) + return act; + + if (tb[P4TC_ACT_ACTIVE]) + active = nla_get_u8(tb[P4TC_ACT_ACTIVE]); + + if (act->active) { + if (!active) { + if (refcount_read(&act->ops.dyn_ref) > 1) { + NL_SET_ERR_MSG(extack, + "Unable to inactivate referenced action"); + return ERR_PTR(-EINVAL); + } + act->active = false; + return act; + } + NL_SET_ERR_MSG(extack, "Unable to update active action"); + return ERR_PTR(-EINVAL); + } + + if (tb[P4TC_ACT_PARMS]) { + num_params = p4_act_init_params(act, tb[P4TC_ACT_PARMS], params, + true, extack); + if (num_params < 0) { + ret = num_params; + goto out; + } + set_param_indices(act); + } + + act->pipeline = pipeline; + if (active == 1) { + act->active = true; + } else if (!active) { + NL_SET_ERR_MSG(extack, "Action is already inactive"); + ret = -EINVAL; + goto params_del; + } + + if (tb[P4TC_ACT_CMDS_LIST]) { + ret = determine_act_topological_order(pipeline, true); + if (ret < 0) + goto params_del; + } + + p4tc_params_replace_many(&act->params_idr, params, num_params); + return act; + +params_del: + p4_put_many_params(&act->params_idr, params, num_params); + +out: + return ERR_PTR(ret); +} + +static struct p4tc_template_common * +tcf_act_cu(struct net *net, struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + const u32 pipeid = ids[P4TC_PID_IDX]; + struct nlattr *tb[P4TC_ACT_MAX + 1]; + struct p4tc_act *act; + struct p4tc_pipeline *pipeline; + int ret; + + pipeline = tcf_pipeline_find_byany_unsealed(net, nl_pname->data, pipeid, + extack); + if (IS_ERR(pipeline)) + return (void *)pipeline; + + ret = nla_parse_nested(tb, P4TC_ACT_MAX, nla, p4tc_act_policy, extack); + if (ret < 0) + return ERR_PTR(ret); + + if (n->nlmsg_flags & NLM_F_REPLACE) + act = tcf_act_update(net, tb, pipeline, ids, n->nlmsg_flags, + extack); + else + act = tcf_act_create(net, tb, pipeline, ids, extack); + if (IS_ERR(act)) + goto out; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + +out: + return (struct p4tc_template_common *)act; +} + +static int tcf_act_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, + struct nlattr *nla, char **p_name, u32 *ids, + struct netlink_ext_ack *extack) +{ + struct net *net = sock_net(skb->sk); + struct p4tc_pipeline *pipeline; + + if (!ctx->ids[P4TC_PID_IDX]) { + pipeline = tcf_pipeline_find_byany(net, *p_name, + ids[P4TC_PID_IDX], extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + ctx->ids[P4TC_PID_IDX] = pipeline->common.p_id; + } else { + pipeline = tcf_pipeline_find_byid(net, ctx->ids[P4TC_PID_IDX]); + } + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!(*p_name)) + *p_name = pipeline->common.name; + + return tcf_p4_tmpl_generic_dump(skb, ctx, &pipeline->p_act_idr, + P4TC_AID_IDX, extack); +} + +static int tcf_act_dump_1(struct sk_buff *skb, + struct p4tc_template_common *common) +{ + struct nlattr *param = nla_nest_start(skb, P4TC_PARAMS); + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_act *act = to_act(common); + struct nlattr *nest; + + if (!param) + goto out_nlmsg_trim; + + if (nla_put_string(skb, P4TC_ACT_NAME, act->common.name)) + goto out_nlmsg_trim; + + nest = nla_nest_start(skb, P4TC_ACT_CMDS_LIST); + nla_nest_end(skb, nest); + + if (nla_put_u8(skb, P4TC_ACT_ACTIVE, act->active)) + goto out_nlmsg_trim; + + nla_nest_end(skb, param); + + return 0; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -ENOMEM; +} + +const struct p4tc_template_ops p4tc_act_ops = { + .init = NULL, + .cu = tcf_act_cu, + .put = tcf_act_put, + .gd = tcf_act_gd, + .fill_nlmsg = tcf_act_fill_nlmsg, + .dump = tcf_act_dump, + .dump_1 = tcf_act_dump_1, +}; diff --git a/net/sched/p4tc/p4tc_meta.c b/net/sched/p4tc/p4tc_meta.c index 21a5477ab0c6..140759818da7 100644 --- a/net/sched/p4tc/p4tc_meta.c +++ b/net/sched/p4tc/p4tc_meta.c @@ -202,6 +202,67 @@ static int p4tc_check_meta_size(struct p4tc_meta_size_params *sz_params, return new_bitsz; } +static inline void *tcf_meta_fetch_kernel(struct sk_buff *skb, + const u32 kernel_meta_id) +{ + switch (kernel_meta_id) { + case P4TC_KERNEL_META_QMAP: + return &skb->queue_mapping; + case P4TC_KERNEL_META_PKTLEN: + return &skb->len; + case P4TC_KERNEL_META_DATALEN: + return &skb->data_len; + case P4TC_KERNEL_META_SKBMARK: + return &skb->mark; + case P4TC_KERNEL_META_TCINDEX: + return &skb->tc_index; + case P4TC_KERNEL_META_SKBHASH: + return &skb->hash; + case P4TC_KERNEL_META_SKBPRIO: + return &skb->priority; + case P4TC_KERNEL_META_IFINDEX: + return &skb->dev->ifindex; + case P4TC_KERNEL_META_SKBIIF: + return &skb->skb_iif; + case P4TC_KERNEL_META_PROTOCOL: + return &skb->protocol; + case P4TC_KERNEL_META_PKTYPE: + case P4TC_KERNEL_META_IDF: + case P4TC_KERNEL_META_IPSUM: + case P4TC_KERNEL_META_OOOK: + case P4TC_KERNEL_META_PTYPEOFF: + case P4TC_KERNEL_META_PTCLNOFF: + return &skb->__pkt_type_offset; + case P4TC_KERNEL_META_FCLONE: + case P4TC_KERNEL_META_PEEKED: + case P4TC_KERNEL_META_CLONEOFF: + return &skb->__cloned_offset; + case P4TC_KERNEL_META_DIRECTION: + return &skb->__mono_tc_offset; + default: + return NULL; + } + + return NULL; +} + +static inline void *tcf_meta_fetch_user(struct sk_buff *skb, const u32 skb_off) +{ + struct p4tc_percpu_scratchpad *pad; + + pad = this_cpu_ptr(&p4tc_percpu_scratchpad); + + return &pad->metadata[skb_off]; +} + +void *tcf_meta_fetch(struct sk_buff *skb, struct p4tc_metadata *meta) +{ + if (meta->common.p_id != P4TC_KERNEL_PIPEID) + return tcf_meta_fetch_user(skb, meta->m_skb_off); + + return tcf_meta_fetch_kernel(skb, meta->m_id); +} + void tcf_meta_fill_user_offsets(struct p4tc_pipeline *pipeline) { u32 meta_off = START_META_OFFSET; diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c index ed924059cb6a..e4cb5ad994e8 100644 --- a/net/sched/p4tc/p4tc_pipeline.c +++ b/net/sched/p4tc/p4tc_pipeline.c @@ -77,10 +77,226 @@ static const struct nla_policy tc_pipeline_policy[P4TC_PIPELINE_MAX + 1] = { [P4TC_PIPELINE_POSTACTIONS] = { .type = NLA_NESTED }, }; +static void __act_dep_graph_free(struct list_head *incoming_egde_list) +{ + struct p4tc_act_dep_edge_node *cursor_edge, *tmp_edge; + + list_for_each_entry_safe(cursor_edge, tmp_edge, incoming_egde_list, + head) { + list_del(&cursor_edge->head); + kfree(cursor_edge); + } +} + +static void act_dep_graph_free(struct list_head *graph) +{ + struct p4tc_act_dep_node *cursor, *tmp; + + list_for_each_entry_safe(cursor, tmp, graph, head) { + __act_dep_graph_free(&cursor->incoming_egde_list); + + list_del(&cursor->head); + kfree(cursor); + } +} + +void tcf_pipeline_delete_from_dep_graph(struct p4tc_pipeline *pipeline, + struct p4tc_act *act) +{ + struct p4tc_act_dep_node *act_node, *node_tmp; + + list_for_each_entry_safe(act_node, node_tmp, &pipeline->act_dep_graph, + head) { + if (act_node->act_id == act->a_id) { + __act_dep_graph_free(&act_node->incoming_egde_list); + list_del(&act_node->head); + kfree(act_node); + } + } + + list_for_each_entry_safe(act_node, node_tmp, + &pipeline->act_topological_order, head) { + if (act_node->act_id == act->a_id) { + list_del(&act_node->head); + kfree(act_node); + } + } +} + +/* Node id indicates the callee's act id. + * edge_node->act_id indicates the caller's act id. + */ +void tcf_pipeline_add_dep_edge(struct p4tc_pipeline *pipeline, + struct p4tc_act_dep_edge_node *edge_node, + u32 node_id) +{ + struct p4tc_act_dep_node *cursor; + + list_for_each_entry(cursor, &pipeline->act_dep_graph, head) { + if (cursor->act_id == node_id) + break; + } + + list_add_tail(&edge_node->head, &cursor->incoming_egde_list); +} + +/* Find root node, that is, the node in our graph that has no incoming edges. + */ +struct p4tc_act_dep_node *find_root_node(struct list_head *act_dep_graph) +{ + struct p4tc_act_dep_node *cursor, *root_node; + + list_for_each_entry(cursor, act_dep_graph, head) { + if (list_empty(&cursor->incoming_egde_list)) { + root_node = cursor; + return root_node; + } + } + + return NULL; +} + +/* node_id indicates where the edge is directed to + * edge_node->act_id indicates where the edge comes from. + */ +bool tcf_pipeline_check_act_backedge(struct p4tc_pipeline *pipeline, + struct p4tc_act_dep_edge_node *edge_node, + u32 node_id) +{ + struct p4tc_act_dep_node *root_node = NULL; + + /* make sure we dont call ourselves */ + if (edge_node->act_id == node_id) + return true; + + /* add to the list temporarily so we can run our algorithm to + * find edgeless node and detect a cycle + */ + tcf_pipeline_add_dep_edge(pipeline, edge_node, node_id); + + /* Now lets try to find a node which has no incoming edges (root node). + * If we find a root node it means there is no cycle; + * OTOH, if we dont find one, it means we have circular depency. + */ + root_node = find_root_node(&pipeline->act_dep_graph); + + if (!root_node) + return true; + + list_del(&edge_node->head); + + return false; +} + +static struct p4tc_act_dep_node * +find_and_del_root_node(struct list_head *act_dep_graph) +{ + struct p4tc_act_dep_node *cursor, *tmp, *root_node; + + root_node = find_root_node(act_dep_graph); + list_del(&root_node->head); + + list_for_each_entry_safe(cursor, tmp, act_dep_graph, head) { + struct p4tc_act_dep_edge_node *cursor_edge, *tmp_edge; + + list_for_each_entry_safe(cursor_edge, tmp_edge, + &cursor->incoming_egde_list, head) { + if (cursor_edge->act_id == root_node->act_id) { + list_del(&cursor_edge->head); + kfree(cursor_edge); + } + } + } + + return root_node; +} + +static int act_dep_graph_copy(struct list_head *new_graph, + struct list_head *old_graph) +{ + int err = -ENOMEM; + struct p4tc_act_dep_node *cursor, *tmp; + + list_for_each_entry_safe(cursor, tmp, old_graph, head) { + struct p4tc_act_dep_edge_node *cursor_edge, *tmp_edge; + struct p4tc_act_dep_node *new_dep_node; + + new_dep_node = kzalloc(sizeof(*new_dep_node), GFP_KERNEL); + if (!new_dep_node) + goto free_graph; + + INIT_LIST_HEAD(&new_dep_node->incoming_egde_list); + list_add_tail(&new_dep_node->head, new_graph); + new_dep_node->act_id = cursor->act_id; + + list_for_each_entry_safe(cursor_edge, tmp_edge, + &cursor->incoming_egde_list, head) { + struct p4tc_act_dep_edge_node *new_dep_edge_node; + + new_dep_edge_node = + kzalloc(sizeof(*new_dep_edge_node), GFP_KERNEL); + if (!new_dep_edge_node) + goto free_graph; + + list_add_tail(&new_dep_edge_node->head, + &new_dep_node->incoming_egde_list); + new_dep_edge_node->act_id = cursor_edge->act_id; + } + } + + return 0; + +free_graph: + act_dep_graph_free(new_graph); + return err; +} + +int determine_act_topological_order(struct p4tc_pipeline *pipeline, + bool copy_dep_graph) +{ + int i = pipeline->num_created_acts; + struct p4tc_act_dep_node *act_node, *node_tmp; + struct p4tc_act_dep_node *node; + struct list_head *dep_graph; + + if (copy_dep_graph) { + int err; + + dep_graph = kzalloc(sizeof(*dep_graph), GFP_KERNEL); + if (!dep_graph) + return -ENOMEM; + + INIT_LIST_HEAD(dep_graph); + err = act_dep_graph_copy(dep_graph, &pipeline->act_dep_graph); + if (err < 0) + return err; + } else { + dep_graph = &pipeline->act_dep_graph; + } + + /* Clear from previous calls */ + list_for_each_entry_safe(act_node, node_tmp, + &pipeline->act_topological_order, head) { + list_del(&act_node->head); + kfree(act_node); + } + + while (i--) { + node = find_and_del_root_node(dep_graph); + list_add_tail(&node->head, &pipeline->act_topological_order); + } + + if (copy_dep_graph) + kfree(dep_graph); + + return 0; +} + static void tcf_pipeline_destroy(struct p4tc_pipeline *pipeline, bool free_pipeline) { idr_destroy(&pipeline->p_meta_idr); + idr_destroy(&pipeline->p_act_idr); if (free_pipeline) kfree(pipeline); @@ -106,21 +322,15 @@ static int tcf_pipeline_put(struct net *net, struct p4tc_pipeline_net *pipe_net = net_generic(net, pipeline_net_id); struct p4tc_pipeline *pipeline = to_pipeline(template); struct net *pipeline_net = maybe_get_net(net); - struct p4tc_metadata *meta; + struct p4tc_act_dep_node *act_node, *node_tmp; unsigned long m_id, tmp; + struct p4tc_metadata *meta; if (pipeline_net && !refcount_dec_if_one(&pipeline->p_ref)) { NL_SET_ERR_MSG(extack, "Can't delete referenced pipeline"); return -EBUSY; } - idr_remove(&pipe_net->pipeline_idr, pipeline->common.p_id); - if (pipeline->parser) - tcf_parser_del(net, pipeline, pipeline->parser, extack); - - idr_for_each_entry_ul(&pipeline->p_meta_idr, meta, tmp, m_id) - meta->common.ops->put(net, &meta->common, true, extack); - /* XXX: The action fields are only accessed in the control path * since they will be copied to the filter, where the data path * will use them. So there is no need to free them in the rcu @@ -129,6 +339,26 @@ static int tcf_pipeline_put(struct net *net, p4tc_action_destroy(pipeline->preacts); p4tc_action_destroy(pipeline->postacts); + act_dep_graph_free(&pipeline->act_dep_graph); + + list_for_each_entry_safe(act_node, node_tmp, + &pipeline->act_topological_order, head) { + struct p4tc_act *act; + + act = tcf_action_find_byid(pipeline, act_node->act_id); + act->common.ops->put(net, &act->common, true, extack); + list_del(&act_node->head); + kfree(act_node); + } + + idr_for_each_entry_ul(&pipeline->p_meta_idr, meta, tmp, m_id) + meta->common.ops->put(net, &meta->common, true, extack); + + if (pipeline->parser) + tcf_parser_del(net, pipeline, pipeline->parser, extack); + + idr_remove(&pipe_net->pipeline_idr, pipeline->common.p_id); + if (pipeline_net) call_rcu(&pipeline->rcu, tcf_pipeline_destroy_rcu); else @@ -159,26 +389,13 @@ static inline int pipeline_try_set_state_ready(struct p4tc_pipeline *pipeline, return -EINVAL; } + /* Will never fail in this case */ + determine_act_topological_order(pipeline, false); + pipeline->p_state = P4TC_STATE_READY; return true; } -static int p4tc_action_init(struct net *net, struct nlattr *nla, - struct tc_action *acts[], u32 pipeid, u32 flags, - struct netlink_ext_ack *extack) -{ - int init_res[TCA_ACT_MAX_PRIO]; - size_t attrs_size; - int ret; - - /* If action was already created, just bind to existing one*/ - flags = TCA_ACT_FLAGS_BIND; - ret = tcf_action_init(net, NULL, nla, NULL, acts, init_res, &attrs_size, - flags, 0, extack); - - return ret; -} - struct p4tc_pipeline *tcf_pipeline_find_byid(struct net *net, const u32 pipeid) { struct p4tc_pipeline_net *pipe_net; @@ -323,9 +540,15 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, pipeline->parser = NULL; + idr_init(&pipeline->p_act_idr); + idr_init(&pipeline->p_meta_idr); pipeline->p_meta_offset = 0; + INIT_LIST_HEAD(&pipeline->act_dep_graph); + INIT_LIST_HEAD(&pipeline->act_topological_order); + pipeline->num_created_acts = 0; + pipeline->p_state = P4TC_STATE_NOT_READY; pipeline->net = net; @@ -660,7 +883,8 @@ static int tcf_pipeline_gd(struct net *net, struct sk_buff *skb, return PTR_ERR(pipeline); tmpl = (struct p4tc_template_common *)pipeline; - if (tcf_pipeline_fill_nlmsg(net, skb, tmpl, extack) < 0) + ret = tcf_pipeline_fill_nlmsg(net, skb, tmpl, extack); + if (ret < 0) return -1; if (!ids[P4TC_PID_IDX]) diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c index 7a3f5c0c3af1..c294dc0789f0 100644 --- a/net/sched/p4tc/p4tc_tmpl_api.c +++ b/net/sched/p4tc/p4tc_tmpl_api.c @@ -44,6 +44,7 @@ static bool obj_is_valid(u32 obj) case P4TC_OBJ_PIPELINE: case P4TC_OBJ_META: case P4TC_OBJ_HDR_FIELD: + case P4TC_OBJ_ACT: return true; default: return false; @@ -54,6 +55,7 @@ static const struct p4tc_template_ops *p4tc_ops[P4TC_OBJ_MAX] = { [P4TC_OBJ_PIPELINE] = &p4tc_pipeline_ops, [P4TC_OBJ_META] = &p4tc_meta_ops, [P4TC_OBJ_HDR_FIELD] = &p4tc_hdrfield_ops, + [P4TC_OBJ_ACT] = &p4tc_act_ops, }; int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, From patchwork Wed May 17 11:02:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244697 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54BBF2099F for ; Wed, 17 May 2023 11:04:47 +0000 (UTC) Received: from mail-qk1-x735.google.com (mail-qk1-x735.google.com [IPv6:2607:f8b0:4864:20::735]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3B113F3 for ; Wed, 17 May 2023 04:04:23 -0700 (PDT) Received: by mail-qk1-x735.google.com with SMTP id af79cd13be357-759413d99afso624771085a.1 for ; Wed, 17 May 2023 04:04:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321452; x=1686913452; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LMOJQm9CyF20HOcAOv/drwQGo/PZ7/rgyHcrSk7fmDA=; b=Img53V3I7SfQqkieUd8g+R0TqklaLaJYDUt6sRx3+1vd6csHjCqjyssCy9X6Aro+Qq eJCcrKu0YzxK/uNnOg0qIjHC4QHcTvCYanvImTDJPQRG1e/5jE2JKSAOLY0np9hDQh6N 1qCNJ0gtEUb2owwEr3igNsRru0Vpcz/TiTNIGKtTgf9HFt33mYnDQFJV0lHN0M9v+9tb l2mlObzYV7dNWv9JU/4eRSPeQchRmC0yaIKIG/6b0MZDZsfWFMbnK0bJkIdqEmPahHMd o9ALJ9FFRMkvebFuhan7OXaCiFnfVwrbtw//Bmtsk3iU64ecyiwtIuGTo8Ys40YqTT+Z tB2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321452; x=1686913452; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LMOJQm9CyF20HOcAOv/drwQGo/PZ7/rgyHcrSk7fmDA=; b=kaAQ7Kb9cM+LB45jOpMCQvc7jTJvVMlAij5drQwEQrdJ7fQ5Zi+1b8KIfIVsXO6dku +7sKUhmm29ltwQDYqhoTy/Yjimc73ovtdMwmC0bj5MGzyQjoWEp09wTO10Igl+JMtWuO ZE3KzV+CuuDZTc25SNqbEjlzohbDJJ3xNdHteMZTH2RAFiLhBqrXfwzt/ZbM88H8yG7w oZWr9242Cnbk9/WzYIXcscadXJXXu0574IKAURYjrfBXU+zB1GYpRJFPlJ/Vz9VgYGwV ImEL28YyAXhCG1h+ehg//Hg5hvpZpWs5LfAdM0YY1eVJIY4XT38sLvmm3LYEP8GidEWZ 1uHA== X-Gm-Message-State: AC+VfDzCegHBpESyjY3kp5P0YKnDgQ+ZUOuQkgLjQCS7R2/ed2LuCjPp UNwZ7xeAoc+7D8EMcC9/FZHAFbJff7Mk78oNfsA= X-Google-Smtp-Source: ACHHUZ7Kq6PrnfFy6ZrRj7m0g3I5ErtzfgEtM3Vl1cXwqTNBXq8B4Gw/ZTxO61XiM+HJwqMUDNyCsg== X-Received: by 2002:ad4:5cc4:0:b0:5e9:48da:9938 with SMTP id iu4-20020ad45cc4000000b005e948da9938mr3325899qvb.11.1684321451445; Wed, 17 May 2023 04:04:11 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id w18-20020a0cb552000000b006216ff88b27sm4064975qvd.79.2023.05.17.04.04.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:04:10 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 14/28] p4tc: add table create, update, delete, get, flush and dump Date: Wed, 17 May 2023 07:02:18 -0400 Message-Id: <20230517110232.29349-14-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This commit introduces code to create and maintain P4 tables within a P4 program from user space and the next patch will have the code for maintaining entries in the table. As with all other P4TC objects, tables conform to CRUD operations and it's important to note that write operations, such as create, update and delete, can only be made if the pipeline is not sealed. Per the P4 specification, tables prefix their name with the control block (although this could be overridden by P4 annotations). As an example, if one were to create a table named table1 in a pipeline named myprog1, on control block "mycontrol", one would use the following command: tc p4template create table/myprog1/mycontrol/table1 tblid 1 \ keysz 32 nummasks 8 tentries 8192 Above says that we are creating a table (table1) attached to pipeline myprog1 on control block mycontrol which is called table1. Its key size is 32 bits and it can have up to 8 masks and 8192. The table id for table1 is 1. The table id is typically provided by the compiler. Parameters such as nummasks (number of masks this table may have) and tentries (maximum number of entries this table may have) may also be omitted in which case 8 masks and 256 entries will be assumed. If one were to retrieve the table named table1 (before or after the pipeline is sealed) one would use the following command: tc p4template get table/myprog1/mycontrol/table1 If one were to dump all the tables from a pipeline named myprog1, one would use the following command: tc p4template get table/myprog1 If one were to update table1 (before the pipeline is sealed) one would use the following command: tc p4template update table/myprog1/mycontrol/table1 .... If one were to delete table1 (before the pipeline is sealed) one would use the following command: tc p4template del table/myprog1/mycontrol/table1 If one were to flush all the tables from a pipeline named myprog1, control block "mycontrol" one would use the following command: tc p4template del table/myprog1/mycontrol/ ___Table Permissions___ Tables can have permissions which apply to all the entries in the specified table. Permissions are defined for both what the control plane (user space) is allowed to do as well as datapath. The permissions field is a 16bit value which will hold CRUDX (create, read, update, delete and execute) permissions for control and data path. Bits 9-5 will have the CRUDX values for control and bits 4-0 will have CRUDX values for data path. By default each table has the following permissions: CRUD--R--X Which means the control plane can perform CRUD operations whereas the data path can only Read and execute on the entries. The user can override these permissions when creating the table or when updating. For example, the following command will create a table which will not allow the datapath to create, update or delete entries but give full CRUD permissions for the control plane. $TC p4template create table/aP4proggie/cb/tname tblid 1 keysz 64 permissions 0x349 ... Recall that these permissions come in the form of CRUDXCRUDX, where the first CRUDX block is for control and the last is for data path. So 0x349 is equivalent to CR-D--R--X If we were to do a get with the following command: $TC p4template get table/aP4proggie/cb/tname The output would be the following: pipeline name aP4proggie pipeline id 22 table id 1 table name cb/tname key_sz 64 max entries 256 masks 8 table entries 0 permissions CR-D--R--X Note, the permissions concept is more powerful than classical const definition currently taken by P4 which makes everything in a table read-only. ___Initial Table Entries___ Templating can create initial table entries. For example: tc p4template update table/myprog/cb/tname \ entry srcAddr 10.10.10.10/24 dstAddr 1.1.1.0/24 prio 17 In this command we are "updating" table cb/tname with a new entry. This entry has as its key srcAddr concatenated with dstAddr (both IPv4 addresses) and prio 17. If one was to read back the entry by issuing the following command: tc p4template get myprog/table/cb/tname They would get: pipeline id 22 table id 1 table name cb/tname key_sz 64 max entries 256 masks 8 table entries 1 permissions CRUD--R--X entry: table id 1 entry priority 17 key blob 101010a0a0a0a mask blob ffffff00ffffff create whodunnit tc permissions -RUD--R--X ___Table Actions List___ P4 tables allow certain actions but not other to be part of match entry on a table or as default actions when there is a miss. We also allow flags for each of the actions in this list that specify if the action can be added only as a table entry (tableonly), or only as a default action (defaultonly). If no flags are specified, it is assumed that the action can be used in both contexts. In P4TC we extend the concept of default action - which in P4 is mapped to "a default miss action". Our extension is to add a "hit action" which is executed every time there is a hit. The default miss action will be executed whenever a table lookup doesn't match any of the entries. Both default hit and default miss are optional. An example of specifying a default miss action is as follows: tc p4template update table/myprog/cb/mytable \ default_miss_action permissions 0x109 action drop The above will drop packets if the entry is not found in mytable. Note the above makes the default action a const. Meaning the control plane can neither replace it nor delete it. tc p4template update table/myprog/mytable \ default_hit_action permissions 0x30F action ok Whereas the above allows a default hit action to accept the packet. The permission 0x30F in binary is (1100001111), which means we have only Create and Read permissions in the control plane and Read, Update, Delete and eXecute permissions in the data plane. This means, for example, that now we can only delete the default hit action from the data plane. __Packet Flow___ As with the pipeline, we also have preactions and postactions for tables which can be programmed to teach the kernel how to process the packet. Both are optional. When a table apply() cmd is invoked on a table: 1) The table preaction if present is invoked 2) A "key action" is invoked to construct the table key 3) A table lookup is done using the key from #2 4a) If there is a hit - the match entry action will be executed - if there was a match and the entry has no action and a default hit action has been specified then the default hit action will be executed. 4b) If there was a miss - if there was a default miss action it will be executed then 5) if there is table post action then that is invoked next Example of how one would create a key action for a table: tc p4template create action/myprog/mytable/tkey \ cmd set key.myprog.cb/mytable \ hdrfield.myprog.parser1.ipv4.dstAddr and now bind the key action to the table "mytable" $TC p4template update table/myprog/cb/mytable \ key action myprog/mytable/tkey Example of how one would create a table post action is: tc p4template create action/myprog/mytable/T_mytable_POA \ cmd print prefix T_mytable_POA_res results.hit \ cmd print prefix T_mytable_POA hdrfield.myprog.parser1.ipv4.dstAddr Activate it.. tc p4template update action/myprog/mytable/T_mytable_POA state active bind it.. $TC p4template update table/myprog/cb/mytable postactions \ action myprog/mytable/T_mytable_POA Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/p4tc.h | 92 ++ include/net/p4tc_types.h | 2 +- include/uapi/linux/p4tc.h | 112 +++ net/sched/p4tc/Makefile | 2 +- net/sched/p4tc/p4tc_pipeline.c | 15 +- net/sched/p4tc/p4tc_table.c | 1664 ++++++++++++++++++++++++++++++++ net/sched/p4tc/p4tc_tmpl_api.c | 2 + 7 files changed, 1886 insertions(+), 3 deletions(-) create mode 100644 net/sched/p4tc/p4tc_table.c diff --git a/include/net/p4tc.h b/include/net/p4tc.h index 6111566b05eb..fa8c6a43c6d3 100644 --- a/include/net/p4tc.h +++ b/include/net/p4tc.h @@ -16,11 +16,18 @@ #define P4TC_DEFAULT_MAX_RULES 1 #define P4TC_MAXMETA_OFFSET 512 #define P4TC_PATH_MAX 3 +#define P4TC_MAX_TENTRIES (2 << 23) +#define P4TC_DEFAULT_TENTRIES 256 +#define P4TC_MAX_TMASKS 1024 +#define P4TC_DEFAULT_TMASKS 8 + +#define P4TC_MAX_PERMISSION (GENMASK(P4TC_PERM_MAX_BIT, 0)) #define P4TC_KERNEL_PIPEID 0 #define P4TC_PID_IDX 0 #define P4TC_MID_IDX 1 +#define P4TC_TBLID_IDX 1 #define P4TC_AID_IDX 1 #define P4TC_PARSEID_IDX 1 #define P4TC_HDRFIELDID_IDX 2 @@ -111,6 +118,7 @@ struct p4tc_pipeline { struct p4tc_template_common common; struct idr p_meta_idr; struct idr p_act_idr; + struct idr p_tbl_idr; struct rcu_head rcu; struct net *net; struct p4tc_parser *parser; @@ -197,6 +205,70 @@ struct p4tc_metadata { extern const struct p4tc_template_ops p4tc_meta_ops; +struct p4tc_table_key { + struct tc_action **key_acts; + int key_num_acts; +}; + +#define P4TC_CONTROL_PERMISSIONS (GENMASK(9, 5)) +#define P4TC_DATA_PERMISSIONS (GENMASK(4, 0)) + +#define P4TC_TABLE_PERMISSIONS \ + ((GENMASK(P4TC_CTRL_PERM_C_BIT, P4TC_CTRL_PERM_D_BIT)) | \ + P4TC_DATA_PERM_R | P4TC_DATA_PERM_X) + +#define P4TC_PERMISSIONS_UNINIT (1 << P4TC_PERM_MAX_BIT) + +struct p4tc_table_defact { + struct tc_action **default_acts; + /* Will have 2 5 bits blocks containing CRUDX (Create, read, update, + * delete, execute) permissions for control plane and data plane. + * The first 5 bits are for control and the next five are for data plane. + * |crudxcrudx| if we were to denote it as UNIX permission flags. + */ + __u16 permissions; + struct rcu_head rcu; +}; + +struct p4tc_table_perm { + __u16 permissions; + struct rcu_head rcu; +}; + +struct p4tc_table { + struct p4tc_template_common common; + struct list_head tbl_acts_list; + struct p4tc_table_key *tbl_key; + struct idr tbl_masks_idr; + struct idr tbl_prio_idr; + struct rhltable tbl_entries; + struct tc_action **tbl_preacts; + struct tc_action **tbl_postacts; + struct p4tc_table_defact __rcu *tbl_default_hitact; + struct p4tc_table_defact __rcu *tbl_default_missact; + struct p4tc_table_perm __rcu *tbl_permissions; + struct p4tc_table_entry_mask __rcu **tbl_masks_array; + unsigned long __rcu *tbl_free_masks_bitmap; + spinlock_t tbl_masks_idr_lock; + spinlock_t tbl_prio_idr_lock; + int tbl_num_postacts; + int tbl_num_preacts; + u32 tbl_count; + u32 tbl_curr_count; + u32 tbl_keysz; + u32 tbl_id; + u32 tbl_max_entries; + u32 tbl_max_masks; + u32 tbl_curr_used_entries; + u32 tbl_curr_num_masks; + refcount_t tbl_ctrl_ref; + refcount_t tbl_ref; + refcount_t tbl_entries_ref; + u16 tbl_type; +}; + +extern const struct p4tc_template_ops p4tc_table_ops; + struct p4tc_ipv4_param_value { u32 value; u32 mask; @@ -254,6 +326,12 @@ struct p4tc_act { refcount_t a_ref; }; +struct p4tc_table_act { + struct list_head node; + struct tc_action_ops *ops; + u8 flags; +}; + extern const struct p4tc_template_ops p4tc_act_ops; extern const struct rhashtable_params p4tc_label_ht_params; extern const struct rhashtable_params acts_params; @@ -352,6 +430,19 @@ struct p4tc_act_param *tcf_param_find_byany(struct p4tc_act *act, const u32 param_id, struct netlink_ext_ack *extack); +struct p4tc_table *tcf_table_find_byany(struct p4tc_pipeline *pipeline, + const char *tblname, const u32 tbl_id, + struct netlink_ext_ack *extack); +struct p4tc_table *tcf_table_find_byid(struct p4tc_pipeline *pipeline, + const u32 tbl_id); +void *tcf_table_fetch(struct sk_buff *skb, void *tbl_value_ops); +int tcf_table_try_set_state_ready(struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack); +struct p4tc_table *tcf_table_get(struct p4tc_pipeline *pipeline, + const char *tblname, const u32 tbl_id, + struct netlink_ext_ack *extack); +void tcf_table_put_ref(struct p4tc_table *table); + struct p4tc_parser *tcf_parser_create(struct p4tc_pipeline *pipeline, const char *parser_name, u32 parser_inst_id, @@ -402,5 +493,6 @@ int generic_dump_param_value(struct sk_buff *skb, struct p4tc_type *type, #define to_meta(t) ((struct p4tc_metadata *)t) #define to_hdrfield(t) ((struct p4tc_hdrfield *)t) #define to_act(t) ((struct p4tc_act *)t) +#define to_table(t) ((struct p4tc_table *)t) #endif diff --git a/include/net/p4tc_types.h b/include/net/p4tc_types.h index 26594c0b0298..bd3217c938ca 100644 --- a/include/net/p4tc_types.h +++ b/include/net/p4tc_types.h @@ -8,7 +8,7 @@ #include -#define P4T_MAX_BITSZ 128 +#define P4T_MAX_BITSZ P4TC_MAX_KEYSZ struct p4tc_type_mask_shift { void *mask; diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h index 15876c471266..99a24ce8f319 100644 --- a/include/uapi/linux/p4tc.h +++ b/include/uapi/linux/p4tc.h @@ -31,6 +31,70 @@ struct p4tcmsg { #define PARSERNAMSIZ TEMPLATENAMSZ #define HDRFIELDNAMSIZ TEMPLATENAMSZ #define ACTPARAMNAMSIZ TEMPLATENAMSZ +#define TABLENAMSIZ TEMPLATENAMSZ + +#define P4TC_TABLE_FLAGS_KEYSZ 0x01 +#define P4TC_TABLE_FLAGS_MAX_ENTRIES 0x02 +#define P4TC_TABLE_FLAGS_MAX_MASKS 0x04 +#define P4TC_TABLE_FLAGS_DEFAULT_KEY 0x08 +#define P4TC_TABLE_FLAGS_PERMISSIONS 0x10 +#define P4TC_TABLE_FLAGS_TYPE 0x20 + +enum { + P4TC_TABLE_TYPE_EXACT = 1, + P4TC_TABLE_TYPE_LPM = 2, + __P4TC_TABLE_TYPE_MAX, +}; +#define P4TC_TABLE_TYPE_MAX (__P4TC_TABLE_TYPE_MAX - 1) + +#define P4TC_CTRL_PERM_C_BIT 9 +#define P4TC_CTRL_PERM_R_BIT 8 +#define P4TC_CTRL_PERM_U_BIT 7 +#define P4TC_CTRL_PERM_D_BIT 6 +#define P4TC_CTRL_PERM_X_BIT 5 + +#define P4TC_DATA_PERM_C_BIT 4 +#define P4TC_DATA_PERM_R_BIT 3 +#define P4TC_DATA_PERM_U_BIT 2 +#define P4TC_DATA_PERM_D_BIT 1 +#define P4TC_DATA_PERM_X_BIT 0 + +#define P4TC_PERM_MAX_BIT P4TC_CTRL_PERM_C_BIT + +#define P4TC_CTRL_PERM_C (1 << P4TC_CTRL_PERM_C_BIT) +#define P4TC_CTRL_PERM_R (1 << P4TC_CTRL_PERM_R_BIT) +#define P4TC_CTRL_PERM_U (1 << P4TC_CTRL_PERM_U_BIT) +#define P4TC_CTRL_PERM_D (1 << P4TC_CTRL_PERM_D_BIT) +#define P4TC_CTRL_PERM_X (1 << P4TC_CTRL_PERM_X_BIT) + +#define P4TC_DATA_PERM_C (1 << P4TC_DATA_PERM_C_BIT) +#define P4TC_DATA_PERM_R (1 << P4TC_DATA_PERM_R_BIT) +#define P4TC_DATA_PERM_U (1 << P4TC_DATA_PERM_U_BIT) +#define P4TC_DATA_PERM_D (1 << P4TC_DATA_PERM_D_BIT) +#define P4TC_DATA_PERM_X (1 << P4TC_DATA_PERM_X_BIT) + +#define p4tc_ctrl_create_ok(perm) (perm & P4TC_CTRL_PERM_C) +#define p4tc_ctrl_read_ok(perm) (perm & P4TC_CTRL_PERM_R) +#define p4tc_ctrl_update_ok(perm) (perm & P4TC_CTRL_PERM_U) +#define p4tc_ctrl_delete_ok(perm) (perm & P4TC_CTRL_PERM_D) +#define p4tc_ctrl_exec_ok(perm) (perm & P4TC_CTRL_PERM_X) + +#define p4tc_data_create_ok(perm) (perm & P4TC_DATA_PERM_C) +#define p4tc_data_read_ok(perm) (perm & P4TC_DATA_PERM_R) +#define p4tc_data_update_ok(perm) (perm & P4TC_DATA_PERM_U) +#define p4tc_data_delete_ok(perm) (perm & P4TC_DATA_PERM_D) +#define p4tc_data_exec_ok(perm) (perm & P4TC_DATA_PERM_X) + +struct p4tc_table_parm { + __u32 tbl_keysz; + __u32 tbl_max_entries; + __u32 tbl_max_masks; + __u32 tbl_flags; + __u32 tbl_num_entries; + __u16 tbl_permissions; + __u8 tbl_type; + __u8 PAD0; +}; #define LABELNAMSIZ 32 @@ -63,6 +127,7 @@ enum { P4TC_OBJ_META, P4TC_OBJ_HDR_FIELD, P4TC_OBJ_ACT, + P4TC_OBJ_TABLE, __P4TC_OBJ_MAX, }; #define P4TC_OBJ_MAX __P4TC_OBJ_MAX @@ -161,6 +226,53 @@ enum { }; #define P4TC_KERNEL_META_MAX (__P4TC_KERNEL_META_MAX - 1) +/* Table key attributes */ +enum { + P4TC_KEY_UNSPEC, + P4TC_KEY_ACT, /* nested key actions */ + __P4TC_TKEY_MAX +}; +#define P4TC_TKEY_MAX __P4TC_TKEY_MAX + +enum { + P4TC_TABLE_DEFAULT_UNSPEC, + P4TC_TABLE_DEFAULT_ACTION, + P4TC_TABLE_DEFAULT_PERMISSIONS, + __P4TC_TABLE_DEFAULT_MAX +}; +#define P4TC_TABLE_DEFAULT_MAX (__P4TC_TABLE_DEFAULT_MAX - 1) + +enum { + P4TC_TABLE_ACTS_DEFAULT_ONLY, + P4TC_TABLE_ACTS_TABLE_ONLY, + __P4TC_TABLE_ACTS_FLAGS_MAX, +}; +#define P4TC_TABLE_ACTS_FLAGS_MAX (__P4TC_TABLE_ACTS_FLAGS_MAX - 1) + +enum { + P4TC_TABLE_ACT_UNSPEC, + P4TC_TABLE_ACT_FLAGS, /* u8 */ + P4TC_TABLE_ACT_NAME, /* string */ + __P4TC_TABLE_ACT_MAX +}; +#define P4TC_TABLE_ACT_MAX (__P4TC_TABLE_ACT_MAX - 1) + +/* Table type attributes */ +enum { + P4TC_TABLE_UNSPEC, + P4TC_TABLE_NAME, /* string */ + P4TC_TABLE_INFO, /* struct tc_p4_table_type_parm */ + P4TC_TABLE_PREACTIONS, /* nested table preactions */ + P4TC_TABLE_KEY, /* nested table key */ + P4TC_TABLE_POSTACTIONS, /* nested table postactions */ + P4TC_TABLE_DEFAULT_HIT, /* nested default hit action attributes */ + P4TC_TABLE_DEFAULT_MISS, /* nested default miss action attributes */ + P4TC_TABLE_OPT_ENTRY, /* nested const table entry*/ + P4TC_TABLE_ACTS_LIST, /* nested table actions list */ + __P4TC_TABLE_MAX +}; +#define P4TC_TABLE_MAX __P4TC_TABLE_MAX + struct p4tc_hdrfield_ty { __u16 startbit; __u16 endbit; diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index 3f7267366827..de3a7b83305c 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.o p4tc_meta.o \ - p4tc_parser_api.o p4tc_hdrfield.o p4tc_action.o + p4tc_parser_api.o p4tc_hdrfield.o p4tc_action.o p4tc_table.o diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c index e4cb5ad994e8..51b47b07ba65 100644 --- a/net/sched/p4tc/p4tc_pipeline.c +++ b/net/sched/p4tc/p4tc_pipeline.c @@ -297,6 +297,7 @@ static void tcf_pipeline_destroy(struct p4tc_pipeline *pipeline, { idr_destroy(&pipeline->p_meta_idr); idr_destroy(&pipeline->p_act_idr); + idr_destroy(&pipeline->p_tbl_idr); if (free_pipeline) kfree(pipeline); @@ -323,8 +324,9 @@ static int tcf_pipeline_put(struct net *net, struct p4tc_pipeline *pipeline = to_pipeline(template); struct net *pipeline_net = maybe_get_net(net); struct p4tc_act_dep_node *act_node, *node_tmp; - unsigned long m_id, tmp; + unsigned long tbl_id, m_id, tmp; struct p4tc_metadata *meta; + struct p4tc_table *table; if (pipeline_net && !refcount_dec_if_one(&pipeline->p_ref)) { NL_SET_ERR_MSG(extack, "Can't delete referenced pipeline"); @@ -339,6 +341,9 @@ static int tcf_pipeline_put(struct net *net, p4tc_action_destroy(pipeline->preacts); p4tc_action_destroy(pipeline->postacts); + idr_for_each_entry_ul(&pipeline->p_tbl_idr, table, tmp, tbl_id) + table->common.ops->put(net, &table->common, true, extack); + act_dep_graph_free(&pipeline->act_dep_graph); list_for_each_entry_safe(act_node, node_tmp, @@ -371,6 +376,8 @@ static int tcf_pipeline_put(struct net *net, static inline int pipeline_try_set_state_ready(struct p4tc_pipeline *pipeline, struct netlink_ext_ack *extack) { + int ret; + if (pipeline->curr_tables != pipeline->num_tables) { NL_SET_ERR_MSG(extack, "Must have all table defined to update state to ready"); @@ -388,6 +395,9 @@ static inline int pipeline_try_set_state_ready(struct p4tc_pipeline *pipeline, "Must specify pipeline postactions before sealing"); return -EINVAL; } + ret = tcf_table_try_set_state_ready(pipeline, extack); + if (ret < 0) + return ret; /* Will never fail in this case */ determine_act_topological_order(pipeline, false); @@ -542,6 +552,9 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, idr_init(&pipeline->p_act_idr); + idr_init(&pipeline->p_tbl_idr); + pipeline->curr_tables = 0; + idr_init(&pipeline->p_meta_idr); pipeline->p_meta_offset = 0; diff --git a/net/sched/p4tc/p4tc_table.c b/net/sched/p4tc/p4tc_table.c new file mode 100644 index 000000000000..1ae4ed6d39e9 --- /dev/null +++ b/net/sched/p4tc/p4tc_table.c @@ -0,0 +1,1664 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_table.c P4 TC TABLE + * + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define P4TC_P_UNSPEC 0 +#define P4TC_P_CREATED 1 + +static int tcf_key_try_set_state_ready(struct p4tc_table_key *key, + struct netlink_ext_ack *extack) +{ + if (!key->key_acts) { + NL_SET_ERR_MSG(extack, + "Table key must have actions before sealing pipelline"); + return -EINVAL; + } + + return 0; +} + +static int __tcf_table_try_set_state_ready(struct p4tc_table *table, + struct netlink_ext_ack *extack) +{ + int i; + int ret; + + if (!table->tbl_postacts) { + NL_SET_ERR_MSG(extack, + "All tables must have postactions before sealing pipelline"); + return -EINVAL; + } + + if (!table->tbl_key) { + NL_SET_ERR_MSG(extack, + "Table must have key before sealing pipeline"); + return -EINVAL; + } + + ret = tcf_key_try_set_state_ready(table->tbl_key, extack); + if (ret < 0) + return ret; + + table->tbl_masks_array = kcalloc(table->tbl_max_masks, + sizeof(*(table->tbl_masks_array)), + GFP_KERNEL); + if (!table->tbl_masks_array) + return -ENOMEM; + + table->tbl_free_masks_bitmap = + bitmap_alloc(P4TC_MAX_TMASKS, GFP_KERNEL); + if (!table->tbl_free_masks_bitmap) { + kfree(table->tbl_masks_array); + return -ENOMEM; + } + + bitmap_fill(table->tbl_free_masks_bitmap, P4TC_MAX_TMASKS); + + return 0; +} + +void free_table_cache_array(struct p4tc_table **set_tables, + int num_tables) +{ + int i; + + for (i = 0; i < num_tables; i++) { + struct p4tc_table *table = set_tables[i]; + + kfree(table->tbl_masks_array); + bitmap_free(table->tbl_free_masks_bitmap); + } +} + +int tcf_table_try_set_state_ready(struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + int i = 0; + struct p4tc_table **set_tables; + struct p4tc_table *table; + unsigned long tmp, id; + int ret; + + set_tables = kcalloc(pipeline->num_tables, sizeof(*set_tables), + GFP_KERNEL); + if (!set_tables) + return -ENOMEM; + + idr_for_each_entry_ul(&pipeline->p_tbl_idr, table, tmp, id) { + ret = __tcf_table_try_set_state_ready(table, extack); + if (ret < 0) + goto free_set_tables; + set_tables[i] = table; + i++; + } + kfree(set_tables); + + return 0; + +free_set_tables: + free_table_cache_array(set_tables, i); + kfree(set_tables); + return ret; +} + +static const struct nla_policy p4tc_table_policy[P4TC_TABLE_MAX + 1] = { + [P4TC_TABLE_NAME] = { .type = NLA_STRING, .len = TABLENAMSIZ }, + [P4TC_TABLE_INFO] = { .type = NLA_BINARY, + .len = sizeof(struct p4tc_table_parm) }, + [P4TC_TABLE_PREACTIONS] = { .type = NLA_NESTED }, + [P4TC_TABLE_KEY] = { .type = NLA_NESTED }, + [P4TC_TABLE_POSTACTIONS] = { .type = NLA_NESTED }, + [P4TC_TABLE_DEFAULT_HIT] = { .type = NLA_NESTED }, + [P4TC_TABLE_DEFAULT_MISS] = { .type = NLA_NESTED }, + [P4TC_TABLE_ACTS_LIST] = { .type = NLA_NESTED }, + [P4TC_TABLE_OPT_ENTRY] = { .type = NLA_NESTED }, +}; + +static const struct nla_policy p4tc_table_key_policy[P4TC_MAXPARSE_KEYS + 1] = { + [P4TC_KEY_ACT] = { .type = NLA_NESTED }, +}; + +static int tcf_table_key_fill_nlmsg(struct sk_buff *skb, + struct p4tc_table_key *key) +{ + int ret = 0; + struct nlattr *nest_action; + + if (key->key_acts) { + nest_action = nla_nest_start(skb, P4TC_KEY_ACT); + ret = tcf_action_dump(skb, key->key_acts, 0, 0, false); + if (ret < 0) + return ret; + nla_nest_end(skb, nest_action); + } + + return ret; +} + +static int _tcf_table_fill_nlmsg(struct sk_buff *skb, struct p4tc_table *table) +{ + unsigned char *b = nlmsg_get_pos(skb); + int i = 1; + struct p4tc_table_perm *tbl_perm; + struct p4tc_table_act *table_act; + struct nlattr *nested_tbl_acts; + struct nlattr *default_missact; + struct nlattr *default_hitact; + struct nlattr *nested_count; + struct p4tc_table_parm parm; + struct nlattr *nest_key; + struct nlattr *nest; + struct nlattr *preacts; + struct nlattr *postacts; + int err; + + if (nla_put_u32(skb, P4TC_PATH, table->tbl_id)) + goto out_nlmsg_trim; + + nest = nla_nest_start(skb, P4TC_PARAMS); + if (!nest) + goto out_nlmsg_trim; + + if (nla_put_string(skb, P4TC_TABLE_NAME, table->common.name)) + goto out_nlmsg_trim; + + parm.tbl_keysz = table->tbl_keysz; + parm.tbl_max_entries = table->tbl_max_entries; + parm.tbl_max_masks = table->tbl_max_masks; + parm.tbl_num_entries = refcount_read(&table->tbl_entries_ref) - 1; + + tbl_perm = rcu_dereference_rtnl(table->tbl_permissions); + parm.tbl_permissions = tbl_perm->permissions; + + if (table->tbl_key) { + nest_key = nla_nest_start(skb, P4TC_TABLE_KEY); + err = tcf_table_key_fill_nlmsg(skb, table->tbl_key); + if (err < 0) + goto out_nlmsg_trim; + nla_nest_end(skb, nest_key); + } + + if (table->tbl_preacts) { + preacts = nla_nest_start(skb, P4TC_TABLE_PREACTIONS); + if (tcf_action_dump(skb, table->tbl_preacts, 0, 0, false) < 0) + goto out_nlmsg_trim; + nla_nest_end(skb, preacts); + } + + if (table->tbl_postacts) { + postacts = nla_nest_start(skb, P4TC_TABLE_POSTACTIONS); + if (tcf_action_dump(skb, table->tbl_postacts, 0, 0, false) < 0) + goto out_nlmsg_trim; + nla_nest_end(skb, postacts); + } + + if (table->tbl_default_hitact) { + struct p4tc_table_defact *hitact; + + default_hitact = nla_nest_start(skb, P4TC_TABLE_DEFAULT_HIT); + rcu_read_lock(); + hitact = rcu_dereference_rtnl(table->tbl_default_hitact); + if (hitact->default_acts) { + struct nlattr *nest; + + nest = nla_nest_start(skb, P4TC_TABLE_DEFAULT_ACTION); + if (tcf_action_dump(skb, hitact->default_acts, 0, 0, + false) < 0) { + rcu_read_unlock(); + goto out_nlmsg_trim; + } + nla_nest_end(skb, nest); + } + if (nla_put_u16(skb, P4TC_TABLE_DEFAULT_PERMISSIONS, + hitact->permissions) < 0) { + rcu_read_unlock(); + goto out_nlmsg_trim; + } + rcu_read_unlock(); + nla_nest_end(skb, default_hitact); + } + + if (table->tbl_default_missact) { + struct p4tc_table_defact *missact; + + default_missact = nla_nest_start(skb, P4TC_TABLE_DEFAULT_MISS); + rcu_read_lock(); + missact = rcu_dereference_rtnl(table->tbl_default_missact); + if (missact->default_acts) { + struct nlattr *nest; + + nest = nla_nest_start(skb, P4TC_TABLE_DEFAULT_ACTION); + if (tcf_action_dump(skb, missact->default_acts, 0, 0, + false) < 0) { + rcu_read_unlock(); + goto out_nlmsg_trim; + } + nla_nest_end(skb, nest); + } + if (nla_put_u16(skb, P4TC_TABLE_DEFAULT_PERMISSIONS, + missact->permissions) < 0) { + rcu_read_unlock(); + goto out_nlmsg_trim; + } + rcu_read_unlock(); + nla_nest_end(skb, default_missact); + } + + nested_tbl_acts = nla_nest_start(skb, P4TC_TABLE_ACTS_LIST); + list_for_each_entry(table_act, &table->tbl_acts_list, node) { + nested_count = nla_nest_start(skb, i); + if (nla_put_string(skb, P4TC_TABLE_ACT_NAME, + table_act->ops->kind) < 0) + goto out_nlmsg_trim; + if (nla_put_u32(skb, P4TC_TABLE_ACT_FLAGS, + table_act->flags) < 0) + goto out_nlmsg_trim; + + nla_nest_end(skb, nested_count); + i++; + } + nla_nest_end(skb, nested_tbl_acts); + + if (nla_put(skb, P4TC_TABLE_INFO, sizeof(parm), &parm)) + goto out_nlmsg_trim; + nla_nest_end(skb, nest); + + return skb->len; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -1; +} + +static int tcf_table_fill_nlmsg(struct net *net, struct sk_buff *skb, + struct p4tc_template_common *template, + struct netlink_ext_ack *extack) +{ + struct p4tc_table *table = to_table(template); + + if (_tcf_table_fill_nlmsg(skb, table) <= 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for table"); + return -EINVAL; + } + + return 0; +} + +static inline void tcf_table_key_put(struct p4tc_table_key *key) +{ + p4tc_action_destroy(key->key_acts); + kfree(key); +} + +static inline void p4tc_table_defact_destroy(struct p4tc_table_defact *defact) +{ + if (defact) { + p4tc_action_destroy(defact->default_acts); + kfree(defact); + } +} + +void tcf_table_acts_list_destroy(struct list_head *acts_list) +{ + struct p4tc_table_act *table_act, *tmp; + + list_for_each_entry_safe(table_act, tmp, acts_list, node) { + struct p4tc_act *act; + + act = container_of(table_act->ops, typeof(*act), ops); + list_del(&table_act->node); + kfree(table_act); + WARN_ON(!refcount_dec_not_one(&act->a_ref)); + } +} + +static inline int _tcf_table_put(struct net *net, struct nlattr **tb, + struct p4tc_pipeline *pipeline, + struct p4tc_table *table, + bool unconditional_purge, + struct netlink_ext_ack *extack) +{ + bool default_act_del = false; + struct p4tc_table_perm *perm; + + if (tb) + default_act_del = tb[P4TC_TABLE_DEFAULT_HIT] || + tb[P4TC_TABLE_DEFAULT_MISS]; + + if (!default_act_del) { + if (!unconditional_purge && + !refcount_dec_if_one(&table->tbl_ctrl_ref)) { + NL_SET_ERR_MSG(extack, + "Unable to delete referenced table"); + return -EBUSY; + } + + if (!unconditional_purge && + !refcount_dec_if_one(&table->tbl_ref)) { + refcount_set(&table->tbl_ctrl_ref, 1); + NL_SET_ERR_MSG(extack, + "Unable to delete referenced table"); + return -EBUSY; + } + } + + if (tb && tb[P4TC_TABLE_DEFAULT_HIT]) { + struct p4tc_table_defact *hitact; + + rcu_read_lock(); + hitact = rcu_dereference(table->tbl_default_hitact); + if (hitact && !p4tc_ctrl_delete_ok(hitact->permissions)) { + NL_SET_ERR_MSG(extack, + "Permission denied: Unable to delete default hitact"); + rcu_read_unlock(); + return -EPERM; + } + rcu_read_unlock(); + } + + if (tb && tb[P4TC_TABLE_DEFAULT_MISS]) { + struct p4tc_table_defact *missact; + + rcu_read_lock(); + missact = rcu_dereference(table->tbl_default_missact); + if (missact && !p4tc_ctrl_delete_ok(missact->permissions)) { + NL_SET_ERR_MSG(extack, + "Permission denied: Unable to delete default missact"); + rcu_read_unlock(); + return -EPERM; + } + rcu_read_unlock(); + } + + if (!default_act_del || tb[P4TC_TABLE_DEFAULT_HIT]) { + struct p4tc_table_defact *hitact; + + hitact = rtnl_dereference(table->tbl_default_hitact); + if (hitact) { + rcu_replace_pointer_rtnl(table->tbl_default_hitact, + NULL); + synchronize_rcu(); + p4tc_table_defact_destroy(hitact); + } + } + + if (!default_act_del || tb[P4TC_TABLE_DEFAULT_MISS]) { + struct p4tc_table_defact *missact; + + missact = rtnl_dereference(table->tbl_default_missact); + if (missact) { + rcu_replace_pointer_rtnl(table->tbl_default_missact, + NULL); + synchronize_rcu(); + p4tc_table_defact_destroy(missact); + } + } + + if (default_act_del) + return 0; + + if (table->tbl_key) + tcf_table_key_put(table->tbl_key); + + p4tc_action_destroy(table->tbl_preacts); + p4tc_action_destroy(table->tbl_postacts); + + tcf_table_acts_list_destroy(&table->tbl_acts_list); + + idr_destroy(&table->tbl_masks_idr); + idr_destroy(&table->tbl_prio_idr); + + perm = rcu_replace_pointer_rtnl(table->tbl_permissions, NULL); + kfree_rcu(perm, rcu); + + idr_remove(&pipeline->p_tbl_idr, table->tbl_id); + pipeline->curr_tables -= 1; + + kfree(table->tbl_masks_array); + bitmap_free(table->tbl_free_masks_bitmap); + + kfree(table); + + return 0; +} + +static int tcf_table_put(struct net *net, struct p4tc_template_common *tmpl, + bool unconditional_purge, + struct netlink_ext_ack *extack) +{ + struct p4tc_pipeline *pipeline = + tcf_pipeline_find_byid(net, tmpl->p_id); + struct p4tc_table *table = to_table(tmpl); + + return _tcf_table_put(net, NULL, pipeline, table, unconditional_purge, + extack); +} + +static inline struct p4tc_table_key * +tcf_table_key_add(struct net *net, struct p4tc_table *table, struct nlattr *nla, + struct netlink_ext_ack *extack) +{ + int ret = 0; + struct nlattr *tb[P4TC_TKEY_MAX + 1]; + struct p4tc_table_key *key; + + ret = nla_parse_nested(tb, P4TC_TKEY_MAX, nla, p4tc_table_key_policy, + extack); + if (ret < 0) + goto out; + + key = kzalloc(sizeof(*key), GFP_KERNEL); + if (!key) { + NL_SET_ERR_MSG(extack, "Failed to allocate table key"); + ret = -ENOMEM; + goto out; + } + + if (tb[P4TC_KEY_ACT]) { + key->key_acts = kcalloc(TCA_ACT_MAX_PRIO, + sizeof(struct tc_action *), GFP_KERNEL); + if (!key->key_acts) { + ret = -ENOMEM; + goto free_key; + } + + ret = p4tc_action_init(net, tb[P4TC_KEY_ACT], key->key_acts, + table->common.p_id, 0, extack); + if (ret < 0) { + kfree(key->key_acts); + goto free_key; + } + key->key_num_acts = ret; + } + + return key; + +free_key: + kfree(key); + +out: + return ERR_PTR(ret); +} + +struct p4tc_table *tcf_table_find_byid(struct p4tc_pipeline *pipeline, + const u32 tbl_id) +{ + return idr_find(&pipeline->p_tbl_idr, tbl_id); +} + +static struct p4tc_table *table_find_byname(const char *tblname, + struct p4tc_pipeline *pipeline) +{ + struct p4tc_table *table; + unsigned long tmp, id; + + idr_for_each_entry_ul(&pipeline->p_tbl_idr, table, tmp, id) + if (strncmp(table->common.name, tblname, TABLENAMSIZ) == 0) + return table; + + return NULL; +} + +#define SEPARATOR '/' +struct p4tc_table *tcf_table_find_byany(struct p4tc_pipeline *pipeline, + const char *tblname, const u32 tbl_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_table *table; + int err; + + if (tbl_id) { + table = tcf_table_find_byid(pipeline, tbl_id); + if (!table) { + NL_SET_ERR_MSG(extack, "Unable to find table by id"); + err = -EINVAL; + goto out; + } + } else { + if (tblname) { + table = table_find_byname(tblname, pipeline); + if (!table) { + NL_SET_ERR_MSG(extack, "Table name not found"); + err = -EINVAL; + goto out; + } + } else { + NL_SET_ERR_MSG(extack, "Must specify table name or id"); + err = -EINVAL; + goto out; + } + } + + return table; +out: + return ERR_PTR(err); +} + +struct p4tc_table *tcf_table_get(struct p4tc_pipeline *pipeline, + const char *tblname, const u32 tbl_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_table *table; + + table = tcf_table_find_byany(pipeline, tblname, tbl_id, extack); + if (IS_ERR(table)) + return table; + + /* Should never be zero */ + WARN_ON(!refcount_inc_not_zero(&table->tbl_ref)); + return table; +} + +void tcf_table_put_ref(struct p4tc_table *table) +{ + /* Should never be zero */ + WARN_ON(!refcount_dec_not_one(&table->tbl_ref)); +} + +static int tcf_table_init_default_act(struct net *net, struct nlattr **tb, + struct p4tc_table_defact **default_act, + u32 pipeid, __u16 curr_permissions, + struct netlink_ext_ack *extack) +{ + int ret; + + *default_act = kzalloc(sizeof(**default_act), GFP_KERNEL); + if (!(*default_act)) + return -ENOMEM; + + if (tb[P4TC_TABLE_DEFAULT_PERMISSIONS]) { + __u16 *permissions; + + permissions = nla_data(tb[P4TC_TABLE_DEFAULT_PERMISSIONS]); + if (!p4tc_data_exec_ok(*permissions)) { + NL_SET_ERR_MSG(extack, + "Default action must have data path execute permissions"); + ret = -EINVAL; + goto default_act_free; + } + (*default_act)->permissions = *permissions; + } else { + (*default_act)->permissions = curr_permissions; + } + + if (tb[P4TC_TABLE_DEFAULT_ACTION]) { + struct tc_action **default_acts; + + if (!p4tc_ctrl_update_ok(curr_permissions)) { + NL_SET_ERR_MSG(extack, + "Permission denied: Unable to update default hit action"); + ret = -EPERM; + goto default_act_free; + } + + default_acts = kcalloc(TCA_ACT_MAX_PRIO, + sizeof(struct tc_action *), GFP_KERNEL); + if (!default_acts) { + ret = -ENOMEM; + goto default_act_free; + } + + ret = p4tc_action_init(net, tb[P4TC_TABLE_DEFAULT_ACTION], + default_acts, pipeid, 0, extack); + if (ret < 0) { + kfree(default_acts); + goto default_act_free; + } else if (ret > 1) { + NL_SET_ERR_MSG(extack, "Can only have one hit action"); + tcf_action_destroy(default_acts, TCA_ACT_UNBIND); + kfree(default_acts); + ret = -EINVAL; + goto default_act_free; + } + (*default_act)->default_acts = default_acts; + } + + return 0; + +default_act_free: + kfree(*default_act); + + return ret; +} + +static int tcf_table_check_defacts(struct tc_action *defact, + struct list_head *acts_list) +{ + struct p4tc_table_act *table_act; + + list_for_each_entry(table_act, acts_list, node) { + if (table_act->ops->id == defact->ops->id && + !(table_act->flags & BIT(P4TC_TABLE_ACTS_TABLE_ONLY))) + return true; + } + + return false; +} + +static struct nla_policy p4tc_table_default_policy[P4TC_TABLE_DEFAULT_MAX + 1] = { + [P4TC_TABLE_DEFAULT_ACTION] = { .type = NLA_NESTED }, + [P4TC_TABLE_DEFAULT_PERMISSIONS] = + NLA_POLICY_MAX(NLA_U16, P4TC_MAX_PERMISSION), +}; + +static int +tcf_table_init_default_acts(struct net *net, struct nlattr **tb, + struct p4tc_table *table, + struct p4tc_table_defact **default_hitact, + struct p4tc_table_defact **default_missact, + struct list_head *acts_list, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb_default[P4TC_TABLE_DEFAULT_MAX + 1]; + __u16 permissions = P4TC_CONTROL_PERMISSIONS | P4TC_DATA_PERMISSIONS; + int ret; + + *default_missact = NULL; + *default_hitact = NULL; + + if (tb[P4TC_TABLE_DEFAULT_HIT]) { + struct p4tc_table_defact *defact; + + rcu_read_lock(); + defact = rcu_dereference(table->tbl_default_hitact); + if (defact) + permissions = defact->permissions; + rcu_read_unlock(); + + ret = nla_parse_nested(tb_default, P4TC_TABLE_DEFAULT_MAX, + tb[P4TC_TABLE_DEFAULT_HIT], + p4tc_table_default_policy, extack); + if (ret < 0) + return ret; + + if (!tb_default[P4TC_TABLE_DEFAULT_ACTION] && + !tb_default[P4TC_TABLE_DEFAULT_PERMISSIONS]) + return 0; + + ret = tcf_table_init_default_act(net, tb_default, + default_hitact, + table->common.p_id, permissions, + extack); + if (ret < 0) + return ret; + if (!tcf_table_check_defacts((*default_hitact)->default_acts[0], + acts_list)) { + ret = -EPERM; + NL_SET_ERR_MSG(extack, + "Action is not allowed as default hit action"); + goto default_hitacts_free; + } + } + + if (tb[P4TC_TABLE_DEFAULT_MISS]) { + struct p4tc_table_defact *defact; + + rcu_read_lock(); + defact = rcu_dereference(table->tbl_default_missact); + if (defact) + permissions = defact->permissions; + rcu_read_unlock(); + + ret = nla_parse_nested(tb_default, P4TC_TABLE_DEFAULT_MAX, + tb[P4TC_TABLE_DEFAULT_MISS], + p4tc_table_default_policy, extack); + if (ret < 0) + goto default_hitacts_free; + + if (!tb_default[P4TC_TABLE_DEFAULT_ACTION] && + !tb_default[P4TC_TABLE_DEFAULT_PERMISSIONS]) + return 0; + + ret = tcf_table_init_default_act(net, tb_default, + default_missact, + table->common.p_id, permissions, + extack); + if (ret < 0) + goto default_hitacts_free; + if (!tcf_table_check_defacts((*default_missact)->default_acts[0], + acts_list)) { + ret = -EPERM; + NL_SET_ERR_MSG(extack, + "Action is not allowed as default miss action"); + goto default_missact_free; + } + } + + return 0; + +default_missact_free: + p4tc_table_defact_destroy(*default_missact); + +default_hitacts_free: + p4tc_table_defact_destroy(*default_hitact); + + return ret; +} + +static const struct nla_policy p4tc_acts_list_policy[P4TC_TABLE_MAX + 1] = { + [P4TC_TABLE_ACT_FLAGS] = + NLA_POLICY_RANGE(NLA_U8, 0, BIT(P4TC_TABLE_ACTS_FLAGS_MAX)), + [P4TC_TABLE_ACT_NAME] = { .type = NLA_STRING, .len = ACTNAMSIZ }, +}; + +static struct p4tc_table_act *tcf_table_act_init(struct nlattr *nla, + struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_TABLE_ACT_MAX + 1]; + struct p4tc_table_act *table_act; + int ret; + + ret = nla_parse_nested(tb, P4TC_TABLE_ACT_MAX, nla, + p4tc_acts_list_policy, extack); + if (ret < 0) + return ERR_PTR(ret); + + table_act = kzalloc(sizeof(*table_act), GFP_KERNEL); + if (!table_act) + return ERR_PTR(-ENOMEM); + + if (tb[P4TC_TABLE_ACT_NAME]) { + const char *actname = nla_data(tb[P4TC_TABLE_ACT_NAME]); + char *act_name_clone, *act_name, *p_name; + struct p4tc_act *act; + + act_name_clone = act_name = kstrdup(actname, GFP_KERNEL); + if (!act_name) { + ret = -ENOMEM; + goto free_table_act; + } + + p_name = strsep(&act_name, "/"); + act = tcf_action_find_byname(act_name, pipeline); + if (!act) { + NL_SET_ERR_MSG_FMT(extack, + "Unable to find action %s/%s", + p_name, act_name); + ret = -ENOENT; + kfree(act_name_clone); + goto free_table_act; + } + + kfree(act_name_clone); + + table_act->ops = &act->ops; + WARN_ON(!refcount_inc_not_zero(&act->a_ref)); + } else { + NL_SET_ERR_MSG(extack, + "Must specify allowed table action name"); + ret = -EINVAL; + goto free_table_act; + } + + if (tb[P4TC_TABLE_ACT_FLAGS]) { + u8 *flags = nla_data(tb[P4TC_TABLE_ACT_FLAGS]); + + table_act->flags = *flags; + } + + return table_act; + +free_table_act: + kfree(table_act); + return ERR_PTR(ret); +} + +static int tcf_table_acts_list_init(struct nlattr *nla, + struct p4tc_pipeline *pipeline, + struct list_head *acts_list, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1]; + struct p4tc_table_act *table_act; + int ret; + int i; + + ret = nla_parse_nested(tb, P4TC_MSGBATCH_SIZE, nla, NULL, extack); + if (ret < 0) + return ret; + + for (i = 1; i < P4TC_MSGBATCH_SIZE + 1 && tb[i]; i++) { + table_act = tcf_table_act_init(tb[i], pipeline, extack); + if (IS_ERR(table_act)) { + ret = PTR_ERR(table_act); + goto free_acts_list_list; + } + list_add_tail(&table_act->node, acts_list); + } + + return 0; + +free_acts_list_list: + tcf_table_acts_list_destroy(acts_list); + + return ret; +} + +static struct p4tc_table * +tcf_table_find_byanyattr(struct p4tc_pipeline *pipeline, + struct nlattr *name_attr, const u32 tbl_id, + struct netlink_ext_ack *extack) +{ + char *tblname = NULL; + + if (name_attr) + tblname = nla_data(name_attr); + + return tcf_table_find_byany(pipeline, tblname, tbl_id, extack); +} + +static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, + u32 tbl_id, + struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + struct p4tc_table_key *key = NULL; + struct p4tc_table_parm *parm; + struct p4tc_table *table; + char *tblname; + int ret; + + if (pipeline->curr_tables == pipeline->num_tables) { + NL_SET_ERR_MSG(extack, + "Table range exceeded max allowed value"); + ret = -EINVAL; + goto out; + } + + if (NL_REQ_ATTR_CHECK(extack, NULL, tb, P4TC_TABLE_NAME)) { + NL_SET_ERR_MSG(extack, "Must specify table name"); + ret = -EINVAL; + goto out; + } + + tblname = + strnchr(nla_data(tb[P4TC_TABLE_NAME]), TABLENAMSIZ, SEPARATOR); + if (!tblname) { + NL_SET_ERR_MSG(extack, "Table name must contain control block"); + ret = -EINVAL; + goto out; + } + + tblname += 1; + if (tblname[0] == '\0') { + NL_SET_ERR_MSG(extack, "Control block name is too big"); + ret = -EINVAL; + goto out; + } + + table = tcf_table_find_byanyattr(pipeline, tb[P4TC_TABLE_NAME], tbl_id, + NULL); + if (!IS_ERR(table)) { + NL_SET_ERR_MSG(extack, "Table already exists"); + ret = -EEXIST; + goto out; + } + + table = kzalloc(sizeof(*table), GFP_KERNEL); + if (!table) { + NL_SET_ERR_MSG(extack, "Unable to create table"); + ret = -ENOMEM; + goto out; + } + + table->common.p_id = pipeline->common.p_id; + strscpy(table->common.name, nla_data(tb[P4TC_TABLE_NAME]), TABLENAMSIZ); + + if (NL_REQ_ATTR_CHECK(extack, NULL, tb, P4TC_TABLE_INFO)) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Missing table info"); + goto free; + } + parm = nla_data(tb[P4TC_TABLE_INFO]); + + if (parm->tbl_flags & P4TC_TABLE_FLAGS_KEYSZ) { + if (!parm->tbl_keysz) { + NL_SET_ERR_MSG(extack, "Table keysz cannot be zero"); + ret = -EINVAL; + goto free; + } + if (parm->tbl_keysz > P4TC_MAX_KEYSZ) { + NL_SET_ERR_MSG(extack, + "Table keysz exceeds maximum keysz"); + ret = -EINVAL; + goto free; + } + table->tbl_keysz = parm->tbl_keysz; + } else { + NL_SET_ERR_MSG(extack, "Must specify table key size"); + ret = -EINVAL; + goto free; + } + + if (parm->tbl_flags & P4TC_TABLE_FLAGS_MAX_ENTRIES) { + if (!parm->tbl_max_entries) { + NL_SET_ERR_MSG(extack, + "Table max_entries cannot be zero"); + ret = -EINVAL; + goto free; + } + if (parm->tbl_max_entries > P4TC_MAX_TENTRIES) { + NL_SET_ERR_MSG(extack, + "Table max_entries exceeds maximum value"); + ret = -EINVAL; + goto free; + } + table->tbl_max_entries = parm->tbl_max_entries; + } else { + table->tbl_max_entries = P4TC_DEFAULT_TENTRIES; + } + + if (parm->tbl_flags & P4TC_TABLE_FLAGS_MAX_MASKS) { + if (!parm->tbl_max_masks) { + NL_SET_ERR_MSG(extack, + "Table max_masks cannot be zero"); + ret = -EINVAL; + goto free; + } + if (parm->tbl_max_masks > P4TC_MAX_TMASKS) { + NL_SET_ERR_MSG(extack, + "Table max_masks exceeds maximum value"); + ret = -EINVAL; + goto free; + } + table->tbl_max_masks = parm->tbl_max_masks; + } else { + table->tbl_max_masks = P4TC_DEFAULT_TMASKS; + } + + if (parm->tbl_flags & P4TC_TABLE_FLAGS_PERMISSIONS) { + if (parm->tbl_permissions > P4TC_MAX_PERMISSION) { + NL_SET_ERR_MSG(extack, + "Permission may only have 10 bits turned on"); + ret = -EINVAL; + goto free; + } + if (!p4tc_data_exec_ok(parm->tbl_permissions)) { + NL_SET_ERR_MSG(extack, + "Table must have execute permissions"); + ret = -EINVAL; + goto free; + } + if (!p4tc_data_read_ok(parm->tbl_permissions)) { + NL_SET_ERR_MSG(extack, + "Data path read permissions must be set"); + ret = -EINVAL; + goto free; + } + table->tbl_permissions = + kzalloc(sizeof(*table->tbl_permissions), GFP_KERNEL); + if (!table->tbl_permissions) { + ret = -ENOMEM; + goto free; + } + table->tbl_permissions->permissions = parm->tbl_permissions; + } else { + table->tbl_permissions = + kzalloc(sizeof(*table->tbl_permissions), GFP_KERNEL); + if (!table->tbl_permissions) { + ret = -ENOMEM; + goto free; + } + table->tbl_permissions->permissions = P4TC_TABLE_PERMISSIONS; + } + + if (parm->tbl_flags & P4TC_TABLE_FLAGS_TYPE) { + if (parm->tbl_type > P4TC_TABLE_TYPE_MAX) { + NL_SET_ERR_MSG(extack, "Table type can only be exact or LPM"); + ret = -EINVAL; + goto free_permissions; + } + table->tbl_type = parm->tbl_type; + } else { + table->tbl_type = P4TC_TABLE_TYPE_EXACT; + } + + refcount_set(&table->tbl_ref, 1); + refcount_set(&table->tbl_ctrl_ref, 1); + + if (tbl_id) { + table->tbl_id = tbl_id; + ret = idr_alloc_u32(&pipeline->p_tbl_idr, table, &table->tbl_id, + table->tbl_id, GFP_KERNEL); + if (ret < 0) { + NL_SET_ERR_MSG(extack, "Unable to allocate table id"); + goto free_permissions; + } + } else { + table->tbl_id = 1; + ret = idr_alloc_u32(&pipeline->p_tbl_idr, table, &table->tbl_id, + UINT_MAX, GFP_KERNEL); + if (ret < 0) { + NL_SET_ERR_MSG(extack, "Unable to allocate table id"); + goto free_permissions; + } + } + + INIT_LIST_HEAD(&table->tbl_acts_list); + if (tb[P4TC_TABLE_ACTS_LIST]) { + ret = tcf_table_acts_list_init(tb[P4TC_TABLE_ACTS_LIST], + pipeline, &table->tbl_acts_list, + extack); + if (ret < 0) + goto idr_rm; + } + + if (tb[P4TC_TABLE_PREACTIONS]) { + table->tbl_preacts = kcalloc(TCA_ACT_MAX_PRIO, + sizeof(struct tc_action *), + GFP_KERNEL); + if (!table->tbl_preacts) { + ret = -ENOMEM; + goto table_acts_destroy; + } + + ret = p4tc_action_init(net, tb[P4TC_TABLE_PREACTIONS], + table->tbl_preacts, table->common.p_id, + 0, extack); + if (ret < 0) { + kfree(table->tbl_preacts); + goto table_acts_destroy; + } + table->tbl_num_preacts = ret; + } else { + table->tbl_preacts = NULL; + } + + if (tb[P4TC_TABLE_POSTACTIONS]) { + table->tbl_postacts = kcalloc(TCA_ACT_MAX_PRIO, + sizeof(struct tc_action *), + GFP_KERNEL); + if (!table->tbl_postacts) { + ret = -ENOMEM; + goto preactions_destroy; + } + + ret = p4tc_action_init(net, tb[P4TC_TABLE_POSTACTIONS], + table->tbl_postacts, table->common.p_id, + 0, extack); + if (ret < 0) { + kfree(table->tbl_postacts); + goto preactions_destroy; + } + table->tbl_num_postacts = ret; + } else { + table->tbl_postacts = NULL; + table->tbl_num_postacts = 0; + } + + if (tb[P4TC_TABLE_KEY]) { + key = tcf_table_key_add(net, table, tb[P4TC_TABLE_KEY], extack); + if (IS_ERR(key)) { + ret = PTR_ERR(key); + goto postacts_destroy; + } + } + + ret = tcf_table_init_default_acts(net, tb, table, + &table->tbl_default_hitact, + &table->tbl_default_missact, + &table->tbl_acts_list, extack); + if (ret < 0) + goto key_put; + + table->tbl_curr_used_entries = 0; + table->tbl_curr_count = 0; + + refcount_set(&table->tbl_entries_ref, 1); + + idr_init(&table->tbl_masks_idr); + idr_init(&table->tbl_prio_idr); + spin_lock_init(&table->tbl_masks_idr_lock); + spin_lock_init(&table->tbl_prio_idr_lock); + + table->tbl_key = key; + + pipeline->curr_tables += 1; + + table->common.ops = (struct p4tc_template_ops *)&p4tc_table_ops; + + return table; + +key_put: + if (key) + tcf_table_key_put(key); + +postacts_destroy: + p4tc_action_destroy(table->tbl_postacts); + +preactions_destroy: + p4tc_action_destroy(table->tbl_preacts); + +idr_rm: + idr_remove(&pipeline->p_tbl_idr, table->tbl_id); + +free_permissions: + kfree(table->tbl_permissions); + +table_acts_destroy: + tcf_table_acts_list_destroy(&table->tbl_acts_list); + +free: + kfree(table); + +out: + return ERR_PTR(ret); +} + +static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, + u32 tbl_id, + struct p4tc_pipeline *pipeline, + u32 flags, + struct netlink_ext_ack *extack) +{ + struct p4tc_table_key *key = NULL; + int num_postacts = 0, num_preacts = 0; + struct p4tc_table_defact *default_hitact = NULL; + struct p4tc_table_defact *default_missact = NULL; + struct list_head *tbl_acts_list = NULL; + struct p4tc_table_perm *perm = NULL; + struct p4tc_table_parm *parm = NULL; + struct tc_action **postacts = NULL; + struct tc_action **preacts = NULL; + int ret = 0; + struct p4tc_table *table; + + table = tcf_table_find_byanyattr(pipeline, tb[P4TC_TABLE_NAME], tbl_id, + extack); + if (IS_ERR(table)) + return table; + + if (tb[P4TC_TABLE_ACTS_LIST]) { + tbl_acts_list = kzalloc(sizeof(*tbl_acts_list), GFP_KERNEL); + if (!tbl_acts_list) { + ret = -ENOMEM; + goto out; + } + INIT_LIST_HEAD(tbl_acts_list); + ret = tcf_table_acts_list_init(tb[P4TC_TABLE_ACTS_LIST], + pipeline, tbl_acts_list, extack); + if (ret < 0) + goto table_acts_destroy; + } + + if (tb[P4TC_TABLE_PREACTIONS]) { + preacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), + GFP_KERNEL); + if (!preacts) { + ret = -ENOMEM; + goto table_acts_destroy; + } + + ret = p4tc_action_init(net, tb[P4TC_TABLE_PREACTIONS], preacts, + table->common.p_id, 0, extack); + if (ret < 0) { + kfree(preacts); + goto table_acts_destroy; + } + num_preacts = ret; + } + + if (tb[P4TC_TABLE_POSTACTIONS]) { + postacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), + GFP_KERNEL); + if (!postacts) { + ret = -ENOMEM; + goto preactions_destroy; + } + + ret = p4tc_action_init(net, tb[P4TC_TABLE_POSTACTIONS], + postacts, table->common.p_id, 0, extack); + if (ret < 0) { + kfree(postacts); + goto preactions_destroy; + } + num_postacts = ret; + } + + if (tbl_acts_list) + ret = tcf_table_init_default_acts(net, tb, table, + &default_hitact, + &default_missact, + tbl_acts_list, extack); + else + ret = tcf_table_init_default_acts(net, tb, table, + &default_hitact, + &default_missact, + &table->tbl_acts_list, + extack); + if (ret < 0) + goto postactions_destroy; + + if (tb[P4TC_TABLE_KEY]) { + key = tcf_table_key_add(net, table, tb[P4TC_TABLE_KEY], extack); + if (IS_ERR(key)) { + ret = PTR_ERR(key); + goto defaultacts_destroy; + } + } + + if (tb[P4TC_TABLE_INFO]) { + parm = nla_data(tb[P4TC_TABLE_INFO]); + if (parm->tbl_flags & P4TC_TABLE_FLAGS_KEYSZ) { + if (!parm->tbl_keysz) { + NL_SET_ERR_MSG(extack, + "Table keysz cannot be zero"); + ret = -EINVAL; + goto key_destroy; + } + if (parm->tbl_keysz > P4TC_MAX_KEYSZ) { + NL_SET_ERR_MSG(extack, + "Table keysz exceeds maximum keysz"); + ret = -EINVAL; + goto key_destroy; + } + table->tbl_keysz = parm->tbl_keysz; + } + + if (parm->tbl_flags & P4TC_TABLE_FLAGS_MAX_ENTRIES) { + if (!parm->tbl_max_entries) { + NL_SET_ERR_MSG(extack, + "Table max_entries cannot be zero"); + ret = -EINVAL; + goto key_destroy; + } + if (parm->tbl_max_entries > P4TC_MAX_TENTRIES) { + NL_SET_ERR_MSG(extack, + "Table max_entries exceeds maximum value"); + ret = -EINVAL; + goto key_destroy; + } + table->tbl_max_entries = parm->tbl_max_entries; + } + + if (parm->tbl_flags & P4TC_TABLE_FLAGS_MAX_MASKS) { + if (!parm->tbl_max_masks) { + NL_SET_ERR_MSG(extack, + "Table max_masks cannot be zero"); + ret = -EINVAL; + goto key_destroy; + } + if (parm->tbl_max_masks > P4TC_MAX_TMASKS) { + NL_SET_ERR_MSG(extack, + "Table max_masks exceeds maximum value"); + ret = -EINVAL; + goto key_destroy; + } + table->tbl_max_masks = parm->tbl_max_masks; + } + if (parm->tbl_flags & P4TC_TABLE_FLAGS_PERMISSIONS) { + if (parm->tbl_permissions > P4TC_MAX_PERMISSION) { + NL_SET_ERR_MSG(extack, + "Permission may only have 10 bits turned on"); + ret = -EINVAL; + goto key_destroy; + } + if (!p4tc_data_exec_ok(parm->tbl_permissions)) { + NL_SET_ERR_MSG(extack, + "Table must have execute permissions"); + ret = -EINVAL; + goto key_destroy; + } + if (!p4tc_data_read_ok(parm->tbl_permissions)) { + NL_SET_ERR_MSG(extack, + "Data path read permissions must be set"); + ret = -EINVAL; + goto key_destroy; + } + + perm = kzalloc(sizeof(*perm), GFP_KERNEL); + if (!perm) { + ret = -ENOMEM; + goto key_destroy; + } + perm->permissions = parm->tbl_permissions; + } + + if (parm->tbl_flags & P4TC_TABLE_FLAGS_TYPE) { + if (parm->tbl_type > P4TC_TABLE_TYPE_MAX) { + NL_SET_ERR_MSG(extack, "Table type can only be exact or LPM"); + ret = -EINVAL; + goto key_destroy; + } + table->tbl_type = parm->tbl_type; + } + } + + if (preacts) { + p4tc_action_destroy(table->tbl_preacts); + table->tbl_preacts = preacts; + table->tbl_num_preacts = num_preacts; + } + + if (postacts) { + p4tc_action_destroy(table->tbl_postacts); + table->tbl_postacts = postacts; + table->tbl_num_postacts = num_postacts; + } + + if (default_hitact) { + struct p4tc_table_defact *hitact; + + hitact = rcu_replace_pointer_rtnl(table->tbl_default_hitact, + default_hitact); + if (hitact) { + synchronize_rcu(); + p4tc_table_defact_destroy(hitact); + } + } + + if (default_missact) { + struct p4tc_table_defact *missact; + + missact = rcu_replace_pointer_rtnl(table->tbl_default_missact, + default_missact); + if (missact) { + synchronize_rcu(); + p4tc_table_defact_destroy(missact); + } + } + + if (key) { + if (table->tbl_key) + tcf_table_key_put(table->tbl_key); + table->tbl_key = key; + } + + if (perm) { + perm = rcu_replace_pointer_rtnl(table->tbl_permissions, perm); + kfree_rcu(perm, rcu); + } + + return table; + +key_destroy: + if (key) + tcf_table_key_put(key); + +defaultacts_destroy: + p4tc_table_defact_destroy(default_missact); + p4tc_table_defact_destroy(default_hitact); + +postactions_destroy: + p4tc_action_destroy(postacts); + +preactions_destroy: + p4tc_action_destroy(preacts); + +table_acts_destroy: + if (tbl_acts_list) { + tcf_table_acts_list_destroy(tbl_acts_list); + kfree(tbl_acts_list); + } + +out: + return ERR_PTR(ret); +} + +static bool tcf_table_check_runtime_update(struct nlmsghdr *n, + struct nlattr **tb) +{ + int i; + + if (n->nlmsg_type == RTM_CREATEP4TEMPLATE && + !(n->nlmsg_flags & NLM_F_REPLACE)) + return false; + + if (tb[P4TC_TABLE_INFO]) { + struct p4tc_table_parm *info; + + info = nla_data(tb[P4TC_TABLE_INFO]); + if ((info->tbl_flags & ~P4TC_TABLE_FLAGS_PERMISSIONS) || + !(info->tbl_flags & P4TC_TABLE_FLAGS_PERMISSIONS)) + return false; + } + + for (i = P4TC_TABLE_PREACTIONS; i < P4TC_TABLE_MAX; i++) { + if (i != P4TC_TABLE_DEFAULT_HIT && + i != P4TC_TABLE_DEFAULT_MISS && tb[i]) + return false; + } + + return true; +} + +static struct p4tc_template_common * +tcf_table_cu(struct net *net, struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + u32 pipeid = ids[P4TC_PID_IDX], tbl_id = ids[P4TC_TBLID_IDX]; + struct nlattr *tb[P4TC_TABLE_MAX + 1]; + struct p4tc_pipeline *pipeline; + struct p4tc_table *table; + int ret; + + pipeline = tcf_pipeline_find_byany(net, nl_pname->data, pipeid, extack); + if (IS_ERR(pipeline)) + return (void *)pipeline; + + ret = nla_parse_nested(tb, P4TC_TABLE_MAX, nla, p4tc_table_policy, + extack); + if (ret < 0) + return ERR_PTR(ret); + + if (pipeline_sealed(pipeline) && + !tcf_table_check_runtime_update(n, tb)) { + NL_SET_ERR_MSG(extack, + "Only default action updates are allowed in sealed pipeline"); + return ERR_PTR(-EINVAL); + } + + if (n->nlmsg_flags & NLM_F_REPLACE) + table = tcf_table_update(net, tb, tbl_id, pipeline, + n->nlmsg_flags, extack); + else + table = tcf_table_create(net, tb, tbl_id, pipeline, extack); + + if (IS_ERR(table)) + goto out; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!ids[P4TC_TBLID_IDX]) + ids[P4TC_TBLID_IDX] = table->tbl_id; + +out: + return (struct p4tc_template_common *)table; +} + +static int tcf_table_flush(struct net *net, struct sk_buff *skb, + struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_table *table; + unsigned long tmp, tbl_id; + int ret = 0; + int i = 0; + + if (nla_put_u32(skb, P4TC_PATH, 0)) + goto out_nlmsg_trim; + + if (idr_is_empty(&pipeline->p_tbl_idr)) { + NL_SET_ERR_MSG(extack, "There are not tables to flush"); + goto out_nlmsg_trim; + } + + idr_for_each_entry_ul(&pipeline->p_tbl_idr, table, tmp, tbl_id) { + if (_tcf_table_put(net, NULL, pipeline, table, false, extack) < 0) { + ret = -EBUSY; + continue; + } + i++; + } + + nla_put_u32(skb, P4TC_COUNT, i); + + if (ret < 0) { + if (i == 0) { + NL_SET_ERR_MSG(extack, "Unable to flush any table"); + goto out_nlmsg_trim; + } else { + NL_SET_ERR_MSG(extack, "Unable to flush all tables"); + } + } + + return i; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_table_gd(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + u32 pipeid = ids[P4TC_PID_IDX], tbl_id = ids[P4TC_MID_IDX]; + struct nlattr *tb[P4TC_TABLE_MAX + 1] = {}; + unsigned char *b = nlmsg_get_pos(skb); + int ret = 0; + struct p4tc_pipeline *pipeline; + struct p4tc_table *table; + + if (nla) { + ret = nla_parse_nested(tb, P4TC_TABLE_MAX, nla, + p4tc_table_policy, extack); + + if (ret < 0) + return ret; + } + + if (n->nlmsg_type == RTM_GETP4TEMPLATE || + tcf_table_check_runtime_update(n, tb)) + pipeline = tcf_pipeline_find_byany(net, nl_pname->data, pipeid, + extack); + else + pipeline = tcf_pipeline_find_byany_unsealed(net, nl_pname->data, + pipeid, extack); + + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (n->nlmsg_type == RTM_DELP4TEMPLATE && (n->nlmsg_flags & NLM_F_ROOT)) + return tcf_table_flush(net, skb, pipeline, extack); + + table = tcf_table_find_byanyattr(pipeline, tb[P4TC_TABLE_NAME], tbl_id, + extack); + if (IS_ERR(table)) + return PTR_ERR(table); + + if (_tcf_table_fill_nlmsg(skb, table) < 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for table"); + return -EINVAL; + } + + if (n->nlmsg_type == RTM_DELP4TEMPLATE) { + ret = _tcf_table_put(net, tb, pipeline, table, false, extack); + if (ret < 0) + goto out_nlmsg_trim; + } + + return 0; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_table_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, + struct nlattr *nla, char **p_name, u32 *ids, + struct netlink_ext_ack *extack) +{ + struct net *net = sock_net(skb->sk); + struct p4tc_pipeline *pipeline; + + if (!ctx->ids[P4TC_PID_IDX]) { + pipeline = tcf_pipeline_find_byany(net, *p_name, + ids[P4TC_PID_IDX], extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + ctx->ids[P4TC_PID_IDX] = pipeline->common.p_id; + } else { + pipeline = tcf_pipeline_find_byid(net, ctx->ids[P4TC_PID_IDX]); + } + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!(*p_name)) + *p_name = pipeline->common.name; + + return tcf_p4_tmpl_generic_dump(skb, ctx, &pipeline->p_tbl_idr, + P4TC_TBLID_IDX, extack); +} + +static int tcf_table_dump_1(struct sk_buff *skb, + struct p4tc_template_common *common) +{ + struct p4tc_table *table = to_table(common); + struct nlattr *nest = nla_nest_start(skb, P4TC_PARAMS); + + if (!nest) + return -ENOMEM; + + if (nla_put_string(skb, P4TC_TABLE_NAME, table->common.name)) { + nla_nest_cancel(skb, nest); + return -ENOMEM; + } + + nla_nest_end(skb, nest); + + return 0; +} + +const struct p4tc_template_ops p4tc_table_ops = { + .init = NULL, + .cu = tcf_table_cu, + .fill_nlmsg = tcf_table_fill_nlmsg, + .gd = tcf_table_gd, + .put = tcf_table_put, + .dump = tcf_table_dump, + .dump_1 = tcf_table_dump_1, +}; diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c index c294dc0789f0..e5be7db054dd 100644 --- a/net/sched/p4tc/p4tc_tmpl_api.c +++ b/net/sched/p4tc/p4tc_tmpl_api.c @@ -45,6 +45,7 @@ static bool obj_is_valid(u32 obj) case P4TC_OBJ_META: case P4TC_OBJ_HDR_FIELD: case P4TC_OBJ_ACT: + case P4TC_OBJ_TABLE: return true; default: return false; @@ -56,6 +57,7 @@ static const struct p4tc_template_ops *p4tc_ops[P4TC_OBJ_MAX] = { [P4TC_OBJ_META] = &p4tc_meta_ops, [P4TC_OBJ_HDR_FIELD] = &p4tc_hdrfield_ops, [P4TC_OBJ_ACT] = &p4tc_act_ops, + [P4TC_OBJ_TABLE] = &p4tc_table_ops, }; int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, From patchwork Wed May 17 11:02:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244698 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B3AA72099F for ; Wed, 17 May 2023 11:04:51 +0000 (UTC) Received: from mail-vs1-xe34.google.com (mail-vs1-xe34.google.com [IPv6:2607:f8b0:4864:20::e34]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E2E372D47 for ; Wed, 17 May 2023 04:04:29 -0700 (PDT) Received: by mail-vs1-xe34.google.com with SMTP id ada2fe7eead31-43627012261so150879137.2 for ; Wed, 17 May 2023 04:04:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321460; x=1686913460; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=aGqF83hZfe+eyBbjjMuEh4mzAlQ3eIRzf6VHoHnB4Sk=; b=Mw6yCkmAddf9pypHhzezcxgelntlpVF+dKlMCdhYa6S5FN5OBSt1jAsfUo/7WRJNr7 fpDNNbYCthO9WmAgp+q0wJRPx3YPfGJXdm07xk86+NXjSqhCo+EED47ngf5+Wy7uwjXE FP+5yEan8La1iBxXLXXoGYExdYPsoW+GbCdPLWYs7foeWP0zhr5hPnEwBGP6dumyc8Xp n1YJg3WHDjNBzVxn2otvNV/jsyr0/2KyxHAbJ2y4ZgfClgyo6N2eo0qU6USu8/EUQn8b InpnR+ar18QnY7VvmQeBvRvhRY6XJEu+CsBUc2Up2l7Kd96oNn1CMZMvQINKMOfS2egz BFSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321460; x=1686913460; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=aGqF83hZfe+eyBbjjMuEh4mzAlQ3eIRzf6VHoHnB4Sk=; b=cBZN7opMJWuBQrMe2ZymGwNy6+gr6MQVs7Eq95G/SpjJ5WrfmP+UiVeFQA815biW+C uVFV0EQWbmeXmlrOt0mUZ0xITL8NtKOnV18ndUvAS9MaBBCIiK4Lu4ndhZy/zSMxTGSm FOWzlQ18lKka4PiFWH9W9BbS+V7XrypL2hOiiJ36VoObPl9rjgq4vLduT0FwttDBDDGc wRRqcisIieTru5pZ3unaEJhWJes36OZi30dwNFzWDys8sH4cAhjG2Ak7edAWvhxb4Rz8 SZw6HyozvbBO/E2P5fpZFWKUPghbc2JCWtDPnAPD4+b9GD852xuQDBPsXS6LwlskD3Td OjrQ== X-Gm-Message-State: AC+VfDxr1A7DG0hjVsgGtJnPNHJy/25p+mpnaFFcKBEcNCk5Prmp5776 bIvYWOuKnHzahVtv+YNqOoBVJrkpZWEbqt3Ak4A= X-Google-Smtp-Source: ACHHUZ6uXFFij2/I8vSrlPENZi+j2IPlF81YDtEAVbcGL6B8MeAYKdydjM1ZuH3ylWu43ZjY8gLR8Q== X-Received: by 2002:a67:ffd5:0:b0:434:69be:8495 with SMTP id w21-20020a67ffd5000000b0043469be8495mr16436804vsq.9.1684321458953; Wed, 17 May 2023 04:04:18 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id v11-20020ae9e30b000000b0074636e35405sm527137qkf.65.2023.05.17.04.04.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:04:18 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 15/28] p4tc: add table entry create, update, get, delete, flush and dump Date: Wed, 17 May 2023 07:02:19 -0400 Message-Id: <20230517110232.29349-15-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Tables are conceptually similar to TCAMs and this implementation could be labelled as an "algorithmic" TCAM. Tables have a key of a specific size, maximum number of entries and masks allowed. The basic P4 key types are supported (exact, LPM, ternary, and ranges) although the kernel side is oblivious of all that and sees only bit blobs which it masks before a lookup is performed. This commit allows users to create, update, delete, get, flush and dump table _entries_ (templates were described in earlier patch). For example, a user issuing the following command: tc p4runtime create myprog/table/cb/tname \ dstAddr 10.10.10.0/24 srcAddr 192.168.0.0/16 prio 16 \ action myprog/cb/send param port type dev port1 indicates we are creating a table entry in table "tname" on a pipeline named "myprog" User space tc will create a key which has a value of 0x0a0a0a00c0a00000 (10.10.10.0 concatenated with 192.168.0.0) and a mask value of 0xffffff00ffff0000 (/24 concatenated with /16) that will be sent to the kernel. In addition a priority field of 16 is passed to the kernel as well as the action definition. The priority field is needed to disambiguate in case two entries match. In that case, the kernel will choose the one with lowest priority number. Note that table entries can only be created once the pipeline template is sealed. If the user wanted to, for example, add an action to our just created entry, they'd issue the following command: tc p4runtime update myprog/table/cb/tname srcAddr 10.10.10.0/24 \ dstAddr 192.168.0.0/16 prio 16 action myprog/cb/send param port type dev port5 In this case, the user needs to specify the pipeline name, the table name, the key and the priority, so that we can locate the table entry. If the user wanted to, for example, get the table entry that we just updated, they'd issue the following command: tc p4runtime get myprog/table/cb/tname srcAddr 10.10.10.0/24 \ dstAddr 192.168.0.0/16 prio 16 Note that, again, we need to specify the pipeline name, the table name, the key and the priority, so that we can locate the table entry. If the user wanted to delete the table entry we created, they'd issue the following command: tc p4runtime del myprog/table/cb/tname srcAddr 10.10.10.0/24 \ dstAddr 192.168.0.0/16 prio 16 Note that, again, we need to specify the pipeline name, the table name, the key and the priority, so that we can locate the table entry. We can also flush all the table entries from a specific table. To flush the table entries of table tname ane pipeline ptables, the user would issue the following command: tc p4runtime del myprog/table/cb/tname We can also dump all the table entries from a specific table . To dump the table entries of table tname and pipeline myprog, the user would issue the following command: tc p4runtime get myprog/table/cb/tname __Table Entry Permissions__ Table entries can have permissions specified when they are being added. Caveat: we are doing a lot more than what P4 defines because we feel it is necessary. Table entry permissions build on the table permissions provided when a table is created via the template (see earlier patch). We have two types of permissions: Control path vs datapath. The template definition can set either one. For example, one could allow for adding table entries by the datapath in case of PNA add-on-miss is needed. By default tables entries have control plane RUD, meaning the control plane can Read, Update or Delete entries. By default, as well, the control plane can create new entries unless specified otherwise by the template. Lets see an example of defining a table "tname" at template time: $TC p4template create table/ptables/cb/tname tblid 1 keysz 64 permissions 0x3C9 ... Above is setting the table tname's permission to be 0x3C9 is equivalent to CRUD--R--X meaning: The control plane can Create, Read, Update, Delete The datapath can only Read and Execute table entries. If one was to dump this table with: $TC p4template get table/ptables/cb/tname The output would be the following: pipeline name ptables id 22 table id 1 table name cb/tname key_sz 64 max entries 256 masks 8 table entries 0 permissions CRUD--R--X The expressed permissions above are probably the most practical for most use cases. __Constant Tables And P4-programmed Defined Entries__ If one wanted to restrict the table to be an equivalent to a "const" then the permissions would be set to be: -R----R--X In such a case, typically the P4 program will have some entries defined (see the famous P4 calc example). The "initial entries" specified in the P4 program will have to be added by the template (as generated by the compiler), as such: $TC p4template update table/ptables/cb/tname entry srcAddr 10.10.10.10/24 dstAddr 1.1.1.0/24 prio 17 This table cannot be updated at runtime. Any attempt to add an entry of a table which is read-only at runtime will get a permission denied response back from the kernel. Note: If one was to create an equivalent for PNA add-on-miss feature for this table, then the template would issue table permissions as: -R---CR--X PNA doesn't specify whether the datapath can also delete or update entries, but if it did then more appropriate permissions will be: -R----XCRUDX __Mix And Match of RW vs Constant Entries__ Lets look at other scenarios; lets say the table has CRUD--R--X permissions as defined by the template... At runtime the user could add entries which are "const" - by specifying the entry's permission as -R---R--X example: $TC p4runtime create ptables/table/cb/tname srcAddr 10.10.10.10/24 \ dstAddr 1.1.1.0/24 prio 17 permissions 0x109 action drop or not specify permissions at all as such: $TC p4runtime create ptables/table/cb/tname srcAddr 10.10.10.10/24 \ dstAddr 1.1.1.0/24 prio 17 \ action drop in which case the table's permissions defined at template time( CRUD--R--X) are assumed; meaning the table entry can be deleted or updated by the control plane. __Entries permissions Allowed On A Table Entry Creation At Runtime__ When an entry is added with expressed permissions it has at most to have what the template table definition expressed but could ask for less permission. For example, assuming a table with templated specified permissions of CR-D--R--X: An entry created at runtime with permission of -R----R--X is allowed but an entry with -RUD--R--X will be rejected. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/p4tc.h | 76 +- include/uapi/linux/p4tc.h | 36 + include/uapi/linux/rtnetlink.h | 7 + net/sched/p4tc/Makefile | 3 +- net/sched/p4tc/p4tc_pipeline.c | 12 + net/sched/p4tc/p4tc_table.c | 54 +- net/sched/p4tc/p4tc_tbl_api.c | 2069 ++++++++++++++++++++++++++++++++ security/selinux/nlmsgtab.c | 5 +- 8 files changed, 2254 insertions(+), 8 deletions(-) create mode 100644 net/sched/p4tc/p4tc_tbl_api.c diff --git a/include/net/p4tc.h b/include/net/p4tc.h index fa8c6a43c6d3..e784df312582 100644 --- a/include/net/p4tc.h +++ b/include/net/p4tc.h @@ -133,6 +133,7 @@ struct p4tc_pipeline { u32 num_created_acts; refcount_t p_ref; refcount_t p_ctrl_ref; + refcount_t p_entry_deferal_ref; u16 num_tables; u16 curr_tables; u8 p_state; @@ -240,17 +241,17 @@ struct p4tc_table { struct list_head tbl_acts_list; struct p4tc_table_key *tbl_key; struct idr tbl_masks_idr; - struct idr tbl_prio_idr; + struct ida tbl_prio_idr; struct rhltable tbl_entries; struct tc_action **tbl_preacts; struct tc_action **tbl_postacts; + struct p4tc_table_entry *tbl_const_entry; struct p4tc_table_defact __rcu *tbl_default_hitact; struct p4tc_table_defact __rcu *tbl_default_missact; struct p4tc_table_perm __rcu *tbl_permissions; struct p4tc_table_entry_mask __rcu **tbl_masks_array; unsigned long __rcu *tbl_free_masks_bitmap; spinlock_t tbl_masks_idr_lock; - spinlock_t tbl_prio_idr_lock; int tbl_num_postacts; int tbl_num_preacts; u32 tbl_count; @@ -265,6 +266,7 @@ struct p4tc_table { refcount_t tbl_ref; refcount_t tbl_entries_ref; u16 tbl_type; + u16 PAD0; }; extern const struct p4tc_template_ops p4tc_table_ops; @@ -337,6 +339,66 @@ extern const struct rhashtable_params p4tc_label_ht_params; extern const struct rhashtable_params acts_params; void p4tc_label_ht_destroy(void *ptr, void *arg); +extern const struct rhashtable_params entry_hlt_params; + +struct p4tc_table_entry; +struct p4tc_table_entry_work { + struct work_struct work; + struct p4tc_pipeline *pipeline; + struct p4tc_table_entry *entry; + bool defer_deletion; +}; + +struct p4tc_table_entry_key { + u32 keysz; + /* Key start */ + u32 maskid; + unsigned char fa_key[] __aligned(8); +}; + +struct p4tc_table_entry_value { + u32 prio; + int num_acts; + struct tc_action **acts; + refcount_t entries_ref; + u32 permissions; + struct p4tc_table_entry_tm __rcu *tm; + struct p4tc_table_entry_work *entry_work; +}; + +struct p4tc_table_entry_mask { + struct rcu_head rcu; + u32 sz; + u32 mask_index; + refcount_t mask_ref; + u32 mask_id; + unsigned char fa_value[] __aligned(8); +}; + +struct p4tc_table_entry { + struct rcu_head rcu; + struct rhlist_head ht_node; + struct p4tc_table_entry_key key; + /* fallthrough: key data + value */ +}; + +#define P4TC_KEYSZ_BYTES(bits) round_up(BITS_TO_BYTES(bits), 8) + +static inline void *p4tc_table_entry_value(struct p4tc_table_entry *entry) +{ + return entry->key.fa_key + P4TC_KEYSZ_BYTES(entry->key.keysz); +} + +extern const struct nla_policy p4tc_root_policy[P4TC_ROOT_MAX + 1]; +extern const struct nla_policy p4tc_policy[P4TC_MAX + 1]; +struct p4tc_table_entry *p4tc_table_entry_lookup(struct sk_buff *skb, + struct p4tc_table *table, + u32 keysz); +int __tcf_table_entry_del(struct p4tc_pipeline *pipeline, + struct p4tc_table *table, + struct p4tc_table_entry_key *key, + struct p4tc_table_entry_mask *mask, u32 prio); + struct p4tc_parser { char parser_name[PARSERNAMSIZ]; struct idr hdr_fields_idr; @@ -443,6 +505,16 @@ struct p4tc_table *tcf_table_get(struct p4tc_pipeline *pipeline, struct netlink_ext_ack *extack); void tcf_table_put_ref(struct p4tc_table *table); +void tcf_table_entry_destroy_hash(void *ptr, void *arg); + +struct p4tc_table_entry * +tcf_table_const_entry_cu(struct net *net, struct nlattr *arg, + struct p4tc_pipeline *pipeline, + struct p4tc_table *table, + struct netlink_ext_ack *extack); +int p4tca_table_get_entry_fill(struct sk_buff *skb, struct p4tc_table *table, + struct p4tc_table_entry *entry, u32 tbl_id); + struct p4tc_parser *tcf_parser_create(struct p4tc_pipeline *pipeline, const char *parser_name, u32 parser_inst_id, diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h index 99a24ce8f319..62e817c483b5 100644 --- a/include/uapi/linux/p4tc.h +++ b/include/uapi/linux/p4tc.h @@ -43,6 +43,7 @@ struct p4tcmsg { enum { P4TC_TABLE_TYPE_EXACT = 1, P4TC_TABLE_TYPE_LPM = 2, + P4TC_TABLE_TYPE_TERNARY = 3, __P4TC_TABLE_TYPE_MAX, }; #define P4TC_TABLE_TYPE_MAX (__P4TC_TABLE_TYPE_MAX - 1) @@ -128,6 +129,7 @@ enum { P4TC_OBJ_HDR_FIELD, P4TC_OBJ_ACT, P4TC_OBJ_TABLE, + P4TC_OBJ_TABLE_ENTRY, __P4TC_OBJ_MAX, }; #define P4TC_OBJ_MAX __P4TC_OBJ_MAX @@ -330,6 +332,40 @@ struct tc_act_dyna { tc_gen; }; +struct p4tc_table_entry_tm { + __u64 created; + __u64 lastused; + __u64 firstused; + __u16 who_created; + __u16 who_updated; + __u16 permissions; +}; + +/* Table entry attributes */ +enum { + P4TC_ENTRY_UNSPEC, + P4TC_ENTRY_TBLNAME, /* string */ + P4TC_ENTRY_KEY_BLOB, /* Key blob */ + P4TC_ENTRY_MASK_BLOB, /* Mask blob */ + P4TC_ENTRY_PRIO, /* u32 */ + P4TC_ENTRY_ACT, /* nested actions */ + P4TC_ENTRY_TM, /* entry data path timestamps */ + P4TC_ENTRY_WHODUNNIT, /* tells who's modifying the entry */ + P4TC_ENTRY_CREATE_WHODUNNIT, /* tells who created the entry */ + P4TC_ENTRY_UPDATE_WHODUNNIT, /* tells who updated the entry last */ + P4TC_ENTRY_PERMISSIONS, /* entry CRUDX permissions */ + P4TC_ENTRY_PAD, + __P4TC_ENTRY_MAX +}; +#define P4TC_ENTRY_MAX (__P4TC_ENTRY_MAX - 1) + +enum { + P4TC_ENTITY_UNSPEC, + P4TC_ENTITY_KERNEL, + P4TC_ENTITY_TC, + P4TC_ENTITY_MAX +}; + #define P4TC_RTA(r) \ ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct p4tcmsg)))) diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 41a4046e7958..c06fe3d8f6ac 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -201,6 +201,13 @@ enum { RTM_GETP4TEMPLATE, #define RTM_GETP4TEMPLATE RTM_GETP4TEMPLATE + RTM_P4TC_CREATE = 128, +#define RTM_P4TC_CREATE RTM_P4TC_CREATE + RTM_P4TC_DEL, +#define RTM_P4TC_DEL RTM_P4TC_DEL + RTM_P4TC_GET, +#define RTM_P4TC_GET RTM_P4TC_GET + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index de3a7b83305c..0d2c20223154 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.o p4tc_meta.o \ - p4tc_parser_api.o p4tc_hdrfield.o p4tc_action.o p4tc_table.o + p4tc_parser_api.o p4tc_hdrfield.o p4tc_action.o p4tc_table.o \ + p4tc_tbl_api.o diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c index 51b47b07ba65..1b6ac9fc2050 100644 --- a/net/sched/p4tc/p4tc_pipeline.c +++ b/net/sched/p4tc/p4tc_pipeline.c @@ -328,7 +328,16 @@ static int tcf_pipeline_put(struct net *net, struct p4tc_metadata *meta; struct p4tc_table *table; + if (!refcount_dec_if_one(&pipeline->p_ctrl_ref)) { + if (pipeline_net) { + put_net(pipeline_net); + NL_SET_ERR_MSG(extack, "Can't delete referenced pipeline"); + return -EBUSY; + } + } + if (pipeline_net && !refcount_dec_if_one(&pipeline->p_ref)) { + refcount_set(&pipeline->p_ctrl_ref, 1); NL_SET_ERR_MSG(extack, "Can't delete referenced pipeline"); return -EBUSY; } @@ -567,6 +576,9 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, pipeline->net = net; refcount_set(&pipeline->p_ref, 1); + refcount_set(&pipeline->p_ctrl_ref, 1); + refcount_set(&pipeline->p_hdrs_used, 1); + refcount_set(&pipeline->p_entry_deferal_ref, 1); pipeline->common.ops = (struct p4tc_template_ops *)&p4tc_pipeline_ops; diff --git a/net/sched/p4tc/p4tc_table.c b/net/sched/p4tc/p4tc_table.c index 1ae4ed6d39e9..e5b1a56aed7d 100644 --- a/net/sched/p4tc/p4tc_table.c +++ b/net/sched/p4tc/p4tc_table.c @@ -285,6 +285,17 @@ static int _tcf_table_fill_nlmsg(struct sk_buff *skb, struct p4tc_table *table) } nla_nest_end(skb, nested_tbl_acts); + if (table->tbl_const_entry) { + struct nlattr *const_nest; + + const_nest = nla_nest_start(skb, P4TC_TABLE_OPT_ENTRY); + p4tca_table_get_entry_fill(skb, table, table->tbl_const_entry, + table->tbl_id); + nla_nest_end(skb, const_nest); + } + kfree(table->tbl_const_entry); + table->tbl_const_entry = NULL; + if (nla_put(skb, P4TC_TABLE_INFO, sizeof(parm), &parm)) goto out_nlmsg_trim; nla_nest_end(skb, nest); @@ -432,8 +443,11 @@ static inline int _tcf_table_put(struct net *net, struct nlattr **tb, tcf_table_acts_list_destroy(&table->tbl_acts_list); + rhltable_free_and_destroy(&table->tbl_entries, + tcf_table_entry_destroy_hash, table); + idr_destroy(&table->tbl_masks_idr); - idr_destroy(&table->tbl_prio_idr); + ida_destroy(&table->tbl_prio_idr); perm = rcu_replace_pointer_rtnl(table->tbl_permissions, NULL); kfree_rcu(perm, rcu); @@ -880,6 +894,7 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, struct p4tc_pipeline *pipeline, struct netlink_ext_ack *extack) { + struct rhashtable_params table_hlt_params = entry_hlt_params; struct p4tc_table_key *key = NULL; struct p4tc_table_parm *parm; struct p4tc_table *table; @@ -1135,9 +1150,19 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, refcount_set(&table->tbl_entries_ref, 1); idr_init(&table->tbl_masks_idr); - idr_init(&table->tbl_prio_idr); + ida_init(&table->tbl_prio_idr); spin_lock_init(&table->tbl_masks_idr_lock); - spin_lock_init(&table->tbl_prio_idr_lock); + + table_hlt_params.max_size = table->tbl_max_entries; + if (table->tbl_max_entries > U16_MAX) + table_hlt_params.nelem_hint = U16_MAX / 4 * 3; + else + table_hlt_params.nelem_hint = table->tbl_max_entries / 4 * 3; + + if (rhltable_init(&table->tbl_entries, &table_hlt_params) < 0) { + ret = -EINVAL; + goto defaultacts_destroy; + } table->tbl_key = key; @@ -1147,6 +1172,10 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, return table; +defaultacts_destroy: + p4tc_table_defact_destroy(table->tbl_default_missact); + p4tc_table_defact_destroy(table->tbl_default_hitact); + key_put: if (key) tcf_table_key_put(key); @@ -1346,12 +1375,26 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, if (parm->tbl_type > P4TC_TABLE_TYPE_MAX) { NL_SET_ERR_MSG(extack, "Table type can only be exact or LPM"); ret = -EINVAL; - goto key_destroy; + goto free_perm; } table->tbl_type = parm->tbl_type; } } + if (tb[P4TC_TABLE_OPT_ENTRY]) { + struct p4tc_table_entry *entry; + + /* Workaround to make this work */ + entry = tcf_table_const_entry_cu(net, tb[P4TC_TABLE_OPT_ENTRY], + pipeline, table, extack); + if (IS_ERR(entry)) { + ret = PTR_ERR(entry); + goto free_perm; + } + + table->tbl_const_entry = entry; + } + if (preacts) { p4tc_action_destroy(table->tbl_preacts); table->tbl_preacts = preacts; @@ -1399,6 +1442,9 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, return table; +free_perm: + kfree(perm); + key_destroy: if (key) tcf_table_key_put(key); diff --git a/net/sched/p4tc/p4tc_tbl_api.c b/net/sched/p4tc/p4tc_tbl_api.c new file mode 100644 index 000000000000..21784b84864f --- /dev/null +++ b/net/sched/p4tc/p4tc_tbl_api.c @@ -0,0 +1,2069 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_tbl_api.c TC P4 TABLE API + * + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIZEOF_MASKID (sizeof(((struct p4tc_table_entry_key *)0)->maskid)) + +#define STARTOF_KEY(key) (&((key)->maskid)) + +static u32 p4tc_entry_hash_fn(const void *data, u32 len, u32 seed) +{ + const struct p4tc_table_entry_key *key = data; + /* The key memory area is always zero allocated aligned to 8 */ + u32 keysz = round_up(SIZEOF_MASKID + (key->keysz >> 3), 4); + + return jhash2(STARTOF_KEY(key), keysz / sizeof(u32), seed); +} + +static int p4tc_entry_hash_cmp(struct rhashtable_compare_arg *arg, + const void *ptr) +{ + const struct p4tc_table_entry_key *key = arg->key; + const struct p4tc_table_entry *entry = ptr; + u32 keysz = SIZEOF_MASKID + (entry->key.keysz >> 3); + + return memcmp(STARTOF_KEY(&entry->key), STARTOF_KEY(key), keysz); +} + +static u32 p4tc_entry_obj_hash_fn(const void *data, u32 len, u32 seed) +{ + const struct p4tc_table_entry *entry = data; + + return p4tc_entry_hash_fn(&entry->key, len, seed); +} + +const struct rhashtable_params entry_hlt_params = { + .obj_cmpfn = p4tc_entry_hash_cmp, + .obj_hashfn = p4tc_entry_obj_hash_fn, + .hashfn = p4tc_entry_hash_fn, + .head_offset = offsetof(struct p4tc_table_entry, ht_node), + .key_offset = offsetof(struct p4tc_table_entry, key), + .automatic_shrinking = true, +}; + +static struct p4tc_table_entry * +p4tc_entry_lookup(struct p4tc_table *table, struct p4tc_table_entry_key *key, + u32 prio) __must_hold(RCU) +{ + struct p4tc_table_entry *entry; + struct rhlist_head *tmp, *bucket_list; + + bucket_list = + rhltable_lookup(&table->tbl_entries, key, entry_hlt_params); + if (!bucket_list) + return NULL; + + rhl_for_each_entry_rcu(entry, tmp, bucket_list, ht_node) { + struct p4tc_table_entry_value *value = + p4tc_table_entry_value(entry); + + if (value->prio == prio) + return entry; + } + + return NULL; +} + +static struct p4tc_table_entry * +__p4tc_entry_lookup(struct p4tc_table *table, struct p4tc_table_entry_key *key) + __must_hold(RCU) +{ + struct p4tc_table_entry *entry = NULL; + u32 smallest_prio = U32_MAX; + struct rhlist_head *tmp, *bucket_list; + struct p4tc_table_entry *entry_curr; + + bucket_list = + rhltable_lookup(&table->tbl_entries, key, entry_hlt_params); + if (!bucket_list) + return NULL; + + rhl_for_each_entry_rcu(entry_curr, tmp, bucket_list, ht_node) { + struct p4tc_table_entry_value *value = + p4tc_table_entry_value(entry_curr); + if (value->prio <= smallest_prio) { + smallest_prio = value->prio; + entry = entry_curr; + } + } + + return entry; +} + +static struct p4tc_table_entry * +__p4tc_entry_lookup_fast(struct p4tc_table *table, struct p4tc_table_entry_key *key) + __must_hold(RCU) +{ + struct rhlist_head *bucket_list; + struct p4tc_table_entry *entry_curr; + + bucket_list = + rhltable_lookup(&table->tbl_entries, key, entry_hlt_params); + if (!bucket_list) + return NULL; + + rht_entry(entry_curr, bucket_list, ht_node); + + return entry_curr; +} + +static void mask_key(const struct p4tc_table_entry_mask *mask, u8 *masked_key, + u8 *skb_key) +{ + int i; + + for (i = 0; i < BITS_TO_BYTES(mask->sz); i++) + masked_key[i] = skb_key[i] & mask->fa_value[i]; +} + +struct p4tc_table_entry *p4tc_table_entry_lookup(struct sk_buff *skb, + struct p4tc_table *table, + u32 keysz) +{ + const struct p4tc_table_entry_mask **masks_array; + u32 smallest_prio = U32_MAX; + struct p4tc_table_entry *entry = NULL; + struct p4tc_percpu_scratchpad *pad; + struct p4tc_table_entry_key *key; + int i; + + pad = this_cpu_ptr(&p4tc_percpu_scratchpad); + + key = (struct p4tc_table_entry_key *)&pad->keysz; + key->keysz = keysz; + key->maskid = 0; + + if (table->tbl_type == P4TC_TABLE_TYPE_EXACT) + return __p4tc_entry_lookup_fast(table, key); + + masks_array = (const struct p4tc_table_entry_mask **)rcu_dereference(table->tbl_masks_array); + for (i = 0; i < table->tbl_curr_num_masks; i++) { + u8 __mkey[sizeof(*key) + BITS_TO_BYTES(P4TC_MAX_KEYSZ)]; + const struct p4tc_table_entry_mask *mask = masks_array[i]; + struct p4tc_table_entry_key *mkey = (void *)&__mkey; + struct p4tc_table_entry *entry_curr = NULL; + + mkey->keysz = key->keysz; + mkey->maskid = mask->mask_id; + mask_key(mask, mkey->fa_key, key->fa_key); + + if (table->tbl_type == P4TC_TABLE_TYPE_LPM) { + entry_curr = __p4tc_entry_lookup_fast(table, mkey); + if (entry_curr) + return entry_curr; + } else { + entry_curr = __p4tc_entry_lookup(table, mkey); + + if (entry_curr) { + struct p4tc_table_entry_value *value = + p4tc_table_entry_value(entry_curr); + if (value->prio <= smallest_prio) { + smallest_prio = value->prio; + entry = entry_curr; + } + } + } + } + + return entry; +} + +#define tcf_table_entry_mask_find_byid(table, id) \ + (idr_find(&(table)->tbl_masks_idr, id)) + +static void gen_exact_mask(u8 *mask, u32 mask_size) +{ + int i; + + for (i = 0; i < mask_size; i++) { + mask[i] = 0xFF; + } +} + +static int p4tca_table_get_entry_keys(struct sk_buff *skb, + struct p4tc_table *table, + struct p4tc_table_entry *entry) +{ + unsigned char *b = nlmsg_get_pos(skb); + int ret = -ENOMEM; + struct p4tc_table_entry_mask *mask; + u32 key_sz_bytes; + + if (table->tbl_type == P4TC_TABLE_TYPE_EXACT) { + u8 mask_value[BITS_TO_BYTES(P4TC_MAX_KEYSZ)] = { 0 }; + + key_sz_bytes = BITS_TO_BYTES(entry->key.keysz); + if (nla_put(skb, P4TC_ENTRY_KEY_BLOB, key_sz_bytes, + entry->key.fa_key)) + goto out_nlmsg_trim; + + gen_exact_mask(mask_value, key_sz_bytes); + if (nla_put(skb, P4TC_ENTRY_MASK_BLOB, key_sz_bytes, mask_value)) + goto out_nlmsg_trim; + } else { + key_sz_bytes = BITS_TO_BYTES(entry->key.keysz); + if (nla_put(skb, P4TC_ENTRY_KEY_BLOB, key_sz_bytes, + entry->key.fa_key)) + goto out_nlmsg_trim; + + mask = tcf_table_entry_mask_find_byid(table, entry->key.maskid); + if (nla_put(skb, P4TC_ENTRY_MASK_BLOB, key_sz_bytes, + mask->fa_value)) + goto out_nlmsg_trim; + } + + return 0; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static void p4tc_table_entry_tm_dump(struct p4tc_table_entry_tm *dtm, + struct p4tc_table_entry_tm *stm) +{ + unsigned long now = jiffies; + + dtm->created = stm->created ? + jiffies_to_clock_t(now - stm->created) : 0; + dtm->lastused = stm->lastused ? + jiffies_to_clock_t(now - stm->lastused) : 0; + dtm->firstused = stm->firstused ? + jiffies_to_clock_t(now - stm->firstused) : 0; +} + +#define P4TC_ENTRY_MAX_IDS (P4TC_PATH_MAX - 1) + +int p4tca_table_get_entry_fill(struct sk_buff *skb, struct p4tc_table *table, + struct p4tc_table_entry *entry, u32 tbl_id) +{ + unsigned char *b = nlmsg_get_pos(skb); + int ret = -ENOMEM; + struct p4tc_table_entry_value *value; + struct nlattr *nest, *nest_acts; + struct p4tc_table_entry_tm dtm, *tm; + u32 ids[P4TC_ENTRY_MAX_IDS]; + + ids[P4TC_TBLID_IDX - 1] = tbl_id; + + if (nla_put(skb, P4TC_PATH, P4TC_ENTRY_MAX_IDS * sizeof(u32), ids)) + goto out_nlmsg_trim; + + nest = nla_nest_start(skb, P4TC_PARAMS); + if (!nest) + goto out_nlmsg_trim; + + value = p4tc_table_entry_value(entry); + + if (nla_put_u32(skb, P4TC_ENTRY_PRIO, value->prio)) + goto out_nlmsg_trim; + + if (p4tca_table_get_entry_keys(skb, table, entry) < 0) + goto out_nlmsg_trim; + + if (value->acts) { + nest_acts = nla_nest_start(skb, P4TC_ENTRY_ACT); + if (tcf_action_dump(skb, value->acts, 0, 0, false) < 0) + goto out_nlmsg_trim; + nla_nest_end(skb, nest_acts); + } + + if (nla_put_u16(skb, P4TC_ENTRY_PERMISSIONS, value->permissions)) + goto out_nlmsg_trim; + + tm = rtnl_dereference(value->tm); + + if (nla_put_u8(skb, P4TC_ENTRY_CREATE_WHODUNNIT, tm->who_created)) + goto out_nlmsg_trim; + + if (tm->who_updated) { + if (nla_put_u8(skb, P4TC_ENTRY_UPDATE_WHODUNNIT, + tm->who_updated)) + goto out_nlmsg_trim; + } + + p4tc_table_entry_tm_dump(&dtm, tm); + if (nla_put_64bit(skb, P4TC_ENTRY_TM, sizeof(dtm), &dtm, + P4TC_ENTRY_PAD)) + goto out_nlmsg_trim; + + nla_nest_end(skb, nest); + + return skb->len; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static const struct nla_policy p4tc_entry_policy[P4TC_ENTRY_MAX + 1] = { + [P4TC_ENTRY_TBLNAME] = { .type = NLA_STRING }, + [P4TC_ENTRY_KEY_BLOB] = { .type = NLA_BINARY }, + [P4TC_ENTRY_MASK_BLOB] = { .type = NLA_BINARY }, + [P4TC_ENTRY_PRIO] = { .type = NLA_U32 }, + [P4TC_ENTRY_ACT] = { .type = NLA_NESTED }, + [P4TC_ENTRY_TM] = { .type = NLA_BINARY, + .len = sizeof(struct p4tc_table_entry_tm) }, + [P4TC_ENTRY_WHODUNNIT] = { .type = NLA_U8 }, + [P4TC_ENTRY_CREATE_WHODUNNIT] = { .type = NLA_U8 }, + [P4TC_ENTRY_UPDATE_WHODUNNIT] = { .type = NLA_U8 }, + [P4TC_ENTRY_PERMISSIONS] = NLA_POLICY_MAX(NLA_U16, P4TC_MAX_PERMISSION), +}; + +static struct p4tc_table_entry_mask * +tcf_table_entry_mask_find_byvalue(struct p4tc_table *table, + struct p4tc_table_entry_mask *mask) +{ + struct p4tc_table_entry_mask *mask_cur; + unsigned long mask_id, tmp; + + idr_for_each_entry_ul(&table->tbl_masks_idr, mask_cur, tmp, mask_id) { + if (mask_cur->sz == mask->sz) { + u32 mask_sz_bytes = BITS_TO_BYTES(mask->sz); + void *curr_mask_value = mask_cur->fa_value; + void *mask_value = mask->fa_value; + + if (memcmp(curr_mask_value, mask_value, mask_sz_bytes) == 0) + return mask_cur; + } + } + + return NULL; +} + +static void __tcf_table_entry_mask_del(struct p4tc_table *table, + struct p4tc_table_entry_mask *mask) +{ + if (table->tbl_type == P4TC_TABLE_TYPE_TERNARY) { + table->tbl_masks_array[mask->mask_index] = NULL; + bitmap_set(table->tbl_free_masks_bitmap, mask->mask_index, 1); + } else if (table->tbl_type == P4TC_TABLE_TYPE_LPM) { + int i; + + for (i = mask->mask_index; i < table->tbl_curr_num_masks - 1; i++) { + table->tbl_masks_array[i] = table->tbl_masks_array[i + 1]; + } + table->tbl_masks_array[table->tbl_curr_num_masks - 1] = NULL; + } + + table->tbl_curr_num_masks--; +} + +static void tcf_table_entry_mask_del(struct p4tc_table *table, + struct p4tc_table_entry *entry) +{ + const u32 mask_id = entry->key.maskid; + struct p4tc_table_entry_mask *mask_found; + + /* Will always be found */ + mask_found = tcf_table_entry_mask_find_byid(table, mask_id); + + /* Last reference, can delete */ + if (refcount_dec_if_one(&mask_found->mask_ref)) { + spin_lock_bh(&table->tbl_masks_idr_lock); + idr_remove(&table->tbl_masks_idr, mask_found->mask_id); + __tcf_table_entry_mask_del(table, mask_found); + spin_unlock_bh(&table->tbl_masks_idr_lock); + kfree_rcu(mask_found, rcu); + } else { + if (!refcount_dec_not_one(&mask_found->mask_ref)) + pr_warn("Mask was deleted in parallel"); + } +} + +static inline u32 p4tc_ffs(u8 *ptr, size_t len) +{ + int i; + + for (i = 0; i < len; i++) { + int pos = ffs(ptr[i]); + + if (pos) + return (i * 8) + pos; + } + + return 0; +} + +static inline u32 p4tc_fls(u8 *ptr, size_t len) +{ + int i; + + for (i = len - 1; i >= 0; i--) { + int pos = fls(ptr[i]); + + if (pos) + return (i * 8) + pos; + } + + return 0; +} + +static inline u32 find_lpm_mask(struct p4tc_table *table, u8 *ptr) +{ + u32 ret; +#if defined(__LITTLE_ENDIAN_BITFIELD) + ret = p4tc_fls(ptr, BITS_TO_BYTES(table->tbl_keysz)); +#else + ret = p4tc_ffs(ptr, BITS_TO_BYTES(table->tbl_keysz)); +#endif + return ret ?: table->tbl_keysz; +} + +static inline int p4tc_table_lpm_mask_insert(struct p4tc_table *table, + struct p4tc_table_entry_mask *mask) +{ + const u32 nmasks = table->tbl_curr_num_masks ?: 1; + int pos; + + for (pos = 0; pos < nmasks; pos++) { + u32 mask_value = find_lpm_mask(table, mask->fa_value); + + if (table->tbl_masks_array[pos]) { + u32 array_mask_value; + + array_mask_value = find_lpm_mask(table, table->tbl_masks_array[pos]->fa_value); + + if (mask_value > array_mask_value) { + /* shift masks to the right (will keep invariant) */ + u32 tail = nmasks; + + while (tail > pos + 1) { + table->tbl_masks_array[tail] = + table->tbl_masks_array[tail - 1]; + tail--; + } + table->tbl_masks_array[pos + 1] = + table->tbl_masks_array[pos]; + /* assign to pos */ + break; + } + } else { + /* pos is empty, assign to pos */ + break; + } + } + + mask->mask_index = pos; + table->tbl_masks_array[pos] = mask; + table->tbl_curr_num_masks++; + + return 0; +} + +static inline int +p4tc_table_ternary_mask_insert(struct p4tc_table *table, + struct p4tc_table_entry_mask *mask) +{ + unsigned long pos = + find_first_bit(table->tbl_free_masks_bitmap, P4TC_MAX_TMASKS); + if (pos == P4TC_MAX_TMASKS) + return -ENOSPC; + + mask->mask_index = pos; + table->tbl_masks_array[pos] = mask; + bitmap_clear(table->tbl_free_masks_bitmap, pos, 1); + table->tbl_curr_num_masks++; + + return 0; +} + +static inline int p4tc_table_add_mask_array(struct p4tc_table *table, + struct p4tc_table_entry_mask *mask) +{ + if (table->tbl_max_masks < table->tbl_curr_num_masks + 1) + return -ENOSPC; + + switch (table->tbl_type) { + case P4TC_TABLE_TYPE_TERNARY: + return p4tc_table_ternary_mask_insert(table, mask); + case P4TC_TABLE_TYPE_LPM: + return p4tc_table_lpm_mask_insert(table, mask); + default: + return -ENOSPC; + } +} + +/* TODO: Ordering optimisation for LPM */ +static struct p4tc_table_entry_mask * +tcf_table_entry_mask_add(struct p4tc_table *table, + struct p4tc_table_entry *entry, + struct p4tc_table_entry_mask *mask) +{ + struct p4tc_table_entry_mask *mask_found; + int ret; + + mask_found = tcf_table_entry_mask_find_byvalue(table, mask); + /* Only add mask if it was not already added */ + if (!mask_found) { + struct p4tc_table_entry_mask *nmask; + size_t mask_sz_bytes = BITS_TO_BYTES(mask->sz); + + nmask = kzalloc(struct_size(mask_found, fa_value, mask_sz_bytes), GFP_ATOMIC); + if (!nmask) + return ERR_PTR(-ENOMEM); + + memcpy(nmask->fa_value, mask->fa_value, mask_sz_bytes); + + nmask->mask_id = 1; + nmask->sz = mask->sz; + refcount_set(&nmask->mask_ref, 1); + + spin_lock_bh(&table->tbl_masks_idr_lock); + ret = idr_alloc_u32(&table->tbl_masks_idr, nmask, + &nmask->mask_id, UINT_MAX, GFP_ATOMIC); + if (ret < 0) + goto unlock; + + ret = p4tc_table_add_mask_array(table, nmask); + if (ret < 0) + goto unlock; +unlock: + spin_unlock_bh(&table->tbl_masks_idr_lock); + if (ret < 0) { + kfree(nmask); + return ERR_PTR(ret); + } + entry->key.maskid = nmask->mask_id; + mask_found = nmask; + } else { + if (!refcount_inc_not_zero(&mask_found->mask_ref)) + return ERR_PTR(-EBUSY); + entry->key.maskid = mask_found->mask_id; + } + + return mask_found; +} + +static void tcf_table_entry_del_act(struct p4tc_table_entry *entry) +{ + struct p4tc_table_entry_value *value = p4tc_table_entry_value(entry); + + p4tc_action_destroy(value->acts); + kfree(entry); +} + +static void tcf_table_entry_del_act_work(struct work_struct *work) +{ + struct p4tc_table_entry_work *entry_work = + container_of(work, typeof(*entry_work), work); + struct p4tc_pipeline *pipeline = entry_work->pipeline; + + tcf_table_entry_del_act(entry_work->entry); + put_net(pipeline->net); + + refcount_dec(&entry_work->pipeline->p_entry_deferal_ref); + + kfree(entry_work); +} + +static void tcf_table_entry_put(struct p4tc_table_entry *entry) +{ + struct p4tc_table_entry_value *value = p4tc_table_entry_value(entry); + struct p4tc_table_entry_tm *tm; + + tm = rcu_dereference(value->tm); + kfree(tm); + + if (value->acts) { + struct p4tc_table_entry_work *entry_work = value->entry_work; + struct p4tc_pipeline *pipeline = entry_work->pipeline; + struct net *net; + + if (entry_work->defer_deletion) { + net = get_net(pipeline->net); + refcount_inc(&entry_work->pipeline->p_entry_deferal_ref); + schedule_work(&entry_work->work); + } else { + kfree(entry_work); + tcf_table_entry_del_act(entry); + } + } else { + kfree(value->entry_work); + kfree(entry); + } +} + +static void tcf_table_entry_put_rcu(struct rcu_head *rcu) +{ + struct p4tc_table_entry *entry; + + entry = container_of(rcu, struct p4tc_table_entry, rcu); + + tcf_table_entry_put(entry); +} + +static int tcf_table_entry_destroy(struct p4tc_table *table, + struct p4tc_table_entry *entry, + bool remove_from_hash) +{ + struct p4tc_table_entry_value *value = p4tc_table_entry_value(entry); + + /* Entry was deleted in parallel */ + if (!refcount_dec_if_one(&value->entries_ref)) + return -EBUSY; + + if (remove_from_hash) + rhltable_remove(&table->tbl_entries, &entry->ht_node, + entry_hlt_params); + + ida_free(&table->tbl_prio_idr, value->prio); + + if (table->tbl_type != P4TC_TABLE_TYPE_EXACT) + tcf_table_entry_mask_del(table, entry); + + if (value->entry_work->defer_deletion) { + call_rcu(&entry->rcu, tcf_table_entry_put_rcu); + } else { + synchronize_rcu(); + tcf_table_entry_put(entry); + } + + return 0; +} + +/* Only deletes entries when called from pipeline delete, which means + * pipeline->p_ref will already be 0, so no need to use that refcount. + */ +void tcf_table_entry_destroy_hash(void *ptr, void *arg) +{ + struct p4tc_table *table = arg; + struct p4tc_table_entry *entry = ptr; + struct p4tc_table_entry_value *value = p4tc_table_entry_value(entry); + + refcount_dec(&table->tbl_entries_ref); + + value->entry_work->defer_deletion = false; + tcf_table_entry_destroy(table, entry, false); +} + +static void tcf_table_entry_put_table(struct p4tc_pipeline *pipeline, + struct p4tc_table *table) +{ + /* If we are here, it means that this was just incremented, so it should be > 1 */ + WARN_ON(!refcount_dec_not_one(&table->tbl_ctrl_ref)); + WARN_ON(!refcount_dec_not_one(&pipeline->p_ctrl_ref)); +} + +static int tcf_table_entry_get_table(struct net *net, + struct p4tc_pipeline **pipeline, + struct p4tc_table **table, + struct nlattr **tb, u32 *ids, char *p_name, + struct netlink_ext_ack *extack) + __must_hold(RCU) +{ + u32 pipeid, tbl_id; + char *tblname; + int ret; + + pipeid = ids[P4TC_PID_IDX]; + + *pipeline = tcf_pipeline_find_byany(net, p_name, pipeid, extack); + if (IS_ERR(*pipeline)) { + ret = PTR_ERR(*pipeline); + goto out; + } + + if (!refcount_inc_not_zero(&((*pipeline)->p_ctrl_ref))) { + NL_SET_ERR_MSG(extack, "Pipeline is stale"); + ret = -EBUSY; + goto out; + } + + tbl_id = ids[P4TC_TBLID_IDX]; + + tblname = tb[P4TC_ENTRY_TBLNAME] ? nla_data(tb[P4TC_ENTRY_TBLNAME]) : NULL; + *table = tcf_table_find_byany(*pipeline, tblname, tbl_id, extack); + if (IS_ERR(*table)) { + ret = PTR_ERR(*table); + goto dec_pipeline_refcount; + } + if (!refcount_inc_not_zero(&((*table)->tbl_ctrl_ref))) { + NL_SET_ERR_MSG(extack, "Table is marked for deletion"); + ret = -EBUSY; + goto dec_pipeline_refcount; + } + + return 0; + +/* If we are here, it means that this was just incremented, so it should be > 1 */ +dec_pipeline_refcount: + WARN_ON(!refcount_dec_not_one(&((*pipeline)->p_ctrl_ref))); + +out: + return ret; +} + +static void tcf_table_entry_assign_key_exact(struct p4tc_table_entry_key *key, + u8 *keyblob) +{ + memcpy(key->fa_key, keyblob, BITS_TO_BYTES(key->keysz)); +} + +static void +tcf_table_entry_assign_key_generic(struct p4tc_table_entry_key *key, + struct p4tc_table_entry_mask *mask, + u8 *keyblob, u8 *maskblob) +{ + u32 keysz = BITS_TO_BYTES(key->keysz); + + memcpy(key->fa_key, keyblob, keysz); + memcpy(mask->fa_value, maskblob, keysz); +} + +static void tcf_table_entry_assign_key(struct p4tc_table *table, + struct p4tc_table_entry_key *key, + struct p4tc_table_entry_mask *mask, + u8 *keyblob, u8 *maskblob) +{ + if (table->tbl_type == P4TC_TABLE_TYPE_EXACT) + tcf_table_entry_assign_key_exact(key, keyblob); + else + tcf_table_entry_assign_key_generic(key, mask, keyblob, + maskblob); +} + +static int tcf_table_entry_extract_key(struct p4tc_table *table, + struct nlattr **tb, + struct p4tc_table_entry_key *key, + struct p4tc_table_entry_mask *mask, + struct netlink_ext_ack *extack) +{ + u32 keysz; + + if (NL_REQ_ATTR_CHECK(extack, NULL, tb, P4TC_ENTRY_KEY_BLOB)) { + NL_SET_ERR_MSG(extack, "Must specify key blobs"); + return -EINVAL; + } + + if (NL_REQ_ATTR_CHECK(extack, NULL, tb, P4TC_ENTRY_MASK_BLOB)) { + NL_SET_ERR_MSG(extack, "Must specify mask blobs"); + return -EINVAL; + } + + keysz = nla_len(tb[P4TC_ENTRY_KEY_BLOB]); + if (BITS_TO_BYTES(key->keysz) != keysz) { + NL_SET_ERR_MSG(extack, + "Key blob size and table key size differ"); + return -EINVAL; + } + + if (keysz != nla_len(tb[P4TC_ENTRY_MASK_BLOB])) { + NL_SET_ERR_MSG(extack, + "Key and mask blob must have the same length"); + return -EINVAL; + } + + tcf_table_entry_assign_key(table, key, mask, + nla_data(tb[P4TC_ENTRY_KEY_BLOB]), + nla_data(tb[P4TC_ENTRY_MASK_BLOB])); + + return 0; +} + +static void tcf_table_entry_build_key(struct p4tc_table *table, + struct p4tc_table_entry_key *key, + struct p4tc_table_entry_mask *mask) +{ + int i; + + if (table->tbl_type == P4TC_TABLE_TYPE_EXACT) + return; + + key->maskid = mask->mask_id; + + for (i = 0; i < BITS_TO_BYTES(key->keysz); i++) + key->fa_key[i] &= mask->fa_value[i]; +} + +static int ___tcf_table_entry_del(struct p4tc_pipeline *pipeline, + struct p4tc_table *table, + struct p4tc_table_entry *entry, + bool from_control) + __must_hold(RCU) +{ + struct p4tc_table_entry_value *value = p4tc_table_entry_value(entry); + int ret = 0; + + if (from_control) { + if (!p4tc_ctrl_delete_ok(value->permissions)) + return -EPERM; + } else { + if (!p4tc_data_delete_ok(value->permissions)) + return -EPERM; + } + + if (!refcount_dec_not_one(&table->tbl_entries_ref)) + return -EBUSY; + + if (tcf_table_entry_destroy(table, entry, true) < 0) { + ret = -EBUSY; + goto inc_entries_ref; + } + + goto out; + +inc_entries_ref: + WARN_ON(!refcount_inc_not_zero(&table->tbl_entries_ref)); + +out: + return ret; +} + +/* Internal function which will be called by the data path */ +int __tcf_table_entry_del(struct p4tc_pipeline *pipeline, + struct p4tc_table *table, + struct p4tc_table_entry_key *key, + struct p4tc_table_entry_mask *mask, u32 prio) +{ + struct p4tc_table_entry_value *value; + struct p4tc_table_entry *entry; + int ret; + + tcf_table_entry_build_key(table, key, mask); + + entry = p4tc_entry_lookup(table, key, prio); + if (!entry) + return -ENOENT; + + value = p4tc_table_entry_value(entry); + + value->entry_work->defer_deletion = true; + ret = ___tcf_table_entry_del(pipeline, table, entry, false); + + return ret; +} + +static int tcf_table_entry_gd(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, struct nlattr *arg, u32 *ids, + struct p4tc_nl_pname *nl_pname, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_ENTRY_MAX + 1] = { NULL }; + struct p4tc_table_entry *entry = NULL; + struct p4tc_pipeline *pipeline = NULL; + struct p4tc_table_entry_mask *mask = NULL, *new_mask; + struct p4tc_table_entry_value *value; + struct p4tc_table_entry_key *key; + struct p4tc_table *table; + u32 keysz_bits; + u32 keysz_bytes; + u32 prio; + int ret; + + ret = nla_parse_nested(tb, P4TC_ENTRY_MAX, arg, p4tc_entry_policy, + extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(extack, arg, tb, P4TC_ENTRY_PRIO)) { + NL_SET_ERR_MSG(extack, "Must specify table entry priority"); + return -EINVAL; + } + prio = nla_get_u32(tb[P4TC_ENTRY_PRIO]); + + rcu_read_lock(); + ret = tcf_table_entry_get_table(net, &pipeline, &table, tb, ids, + nl_pname->data, extack); + rcu_read_unlock(); + if (ret < 0) + return ret; + + if (n->nlmsg_type == RTM_P4TC_DEL && !pipeline_sealed(pipeline)) { + NL_SET_ERR_MSG(extack, + "Unable to delete table entry in unsealed pipeline"); + ret = -EINVAL; + goto table_put; + } + + keysz_bits = table->tbl_keysz; + keysz_bytes = P4TC_KEYSZ_BYTES(table->tbl_keysz); + + key = kzalloc(struct_size(key, fa_key, keysz_bytes), GFP_KERNEL); + if (!key) { + NL_SET_ERR_MSG(extack, "Unable to allocate key"); + ret = -ENOMEM; + goto table_put; + } + + key->keysz = keysz_bits; + + if (table->tbl_type != P4TC_TABLE_TYPE_EXACT) { + mask = kzalloc(struct_size(mask, fa_value, keysz_bytes), + GFP_KERNEL); + if (!mask) { + NL_SET_ERR_MSG(extack, "Failed to allocate mask"); + ret = -ENOMEM; + goto free_key; + } + mask->sz = key->keysz; + } + + ret = tcf_table_entry_extract_key(table, tb, key, mask, extack); + if (ret < 0) { + if (table->tbl_type != P4TC_TABLE_TYPE_EXACT) { + kfree(mask); + } + goto free_key; + } + + if (table->tbl_type != P4TC_TABLE_TYPE_EXACT) { + new_mask = tcf_table_entry_mask_find_byvalue(table, mask); + kfree(mask); + if (!new_mask) { + NL_SET_ERR_MSG(extack, "Unable to find entry"); + ret = -ENOENT; + goto free_key; + } else { + mask = new_mask; + } + } + + tcf_table_entry_build_key(table, key, mask); + + rcu_read_lock(); + entry = p4tc_entry_lookup(table, key, prio); + if (!entry) { + NL_SET_ERR_MSG(extack, "Unable to find entry"); + ret = -EINVAL; + goto unlock; + } + + value = p4tc_table_entry_value(entry); + if (n->nlmsg_type == RTM_P4TC_GET) { + if (!p4tc_ctrl_read_ok(value->permissions)) { + NL_SET_ERR_MSG(extack, + "Permission denied: Unable to read table entry"); + ret = -EINVAL; + goto unlock; + } + } + + if (p4tca_table_get_entry_fill(skb, table, entry, table->tbl_id) <= 0) { + NL_SET_ERR_MSG(extack, "Unable to fill table entry attributes"); + ret = -EINVAL; + goto unlock; + } + + if (n->nlmsg_type == RTM_P4TC_DEL) { + value->entry_work->defer_deletion = true; + ret = ___tcf_table_entry_del(pipeline, table, entry, true); + if (ret < 0) + goto unlock; + } + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + ret = 0; + + goto unlock; + +unlock: + rcu_read_unlock(); + +free_key: + kfree(key); + +table_put: + tcf_table_entry_put_table(pipeline, table); + + return ret; +} + +static int tcf_table_entry_flush(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, struct nlattr *arg, + u32 *ids, struct p4tc_nl_pname *nl_pname, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_ENTRY_MAX + 1] = { NULL }; + unsigned char *b = nlmsg_get_pos(skb); + int ret = 0; + int i = 0; + struct p4tc_pipeline *pipeline; + struct p4tc_table_entry *entry; + struct p4tc_table *table; + u32 arg_ids[P4TC_PATH_MAX - 1]; + struct rhashtable_iter iter; + + if (arg) { + ret = nla_parse_nested(tb, P4TC_ENTRY_MAX, arg, + p4tc_entry_policy, extack); + if (ret < 0) + return ret; + } + + rcu_read_lock(); + ret = tcf_table_entry_get_table(net, &pipeline, &table, tb, ids, + nl_pname->data, extack); + rcu_read_unlock(); + if (ret < 0) + return ret; + + if (!ids[P4TC_TBLID_IDX]) + arg_ids[P4TC_TBLID_IDX - 1] = table->tbl_id; + + if (nla_put(skb, P4TC_PATH, sizeof(arg_ids), arg_ids)) { + ret = -ENOMEM; + goto out_nlmsg_trim; + } + + rhltable_walk_enter(&table->tbl_entries, &iter); + do { + rhashtable_walk_start(&iter); + + while ((entry = rhashtable_walk_next(&iter)) && !IS_ERR(entry)) { + struct p4tc_table_entry_value *value = + p4tc_table_entry_value(entry); + if (!p4tc_ctrl_delete_ok(value->permissions)) { + ret = -EPERM; + continue; + } + + if (!refcount_dec_not_one(&table->tbl_entries_ref)) { + NL_SET_ERR_MSG(extack, "Table entry is stale"); + ret = -EBUSY; + rhashtable_walk_stop(&iter); + goto walk_exit; + } + + value->entry_work->defer_deletion = true; + if (tcf_table_entry_destroy(table, entry, true) < 0) { + ret = -EBUSY; + continue; + } + i++; + } + + rhashtable_walk_stop(&iter); + } while (entry == ERR_PTR(-EAGAIN)); + +walk_exit: + rhashtable_walk_exit(&iter); + + nla_put_u32(skb, P4TC_COUNT, i); + + if (ret < 0) { + if (i == 0) { + if (!extack->_msg) + NL_SET_ERR_MSG(extack, + "Unable to flush any entries"); + goto out_nlmsg_trim; + } else { + if (!extack->_msg) + NL_SET_ERR_MSG(extack, + "Unable to flush all entries"); + } + } + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + ret = 0; + goto table_put; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + +/* If we are here, it means that this was just incremented, so it should be > 1 */ +table_put: + tcf_table_entry_put_table(pipeline, table); + + return ret; +} + +/* Invoked from both control and data path */ +static int __tcf_table_entry_create(struct p4tc_pipeline *pipeline, + struct p4tc_table *table, + struct p4tc_table_entry *entry, + struct p4tc_table_entry_mask *mask, + u16 whodunnit, bool from_control) + __must_hold(RCU) +{ + struct p4tc_table_perm *tbl_perm; + struct p4tc_table_entry_mask *mask_found = NULL; + struct p4tc_table_entry_work *entry_work; + struct p4tc_table_entry_value *value; + struct p4tc_table_entry_tm *dtm; + u16 permissions; + int ret; + + value = p4tc_table_entry_value(entry); + refcount_set(&value->entries_ref, 1); + + tbl_perm = rcu_dereference(table->tbl_permissions); + permissions = tbl_perm->permissions; + if (from_control) { + if (!p4tc_ctrl_create_ok(permissions)) + return -EPERM; + } else { + if (!p4tc_data_create_ok(permissions)) + return -EPERM; + } + + if (table->tbl_type != P4TC_TABLE_TYPE_EXACT) { + mask_found = tcf_table_entry_mask_add(table, entry, mask); + if (IS_ERR(mask_found)) { + ret = PTR_ERR(mask_found); + goto out; + } + } + + tcf_table_entry_build_key(table, &entry->key, mask_found); + + if (!refcount_inc_not_zero(&table->tbl_entries_ref)) { + ret = -EBUSY; + goto rm_masks_idr; + } + + if (p4tc_entry_lookup(table, &entry->key, value->prio)) { + ret = -EEXIST; + goto dec_entries_ref; + } + + dtm = kzalloc(sizeof(*dtm), GFP_ATOMIC); + if (!dtm) { + ret = -ENOMEM; + goto dec_entries_ref; + } + + dtm->who_created = whodunnit; + dtm->created = jiffies; + dtm->firstused = 0; + dtm->lastused = jiffies; + + rcu_assign_pointer(value->tm, dtm); + + entry_work = kzalloc(sizeof(*entry_work), GFP_ATOMIC); + if (!entry_work) { + ret = -ENOMEM; + goto free_tm; + } + + entry_work->pipeline = pipeline; + entry_work->entry = entry; + value->entry_work = entry_work; + + INIT_WORK(&entry_work->work, tcf_table_entry_del_act_work); + + if (rhltable_insert(&table->tbl_entries, &entry->ht_node, + entry_hlt_params) < 0) { + ret = -EBUSY; + goto free_entry_work; + } + + return 0; + +free_entry_work: + kfree(entry_work); + +free_tm: + kfree(dtm); +/*If we are here, it means that this was just incremented, so it should be > 1 */ +dec_entries_ref: + WARN_ON(!refcount_dec_not_one(&table->tbl_entries_ref)); + +rm_masks_idr: + if (table->tbl_type != P4TC_TABLE_TYPE_EXACT) + tcf_table_entry_mask_del(table, entry); + +out: + return ret; +} + +/* Invoked from both control and data path */ +static int __tcf_table_entry_update(struct p4tc_pipeline *pipeline, + struct p4tc_table *table, + struct p4tc_table_entry *entry, + struct p4tc_table_entry_mask *mask, + u16 whodunnit, bool from_control) + __must_hold(RCU) +{ + struct p4tc_table_entry_mask *mask_found = NULL; + struct p4tc_table_entry_work *entry_work; + struct p4tc_table_entry_value *value_old; + struct p4tc_table_entry_value *value; + struct p4tc_table_entry *entry_old; + struct p4tc_table_entry_tm *tm_old; + struct p4tc_table_entry_tm *tm; + int ret; + + value = p4tc_table_entry_value(entry); + refcount_set(&value->entries_ref, 1); + + if (table->tbl_type != P4TC_TABLE_TYPE_EXACT) { + mask_found = tcf_table_entry_mask_add(table, entry, mask); + if (IS_ERR(mask_found)) { + ret = PTR_ERR(mask_found); + goto out; + } + } + + tcf_table_entry_build_key(table, &entry->key, mask_found); + + entry_old = p4tc_entry_lookup(table, &entry->key, value->prio); + if (!entry_old) { + ret = -ENOENT; + goto rm_masks_idr; + } + + value_old = p4tc_table_entry_value(entry_old); + + if (from_control) { + if (!p4tc_ctrl_update_ok(value_old->permissions)) { + ret = -EPERM; + goto rm_masks_idr; + } + } else { + if (!p4tc_data_update_ok(value_old->permissions)) { + ret = -EPERM; + goto rm_masks_idr; + } + } + + if (refcount_read(&value_old->entries_ref) > 1) { + ret = -EBUSY; + goto rm_masks_idr; + } + + tm = kzalloc(sizeof(*tm), GFP_ATOMIC); + if (!tm) { + ret = -ENOMEM; + goto rm_masks_idr; + } + + tm_old = rcu_dereference_protected(value_old->tm, 1); + *tm = *tm_old; + + tm->lastused = jiffies; + tm->who_updated = whodunnit; + + if (value->permissions == P4TC_PERMISSIONS_UNINIT) + value->permissions = value_old->permissions; + + rcu_assign_pointer(value->tm, tm); + + entry_work = kzalloc(sizeof(*(entry_work)), GFP_ATOMIC); + if (!entry_work) { + ret = -ENOMEM; + goto free_tm; + } + + entry_work->pipeline = pipeline; + entry_work->entry = entry; + value->entry_work = entry_work; + + INIT_WORK(&entry_work->work, tcf_table_entry_del_act_work); + + if (rhltable_insert(&table->tbl_entries, &entry->ht_node, + entry_hlt_params) < 0) { + ret = -EEXIST; + goto free_entry_work; + } + + value_old->entry_work->defer_deletion = true; + if (tcf_table_entry_destroy(table, entry_old, true) < 0) { + ret = -EBUSY; + goto out; + } + + return 0; + +free_entry_work: + kfree(entry_work); + +free_tm: + kfree(tm); + +rm_masks_idr: + if (table->tbl_type != P4TC_TABLE_TYPE_EXACT) + tcf_table_entry_mask_del(table, entry); + +out: + return ret; +} + +#define P4TC_DEFAULT_TENTRY_PERMISSIONS \ + (P4TC_CTRL_PERM_R | P4TC_CTRL_PERM_U | P4TC_CTRL_PERM_D | \ + P4TC_DATA_PERM_R | P4TC_DATA_PERM_X) + +static bool tcf_table_check_entry_acts(struct p4tc_table *table, + struct tc_action *entry_acts[], + struct list_head *allowed_acts, + int num_entry_acts) +{ + struct p4tc_table_act *table_act; + int i; + + for (i = 0; i < num_entry_acts; i++) { + const struct tc_action *entry_act = entry_acts[i]; + + list_for_each_entry(table_act, allowed_acts, node) { + if (table_act->ops->id == entry_act->ops->id && + !(table_act->flags & BIT(P4TC_TABLE_ACTS_DEFAULT_ONLY))) + return true; + } + } + + return false; +} + +static struct p4tc_table_entry *__tcf_table_entry_cu(struct net *net, u32 flags, + struct nlattr **tb, + struct p4tc_pipeline *pipeline, + struct p4tc_table *table, + struct netlink_ext_ack *extack) +{ + u8 __mask[sizeof(struct p4tc_table_entry_mask) + + BITS_TO_BYTES(P4TC_MAX_KEYSZ)] = { 0 }; + struct p4tc_table_entry_mask *mask = (void *)&__mask; + u8 whodunnit = P4TC_ENTITY_UNSPEC; + int ret = 0; + struct p4tc_table_entry_value *value; + struct p4tc_table_entry *entry; + u32 keysz_bits; + u32 keysz_bytes; + u32 entrysz; + u32 prio; + + prio = tb[P4TC_ENTRY_PRIO] ? nla_get_u32(tb[P4TC_ENTRY_PRIO]) : 0; + if (flags & NLM_F_REPLACE) { + if (!prio) { + NL_SET_ERR_MSG(extack, "Must specify entry priority"); + return ERR_PTR(-EINVAL); + } + } else { + if (prio) + ret = ida_alloc_range(&table->tbl_prio_idr, prio, + prio, GFP_ATOMIC); + else + ret = ida_alloc_min(&table->tbl_prio_idr, 1, + GFP_ATOMIC); + if (ret < 0) { + NL_SET_ERR_MSG(extack, + "Unable to allocate priority"); + return ERR_PTR(ret); + } + prio = ret; + + if (refcount_read(&table->tbl_entries_ref) > table->tbl_max_entries) { + NL_SET_ERR_MSG(extack, + "Table instance max entries reached"); + return ERR_PTR(-EINVAL); + } + } + + whodunnit = nla_get_u8(tb[P4TC_ENTRY_WHODUNNIT]); + + keysz_bits = table->tbl_keysz; + keysz_bytes = P4TC_KEYSZ_BYTES(keysz_bits); + + /* Entry memory layout: + * { entry | key __aligned(8) | value } + */ + entrysz = sizeof(*entry) + keysz_bytes + + sizeof(struct p4tc_table_entry_value); + + entry = kzalloc(entrysz, GFP_KERNEL); + if (!entry) { + NL_SET_ERR_MSG(extack, "Unable to allocate table entry"); + ret = -ENOMEM; + goto idr_rm; + } + + entry->key.keysz = keysz_bits; + mask->sz = keysz_bits; + + ret = tcf_table_entry_extract_key(table, tb, &entry->key, mask, extack); + if (ret < 0) + goto free_entry; + + value = p4tc_table_entry_value(entry); + value->prio = prio; + + if (tb[P4TC_ENTRY_PERMISSIONS]) { + const u16 tblperm = + rcu_dereference(table->tbl_permissions)->permissions; + u16 nlperm; + + nlperm = nla_get_u16(tb[P4TC_ENTRY_PERMISSIONS]); + if (p4tc_ctrl_create_ok(nlperm) || + p4tc_data_create_ok(nlperm)) { + NL_SET_ERR_MSG(extack, + "Create permission for table entry doesn't make sense"); + ret = -EINVAL; + goto free_entry; + } + if (!p4tc_data_read_ok(nlperm)) { + NL_SET_ERR_MSG(extack, + "Data path read permission must be set"); + ret = -EINVAL; + goto free_entry; + } + if (!p4tc_data_exec_ok(nlperm)) { + NL_SET_ERR_MSG(extack, + "Data path execute permissions for entry must be set"); + ret = -EINVAL; + goto free_entry; + } + + if (~tblperm & nlperm) { + NL_SET_ERR_MSG(extack, + "Trying to set permission bits which aren't allowed by table"); + ret = -EINVAL; + goto free_entry; + } + value->permissions = nlperm; + } else { + if (flags & NLM_F_REPLACE) + value->permissions = P4TC_PERMISSIONS_UNINIT; + else + value->permissions = P4TC_DEFAULT_TENTRY_PERMISSIONS; + } + + if (tb[P4TC_ENTRY_ACT]) { + + value->acts = kcalloc(TCA_ACT_MAX_PRIO, + sizeof(struct tc_action *), GFP_KERNEL); + if (!value->acts) { + ret = -ENOMEM; + goto free_entry; + } + + ret = p4tc_action_init(net, tb[P4TC_ENTRY_ACT], value->acts, + table->common.p_id, + TCA_ACT_FLAGS_NO_RTNL, extack); + if (ret < 0) { + kfree(value->acts); + value->acts = NULL; + goto free_entry; + } + + value->num_acts = ret; + + if (!tcf_table_check_entry_acts(table, value->acts, + &table->tbl_acts_list, ret)) { + ret = -EPERM; + NL_SET_ERR_MSG(extack, + "Action is not allowed as entry action"); + goto free_acts; + } + } + + rcu_read_lock(); + if (flags & NLM_F_REPLACE) + ret = __tcf_table_entry_update(pipeline, table, entry, mask, + whodunnit, true); + else + ret = __tcf_table_entry_create(pipeline, table, entry, mask, + whodunnit, true); + if (ret < 0) { + rcu_read_unlock(); + goto free_acts; + } + rcu_read_unlock(); + + return entry; + +free_acts: + p4tc_action_destroy(value->acts); + +free_entry: + kfree(entry); + +idr_rm: + if (!(flags & NLM_F_REPLACE)) + ida_free(&table->tbl_prio_idr, prio); + + return ERR_PTR(ret); +} + +static int tcf_table_entry_cu(struct sk_buff *skb, struct net *net, u32 flags, + struct nlattr *arg, u32 *ids, + struct p4tc_nl_pname *nl_pname, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_ENTRY_MAX + 1] = { NULL }; + struct p4tc_pipeline *pipeline; + struct p4tc_table_entry *entry; + struct p4tc_table *table; + int ret; + + ret = nla_parse_nested(tb, P4TC_ENTRY_MAX, arg, p4tc_entry_policy, + extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(extack, arg, tb, P4TC_ENTRY_WHODUNNIT)) { + NL_SET_ERR_MSG(extack, "Must specify whodunnit attribute"); + return -EINVAL; + } + + rcu_read_lock(); + ret = tcf_table_entry_get_table(net, &pipeline, &table, tb, ids, + nl_pname->data, extack); + rcu_read_unlock(); + if (ret < 0) + return ret; + + if (!pipeline_sealed(pipeline)) { + NL_SET_ERR_MSG(extack, + "Need to seal pipeline before issuing runtime command"); + ret = -EINVAL; + goto table_put; + } + + entry = __tcf_table_entry_cu(net, flags, tb, pipeline, table, extack); + if (IS_ERR(entry)) { + ret = PTR_ERR(entry); + goto table_put; + } + + if (p4tca_table_get_entry_fill(skb, table, entry, table->tbl_id) <= 0) + NL_SET_ERR_MSG(extack, "Unable to fill table entry attributes"); + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + +table_put: + tcf_table_entry_put_table(pipeline, table); + return ret; +} + +struct p4tc_table_entry * +tcf_table_const_entry_cu(struct net *net, + struct nlattr *arg, + struct p4tc_pipeline *pipeline, + struct p4tc_table *table, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_ENTRY_MAX + 1] = { NULL }; + int ret; + + ret = nla_parse_nested(tb, P4TC_ENTRY_MAX, arg, p4tc_entry_policy, + extack); + if (ret < 0) + return ERR_PTR(ret); + + if (NL_REQ_ATTR_CHECK(extack, arg, tb, P4TC_ENTRY_WHODUNNIT)) { + NL_SET_ERR_MSG(extack, "Must specify whodunnit attribute"); + return ERR_PTR(-EINVAL); + } + + return __tcf_table_entry_cu(net, 0, tb, pipeline, table, extack); +} + +static int tc_ctl_p4_get_1(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, u32 *ids, struct nlattr *arg, + struct p4tc_nl_pname *nl_pname, + struct netlink_ext_ack *extack) +{ + int ret = 0; + struct nlattr *tb[P4TC_MAX + 1]; + u32 *arg_ids; + + ret = nla_parse_nested(tb, P4TC_MAX, arg, p4tc_policy, extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(extack, arg, tb, P4TC_PATH)) { + NL_SET_ERR_MSG(extack, "Must specify object path"); + return -EINVAL; + } + + if (NL_REQ_ATTR_CHECK(extack, arg, tb, P4TC_PARAMS)) { + NL_SET_ERR_MSG(extack, "Must specify parameters"); + return -EINVAL; + } + + arg_ids = nla_data(tb[P4TC_PATH]); + memcpy(&ids[P4TC_TBLID_IDX], arg_ids, nla_len(tb[P4TC_PATH])); + + return tcf_table_entry_gd(net, skb, n, tb[P4TC_PARAMS], ids, nl_pname, + extack); +} + +static int tc_ctl_p4_delete_1(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, struct nlattr *arg, u32 *ids, + struct p4tc_nl_pname *nl_pname, + struct netlink_ext_ack *extack) +{ + int ret = 0; + struct nlattr *tb[P4TC_MAX + 1]; + u32 *arg_ids; + + ret = nla_parse_nested(tb, P4TC_MAX, arg, p4tc_policy, extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(extack, arg, tb, P4TC_PATH)) { + NL_SET_ERR_MSG(extack, "Must specify object path"); + return -EINVAL; + } + + arg_ids = nla_data(tb[P4TC_PATH]); + memcpy(&ids[P4TC_TBLID_IDX], arg_ids, nla_len(tb[P4TC_PATH])); + if (n->nlmsg_flags & NLM_F_ROOT) { + ret = tcf_table_entry_flush(net, skb, n, tb[P4TC_PARAMS], ids, + nl_pname, extack); + } else { + if (NL_REQ_ATTR_CHECK(extack, arg, tb, P4TC_PARAMS)) { + NL_SET_ERR_MSG(extack, "Must specify parameters"); + return -EINVAL; + } + ret = tcf_table_entry_gd(net, skb, n, tb[P4TC_PARAMS], ids, + nl_pname, extack); + } + + return ret; +} + +static int tc_ctl_p4_cu_1(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, u32 *ids, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, + struct netlink_ext_ack *extack) +{ + int ret = 0; + struct nlattr *tb[P4TC_MAX + 1]; + u32 *arg_ids; + + ret = nla_parse_nested(tb, P4TC_MAX, nla, p4tc_policy, extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(extack, nla, tb, P4TC_PATH)) { + NL_SET_ERR_MSG(extack, "Must specify object path"); + return -EINVAL; + } + + if (NL_REQ_ATTR_CHECK(extack, nla, tb, P4TC_PARAMS)) { + NL_SET_ERR_MSG(extack, "Must specify object attributes"); + return -EINVAL; + } + + arg_ids = nla_data(tb[P4TC_PATH]); + memcpy(&ids[P4TC_TBLID_IDX], arg_ids, nla_len(tb[P4TC_PATH])); + + return tcf_table_entry_cu(skb, net, n->nlmsg_flags, tb[P4TC_PARAMS], + ids, nl_pname, extack); +} + +static int tc_ctl_p4_table_n(struct sk_buff *skb, struct nlmsghdr *n, int cmd, + char *p_name, struct nlattr *nla, + struct netlink_ext_ack *extack) +{ + struct p4tcmsg *t = (struct p4tcmsg *)nlmsg_data(n); + struct net *net = sock_net(skb->sk); + u32 portid = NETLINK_CB(skb).portid; + u32 ids[P4TC_PATH_MAX] = { 0 }; + int ret = 0, ret_send; + struct nlattr *p4tca[P4TC_MSGBATCH_SIZE + 1]; + struct p4tc_nl_pname nl_pname; + struct sk_buff *new_skb; + struct p4tcmsg *t_new; + struct nlmsghdr *nlh; + struct nlattr *pnatt; + struct nlattr *root; + int i; + + ret = nla_parse_nested(p4tca, P4TC_MSGBATCH_SIZE, nla, NULL, extack); + if (ret < 0) + return ret; + + if (!p4tca[1]) { + NL_SET_ERR_MSG(extack, "No elements in root table array"); + return -EINVAL; + } + + new_skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!new_skb) + return -ENOBUFS; + + nlh = nlmsg_put(new_skb, portid, n->nlmsg_seq, cmd, sizeof(*t), + n->nlmsg_flags); + if (!nlh) + goto out; + + t_new = nlmsg_data(nlh); + t_new->pipeid = t->pipeid; + t_new->obj = t->obj; + ids[P4TC_PID_IDX] = t_new->pipeid; + + pnatt = nla_reserve(new_skb, P4TC_ROOT_PNAME, PIPELINENAMSIZ); + if (!pnatt) { + ret = -ENOMEM; + goto out; + } + + nl_pname.data = nla_data(pnatt); + if (!p_name) { + /* Filled up by the operation or forced failure */ + memset(nl_pname.data, 0, PIPELINENAMSIZ); + nl_pname.passed = false; + } else { + strscpy(nl_pname.data, p_name, PIPELINENAMSIZ); + nl_pname.passed = true; + } + + net = maybe_get_net(net); + if (!net) { + NL_SET_ERR_MSG(extack, "Net namespace is going down"); + ret = -EBUSY; + goto out; + } + + root = nla_nest_start(new_skb, P4TC_ROOT); + for (i = 1; i < P4TC_MSGBATCH_SIZE + 1 && p4tca[i]; i++) { + struct nlattr *nest = nla_nest_start(new_skb, i); + + if (cmd == RTM_P4TC_GET) + ret = tc_ctl_p4_get_1(net, new_skb, nlh, ids, p4tca[i], + &nl_pname, extack); + else if (cmd == RTM_P4TC_CREATE) + ret = tc_ctl_p4_cu_1(net, new_skb, nlh, ids, p4tca[i], + &nl_pname, extack); + else if (cmd == RTM_P4TC_DEL) + ret = tc_ctl_p4_delete_1(net, new_skb, nlh, p4tca[i], + ids, &nl_pname, extack); + + if (ret < 0) { + if (i == 1) { + goto put_net; + } else { + nla_nest_cancel(new_skb, nest); + break; + } + } + nla_nest_end(new_skb, nest); + } + nla_nest_end(new_skb, root); + + if (!t_new->pipeid) + t_new->pipeid = ids[P4TC_PID_IDX]; + + nlmsg_end(new_skb, nlh); + + if (cmd == RTM_P4TC_GET) + ret_send = rtnl_unicast(new_skb, net, portid); + else + ret_send = rtnetlink_send(new_skb, net, portid, RTNLGRP_TC, + n->nlmsg_flags & NLM_F_ECHO); + + put_net(net); + + return ret_send ? ret_send : ret; + +put_net: + put_net(net); + +out: + kfree_skb(new_skb); + return ret; +} + +static int tc_ctl_p4_root(struct sk_buff *skb, struct nlmsghdr *n, int cmd, + struct netlink_ext_ack *extack) +{ + char *p_name = NULL; + int ret = 0; + struct nlattr *tb[P4TC_ROOT_MAX + 1]; + + ret = nlmsg_parse(n, sizeof(struct p4tcmsg), tb, P4TC_ROOT_MAX, + p4tc_root_policy, extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(extack, NULL, tb, P4TC_ROOT)) { + NL_SET_ERR_MSG(extack, "Netlink P4TC table attributes missing"); + return -EINVAL; + } + + if (tb[P4TC_ROOT_PNAME]) + p_name = nla_data(tb[P4TC_ROOT_PNAME]); + + return tc_ctl_p4_table_n(skb, n, cmd, p_name, tb[P4TC_ROOT], extack); +} + +static int tc_ctl_p4_get(struct sk_buff *skb, struct nlmsghdr *n, + struct netlink_ext_ack *extack) +{ + return tc_ctl_p4_root(skb, n, RTM_P4TC_GET, extack); +} + +static int tc_ctl_p4_delete(struct sk_buff *skb, struct nlmsghdr *n, + struct netlink_ext_ack *extack) +{ + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + + return tc_ctl_p4_root(skb, n, RTM_P4TC_DEL, extack); +} + +static int tc_ctl_p4_cu(struct sk_buff *skb, struct nlmsghdr *n, + struct netlink_ext_ack *extack) +{ + int ret; + + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + + ret = tc_ctl_p4_root(skb, n, RTM_P4TC_CREATE, extack); + + return ret; +} + +static int tcf_table_entry_dump(struct sk_buff *skb, struct nlattr *arg, + u32 *ids, struct netlink_callback *cb, + char **p_name, struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_ENTRY_MAX + 1] = { NULL }; + struct p4tc_dump_ctx *ctx = (void *)cb->ctx; + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_pipeline *pipeline = NULL; + struct p4tc_table_entry *entry = NULL; + struct net *net = sock_net(skb->sk); + int i = 0; + struct p4tc_table *table; + int ret; + + net = maybe_get_net(net); + if (!net) { + NL_SET_ERR_MSG(extack, "Net namespace is going down"); + return -EBUSY; + } + + if (arg) { + ret = nla_parse_nested(tb, P4TC_ENTRY_MAX, arg, + p4tc_entry_policy, extack); + if (ret < 0) { + kfree(ctx->iter); + goto net_put; + } + } + + rcu_read_lock(); + ret = tcf_table_entry_get_table(net, &pipeline, &table, tb, ids, + *p_name, extack); + rcu_read_unlock(); + if (ret < 0) { + kfree(ctx->iter); + goto net_put; + } + + if (!ctx->iter) { + ctx->iter = kzalloc(sizeof(*ctx->iter), GFP_KERNEL); + if (!ctx->iter) { + ret = -ENOMEM; + goto table_put; + } + + rhltable_walk_enter(&table->tbl_entries, ctx->iter); + } + + ret = -ENOMEM; + rhashtable_walk_start(ctx->iter); + do { + for (i = 0; i < P4TC_MSGBATCH_SIZE && + (entry = rhashtable_walk_next(ctx->iter)) && + !IS_ERR(entry); i++) { + struct p4tc_table_entry_value *value = + p4tc_table_entry_value(entry); + struct nlattr *count; + + if (!p4tc_ctrl_read_ok(value->permissions)) { + i--; + continue; + } + + count = nla_nest_start(skb, i + 1); + if (!count) { + rhashtable_walk_stop(ctx->iter); + goto table_put; + } + ret = p4tca_table_get_entry_fill(skb, table, entry, + table->tbl_id); + if (ret == 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for table entry"); + goto walk_done; + } else if (ret == -ENOMEM) { + ret = 1; + nla_nest_cancel(skb, count); + rhashtable_walk_stop(ctx->iter); + goto table_put; + } + nla_nest_end(skb, count); + } + } while (entry == ERR_PTR(-EAGAIN)); + rhashtable_walk_stop(ctx->iter); + + if (!i) { + rhashtable_walk_exit(ctx->iter); + + ret = 0; + kfree(ctx->iter); + + goto table_put; + } + + if (!*p_name) + *p_name = pipeline->common.name; + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + ret = skb->len; + + goto table_put; + +walk_done: + rhashtable_walk_stop(ctx->iter); + rhashtable_walk_exit(ctx->iter); + kfree(ctx->iter); + + nlmsg_trim(skb, b); + +table_put: + tcf_table_entry_put_table(pipeline, table); + +net_put: + put_net(net); + + return ret; +} + +static int tc_ctl_p4_dump_1(struct sk_buff *skb, struct netlink_callback *cb, + struct nlattr *arg, char *p_name) +{ + struct netlink_ext_ack *extack = cb->extack; + u32 portid = NETLINK_CB(cb->skb).portid; + const struct nlmsghdr *n = cb->nlh; + u32 ids[P4TC_PATH_MAX] = { 0 }; + struct nlattr *tb[P4TC_MAX + 1]; + struct p4tcmsg *t_new; + struct nlmsghdr *nlh; + struct nlattr *root; + struct p4tcmsg *t; + u32 *arg_ids; + int ret; + + ret = nla_parse_nested(tb, P4TC_MAX, arg, p4tc_policy, extack); + if (ret < 0) + return ret; + + nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_P4TC_GET, sizeof(*t), + n->nlmsg_flags); + if (!nlh) + return -ENOSPC; + + t = (struct p4tcmsg *)nlmsg_data(n); + t_new = nlmsg_data(nlh); + t_new->pipeid = t->pipeid; + t_new->obj = t->obj; + + if (NL_REQ_ATTR_CHECK(extack, arg, tb, P4TC_PATH)) { + NL_SET_ERR_MSG(extack, "Must specify object path"); + return -EINVAL; + } + + ids[P4TC_PID_IDX] = t_new->pipeid; + arg_ids = nla_data(tb[P4TC_PATH]); + memcpy(&ids[P4TC_TBLID_IDX], arg_ids, nla_len(tb[P4TC_PATH])); + + root = nla_nest_start(skb, P4TC_ROOT); + ret = tcf_table_entry_dump(skb, tb[P4TC_PARAMS], ids, cb, &p_name, + extack); + if (ret <= 0) + goto out; + nla_nest_end(skb, root); + + if (p_name) { + if (nla_put_string(skb, P4TC_ROOT_PNAME, p_name)) { + ret = -1; + goto out; + } + } + + if (!t_new->pipeid) + t_new->pipeid = ids[P4TC_PID_IDX]; + + nlmsg_end(skb, nlh); + + return skb->len; + +out: + nlmsg_cancel(skb, nlh); + return ret; +} + +static int tc_ctl_p4_dump(struct sk_buff *skb, struct netlink_callback *cb) +{ + char *p_name = NULL; + int ret = 0; + struct nlattr *tb[P4TC_ROOT_MAX + 1]; + + ret = nlmsg_parse(cb->nlh, sizeof(struct p4tcmsg), tb, P4TC_ROOT_MAX, + p4tc_root_policy, cb->extack); + if (ret < 0) + return ret; + + if (NL_REQ_ATTR_CHECK(cb->extack, NULL, tb, P4TC_ROOT)) { + NL_SET_ERR_MSG(cb->extack, + "Netlink P4TC table attributes missing"); + return -EINVAL; + } + + if (tb[P4TC_ROOT_PNAME]) + p_name = nla_data(tb[P4TC_ROOT_PNAME]); + + return tc_ctl_p4_dump_1(skb, cb, tb[P4TC_ROOT], p_name); +} + +static int __init p4tc_tbl_init(void) +{ + rtnl_register(PF_UNSPEC, RTM_P4TC_CREATE, tc_ctl_p4_cu, NULL, + RTNL_FLAG_DOIT_UNLOCKED); + rtnl_register(PF_UNSPEC, RTM_P4TC_DEL, tc_ctl_p4_delete, NULL, + RTNL_FLAG_DOIT_UNLOCKED); + rtnl_register(PF_UNSPEC, RTM_P4TC_GET, tc_ctl_p4_get, tc_ctl_p4_dump, + RTNL_FLAG_DOIT_UNLOCKED); + + return 0; +} + +subsys_initcall(p4tc_tbl_init); diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 0a8daf2f8f2a..208e5e258580 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -97,6 +97,9 @@ static const struct nlmsg_perm nlmsg_route_perms[] = { { RTM_CREATEP4TEMPLATE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_DELP4TEMPLATE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_GETP4TEMPLATE, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_P4TC_CREATE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_P4TC_DEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_P4TC_GET, NETLINK_ROUTE_SOCKET__NLMSG_READ }, }; static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = { @@ -179,7 +182,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) * structures at the top of this file with the new mappings * before updating the BUILD_BUG_ON() macro! */ - BUILD_BUG_ON(RTM_MAX != (RTM_CREATEP4TEMPLATE + 3)); + BUILD_BUG_ON(RTM_MAX != (RTM_P4TC_CREATE + 3)); err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms, sizeof(nlmsg_route_perms)); break; From patchwork Wed May 17 11:02:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244699 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8C5A92099F for ; Wed, 17 May 2023 11:04:52 +0000 (UTC) Received: from mail-qk1-x732.google.com (mail-qk1-x732.google.com [IPv6:2607:f8b0:4864:20::732]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10A1F3AB1 for ; Wed, 17 May 2023 04:04:31 -0700 (PDT) Received: by mail-qk1-x732.google.com with SMTP id af79cd13be357-759413d99afso624842585a.1 for ; Wed, 17 May 2023 04:04:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321466; x=1686913466; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=PdrzsaeYuEcNPxmszuB7JPjU5/3VHTZcTM8X5ncBow0=; b=nUDGLvgSP+xITnVSzD60+GW25TlWALKO4V7+HuOSj/VWfqTm5UTrR2QneM/VifnDMl S+emNDVQlvpuwC0P6Pce3sx8Rcw73ldD0ebNuV5CJJLHvZ2yftaOsbGmBCqRyp38BYcm C4fAmp5zuMrKvcrGb7raDdDAA1QYEzNRzWibZ9GtpqmQZ0n0IYriUVGCyUCCW0Ij7dNR A5Y49C/TCuGzjTl2xkEqfA4DU4PyeSdVsK3GAwqXTmkNhyA472k8o1OziNExBIZInh84 0SwG+THWtLbgyk6oISQqtcr8Pzcxs6w0zgEhO6oP7IlGvOvLxNaRsLos2csf/9qQUy2U E93g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321466; x=1686913466; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=PdrzsaeYuEcNPxmszuB7JPjU5/3VHTZcTM8X5ncBow0=; b=RSRdYwxdZtgmQxI2TvxYlGHDwfkXPdKshusepQliM0w7uF2jwj5Z8jCpqbecl1mdxU uCsWhrz239tRK3feAHAiGUu59g7oU+QbICJ3lACMfrgarsuje+K+OpFUPe2Crbpp9x0A Xmxa+6gAimIhb8KemDw7XiZ4CztEgxFva2OrcMXAHmEcyA4D/zrXHuMqy2Y0YNlfhb6j z9ZwtThoH3VBKyUH2pG3tBeense5LNEnl0h1lL5siWd0HndZbxz6y9B7ZPP4BK2qXZoW BR5iqidspdXGice6BX1ID5S3rmXSGUo5dsQkJveo5P82b0MVB1XLNYXKw+jPNlh8K65h 5wBw== X-Gm-Message-State: AC+VfDwPByj2rwyed+hAYCv2LaqD1N0HfcWU5GyQbX9SXAUAhfXzDw/K jKwsCbDRySLyCwfRwfC0ACsXckPG0NdrgL45Mkg= X-Google-Smtp-Source: ACHHUZ6JiCY+EvaUccxqqssJZjWZPKcbbTJ/QWfuI6YsbDl3qnIavn8wnuwQv35XlFcLRsnNx2MjWw== X-Received: by 2002:a05:622a:205:b0:3ef:2a5:ee78 with SMTP id b5-20020a05622a020500b003ef02a5ee78mr3068643qtx.10.1684321466206; Wed, 17 May 2023 04:04:26 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id p7-20020a05620a112700b007579371d70esm532935qkk.46.2023.05.17.04.04.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:04:25 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 16/28] p4tc: add register create, update, delete, get, flush and dump Date: Wed, 17 May 2023 07:02:20 -0400 Message-Id: <20230517110232.29349-16-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This commit allows users to create, update, delete, get, flush and dump P4 registers. It's important to note that write operations, such as create, update and delete, can only be made if the pipeline is not sealed. Registers in P4 provide a way to store data in your program that can be accessed throughout the lifetime of your P4 program. Which means this a way of storing state between the P4 program's invocations. Let's take a look at an example register declaration in a P4 program: Register>(2) register1; This declaration corresponds to a register named register1, with 2 elements which are of type bit32. You can think of this register as an array of bit32s with 2 elements. If one were to create this register with P4TC, one would issue the following command: tc p4template create register/ptables/register1 type bit32 numelems 2 This will create register "register1" and give it an ID that will be assigned by the kernel. If the user wished to specify also the register id, the command would be the following tc p4template create register/ptables/register1 regid 1 type bit32 \ numelems 2 Now, after creating register1, if one wished to, for example, update index 1 of register1 with value 32, one would issue the following command: tc p4template update register/ptables/register1 index 1 \ value constant.bit32.32 One could also change the value of a specific index using hex notation, examplified by the following command: tc p4template update register/ptables/ regid 1 index 1 \ value constant.bit32.0x20 Note that we used regid in here instead of the register name (register1). We can always use name or id. It's important to note that all elements of a register will be initialised with zero when the register is created Now, after updating the new register the user could issue a get command to check if the register's parameters (type, num elems, id, ...) and the register element values are correct. To do so, the user would issue the following command: tc p4template get register/ptables/register1 Which will output the following: template obj type register pipeline name ptables id 22 register name register1 register id 1 container type bit32 startbit 0 endbit 31 number of elements 2 register1[0] 0 register1[1] 32 Notice that register[0] was unaltered, so it is a 0 because zero is the default initial values. register[1] has value 32, because it was updated in the previous command. The user could also list all of the created registers associated to a pipeline. For example, to list all of the registers associated with pipeline ptables, the user would issue the following command: tc p4template get register/ptables/ Which will output the following: template obj type register pipeline name ptables id 22 register name register1 Another option is to check the value of a specific index inside register1, that can be done using the following command: tc p4template get register/ptables/register1 index 1 Which will output the following: template obj type register pipeline name ptables id 22 register name register1 register id 1 container type bit32 register1[1] 32 To delete register1, the user would issue the following command: tc p4template del register/ptables/register1 Now, to delete all the registers associated with pipeline ptables, the user would issue the following command: tc p4template del register/ptables/ Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/p4tc.h | 32 ++ include/uapi/linux/p4tc.h | 28 ++ net/sched/p4tc/Makefile | 2 +- net/sched/p4tc/p4tc_pipeline.c | 9 +- net/sched/p4tc/p4tc_register.c | 746 +++++++++++++++++++++++++++++++++ net/sched/p4tc/p4tc_tmpl_api.c | 2 + 6 files changed, 817 insertions(+), 2 deletions(-) create mode 100644 net/sched/p4tc/p4tc_register.c diff --git a/include/net/p4tc.h b/include/net/p4tc.h index e784df312582..d098ae47d088 100644 --- a/include/net/p4tc.h +++ b/include/net/p4tc.h @@ -31,6 +31,7 @@ #define P4TC_AID_IDX 1 #define P4TC_PARSEID_IDX 1 #define P4TC_HDRFIELDID_IDX 2 +#define P4TC_REGID_IDX 1 #define P4TC_HDRFIELD_IS_VALIDITY_BIT 0x1 @@ -119,6 +120,7 @@ struct p4tc_pipeline { struct idr p_meta_idr; struct idr p_act_idr; struct idr p_tbl_idr; + struct idr p_reg_idr; struct rcu_head rcu; struct net *net; struct p4tc_parser *parser; @@ -420,6 +422,21 @@ struct p4tc_hdrfield { extern const struct p4tc_template_ops p4tc_hdrfield_ops; +struct p4tc_register { + struct p4tc_template_common common; + spinlock_t reg_value_lock; + struct p4tc_type *reg_type; + struct p4tc_type_mask_shift *reg_mask_shift; + void *reg_value; + u32 reg_num_elems; + u32 reg_id; + refcount_t reg_ref; + u16 reg_startbit; /* Relative to its container */ + u16 reg_endbit; /* Relative to its container */ +}; + +extern const struct p4tc_template_ops p4tc_register_ops; + struct p4tc_metadata *tcf_meta_find_byid(struct p4tc_pipeline *pipeline, u32 m_id); void tcf_meta_fill_user_offsets(struct p4tc_pipeline *pipeline); @@ -561,10 +578,25 @@ extern const struct p4tc_act_param_ops param_ops[P4T_MAX + 1]; int generic_dump_param_value(struct sk_buff *skb, struct p4tc_type *type, struct p4tc_act_param *param); +struct p4tc_register *tcf_register_find_byid(struct p4tc_pipeline *pipeline, + const u32 reg_id); +struct p4tc_register *tcf_register_get(struct p4tc_pipeline *pipeline, + const char *regname, const u32 reg_id, + struct netlink_ext_ack *extack); +void tcf_register_put_ref(struct p4tc_register *reg); + +struct p4tc_register *tcf_register_find_byany(struct p4tc_pipeline *pipeline, + const char *regname, + const u32 reg_id, + struct netlink_ext_ack *extack); + +void tcf_register_put_rcu(struct rcu_head *head); + #define to_pipeline(t) ((struct p4tc_pipeline *)t) #define to_meta(t) ((struct p4tc_metadata *)t) #define to_hdrfield(t) ((struct p4tc_hdrfield *)t) #define to_act(t) ((struct p4tc_act *)t) #define to_table(t) ((struct p4tc_table *)t) +#define to_register(t) ((struct p4tc_register *)t) #endif diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h index 62e817c483b5..a09c4fa96e68 100644 --- a/include/uapi/linux/p4tc.h +++ b/include/uapi/linux/p4tc.h @@ -22,6 +22,7 @@ struct p4tcmsg { #define P4TC_MAX_KEYSZ 512 #define HEADER_MAX_LEN 512 #define META_MAX_LEN 512 +#define P4TC_MAX_REGISTER_ELEMS 128 #define P4TC_MAX_KEYSZ 512 @@ -32,6 +33,7 @@ struct p4tcmsg { #define HDRFIELDNAMSIZ TEMPLATENAMSZ #define ACTPARAMNAMSIZ TEMPLATENAMSZ #define TABLENAMSIZ TEMPLATENAMSZ +#define REGISTERNAMSIZ TEMPLATENAMSZ #define P4TC_TABLE_FLAGS_KEYSZ 0x01 #define P4TC_TABLE_FLAGS_MAX_ENTRIES 0x02 @@ -130,6 +132,7 @@ enum { P4TC_OBJ_ACT, P4TC_OBJ_TABLE, P4TC_OBJ_TABLE_ENTRY, + P4TC_OBJ_REGISTER, __P4TC_OBJ_MAX, }; #define P4TC_OBJ_MAX __P4TC_OBJ_MAX @@ -366,6 +369,31 @@ enum { P4TC_ENTITY_MAX }; +#define P4TC_REGISTER_FLAGS_DATATYPE 0x1 +#define P4TC_REGISTER_FLAGS_STARTBIT 0x2 +#define P4TC_REGISTER_FLAGS_ENDBIT 0x4 +#define P4TC_REGISTER_FLAGS_NUMELEMS 0x8 +#define P4TC_REGISTER_FLAGS_INDEX 0x10 + +struct p4tc_u_register { + __u32 num_elems; + __u32 datatype; + __u32 index; + __u16 startbit; + __u16 endbit; + __u16 flags; +}; + +/* P4 Register attributes */ +enum { + P4TC_REGISTER_UNSPEC, + P4TC_REGISTER_NAME, /* string */ + P4TC_REGISTER_INFO, /* struct p4tc_u_register */ + P4TC_REGISTER_VALUE, /* value blob */ + __P4TC_REGISTER_MAX +}; +#define P4TC_REGISTER_MAX (__P4TC_REGISTER_MAX - 1) + #define P4TC_RTA(r) \ ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct p4tcmsg)))) diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index 0d2c20223154..b35ced1e3c9a 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -2,4 +2,4 @@ obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.o p4tc_meta.o \ p4tc_parser_api.o p4tc_hdrfield.o p4tc_action.o p4tc_table.o \ - p4tc_tbl_api.o + p4tc_tbl_api.o p4tc_register.o diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c index 1b6ac9fc2050..fafb9c849b13 100644 --- a/net/sched/p4tc/p4tc_pipeline.c +++ b/net/sched/p4tc/p4tc_pipeline.c @@ -298,6 +298,7 @@ static void tcf_pipeline_destroy(struct p4tc_pipeline *pipeline, idr_destroy(&pipeline->p_meta_idr); idr_destroy(&pipeline->p_act_idr); idr_destroy(&pipeline->p_tbl_idr); + idr_destroy(&pipeline->p_reg_idr); if (free_pipeline) kfree(pipeline); @@ -324,8 +325,9 @@ static int tcf_pipeline_put(struct net *net, struct p4tc_pipeline *pipeline = to_pipeline(template); struct net *pipeline_net = maybe_get_net(net); struct p4tc_act_dep_node *act_node, *node_tmp; - unsigned long tbl_id, m_id, tmp; + unsigned long reg_id, tbl_id, m_id, tmp; struct p4tc_metadata *meta; + struct p4tc_register *reg; struct p4tc_table *table; if (!refcount_dec_if_one(&pipeline->p_ctrl_ref)) { @@ -371,6 +373,9 @@ static int tcf_pipeline_put(struct net *net, if (pipeline->parser) tcf_parser_del(net, pipeline, pipeline->parser, extack); + idr_for_each_entry_ul(&pipeline->p_reg_idr, reg, tmp, reg_id) + reg->common.ops->put(net, ®->common, true, extack); + idr_remove(&pipe_net->pipeline_idr, pipeline->common.p_id); if (pipeline_net) @@ -567,6 +572,8 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, idr_init(&pipeline->p_meta_idr); pipeline->p_meta_offset = 0; + idr_init(&pipeline->p_reg_idr); + INIT_LIST_HEAD(&pipeline->act_dep_graph); INIT_LIST_HEAD(&pipeline->act_topological_order); pipeline->num_created_acts = 0; diff --git a/net/sched/p4tc/p4tc_register.c b/net/sched/p4tc/p4tc_register.c new file mode 100644 index 000000000000..def6624fc193 --- /dev/null +++ b/net/sched/p4tc/p4tc_register.c @@ -0,0 +1,746 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_register.c P4 TC REGISTER + * + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct nla_policy p4tc_register_policy[P4TC_REGISTER_MAX + 1] = { + [P4TC_REGISTER_NAME] = { .type = NLA_STRING, .len = REGISTERNAMSIZ }, + [P4TC_REGISTER_INFO] = { + .type = NLA_BINARY, + .len = sizeof(struct p4tc_u_register), + }, + [P4TC_REGISTER_VALUE] = { .type = NLA_BINARY }, +}; + +struct p4tc_register *tcf_register_find_byid(struct p4tc_pipeline *pipeline, + const u32 reg_id) +{ + return idr_find(&pipeline->p_reg_idr, reg_id); +} + +static struct p4tc_register * +tcf_register_find_byname(const char *regname, struct p4tc_pipeline *pipeline) +{ + struct p4tc_register *reg; + unsigned long tmp, id; + + idr_for_each_entry_ul(&pipeline->p_reg_idr, reg, tmp, id) + if (strncmp(reg->common.name, regname, REGISTERNAMSIZ) == 0) + return reg; + + return NULL; +} + +struct p4tc_register *tcf_register_find_byany(struct p4tc_pipeline *pipeline, + const char *regname, + const u32 reg_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_register *reg; + int err; + + if (reg_id) { + reg = tcf_register_find_byid(pipeline, reg_id); + if (!reg) { + NL_SET_ERR_MSG(extack, "Unable to find register by id"); + err = -EINVAL; + goto out; + } + } else { + if (regname) { + reg = tcf_register_find_byname(regname, pipeline); + if (!reg) { + NL_SET_ERR_MSG(extack, + "Register name not found"); + err = -EINVAL; + goto out; + } + } else { + NL_SET_ERR_MSG(extack, + "Must specify register name or id"); + err = -EINVAL; + goto out; + } + } + + return reg; +out: + return ERR_PTR(err); +} + +struct p4tc_register *tcf_register_get(struct p4tc_pipeline *pipeline, + const char *regname, const u32 reg_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_register *reg; + + reg = tcf_register_find_byany(pipeline, regname, reg_id, extack); + if (IS_ERR(reg)) + return reg; + + WARN_ON(!refcount_inc_not_zero(®->reg_ref)); + + return reg; +} + +void tcf_register_put_ref(struct p4tc_register *reg) +{ + WARN_ON(!refcount_dec_not_one(®->reg_ref)); +} + +static struct p4tc_register * +tcf_register_find_byanyattr(struct p4tc_pipeline *pipeline, + struct nlattr *name_attr, const u32 reg_id, + struct netlink_ext_ack *extack) +{ + char *regname = NULL; + + if (name_attr) + regname = nla_data(name_attr); + + return tcf_register_find_byany(pipeline, regname, reg_id, extack); +} + +static int _tcf_register_fill_nlmsg(struct sk_buff *skb, + struct p4tc_register *reg, + struct p4tc_u_register *parm_arg) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_u_register parm = { 0 }; + size_t value_bytesz; + struct nlattr *nest; + void *value; + + if (nla_put_u32(skb, P4TC_PATH, reg->reg_id)) + goto out_nlmsg_trim; + + nest = nla_nest_start(skb, P4TC_PARAMS); + if (!nest) + goto out_nlmsg_trim; + + if (nla_put_string(skb, P4TC_REGISTER_NAME, reg->common.name)) + goto out_nlmsg_trim; + + parm.datatype = reg->reg_type->typeid; + parm.flags |= P4TC_REGISTER_FLAGS_DATATYPE; + if (parm_arg) { + parm.index = parm_arg->index; + parm.flags |= P4TC_REGISTER_FLAGS_INDEX; + } else { + parm.startbit = reg->reg_startbit; + parm.flags |= P4TC_REGISTER_FLAGS_STARTBIT; + parm.endbit = reg->reg_endbit; + parm.flags |= P4TC_REGISTER_FLAGS_ENDBIT; + parm.num_elems = reg->reg_num_elems; + parm.flags |= P4TC_REGISTER_FLAGS_NUMELEMS; + } + + if (nla_put(skb, P4TC_REGISTER_INFO, sizeof(parm), &parm)) + goto out_nlmsg_trim; + + value_bytesz = BITS_TO_BYTES(reg->reg_type->container_bitsz); + spin_lock_bh(®->reg_value_lock); + if (parm.flags & P4TC_REGISTER_FLAGS_INDEX) { + value = reg->reg_value + parm.index * value_bytesz; + } else { + value = reg->reg_value; + value_bytesz *= reg->reg_num_elems; + } + + if (nla_put(skb, P4TC_REGISTER_VALUE, value_bytesz, value)) { + spin_unlock_bh(®->reg_value_lock); + goto out_nlmsg_trim; + } + spin_unlock_bh(®->reg_value_lock); + + nla_nest_end(skb, nest); + + return skb->len; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return -1; +} + +static int tcf_register_fill_nlmsg(struct net *net, struct sk_buff *skb, + struct p4tc_template_common *template, + struct netlink_ext_ack *extack) +{ + struct p4tc_register *reg = to_register(template); + + if (_tcf_register_fill_nlmsg(skb, reg, NULL) <= 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for register"); + return -EINVAL; + } + + return 0; +} + +static int _tcf_register_put(struct p4tc_pipeline *pipeline, + struct p4tc_register *reg, + bool unconditional_purge, + struct netlink_ext_ack *extack) +{ + void *value; + + if (!refcount_dec_if_one(®->reg_ref) && !unconditional_purge) + return -EBUSY; + + idr_remove(&pipeline->p_reg_idr, reg->reg_id); + + spin_lock_bh(®->reg_value_lock); + value = reg->reg_value; + reg->reg_value = NULL; + spin_unlock_bh(®->reg_value_lock); + kfree(value); + + if (reg->reg_mask_shift) { + kfree(reg->reg_mask_shift->mask); + kfree(reg->reg_mask_shift); + } + kfree(reg); + + return 0; +} + +static int tcf_register_put(struct net *net, struct p4tc_template_common *tmpl, + bool unconditional_purge, + struct netlink_ext_ack *extack) +{ + struct p4tc_pipeline *pipeline = + tcf_pipeline_find_byid(net, tmpl->p_id); + struct p4tc_register *reg = to_register(tmpl); + int ret; + + ret = _tcf_register_put(pipeline, reg, unconditional_purge, extack); + if (ret < 0) + NL_SET_ERR_MSG(extack, "Unable to delete referenced register"); + + return ret; +} + +static struct p4tc_register *tcf_register_create(struct net *net, + struct nlmsghdr *n, + struct nlattr *nla, u32 reg_id, + struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_REGISTER_MAX + 1]; + struct p4tc_u_register *parm; + struct p4tc_type *datatype; + struct p4tc_register *reg; + int ret; + + ret = nla_parse_nested(tb, P4TC_REGISTER_MAX, nla, p4tc_register_policy, + extack); + + if (ret < 0) + return ERR_PTR(ret); + + reg = kzalloc(sizeof(*reg), GFP_KERNEL); + if (!reg) + return ERR_PTR(-ENOMEM); + + if (NL_REQ_ATTR_CHECK(extack, nla, tb, P4TC_REGISTER_NAME)) { + NL_SET_ERR_MSG(extack, "Must specify register name"); + ret = -EINVAL; + goto free_reg; + } + + if (tcf_register_find_byname(nla_data(tb[P4TC_REGISTER_NAME]), pipeline) || + tcf_register_find_byid(pipeline, reg_id)) { + NL_SET_ERR_MSG(extack, "Register already exists"); + ret = -EEXIST; + goto free_reg; + } + + reg->common.p_id = pipeline->common.p_id; + strscpy(reg->common.name, nla_data(tb[P4TC_REGISTER_NAME]), + REGISTERNAMSIZ); + + if (NL_REQ_ATTR_CHECK(extack, nla, tb, P4TC_REGISTER_INFO)) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Missing register info"); + goto free_reg; + } + parm = nla_data(tb[P4TC_REGISTER_INFO]); + + if (tb[P4TC_REGISTER_VALUE]) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Value can't be passed in create"); + goto free_reg; + } + + if (parm->flags & P4TC_REGISTER_FLAGS_INDEX) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Index can't be passed in create"); + goto free_reg; + } + + if (parm->flags & P4TC_REGISTER_FLAGS_NUMELEMS) { + if (!parm->num_elems) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Num elems can't be zero"); + goto free_reg; + } + + if (parm->num_elems > P4TC_MAX_REGISTER_ELEMS) { + NL_SET_ERR_MSG(extack, + "Number of elements exceededs P4 register maximum"); + ret = -EINVAL; + goto free_reg; + } + } else { + NL_SET_ERR_MSG(extack, "Must specify num elems"); + ret = -EINVAL; + goto free_reg; + } + + if (!(parm->flags & P4TC_REGISTER_FLAGS_STARTBIT) || + !(parm->flags & P4TC_REGISTER_FLAGS_ENDBIT)) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Must specify start and endbit"); + goto free_reg; + } + + if (parm->startbit > parm->endbit) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "startbit > endbit"); + goto free_reg; + } + + if (parm->flags & P4TC_REGISTER_FLAGS_DATATYPE) { + datatype = p4type_find_byid(parm->datatype); + if (!datatype) { + NL_SET_ERR_MSG(extack, + "Invalid data type for P4 register"); + ret = -EINVAL; + goto free_reg; + } + reg->reg_type = datatype; + } else { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Must specify datatype"); + goto free_reg; + } + + if (parm->endbit > datatype->bitsz) { + NL_SET_ERR_MSG(extack, + "Endbit doesn't fix in container datatype"); + ret = -EINVAL; + goto free_reg; + } + reg->reg_startbit = parm->startbit; + reg->reg_endbit = parm->endbit; + + reg->reg_num_elems = parm->num_elems; + + spin_lock_init(®->reg_value_lock); + + reg->reg_value = kcalloc(reg->reg_num_elems, + BITS_TO_BYTES(datatype->container_bitsz), + GFP_KERNEL); + if (!reg->reg_value) { + ret = -ENOMEM; + goto free_reg; + } + + if (reg_id) { + reg->reg_id = reg_id; + ret = idr_alloc_u32(&pipeline->p_reg_idr, reg, ®->reg_id, + reg->reg_id, GFP_KERNEL); + if (ret < 0) { + NL_SET_ERR_MSG(extack, + "Unable to allocate register id"); + goto free_reg_value; + } + } else { + reg->reg_id = 1; + ret = idr_alloc_u32(&pipeline->p_reg_idr, reg, ®->reg_id, + UINT_MAX, GFP_KERNEL); + if (ret < 0) { + NL_SET_ERR_MSG(extack, + "Unable to allocate register id"); + goto free_reg_value; + } + } + + if (datatype->ops->create_bitops) { + size_t bitsz = reg->reg_endbit - reg->reg_startbit + 1; + struct p4tc_type_mask_shift *mask_shift; + + mask_shift = datatype->ops->create_bitops(bitsz, + reg->reg_startbit, + reg->reg_endbit, + extack); + if (IS_ERR(mask_shift)) { + ret = PTR_ERR(mask_shift); + goto idr_rm; + } + reg->reg_mask_shift = mask_shift; + } + + refcount_set(®->reg_ref, 1); + + reg->common.ops = (struct p4tc_template_ops *)&p4tc_register_ops; + + return reg; + +idr_rm: + idr_remove(&pipeline->p_reg_idr, reg->reg_id); + +free_reg_value: + kfree(reg->reg_value); + +free_reg: + kfree(reg); + return ERR_PTR(ret); +} + +static struct p4tc_register *tcf_register_update(struct net *net, + struct nlmsghdr *n, + struct nlattr *nla, u32 reg_id, + struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + void *user_value = NULL; + struct nlattr *tb[P4TC_REGISTER_MAX + 1]; + struct p4tc_u_register *parm; + struct p4tc_type *datatype; + struct p4tc_register *reg; + int ret; + + ret = nla_parse_nested(tb, P4TC_REGISTER_MAX, nla, p4tc_register_policy, + extack); + + if (ret < 0) + return ERR_PTR(ret); + + reg = tcf_register_find_byanyattr(pipeline, tb[P4TC_REGISTER_NAME], + reg_id, extack); + if (IS_ERR(reg)) + return reg; + + if (NL_REQ_ATTR_CHECK(extack, nla, tb, P4TC_REGISTER_INFO)) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Missing register info"); + goto err; + } + parm = nla_data(tb[P4TC_REGISTER_INFO]); + + datatype = reg->reg_type; + + if (parm->flags & P4TC_REGISTER_FLAGS_NUMELEMS) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Can't update register num elems"); + goto err; + } + + if (!(parm->flags & P4TC_REGISTER_FLAGS_STARTBIT) || + !(parm->flags & P4TC_REGISTER_FLAGS_ENDBIT)) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Must specify start and endbit"); + goto err; + } + + if (parm->startbit != reg->reg_startbit || + parm->endbit != reg->reg_endbit) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, + "Start and endbit don't match with register values"); + goto err; + } + + if (!(parm->flags & P4TC_REGISTER_FLAGS_INDEX)) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Must specify index"); + goto err; + } + + if (NL_REQ_ATTR_CHECK(extack, nla, tb, P4TC_REGISTER_VALUE)) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Missing register value"); + goto err; + } + if (nla_len(tb[P4TC_REGISTER_VALUE]) != + BITS_TO_BYTES(datatype->container_bitsz)) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, + "Value size differs from register type's container size"); + goto err; + } + user_value = nla_data(tb[P4TC_REGISTER_VALUE]); + + if (parm->index >= reg->reg_num_elems) { + ret = -EINVAL; + NL_SET_ERR_MSG(extack, "Register index out of bounds"); + goto err; + } + + if (user_value) { + u64 read_user_value[2] = { 0 }; + size_t type_bytesz; + void *value; + + type_bytesz = BITS_TO_BYTES(datatype->container_bitsz); + + datatype->ops->host_read(datatype, reg->reg_mask_shift, + user_value, read_user_value); + + spin_lock_bh(®->reg_value_lock); + value = reg->reg_value + parm->index * type_bytesz; + datatype->ops->host_write(datatype, reg->reg_mask_shift, + read_user_value, value); + spin_unlock_bh(®->reg_value_lock); + } + + return reg; + +err: + return ERR_PTR(ret); +} + +static struct p4tc_template_common * +tcf_register_cu(struct net *net, struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + u32 pipeid = ids[P4TC_PID_IDX], reg_id = ids[P4TC_REGID_IDX]; + struct p4tc_pipeline *pipeline; + struct p4tc_register *reg; + + pipeline = tcf_pipeline_find_byany_unsealed(net, nl_pname->data, pipeid, + extack); + if (IS_ERR(pipeline)) + return (void *)pipeline; + + if (n->nlmsg_flags & NLM_F_REPLACE) + reg = tcf_register_update(net, n, nla, reg_id, pipeline, + extack); + else + reg = tcf_register_create(net, n, nla, reg_id, pipeline, + extack); + + if (IS_ERR(reg)) + goto out; + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = reg->common.p_id; + +out: + return (struct p4tc_template_common *)reg; +} + +static int tcf_register_flush(struct sk_buff *skb, + struct p4tc_pipeline *pipeline, + struct netlink_ext_ack *extack) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_register *reg; + unsigned long tmp, reg_id; + int ret = 0; + int i = 0; + + if (nla_put_u32(skb, P4TC_PATH, 0)) + goto out_nlmsg_trim; + + if (idr_is_empty(&pipeline->p_reg_idr)) { + NL_SET_ERR_MSG(extack, "There are no registers to flush"); + goto out_nlmsg_trim; + } + + idr_for_each_entry_ul(&pipeline->p_reg_idr, reg, tmp, reg_id) { + if (_tcf_register_put(pipeline, reg, false, extack) < 0) { + ret = -EBUSY; + continue; + } + i++; + } + + nla_put_u32(skb, P4TC_COUNT, i); + + if (ret < 0) { + if (i == 0) { + NL_SET_ERR_MSG(extack, "Unable to flush any register"); + goto out_nlmsg_trim; + } else { + NL_SET_ERR_MSG(extack, "Unable to flush all registers"); + } + } + + return i; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_register_gd(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, struct nlattr *nla, + struct p4tc_nl_pname *nl_pname, u32 *ids, + struct netlink_ext_ack *extack) +{ + u32 pipeid = ids[P4TC_PID_IDX], reg_id = ids[P4TC_REGID_IDX]; + struct nlattr *tb[P4TC_REGISTER_MAX + 1] = {}; + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_u_register *parm_arg = NULL; + int ret = 0; + struct p4tc_pipeline *pipeline; + struct p4tc_register *reg; + struct nlattr *attr_info; + + if (n->nlmsg_type == RTM_DELP4TEMPLATE) + pipeline = tcf_pipeline_find_byany_unsealed(net, nl_pname->data, + pipeid, extack); + else + pipeline = tcf_pipeline_find_byany(net, nl_pname->data, pipeid, + extack); + + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + + if (nla) { + ret = nla_parse_nested(tb, P4TC_REGISTER_MAX, nla, + p4tc_register_policy, extack); + + if (ret < 0) + return ret; + } + + if (!nl_pname->passed) + strscpy(nl_pname->data, pipeline->common.name, PIPELINENAMSIZ); + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (n->nlmsg_type == RTM_DELP4TEMPLATE && (n->nlmsg_flags & NLM_F_ROOT)) + return tcf_register_flush(skb, pipeline, extack); + + reg = tcf_register_find_byanyattr(pipeline, tb[P4TC_REGISTER_NAME], + reg_id, extack); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + attr_info = tb[P4TC_REGISTER_INFO]; + if (attr_info) { + if (n->nlmsg_type == RTM_DELP4TEMPLATE) { + NL_SET_ERR_MSG(extack, + "Can't pass info attribute in delete"); + return -EINVAL; + } + parm_arg = nla_data(attr_info); + if (!(parm_arg->flags & P4TC_REGISTER_FLAGS_INDEX) || + (parm_arg->flags & ~P4TC_REGISTER_FLAGS_INDEX)) { + NL_SET_ERR_MSG(extack, + "Must specify param index and only param index"); + return -EINVAL; + } + if (parm_arg->index >= reg->reg_num_elems) { + NL_SET_ERR_MSG(extack, "Register index out of bounds"); + return -EINVAL; + } + } + if (_tcf_register_fill_nlmsg(skb, reg, parm_arg) < 0) { + NL_SET_ERR_MSG(extack, + "Failed to fill notification attributes for register"); + return -EINVAL; + } + + if (n->nlmsg_type == RTM_DELP4TEMPLATE) { + ret = _tcf_register_put(pipeline, reg, false, extack); + if (ret < 0) { + NL_SET_ERR_MSG(extack, + "Unable to delete referenced register"); + goto out_nlmsg_trim; + } + } + + return 0; + +out_nlmsg_trim: + nlmsg_trim(skb, b); + return ret; +} + +static int tcf_register_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, + struct nlattr *nla, char **p_name, u32 *ids, + struct netlink_ext_ack *extack) +{ + struct net *net = sock_net(skb->sk); + struct p4tc_pipeline *pipeline; + + if (!ctx->ids[P4TC_PID_IDX]) { + pipeline = tcf_pipeline_find_byany(net, *p_name, + ids[P4TC_PID_IDX], extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + ctx->ids[P4TC_PID_IDX] = pipeline->common.p_id; + } else { + pipeline = tcf_pipeline_find_byid(net, ctx->ids[P4TC_PID_IDX]); + } + + if (!ids[P4TC_PID_IDX]) + ids[P4TC_PID_IDX] = pipeline->common.p_id; + + if (!(*p_name)) + *p_name = pipeline->common.name; + + return tcf_p4_tmpl_generic_dump(skb, ctx, &pipeline->p_reg_idr, + P4TC_REGID_IDX, extack); +} + +static int tcf_register_dump_1(struct sk_buff *skb, + struct p4tc_template_common *common) +{ + struct nlattr *nest = nla_nest_start(skb, P4TC_PARAMS); + struct p4tc_register *reg = to_register(common); + + if (!nest) + return -ENOMEM; + + if (nla_put_string(skb, P4TC_REGISTER_NAME, reg->common.name)) { + nla_nest_cancel(skb, nest); + return -ENOMEM; + } + + nla_nest_end(skb, nest); + + return 0; +} + +const struct p4tc_template_ops p4tc_register_ops = { + .cu = tcf_register_cu, + .fill_nlmsg = tcf_register_fill_nlmsg, + .gd = tcf_register_gd, + .put = tcf_register_put, + .dump = tcf_register_dump, + .dump_1 = tcf_register_dump_1, +}; diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c index e5be7db054dd..e8f2ad250256 100644 --- a/net/sched/p4tc/p4tc_tmpl_api.c +++ b/net/sched/p4tc/p4tc_tmpl_api.c @@ -46,6 +46,7 @@ static bool obj_is_valid(u32 obj) case P4TC_OBJ_HDR_FIELD: case P4TC_OBJ_ACT: case P4TC_OBJ_TABLE: + case P4TC_OBJ_REGISTER: return true; default: return false; @@ -58,6 +59,7 @@ static const struct p4tc_template_ops *p4tc_ops[P4TC_OBJ_MAX] = { [P4TC_OBJ_HDR_FIELD] = &p4tc_hdrfield_ops, [P4TC_OBJ_ACT] = &p4tc_act_ops, [P4TC_OBJ_TABLE] = &p4tc_table_ops, + [P4TC_OBJ_REGISTER] = &p4tc_register_ops, }; int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, From patchwork Wed May 17 11:02:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244700 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0AC35182C3 for ; Wed, 17 May 2023 11:04:58 +0000 (UTC) Received: from mail-qt1-x82d.google.com (mail-qt1-x82d.google.com [IPv6:2607:f8b0:4864:20::82d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 924934C2D for ; Wed, 17 May 2023 04:04:35 -0700 (PDT) Received: by mail-qt1-x82d.google.com with SMTP id d75a77b69052e-3f610c11472so2400671cf.0 for ; Wed, 17 May 2023 04:04:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321475; x=1686913475; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=TjLZQ8ngtzt+yBrdcy5zxSmrOXnskZVyCUEJzb3SrUk=; b=kLDp7m0tYz2X39JNpRd4VW//i5AvXhjF8vWdpoMDkFkljnnoBFhr21xoMFR+8AW419 VO8tI9Ia24TY8bT42iLC10oxAZJc+0AbZ+Ewvq2ESGVQQNYlQbX9oUFyNN3b4jI7vXis W6dOhvubtVoXM6s2HnMrF8zbWPtkpbkmekUSlhDYf7LFMSoFQbp0M7bZRF8oMH5WIg9A 1LHGgHPrvo6TAQe+usOf1cSQEAk4dcKmdRtyVSv9X9r8Neeeri8TlK/butmZ1CyYwtvt 0dRLtg1bSaenMLkCeWAmti87LJxY6cZd97GDIDlGtz8UDAX3kxYTe5dXxznNxNjIFBXj x2vg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321475; x=1686913475; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TjLZQ8ngtzt+yBrdcy5zxSmrOXnskZVyCUEJzb3SrUk=; b=DJAPRMrdPKju9i0T+zMEmWpQO9RkwiTZn/Ha1R2i0ECSy7tre0LylXJXaVD4l1LrGZ t2uQ9hCC8MSNHTH5Jth6FsXqfDCpD5txZ13DtpPeE0dIN4JfBQRLFdpYZjjM6Vzpb5Am ROVfMYpEnBYzydqQVcIDiI+BUmyXobk1WUreSUumJLDcOacAMcYgvv+WcjGr1EnqBES3 ECJQhTuO5jCht/5oVIGB3yrbUzUcVfpTEW749rDMMo4ifMWxxOtrLNKKD6LtrqfxFfLq 4m684OlynR2ZjlmaM/WchYK7Cm2ebPPhkwyzAzS/wiUUhEdCR7gnoM4+fb63GycCRXjQ 1Kfw== X-Gm-Message-State: AC+VfDwvOgrsO3C8gLGos5M6no+FiRpLXBAgTVvJEnPydIua+L4fn/ZP MXnCyvlgexhhEEWrTXsec3XLPDVtWL0Wbai7sjE= X-Google-Smtp-Source: ACHHUZ7Rh2MCX5Jf+7w100WRBtlFr3oOEZIZpqLmsf5WZn50+3Gharud030Ad68n8Tfj708WR+2Jgw== X-Received: by 2002:a05:622a:1186:b0:3f2:626:9c3 with SMTP id m6-20020a05622a118600b003f2062609c3mr64298990qtk.36.1684321473415; Wed, 17 May 2023 04:04:33 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id z24-20020ae9c118000000b0074683c45f6csm544019qki.1.2023.05.17.04.04.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:04:32 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 17/28] p4tc: add dynamic action commands Date: Wed, 17 May 2023 07:02:21 -0400 Message-Id: <20230517110232.29349-17-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC In this initial patch, we introduce dynamic action commands which will be used by dynamic action in P4TC. ================================SET================================ The set operation allows us to assign values to objects. The assignee operand("A") can be metadata, header field, table key, dev or register. Whilst the assignor operand("B") can be metadata, header field, table key, register, constant, dev, param or result. We'll describe each of these operand types further down the commit message. The set command has the following syntax: set A B Operand A's size must be bigger or equal to operand B's size. Here are some examples of setting metadata to constants: Create an action that sets kernel skbmark to decimal 1234 tc p4template create action/myprog/test actid 1 \ cmd set metadata.kernel.skbmark constant.bit32.1234 set kernel tcindex to 0x5678 tc p4template create action/myprog/test actid 1 \ cmd metadata.kernel.tcindex constant.bit32.0x5678 Note that we may specify constants in decimal or hexadecimal format. Here are some examples of setting metadata to metadata: Create an action that sets skb->hash to skb->mark tc p4template create action/myprog/test actid 1 \ cmd set metadata.kernel.skbhash metadata.kernel.skbmark Create an action that sets skb->ifindex to skb->iif tc p4template create action/myprog/test actid 1 \ cmd set metadata.kernel.ifindex metadata.kernel.iif We can also use user defined metadata in set operations. For example, if we define the following user metadata tc p4template create metadata/myprog/mymd type bit32 We could create an action to set its value to skbmark, for example tc p4template create action/myprog/test actid 1 \ cmd set metadata.myprog.mymd metadata.kernel.skbmark Note that the way to reference user metadata (from iproute2 perspective) is equivalent to the way we reference kernel metadata. That is: METADATA.PIPELINE_NAME.METADATA_NAME All kernel metadata is stored inside a special pipeline called "kernel". We can also use bit slices in set operations. For example, if one wanted to create an action to assign the first 16 bits of user metadata known as "md" to kernel metadata tcindex, one would right the following: tc p4template create action/myprog/test actid 1 \ cmd set metadata.myprog.tcindex metadata.kernel.md[0-15] If we wanted to write the last 16 bits of user metadata "mymd" to kernel metadata tcindex, we'd issue the following command: tc p4template create action/myprog/test actid 1 \ cmd set metadata.myprog.tcindex metadata.kernel.md[16-31] of course one could create multiple sets in one action as such: tc p4template create action/myprog/swap_ether actid 1 \ cmd set metadata.myprog.temp hdrfield.myprog.parser1.ethernet.dstAddr \ cmd set hdrfield.myprog.parser1.ethernet.dstAddr hdrfield.myprog.parser1.ethernet.srcAddr \ cmd set hdrfield.myprog.parser1.ethernet.srcAddr metadata.myprog.temp ================================ACT================================ The act operation is used to call other actions from dynamic action commands. Note: we can invoke either kernel native actions, such as gact and mirred, etc or pipeline defined dynamic actions. There are two ways to use the act command. - Create an instance of an action and then calling this specific instance - Specify the action parameters directly in the act command. __Method One__ The basic syntax for the first option is: act PIPELINE_NAME.ACTION_NAME.INDEX Where PIPELINE_NAME could be a user created pipeline or the native "kernel" pipeline. For example, if we wanted to call an instance of a mirred action that mirrors a packet to egress on a specific interface (eth0) then first we create an instance of the action kind an assign it an index as follows: tc actions add action mirred egress mirror dev eth0 index 1 After that, we can then use it on a command by indicating the appropriate action name and index. tc p4template create action/myprog/test actid 1 \ cmd act kernel.mirred.1 Note that we use "kernel" as the pipeline name. That's because mirred is a native kernel action. We could also call pipeline specific action from a dynamic action's commands, so for example, if we created the following action template: We can do the same thing but with user created actions, we could do the following: tc p4template create action/myprog/test actid 1 param param1 type bit32 Add an instance of it: tc actions add action myprog/test param param1 type bit32 22 index 1 We could call it using the following command: tc p4template create action/myprog/test actid 12 \ cmd act myprog.test.1 __Method Two__ The syntax for the second method is: act ACTION_NAME PARAMS The second method can only be applied to user defined dynamic actions and allows us to invoke action and passing parameter directly in the invocation. So the above example from method1 would turn into the following: tc p4template create action/myprog/test actid 12 \ cmd act myprog.test constant.bit32.22 We can also specify runtime parameters with this new syntax, such as metadata or header field. For example: tc p4template create action/myprog/test actid 12 \ cmd act myprog.test metadata.myprog.mymd ================================BRANCHING================================ We have several branch commands: beq (branch-equal), bne (branch-not-equal), bgt (branch-greater-then), blt (branch-less-then), bge (branch-greater-then), ble (branch-less-equal) The basic syntax for branching instructions is: / Where compare-operation could be beq, bne, bg1, blt, bge and ble. A is one of: header field, metadata, key or result field (like result.hit or result.miss). B is one of: a constant, header field or metadata A and B don't need to be the same size and type as long as B's size is smaller or equal to A's size. Note, inherently this means A and B can't both be constants. Let's take a look at some examples: tc p4template create action/myprog/test actid 1 \ cmd beq metadata.kernel.skbmark constant.u32.4 control pipe / jump 1 \ cmd set metadata.kernel.skbmark constant.u32.123 control ok \ cmd set metadata.kernel.skbidf constant.bit1.0 The above action executes the equivalent of the following pseudo code: if (metadata.kernel.skbmark == 4) then metadata.kernel.skbmark = 123 else metadata.kernel.skbidf = 0 endif Here is another example, now with bne: tc p4template create action/myprog/test actid 1 \ cmd bne metadata.kernel.skbmark constant.u32.4 control pipe / jump else \ cmd set metadata.kernel.skbmark constant.u32.123 \ cmd jump endif \ cmd label else \ cmd set metadata.kernel.skbidf constant.bit1.0 \ cmd label endif Note in this example we use "labels". These are a more user-friendly alternative to jumps with numbers, but basically what example action above does is equivalent of the following pseudo code: if (metadata.kernel.skbmark != 4) then metadata.kernel.skbmark = 123 else metadata.kernel.skbidf = 0 endif This example is basically the logical oposite of the previous one. ================================PRINT================================ The print operation allows us to print the value of operands for debugging purposes. The syntax for the print instruction is the following: PRINT [PREFIX] [ACTUAL_PREFIX] operA Where operA could be a header field, metadata, key, result, register or action param. The PREFIX and ACTUAL_PREFIX fields are optional and could contain a prefix string that will be printed before operA's value. Let's first see an example that doesn't use prefix: sudo tc p4template create action/myprog/test actid 1 \ cmd print metadata.kernel.skbmark \ cmd set metadata.kernel.skbmark constant.u32.123 \ cmd print metadata.kernel.skbmark Assuming skb->mark was initially 0, this will print: kernel.skbmark 0 kernel.skbmark 123 If we wanted to add prefixes to those commands, we could do the following: sudo tc p4template create action/myprog/test actid 1 \ cmd print prefix before metadata.kernel.skbmark \ cmd set metadata.kernel.skbmark constant.u32.123 \ cmd print prefix after metadata.kernel.skbmark This will print: before kernel.skbmark 0 after kernel.skbmark 123 ================================PLUS================================ The plus command is used to add two operands The basic syntax for the plus command is: cmd plus operA operB operC The command will add operands operB and operC and store the result in operC. That is: operA = operB + operC operA can be one of: metadatum, header field. operB and operC can be one of: constant, metadatum, key, header field or param. The following example will add metadatum mymd from pipeline myprog and constant 16 and store the result in metadatum mymd2 of pipeline myprog: tc p4template create action/myprog/myfunc \ cmd plus metadata.myprog.mymd2 metadata.myprog.mymd constant.bit32.16 ================================SUB================================ The sub command is used to subtract two operands The basic syntax for the sub command is: cmd sub operA operB operC The command will subtract operands operB and operC and store the result in operC. That is: operA = operB - operC operA can be one of: metadatum, header field. operB and operC can be one of: constant, metadatum, key, header field or param. The following example will subtract metadatum mymd from pipeline myprog and constant 16 and store the result in metadatum mymd2 of pipeline myprog: tc p4template create action/myprog/myfunc \ cmd sub metadata.myprog.mymd2 metadata.myprog.mymd constant.bit32.16 ================================CONCAT================================ The concat command is used to concat upto 8 operands and save the result to a lvalue. The basic syntax for the sub command is: cmd concat operA operB operC [..] The command will concat operands operB and operC and optionally 6 more store the result in operC. It goes without saying that operA's size must be greater or equal to the sum of (operB's size + operC's size .... operI's size) operA can be one of: metadatum, a key, a header field. operB .. operI can only be a constant, a metadatum, a key, a header field or a param. The following example will concat metadatum mymd from pipeline myprog with header field tcp.dport and store the result in metadatum mymd2 of pipeline myprog: tc p4template create action/myprog/myfunc \ cmd concat \ metadata.myprog.mymd2 metadata.myprog.mymd hdrfield.myprog.myparser.tcp.dport ================================BAND================================ The band command is used to perform a binary AND operation between two operands. The basic syntax for the band command is: cmd band operA operB operC The command will perform the "operB AND operC" and store the result in operC. That is: operA = operB & operC operA can be one of: metadatum, header field. operB and operC can be one of: constant, metadatum, key, header field or param. The following example will perform an AND operation of constant 16 and mymd metadata and store the result in metadatum mymd2 of pipeline myprog: tc p4template create action/myprog/myfunc \ cmd band metadata.myprog.mymd2 metadata.myprog.mymd constant.bit32.16 ================================BOR================================ The bor command is used to perform an binary OR operation between two operands. The basic syntax for the bor command is: cmd bor operA operB operC The command will perform the "operB OR operC" and store the result in operC. That is: operA = operB | operC operA can be one of: metadatum, header field. operB and operC can be one of: constant, metadatum, key, header field or param. The following example will perform an OR operation of constant 16 and mymd metadata and store the result in metadatum mymd2 of pipeline myprog: tc p4template create action/myprog/myfunc \ cmd bor metadata.myprog.mymd2 metadata.myprog.mymd constant.bit32.16 ================================BXOR================================ The bxor command is used to perform an binary XOR operation between two operands. The basic syntax for the bxor command is: cmd bxor operA operB operC The command will perform the "operB XOR operC" and store the result in operC. That is: operA = operB ^ operC operA can be one of: metadatum, header field. operB and operC can be one of: constant, metadatum, key, header field or param. The following example will perform a XOR operation of constant 16 and mymd metadata and store the result in metadatum mymd2 of pipeline myprog: tc p4template create action/myprog/myfunc \ cmd bxor metadata.myprog.mymd2 metadata.myprog.mymd constant.bit32.16 ===============================SND PORT EGRESS=============================== The send_port_egress command sends the received packet to a specific network interface device. The syntax of the commands is: cmd send_port_egress operA operA must be of type dev, that is, a network interface device, which exists and is up. The following example uses the send_port_egress to send a packet to port eth0. Note that no other action can run after send_port_egress. tc p4template create action/myprog/myfunc \ cmd send_port_egress dev.eth0 ===============================MIRPORTEGRESS=============================== The mirror_port_egress command mirror the received packet to a specific network interface device. The syntax of the commands is: cmd send_port_egress operA operA must be of type dev, that is, a network interface device, which exists and is up. The following example uses the mirror_port_egress to mirror a packet to port eth0. Note that the semantic of mirror here is means that we are cloning the packet and sending it to the specified network interface. This command won't edit or change the course of the original packet. tc p4template create action/myprog/myfunc \ cmd mirror_port_egress dev.eth0 Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Co-developed-by: Evangelos Haleplidis Signed-off-by: Evangelos Haleplidis Signed-off-by: Jamal Hadi Salim --- include/net/p4tc.h | 83 +- include/net/tc_act/p4tc.h | 5 + include/uapi/linux/p4tc.h | 126 ++ net/sched/p4tc/Makefile | 2 +- net/sched/p4tc/p4tc_action.c | 86 +- net/sched/p4tc/p4tc_cmds.c | 3639 ++++++++++++++++++++++++++++++++++ 6 files changed, 3934 insertions(+), 7 deletions(-) create mode 100644 net/sched/p4tc/p4tc_cmds.c diff --git a/include/net/p4tc.h b/include/net/p4tc.h index d098ae47d088..a31a6420e7e3 100644 --- a/include/net/p4tc.h +++ b/include/net/p4tc.h @@ -180,6 +180,7 @@ static inline bool pipeline_sealed(struct p4tc_pipeline *pipeline) { return pipeline->p_state == P4TC_STATE_READY; } + void tcf_pipeline_add_dep_edge(struct p4tc_pipeline *pipeline, struct p4tc_act_dep_edge_node *edge_node, u32 vertex_id); @@ -514,7 +515,6 @@ struct p4tc_table *tcf_table_find_byany(struct p4tc_pipeline *pipeline, struct netlink_ext_ack *extack); struct p4tc_table *tcf_table_find_byid(struct p4tc_pipeline *pipeline, const u32 tbl_id); -void *tcf_table_fetch(struct sk_buff *skb, void *tbl_value_ops); int tcf_table_try_set_state_ready(struct p4tc_pipeline *pipeline, struct netlink_ext_ack *extack); struct p4tc_table *tcf_table_get(struct p4tc_pipeline *pipeline, @@ -557,6 +557,7 @@ struct p4tc_hdrfield *tcf_hdrfield_get(struct p4tc_parser *parser, const char *hdrfield_name, u32 hdrfield_id, struct netlink_ext_ack *extack); +void *tcf_hdrfield_fetch(struct sk_buff *skb, struct p4tc_hdrfield *hdrfield); void tcf_hdrfield_put_ref(struct p4tc_hdrfield *hdrfield); int p4tc_init_net_ops(struct net *net, unsigned int id); @@ -599,4 +600,84 @@ void tcf_register_put_rcu(struct rcu_head *head); #define to_table(t) ((struct p4tc_table *)t) #define to_register(t) ((struct p4tc_register *)t) +/* P4TC COMMANDS */ +int p4tc_cmds_parse(struct net *net, struct p4tc_act *act, struct nlattr *nla, + bool ovr, struct netlink_ext_ack *extack); +int p4tc_cmds_copy(struct p4tc_act *act, struct list_head *new_cmd_operations, + bool delete_old, struct netlink_ext_ack *extack); + +int p4tc_cmds_fillup(struct sk_buff *skb, struct list_head *meta_ops); +void p4tc_cmds_release_ope_list(struct net *net, struct list_head *entries, + bool called_from_template); +struct p4tc_cmd_operand; +int p4tc_cmds_fill_operand(struct sk_buff *skb, struct p4tc_cmd_operand *kopnd); + +struct p4tc_cmd_operate { + struct list_head cmd_operations; + struct list_head operands_list; + struct p4tc_cmd_s *cmd; + char *label1; + char *label2; + char *cmd_label; + u32 num_opnds; + u32 ctl1; + u32 ctl2; + u16 op_id; /* P4TC_CMD_OP_XXX */ + u32 cmd_offset; + u8 op_flags; + u8 op_cnt; +}; + +struct tcf_p4act; +struct p4tc_cmd_operand { + struct list_head oper_list_node; + void *(*fetch)(struct sk_buff *skb, struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res); + struct p4tc_type *oper_datatype; /* what is stored in path_or_value - P4T_XXX */ + struct p4tc_type_mask_shift *oper_mask_shift; + struct tc_action *action; + void *path_or_value; + void *path_or_value_extra; + void *print_prefix; + void *priv; + u64 immedv_large[BITS_TO_U64(P4T_MAX_BITSZ)]; + u32 immedv; /* one of: immediate value, metadata id, action id */ + u32 immedv2; /* one of: action instance */ + u32 path_or_value_sz; + u32 path_or_value_extra_sz; + u32 print_prefix_sz; + u32 immedv_large_sz; + u32 pipeid; /* 0 for kernel */ + u8 oper_type; /* P4TC_CMD_OPER_XXX */ + u8 oper_cbitsize; /* based on P4T_XXX container size */ + u8 oper_bitsize; /* diff between bitend - oper_bitend */ + u8 oper_bitstart; + u8 oper_bitend; + u8 oper_flags; /* TBA: DATA_IS_IMMEDIATE */ +}; + +struct p4tc_cmd_s { + int cmdid; + u32 num_opnds; + int (*validate_operands)(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opns, + struct netlink_ext_ack *extack); + void (*free_operation)(struct net *net, struct p4tc_cmd_operate *op, + bool called_for_instance, + struct netlink_ext_ack *extack); + int (*run)(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res); +}; + +#ifdef CONFIG_RETPOLINE +int __p4tc_cmd_run(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res); +#else +static inline int __p4tc_cmd_run(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return op->cmd->run(skb, op, cmd, res); +} +#endif + #endif diff --git a/include/net/tc_act/p4tc.h b/include/net/tc_act/p4tc.h index 8526559c74dc..a6610bd83f63 100644 --- a/include/net/tc_act/p4tc.h +++ b/include/net/tc_act/p4tc.h @@ -2,6 +2,7 @@ #ifndef __NET_TC_ACT_P4_H #define __NET_TC_ACT_P4_H +#include #include #include @@ -24,4 +25,8 @@ struct tcf_p4act { }; #define to_p4act(a) ((struct tcf_p4act *)a) +INDIRECT_CALLABLE_DECLARE(int tcf_p4_dyna_act(struct sk_buff *skb, + const struct tc_action *a, + struct tcf_result *res)); + #endif /* __NET_TC_ACT_P4_H */ diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h index a09c4fa96e68..768f95f87963 100644 --- a/include/uapi/linux/p4tc.h +++ b/include/uapi/linux/p4tc.h @@ -397,4 +397,130 @@ enum { #define P4TC_RTA(r) \ ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct p4tcmsg)))) +/* P4TC COMMANDS */ + +/* Operations */ +enum { + P4TC_CMD_OP_UNSPEC, + P4TC_CMD_OP_SET, + P4TC_CMD_OP_ACT, + P4TC_CMD_OP_BEQ, + P4TC_CMD_OP_BNE, + P4TC_CMD_OP_BLT, + P4TC_CMD_OP_BLE, + P4TC_CMD_OP_BGT, + P4TC_CMD_OP_BGE, + P4TC_CMD_OP_PLUS, + P4TC_CMD_OP_PRINT, + P4TC_CMD_OP_TBLAPP, + P4TC_CMD_OP_SNDPORTEGR, + P4TC_CMD_OP_MIRPORTEGR, + P4TC_CMD_OP_SUB, + P4TC_CMD_OP_CONCAT, + P4TC_CMD_OP_BAND, + P4TC_CMD_OP_BOR, + P4TC_CMD_OP_BXOR, + P4TC_CMD_OP_LABEL, + P4TC_CMD_OP_JUMP, + P4TC_CMD_OP_RET, + __P4TC_CMD_OP_MAX +}; +#define P4TC_CMD_OP_MAX (__P4TC_CMD_OP_MAX - 1) + +#define P4TC_CMD_OPERS_MAX 9 + +/* single operation within P4TC_ACT_CMDS_LIST */ +enum { + P4TC_CMD_UNSPEC, + P4TC_CMD_OPERATION, /*struct p4tc_u_operate */ + P4TC_CMD_OPER_LIST, /*nested P4TC_CMD_OPER_XXX list */ + P4TC_CMD_OPER_LABEL1, + P4TC_CMD_OPER_LABEL2, + P4TC_CMD_OPER_CMD_LABEL, + __P4TC_CMD_OPER_MAX +}; +#define P4TC_CMD_OPER_MAX (__P4TC_CMD_OPER_MAX - 1) + +enum { + P4TC_CMD_OPER_A, + P4TC_CMD_OPER_B, + P4TC_CMD_OPER_C, + P4TC_CMD_OPER_D, + P4TC_CMD_OPER_E, + P4TC_CMD_OPER_F, + P4TC_CMD_OPER_G, + P4TC_CMD_OPER_H, + P4TC_CMD_OPER_I, +}; + +#define P4TC_CMDS_RESULTS_HIT 1 +#define P4TC_CMDS_RESULTS_MISS 2 + +/* P4TC_CMD_OPERATION */ +struct p4tc_u_operate { + __u16 op_type; /* P4TC_CMD_OP_XXX */ + __u8 op_flags; + __u8 op_UNUSED; + __u32 op_ctl1; + __u32 op_ctl2; +}; + +/* Nested P4TC_CMD_OPER_XXX */ +enum { + P4TC_CMD_OPND_UNSPEC, + P4TC_CMD_OPND_INFO, + P4TC_CMD_OPND_PATH, + P4TC_CMD_OPND_PATH_EXTRA, + P4TC_CMD_OPND_LARGE_CONSTANT, + P4TC_CMD_OPND_PREFIX, + __P4TC_CMD_OPND_MAX +}; +#define P4TC_CMD_OPND_MAX (__P4TC_CMD_OPND_MAX - 1) + +/* operand types */ +enum { + P4TC_OPER_UNSPEC, + P4TC_OPER_CONST, + P4TC_OPER_META, + P4TC_OPER_ACTID, + P4TC_OPER_TBL, + P4TC_OPER_KEY, + P4TC_OPER_RES, + P4TC_OPER_HDRFIELD, + P4TC_OPER_PARAM, + P4TC_OPER_DEV, + P4TC_OPER_REG, + P4TC_OPER_LABEL, + P4TC_OPER_RET, + __P4TC_OPER_MAX +}; +#define P4TC_OPER_MAX (__P4TC_OPER_MAX - 1) + +#define P4TC_CMD_MAX_OPER_PATH_LEN 32 + +/* P4TC_CMD_OPER_INFO operand*/ +struct p4tc_u_operand { + __u32 immedv; /* immediate value */ + __u32 immedv2; + __u32 pipeid; /* 0 for kernel-global */ + __u8 oper_type; /* P4TC_OPER_XXX */ + __u8 oper_datatype; /* T_XXX */ + __u8 oper_cbitsize; /* Size of container, u8 = 8, etc + * Useful for a type that is not atomic + */ + __u8 oper_startbit; + __u8 oper_endbit; + __u8 oper_flags; +}; + +/* operand flags */ +#define DATA_IS_IMMEDIATE (BIT(0)) /* data is held as immediate value */ +#define DATA_IS_RAW (BIT(1)) /* bitXX datatype, not intepreted by kernel */ +#define DATA_IS_SLICE (BIT(2)) /* bitslice in a container, not intepreted + * by kernel + */ +#define DATA_USES_ROOT_PIPE (BIT(3)) +#define DATA_HAS_TYPE_INFO (BIT(4)) +#define DATA_IS_READ_ONLY (BIT(5)) + #endif diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index b35ced1e3c9a..396fcd249fb8 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -2,4 +2,4 @@ obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.o p4tc_meta.o \ p4tc_parser_api.o p4tc_hdrfield.o p4tc_action.o p4tc_table.o \ - p4tc_tbl_api.o p4tc_register.o + p4tc_tbl_api.o p4tc_register.o p4tc_cmds.o diff --git a/net/sched/p4tc/p4tc_action.c b/net/sched/p4tc/p4tc_action.c index 617aed297a58..8b69842cc3ce 100644 --- a/net/sched/p4tc/p4tc_action.c +++ b/net/sched/p4tc/p4tc_action.c @@ -9,6 +9,7 @@ * Pedro Tammela */ +#include #include #include #include @@ -159,7 +160,7 @@ static int __tcf_p4_dyna_init_set(struct p4tc_act *act, struct tc_action **a, { struct tcf_p4act_params *params_old; struct tcf_p4act *p; - int err = 0; + int err; p = to_p4act(*a); @@ -168,6 +169,14 @@ static int __tcf_p4_dyna_init_set(struct p4tc_act *act, struct tc_action **a, goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); + err = p4tc_cmds_copy(act, &p->cmd_operations, exists, extack); + if (err < 0) { + if (exists) + spin_unlock_bh(&p->tcf_lock); + + return err; + } + params_old = rcu_replace_pointer(p->params, params, 1); if (exists) spin_unlock_bh(&p->tcf_lock); @@ -370,9 +379,15 @@ static int dev_dump_param_value(struct sk_buff *skb, nest = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE); if (param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN) { + struct p4tc_cmd_operand *kopnd; struct nlattr *nla_opnd; nla_opnd = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE_OPND); + kopnd = param->value; + if (p4tc_cmds_fill_operand(skb, kopnd) < 0) { + ret = -1; + goto out_nla_cancel; + } nla_nest_end(skb, nla_opnd); } else { const u32 *ifindex = param->value; @@ -565,15 +580,45 @@ int tcf_p4_dyna_template_init(struct net *net, struct tc_action **a, return err; } -static int tcf_p4_dyna_act(struct sk_buff *skb, const struct tc_action *a, - struct tcf_result *res) +INDIRECT_CALLABLE_SCOPE int tcf_p4_dyna_act(struct sk_buff *skb, + const struct tc_action *a, + struct tcf_result *res) { struct tcf_p4act *dynact = to_p4act(a); int ret = 0; + int jmp_cnt = 0; + struct p4tc_cmd_operate *op; tcf_lastuse_update(&dynact->tcf_tm); tcf_action_update_bstats(&dynact->common, skb); + list_for_each_entry(op, &dynact->cmd_operations, cmd_operations) { + if (jmp_cnt-- > 0) + continue; + + if (op->op_id == P4TC_CMD_OP_LABEL) { + ret = TC_ACT_PIPE; + continue; + } + + ret = __p4tc_cmd_run(skb, op, dynact, res); + if (TC_ACT_EXT_CMP(ret, TC_ACT_JUMP)) { + jmp_cnt = ret & TC_ACT_EXT_VAL_MASK; + continue; + } else if (ret != TC_ACT_PIPE) { + break; + } + } + + if (ret == TC_ACT_SHOT) + tcf_action_inc_drop_qstats(&dynact->common); + + if (ret == TC_ACT_STOLEN || ret == TC_ACT_TRAP) + ret = TC_ACT_CONSUMED; + + if (ret == TC_ACT_OK) + ret = dynact->tcf_action; + return ret; } @@ -602,6 +647,8 @@ static int tcf_p4_dyna_dump(struct sk_buff *skb, struct tc_action *a, int bind, goto nla_put_failure; nest = nla_nest_start(skb, P4TC_ACT_CMDS_LIST); + if (p4tc_cmds_fillup(skb, &dynact->cmd_operations)) + goto nla_put_failure; nla_nest_end(skb, nest); if (nla_put_string(skb, P4TC_ACT_NAME, a->ops->kind)) @@ -697,6 +744,7 @@ static void tcf_p4_dyna_cleanup(struct tc_action *a) if (refcount_read(&ops->dyn_ref) > 1) refcount_dec(&ops->dyn_ref); + p4tc_cmds_release_ope_list(NULL, &m->cmd_operations, false); if (params) call_rcu(¶ms->rcu, tcf_p4_act_params_destroy_rcu); } @@ -710,9 +758,13 @@ int generic_dump_param_value(struct sk_buff *skb, struct p4tc_type *type, nla_value = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE); if (param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN) { + struct p4tc_cmd_operand *kopnd; struct nlattr *nla_opnd; nla_opnd = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE_OPND); + kopnd = param->value; + if (p4tc_cmds_fill_operand(skb, kopnd) < 0) + goto out_nlmsg_trim; nla_nest_end(skb, nla_opnd); } else { if (nla_put(skb, P4TC_ACT_PARAMS_VALUE_RAW, bytesz, @@ -1291,6 +1343,8 @@ static int __tcf_act_put(struct net *net, struct p4tc_pipeline *pipeline, kfree(act_param); } + p4tc_cmds_release_ope_list(net, &act->cmd_operations, true); + ret = tcf_unregister_dyn_action(net, &act->ops); if (ret < 0) { NL_SET_ERR_MSG(extack, @@ -1364,6 +1418,8 @@ static int _tcf_act_fill_nlmsg(struct net *net, struct sk_buff *skb, nla_nest_end(skb, parms); cmds = nla_nest_start(skb, P4TC_ACT_CMDS_LIST); + if (p4tc_cmds_fillup(skb, &act->cmd_operations)) + goto out_nlmsg_trim; nla_nest_end(skb, cmds); nla_nest_end(skb, nest); @@ -1621,13 +1677,19 @@ static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, INIT_LIST_HEAD(&act->cmd_operations); act->pipeline = pipeline; + if (tb[P4TC_ACT_CMDS_LIST]) { + ret = p4tc_cmds_parse(net, act, tb[P4TC_ACT_CMDS_LIST], false, + extack); + if (ret < 0) + goto uninit; + } pipeline->num_created_acts++; ret = determine_act_topological_order(pipeline, true); if (ret < 0) { pipeline->num_created_acts--; - goto uninit; + goto release_cmds; } act->common.p_id = pipeline->common.p_id; @@ -1641,6 +1703,10 @@ static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, return act; +release_cmds: + if (tb[P4TC_ACT_CMDS_LIST]) + p4tc_cmds_release_ope_list(net, &act->cmd_operations, false); + uninit: p4_put_many_params(&act->params_idr, params, num_params); idr_destroy(&act->params_idr); @@ -1720,14 +1786,22 @@ static struct p4tc_act *tcf_act_update(struct net *net, struct nlattr **tb, } if (tb[P4TC_ACT_CMDS_LIST]) { - ret = determine_act_topological_order(pipeline, true); + ret = p4tc_cmds_parse(net, act, tb[P4TC_ACT_CMDS_LIST], true, + extack); if (ret < 0) goto params_del; + + ret = determine_act_topological_order(pipeline, true); + if (ret < 0) + goto release_cmds; } p4tc_params_replace_many(&act->params_idr, params, num_params); return act; +release_cmds: + p4tc_cmds_release_ope_list(net, &act->cmd_operations, false); + params_del: p4_put_many_params(&act->params_idr, params, num_params); @@ -1815,6 +1889,8 @@ static int tcf_act_dump_1(struct sk_buff *skb, goto out_nlmsg_trim; nest = nla_nest_start(skb, P4TC_ACT_CMDS_LIST); + if (p4tc_cmds_fillup(skb, &act->cmd_operations)) + goto out_nlmsg_trim; nla_nest_end(skb, nest); if (nla_put_u8(skb, P4TC_ACT_ACTIVE, act->active)) diff --git a/net/sched/p4tc/p4tc_cmds.c b/net/sched/p4tc/p4tc_cmds.c new file mode 100644 index 000000000000..2ba80f27af34 --- /dev/null +++ b/net/sched/p4tc/p4tc_cmds.c @@ -0,0 +1,3639 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/p4tc_cmds.c - P4 TC cmds + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define GET_OPA(operands_list) \ + (list_first_entry(operands_list, struct p4tc_cmd_operand, \ + oper_list_node)) + +#define GET_OPB(operands_list) \ + (list_next_entry(GET_OPA(operands_list), oper_list_node)) + +#define GET_OPC(operands_list) \ + (list_next_entry(GET_OPB(operands_list), oper_list_node)) + +#define P4TC_FETCH_DECLARE(fname) \ + static void *fname(struct sk_buff *skb, struct p4tc_cmd_operand *op, \ + struct tcf_p4act *cmd, struct tcf_result *res) + +P4TC_FETCH_DECLARE(p4tc_fetch_metadata); +P4TC_FETCH_DECLARE(p4tc_fetch_constant); +P4TC_FETCH_DECLARE(p4tc_fetch_key); +P4TC_FETCH_DECLARE(p4tc_fetch_table); +P4TC_FETCH_DECLARE(p4tc_fetch_result); +P4TC_FETCH_DECLARE(p4tc_fetch_hdrfield); +P4TC_FETCH_DECLARE(p4tc_fetch_param); +P4TC_FETCH_DECLARE(p4tc_fetch_dev); +P4TC_FETCH_DECLARE(p4tc_fetch_reg); + +#define P4TC_CMD_DECLARE(fname) \ + static int fname(struct sk_buff *skb, struct p4tc_cmd_operate *op, \ + struct tcf_p4act *cmd, struct tcf_result *res) + +P4TC_CMD_DECLARE(p4tc_cmd_SET); +P4TC_CMD_DECLARE(p4tc_cmd_ACT); +P4TC_CMD_DECLARE(p4tc_cmd_PRINT); +P4TC_CMD_DECLARE(p4tc_cmd_TBLAPP); +P4TC_CMD_DECLARE(p4tc_cmd_SNDPORTEGR); +P4TC_CMD_DECLARE(p4tc_cmd_MIRPORTEGR); +P4TC_CMD_DECLARE(p4tc_cmd_PLUS); +P4TC_CMD_DECLARE(p4tc_cmd_SUB); +P4TC_CMD_DECLARE(p4tc_cmd_CONCAT); +P4TC_CMD_DECLARE(p4tc_cmd_BAND); +P4TC_CMD_DECLARE(p4tc_cmd_BOR); +P4TC_CMD_DECLARE(p4tc_cmd_BXOR); +P4TC_CMD_DECLARE(p4tc_cmd_JUMP); +P4TC_CMD_DECLARE(p4tc_cmd_RET); + +#ifdef CONFIG_RETPOLINE +int __p4tc_cmd_run(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + #define RUN(fname) \ + if (op->cmd->run == fname) \ + return fname(skb, op, cmd, res) + + RUN(p4tc_cmd_SET); + RUN(p4tc_cmd_ACT); + RUN(p4tc_cmd_PRINT); + RUN(p4tc_cmd_TBLAPP); + RUN(p4tc_cmd_SNDPORTEGR); + RUN(p4tc_cmd_MIRPORTEGR); + RUN(p4tc_cmd_PLUS); + RUN(p4tc_cmd_SUB); + RUN(p4tc_cmd_CONCAT); + RUN(p4tc_cmd_BAND); + RUN(p4tc_cmd_BOR); + RUN(p4tc_cmd_BXOR); + + return op->cmd->run(skb, op, cmd, res); +} + +static inline void *__p4tc_fetch(struct sk_buff *skb, + struct p4tc_cmd_operand *oprnd, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + #define FETCH(fname) \ + if (oprnd->fetch == fname) \ + return fname(skb, oprnd, cmd, res) + + FETCH(p4tc_fetch_metadata); + FETCH(p4tc_fetch_constant); + FETCH(p4tc_fetch_table); + FETCH(p4tc_fetch_key); + FETCH(p4tc_fetch_result); + FETCH(p4tc_fetch_hdrfield); + FETCH(p4tc_fetch_param); + FETCH(p4tc_fetch_dev); + FETCH(p4tc_fetch_reg); + + return oprnd->fetch(skb, oprnd, cmd, res); +} +#else +static inline void *__p4tc_fetch(struct sk_buff *skb, + struct p4tc_cmd_operand *oprnd, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return oprnd->fetch(skb, oprnd, cmd, res); +} +#endif + +static void kfree_opentry(struct net *net, struct p4tc_cmd_operate *ope, + bool called_from_template) +{ + if (!ope) + return; + + ope->cmd->free_operation(net, ope, called_from_template, NULL); +} + +static void copy_k2u_operand(struct p4tc_cmd_operand *k, + struct p4tc_u_operand *u) +{ + u->pipeid = k->pipeid; + u->immedv = k->immedv; + u->immedv2 = k->immedv2; + u->oper_type = k->oper_type; + u->oper_datatype = k->oper_datatype->typeid; + u->oper_cbitsize = k->oper_cbitsize; + u->oper_startbit = k->oper_bitstart; + u->oper_endbit = k->oper_bitend; + u->oper_flags = k->oper_flags; +} + +static int copy_u2k_operand(struct p4tc_u_operand *uopnd, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_type *type; + + type = p4type_find_byid(uopnd->oper_datatype); + if (kopnd->oper_flags & DATA_HAS_TYPE_INFO && !type) { + NL_SET_ERR_MSG_MOD(extack, "Invalid operand type"); + return -EINVAL; + } + + kopnd->pipeid = uopnd->pipeid; + kopnd->immedv = uopnd->immedv; + kopnd->immedv2 = uopnd->immedv2; + kopnd->oper_type = uopnd->oper_type; + kopnd->oper_datatype = type; + kopnd->oper_cbitsize = uopnd->oper_cbitsize; + kopnd->oper_bitstart = uopnd->oper_startbit; + kopnd->oper_bitend = uopnd->oper_endbit; + kopnd->oper_bitsize = 1 + kopnd->oper_bitend - kopnd->oper_bitstart; + kopnd->oper_flags = uopnd->oper_flags; + + return 0; +} + +int p4tc_cmds_fill_operand(struct sk_buff *skb, struct p4tc_cmd_operand *kopnd) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_u_operand oper = { 0 }; + u32 plen; + + copy_k2u_operand(kopnd, &oper); + if (nla_put(skb, P4TC_CMD_OPND_INFO, sizeof(struct p4tc_u_operand), + &oper)) + goto nla_put_failure; + + if (kopnd->path_or_value && + nla_put_string(skb, P4TC_CMD_OPND_PATH, kopnd->path_or_value)) + goto nla_put_failure; + + if (kopnd->path_or_value_extra && + nla_put_string(skb, P4TC_CMD_OPND_PATH_EXTRA, + kopnd->path_or_value_extra)) + goto nla_put_failure; + + if (kopnd->print_prefix && + nla_put_string(skb, P4TC_CMD_OPND_PREFIX, kopnd->print_prefix)) + goto nla_put_failure; + + plen = kopnd->immedv_large_sz; + + if (plen && nla_put(skb, P4TC_CMD_OPND_LARGE_CONSTANT, plen, + kopnd->immedv_large)) + goto nla_put_failure; + + return skb->len; + +nla_put_failure: + nlmsg_trim(skb, b); + return -1; +} + +static int p4tc_cmds_fill_operands_list(struct sk_buff *skb, + struct list_head *operands_list) +{ + unsigned char *b = nlmsg_get_pos(skb); + int i = 1; + struct p4tc_cmd_operand *cursor; + struct nlattr *nest_count; + + list_for_each_entry(cursor, operands_list, oper_list_node) { + nest_count = nla_nest_start(skb, i); + + if (p4tc_cmds_fill_operand(skb, cursor) < 0) + goto nla_put_failure; + + nla_nest_end(skb, nest_count); + i++; + } + + return skb->len; + +nla_put_failure: + nlmsg_trim(skb, b); + return -1; +} + +/* under spin lock */ +int p4tc_cmds_fillup(struct sk_buff *skb, struct list_head *cmd_operations) +{ + unsigned char *b = nlmsg_get_pos(skb); + struct p4tc_u_operate op = {}; + int i = 1; + struct nlattr *nest_op, *nest_opnds; + struct p4tc_cmd_operate *entry; + int err; + + list_for_each_entry(entry, cmd_operations, cmd_operations) { + nest_op = nla_nest_start(skb, i); + + op.op_type = entry->op_id; + op.op_flags = entry->op_flags; + op.op_ctl1 = entry->ctl1; + op.op_ctl2 = entry->ctl2; + if (nla_put(skb, P4TC_CMD_OPERATION, + sizeof(struct p4tc_u_operate), &op)) + goto nla_put_failure; + + if (!list_empty(&entry->operands_list)) { + nest_opnds = nla_nest_start(skb, P4TC_CMD_OPER_LIST); + err = p4tc_cmds_fill_operands_list(skb, + &entry->operands_list); + if (err < 0) + goto nla_put_failure; + nla_nest_end(skb, nest_opnds); + } + + if (entry->cmd_label && + nla_put_string(skb, P4TC_CMD_OPER_CMD_LABEL, entry->cmd_label)) + goto nla_put_failure; + + nla_nest_end(skb, nest_op); + i++; + } + + return 0; + +nla_put_failure: + nlmsg_trim(skb, b); + return -1; +} + +void p4tc_cmds_release_ope_list(struct net *net, struct list_head *entries, + bool called_from_template) +{ + struct p4tc_cmd_operate *entry, *e; + + list_for_each_entry_safe(entry, e, entries, cmd_operations) { + list_del(&entry->cmd_operations); + kfree_opentry(net, entry, called_from_template); + } +} + +static void kfree_tmp_oplist(struct net *net, struct p4tc_cmd_operate *oplist[], + bool called_from_template) +{ + int i = 0; + struct p4tc_cmd_operate *ope; + + for (i = 0; i < P4TC_CMDS_LIST_MAX; i++) { + ope = oplist[i]; + if (!ope) + continue; + + kfree_opentry(net, ope, called_from_template); + } +} + +static int validate_metadata_operand(struct p4tc_cmd_operand *kopnd, + struct p4tc_type *container_type, + struct netlink_ext_ack *extack) +{ + const struct p4tc_type_ops *type_ops = container_type->ops; + int err; + + if (kopnd->oper_cbitsize < kopnd->oper_bitsize) { + NL_SET_ERR_MSG_MOD(extack, "bitsize has to be <= cbitsize\n"); + return -EINVAL; + } + + if (type_ops->validate_p4t) { + if (kopnd->oper_type == P4TC_OPER_CONST) + if (kopnd->oper_flags & DATA_IS_IMMEDIATE) { + err = type_ops->validate_p4t(container_type, + &kopnd->immedv, + kopnd->oper_bitstart, + kopnd->oper_bitend, + extack); + } else { + err = type_ops->validate_p4t(container_type, + kopnd->immedv_large, + kopnd->oper_bitstart, + kopnd->oper_bitend, + extack); + } + else + err = type_ops->validate_p4t(container_type, NULL, + kopnd->oper_bitstart, + kopnd->oper_bitend, + extack); + if (err) + return err; + } + + return 0; +} + +static int validate_table_operand(struct p4tc_act *act, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_table *table; + + table = tcf_table_get(act->pipeline, (const char *)kopnd->path_or_value, + kopnd->immedv, extack); + if (IS_ERR(table)) + return PTR_ERR(table); + + kopnd->priv = table; + + return 0; +} + +static int validate_key_operand(struct p4tc_act *act, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_type *t = kopnd->oper_datatype; + struct p4tc_table *table; + + kopnd->pipeid = act->pipeline->common.p_id; + + table = tcf_table_get(act->pipeline, (const char *)kopnd->path_or_value, + kopnd->immedv, extack); + if (IS_ERR(table)) + return PTR_ERR(table); + kopnd->immedv = table->tbl_id; + + if (kopnd->oper_flags & DATA_HAS_TYPE_INFO) { + if (kopnd->oper_bitstart != 0) { + NL_SET_ERR_MSG_MOD(extack, "Key bitstart must be zero"); + return -EINVAL; + } + + if (t->typeid != P4T_KEY) { + NL_SET_ERR_MSG_MOD(extack, "Key type must be key"); + return -EINVAL; + } + + if (table->tbl_keysz != kopnd->oper_bitsize) { + NL_SET_ERR_MSG_MOD(extack, + "Type size doesn't match table keysz"); + return -EINVAL; + } + + t->bitsz = kopnd->oper_bitsize; + } else { + t = p4type_find_byid(P4T_KEY); + if (!t) + return -EINVAL; + + kopnd->oper_bitstart = 0; + kopnd->oper_bitend = table->tbl_keysz - 1; + kopnd->oper_bitsize = table->tbl_keysz; + kopnd->oper_datatype = t; + } + + return 0; +} + +static int validate_hdrfield_operand_type(struct p4tc_cmd_operand *kopnd, + struct p4tc_hdrfield *hdrfield, + struct netlink_ext_ack *extack) +{ + if (hdrfield->startbit != kopnd->oper_bitstart || + hdrfield->endbit != kopnd->oper_bitend || + hdrfield->datatype != kopnd->oper_datatype->typeid) { + NL_SET_ERR_MSG_MOD(extack, "Header field type mismatch"); + return -EINVAL; + } + + return 0; +} + +static int validate_hdrfield_operand(struct p4tc_act *act, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_hdrfield *hdrfield; + struct p4tc_parser *parser; + struct p4tc_type *typ; + + kopnd->pipeid = act->pipeline->common.p_id; + + parser = tcf_parser_find_byany(act->pipeline, + (const char *)kopnd->path_or_value, + kopnd->immedv, extack); + if (IS_ERR(parser)) + return PTR_ERR(parser); + kopnd->immedv = parser->parser_inst_id; + + hdrfield = tcf_hdrfield_get(parser, + (const char *)kopnd->path_or_value_extra, + kopnd->immedv2, extack); + if (IS_ERR(hdrfield)) + return PTR_ERR(hdrfield); + kopnd->immedv2 = hdrfield->hdrfield_id; + + if (kopnd->oper_flags & DATA_HAS_TYPE_INFO) { + if (validate_hdrfield_operand_type(kopnd, hdrfield, extack) < 0) + return -EINVAL; + } else { + kopnd->oper_bitstart = hdrfield->startbit; + kopnd->oper_bitend = hdrfield->endbit; + kopnd->oper_datatype = p4type_find_byid(hdrfield->datatype); + kopnd->oper_bitsize = hdrfield->endbit - hdrfield->startbit + 1; + kopnd->oper_cbitsize = kopnd->oper_datatype->container_bitsz; + } + typ = kopnd->oper_datatype; + if (typ->ops->create_bitops) { + struct p4tc_type_mask_shift *mask_shift; + + mask_shift = typ->ops->create_bitops(kopnd->oper_bitsize, + kopnd->oper_bitstart, + kopnd->oper_bitend, + extack); + if (IS_ERR(mask_shift)) + return PTR_ERR(mask_shift); + + kopnd->oper_mask_shift = mask_shift; + } + + kopnd->priv = hdrfield; + + refcount_inc(&act->pipeline->p_hdrs_used); + + return 0; +} + +struct p4tc_cmd_opnd_priv_dev { + struct net_device *dev; + netdevice_tracker *tracker; +}; + +static int validate_dev_operand(struct net *net, struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_opnd_priv_dev *priv_dev; + struct net_device *dev; + + if (kopnd->oper_datatype->typeid != P4T_DEV) { + NL_SET_ERR_MSG_MOD(extack, "dev parameter must be dev"); + return -EINVAL; + } + + if (kopnd->oper_datatype->ops->validate_p4t(kopnd->oper_datatype, + &kopnd->immedv, + kopnd->oper_bitstart, + kopnd->oper_bitend, + extack) < 0) { + return -EINVAL; + } + + priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); + if (!priv_dev) + return -ENOMEM; + kopnd->priv = priv_dev; + + dev = dev_get_by_index(net, kopnd->immedv); + if (!dev) { + NL_SET_ERR_MSG_MOD(extack, "Invalid ifindex"); + return -ENODEV; + } + priv_dev->dev = dev; + netdev_tracker_alloc(dev, priv_dev->tracker, GFP_KERNEL); + + return 0; +} + +static int validate_param_operand(struct p4tc_act *act, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_act_param *param; + struct p4tc_type *type; + + param = tcf_param_find_byany(act, (const char *)kopnd->path_or_value, + kopnd->immedv2, extack); + + if (IS_ERR(param)) + return PTR_ERR(param); + + kopnd->pipeid = act->pipeline->common.p_id; + kopnd->immedv = act->a_id; + kopnd->immedv2 = param->index; + + type = param->type; + if (kopnd->oper_flags & DATA_HAS_TYPE_INFO) { + if (type->typeid != kopnd->oper_datatype->typeid) { + NL_SET_ERR_MSG_MOD(extack, "Param type mismatch"); + return -EINVAL; + } + + if (type->bitsz != kopnd->oper_datatype->bitsz) { + NL_SET_ERR_MSG_MOD(extack, "Param size mismatch"); + return -EINVAL; + } + } else { + kopnd->oper_datatype = type; + kopnd->oper_bitstart = 0; + kopnd->oper_bitend = type->bitsz - 1; + kopnd->oper_bitsize = type->bitsz; + } + kopnd->pipeid = act->pipeline->common.p_id; + kopnd->immedv = act->a_id; + kopnd->oper_flags |= DATA_IS_READ_ONLY; + + if (kopnd->oper_bitstart != 0) { + NL_SET_ERR_MSG_MOD(extack, "Param startbit must be zero"); + return -EINVAL; + } + + if (kopnd->oper_bitstart > kopnd->oper_bitend) { + NL_SET_ERR_MSG_MOD(extack, "Param startbit > endbit"); + return -EINVAL; + } + + if (type->ops->create_bitops) { + struct p4tc_type_mask_shift *mask_shift; + + mask_shift = type->ops->create_bitops(kopnd->oper_bitsize, + kopnd->oper_bitstart, + kopnd->oper_bitend, + extack); + if (IS_ERR(mask_shift)) + return PTR_ERR(mask_shift); + + kopnd->oper_mask_shift = mask_shift; + } + + return 0; +} + +static int validate_res_operand(struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + if (kopnd->immedv == P4TC_CMDS_RESULTS_HIT || + kopnd->immedv == P4TC_CMDS_RESULTS_MISS) + return 0; + + kopnd->oper_flags |= DATA_IS_READ_ONLY; + + NL_SET_ERR_MSG_MOD(extack, "Invalid result field"); + return -EINVAL; +} + +static int register_label(struct p4tc_act *act, const char *label, + int cmd_offset, struct netlink_ext_ack *extack) +{ + const size_t labelsz = strnlen(label, LABELNAMSIZ) + 1; + struct p4tc_label_node *node; + void *ptr; + int err; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + + node->key.label = kzalloc(labelsz, GFP_KERNEL); + if (!(node->key.label)) { + err = -ENOMEM; + goto free_node; + } + + strscpy(node->key.label, label, labelsz); + node->key.labelsz = labelsz; + + node->cmd_offset = cmd_offset; + + ptr = rhashtable_insert_slow(act->labels, &node->key, &node->ht_node); + if (IS_ERR(ptr)) { + NL_SET_ERR_MSG_MOD(extack, + "Unable to insert in labels hashtable"); + err = PTR_ERR(ptr); + goto free_label; + } + + return 0; + +free_label: + kfree(node->key.label); + +free_node: + kfree(node); + + return err; +} + +static int cmd_find_label_offset(struct p4tc_act *act, const char *label, + struct netlink_ext_ack *extack) +{ + struct p4tc_label_node *node; + struct p4tc_label_key label_key; + + label_key.label = (char *)label; + label_key.labelsz = strnlen(label, LABELNAMSIZ) + 1; + + node = rhashtable_lookup(act->labels, &label_key, p4tc_label_ht_params); + if (!node) { + NL_SET_ERR_MSG_MOD(extack, "Unable to find label"); + return -ENOENT; + } + + return node->cmd_offset; +} + +static int validate_reg_operand(struct p4tc_act *act, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_register *reg; + struct p4tc_type *t; + + reg = tcf_register_get(act->pipeline, + (const char *)kopnd->path_or_value, + kopnd->immedv, extack); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + kopnd->pipeid = act->pipeline->common.p_id; + kopnd->immedv = reg->reg_id; + + if (kopnd->immedv2 >= reg->reg_num_elems) { + NL_SET_ERR_MSG_MOD(extack, "Register index out of bounds"); + return -EINVAL; + } + + t = reg->reg_type; + kopnd->oper_datatype = t; + + if (kopnd->oper_flags & DATA_HAS_TYPE_INFO) { + if (reg->reg_type->typeid != kopnd->oper_datatype->typeid) { + NL_SET_ERR_MSG_MOD(extack, + "Invalid register data type"); + return -EINVAL; + } + + if (kopnd->oper_bitstart > kopnd->oper_bitend) { + NL_SET_ERR_MSG_MOD(extack, + "Register startbit > endbit"); + return -EINVAL; + } + } else { + kopnd->oper_bitstart = 0; + kopnd->oper_bitend = t->bitsz - 1; + kopnd->oper_bitsize = t->bitsz; + } + + if (t->ops->create_bitops) { + struct p4tc_type_mask_shift *mask_shift; + + mask_shift = t->ops->create_bitops(kopnd->oper_bitsize, + kopnd->oper_bitstart, + kopnd->oper_bitend, extack); + if (IS_ERR(mask_shift)) + return PTR_ERR(mask_shift); + + kopnd->oper_mask_shift = mask_shift; + } + + /* Should never fail */ + WARN_ON(!refcount_inc_not_zero(®->reg_ref)); + + kopnd->priv = reg; + + return 0; +} + +static struct p4tc_type_mask_shift * +create_metadata_bitops(struct p4tc_cmd_operand *kopnd, + struct p4tc_metadata *meta, struct p4tc_type *t, + struct netlink_ext_ack *extack) +{ + struct p4tc_type_mask_shift *mask_shift; + u8 bitstart, bitend; + u32 bitsz; + + if (kopnd->oper_flags & DATA_IS_SLICE) { + bitstart = meta->m_startbit + kopnd->oper_bitstart; + bitend = meta->m_startbit + kopnd->oper_bitend; + } else { + bitstart = meta->m_startbit; + bitend = meta->m_endbit; + } + bitsz = bitend - bitstart + 1; + mask_shift = t->ops->create_bitops(bitsz, bitstart, bitend, extack); + return mask_shift; +} + +static int __validate_metadata_operand(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_type *container_type; + struct p4tc_pipeline *pipeline; + struct p4tc_metadata *meta; + u32 bitsz; + int err; + + if (kopnd->oper_flags & DATA_USES_ROOT_PIPE) + pipeline = tcf_pipeline_find_byid(net, 0); + else + pipeline = act->pipeline; + + kopnd->pipeid = pipeline->common.p_id; + + meta = tcf_meta_get(pipeline, (const char *)kopnd->path_or_value, + kopnd->immedv, extack); + if (IS_ERR(meta)) + return PTR_ERR(meta); + kopnd->immedv = meta->m_id; + + if (!(kopnd->oper_flags & DATA_IS_SLICE)) { + kopnd->oper_bitstart = meta->m_startbit; + kopnd->oper_bitend = meta->m_endbit; + + bitsz = meta->m_endbit - meta->m_startbit + 1; + kopnd->oper_bitsize = bitsz; + } else { + bitsz = kopnd->oper_bitend - kopnd->oper_bitstart + 1; + } + + if (kopnd->oper_flags & DATA_HAS_TYPE_INFO) { + if (meta->m_datatype != kopnd->oper_datatype->typeid) { + NL_SET_ERR_MSG_MOD(extack, + "Invalid metadata data type"); + return -EINVAL; + } + + if (bitsz < kopnd->oper_bitsize) { + NL_SET_ERR_MSG_MOD(extack, "Invalid metadata bit size"); + return -EINVAL; + } + + if (kopnd->oper_bitstart > meta->m_endbit) { + NL_SET_ERR_MSG_MOD(extack, + "Invalid metadata slice start bit"); + return -EINVAL; + } + + if (kopnd->oper_bitend > meta->m_endbit) { + NL_SET_ERR_MSG_MOD(extack, + "Invalid metadata slice end bit"); + return -EINVAL; + } + } else { + kopnd->oper_datatype = p4type_find_byid(meta->m_datatype); + kopnd->oper_bitsize = bitsz; + kopnd->oper_cbitsize = bitsz; + } + + container_type = p4type_find_byid(meta->m_datatype); + if (!container_type) { + NL_SET_ERR_MSG_MOD(extack, "Invalid metadata type"); + return -EINVAL; + } + + err = validate_metadata_operand(kopnd, container_type, extack); + if (err < 0) + return err; + + if (meta->m_read_only) + kopnd->oper_flags |= DATA_IS_READ_ONLY; + + if (container_type->ops->create_bitops) { + struct p4tc_type_mask_shift *mask_shift; + + mask_shift = create_metadata_bitops(kopnd, meta, container_type, + extack); + if (IS_ERR(mask_shift)) + return -EINVAL; + + kopnd->oper_mask_shift = mask_shift; + } + + kopnd->priv = meta; + + return 0; +} + +static struct p4tc_type_mask_shift * +create_constant_bitops(struct p4tc_cmd_operand *kopnd, struct p4tc_type *t, + struct netlink_ext_ack *extack) +{ + struct p4tc_type_mask_shift *mask_shift; + + mask_shift = t->ops->create_bitops(t->bitsz, kopnd->oper_bitstart, + kopnd->oper_bitend, extack); + return mask_shift; +} + +static int validate_large_operand(struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_type *t = kopnd->oper_datatype; + int err = 0; + + err = validate_metadata_operand(kopnd, t, extack); + if (err) + return err; + if (t->ops->create_bitops) { + struct p4tc_type_mask_shift *mask_shift; + + mask_shift = create_constant_bitops(kopnd, t, extack); + if (IS_ERR(mask_shift)) + return -EINVAL; + + kopnd->oper_mask_shift = mask_shift; + } + + return 0; +} + +/*Data is constant <=32 bits */ +static int validate_immediate_operand(struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_type *t = kopnd->oper_datatype; + int err = 0; + + err = validate_metadata_operand(kopnd, t, extack); + if (err) + return err; + if (t->ops->create_bitops) { + struct p4tc_type_mask_shift *mask_shift; + + mask_shift = create_constant_bitops(kopnd, t, extack); + if (IS_ERR(mask_shift)) + return -EINVAL; + + kopnd->oper_mask_shift = mask_shift; + } + + return 0; +} + +static bool check_gact_return(const u32 return_code) +{ + switch (return_code) { + case TC_ACT_OK: + case TC_ACT_RECLASSIFY: + case TC_ACT_SHOT: + case TC_ACT_PIPE: + case TC_ACT_STOLEN: + case TC_ACT_QUEUED: + case TC_ACT_REPEAT: + case TC_ACT_REDIRECT: + case TC_ACT_TRAP: + return true; + } + + if (!TC_ACT_EXT_CMP(return_code, TC_ACT_GOTO_CHAIN) || + !TC_ACT_EXT_CMP(return_code, TC_ACT_JUMP)) + return true; + + return false; +} + +static int validate_ret_operand(struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + const u32 return_code = kopnd->immedv; + + if (!check_gact_return(return_code)) { + NL_SET_ERR_MSG_FMT_MOD(extack, "Unknown gact return code %u\n", + return_code); + return -EINVAL; + } + + return 0; +} + +static int validate_operand(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + int err = 0; + + if (!kopnd) + return err; + + switch (kopnd->oper_type) { + case P4TC_OPER_CONST: + if (kopnd->oper_flags & DATA_IS_IMMEDIATE) + err = validate_immediate_operand(kopnd, extack); + else + err = validate_large_operand(kopnd, extack); + kopnd->oper_flags |= DATA_IS_READ_ONLY; + break; + case P4TC_OPER_META: + err = __validate_metadata_operand(net, act, kopnd, extack); + break; + case P4TC_OPER_ACTID: + err = 0; + break; + case P4TC_OPER_TBL: + err = validate_table_operand(act, kopnd, extack); + break; + case P4TC_OPER_KEY: + err = validate_key_operand(act, kopnd, extack); + break; + case P4TC_OPER_RES: + err = validate_res_operand(kopnd, extack); + break; + case P4TC_OPER_HDRFIELD: + err = validate_hdrfield_operand(act, kopnd, extack); + break; + case P4TC_OPER_PARAM: + err = validate_param_operand(act, kopnd, extack); + break; + case P4TC_OPER_DEV: + err = validate_dev_operand(net, kopnd, extack); + break; + case P4TC_OPER_REG: + err = validate_reg_operand(act, kopnd, extack); + break; + case P4TC_OPER_LABEL: + break; + case P4TC_OPER_RET: + err = validate_ret_operand(kopnd, extack); + break; + default: + NL_SET_ERR_MSG_MOD(extack, "Unknown operand type"); + err = -EINVAL; + } + + return err; +} + +static void __free_operand(struct p4tc_cmd_operand *op) +{ + if (op->oper_mask_shift) + p4t_release(op->oper_mask_shift); + kfree(op->path_or_value); + kfree(op->path_or_value_extra); + kfree(op->print_prefix); + kfree(op); +} + +static void _free_operand_template(struct net *net, struct p4tc_cmd_operand *op) +{ + switch (op->oper_type) { + case P4TC_OPER_META: { + struct p4tc_pipeline *pipeline; + struct p4tc_metadata *meta; + + pipeline = tcf_pipeline_find_byid(net, op->pipeid); + if (pipeline) { + meta = tcf_meta_find_byid(pipeline, op->immedv); + if (meta) + tcf_meta_put_ref(meta); + } + break; + } + case P4TC_OPER_ACTID: { + struct p4tc_pipeline *pipeline; + struct p4tc_act *act; + + if (!(op->oper_flags & DATA_USES_ROOT_PIPE)) { + pipeline = tcf_pipeline_find_byid(net, op->pipeid); + if (pipeline) { + act = tcf_action_find_byid(pipeline, + op->immedv); + if (act) + tcf_action_put(act); + } + } + kfree(op->priv); + break; + } + case P4TC_OPER_TBL: { + struct p4tc_pipeline *pipeline; + struct p4tc_table *table; + + pipeline = tcf_pipeline_find_byid(net, op->pipeid); + if (pipeline) { + table = tcf_table_find_byid(pipeline, op->immedv); + if (table) + tcf_table_put_ref(table); + } + break; + } + case P4TC_OPER_KEY: { + struct p4tc_pipeline *pipeline; + struct p4tc_table *table; + + pipeline = tcf_pipeline_find_byid(net, op->pipeid); + if (pipeline) { + table = tcf_table_find_byid(pipeline, op->immedv); + if (table) + tcf_table_put_ref(table); + } + break; + } + case P4TC_OPER_HDRFIELD: { + struct p4tc_pipeline *pipeline; + + pipeline = tcf_pipeline_find_byid(net, op->pipeid); + /* Should never be NULL */ + if (pipeline) { + struct p4tc_hdrfield *hdrfield; + struct p4tc_parser *parser; + + if (refcount_read(&pipeline->p_hdrs_used) > 1) + refcount_dec(&pipeline->p_hdrs_used); + + parser = tcf_parser_find_byid(pipeline, op->immedv); + if (parser) { + hdrfield = tcf_hdrfield_find_byid(parser, + op->immedv2); + + if (hdrfield) + if (refcount_read(&hdrfield->hdrfield_ref) > 1) + tcf_hdrfield_put_ref(hdrfield); + } + } + break; + } + case P4TC_OPER_DEV: { + struct p4tc_cmd_opnd_priv_dev *priv = op->priv; + + if (priv && priv->dev) + netdev_put(priv->dev, priv->tracker); + kfree(priv); + break; + } + case P4TC_OPER_REG: { + struct p4tc_pipeline *pipeline; + + pipeline = tcf_pipeline_find_byid(net, op->pipeid); + /* Should never be NULL */ + if (pipeline) { + struct p4tc_register *reg; + + reg = tcf_register_find_byid(pipeline, op->immedv); + if (reg) + tcf_register_put_ref(reg); + } + break; + } + } + + __free_operand(op); +} + +static void _free_operand_list_instance(struct list_head *operands_list) +{ + struct p4tc_cmd_operand *op, *tmp; + + list_for_each_entry_safe(op, tmp, operands_list, oper_list_node) { + list_del(&op->oper_list_node); + __free_operand(op); + } +} + +static void _free_operand_list_template(struct net *net, + struct list_head *operands_list) +{ + struct p4tc_cmd_operand *op, *tmp; + + list_for_each_entry_safe(op, tmp, operands_list, oper_list_node) { + list_del(&op->oper_list_node); + _free_operand_template(net, op); + } +} + +static void _free_operation(struct net *net, struct p4tc_cmd_operate *ope, + bool called_from_template, + struct netlink_ext_ack *extack) +{ + if (called_from_template) + _free_operand_list_template(net, &ope->operands_list); + else + _free_operand_list_instance(&ope->operands_list); + + kfree(ope->cmd_label); + kfree(ope->label1); + kfree(ope->label2); + kfree(ope); +} + +/* XXX: copied from act_api::tcf_free_cookie_rcu - at some point share the code */ +static void _tcf_free_cookie_rcu(struct rcu_head *p) +{ + struct tc_cookie *cookie = container_of(p, struct tc_cookie, rcu); + + kfree(cookie->data); + kfree(cookie); +} + +/* XXX: copied from act_api::tcf_set_action_cookie - at some point share the code */ +static void _tcf_set_action_cookie(struct tc_cookie __rcu **old_cookie, + struct tc_cookie *new_cookie) +{ + struct tc_cookie *old; + + old = xchg((__force struct tc_cookie **)old_cookie, new_cookie); + if (old) + call_rcu(&old->rcu, _tcf_free_cookie_rcu); +} + +/* XXX: copied from act_api::free_tcf - at some point share the code */ +static void _free_tcf(struct tc_action *p) +{ + struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1); + + free_percpu(p->cpu_bstats); + free_percpu(p->cpu_bstats_hw); + free_percpu(p->cpu_qstats); + + _tcf_set_action_cookie(&p->user_cookie, NULL); + if (chain) + tcf_chain_put_by_act(chain); + + kfree(p); +} + +#define P4TC_CMD_OPER_ACT_RUNTIME (BIT(0)) + +static void free_op_ACT(struct net *net, struct p4tc_cmd_operate *ope, + bool dec_act_refs, struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A; + struct tc_action *p = NULL; + + A = GET_OPA(&ope->operands_list); + if (A) + p = A->action; + + if (p) { + if (dec_act_refs) { + struct tcf_idrinfo *idrinfo = p->idrinfo; + + atomic_dec(&p->tcfa_bindcnt); + + if (refcount_dec_and_mutex_lock(&p->tcfa_refcnt, + &idrinfo->lock)) { + idr_remove(&idrinfo->action_idr, p->tcfa_index); + mutex_unlock(&idrinfo->lock); + + if (p->ops->cleanup) + p->ops->cleanup(p); + + gen_kill_estimator(&p->tcfa_rate_est); + _free_tcf(p); + } + } + } + + return _free_operation(net, ope, dec_act_refs, extack); +} + +static inline int opnd_is_assignable(struct p4tc_cmd_operand *kopnd) +{ + return !(kopnd->oper_flags & DATA_IS_READ_ONLY); +} + +static int validate_multiple_rvals(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, + const size_t max_operands, + const size_t max_size, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *cursor; + int rvalue_tot_sz = 0; + int i = 0; + int err; + + cursor = GET_OPA(&ope->operands_list); + list_for_each_entry_continue(cursor, &ope->operands_list, oper_list_node) { + struct p4tc_type *cursor_type; + + if (i == max_operands - 1) { + NL_SET_ERR_MSG_MOD(extack, + "Operands list exceeds maximum allowed value"); + return -EINVAL; + } + + switch (cursor->oper_type) { + case P4TC_OPER_KEY: + case P4TC_OPER_META: + case P4TC_OPER_CONST: + case P4TC_OPER_HDRFIELD: + case P4TC_OPER_PARAM: + break; + default: + NL_SET_ERR_MSG_MOD(extack, + "Rvalue operand must be key, metadata, const, hdrfield or param"); + return -EINVAL; + } + + err = validate_operand(net, act, ope, cursor, extack); + if (err < 0) + return err; + + cursor_type = cursor->oper_datatype; + if (!cursor_type->ops->host_read) { + NL_SET_ERR_MSG_MOD(extack, + "Rvalue operand's types must have host_read op"); + return -EINVAL; + } + + if (cursor_type->container_bitsz > max_size) { + NL_SET_ERR_MSG_MOD(extack, + "Rvalue operand's types must be <= 64 bits"); + return -EINVAL; + } + if (cursor->oper_bitsize % 8 != 0) { + NL_SET_ERR_MSG_MOD(extack, + "All Rvalues must have bitsize multiple of 8"); + return -EINVAL; + } + rvalue_tot_sz += cursor->oper_bitsize; + i++; + } + + if (i < 2) { + NL_SET_ERR_MSG_MOD(extack, + "Operation must have at least two operands"); + return -EINVAL; + } + + return rvalue_tot_sz; +} + +static int __validate_CONCAT(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, + const size_t max_operands, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A; + int err; + + A = GET_OPA(&ope->operands_list); + err = validate_operand(net, act, ope, A, extack); + if (err) /*a better NL_SET_ERR_MSG_MOD done by validate_operand() */ + return err; + + if (!opnd_is_assignable(A)) { + NL_SET_ERR_MSG_MOD(extack, + "Unable to store op result in read-only operand"); + return -EPERM; + } + + return validate_multiple_rvals(net, act, ope, max_operands, + P4T_MAX_BITSZ, extack); +} + +static int __validate_BINARITH(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, + const size_t max_operands, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A; + struct p4tc_type *A_type; + int err; + + A = GET_OPA(&ope->operands_list); + err = validate_operand(net, act, ope, A, extack); + if (err) /*a better NL_SET_ERR_MSG_MOD done by validate_operand() */ + return err > 0 ? -err : err; + + if (!opnd_is_assignable(A)) { + NL_SET_ERR_MSG_MOD(extack, + "Unable to store op result in read-only operand"); + return -EPERM; + } + + switch (A->oper_type) { + case P4TC_OPER_META: + case P4TC_OPER_HDRFIELD: + break; + default: + NL_SET_ERR_MSG_MOD(extack, + "Operand A must be metadata or hdrfield"); + return -EINVAL; + } + + A_type = A->oper_datatype; + if (!A_type->ops->host_write) { + NL_SET_ERR_MSG_MOD(extack, + "Operand A's type must have host_write op"); + return -EINVAL; + } + + if (A_type->container_bitsz > 64) { + NL_SET_ERR_MSG_MOD(extack, + "Operand A's container type must be <= 64 bits"); + return -EINVAL; + } + + return validate_multiple_rvals(net, act, ope, max_operands, 64, extack); +} + +static int validate_num_opnds(struct p4tc_cmd_operate *ope, u32 cmd_num_opnds) +{ + if (ope->num_opnds != cmd_num_opnds) + return -EINVAL; + + return 0; +} + +static struct p4tc_act_param *validate_act_param(struct p4tc_act *act, + struct p4tc_cmd_operand *op, + unsigned long *param_id, + struct netlink_ext_ack *extack) +{ + struct p4tc_act_param *nparam; + struct p4tc_act_param *param; + + param = idr_get_next_ul(&act->params_idr, param_id); + if (!param) { + NL_SET_ERR_MSG_MOD(extack, + "Act has less runtime parameters than passed in call"); + return ERR_PTR(-EINVAL); + } + + if (op->oper_datatype->typeid != param->type->typeid) { + NL_SET_ERR_MSG_MOD(extack, "Operand type differs from params"); + return ERR_PTR(-EINVAL); + } + nparam = kzalloc(sizeof(*nparam), GFP_KERNEL); + if (!nparam) + return ERR_PTR(-ENOMEM); + strscpy(nparam->name, param->name, ACTPARAMNAMSIZ); + nparam->id = *param_id; + nparam->value = op; + nparam->type = param->type; + nparam->flags |= P4TC_ACT_PARAM_FLAGS_ISDYN; + + return nparam; +} + +static int validate_act_params(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, + struct p4tc_cmd_operand *A, + struct list_head *params_lst, + struct netlink_ext_ack *extack) +{ + struct p4tc_act_param *params[P4TC_MSGBATCH_SIZE] = { NULL }; + unsigned long param_id = 0; + int i = 0; + struct p4tc_cmd_operand *kopnd; + int err; + + kopnd = A; + list_for_each_entry_continue(kopnd, &ope->operands_list, oper_list_node) { + struct p4tc_act_param *nparam; + + err = validate_operand(net, act, ope, kopnd, extack); + if (err) + goto free_params; + + nparam = validate_act_param(act, kopnd, ¶m_id, extack); + if (IS_ERR(nparam)) { + err = PTR_ERR(nparam); + goto free_params; + } + + params[i] = nparam; + list_add_tail(&nparam->head, params_lst); + i++; + param_id++; + } + + if (idr_get_next_ul(&act->params_idr, ¶m_id)) { + NL_SET_ERR_MSG_MOD(extack, + "Act has more runtime params than passed in call"); + err = -EINVAL; + goto free_params; + } + + return 0; + +free_params: + while (i--) + kfree(params[i]); + + return err; +} + +static void free_intermediate_params_list(struct list_head *params_list) +{ + struct p4tc_act_param *nparam, *p; + + list_for_each_entry_safe(nparam, p, params_list, head) + kfree(nparam); +} + +/* Actions with runtime parameters don't have instance ids (found in immedv2) + * because the action is not created apriori. Example: + * cmd act myprog.myact param1 param2 ... doesn't specify instance. + * As noted, it is equivalent to treating an action like a function call with + * action attributes derived at runtime.If these actions were already + * instantiated then immedv2 will have a non-zero value equal to the action index. + */ +static int check_runtime_params(struct p4tc_cmd_operate *ope, + struct p4tc_cmd_operand *A, + bool *is_runtime_act, + struct netlink_ext_ack *extack) +{ + if (A->immedv2 && ope->num_opnds > 1) { + NL_SET_ERR_MSG_MOD(extack, + "Can't specify runtime params together with instance id"); + return -EINVAL; + } + + if (A->oper_flags & DATA_USES_ROOT_PIPE && !A->immedv2) { + NL_SET_ERR_MSG_MOD(extack, + "Must specify instance id for kernel act calls"); + return -EINVAL; + } + + *is_runtime_act = !A->immedv2; + + return 0; +} + +/* Syntax: act ACTION_ID ACTION_INDEX | act ACTION_ID/ACTION_NAME PARAMS + * Operation: The tc action instance of kind ID ACTION_ID and optional index ACTION_INDEX + * is executed. + */ +static int validate_ACT(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct tc_action_ops *action_ops; + struct list_head params_list; + struct p4tc_cmd_operand *A; + struct tc_action *action; + bool is_runtime_act; + int err; + + INIT_LIST_HEAD(¶ms_list); + + A = GET_OPA(&ope->operands_list); + err = validate_operand(net, act, ope, A, extack); + if (err < 0) + return err; + + if (A->oper_type != P4TC_OPER_ACTID) { + NL_SET_ERR_MSG_MOD(extack, "ACT: Operand type MUST be P4TC_OPER_ACTID\n"); + return -EINVAL; + } + + err = check_runtime_params(ope, A, &is_runtime_act, extack); + if (err < 0) + return err; + + A->oper_datatype = p4type_find_byid(P4T_U32); + + if (A->oper_flags & DATA_USES_ROOT_PIPE) { + action_ops = tc_lookup_action_byid(net, A->immedv); + if (!action_ops) { + NL_SET_ERR_MSG_MOD(extack, "ACT: unknown Action Kind"); + return -EINVAL; + } + A->pipeid = 0; + } else { + struct p4tc_pipeline *pipeline = act->pipeline; + struct p4tc_act_dep_edge_node *edge_node; + struct p4tc_act *callee_act; + bool has_back_edge; + + /* lets check if we have cycles where we are calling an + * action that might end calling us + */ + callee_act = tcf_action_get(pipeline, + (const char *)A->path_or_value, + A->immedv, extack); + if (IS_ERR(callee_act)) + return PTR_ERR(callee_act); + + A->pipeid = act->pipeline->common.p_id; + A->immedv = callee_act->a_id; + + edge_node = kzalloc(sizeof(*edge_node), GFP_KERNEL); + if (!edge_node) { + err = -ENOMEM; + goto free_params_list; + } + edge_node->act_id = act->a_id; + + has_back_edge = tcf_pipeline_check_act_backedge(pipeline, + edge_node, + callee_act->a_id); + if (has_back_edge) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "Call creates a back edge: %s -> %s", + act->common.name, + callee_act->common.name); + err = -EINVAL; + kfree(edge_node); + goto free_params_list; + } + + A->priv = edge_node; + if (is_runtime_act) { + u32 flags = TCA_ACT_FLAGS_BIND; + struct tc_act_dyna parm = { 0 }; + + err = validate_act_params(net, callee_act, ope, A, + ¶ms_list, extack); + if (err < 0) + return err; + + parm.action = TC_ACT_PIPE; + err = tcf_p4_dyna_template_init(net, &action, + callee_act, + ¶ms_list, &parm, + flags, extack); + if (err < 0) + goto free_params_list; + + ope->op_flags |= P4TC_CMD_OPER_ACT_RUNTIME; + } + + action_ops = &callee_act->ops; + } + + if (!is_runtime_act) { + if (__tcf_idr_search(net, action_ops, &action, A->immedv2) == false) { + NL_SET_ERR_MSG_MOD(extack, "ACT: unknown Action index\n"); + module_put(action_ops->owner); + err = -EINVAL; + goto free_params_list; + } + + atomic_inc(&action->tcfa_bindcnt); + } + + A->immedv2 = action->tcfa_index; + A->action = action; + + return 0; + +free_params_list: + free_intermediate_params_list(¶ms_list); + return err; +} + +/* Syntax: set A B + * Operation: B is written to A. + * A could header, or metadata or key + * B could be a constant, header, or metadata + * Restriction: A and B dont have to be of the same size and type + * as long as B's value could be less bits than A + * (example a U16 setting into a U32, etc) + */ +static int validate_SET(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A, *B; + struct p4tc_type *A_type; + struct p4tc_type *B_type; + int err = 0; + + err = validate_num_opnds(ope, cmd_num_opnds); + if (err < 0) { + NL_SET_ERR_MSG_MOD(extack, "SET must have only 2 operands"); + return err; + } + + A = GET_OPA(&ope->operands_list); + err = validate_operand(net, act, ope, A, extack); + if (err) /*a better NL_SET_ERR_MSG_MOD done by validate_operand() */ + return err; + + if (!opnd_is_assignable(A)) { + NL_SET_ERR_MSG_MOD(extack, "Unable to set read-only operand"); + return -EPERM; + } + + B = GET_OPB(&ope->operands_list); + if (B->oper_type == P4TC_OPER_KEY) { + NL_SET_ERR_MSG_MOD(extack, "Operand B cannot be key\n"); + return -EINVAL; + } + + err = validate_operand(net, act, ope, B, extack); + if (err) + return err; + + A_type = A->oper_datatype; + B_type = B->oper_datatype; + if (A->oper_type == P4TC_OPER_KEY) { + A->oper_datatype = B_type; + A_type = B_type; + } + + if ((A_type->typeid == P4T_DEV && + B_type->typeid != P4T_DEV && B_type->typeid != P4T_U32) || + (A_type->typeid != P4T_DEV && A_type->typeid != P4T_U32 && + B_type->typeid == P4T_DEV)) { + NL_SET_ERR_MSG_MOD(extack, + "Can only set dev to other dev or bitX with 16 < X <= 32"); + return -EINVAL; + } + + if (!A_type->ops->host_read || !B_type->ops->host_read) { + NL_SET_ERR_MSG_MOD(extack, + "Types of A and B must have host_read op"); + return -EINVAL; + } + + if (!A_type->ops->host_write || !B_type->ops->host_write) { + NL_SET_ERR_MSG_MOD(extack, + "Types of A and B must have host_write op"); + return -EINVAL; + } + + if (A->oper_bitsize < B->oper_bitsize) { + NL_SET_ERR_MSG_MOD(extack, + "set: B.bitsize has to be <= A.bitsize\n"); + return -EINVAL; + } + + if (A->oper_bitsize != B->oper_bitsize) { + /* We allow them as long as the value of B can fit in A + * which has already been verified at this point + */ + u64 Amaxval; + u64 Bmaxval; + + /* Anything can be assigned to P4T_U128 */ + if (A->oper_datatype->typeid == P4T_U128) + return 0; + + Amaxval = GENMASK_ULL(A->oper_bitend, A->oper_bitstart); + + if (B->oper_type == P4TC_OPER_CONST) + Bmaxval = B->immedv; + else + Bmaxval = GENMASK_ULL(B->oper_bitend, B->oper_bitstart); + + if (Bmaxval > Amaxval) { + NL_SET_ERR_MSG_MOD(extack, + "set: B bits has to fit in A\n"); + return -EINVAL; + } + } + + return 0; +} + +static int validate_PRINT(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A; + int err; + + err = validate_num_opnds(ope, cmd_num_opnds); + if (err < 0) { + NL_SET_ERR_MSG_MOD(extack, "print must have only 1 operands"); + return err; + } + + A = GET_OPA(&ope->operands_list); + + if (A->oper_type == P4TC_OPER_CONST) { + NL_SET_ERR_MSG_MOD(extack, "Operand A cannot be constant\n"); + return -EINVAL; + } + + return validate_operand(net, act, ope, A, extack); +} + +static int validate_TBLAPP(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A; + int err; + + err = validate_num_opnds(ope, cmd_num_opnds); + if (err < 0) { + NL_SET_ERR_MSG_MOD(extack, + "tableapply must have only 1 operands"); + return err; + } + + A = GET_OPA(&ope->operands_list); + if (A->oper_type != P4TC_OPER_TBL) { + NL_SET_ERR_MSG_MOD(extack, "Operand A must be a table\n"); + return -EINVAL; + } + + err = validate_operand(net, act, ope, A, extack); + if (err) /*a better NL_SET_ERR_MSG_MOD done by validate_operand() */ + return err; + + return 0; +} + +static int validate_SNDPORTEGR(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A; + int err; + + err = validate_num_opnds(ope, cmd_num_opnds); + if (err < 0) { + NL_SET_ERR_MSG_MOD(extack, + "send_port_egress must have only 1 operands"); + return err; + } + + A = GET_OPA(&ope->operands_list); + + err = validate_operand(net, act, ope, A, extack); + if (err) /*a better NL_SET_ERR_MSG_MOD done by validate_operand() */ + return err; + + return 0; +} + +static int validate_BINARITH(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A, *B, *C; + struct p4tc_type *A_type; + struct p4tc_type *B_type; + struct p4tc_type *C_type; + int err; + + err = __validate_BINARITH(net, act, ope, cmd_num_opnds, extack); + if (err < 0) + return err; + + A = GET_OPA(&ope->operands_list); + B = GET_OPB(&ope->operands_list); + C = GET_OPC(&ope->operands_list); + + A_type = A->oper_datatype; + B_type = B->oper_datatype; + C_type = C->oper_datatype; + + /* For now, they must be the same. + * Will change that very soon. + */ + if (A_type != B_type || A_type != C_type) { + NL_SET_ERR_MSG_MOD(extack, + "Type of A, B and C must be the same"); + return -EINVAL; + } + + return 0; +} + +static int validate_CONCAT(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A; + int rvalue_tot_sz; + + A = GET_OPA(&ope->operands_list); + + rvalue_tot_sz = __validate_CONCAT(net, act, ope, cmd_num_opnds, extack); + if (rvalue_tot_sz < 0) + return rvalue_tot_sz; + + if (A->oper_bitsize < rvalue_tot_sz) { + NL_SET_ERR_MSG_MOD(extack, + "Rvalue operands concatenated must fit inside operand A"); + return -EINVAL; + } + + return 0; +} + +/* We'll validate jump to labels later once we have all labels processed */ +static int validate_JUMP(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A; + int err; + + err = validate_num_opnds(ope, cmd_num_opnds); + if (err < 0) { + NL_SET_ERR_MSG_MOD(extack, "jump must have only 1 operands"); + return err; + } + + A = GET_OPA(&ope->operands_list); + if (A->oper_type != P4TC_OPER_LABEL) { + NL_SET_ERR_MSG_MOD(extack, "Operand A must be a label\n"); + return -EINVAL; + } + + if (A->immedv) { + int jmp_num; + + jmp_num = A->immedv & TC_ACT_EXT_VAL_MASK; + + if (jmp_num <= 0) { + NL_SET_ERR_MSG_MOD(extack, + "Backward jumps are not allowed"); + return -EINVAL; + } + } + + A->oper_datatype = p4type_find_byid(P4T_U32); + + return 0; +} + +static int validate_LABEL(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + int err; + + err = validate_num_opnds(ope, cmd_num_opnds); + if (err < 0) { + NL_SET_ERR_MSG_MOD(extack, + "label command mustn't have operands"); + return err; + } + + return 0; +} + +static int validate_RET(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A; + int err; + + err = validate_num_opnds(ope, cmd_num_opnds); + if (err < 0) { + NL_SET_ERR_MSG_MOD(extack, "return must have only 1 operand"); + return err; + } + + A = GET_OPA(&ope->operands_list); + if (A->oper_type != P4TC_OPER_RET) { + NL_SET_ERR_MSG_MOD(extack, "Operand A must be a return code"); + return -EINVAL; + } + + err = validate_operand(net, act, ope, A, extack); + if (err) + return err; + + return 0; +} + +static void p4tc_reg_lock(struct p4tc_cmd_operand *A, + struct p4tc_cmd_operand *B, + struct p4tc_cmd_operand *C) +{ + struct p4tc_register *reg_A, *reg_B, *reg_C; + + if (A->oper_type == P4TC_OPER_REG) { + reg_A = A->priv; + spin_lock_bh(®_A->reg_value_lock); + } + + if (B && B->oper_type == P4TC_OPER_REG) { + reg_B = B->priv; + spin_lock_bh(®_B->reg_value_lock); + } + + if (C && C->oper_type == P4TC_OPER_REG) { + reg_C = C->priv; + spin_lock_bh(®_C->reg_value_lock); + } +} + +static void p4tc_reg_unlock(struct p4tc_cmd_operand *A, + struct p4tc_cmd_operand *B, + struct p4tc_cmd_operand *C) +{ + struct p4tc_register *reg_A, *reg_B, *reg_C; + + if (C && C->oper_type == P4TC_OPER_REG) { + reg_C = C->priv; + spin_unlock_bh(®_C->reg_value_lock); + } + + if (B && B->oper_type == P4TC_OPER_REG) { + reg_B = B->priv; + spin_unlock_bh(®_B->reg_value_lock); + } + + if (A->oper_type == P4TC_OPER_REG) { + reg_A = A->priv; + spin_unlock_bh(®_A->reg_value_lock); + } +} + +static int p4tc_cmp_op(struct p4tc_cmd_operand *A, struct p4tc_cmd_operand *B, + void *A_val, void *B_val) +{ + int res; + + p4tc_reg_lock(A, B, NULL); + + res = p4t_cmp(A->oper_mask_shift, A->oper_datatype, A_val, + B->oper_mask_shift, B->oper_datatype, B_val); + + p4tc_reg_unlock(A, B, NULL); + + return res; +} + +static int p4tc_copy_op(struct p4tc_cmd_operand *A, struct p4tc_cmd_operand *B, + void *A_val, void *B_val) +{ + int res; + + p4tc_reg_lock(A, B, NULL); + + res = p4t_copy(A->oper_mask_shift, A->oper_datatype, A_val, + B->oper_mask_shift, B->oper_datatype, B_val); + + p4tc_reg_unlock(A, B, NULL); + + return res; +} + +/* Syntax: BRANCHOP A B + * BRANCHOP := BEQ, BNEQ, etc + * Operation: B's value is compared to A's value. + * XXX: In the future we will take expressions instead of values + * A could a constant, header, or metadata or key + * B could be a constant, header, metadata, or key + * Restriction: A and B cannot both be constants + */ + +/* if A == B else */ +static int p4tc_cmd_BEQ(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A, *B; + int res_cmp; + void *B_val; + void *A_val; + + A = GET_OPA(&op->operands_list); + B = GET_OPB(&op->operands_list); + + A_val = __p4tc_fetch(skb, A, cmd, res); + B_val = __p4tc_fetch(skb, B, cmd, res); + + if (!A_val || !B_val) + return TC_ACT_OK; + + res_cmp = p4tc_cmp_op(A, B, A_val, B_val); + if (!res_cmp) + return op->ctl1; + + return op->ctl2; +} + +/* if A != B else */ +static int p4tc_cmd_BNE(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A, *B; + int res_cmp; + void *B_val; + void *A_val; + + A = GET_OPA(&op->operands_list); + B = GET_OPB(&op->operands_list); + + A_val = __p4tc_fetch(skb, A, cmd, res); + B_val = __p4tc_fetch(skb, B, cmd, res); + + if (!A_val || !B_val) + return TC_ACT_OK; + + res_cmp = p4tc_cmp_op(A, B, A_val, B_val); + if (res_cmp) + return op->ctl1; + + return op->ctl2; +} + +/* if A < B else */ +static int p4tc_cmd_BLT(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A, *B; + int res_cmp; + void *B_val; + void *A_val; + + A = GET_OPA(&op->operands_list); + B = GET_OPB(&op->operands_list); + + A_val = __p4tc_fetch(skb, A, cmd, res); + B_val = __p4tc_fetch(skb, B, cmd, res); + + if (!A_val || !B_val) + return TC_ACT_OK; + + res_cmp = p4tc_cmp_op(A, B, A_val, B_val); + if (res_cmp < 0) + return op->ctl1; + + return op->ctl2; +} + +/* if A <= B else */ +static int p4tc_cmd_BLE(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A, *B; + int res_cmp; + void *B_val; + void *A_val; + + A = GET_OPA(&op->operands_list); + B = GET_OPB(&op->operands_list); + + A_val = __p4tc_fetch(skb, A, cmd, res); + B_val = __p4tc_fetch(skb, B, cmd, res); + + if (!A_val || !B_val) + return TC_ACT_OK; + + res_cmp = p4tc_cmp_op(A, B, A_val, B_val); + if (!res_cmp || res_cmp < 0) + return op->ctl1; + + return op->ctl2; +} + +/* if A > B else */ +static int p4tc_cmd_BGT(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A, *B; + int res_cmp; + void *B_val; + void *A_val; + + A = GET_OPA(&op->operands_list); + B = GET_OPB(&op->operands_list); + + A_val = __p4tc_fetch(skb, A, cmd, res); + B_val = __p4tc_fetch(skb, B, cmd, res); + + if (!A_val || !B_val) + return TC_ACT_OK; + + res_cmp = p4tc_cmp_op(A, B, A_val, B_val); + if (res_cmp > 0) + return op->ctl1; + + return op->ctl2; +} + +/* if A >= B else */ +static int p4tc_cmd_BGE(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A, *B; + int res_cmp; + void *B_val; + void *A_val; + + A = GET_OPA(&op->operands_list); + B = GET_OPB(&op->operands_list); + + A_val = __p4tc_fetch(skb, A, cmd, res); + B_val = __p4tc_fetch(skb, B, cmd, res); + + if (!A_val || !B_val) + return TC_ACT_OK; + + res_cmp = p4tc_cmp_op(A, B, A_val, B_val); + if (!res_cmp || res_cmp > 0) + return op->ctl1; + + return op->ctl2; +} + +static int validate_BRN(struct net *net, struct p4tc_act *act, + struct p4tc_cmd_operate *ope, u32 cmd_num_opnds, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operand *A, *B; + int err = 0; + + if (validate_num_opnds(ope, cmd_num_opnds) < 0) { + NL_SET_ERR_MSG_MOD(extack, + "Branch: branch must have only 2 operands"); + return -EINVAL; + } + + A = GET_OPA(&ope->operands_list); + B = GET_OPB(&ope->operands_list); + + err = validate_operand(net, act, ope, A, extack); + if (err) + return err; + + err = validate_operand(net, act, ope, B, extack); + if (err) + return err; + + if (A->oper_type == P4TC_OPER_CONST && + B->oper_type == P4TC_OPER_CONST) { + NL_SET_ERR_MSG_MOD(extack, + "Branch: A and B can't both be constant\n"); + return -EINVAL; + } + + if (!p4tc_type_unsigned(A->oper_datatype->typeid) || + !p4tc_type_unsigned(B->oper_datatype->typeid)) { + NL_SET_ERR_MSG_MOD(extack, + "Operands A and B must be unsigned\n"); + return -EINVAL; + } + + return 0; +} + +static void generic_free_op(struct net *net, struct p4tc_cmd_operate *ope, + bool called_from_template, + struct netlink_ext_ack *extack) +{ + return _free_operation(net, ope, called_from_template, extack); +} + +static struct p4tc_cmd_s cmds[] = { + { P4TC_CMD_OP_SET, 2, validate_SET, generic_free_op, p4tc_cmd_SET }, + { P4TC_CMD_OP_ACT, 1, validate_ACT, free_op_ACT, p4tc_cmd_ACT }, + { P4TC_CMD_OP_BEQ, 2, validate_BRN, generic_free_op, p4tc_cmd_BEQ }, + { P4TC_CMD_OP_BNE, 2, validate_BRN, generic_free_op, p4tc_cmd_BNE }, + { P4TC_CMD_OP_BGT, 2, validate_BRN, generic_free_op, p4tc_cmd_BGT }, + { P4TC_CMD_OP_BLT, 2, validate_BRN, generic_free_op, p4tc_cmd_BLT }, + { P4TC_CMD_OP_BGE, 2, validate_BRN, generic_free_op, p4tc_cmd_BGE }, + { P4TC_CMD_OP_BLE, 2, validate_BRN, generic_free_op, p4tc_cmd_BLE }, + { P4TC_CMD_OP_PRINT, 1, validate_PRINT, generic_free_op, + p4tc_cmd_PRINT }, + { P4TC_CMD_OP_TBLAPP, 1, validate_TBLAPP, generic_free_op, + p4tc_cmd_TBLAPP }, + { P4TC_CMD_OP_SNDPORTEGR, 1, validate_SNDPORTEGR, generic_free_op, + p4tc_cmd_SNDPORTEGR }, + { P4TC_CMD_OP_MIRPORTEGR, 1, validate_SNDPORTEGR, generic_free_op, + p4tc_cmd_MIRPORTEGR }, + { P4TC_CMD_OP_PLUS, 3, validate_BINARITH, generic_free_op, + p4tc_cmd_PLUS }, + { P4TC_CMD_OP_SUB, 3, validate_BINARITH, generic_free_op, + p4tc_cmd_SUB }, + { P4TC_CMD_OP_CONCAT, P4TC_CMD_OPERS_MAX, validate_CONCAT, + generic_free_op, p4tc_cmd_CONCAT }, + { P4TC_CMD_OP_BAND, 3, validate_BINARITH, generic_free_op, + p4tc_cmd_BAND }, + { P4TC_CMD_OP_BOR, 3, validate_BINARITH, generic_free_op, + p4tc_cmd_BOR }, + { P4TC_CMD_OP_BXOR, 3, validate_BINARITH, generic_free_op, + p4tc_cmd_BXOR }, + { P4TC_CMD_OP_JUMP, 1, validate_JUMP, generic_free_op, p4tc_cmd_JUMP }, + { P4TC_CMD_OP_LABEL, 0, validate_LABEL, generic_free_op, NULL }, + { P4TC_CMD_OP_RET, 1, validate_RET, generic_free_op, p4tc_cmd_RET }, +}; + +static struct p4tc_cmd_s *p4tc_get_cmd_byid(u16 cmdid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cmds); i++) { + if (cmdid == cmds[i].cmdid) + return &cmds[i]; + } + + return NULL; +} + +/* Operands */ +static const struct nla_policy p4tc_cmd_policy_oper[P4TC_CMD_OPND_MAX + 1] = { + [P4TC_CMD_OPND_INFO] = { .type = NLA_BINARY, + .len = sizeof(struct p4tc_u_operand) }, + [P4TC_CMD_OPND_PATH] = { .type = NLA_STRING, .len = TEMPLATENAMSZ }, + [P4TC_CMD_OPND_PATH_EXTRA] = { .type = NLA_STRING, .len = TEMPLATENAMSZ }, + [P4TC_CMD_OPND_LARGE_CONSTANT] = { + .type = NLA_BINARY, + .len = BITS_TO_BYTES(P4T_MAX_BITSZ), + }, + [P4TC_CMD_OPND_PREFIX] = { .type = NLA_STRING, .len = TEMPLATENAMSZ }, +}; + +/* XXX: P4TC_CMD_POLICY is used to disable overwriting extacks downstream + * Could we use error pointers instead of this P4TC_CMD_POLICY trickery? + */ +#define P4TC_CMD_POLICY 12345 +static int p4tc_cmds_process_opnd(struct nlattr *nla, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + int oper_extra_sz = 0; + int oper_prefix_sz = 0; + u32 wantbits = 0; + int oper_sz = 0; + int err = 0; + struct nlattr *tb[P4TC_CMD_OPND_MAX + 1]; + struct p4tc_u_operand *uopnd; + + err = nla_parse_nested(tb, P4TC_CMD_OPND_MAX, nla, p4tc_cmd_policy_oper, + extack); + if (err < 0) { + NL_SET_ERR_MSG_MOD(extack, "parse error: P4TC_CMD_OPND_\n"); + return -EINVAL; + } + + if (!tb[P4TC_CMD_OPND_INFO]) { + NL_SET_ERR_MSG_MOD(extack, "operand information is mandatory"); + return -EINVAL; + } + + uopnd = nla_data(tb[P4TC_CMD_OPND_INFO]); + + if (uopnd->oper_type == P4TC_OPER_META) { + kopnd->fetch = p4tc_fetch_metadata; + } else if (uopnd->oper_type == P4TC_OPER_CONST) { + kopnd->fetch = p4tc_fetch_constant; + } else if (uopnd->oper_type == P4TC_OPER_ACTID) { + kopnd->fetch = NULL; + } else if (uopnd->oper_type == P4TC_OPER_TBL) { + kopnd->fetch = p4tc_fetch_table; + } else if (uopnd->oper_type == P4TC_OPER_KEY) { + kopnd->fetch = p4tc_fetch_key; + } else if (uopnd->oper_type == P4TC_OPER_RES) { + kopnd->fetch = p4tc_fetch_result; + } else if (uopnd->oper_type == P4TC_OPER_HDRFIELD) { + kopnd->fetch = p4tc_fetch_hdrfield; + } else if (uopnd->oper_type == P4TC_OPER_PARAM) { + kopnd->fetch = p4tc_fetch_param; + } else if (uopnd->oper_type == P4TC_OPER_DEV) { + kopnd->fetch = p4tc_fetch_dev; + } else if (uopnd->oper_type == P4TC_OPER_REG) { + kopnd->fetch = p4tc_fetch_reg; + } else if (uopnd->oper_type == P4TC_OPER_LABEL || + uopnd->oper_type == P4TC_OPER_RET) { + kopnd->fetch = NULL; + } else { + NL_SET_ERR_MSG_MOD(extack, "Unknown operand type"); + return -EINVAL; + } + + wantbits = 1 + uopnd->oper_endbit - uopnd->oper_startbit; + if (uopnd->oper_flags & DATA_HAS_TYPE_INFO && + uopnd->oper_type != P4TC_OPER_ACTID && + uopnd->oper_type != P4TC_OPER_TBL && + uopnd->oper_type != P4TC_OPER_REG && + uopnd->oper_cbitsize < wantbits) { + NL_SET_ERR_MSG_MOD(extack, + "Start and end bit dont fit in space"); + return -EINVAL; + } + + err = copy_u2k_operand(uopnd, kopnd, extack); + if (err < 0) + return err; + + if (tb[P4TC_CMD_OPND_LARGE_CONSTANT]) { + int const_sz; + + const_sz = nla_len(tb[P4TC_CMD_OPND_LARGE_CONSTANT]); + if (const_sz) + memcpy(kopnd->immedv_large, + nla_data(tb[P4TC_CMD_OPND_LARGE_CONSTANT]), + const_sz); + else + kopnd->oper_flags |= DATA_IS_IMMEDIATE; + + kopnd->immedv_large_sz = const_sz; + } + + if (tb[P4TC_CMD_OPND_PATH]) + oper_sz = nla_len(tb[P4TC_CMD_OPND_PATH]); + + kopnd->path_or_value_sz = oper_sz; + + if (oper_sz) { + kopnd->path_or_value = kzalloc(oper_sz, GFP_KERNEL); + if (!kopnd->path_or_value) { + NL_SET_ERR_MSG_MOD(extack, + "Failed to alloc operand path data"); + return -ENOMEM; + } + + nla_memcpy(kopnd->path_or_value, tb[P4TC_CMD_OPND_PATH], + oper_sz); + } + + if (tb[P4TC_CMD_OPND_PATH_EXTRA]) + oper_extra_sz = nla_len(tb[P4TC_CMD_OPND_PATH_EXTRA]); + + kopnd->path_or_value_extra_sz = oper_extra_sz; + + if (oper_extra_sz) { + kopnd->path_or_value_extra = kzalloc(oper_extra_sz, GFP_KERNEL); + if (!kopnd->path_or_value_extra) { + kfree(kopnd->path_or_value); + NL_SET_ERR_MSG_MOD(extack, + "Failed to alloc extra operand path data"); + return -ENOMEM; + } + + nla_memcpy(kopnd->path_or_value_extra, + tb[P4TC_CMD_OPND_PATH_EXTRA], oper_extra_sz); + } + + if (tb[P4TC_CMD_OPND_PREFIX]) + oper_prefix_sz = nla_len(tb[P4TC_CMD_OPND_PREFIX]); + + if (!oper_prefix_sz) + return 0; + + kopnd->print_prefix_sz = oper_prefix_sz; + + kopnd->print_prefix = kzalloc(oper_prefix_sz, GFP_KERNEL); + if (!kopnd->print_prefix) { + kfree(kopnd->path_or_value); + kfree(kopnd->path_or_value_extra); + NL_SET_ERR_MSG_MOD(extack, + "Failed to alloc operand print prefix"); + return -ENOMEM; + } + + nla_memcpy(kopnd->print_prefix, tb[P4TC_CMD_OPND_PREFIX], + oper_prefix_sz); + return 0; +} + +/* Operation */ +static const struct nla_policy cmd_ops_policy[P4TC_CMD_OPER_MAX + 1] = { + [P4TC_CMD_OPERATION] = { .type = NLA_BINARY, + .len = sizeof(struct p4tc_u_operate) }, + [P4TC_CMD_OPER_LIST] = { .type = NLA_NESTED }, + [P4TC_CMD_OPER_LABEL1] = { .type = NLA_STRING, .len = LABELNAMSIZ }, + [P4TC_CMD_OPER_LABEL2] = { .type = NLA_STRING, .len = LABELNAMSIZ }, + [P4TC_CMD_OPER_CMD_LABEL] = { .type = NLA_STRING, .len = LABELNAMSIZ }, +}; + +static struct p4tc_cmd_operate *uope_to_kope(struct p4tc_u_operate *uope) +{ + struct p4tc_cmd_operate *ope; + + if (!uope) + return NULL; + + ope = kzalloc(sizeof(*ope), GFP_KERNEL); + if (!ope) + return NULL; + + ope->op_id = uope->op_type; + ope->op_flags = uope->op_flags; + ope->op_cnt = 0; + + ope->ctl1 = uope->op_ctl1; + ope->ctl2 = uope->op_ctl2; + + INIT_LIST_HEAD(&ope->operands_list); + + return ope; +} + +static int p4tc_cmd_process_operands_list(struct nlattr *nla, + struct p4tc_cmd_operate *ope, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[P4TC_CMD_OPERS_MAX + 1]; + struct p4tc_cmd_operand *opnd; + int err; + int i; + + err = nla_parse_nested(tb, P4TC_CMD_OPERS_MAX, nla, NULL, NULL); + if (err < 0) + return err; + + for (i = 1; i < P4TC_CMD_OPERS_MAX + 1 && tb[i]; i++) { + opnd = kzalloc(sizeof(*opnd), GFP_KERNEL); + if (!opnd) + return -ENOMEM; + err = p4tc_cmds_process_opnd(tb[i], opnd, extack); + /* Will add to list because p4tc_cmd_process_opnd may have + * allocated memory inside opnd even in case of failure, + * and this memory must be freed + */ + list_add_tail(&opnd->oper_list_node, &ope->operands_list); + if (err < 0) + return P4TC_CMD_POLICY; + ope->num_opnds++; + } + + return 0; +} + +static int p4tc_cmd_process_ops(struct net *net, struct p4tc_act *act, + struct nlattr *nla, + struct p4tc_cmd_operate **op_entry, + int cmd_offset, struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operate *ope = NULL; + int err = 0; + struct nlattr *tb[P4TC_CMD_OPER_MAX + 1]; + struct p4tc_cmd_s *cmd_t; + + err = nla_parse_nested(tb, P4TC_CMD_OPER_MAX, nla, cmd_ops_policy, + extack); + if (err < 0) { + NL_SET_ERR_MSG_MOD(extack, "parse error: P4TC_CMD_OPER_\n"); + return P4TC_CMD_POLICY; + } + + ope = uope_to_kope(nla_data(tb[P4TC_CMD_OPERATION])); + if (!ope) + return -ENOMEM; + + ope->cmd_offset = cmd_offset; + + cmd_t = p4tc_get_cmd_byid(ope->op_id); + if (!cmd_t) { + NL_SET_ERR_MSG_MOD(extack, "Unknown operation ID\n"); + kfree(ope); + return -EINVAL; + } + + if (tb[P4TC_CMD_OPER_LABEL1]) { + const char *label1 = nla_data(tb[P4TC_CMD_OPER_LABEL1]); + const u32 label1_sz = nla_len(tb[P4TC_CMD_OPER_LABEL1]); + + ope->label1 = kzalloc(label1_sz, GFP_KERNEL); + if (!ope->label1) + return P4TC_CMD_POLICY; + + strscpy(ope->label1, label1, label1_sz); + } + + if (tb[P4TC_CMD_OPER_LABEL2]) { + const char *label2 = nla_data(tb[P4TC_CMD_OPER_LABEL2]); + const u32 label2_sz = nla_len(tb[P4TC_CMD_OPER_LABEL2]); + + ope->label2 = kzalloc(label2_sz, GFP_KERNEL); + if (!ope->label2) + return P4TC_CMD_POLICY; + + strscpy(ope->label2, label2, label2_sz); + } + + if (tb[P4TC_CMD_OPER_CMD_LABEL]) { + const char *cmd_label = nla_data(tb[P4TC_CMD_OPER_CMD_LABEL]); + const u32 cmd_label_sz = nla_len(tb[P4TC_CMD_OPER_CMD_LABEL]); + + ope->cmd_label = kzalloc(cmd_label_sz, GFP_KERNEL); + if (!ope->cmd_label) + return P4TC_CMD_POLICY; + + err = register_label(act, cmd_label, ope->cmd_offset, extack); + if (err < 0) + return P4TC_CMD_POLICY; + strscpy(ope->cmd_label, cmd_label, cmd_label_sz); + } + + if (tb[P4TC_CMD_OPER_LIST]) { + err = p4tc_cmd_process_operands_list(tb[P4TC_CMD_OPER_LIST], + ope, extack); + if (err) { + err = P4TC_CMD_POLICY; + goto set_results; + } + } + + err = cmd_t->validate_operands(net, act, ope, cmd_t->num_opnds, extack); + if (err) { + //XXX: think about getting rid of this P4TC_CMD_POLICY + err = P4TC_CMD_POLICY; + goto set_results; + } + +set_results: + ope->cmd = cmd_t; + *op_entry = ope; + + return err; +} + +static inline int cmd_is_branch(u32 cmdid) +{ + if (cmdid == P4TC_CMD_OP_BEQ || cmdid == P4TC_CMD_OP_BNE || + cmdid == P4TC_CMD_OP_BLT || cmdid == P4TC_CMD_OP_BLE || + cmdid == P4TC_CMD_OP_BGT || cmdid == P4TC_CMD_OP_BGE) + return 1; + + return 0; +} + +static int cmd_jump_operand_validate(struct p4tc_act *act, + struct p4tc_cmd_operate *ope, + struct p4tc_cmd_operand *kopnd, int cmdcnt, + struct netlink_ext_ack *extack) +{ + int jmp_cnt, cmd_offset; + + cmd_offset = cmd_find_label_offset(act, + (const char *)kopnd->path_or_value, + extack); + if (cmd_offset < 0) + return cmd_offset; + + if (cmd_offset >= cmdcnt) { + NL_SET_ERR_MSG(extack, "Jump excessive branch"); + return -EINVAL; + } + + jmp_cnt = cmd_offset - ope->cmd_offset - 1; + if (jmp_cnt <= 0) { + NL_SET_ERR_MSG_MOD(extack, "Backward jumps are not allowed"); + return -EINVAL; + } + + kopnd->immedv = TC_ACT_JUMP | jmp_cnt; + + return 0; +} + +static int cmd_brn_validate(struct p4tc_act *act, + struct p4tc_cmd_operate *oplist[], int cnt, + struct netlink_ext_ack *extack) +{ + int cmdcnt = cnt - 1; + int i; + + for (i = 1; i < cmdcnt; i++) { + struct p4tc_cmd_operate *ope = oplist[i - 1]; + int jmp_cnt = 0; + struct p4tc_cmd_operand *kopnd; + + if (ope->op_id == P4TC_CMD_OP_JUMP) { + list_for_each_entry(kopnd, &ope->operands_list, oper_list_node) { + int ret; + + if (kopnd->immedv) { + jmp_cnt = kopnd->immedv & TC_ACT_EXT_VAL_MASK; + if (jmp_cnt + i >= cmdcnt) { + NL_SET_ERR_MSG(extack, + "jump excessive branch"); + return -EINVAL; + } + } else { + ret = cmd_jump_operand_validate(act, ope, + kopnd, + cmdcnt, extack); + if (ret < 0) + return ret; + } + } + } + + if (!cmd_is_branch(ope->op_id)) + continue; + + if (TC_ACT_EXT_CMP(ope->ctl1, TC_ACT_JUMP)) { + if (ope->label1) { + int cmd_offset; + + cmd_offset = cmd_find_label_offset(act, + ope->label1, + extack); + if (cmd_offset < 0) + return -EINVAL; + + jmp_cnt = cmd_offset - ope->cmd_offset - 1; + + if (jmp_cnt <= 0) { + NL_SET_ERR_MSG_MOD(extack, + "Backward jumps are not allowed"); + return -EINVAL; + } + ope->ctl1 |= jmp_cnt; + } else { + jmp_cnt = ope->ctl1 & TC_ACT_EXT_VAL_MASK; + if (jmp_cnt + i >= cmdcnt) { + NL_SET_ERR_MSG(extack, + "ctl1 excessive branch"); + return -EINVAL; + } + } + } + + if (TC_ACT_EXT_CMP(ope->ctl2, TC_ACT_JUMP)) { + if (ope->label2) { + int cmd_offset; + + cmd_offset = cmd_find_label_offset(act, + ope->label2, + extack); + if (cmd_offset < 0) + return -EINVAL; + + jmp_cnt = cmd_offset - ope->cmd_offset - 1; + + if (jmp_cnt <= 0) { + NL_SET_ERR_MSG_MOD(extack, + "Backward jumps are not allowed"); + return -EINVAL; + } + ope->ctl2 |= jmp_cnt; + } else { + jmp_cnt = ope->ctl2 & TC_ACT_EXT_VAL_MASK; + if (jmp_cnt + i >= cmdcnt) { + NL_SET_ERR_MSG(extack, + "ctl2 excessive branch"); + return -EINVAL; + } + } + } + } + + return 0; +} + +static void p4tc_cmds_insert_acts(struct p4tc_act *act, + struct p4tc_cmd_operate *ope) +{ + struct tc_action *actions[TCA_ACT_MAX_PRIO] = { NULL }; + int i = 0; + struct p4tc_cmd_operand *kopnd; + + list_for_each_entry(kopnd, &ope->operands_list, oper_list_node) { + if (kopnd->oper_type == P4TC_OPER_ACTID && + !(kopnd->oper_flags & DATA_USES_ROOT_PIPE)) { + struct p4tc_act_dep_edge_node *edge_node = kopnd->priv; + struct tcf_p4act *p = to_p4act(kopnd->action); + + /* Add to the dependency graph so we can detect + * circular references + */ + tcf_pipeline_add_dep_edge(act->pipeline, edge_node, + p->act_id); + kopnd->priv = NULL; + + actions[i] = kopnd->action; + i++; + } + } + + tcf_idr_insert_many(actions); +} + +static void p4tc_cmds_ops_pass_to_list(struct p4tc_act *act, + struct p4tc_cmd_operate **oplist, + struct list_head *cmd_operations, + bool called_from_instance) +{ + int i; + + for (i = 0; i < P4TC_CMDS_LIST_MAX && oplist[i]; i++) { + struct p4tc_cmd_operate *ope = oplist[i]; + + if (!called_from_instance) + p4tc_cmds_insert_acts(act, ope); + + list_add_tail(&ope->cmd_operations, cmd_operations); + } +} + +static void p4tc_cmd_ops_del_list(struct net *net, + struct list_head *cmd_operations) +{ + struct p4tc_cmd_operate *ope, *tmp; + + list_for_each_entry_safe(ope, tmp, cmd_operations, cmd_operations) { + list_del(&ope->cmd_operations); + kfree_opentry(net, ope, false); + } +} + +static int p4tc_cmds_copy_opnd(struct p4tc_act *act, + struct p4tc_cmd_operand **new_kopnd, + struct p4tc_cmd_operand *kopnd, + struct netlink_ext_ack *extack) +{ + struct p4tc_type_mask_shift *mask_shift = NULL; + struct p4tc_cmd_operand *_new_kopnd; + int err = 0; + + _new_kopnd = kzalloc(sizeof(*_new_kopnd), GFP_KERNEL); + if (!_new_kopnd) + return -ENOMEM; + + memcpy(_new_kopnd, kopnd, sizeof(*_new_kopnd)); + memset(&_new_kopnd->oper_list_node, 0, sizeof(struct list_head)); + + if (kopnd->oper_type == P4TC_OPER_CONST && + kopnd->oper_datatype->ops->create_bitops) { + mask_shift = create_constant_bitops(kopnd, kopnd->oper_datatype, + extack); + if (IS_ERR(mask_shift)) { + err = -EINVAL; + goto err; + } + } else if (kopnd->oper_type == P4TC_OPER_META && + kopnd->oper_datatype->ops->create_bitops) { + struct p4tc_pipeline *pipeline; + struct p4tc_metadata *meta; + + if (kopnd->pipeid == P4TC_KERNEL_PIPEID) + pipeline = tcf_pipeline_find_byid(NULL, kopnd->pipeid); + else + pipeline = act->pipeline; + + meta = tcf_meta_find_byid(pipeline, kopnd->immedv); + if (!meta) { + err = -EINVAL; + goto err; + } + + mask_shift = create_metadata_bitops(kopnd, meta, + kopnd->oper_datatype, + extack); + if (IS_ERR(mask_shift)) { + err = -EINVAL; + goto err; + } + } else if (kopnd->oper_type == P4TC_OPER_HDRFIELD || + kopnd->oper_type == P4TC_OPER_PARAM || + kopnd->oper_type == P4TC_OPER_REG) { + if (kopnd->oper_datatype->ops->create_bitops) { + const struct p4tc_type_ops *ops = + kopnd->oper_datatype->ops; + + mask_shift = ops->create_bitops(kopnd->oper_bitsize, + kopnd->oper_bitstart, + kopnd->oper_bitend, + extack); + if (IS_ERR(mask_shift)) { + err = -EINVAL; + goto err; + } + } + } + + _new_kopnd->oper_mask_shift = mask_shift; + + if (kopnd->path_or_value_sz) { + _new_kopnd->path_or_value = + kzalloc(kopnd->path_or_value_sz, GFP_KERNEL); + if (!_new_kopnd->path_or_value) { + err = -ENOMEM; + goto err; + } + + memcpy(_new_kopnd->path_or_value, kopnd->path_or_value, + kopnd->path_or_value_sz); + } + + if (kopnd->path_or_value_extra_sz) { + _new_kopnd->path_or_value_extra = + kzalloc(kopnd->path_or_value_extra_sz, GFP_KERNEL); + if (!_new_kopnd->path_or_value_extra) { + err = -ENOMEM; + goto err; + } + + memcpy(_new_kopnd->path_or_value_extra, + kopnd->path_or_value_extra, + kopnd->path_or_value_extra_sz); + } + + if (kopnd->print_prefix_sz) { + _new_kopnd->print_prefix = + kzalloc(kopnd->print_prefix_sz, GFP_KERNEL); + if (!_new_kopnd->print_prefix) { + err = -ENOMEM; + goto err; + } + memcpy(_new_kopnd->print_prefix, kopnd->print_prefix, + kopnd->print_prefix_sz); + } + + memcpy(_new_kopnd->immedv_large, kopnd->immedv_large, + kopnd->immedv_large_sz); + + *new_kopnd = _new_kopnd; + + return 0; + +err: + kfree(_new_kopnd->path_or_value); + kfree(_new_kopnd->path_or_value_extra); + kfree(_new_kopnd); + + return err; +} + +static int p4tc_cmds_copy_ops(struct p4tc_act *act, + struct p4tc_cmd_operate **new_op_entry, + struct p4tc_cmd_operate *op_entry, + struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operate *_new_op_entry; + struct p4tc_cmd_operand *cursor; + int err = 0; + + _new_op_entry = kzalloc(sizeof(*_new_op_entry), GFP_KERNEL); + if (!_new_op_entry) + return -ENOMEM; + + INIT_LIST_HEAD(&_new_op_entry->operands_list); + list_for_each_entry(cursor, &op_entry->operands_list, oper_list_node) { + struct p4tc_cmd_operand *new_opnd = NULL; + + err = p4tc_cmds_copy_opnd(act, &new_opnd, cursor, extack); + if (new_opnd) { + struct list_head *head; + + head = &new_opnd->oper_list_node; + list_add_tail(&new_opnd->oper_list_node, + &_new_op_entry->operands_list); + } + if (err < 0) + goto set_results; + } + + _new_op_entry->op_id = op_entry->op_id; + _new_op_entry->op_flags = op_entry->op_flags; + _new_op_entry->op_cnt = op_entry->op_cnt; + _new_op_entry->cmd_offset = op_entry->cmd_offset; + + _new_op_entry->ctl1 = op_entry->ctl1; + _new_op_entry->ctl2 = op_entry->ctl2; + _new_op_entry->cmd = op_entry->cmd; + +set_results: + *new_op_entry = _new_op_entry; + + return err; +} + +int p4tc_cmds_copy(struct p4tc_act *act, struct list_head *new_cmd_operations, + bool delete_old, struct netlink_ext_ack *extack) +{ + struct p4tc_cmd_operate *oplist[P4TC_CMDS_LIST_MAX] = { NULL }; + int i = 0; + struct p4tc_cmd_operate *op; + int err; + + if (delete_old) + p4tc_cmd_ops_del_list(NULL, new_cmd_operations); + + list_for_each_entry(op, &act->cmd_operations, cmd_operations) { + err = p4tc_cmds_copy_ops(act, &oplist[i], op, extack); + if (err < 0) + goto free_oplist; + + i++; + } + + p4tc_cmds_ops_pass_to_list(act, oplist, new_cmd_operations, true); + + return 0; + +free_oplist: + kfree_tmp_oplist(NULL, oplist, false); + return err; +} + +#define SEPARATOR "/" + +int p4tc_cmds_parse(struct net *net, struct p4tc_act *act, struct nlattr *nla, + bool ovr, struct netlink_ext_ack *extack) +{ + /* XXX: oplist and oplist_attr + * could bloat the stack depending on P4TC_CMDS_LIST_MAX + */ + struct p4tc_cmd_operate *oplist[P4TC_CMDS_LIST_MAX] = { NULL }; + struct nlattr *oplist_attr[P4TC_CMDS_LIST_MAX + 1]; + struct rhashtable *labels = act->labels; + int err; + int i; + + err = nla_parse_nested(oplist_attr, P4TC_CMDS_LIST_MAX, nla, NULL, + extack); + if (err < 0) + return err; + + act->labels = kzalloc(sizeof(*labels), GFP_KERNEL); + if (!act->labels) + return -ENOMEM; + + err = rhashtable_init(act->labels, &p4tc_label_ht_params); + if (err < 0) { + kfree(act->labels); + act->labels = labels; + return err; + } + + for (i = 1; i < P4TC_CMDS_LIST_MAX + 1 && oplist_attr[i]; i++) { + if (!oplist_attr[i]) + break; + err = p4tc_cmd_process_ops(net, act, oplist_attr[i], + &oplist[i - 1], i - 1, extack); + if (err) { + kfree_tmp_oplist(net, oplist, true); + + if (err == P4TC_CMD_POLICY) + err = -EINVAL; + + goto free_labels; + } + } + + err = cmd_brn_validate(act, oplist, i, extack); + if (err < 0) { + kfree_tmp_oplist(net, oplist, true); + goto free_labels; + } + + if (ovr) { + p4tc_cmd_ops_del_list(net, &act->cmd_operations); + if (labels) { + rhashtable_free_and_destroy(labels, p4tc_label_ht_destroy, + NULL); + kfree(labels); + } + } + + /*XXX: At this point we have all the cmds and they are valid */ + p4tc_cmds_ops_pass_to_list(act, oplist, &act->cmd_operations, false); + + return 0; + +free_labels: + rhashtable_destroy(act->labels); + kfree(act->labels); + if (ovr) + act->labels = labels; + else + act->labels = NULL; + + return err; +} + +static void *p4tc_fetch_constant(struct sk_buff *skb, + struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + if (op->oper_flags & DATA_IS_IMMEDIATE) + return &op->immedv; + + return op->immedv_large; +} + +static void *p4tc_fetch_table(struct sk_buff *skb, struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return op->priv; +} + +static void *p4tc_fetch_result(struct sk_buff *skb, struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + if (op->immedv == P4TC_CMDS_RESULTS_HIT) + return &res->hit; + else + return &res->miss; +} + +static void *p4tc_fetch_hdrfield(struct sk_buff *skb, + struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return tcf_hdrfield_fetch(skb, op->priv); +} + +static void *p4tc_fetch_param(struct sk_buff *skb, struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct tcf_p4act_params *params; + struct p4tc_act_param *param; + + params = rcu_dereference(cmd->params); + param = params->params_array[op->immedv2]; + + if (param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN) { + struct p4tc_cmd_operand *intern_op = param->value; + + return __p4tc_fetch(skb, intern_op, cmd, res); + } + + return param->value; +} + +static void *p4tc_fetch_key(struct sk_buff *skb, struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_percpu_scratchpad *pad; + + pad = this_cpu_ptr(&p4tc_percpu_scratchpad); + + return pad->key; +} + +static void *p4tc_fetch_dev(struct sk_buff *skb, struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return &op->immedv; +} + +static void *p4tc_fetch_metadata(struct sk_buff *skb, + struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return tcf_meta_fetch(skb, op->priv); +} + +static void *p4tc_fetch_reg(struct sk_buff *skb, struct p4tc_cmd_operand *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_register *reg = op->priv; + size_t bytesz; + + bytesz = BITS_TO_BYTES(reg->reg_type->container_bitsz); + + return reg->reg_value + bytesz * op->immedv2; +} + +/* SET A B - A is set from B + * + * Assumes everything has been vetted - meaning no checks here + * + */ +static int p4tc_cmd_SET(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A, *B; + void *src; + void *dst; + int err; + + A = GET_OPA(&op->operands_list); + B = GET_OPB(&op->operands_list); + + src = __p4tc_fetch(skb, B, cmd, res); + dst = __p4tc_fetch(skb, A, cmd, res); + + if (!src || !dst) + return TC_ACT_SHOT; + + err = p4tc_copy_op(A, B, dst, src); + + if (err) + return TC_ACT_SHOT; + + return op->ctl1; +} + +/* ACT A - execute action A + * + * Assumes everything has been vetted - meaning no checks here + * + */ +static int p4tc_cmd_ACT(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A = GET_OPA(&op->operands_list); + const struct tc_action *action = A->action; + + /* This should be moved to core TC and applied to other actions as well */ +#ifdef CONFIG_RETPOLINE + if (likely(action->ops->act == tcf_p4_dyna_act)) { + return tcf_p4_dyna_act(skb, action, res); + } else { + return action->ops->act(skb, action, res); + } +#else + return action->ops->act(skb, action, res); +#endif +} + +static int p4tc_cmd_PRINT(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A = GET_OPA(&op->operands_list); + u64 readval[BITS_TO_U64(P4T_MAX_BITSZ)] = { 0 }; + struct net *net = dev_net(skb->dev); + char name[(TEMPLATENAMSZ * 4)]; + struct p4tc_type *val_t; + void *val; + + A = GET_OPA(&op->operands_list); + val = __p4tc_fetch(skb, A, cmd, res); + val_t = A->oper_datatype; + + if (!val) + return TC_ACT_OK; + + p4tc_reg_lock(A, NULL, NULL); + if (val_t->ops->host_read) + val_t->ops->host_read(val_t, A->oper_mask_shift, val, &readval); + else + memcpy(&readval, val, BITS_TO_BYTES(A->oper_bitsize)); + /* This is a debug function, so performance is not a priority */ + if (A->oper_type == P4TC_OPER_META) { + struct p4tc_pipeline *pipeline = NULL; + char *path = (char *)A->print_prefix; + struct p4tc_metadata *meta; + + pipeline = tcf_pipeline_find_byid(net, A->pipeid); + meta = tcf_meta_find_byid(pipeline, A->immedv); + + if (path) + snprintf(name, + (TEMPLATENAMSZ << 1) + + P4TC_CMD_MAX_OPER_PATH_LEN, + "%s %s.%s", path, pipeline->common.name, + meta->common.name); + else + snprintf(name, TEMPLATENAMSZ << 1, "%s.%s", + pipeline->common.name, meta->common.name); + + val_t->ops->print(net, val_t, name, &readval); + } else if (A->oper_type == P4TC_OPER_HDRFIELD) { + char *path = (char *)A->print_prefix; + struct p4tc_hdrfield *hdrfield; + struct p4tc_pipeline *pipeline; + struct p4tc_parser *parser; + + pipeline = tcf_pipeline_find_byid(net, A->pipeid); + parser = tcf_parser_find_byid(pipeline, A->immedv); + hdrfield = tcf_hdrfield_find_byid(parser, A->immedv2); + + if (path) + snprintf(name, TEMPLATENAMSZ * 4, + "%s hdrfield.%s.%s.%s", path, + pipeline->common.name, parser->parser_name, + hdrfield->common.name); + else + snprintf(name, TEMPLATENAMSZ * 4, "hdrfield.%s.%s.%s", + pipeline->common.name, parser->parser_name, + hdrfield->common.name); + + val_t->ops->print(net, val_t, name, &readval); + } else if (A->oper_type == P4TC_OPER_KEY) { + char *path = (char *)A->print_prefix; + struct p4tc_table *table; + struct p4tc_pipeline *pipeline; + + pipeline = tcf_pipeline_find_byid(net, A->pipeid); + table = tcf_table_find_byid(pipeline, A->immedv); + if (path) + snprintf(name, TEMPLATENAMSZ * 3, "%s key.%s.%s.%u", + path, pipeline->common.name, + table->common.name, A->immedv2); + else + snprintf(name, TEMPLATENAMSZ * 3, "key.%s.%s.%u", + pipeline->common.name, table->common.name, + A->immedv2); + val_t->ops->print(net, val_t, name, &readval); + } else if (A->oper_type == P4TC_OPER_PARAM) { + char *path = (char *)A->print_prefix; + + if (path) + snprintf(name, TEMPLATENAMSZ * 2, "%s param", path); + else + strcpy(name, "param"); + + val_t->ops->print(net, val_t, "param", &readval); + } else if (A->oper_type == P4TC_OPER_RES) { + char *path = (char *)A->print_prefix; + + if (A->immedv == P4TC_CMDS_RESULTS_HIT) { + if (path) + snprintf(name, TEMPLATENAMSZ * 2, "%s res.hit", + path); + else + strcpy(name, "res.hit"); + + } else if (A->immedv == P4TC_CMDS_RESULTS_MISS) { + if (path) + snprintf(name, TEMPLATENAMSZ * 2, "%s res.miss", + path); + else + strcpy(name, "res.miss"); + } + + val_t->ops->print(net, val_t, name, &readval); + } else if (A->oper_type == P4TC_OPER_REG) { + char *path = (char *)A->print_prefix; + struct p4tc_pipeline *pipeline; + struct p4tc_register *reg; + + pipeline = tcf_pipeline_find_byid(net, A->pipeid); + reg = tcf_register_find_byid(pipeline, A->immedv); + if (path) + snprintf(name, TEMPLATENAMSZ * 2, + "%s register.%s.%s[%u]", path, + pipeline->common.name, reg->common.name, + A->immedv2); + else + snprintf(name, TEMPLATENAMSZ * 2, "register.%s.%s[%u]", + pipeline->common.name, reg->common.name, + A->immedv2); + + val_t->ops->print(net, val_t, name, &readval); + } else { + pr_info("Unsupported operand for print\n"); + } + p4tc_reg_unlock(A, NULL, NULL); + + return op->ctl1; +} + +#define REDIRECT_RECURSION_LIMIT 4 +static DEFINE_PER_CPU(unsigned int, redirect_rec_level); + +static int p4tc_cmd_SNDPORTEGR(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct sk_buff *skb2 = skb; + int retval = TC_ACT_STOLEN; + struct p4tc_cmd_operand *A; + struct net_device *dev; + unsigned int rec_level; + bool expects_nh; + u32 *ifindex; + int mac_len; + bool at_nh; + int err; + + A = GET_OPA(&op->operands_list); + ifindex = __p4tc_fetch(skb, A, cmd, res); + + rec_level = __this_cpu_inc_return(redirect_rec_level); + if (unlikely(rec_level > REDIRECT_RECURSION_LIMIT)) { + net_warn_ratelimited("SNDPORTEGR: exceeded redirect recursion limit on dev %s\n", + netdev_name(skb->dev)); + __this_cpu_dec(redirect_rec_level); + return TC_ACT_SHOT; + } + + dev = dev_get_by_index_rcu(dev_net(skb->dev), *ifindex); + if (unlikely(!dev)) { + pr_notice_once("SNDPORTEGR: target device is gone\n"); + __this_cpu_dec(redirect_rec_level); + return TC_ACT_SHOT; + } + + if (unlikely(!(dev->flags & IFF_UP)) || !netif_carrier_ok(dev)) { + net_notice_ratelimited("SNDPORTEGR: device %s is down\n", + dev->name); + __this_cpu_dec(redirect_rec_level); + return TC_ACT_SHOT; + } + + nf_reset_ct(skb2); + + expects_nh = !dev_is_mac_header_xmit(dev); + at_nh = skb->data == skb_network_header(skb); + if (at_nh != expects_nh) { + mac_len = skb_at_tc_ingress(skb) ? + skb->mac_len : + skb_network_header(skb) - skb_mac_header(skb); + if (expects_nh) { + /* target device/action expect data at nh */ + skb_pull_rcsum(skb2, mac_len); + } else { + /* target device/action expect data at mac */ + skb_push_rcsum(skb2, mac_len); + } + } + + skb_set_redirected(skb2, skb2->tc_at_ingress); + skb2->skb_iif = skb->dev->ifindex; + skb2->dev = dev; + + err = dev_queue_xmit(skb2); + if (err) + retval = TC_ACT_SHOT; + + __this_cpu_dec(redirect_rec_level); + + return retval; +} + +static int p4tc_cmd_MIRPORTEGR(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct sk_buff *skb2 = skb; + int retval = TC_ACT_PIPE; + struct p4tc_cmd_operand *A; + struct net_device *dev; + unsigned int rec_level; + bool expects_nh; + u32 *ifindex; + int mac_len; + bool at_nh; + int err; + + A = GET_OPA(&op->operands_list); + ifindex = __p4tc_fetch(skb, A, cmd, res); + + rec_level = __this_cpu_inc_return(redirect_rec_level); + if (unlikely(rec_level > REDIRECT_RECURSION_LIMIT)) { + net_warn_ratelimited("MIRPORTEGR: exceeded redirect recursion limit on dev %s\n", + netdev_name(skb->dev)); + __this_cpu_dec(redirect_rec_level); + return TC_ACT_SHOT; + } + + dev = dev_get_by_index_rcu(dev_net(skb->dev), *ifindex); + if (unlikely(!dev)) { + pr_notice_once("MIRPORTEGR: target device is gone\n"); + __this_cpu_dec(redirect_rec_level); + return TC_ACT_SHOT; + } + + if (unlikely(!(dev->flags & IFF_UP))) { + net_notice_ratelimited("MIRPORTEGR: device %s is down\n", + dev->name); + __this_cpu_dec(redirect_rec_level); + return TC_ACT_SHOT; + } + + skb2 = skb_clone(skb, GFP_ATOMIC); + if (!skb2) { + __this_cpu_dec(redirect_rec_level); + return retval; + } + + nf_reset_ct(skb2); + + expects_nh = !dev_is_mac_header_xmit(dev); + at_nh = skb->data == skb_network_header(skb); + if (at_nh != expects_nh) { + mac_len = skb_at_tc_ingress(skb) ? + skb->mac_len : + skb_network_header(skb) - skb_mac_header(skb); + if (expects_nh) { + /* target device/action expect data at nh */ + skb_pull_rcsum(skb2, mac_len); + } else { + /* target device/action expect data at mac */ + skb_push_rcsum(skb2, mac_len); + } + } + + skb2->skb_iif = skb->dev->ifindex; + skb2->dev = dev; + + err = dev_queue_xmit(skb2); + if (err) + retval = TC_ACT_SHOT; + + __this_cpu_dec(redirect_rec_level); + + return retval; +} + +static int p4tc_cmd_TBLAPP(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A = GET_OPA(&op->operands_list); + struct p4tc_table *table = __p4tc_fetch(skb, A, cmd, res); + struct p4tc_table_entry_value *value; + struct p4tc_table_entry *entry; + struct p4tc_table_key *key; + int ret; + + A = GET_OPA(&op->operands_list); + table = __p4tc_fetch(skb, A, cmd, res); + if (unlikely(!table)) + return TC_ACT_SHOT; + + if (table->tbl_preacts) { + ret = tcf_action_exec(skb, table->tbl_preacts, + table->tbl_num_preacts, res); + /* Should check what return code should cause return */ + if (ret == TC_ACT_SHOT) + return ret; + } + + /* Sets key */ + key = table->tbl_key; + ret = tcf_action_exec(skb, key->key_acts, key->key_num_acts, res); + if (ret != TC_ACT_PIPE) + return ret; + + entry = p4tc_table_entry_lookup(skb, table, table->tbl_keysz); + if (entry) + value = p4tc_table_entry_value(entry); + + res->hit = entry ? true : false; + res->miss = !res->hit; + + ret = TC_ACT_PIPE; + if (res->hit) { + struct p4tc_table_defact *hitact; + + hitact = rcu_dereference(table->tbl_default_hitact); + if (value->acts) + ret = tcf_action_exec(skb, value->acts, value->num_acts, + res); + else if (hitact) + ret = tcf_action_exec(skb, hitact->default_acts, 1, + res); + } else { + struct p4tc_table_defact *missact; + + missact = rcu_dereference(table->tbl_default_missact); + if (missact) + ret = tcf_action_exec(skb, missact->default_acts, 1, + res); + } + if (ret != TC_ACT_PIPE) + return ret; + + return tcf_action_exec(skb, table->tbl_postacts, + table->tbl_num_postacts, res); +} + +static int p4tc_cmd_BINARITH(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res, + void (*p4tc_arith_op)(u64 *res, u64 opB, u64 opC)) +{ + u64 result = 0; + u64 B_val = 0; + u64 C_val = 0; + struct p4tc_cmd_operand *A, *B, *C; + const struct p4tc_type_ops *src_C_ops; + const struct p4tc_type_ops *src_B_ops; + const struct p4tc_type_ops *dst_ops; + void *src_B; + void *src_C; + void *dst; + + A = GET_OPA(&op->operands_list); + B = GET_OPB(&op->operands_list); + C = GET_OPC(&op->operands_list); + + dst = __p4tc_fetch(skb, A, cmd, res); + src_B = __p4tc_fetch(skb, B, cmd, res); + src_C = __p4tc_fetch(skb, C, cmd, res); + + if (!src_B || !src_C || !dst) + return TC_ACT_SHOT; + + dst_ops = A->oper_datatype->ops; + src_B_ops = B->oper_datatype->ops; + src_C_ops = C->oper_datatype->ops; + + p4tc_reg_lock(A, B, C); + + __p4tc_type_host_read(src_B_ops, B->oper_datatype, B->oper_mask_shift, + src_B, &B_val); + __p4tc_type_host_read(src_C_ops, C->oper_datatype, C->oper_mask_shift, + src_C, &C_val); + + p4tc_arith_op(&result, B_val, C_val); + + __p4tc_type_host_write(dst_ops, A->oper_datatype, A->oper_mask_shift, + &result, dst); + + p4tc_reg_unlock(A, B, C); + + return op->ctl1; +} + +/* Overflow semantic is the same as C's for u64 */ +static void plus_op(u64 *res, u64 opB, u64 opC) +{ + *res = opB + opC; +} + +static int p4tc_cmd_PLUS(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return p4tc_cmd_BINARITH(skb, op, cmd, res, plus_op); +} + +/* Underflow semantic is the same as C's for u64 */ +static void sub_op(u64 *res, u64 opB, u64 opC) +{ + *res = opB - opC; +} + +static int p4tc_cmd_SUB(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return p4tc_cmd_BINARITH(skb, op, cmd, res, sub_op); +} + +static void band_op(u64 *res, u64 opB, u64 opC) +{ + *res = opB & opC; +} + +static int p4tc_cmd_BAND(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return p4tc_cmd_BINARITH(skb, op, cmd, res, band_op); +} + +static void bor_op(u64 *res, u64 opB, u64 opC) +{ + *res = opB | opC; +} + +static int p4tc_cmd_BOR(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return p4tc_cmd_BINARITH(skb, op, cmd, res, bor_op); +} + +static void bxor_op(u64 *res, u64 opB, u64 opC) +{ + *res = opB ^ opC; +} + +static int p4tc_cmd_BXOR(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + return p4tc_cmd_BINARITH(skb, op, cmd, res, bxor_op); +} + +static int p4tc_cmd_CONCAT(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + u64 RvalAcc[BITS_TO_U64(P4T_MAX_BITSZ)] = { 0 }; + size_t rvalue_tot_sz = 0; + struct p4tc_cmd_operand *cursor; + const struct p4tc_type_ops *dst_ops; + struct p4tc_cmd_operand *A; + void *dst; + + A = GET_OPA(&op->operands_list); + + cursor = A; + list_for_each_entry_continue(cursor, &op->operands_list, oper_list_node) { + size_t cursor_bytesz = BITS_TO_BYTES(cursor->oper_bitsize); + struct p4tc_type *cursor_type = cursor->oper_datatype; + const struct p4tc_type_ops *cursor_type_ops = cursor_type->ops; + void *srcR = __p4tc_fetch(skb, cursor, cmd, res); + u64 Rval[BITS_TO_U64(P4T_MAX_BITSZ)] = {0}; + + __p4tc_type_host_read(cursor_type_ops, cursor->oper_datatype, + cursor->oper_mask_shift, srcR, &Rval); + + __p4tc_type_host_write(cursor_type_ops, cursor->oper_datatype, + cursor->oper_mask_shift, &Rval, + (char *)RvalAcc + rvalue_tot_sz); + rvalue_tot_sz += cursor_bytesz; + } + + dst = __p4tc_fetch(skb, A, cmd, res); + dst_ops = A->oper_datatype->ops; + __p4tc_type_host_write(dst_ops, A->oper_datatype, A->oper_mask_shift, + RvalAcc, dst); + + return op->ctl1; +} + +static int p4tc_cmd_JUMP(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A; + + A = GET_OPA(&op->operands_list); + + return A->immedv; +} + +static int p4tc_cmd_RET(struct sk_buff *skb, struct p4tc_cmd_operate *op, + struct tcf_p4act *cmd, struct tcf_result *res) +{ + struct p4tc_cmd_operand *A; + + A = GET_OPA(&op->operands_list); + + return A->immedv; +} From patchwork Wed May 17 11:02:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244701 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80601182C3 for ; Wed, 17 May 2023 11:05:07 +0000 (UTC) Received: from mail-qk1-x731.google.com (mail-qk1-x731.google.com [IPv6:2607:f8b0:4864:20::731]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A76BA3AA3 for ; Wed, 17 May 2023 04:04:44 -0700 (PDT) Received: by mail-qk1-x731.google.com with SMTP id af79cd13be357-7576ecfa4e7so65836885a.3 for ; Wed, 17 May 2023 04:04:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321482; x=1686913482; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=wbEN9wbp/SdMmeLthzDuS+XbT0QYAxc5l9cIkPgO9w4=; b=GUY+8X9c1f3269ut4lVR5klsi2WZ0cot0+3jLwv/AZ+baX7mYZtsSRK+wUDFfMH0iF +xhxb1YWibUDJJvfdQgPicJAgC3eYmV8nBOJxw8/S4vgxfKXPT1ojXjOmWuwMXmKMMs2 AX5ZVJaZjASQgtLvjWcD4d9cX4Nub0X7kPimh2YeeH2WLOOtVURPgfMMQDE2uXMWzLVt nCs+IZmPVKms2iTKEQgd0XFZ+PG0qctYSZZ3UtTWaPis1W52cbwdYazKKP+Ci0zSIoE0 MNUw8H9B8s5w2CSzKA1+V6yDPzdoWDhOQzbQOr1GzRq6KeVMzjIKqZP8b85+dsHVCEmo qkMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321482; x=1686913482; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=wbEN9wbp/SdMmeLthzDuS+XbT0QYAxc5l9cIkPgO9w4=; b=jskBpjwPGlYGh7nxGmsxgV0DH42P5JftW+ieOmE692vYQrK1hdzo0ngyGB5M3aJuiR z4Kr4RKwJv0MknH4lGj4Dnwxifr9fZacqn+BUj8uvPSi3ewbVKiE61x7D4/6EJo+nGMz 1nl3D8yIdurd9ti1dnCQ/Prf/jENBQHz3LaVPhhcDMHkRymAXApqH5nnwYoY1W54m+wP 4P3NnLwlMnIMZgt8IAXlcSnegqhWucSbfw1s0e/V7XxDLjGvjyiZ/i4dyH30+53GSqpt LAG+50y6e8A1lH6LD/sc0shx23nD1CroPoWvnOy5sH14nuMk5+pUaxidPD+j+bkJXukL cZDg== X-Gm-Message-State: AC+VfDw82nWu2rJydUnBhQIntWiYlhouRbw5GXtW5NqZiQbRdABIzgpq gtnKWsj5g3uG70hXbmbQE1vYNDN/WzDwBErGdfA= X-Google-Smtp-Source: ACHHUZ7e6lCFfFxOdYilI6sXo2aMAAaKX3ZjtYqPdID9pYvqXrYne1s9LyvsILzYZFLHF7cuBRJo3Q== X-Received: by 2002:a05:6214:493:b0:623:3f92:36f8 with SMTP id pt19-20020a056214049300b006233f9236f8mr34343190qvb.23.1684321482198; Wed, 17 May 2023 04:04:42 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id x16-20020a0cda10000000b0061b60afe381sm6225556qvj.85.2023.05.17.04.04.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:04:41 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 18/28] p4tc: add P4 classifier Date: Wed, 17 May 2023 07:02:22 -0400 Message-Id: <20230517110232.29349-18-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Introduce P4 tc classifier. A tc filter instantiated on this classifier is used to bind a P4 pipeline to one or more netdev ports. To use P4 classifier you must specify a pipeline name that will be associated to this filter. That pipeline must have already been create via a template. For example, if we were to add a filter to ingress of network interface of network interface device eth0 and associate it to P4 pipeline simple_l3 we'd issue the following command: tc filter add dev lo parent ffff: protocol any prio 6 p4 pname simple_l3 The filter itself has the following steps: ================================1 PARSING================================ The parser is implemented in ebpf residing either at the TC or XDP level. The parser produces meta-information which prescribes the different headers defined in the P4 program reside. Note: the different headers and their IDs are already described in the templating definition and the generated ebpf code. The ebpf parser invokes a kfunc(bpf_p4tc_get_parser_buffer) to pass on the metainfo to P4TC. To load the eBPF parser program into TC, we issue the following command: tc filter add dev $P0 ingress protocol any prio 1 p4 pname redirect_srcip \ prog tc obj $PROGNAME.o section parser/tc-ingress To load the eBPF parser program into XDP, we first need to load it into XDP using, for example, the ip command: ip link set $P0 xdp obj $PROGNAME.o section parser/xdp verbose Then we pin it: bpftool prog pin id $ID pin /tmp/ After that we create the P4 filter and refernce the XDP program: $TC filter add dev $P0 ingress protocol ip prio 1 p4 pname redirect_srcip \ prog xdp pinned /tmp/xdp_parser prog_cookie 22 Note that we also specify a the "prog_cookie", which is used to verify whether the eBPF program has executed or not before we reach the P4 classifier. To eBPF program sets this cookie by using the kfunc bpf_p4tc_set_cookie. ===============================2 PREACTIONS=============================== After parsing, the classifier will execute the pipeline preactions. Most of the time, the pipeline preactions will consist of a dynamic action table apply command, which will start the match action chain common to P4 programs. The preactions will return a standard action code (TC_ACT_OK, TC_ACT_SHOT and etc). If the preaction returns TC_ACT_PIPE, we'll continue to the next step of the filter execution, otherwise it will stop executing the filter and return the op code. ===============================3 POSTACTIONS=============================== After the pipeline preactions have executed and returned TC_ACT_PIPE, the filter will execute the pipeline postactions. Like the preactions, the postactions will return a standard action code. If the postaction returns TC_ACT_PIPE, we'll continue to the next step of the filter execution, otherwise it will stop executing the filter and return the op code. ==================4 ADDITIONALLY OPTIONAL FILTER ACTIONS================== After the pipeline preactions have executed and returned TC_ACT_PIPE, the filter will execute the filter actions, if any were associated with it. Filter actions are the ones defined outside the P4 program, example: tc filter add dev lo parent ffff: protocol ip prio 6 p4 \ pname simple_l3 action ok The action "ok" is classical Linux gact action. The filter will return the op code returned by this action. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/net/p4tc.h | 1 + include/uapi/linux/pkt_cls.h | 18 ++ net/sched/Kconfig | 12 + net/sched/Makefile | 1 + net/sched/cls_p4.c | 510 +++++++++++++++++++++++++++++++++++ net/sched/p4tc/Makefile | 4 +- net/sched/p4tc/p4tc_bpf.c | 77 ++++++ net/sched/p4tc/trace.c | 10 + net/sched/p4tc/trace.h | 44 +++ 9 files changed, 676 insertions(+), 1 deletion(-) create mode 100644 net/sched/cls_p4.c create mode 100644 net/sched/p4tc/p4tc_bpf.c create mode 100644 net/sched/p4tc/trace.c create mode 100644 net/sched/p4tc/trace.h diff --git a/include/net/p4tc.h b/include/net/p4tc.h index a31a6420e7e3..53d519149d09 100644 --- a/include/net/p4tc.h +++ b/include/net/p4tc.h @@ -36,6 +36,7 @@ #define P4TC_HDRFIELD_IS_VALIDITY_BIT 0x1 struct p4tc_percpu_scratchpad { + u32 prog_cookie; u32 keysz; u32 maskid; u8 key[BITS_TO_BYTES(P4TC_MAX_KEYSZ)]; diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 337411949ad0..0dcf574799bf 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -724,6 +724,24 @@ enum { #define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1) +/* P4 classifier */ + +enum { + TCA_P4_UNSPEC, + TCA_P4_CLASSID, + TCA_P4_ACT, + TCA_P4_PNAME, + TCA_P4_PROG_FD, + TCA_P4_PROG_NAME, + TCA_P4_PROG_TYPE, + TCA_P4_PROG_COOKIE, + TCA_P4_PROG_ID, + TCA_P4_PAD, + __TCA_P4_MAX, +}; + +#define TCA_P4_MAX (__TCA_P4_MAX - 1) + /* Extended Matches */ struct tcf_ematch_tree_hdr { diff --git a/net/sched/Kconfig b/net/sched/Kconfig index ea57a4c7b205..43d300ef0f5a 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -566,6 +566,18 @@ config NET_CLS_MATCHALL To compile this code as a module, choose M here: the module will be called cls_matchall. +config NET_CLS_P4 + tristate "P4 classifier" + select NET_CLS + select NET_P4_TC + help + If you say Y here, you will be able to bind a P4 pipeline + program. You will need to install P4 templates scripts successfully to + use this feature. + + To compile this code as a module, choose M here: the module will + be called cls_p4. + config NET_EMATCH bool "Extended Matches" select NET_CLS diff --git a/net/sched/Makefile b/net/sched/Makefile index 937b8f8a90ce..15bd59ae336c 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_NET_CLS_CGROUP) += cls_cgroup.o obj-$(CONFIG_NET_CLS_BPF) += cls_bpf.o obj-$(CONFIG_NET_CLS_FLOWER) += cls_flower.o obj-$(CONFIG_NET_CLS_MATCHALL) += cls_matchall.o +obj-$(CONFIG_NET_CLS_P4) += cls_p4.o obj-$(CONFIG_NET_EMATCH) += ematch.o obj-$(CONFIG_NET_EMATCH_CMP) += em_cmp.o obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o diff --git a/net/sched/cls_p4.c b/net/sched/cls_p4.c new file mode 100644 index 000000000000..25e3f0cc7aa8 --- /dev/null +++ b/net/sched/cls_p4.c @@ -0,0 +1,510 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/cls_p4.c - P4 Classifier + * Copyright (c) 2022-2023, Mojatatu Networks + * Copyright (c) 2022-2023, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "p4tc/trace.h" + +#define CLS_P4_PROG_NAME_LEN 256 + +struct p4tc_bpf_prog { + struct bpf_prog *p4_prog; + const char *p4_prog_name; +}; + +struct cls_p4_head { + struct tcf_exts exts; + struct tcf_result res; + struct rcu_work rwork; + struct p4tc_pipeline *pipeline; + struct p4tc_bpf_prog *prog; + u32 p4_prog_cookie; + u32 handle; +}; + +static int p4_classify(struct sk_buff *skb, const struct tcf_proto *tp, + struct tcf_result *res) +{ + struct cls_p4_head *head = rcu_dereference_bh(tp->root); + bool at_ingress = skb_at_tc_ingress(skb); + int rc = TC_ACT_PIPE; + struct p4tc_percpu_scratchpad *pad; + struct tcf_result p4res = {}; + struct p4tc_pipeline *pipeline; + + if (unlikely(!head)) { + pr_err("P4 classifier not found\n"); + return -1; + } + + pad = this_cpu_ptr(&p4tc_percpu_scratchpad); + + if (head->prog) { + /* If eBPF program is loaded into TC */ + if (head->prog->p4_prog->type == BPF_PROG_TYPE_SCHED_ACT) { + if (at_ingress) { + /* It is safe to push/pull even if skb_shared() */ + __skb_push(skb, skb->mac_len); + bpf_compute_data_pointers(skb); + rc = bpf_prog_run(head->prog->p4_prog, + skb); + __skb_pull(skb, skb->mac_len); + } else { + bpf_compute_data_pointers(skb); + rc = bpf_prog_run(head->prog->p4_prog, + skb); + } + /* Potentially eBPF program was executed before at XDP and we + * need to check the cookie to see if that was the case. + */ + } else { + if (head->p4_prog_cookie != pad->prog_cookie) { + net_notice_ratelimited("prog_cookie doesn't match"); + return TC_ACT_SHOT; + } + } + } + + if (rc != TC_ACT_PIPE) + goto zero_pad; + + pipeline = head->pipeline; + trace_p4_classify(skb, pipeline); + + rc = tcf_action_exec(skb, pipeline->preacts, pipeline->num_preacts, + &p4res); + if (rc != TC_ACT_PIPE) + goto zero_pad; + + rc = tcf_action_exec(skb, pipeline->postacts, pipeline->num_postacts, + &p4res); + if (rc != TC_ACT_PIPE) + goto zero_pad; + + *res = head->res; + + rc = tcf_exts_exec(skb, &head->exts, res); + +zero_pad: + /* Pad will always be zero initialised after boot. + * Zero it at the end after all users are done with it. + */ + memset(pad, 0, sizeof(*pad)); + + return rc; +} + +static int p4_init(struct tcf_proto *tp) +{ + return 0; +} + +static void p4_bpf_prog_destroy(struct p4tc_bpf_prog *prog) +{ + bpf_prog_put(prog->p4_prog); + kfree(prog->p4_prog_name); + kfree(prog); +} + +static void __p4_destroy(struct cls_p4_head *head) +{ + tcf_exts_destroy(&head->exts); + tcf_exts_put_net(&head->exts); + if (head->prog) + p4_bpf_prog_destroy(head->prog); + __tcf_pipeline_put(head->pipeline); + kfree(head); +} + +static void p4_destroy_work(struct work_struct *work) +{ + struct cls_p4_head *head = + container_of(to_rcu_work(work), struct cls_p4_head, rwork); + + rtnl_lock(); + __p4_destroy(head); + rtnl_unlock(); +} + +static void p4_destroy(struct tcf_proto *tp, bool rtnl_held, + struct netlink_ext_ack *extack) +{ + struct cls_p4_head *head = rtnl_dereference(tp->root); + + if (!head) + return; + + tcf_unbind_filter(tp, &head->res); + + if (tcf_exts_get_net(&head->exts)) + tcf_queue_work(&head->rwork, p4_destroy_work); + else + __p4_destroy(head); +} + +static void *p4_get(struct tcf_proto *tp, u32 handle) +{ + struct cls_p4_head *head = rtnl_dereference(tp->root); + + if (head && head->handle == handle) + return head; + + return NULL; +} + +static const struct nla_policy p4_policy[TCA_P4_MAX + 1] = { + [TCA_P4_UNSPEC] = { .type = NLA_UNSPEC }, + [TCA_P4_CLASSID] = { .type = NLA_U32 }, + [TCA_P4_ACT] = { .type = NLA_NESTED }, + [TCA_P4_PNAME] = { .type = NLA_STRING, .len = PIPELINENAMSIZ }, + [TCA_P4_PROG_FD] = { .type = NLA_U32}, + [TCA_P4_PROG_NAME] = { .type = NLA_STRING, .len = CLS_P4_PROG_NAME_LEN }, + [TCA_P4_PROG_TYPE] = { .type = NLA_U32}, + [TCA_P4_PROG_COOKIE] = { .type = NLA_U32 } +}; + +static int cls_p4_prog_from_efd(struct nlattr **tb, + struct p4tc_bpf_prog *prog, u32 flags, + struct netlink_ext_ack *extack) +{ + struct bpf_prog *fp; + u32 prog_type; + bool skip_sw; + char *name; + u32 bpf_fd; + + bpf_fd = nla_get_u32(tb[TCA_P4_PROG_FD]); + prog_type = nla_get_u32(tb[TCA_P4_PROG_TYPE]); + skip_sw = flags & TCA_CLS_FLAGS_SKIP_SW; + + if (prog_type != BPF_PROG_TYPE_XDP && + prog_type != BPF_PROG_TYPE_SCHED_ACT) { + NL_SET_ERR_MSG(extack, + "BPF prog type must be BPF_PROG_TYPE_SCHED_ACT or BPF_PROG_TYPE_XDP"); + return -EINVAL; + } + + fp = bpf_prog_get_type_dev(bpf_fd, prog_type, skip_sw); + if (IS_ERR(fp)) + return PTR_ERR(fp); + + name = nla_memdup(tb[TCA_P4_PROG_NAME], GFP_KERNEL); + if (!name) { + bpf_prog_put(fp); + return -ENOMEM; + } + + prog->p4_prog_name = name; + prog->p4_prog = fp; + + return 0; +} + +static int p4_set_parms(struct net *net, struct tcf_proto *tp, + struct cls_p4_head *head, unsigned long base, + struct nlattr **tb, struct nlattr *est, u32 flags, + struct netlink_ext_ack *extack) +{ + bool load_bpf_prog = tb[TCA_P4_PROG_NAME] && tb[TCA_P4_PROG_FD] && + tb[TCA_P4_PROG_TYPE]; + struct p4tc_bpf_prog *prog = NULL; + int err; + + err = tcf_exts_validate_ex(net, tp, tb, est, &head->exts, flags, 0, + extack); + if (err < 0) + return err; + + if (load_bpf_prog) { + prog = kzalloc(GFP_KERNEL, sizeof(*prog)); + if (!prog) { + err = -ENOMEM; + goto exts_destroy; + } + + err = cls_p4_prog_from_efd(tb, prog, flags, extack); + if (err < 0) { + kfree(prog); + goto exts_destroy; + } + } + + if (tb[TCA_P4_PROG_COOKIE]) { + struct p4tc_bpf_prog *prog_aux = prog ?: head->prog; + u32 *p4_prog_cookie; + + if (!prog_aux) { + err = -EINVAL; + NL_SET_ERR_MSG(extack, + "Must have a BPF program to specify xdp prog_cookie"); + goto prog_put; + } + + if (prog_aux->p4_prog->type != BPF_PROG_TYPE_XDP) { + err = -EINVAL; + NL_SET_ERR_MSG(extack, + "Program must be attached to XDP to specify prog_cookie"); + goto prog_put; + } + + p4_prog_cookie = nla_data(tb[TCA_P4_PROG_COOKIE]); + head->p4_prog_cookie = *p4_prog_cookie; + } else { + struct p4tc_bpf_prog *prog_aux = prog ?: head->prog; + + if (prog_aux && prog_aux->p4_prog->type == BPF_PROG_TYPE_XDP && + !head->p4_prog_cookie) { + NL_SET_ERR_MSG(extack, + "MUST provide prog_cookie when loading into XDP"); + err = -EINVAL; + goto prog_put; + } + } + + if (tb[TCA_P4_CLASSID]) { + head->res.classid = nla_get_u32(tb[TCA_P4_CLASSID]); + tcf_bind_filter(tp, &head->res, base); + } + + if (head->prog) { + pr_notice("cls_p4: Substituting old BPF program with id %u with new one with id %u\n", + head->prog->p4_prog->aux->id, prog->p4_prog->aux->id); + p4_bpf_prog_destroy(head->prog); + } + head->prog = prog; + + return 0; + +prog_put: + if (prog) + p4_bpf_prog_destroy(prog); +exts_destroy: + tcf_exts_destroy(&head->exts); + return err; +} + +static int p4_change(struct net *net, struct sk_buff *in_skb, + struct tcf_proto *tp, unsigned long base, u32 handle, + struct nlattr **tca, void **arg, u32 flags, + struct netlink_ext_ack *extack) +{ + struct cls_p4_head *head = rtnl_dereference(tp->root); + struct p4tc_pipeline *pipeline = NULL; + char *pname = NULL; + struct nlattr *tb[TCA_P4_MAX + 1]; + struct cls_p4_head *new; + int err; + + if (!tca[TCA_OPTIONS]) { + NL_SET_ERR_MSG(extack, "Must provide pipeline options"); + return -EINVAL; + } + + if (head) + return -EEXIST; + + err = nla_parse_nested(tb, TCA_P4_MAX, tca[TCA_OPTIONS], p4_policy, + extack); + if (err < 0) + return err; + + if (tb[TCA_P4_PNAME]) + pname = nla_data(tb[TCA_P4_PNAME]); + + if (pname) { + pipeline = tcf_pipeline_get(net, pname, 0, extack); + if (IS_ERR(pipeline)) + return PTR_ERR(pipeline); + } else { + NL_SET_ERR_MSG(extack, "MUST provide pipeline name"); + return -EINVAL; + } + + if (!pipeline_sealed(pipeline)) { + err = -EINVAL; + NL_SET_ERR_MSG(extack, "Pipeline must be sealed before use"); + goto pipeline_put; + } + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) { + err = -ENOMEM; + goto pipeline_put; + } + + err = tcf_exts_init(&new->exts, net, TCA_P4_ACT, 0); + if (err) + goto err_exts_init; + + if (!handle) + handle = 1; + + new->handle = handle; + + err = p4_set_parms(net, tp, new, base, tb, tca[TCA_RATE], flags, + extack); + if (err) + goto err_set_parms; + + new->pipeline = pipeline; + *arg = head; + rcu_assign_pointer(tp->root, new); + return 0; + +err_set_parms: + tcf_exts_destroy(&new->exts); +err_exts_init: + kfree(new); +pipeline_put: + __tcf_pipeline_put(pipeline); + return err; +} + +static int p4_delete(struct tcf_proto *tp, void *arg, bool *last, + bool rtnl_held, struct netlink_ext_ack *extack) +{ + *last = true; + return 0; +} + +static void p4_walk(struct tcf_proto *tp, struct tcf_walker *arg, + bool rtnl_held) +{ + struct cls_p4_head *head = rtnl_dereference(tp->root); + + if (arg->count < arg->skip) + goto skip; + + if (!head) + return; + if (arg->fn(tp, head, arg) < 0) + arg->stop = 1; +skip: + arg->count++; +} + +static int p4_prog_dump(struct sk_buff *skb, struct p4tc_bpf_prog *prog, + u32 prog_cookie) +{ + unsigned char *b = nlmsg_get_pos(skb); + + if (nla_put_u32(skb, TCA_P4_PROG_ID, prog->p4_prog->aux->id)) + goto nla_put_failure; + + if (nla_put_string(skb, TCA_P4_PROG_NAME, prog->p4_prog_name)) + goto nla_put_failure; + + if (nla_put_u32(skb, TCA_P4_PROG_TYPE, prog->p4_prog->type)) + goto nla_put_failure; + + if (prog_cookie && + nla_put_u32(skb, TCA_P4_PROG_COOKIE, prog_cookie)) + goto nla_put_failure; + + return 0; + +nla_put_failure: + nlmsg_trim(skb, b); + return -1; +} + +static int p4_dump(struct net *net, struct tcf_proto *tp, void *fh, + struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) +{ + struct cls_p4_head *head = fh; + struct nlattr *nest; + + if (!head) + return skb->len; + + t->tcm_handle = head->handle; + + nest = nla_nest_start(skb, TCA_OPTIONS); + if (!nest) + goto nla_put_failure; + + if (nla_put_string(skb, TCA_P4_PNAME, head->pipeline->common.name)) + goto nla_put_failure; + + if (head->res.classid && + nla_put_u32(skb, TCA_P4_CLASSID, head->res.classid)) + goto nla_put_failure; + + if (head->prog && p4_prog_dump(skb, head->prog, head->p4_prog_cookie)) + goto nla_put_failure; + + if (tcf_exts_dump(skb, &head->exts)) + goto nla_put_failure; + + nla_nest_end(skb, nest); + + if (tcf_exts_dump_stats(skb, &head->exts) < 0) + goto nla_put_failure; + + return skb->len; + +nla_put_failure: + nla_nest_cancel(skb, nest); + return -1; +} + +static void p4_bind_class(void *fh, u32 classid, unsigned long cl, void *q, + unsigned long base) +{ + struct cls_p4_head *head = fh; + + if (head && head->res.classid == classid) { + if (cl) + __tcf_bind_filter(q, &head->res, base); + else + __tcf_unbind_filter(q, &head->res); + } +} + +static struct tcf_proto_ops cls_p4_ops __read_mostly = { + .kind = "p4", + .classify = p4_classify, + .init = p4_init, + .destroy = p4_destroy, + .get = p4_get, + .change = p4_change, + .delete = p4_delete, + .walk = p4_walk, + .dump = p4_dump, + .bind_class = p4_bind_class, + .owner = THIS_MODULE, +}; + +static int __init cls_p4_init(void) +{ + return register_tcf_proto_ops(&cls_p4_ops); +} + +static void __exit cls_p4_exit(void) +{ + unregister_tcf_proto_ops(&cls_p4_ops); +} + +module_init(cls_p4_init); +module_exit(cls_p4_exit); + +MODULE_AUTHOR("Mojatatu Networks"); +MODULE_DESCRIPTION("P4 Classifier"); +MODULE_LICENSE("GPL"); diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index 396fcd249fb8..ac118a79cbf4 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 +CFLAGS_trace.o := -I$(src) + obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.o p4tc_meta.o \ p4tc_parser_api.o p4tc_hdrfield.o p4tc_action.o p4tc_table.o \ - p4tc_tbl_api.o p4tc_register.o p4tc_cmds.o + p4tc_tbl_api.o p4tc_register.o p4tc_cmds.o trace.o diff --git a/net/sched/p4tc/p4tc_bpf.c b/net/sched/p4tc/p4tc_bpf.c new file mode 100644 index 000000000000..08d26a6499c5 --- /dev/null +++ b/net/sched/p4tc/p4tc_bpf.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022, Mojatatu Networks + * Copyright (c) 2022, Intel Corporation. + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BTF_ID_LIST(btf_p4tc_ids) +BTF_ID(struct, p4tc_parser_buffer_act_bpf) + +struct p4tc_parser_buffer_act_bpf *bpf_p4tc_get_parser_buffer(void) +{ + struct p4tc_percpu_scratchpad *pad; + struct p4tc_parser_buffer_act_bpf *parser_buffer; + + pad = this_cpu_ptr(&p4tc_percpu_scratchpad); + + parser_buffer = (struct p4tc_parser_buffer_act_bpf *)&pad->hdrs; + + return parser_buffer; +} + +int is_p4tc_kfunc(const struct bpf_reg_state *reg) +{ + const struct btf_type *p4tc_parser_type, *t; + + p4tc_parser_type = btf_type_by_id(reg->btf, btf_p4tc_ids[0]); + + t = btf_type_by_id(reg->btf, reg->btf_id); + + return p4tc_parser_type == t; +} + +void bpf_p4tc_set_cookie(u32 cookie) +{ + struct p4tc_percpu_scratchpad *pad; + + pad = this_cpu_ptr(&p4tc_percpu_scratchpad); + pad->prog_cookie = cookie; +} + +BTF_SET8_START(p4tc_tbl_kfunc_set) +BTF_ID_FLAGS(func, bpf_p4tc_get_parser_buffer, 0); +BTF_ID_FLAGS(func, bpf_p4tc_set_cookie, 0); +BTF_SET8_END(p4tc_tbl_kfunc_set) + +static const struct btf_kfunc_id_set p4tc_table_kfunc_set = { + .owner = THIS_MODULE, + .set = &p4tc_tbl_kfunc_set, +}; + +int register_p4tc_tbl_bpf(void) +{ + int ret; + + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_ACT, + &p4tc_table_kfunc_set); + ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, + &p4tc_table_kfunc_set); + + return ret; +} diff --git a/net/sched/p4tc/trace.c b/net/sched/p4tc/trace.c new file mode 100644 index 000000000000..6833134077fa --- /dev/null +++ b/net/sched/p4tc/trace.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +#include + +#ifndef __CHECKER__ + +#define CREATE_TRACE_POINTS +#include "trace.h" +EXPORT_TRACEPOINT_SYMBOL_GPL(p4_classify); +#endif diff --git a/net/sched/p4tc/trace.h b/net/sched/p4tc/trace.h new file mode 100644 index 000000000000..80abec13b1bd --- /dev/null +++ b/net/sched/p4tc/trace.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM p4tc + +#if !defined(__P4TC_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define __P4TC_TRACE_H + +#include + +struct p4tc_pipeline; + +TRACE_EVENT(p4_classify, + TP_PROTO(struct sk_buff *skb, struct p4tc_pipeline *pipeline), + + TP_ARGS(skb, pipeline), + + TP_STRUCT__entry(__string(pname, pipeline->common.name) + __field(u32, p_id) + __field(u32, ifindex) + __field(u32, ingress) + ), + + TP_fast_assign(__assign_str(pname, pipeline->common.name); + __entry->p_id = pipeline->common.p_id; + __entry->ifindex = skb->dev->ifindex; + __entry->ingress = skb_at_tc_ingress(skb); + ), + + TP_printk("dev=%u dir=%s pipeline=%s p_id=%u", + __entry->ifindex, + __entry->ingress ? "ingress" : "egress", + __get_str(pname), + __entry->p_id + ) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include From patchwork Wed May 17 11:02:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244702 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2B9B2171A0 for ; Wed, 17 May 2023 11:05:12 +0000 (UTC) Received: from mail-ua1-x934.google.com (mail-ua1-x934.google.com [IPv6:2607:f8b0:4864:20::934]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D6243213B for ; Wed, 17 May 2023 04:04:50 -0700 (PDT) Received: by mail-ua1-x934.google.com with SMTP id a1e0cc1a2514c-77e80c37af1so241852241.0 for ; Wed, 17 May 2023 04:04:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321489; x=1686913489; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=P/xQ01outo04/1fIt9zKHqBnAyMG2ZmwEftsOLnlJU0=; b=j91w53a+ZaMupL+IE5TSJWqSoDVNcpXmFe8pTxFjex20YMCHnLWryDPo2SaCt+W+oF 1MaqQWR0K0tpbCzVF8CqQc0ACqV94C1yxT0xl9gjLHM9y3+d34BblzSQ2uSluEQccIMj 0ISyY4ll5NF/bW1CTnnEbzQ3R+4PoGRUkpO+idZsfH7scg8r1uRRzL6/9B2/w6AQoMBC fITIwo3KL7ILY6D5TGxxYKqLy6quk+NQ1QEvPZb3LwrGcG8M4UR45LcDh4CTItJU2TgN l2IfzqtTJAojqoTjxji9ZBEJLtzS/AO/rmeNaCzAMinO1DPo5ajNCYP+iFVhekNad7Vu s5/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321489; x=1686913489; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=P/xQ01outo04/1fIt9zKHqBnAyMG2ZmwEftsOLnlJU0=; b=WayDL3ev1PVKP5p6n8+JiMRhZB/NrCGVuOZ3J1qMQZSu4sH3SQnVcazivFN2rCJjHZ qgrVTKZn2dxoKT+wGg6ZaOX958EF93Vzq0oIDDjFEsgtVPNl00V18NMV6OeRJc240HyA FQOE90jURK38TC/gMzLt8W3eG2A2RYEO/IzfOs9yHQQAaZ9cH28z2C+L7xm/fGcm9rRr /0fe1nCPQ9F1n+p9BP+/U8oaIxYrmR0/6Z+/5OArMVUPhdQ+2plkLPS0ea16kAMAmFn6 9EJTLjieioTOFuueKlGv+isc+wzunPqeshoCYw78kUR2R+C5r7eHe2EJmHhjRwv4Mrml 71PQ== X-Gm-Message-State: AC+VfDytEpvDzbqaBEH8ubCOMPwpiL8aZe4thegkEzajc+OUXb8rUvx1 P9I8LbZC2qoJRHhv/VSj6Lxpg/9n1INmUQhP4NU= X-Google-Smtp-Source: ACHHUZ6xtJgugvYt8741MvqzZ0vVDmjrbgWzp5Q2yhzyI55Y51vZWsyIttcZYpKPLkExM38bX/dymg== X-Received: by 2002:a67:f943:0:b0:434:9028:275 with SMTP id u3-20020a67f943000000b0043490280275mr14875258vsq.7.1684321489610; Wed, 17 May 2023 04:04:49 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id n19-20020a05620a153300b007595010d3bbsm522587qkk.92.2023.05.17.04.04.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:04:49 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 19/28] selftests: tc-testing: add JSON introspection file directory for P4TC Date: Wed, 17 May 2023 07:02:23 -0400 Message-Id: <20230517110232.29349-19-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Add JSON introspection directory where we'll store the introspection files necessary when adding table entries in P4TC. Also add a sample JSON introspection file (ptables.json) which will be needed by the P4TC table entries test. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- .../introspection-examples/example_pipe.json | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/introspection-examples/example_pipe.json diff --git a/tools/testing/selftests/tc-testing/introspection-examples/example_pipe.json b/tools/testing/selftests/tc-testing/introspection-examples/example_pipe.json new file mode 100644 index 000000000000..9f216ab06d70 --- /dev/null +++ b/tools/testing/selftests/tc-testing/introspection-examples/example_pipe.json @@ -0,0 +1,92 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "example_pipe", + "id" : 22, + "tables" : [ + { + "name" : "cb/tname", + "id" : 1, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 64, + "keyid" : 1, + "keyfields" : [ + { + "id" : 1, + "name" : "srcAddr", + "type" : "ipv4", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "dstAddr", + "type" : "ipv4", + "match_type" : "exact", + "bitwidth" : 32 + } + ], + "actions" : [ + ] + }, + { + "name" : "cb/tname2", + "id" : 2, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 32, + "keyid" : 1, + "keyfields" : [ + { + "id" : 1, + "name" : "srcPort", + "type" : "bit16", + "match_type" : "exact", + "bitwidth" : 16 + }, + { + "id" : 2, + "name" : "dstPort", + "type" : "bit16", + "match_type" : "exact", + "bitwidth" : 16 + } + ], + "actions" : [ + ] + }, + { + "name" : "cb/tname3", + "id" : 3, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 104, + "keyid" : 1, + "keyfields" : [ + { + "id" : 1, + "name" : "randomKey1", + "type" : "bit8", + "match_type" : "exact", + "bitwidth" : 8 + }, + { + "id" : 2, + "name" : "randomKey2", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 3, + "name" : "randomKey3", + "type" : "bit64", + "match_type" : "exact", + "bitwidth" : 64 + } + ], + "actions" : [ + ] + } + ] +} From patchwork Wed May 17 11:02:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244703 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EE440171A0 for ; Wed, 17 May 2023 11:05:16 +0000 (UTC) Received: from mail-vk1-xa29.google.com (mail-vk1-xa29.google.com [IPv6:2607:f8b0:4864:20::a29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D55C01FE3 for ; Wed, 17 May 2023 04:04:59 -0700 (PDT) Received: by mail-vk1-xa29.google.com with SMTP id 71dfb90a1353d-452f0e27a86so249901e0c.3 for ; Wed, 17 May 2023 04:04:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321497; x=1686913497; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=up3sS5TyWBcT2wo5acNSH7hWr8OYTcv0pS8HnefN92w=; b=hvcS+Np80pWtb+5/D4o+7H044DZNHMduU8b4fOh+6yw883IYcYg5sjy+s7GeqeUpy6 KGKXw92FNcSZv+/PdvN4pPz4mSeoD5fLt5US54hi3U51N2mw2iVUJeAJiCBg4VnqrXMt qh2fehp3xEE8T2j3+6zmPCa34CBA6IQrs6ptrg+HekmScSpiDv9DoxeC1NIwwHiJNYHd 3rWBpZW8rTIYH0EpxmpRDHpAns02gcq6O7RpTWWit/cbm1PqFVnZ4fPfsxQfScr7qQHb 4TQSU7/B3DRCoIC+1YB1lK0X/Q+PIoi58fqpESFzI57bV5ZXF2n/FxT2KvmqWkQGxS8C k5+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321497; x=1686913497; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=up3sS5TyWBcT2wo5acNSH7hWr8OYTcv0pS8HnefN92w=; b=JKw7fD4YfsTaDuBTNL9hsK+2xLCZQBICprxPTR60zRmBS2H/X4IJqZKNe01I+SfeYf l1TUkz88bVvESjZFFeAuNtIKRG8lSN46wa4YmpPvOXA+fTHXg+OVQr9xqlKKp7CDsT4R 23ivVeD36M+BeSEJmUc4rSIOeaKGWHegrcHA458xeYcRwh+r77ebCR6KBFS6BwygFhxA lDExiIm++oiLwb5Uaqnzsco+gg+N/j2Y7MbvF0EDNKonu7VLyr82Cs8HZ8Yh2ssx8fSp z5Lwmb32jKZZ3oeCnBM/tFusYx2gzxt5ItyXVSgUGU0eHrevyeKDBLNB7XNKBFksGOoB r+gQ== X-Gm-Message-State: AC+VfDxKjQPi4T6gYP2XyTtWFIOm5fs4cOsjOVRttQgTyEcfNNmrnPrp X9nGXHoRxixFL8aQz9Cwxip/oPfWrHR7h/wISEk= X-Google-Smtp-Source: ACHHUZ5t10jwt2FxmpZyFTE9cYLws9gDHF2WrYxFZ6SGIc7/x7ZImlmppj7CUDhdn49ZSgFEjnQEtw== X-Received: by 2002:a1f:c112:0:b0:439:bd5c:630 with SMTP id r18-20020a1fc112000000b00439bd5c0630mr13654233vkf.6.1684321497131; Wed, 17 May 2023 04:04:57 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id t8-20020a05620a034800b00759495bb52fsm536320qkm.39.2023.05.17.04.04.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:04:56 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 20/28] selftests: tc-testing: Don't assume ENVIR is declared in local config Date: Wed, 17 May 2023 07:02:24 -0400 Message-Id: <20230517110232.29349-20-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Don't assume that the user's tdc_config_local.py declares ENVIR variable. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- tools/testing/selftests/tc-testing/tdc_config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tdc_config.py b/tools/testing/selftests/tc-testing/tdc_config.py index ccb0f06ef9e3..60f74011b62f 100644 --- a/tools/testing/selftests/tc-testing/tdc_config.py +++ b/tools/testing/selftests/tc-testing/tdc_config.py @@ -28,12 +28,14 @@ NAMES = { 'EBPFDIR': './' } +ENVIR= {} ENVIR = { } # put customizations in tdc_config_local.py try: from tdc_config_local import * + except ImportError as ie: pass From patchwork Wed May 17 11:02:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244704 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D363D171A0 for ; Wed, 17 May 2023 11:05:24 +0000 (UTC) Received: from mail-vk1-xa2e.google.com (mail-vk1-xa2e.google.com [IPv6:2607:f8b0:4864:20::a2e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 482562698 for ; Wed, 17 May 2023 04:05:07 -0700 (PDT) Received: by mail-vk1-xa2e.google.com with SMTP id 71dfb90a1353d-45046c21e55so253244e0c.1 for ; Wed, 17 May 2023 04:05:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321506; x=1686913506; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Fb4xw3LTXpPw3jjx94YEnpLJDEmagFP9lFHJltXRIjE=; b=p8t5t3Kc5GY4ss4sZIHpSP+U2JCl/Ei2VbZgG36U/NwLfYNt3morZwKGJAnAYwLwcI yFWe7vUzhzHRJbqh+N50nsQdwF+/SFBnWv2isa2fVdWp85nMAmqwhTjos2r2QMGUlUR4 gIbadziBUaDbSyoVnX3FgOeArbj7B/550opjBqiWDziLGtBp5sK96Ommx5mkVCFIszDi GT6gu2JTcM9uOTntJ8Na6FIi1zkF/Wd+P8n7WfaEJcqIPsq5OYTtvO3mg7JuT20KmDup UnpQE3w/LEOJADReeF5sSW3pPKj6ZlcgcRRJKrofADfxOlDm9TxQhQ2bA/U2jaeoidk7 869Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321506; x=1686913506; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Fb4xw3LTXpPw3jjx94YEnpLJDEmagFP9lFHJltXRIjE=; b=VTo2D80c9AIu8IYzvExji+TS02Ylk7gwioeqAZ3HM1IcLkXfSQL3Lz8DZRLxFp0Tuq Ia7OORf8IthJCunWGGtYRGfcmGd+FMNuvNTBHujw3hzkhbomvgHxeu0BfLdDSD4ggp2y 6vDriZiWO4/Hez/dYyhq6i171kfY7PJYZok/dSCVROSV/+PMjV0lQ5QZBsJ0wsTpfwqa dQcoOGwN2keCalsYRUCd+kqBhbUBOkBGP9G7Ubok6CgKsuJnzy499kmsve34jXjMZOxr 6B8tojpU4Hd2iX6JfV8aQyDfBdI7ESgWuCxhBzJnQm2VpppdXdsqypKyUuEUEfkYp6Hk rCEw== X-Gm-Message-State: AC+VfDy8KhqkJG2SESGtJncdNqiXULr2mBmZVlAmBkTLL6xLpI7VPUoI obPQId2tMBXTS0fFRiOXwBrzVMNXrdSEuPvwk/k= X-Google-Smtp-Source: ACHHUZ4RC0mrvkF3nCZ8jJ75QwBO5+ULhj/BiOkM5pxcWKJcJf/YeaNtQGUP0zuejHqfBh7f9HrD/Q== X-Received: by 2002:a67:ad04:0:b0:425:f7f0:26d2 with SMTP id t4-20020a67ad04000000b00425f7f026d2mr16714844vsl.27.1684321504595; Wed, 17 May 2023 04:05:04 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id p11-20020ae9f30b000000b0074df8eefe2dsm521269qkg.98.2023.05.17.04.05.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:05:03 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 21/28] selftests: tc-testing: add P4TC pipeline control path tdc tests Date: Wed, 17 May 2023 07:02:25 -0400 Message-Id: <20230517110232.29349-21-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Introduce first tdc tests for P4TC pipeline, which are focused on the control path. We test pipeline create, update, delete and dump. Here is a basic description of what we test for each operation: Create: - Create valid pipeline - Try to create pipeline without specifying mandatory arguments - Create pipeline without specifying optional arguments and check optional values after creation - Try to create pipeline passing invalid values for numttypes - Try to create pipeline passing invalid values for maxrules - Try to create pipeline with same name twice - Try to create pipeline with same id twice - Create pipeline with pipeline id == INX_MAX (2147483647) and check for overflow warning when traversing pipeline IDR - Create pipeline with name length > PIPELINENAMSIZ Update: - Update pipeline with valid values for numttypes, maxrules, preactions and postactions - Try to update pipeline with invalid values for maxrules and numttypes - Try to seal pipeline which is not ready - Check action bind and ref values after pipeline preaction update - Check action bind and ref values after pipeline postaction update Delete: - Delete pipeline by name - Delete pipeline by id - Delete inexistent pipeline by name - Delete inexistent pipeline by id - Try to flush pipelines - Check action bind and ref values after pipeline deletion Dump: - Dump pipeline IDR - Dump pipeline IDR when amount of pipelines > P4TC_MAXMSG_COUNT (16) Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- .../tc-testing/tc-tests/p4tc/pipeline.json | 3212 +++++++++++++++++ 1 file changed, 3212 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/pipeline.json diff --git a/tools/testing/selftests/tc-testing/tc-tests/p4tc/pipeline.json b/tools/testing/selftests/tc-testing/tc-tests/p4tc/pipeline.json new file mode 100644 index 000000000000..7b97d375bbdd --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/p4tc/pipeline.json @@ -0,0 +1,3212 @@ +[ + { + "id": "2c2f", + "name": "Create valid pipeline", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 2, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8a18", + "name": "Try to create pipeline without name", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchPattern": "Error: Pipeline name not found.*", + "teardown": [ + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "c0dc", + "name": "Create pipeline without preactions", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 postactions action gact index 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 2, + "pstate": "not ready", + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 1, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "248b", + "name": "Create pipeline without postactions", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 2, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0573", + "name": "Create pipeline without maxrules", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 2, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b103", + "name": "Create pipeline without numtables", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ceff", + "name": "Create pipeline with numtables = 0", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 22 numtables 0 maxrules 1 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7a5a", + "name": "Try to create pipeline with numtables > 32", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 22 numtables 33 maxrules 1 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchPattern": "Error: Pipeline name not found.*", + "teardown": [ + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5dd2", + "name": "Create pipeline with numtables = 32", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 1 numtables 32 maxrules 1 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 32, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4011", + "name": "Try to create pipeline with maxrules = 0", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 22 maxrules 0 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchPattern": "Error: Pipeline name not found.*", + "teardown": [ + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b97a", + "name": "Try to create pipeline with maxrules > 512", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 22 maxrules 513 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchPattern": "Error: Pipeline name not found.*", + "teardown": [ + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "571e", + "name": "Create pipeline with numtables = 256", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 1 numtables 2 maxrules 256 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 256, + "pnumtables": 2, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f6f8", + "name": "Try to create pipeline with same name twice", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 22 numtables 4 maxrules 2 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8e88", + "name": "Update numtables in existing pipeline", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ptables numtables 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 4, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b5fe", + "name": "Update maxrules in existing pipeline", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 maxrules 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ pipeid 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 2, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1120", + "name": "Update preactions in existing pipeline", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC actions add action pass index 3", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 preactions action gact index 3", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 3, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4bd9", + "name": "Update postactions in existing pipeline", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC actions add action pass index 3", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 postactions action gact index 3", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e08b", + "name": "Update maxrules and numtables in existing pipeline", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ptables maxrules 2 numtables 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 2, + "pnumtables": 4, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "bc01", + "name": "Update maxrules and preactions in existing pipeline", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC actions add action pass index 3", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ptables maxrules 2 preactions action gact index 3", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 2, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 3, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2cea", + "name": "Try to update maxrules with 0", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 maxrules 0", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "add7", + "name": "Try to update maxrules with 513", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 maxrules 513", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9e27", + "name": "Update numtables with 0", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 numtables 0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "01a3", + "name": "Try to update numtables with 33", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 numtables 33", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "db08", + "name": "Try to seal pipeline which is not ready", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 state ready", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 1, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 1, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "26", + "name": "Delete pipeline by name", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 maxrules 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del pipeline/ptables", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchPattern": "Error: Pipeline name not found.*", + "teardown": [ + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8855", + "name": "Delete pipeline by id", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 42 maxrules 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del pipeline/ pipeid 42", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ pipeid 42", + "matchCount": "1", + "matchPattern": "Error: Unable to find pipeline by id.*", + "teardown": [ + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "757e", + "name": "Try to delete inexistent pipeline by name", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [], + "cmdUnderTest": "$TC p4template del pipeline/ptables", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchPattern": "Error: Pipeline name not found.*", + "teardown": [] + }, + { + "id": "4bff", + "name": "Try to delete inexistent pipeline by id", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [], + "cmdUnderTest": "$TC p4template del pipeline/ pipeid 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ pipeid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find pipeline by id.*", + "teardown": [] + }, + { + "id": "15b3", + "name": "Try to flush pipelines", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 42 maxrules 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del pipeline/", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 42, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6051", + "name": "Dump pipeline list", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC actions add action pass index 3", + 0 + ], + [ + "$TC actions add action pass index 4", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 42 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables2 pipeid 22 preactions action gact index 3 postactions action gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/", + "matchCount": "1", + "matchJSON": [ + { + "obj": "pipeline" + }, + { + "templates": [ + { + "pname": "ptables2" + }, + { + "pname": "ptables" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC p4template del pipeline/ptables2", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0944", + "name": "Check action bind and ref after pipeline deletion", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 42 maxrules 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del pipeline/ pipeid 42", + "expExitCode": "0", + "verifyCmd": "$TC -j actions ls action gact", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 2 + }, + { + "actions": [ + { + "kind": "gact", + "index": 1, + "ref": 1, + "bind": 0 + }, + { + "kind": "gact", + "index": 2, + "ref": 1, + "bind": 0 + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8dbc", + "name": "Check action bind and ref after pipeline preaction update", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC actions add action pass index 3", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 preactions action gact index 3", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action gact index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "kind": "gact", + "index": 1, + "ref": 1, + "bind": 0 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9170", + "name": "Check action bind and ref after pipeline postaction update", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC actions add action pass index 3", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ pipeid 1 postactions action gact index 3", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action gact index 2", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "kind": "gact", + "index": 2, + "ref": 1, + "bind": 0 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6c15", + "name": "Try to create pipeline with same pipeid twice", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables2 pipeid 22 numtables 4 maxrules 2 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 0, + "pstate": "not ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e32a", + "name": "Dump pipeline when amount of pipelines > P4TC_MSGBATCH_SIZE", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ], + [ + "$TC actions add action pass index 3", + 0 + ], + [ + "$TC actions add action pass index 4", + 0 + ], + [ + "$TC actions add action pass index 5", + 0 + ], + [ + "$TC actions add action pass index 6", + 0 + ], + [ + "$TC actions add action pass index 7", + 0 + ], + [ + "$TC actions add action pass index 8", + 0 + ], + [ + "$TC p4template create pipeline/ptables preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables2 preactions action gact index 3 postactions action gact index 4", + 0 + ], + [ + "$TC p4template create pipeline/ptables3 preactions action gact index 5 postactions action gact index 6", + 0 + ], + [ + "$TC p4template create pipeline/ptables4 preactions action gact index 7 postactions action gact index 8", + 0 + ], + [ + "$TC p4template create pipeline/ptables5 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables6 preactions action gact index 3 postactions action gact index 4", + 0 + ], + [ + "$TC p4template create pipeline/ptables7 preactions action gact index 5 postactions action gact index 6", + 0 + ], + [ + "$TC p4template create pipeline/ptables8 preactions action gact index 7 postactions action gact index 8", + 0 + ], + [ + "$TC p4template create pipeline/ptables9 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables10 preactions action gact index 3 postactions action gact index 4", + 0 + ], + [ + "$TC p4template create pipeline/ptables11 preactions action gact index 5 postactions action gact index 6", + 0 + ], + [ + "$TC p4template create pipeline/ptables12 preactions action gact index 7 postactions action gact index 8", + 0 + ], + [ + "$TC p4template create pipeline/ptables13 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables14 preactions action gact index 3 postactions action gact index 4", + 0 + ], + [ + "$TC p4template create pipeline/ptables15 preactions action gact index 5 postactions action gact index 6", + 0 + ], + [ + "$TC p4template create pipeline/ptables16 preactions action gact index 7 postactions action gact index 8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables17 pipeid 2147483647 preactions action gact index 3 postactions action gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/", + "matchCount": "1", + "matchJSON": [ + { + "obj": "pipeline" + }, + { + "templates": [ + { + "pname": "ptables" + }, + { + "pname": "ptables2" + }, + { + "pname": "ptables3" + }, + { + "pname": "ptables4" + }, + { + "pname": "ptables5" + }, + { + "pname": "ptables6" + }, + { + "pname": "ptables7" + }, + { + "pname": "ptables8" + }, + { + "pname": "ptables9" + }, + { + "pname": "ptables10" + }, + { + "pname": "ptables11" + }, + { + "pname": "ptables12" + }, + { + "pname": "ptables13" + }, + { + "pname": "ptables14" + }, + { + "pname": "ptables15" + }, + { + "pname": "ptables16" + } + ] + }, + { + "obj": "pipeline" + }, + { + "templates": [ + { + "pname": "ptables17" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC p4template del pipeline/ptables2", + 0 + ], + [ + "$TC p4template del pipeline/ptables3", + 0 + ], + [ + "$TC p4template del pipeline/ptables4", + 0 + ], + [ + "$TC p4template del pipeline/ptables5", + 0 + ], + [ + "$TC p4template del pipeline/ptables6", + 0 + ], + [ + "$TC p4template del pipeline/ptables7", + 0 + ], + [ + "$TC p4template del pipeline/ptables8", + 0 + ], + [ + "$TC p4template del pipeline/ptables9", + 0 + ], + [ + "$TC p4template del pipeline/ptables10", + 0 + ], + [ + "$TC p4template del pipeline/ptables11", + 0 + ], + [ + "$TC p4template del pipeline/ptables12", + 0 + ], + [ + "$TC p4template del pipeline/ptables13", + 0 + ], + [ + "$TC p4template del pipeline/ptables14", + 0 + ], + [ + "$TC p4template del pipeline/ptables15", + 0 + ], + [ + "$TC p4template del pipeline/ptables16", + 0 + ], + [ + "$TC p4template del pipeline/ptables17", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "398c", + "name": "Test overflow in pipeid when we search for inexistent pipeline and we have pipeid 2147483647 in idr", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables pipeid 2147483647 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables2", + "matchCount": "1", + "matchPattern": "Error: Pipeline name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cd4e", + "name": "Try to create pipeline without name or id", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ preactions action gact index 1 postactions action gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchPattern": "Error: Pipeline name not found.*", + "teardown": [ + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6356", + "name": "Create pipeline with name length > PIPELINENAMSIZ", + "category": [ + "p4tc", + "template", + "pipeline" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action drop index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/7eozFYyaqVCD7H0xS3M5sMnluUqPgZewfSLnYPf4s3k0lbx8lKoR32zSqiGsh84qJ32vnLPdl7f2XcUh5yIdEP7uJy2C3iPtyU7159s9CMB0EtTAlWTVz4U1jkQ5h2advwp3KCVsZ1jlGgStoJL2op5ZxoThTSUQLR61a5RNDovoSFcq86Brh6oW9DSmTbN6SYygbG3JLnEHzRC5hh0jGmJKHq5ivBK9Y9FlNZQXC9wVwX4qTFAd8ITUTj2Au2Jg1 pipeid 1 preactions action gact index 1 postactions action gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ pipeid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find pipeline by id.*", + "teardown": [ + [ + "$TC actions flush action gact", + 0 + ] + ] + } +] From patchwork Wed May 17 11:02:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244705 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 378D91DDC6 for ; Wed, 17 May 2023 11:05:30 +0000 (UTC) Received: from mail-qk1-x72b.google.com (mail-qk1-x72b.google.com [IPv6:2607:f8b0:4864:20::72b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9EA051BE3 for ; Wed, 17 May 2023 04:05:14 -0700 (PDT) Received: by mail-qk1-x72b.google.com with SMTP id af79cd13be357-75788255892so34917085a.0 for ; Wed, 17 May 2023 04:05:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321513; x=1686913513; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=adIFye+pIPwd8yz03ApDYM1/ixCRHXi7tQYaKa8oWj8=; b=YCP1MwKlpHcSzW9GivtF1gqzs2Ar5ApXRFbMAQnW2zRwL1wnyq0N1gjXYxJS5j8uYm 9YuMfbucbKd9V2ZRF8k2qA860PaZa8t6EsYExyUBpxQUPGvuT6VoNC4wq4Ocmc1poCMr UQhQ7/QCdMPRud1gsGGktiujDEAYzpicyU9DPDI7Fjf1p16ScPFrOyWqUtwbfdB0wLmV FPJpdJsxy4xCWEmJ7Y08QKt39xo/zfp5t1q/wbPuIQ86oEBaqFiLEqLv7txezg2a7W1I seEMpEd5qv/oS2xCINuT/S02unchuN+BaRvGKp1E2LThVDlVxfDLfyJ0lJPfqg0EDHFx U95g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321513; x=1686913513; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=adIFye+pIPwd8yz03ApDYM1/ixCRHXi7tQYaKa8oWj8=; b=iFcHBlqg9TusKpZEPBNXivlWLKA1ETsR/IK+vljf88D9egLNOHGfE6EZ+PW8wQmhce kzPusJ0ls4U28Gw+5Wj+D8RBDSWMVHh2DgP8GmzRJ1vX4CGXQSjaRPoiTeuQQD6zJnDT 6kQ35k25T/Jn8vyJsdaT3nL3/ThkgSPjBLgM5w20jZ2r7Mzehq8KA79/qywj6FSpm0Xr rVbhPzMm22kJ8syYsI+VjM2QcVTS95ruYScbWw6KF4x2EPltYTXT9YN7bGChEv3kayAW BOUXaaHj/QV903zvYXysR11EEbz86jfQOYVnoJJQ2iGInhmV7pGFAHuv61j6fLqRukZH ETyg== X-Gm-Message-State: AC+VfDyJA8hCTL1Uwy16gcw/09rgsrYhuw5V1qKoHPK9x+yLqByMQtRw Zgs2QZHb6FPu7qf6U7zn13s8Cd56Dvk7he8auWs= X-Google-Smtp-Source: ACHHUZ4LVswMQihqM8tC266S3bhkPt3BhFBWYGFnGG+AcY0bW4rCC1oJbY65UOAScpIiM1QrE/hlvQ== X-Received: by 2002:ac8:5b86:0:b0:3f3:a0c0:cd6f with SMTP id a6-20020ac85b86000000b003f3a0c0cd6fmr44408133qta.9.1684321511810; Wed, 17 May 2023 04:05:11 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id bb13-20020a05622a1b0d00b003f521882bc1sm2773442qtb.7.2023.05.17.04.05.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:05:11 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 22/28] selftests: tc-testing: add P4TC metadata control path tdc tests Date: Wed, 17 May 2023 07:02:26 -0400 Message-Id: <20230517110232.29349-22-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Introduce first tdc tests for P4TC metadata, which are focused on the control path. We test metadata create, update, delete, flush and dump. Here is a basic description of what we test for each operation: Create: - Create valid metadatum - Try to create metadatum without specifying mandatory arguments - Try to create metadatum passing invalid values for size - Try to create metadatum without specifying pipeline name or id - Try to create metadatum with same name twice - Try to create metadatum with same id twice - Create metadatum without assigning id - Create metadatum with metadatum id == INX_MAX (2147483647) and check for overflow warning when traversing metadata IDR - Try to create metadatum with name length > METANENAMSIZ - Try to exceed max metadata offset on create Update: - Update metadatum with valid values for size - Try to update metadatum with invalid values for size - Try to update metadatum without specifying pipeline name or id - Try to update metadatum without specifying metadatum name or id - Try to exceed max metadata offset on update Delete: - Delete metadatum by name - Delete metadatum by id - Delete inexistent metadatum by name - Delete inexistent metadatum by id - Try to delete specific metadatum without supplying pipeline name or id Flush: - Flush metadata - Flush empty metadata IDR - Try to flush metadata without specifying pipeline name or id - Flush empty metadata list Dump: - Dump metadata IDR using pname to find pipeline - Dump metadata IDR using pipeid to find pipeline - Try to dump metadata IDR without supplying pipeline name or id - Dump metadatum IDR when amount of metadata > P4TC_MAXMSG_COUNT (16) Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- .../tc-testing/tc-tests/p4tc/metadata.json | 2652 +++++++++++++++++ 1 file changed, 2652 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/metadata.json diff --git a/tools/testing/selftests/tc-testing/tc-tests/p4tc/metadata.json b/tools/testing/selftests/tc-testing/tc-tests/p4tc/metadata.json new file mode 100644 index 000000000000..ceb65a9668e6 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/p4tc/metadata.json @@ -0,0 +1,2652 @@ +[ + { + "id": "62e5", + "name": "Create valid metadatum", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname mid 42 type bit8", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "bit", + "msize": 8 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "40e3", + "name": "Try to create metadatum without specifying pipeline name or id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ mid 42 type bit8", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchPattern": "Error: Metadatum name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b2e7", + "name": "Try to create metadata without name", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/ mid 42 type bit8", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchPattern": "Error: Metadatum name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7dbc", + "name": "Try to create metadata without size", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname mid 42", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchPattern": "Error: Metadatum name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4c52", + "name": "Try to create metadata with size 0", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname mid 42 type bit0", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchPattern": "Error: Metadatum name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4999", + "name": "Try to create metadata with size > 128", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname mid 42 type bit129", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchPattern": "Error: Metadatum name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b738", + "name": "Create metadata with size = 128", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/mname mid 42 type bit128", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ pipeid 22 mid 42", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "mname", + "mtype": "bit", + "msize": 128 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2deb", + "name": "Create metadata of signed type", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname mid 42 type int33", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ pipeid 22 mid 42", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "int", + "msize": 33 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0ddc", + "name": "Create metadata of type int128", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname mid 42 type int128", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ pipeid 22 mid 42", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "int", + "msize": 128 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "be48", + "name": "Try to create metadata of type int129", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname mid 42 type int129", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ pipeid 22 mid 42", + "matchCount": "1", + "matchPattern": "Error: Unable to find metadatum by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "054c", + "name": "Try to create metadatum with same name twice", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mname mid 42 type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/mname type bit13", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "mname", + "mtype": "bit", + "msize": 8 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3088", + "name": "Try to create metadatum with same id twice", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 42 type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname2 mid 42 type bit13", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/ mid 42", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "bit", + "msize": 8 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ad42", + "name": "Create metadatum without assigning mid", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname type bit27", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 1, + "mname": "cb/mname", + "mtype": "bit", + "msize": 27 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1805", + "name": "Update metadatum's size specifying metadatum name", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 42 type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update metadata/ptables/cb/mname type bit13", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "bit", + "msize": 13 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "51a3", + "name": "Update metadatum's size specifying metadatum id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 42 type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update metadata/ptables/ mid 42 type bit13", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/ mid 42", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "bit", + "msize": 13 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "db7d", + "name": "Try to update metadatum without specifying pipeline name or id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 42 type bit4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update metadata/ type bit8", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "bit", + "msize": 4 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d525", + "name": "Try to update metadatum without specifying metadatum name or id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 42 type bit4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update metadata/ptables/ type bit8", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "bit", + "msize": 4 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6853", + "name": "Try to update metadatum's size with zero", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 42 type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update metadata/ptables/cb/mname mid 42 type bit0", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "bit", + "msize": 8 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "514f", + "name": "Try to update metadatum's size with 129", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 42 type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update metadata/ptables/cb/mname mid 42 type bit129", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "bit", + "msize": 8 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "c9d4", + "name": "Update metadata with size = 128", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 42 type bit64", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update metadata/ pipeid 22 mid 42 type bit128", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 42, + "mname": "cb/mname", + "mtype": "bit", + "msize": 128 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0a2d", + "name": "Dump metadata using pname to find pipeline", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname2 type bit27", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mname": "cb/mname" + }, + { + "mname": "cb/mname2" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "380d", + "name": "Dump metadata using pipeid to find pipeline", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname2 type bit27", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ pipeid 22", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mname": "cb/mname" + }, + { + "mname": "cb/mname2" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "c0ee", + "name": "Try to dump metadata without supplying pipeline name or id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname2 type bit27", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/", + "matchCount": "1", + "matchPattern": "Must specify pipeline name or id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a45b", + "name": "Delete specific metadatum by name", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/ptables/cb/mname", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchPattern": "Error: Metadatum name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "fe8d", + "name": "Delete specific metadatum by id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 1 type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/ptables/ mid 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/ mid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find metadatum by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "bf02", + "name": "Try to delete inexistent metadatum by name", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/ptables/cb/mname", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchPattern": "Error: Metadatum name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "253c", + "name": "Try to delete inexistent metadatum by id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/ptables/ mid 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/ mid 1", + "matchCount": "1", + "matchPattern": "Unable to find metadatum by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "deca", + "name": "Try to delete specific metadatum without supplying pipeline name or id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 1, + "mname": "cb/mname", + "mtype": "bit", + "msize": 8 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b331", + "name": "Flush metadata", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/ptables/", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/", + "matchCount": "1", + "matchJSON": [], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1456", + "name": "Try to flush metadata without specifying pipeline name or id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 1, + "mname": "cb/mname", + "mtype": "bit", + "msize": 8 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3a84", + "name": "Try to exceed max metadata offset on create", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit64", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname2 type bit64", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname3 type bit128", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname4 type bit128", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname5 type bit128", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname6 type bit1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname6", + "matchCount": "1", + "matchPattern": "Error: Metadatum name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2f62", + "name": "Try to exceed max metadata offset on update", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit64", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname2 mid 22 type bit32", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname3 type bit64", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname4 type bit64", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname5 type bit128", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname6 type bit128", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update metadata/ptables/cb/mname2 type bit128", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname2", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 22, + "mname": "cb/mname2", + "mtype": "bit", + "msize": 32 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8624", + "name": "Create metadatum with mid of 4 bytes", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname mid 2147483647 type bit128", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/cb/mname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mid": 2147483647, + "mname": "cb/mname", + "mtype": "bit", + "msize": 128 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e8ae", + "name": "Dump pipeline with amount of metadata > P4TC_MSGBATCH_SIZE", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname2 type bit4", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname3 type bit4", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname4 type bit8", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname5 type bit4", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname6 type bit4", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname7 type bit8", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname8 type bit4", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname9 type bit4", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname10 type bit8", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname11 type bit4", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname12 type bit4", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname13 type bit3", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname14 type bit8", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname15 type bit1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname16 mid 2147483647 type bit5", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "metadata" + }, + { + "templates": [ + { + "mname": "cb/mname" + }, + { + "mname": "cb/mname2" + }, + { + "mname": "cb/mname3" + }, + { + "mname": "cb/mname4" + }, + { + "mname": "cb/mname5" + }, + { + "mname": "cb/mname6" + }, + { + "mname": "cb/mname7" + }, + { + "mname": "cb/mname8" + }, + { + "mname": "cb/mname9" + }, + { + "mname": "cb/mname10" + }, + { + "mname": "cb/mname11" + }, + { + "mname": "cb/mname12" + }, + { + "mname": "cb/mname13" + }, + { + "mname": "cb/mname14" + }, + { + "mname": "cb/mname15" + }, + { + "mname": "cb/mname16" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "56ef", + "name": "Flush metadata where one metadatum has mid of 4 bytes", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname2 mid 2147483647 type bit128", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/ptables/ ", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/", + "matchCount": "1", + "matchJSON": [], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1a02", + "name": "Flush empty metadata list", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/ptables/", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ptables/", + "matchCount": "1", + "matchJSON": [], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3a0e", + "name": "Delete specific metadatum by pipelne id and metadatum by id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname mid 1 type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/ pipeid 22 mid 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/ pipeid 22 mid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find metadatum by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b69c", + "name": "Try to create metadatum without name or id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/ mid 1 type bit8", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ pipeid 22 mid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find metadatum by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "287c", + "name": "Try to get metadata without supplying pipeline name or id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/cb/mname type bit8", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/cb/mname2 type bit8", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get metadata/", + "matchCount": "1", + "matchPattern": "Must specify pipeline name or id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "528d", + "name": "Try to create metadatum with name length > METANAMSIZ", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create metadata/ptables/7eozFYyaqVCD7H0xS3M5sMnluUqPgZewfSLnYPf4s3k0lbx8lKoR32zSqiGsh84qJ32vnLPdl7f2XcUh5yIdEP7uJy2C3iPtyU7159s9CMB0EtTAlWTVz4U1jkQ5h2advwp3KCVsZ1jlGgStoJL2op5ZxoThTSUQLR61a5RNDovoSFcq86Brh6oW9DSmTbN6SYygbG3JLnEHzRC5hh0jGmJKHq5ivBK9Y9FlNZQXC9wVwX4qTFAd8ITUTj2Au2Jg1 mid 42 type bit8", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get metadata/ptables/ mid 42", + "matchCount": "1", + "matchPattern": "Unable to find metadatum by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + } +] From patchwork Wed May 17 11:02:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244706 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3275E182C3 for ; Wed, 17 May 2023 11:05:35 +0000 (UTC) Received: from mail-vk1-xa2d.google.com (mail-vk1-xa2d.google.com [IPv6:2607:f8b0:4864:20::a2d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 711D55FE6 for ; Wed, 17 May 2023 04:05:23 -0700 (PDT) Received: by mail-vk1-xa2d.google.com with SMTP id 71dfb90a1353d-44ff6a049a7so256128e0c.2 for ; Wed, 17 May 2023 04:05:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321522; x=1686913522; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=/HJE5nqYcaodKpvFGoSIxBUFx2FXa/qRd48fDSg14cM=; b=j5AKA67Awold7PjDZS7b3gKTWH0/5Idi0Xu15qtzh8h3P0irP6uvb6L/oE5d6DA9jH 7VvH58GJImVmx1qgyLA9LFM0bLqXRdnrHiS2C50F6vWQXTepe5I+c+1JypwhxKhBWNYy B+6GHeMkI4YhmQ9/nQPgxA7G9pn4el13FS8QZSu7q7DWQhlgGL2xwAOdCnVy55LupYqu hzmjnwiq/mpBUUHG5KK96+COSd3m7eKv/zNYCMkyAGuzk2ahxPUMOosurpKSF8rh1JEM cnEbVCeEyER+dTk2oO4nflkfuFJ4nJBkPVcKZ1CgavH02xdzl4VbLpmXCLTT1EXU+D7l 3slA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321522; x=1686913522; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/HJE5nqYcaodKpvFGoSIxBUFx2FXa/qRd48fDSg14cM=; b=G2aVVkWVyjR630EJ1HLqa72649ZYDlz2OY+iJzPtIS4TAu3Sz0tgmv0wpFVe1c5loY raI3xO+2wbCR5EXj4XvuAPI5Z/Bb466OHDkAl75T/pGaMm8vcu797WoC+G9lsNAPK0aG 3BKkiTOKgosnUXg24DNkVa9dT7yHSw8kN87/fYMkjP7bNCUO+cBQTQWmqpaFbvt4pMOX GPg63ZwIH3CN7WoLodN+9R83/AJ928Z3uVtIXrnHOVnuCTDiORlV9HxbnuTYLAL4nBmT AVuvTzqt8NiZDZfP/kjS5UjUC3Eqss1dLJ96//llTflfUCdjZSprRzytXmpn0rT0RwDK l/Hg== X-Gm-Message-State: AC+VfDzXXCF6DtPcO7hW2N8uTQtwckh8hHmJ9jpCWZ8anEvSjs7CYErT DvyusEJP24CZMbKUyZT/mNOZNsGj0Oaay8Vt8Hs= X-Google-Smtp-Source: ACHHUZ4yxUApq9QTrnGf66AFni4iPSmiNeAbgqEywKj9+84rcMe/a2kc+ziF/XHWYafJYIYAb3KLaQ== X-Received: by 2002:a05:6102:384:b0:430:61bd:283 with SMTP id m4-20020a056102038400b0043061bd0283mr14453033vsq.11.1684321520323; Wed, 17 May 2023 04:05:20 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id c20-20020a05620a165400b0074dfd9283afsm527308qko.79.2023.05.17.04.05.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:05:19 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 23/28] selftests: tc-testing: add P4TC action templates tdc tests Date: Wed, 17 May 2023 07:02:27 -0400 Message-Id: <20230517110232.29349-23-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Introduce tdc tests for P4TC table types, which are focused on the control path. We test table type create, update, delete, flush and dump. Here is a basic description of what we test for each operation: Create: - Create valid action template - Create action templates with all possible param types - Try to create action template with param of invalid type - Create valid action template and instantiate action of new kind - Try to create action template with name > IFNAMSIZ - Try to create action template with param type > ACTPARAMNAMSIZ - Create action template with more than one param - Create action template with no params - Try to create action template with same ID twice - Try to create action template with same name twice - Try to create action template with two params and one of unknown type - Create valid action template, instantiate it and update the instance - Create valid action template, create two instances of it and dump - Create action template, add instance and bind action to filter - Create action template, add instance, bind action to filter and send packet Update: - Update action template with actions - Update action template with all param types - Try to add new param during update - Update action template param by id - Try to update inexistent action template by id - Try to update inexistent action template by name Delete: - Delete action template by name - Delete action template by id - Try to delete inexistent action template by name - Try to delete inexistent action template by id - Try to delete action template without supplying pipeline name or id - Flush action templates - Try to flush action templates without supplying pipeline name or id Dump: - Dump action template IDR using pipeline name to find pipeline - Dump action template IDR using pipeline id to find pipeline - Try to dump action templates IDR without specifying pipeline name or id - Dump action templates IDR which has more than P4TC_MAXMSG_COUNT (16) elements Tested-by: "Khan, Mohd Arif" Tested-by: "Pottimurthy, Sathya Narayana" Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- .../tc-tests/p4tc/action_templates.json | 12332 ++++++++++++++++ 1 file changed, 12332 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/action_templates.json diff --git a/tools/testing/selftests/tc-testing/tc-tests/p4tc/action_templates.json b/tools/testing/selftests/tc-testing/tc-tests/p4tc/action_templates.json new file mode 100644 index 000000000000..7b790fbe013f --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/p4tc/action_templates.json @@ -0,0 +1,12332 @@ +[ + { + "id": "c494", + "name": "Create valid action template with param type bit32", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit32", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4964", + "name": "Create valid action template with param type bit8", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit8", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit8", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2ed6", + "name": "Create valid action template with param type bit16", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit16", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit16", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ec54", + "name": "Create valid action template with param type bit64", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit64", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit64", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6c74", + "name": "Create valid action template with param type mac", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type macaddr", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "macaddr", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "bf9c", + "name": "Create valid action template with param type ipv4", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type ipv4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "ipv4", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "03f3", + "name": "Create valid action template with param type bit32 and create an instance of action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test param param1 type bit32 id 1 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit32", + "value": 4294967295, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "80f5", + "name": "Create valid action template with param type bit32 and try to bind it to different pipeline", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create pipeline/ptables2 pipeid 23 maxrules 1 numtables 2 preactions action gact index 1 postactions action ptables/test param param1 type bit32 27", + "expExitCode": "255", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchPattern": "Error: TC action with specified index not found.*", + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "782e", + "name": "Create valid action template with param type bit8 and create an instance of action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit8", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test param param1 type bit8 id 1 255", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit8", + "value": 255, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e250", + "name": "Create valid action template with param type bit16 and create an instance of action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit16", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test param param1 type bit16 id 1 65535", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit16", + "value": 65535, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "99b7", + "name": "Create valid action template with param type bit64 and create an instance of action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit64", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test param param1 type bit64 id 1 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit64", + "value": 4294967295, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "367c", + "name": "Create valid action template with param type mac and create an instance of action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type macaddr", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test param param1 type macaddr id 1 AA:BB:CC:DD:EE:FF", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "macaddr", + "value": "aa:bb:cc:dd:ee:ff", + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "315c", + "name": "Create valid action template with param type ipv4 and create an instance of action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type ipv4", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test param param1 type ipv4 id 1 10.10.10.0/24", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "ipv4", + "value": "10.10.10.0/24", + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "62b1", + "name": "Create valid action template with two params", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 param param2 type bit16", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit32", + "id": 1 + }, + { + "name": "param2", + "type": "bit16", + "id": 2 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "73a5", + "name": "Create valid action template with no params", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "c403", + "name": "Try to create action template with param of unknown type", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type notvalid", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d21f", + "name": "Try to create action template with two params and one of unknown type", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 param param2 type notvalid", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "164e", + "name": "Try to create action template with same name twice", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit64", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit32", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "de27", + "name": "Try to create action template with same id twice", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 actid 1 param param1 type bit64", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit32", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b711", + "name": "Try to create action template with name > IFNAMSIZ", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/CMPCQGOzcLG8HILTQxsQYKfDg4zQQdtmNfosyAhQxhqDTC8cg10QediAAzIMvel2Y actid 1 param param1 type bit32", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find action by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "17f3", + "name": "Try to create action template with param name > ACTPARAMNAMSIZ", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test actid 1 param oDXNP48egpqbhrFfRZxEMcJu4p2932zuTVO7ab81kXaYsLfJJWx1qF4QbohzvlLfBgS7j2Xo5wR3jQ9yuRARyFMNvGilXoufpvvwr8Z5bBaD8H80Lav8LleO5Qss5CjmE8l34Vomvn7LEEfeRTAzOCbPew7L2DuoQz2JQtyGFsZ8dEORnjFaZBZ6CGDPh68strQiFwEHUs6lUpbIxhxB6xarZGpwktZOyascnZLbc901mqrx96gnx939LpDkaNLij type bit32", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find action by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "efbf", + "name": "Update action template with commands", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test cmd set metadata.kernel.skbpeek metadata.kernel.skbidf", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit32", + "id": 1 + } + ], + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 4, + "endbit": 4, + "pname": "kernel", + "name": "skbpeek", + "id": 15 + }, + "OPB": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5bbe", + "name": "Update action template param type to bit16", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test param param1 type bit16", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit16", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e596", + "name": "Update action template param type to bit8", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test param param1 type bit8", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit8", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b74b", + "name": "Update action template param type to bit64", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test param param1 type bit64", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit64", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5d74", + "name": "Update action template param type to ipv4", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test param param1 type ipv4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "ipv4", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3b81", + "name": "Update action template param type to mac", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test param param1 type macaddr", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "macaddr", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cc31", + "name": "Try to add new param during update", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test param param1 type bit16 param param2 type bit8", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit32", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "03b7", + "name": "Update action template param by id", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32 id 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test param param1 type bit16 id 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit16", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "c695", + "name": "Try to update inexistent action template by id", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/ actid 1 param param1 type bit16 id 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/ actid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find action by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "86ef", + "name": "Try to update inexistent action template by name", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test param param1 type bit16 id 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "636f", + "name": "Create valid action template with param type bit32, create an instance of action and update it", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC actions add action ptables/test param param1 type bit32 id 1 4294967295 index 1", + 0 + ] + ], + "cmdUnderTest": "$TC actions replace action ptables/test param param1 type bit32 id 1 22 index 1", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit32", + "value": 22, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f13d", + "name": "Create valid action template with param type bit32, create an instance of action and delete it", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC actions add action ptables/test param param1 type bit32 id 1 4294967295 index 1", + 0 + ] + ], + "cmdUnderTest": "$TC actions del action ptables/test index 1", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchPattern": "Error: TC action with specified index not found.*", + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template update action/ptables/test state inactive", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "11f8", + "name": "Create valid action template with two params, create an instance of action and delete it", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32 param param2 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC actions add action ptables/test param param1 type bit32 4294967295 param param2 type bit32 22 index 1", + 0 + ] + ], + "cmdUnderTest": "$TC actions del action ptables/test index 1", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchPattern": "Error: TC action with specified index not found.*", + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template update action/ptables/test state inactive", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cccb", + "name": "Create valid action template with no params, create an instance of action and delete it", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC actions add action ptables/test index 1", + 0 + ] + ], + "cmdUnderTest": "$TC actions del action ptables/test index 1", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchPattern": "Error: TC action with specified index not found.*", + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template update action/ptables/test state inactive", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8523", + "name": "Create valid action template with param type bit32, create two instances of action and dump", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC actions add action ptables/test param param1 type bit32 id 1 4294967295 index 1", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test param param1 type bit32 id 1 42 index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j actions ls action ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 2 + }, + { + "actions": [ + { + "order": 0, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit32", + "value": 4294967295, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + }, + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit32", + "value": 42, + "id": 1 + } + ], + "index": 2, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template update action/ptables/test state inactive", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cc14", + "name": "Create action template, add instance and try to bind action to filter", + "category": [ + "p4tc", + "template" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32 id 1", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC actions add action ptables/test param param1 type bit32 id 1 4294967295", + 0 + ], + [ + "$TC qdisc add dev $DEV1 ingress", + 0 + ] + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 65535 protocol ip matchall action ptables/test index 1", + "expExitCode": "2", + "verifyCmd": "$TC -j filter get dev $DEV1 parent ffff: handle 1 prio 65535 protocol ip matchall", + "matchCount": "1", + "matchPattern": "Error: Cannot find specified filter chain.*", + "teardown": [ + [ + "$TC qdisc del dev $DEV1 ingress; sleep 1", + 0 + ], + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template update action/ptables/test state inactive", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e3e4", + "name": "Dump action templates using pname to find pipeline", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test2 actid 2 param param1 type bit64", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test3 param param1 type bit64", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "action template" + }, + { + "templates": [ + { + "aname": "ptables/test" + }, + { + "aname": "ptables/test2" + }, + { + "aname": "ptables/test3" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "25bc", + "name": "Dump action templates using pipeid to find pipeline", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test2 actid 2 param param1 type bit64", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test3 param param1 type bit64", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ pipeid 22", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "action template" + }, + { + "templates": [ + { + "aname": "ptables/test" + }, + { + "aname": "ptables/test2" + }, + { + "aname": "ptables/test3" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f1e1", + "name": "Dump action templates without specifying pipeid or pname", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test2 actid 2 param param1 type bit64", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test3 param param1 type bit64", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/", + "matchCount": "1", + "matchPattern": "Error: Must specify pipeline name or id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "dc67", + "name": "Dump action templates IDR with more than P4TC_MAXMSG_COUNT elements", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test2 param param1 type bit64", + 0 + ], + [ + "$TC p4template create action/ptables/test3 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test4 param param1 type bit64", + 0 + ], + [ + "$TC p4template create action/ptables/test5 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test6 param param1 type bit64", + 0 + ], + [ + "$TC p4template create action/ptables/test7 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test8 param param1 type bit64", + 0 + ], + [ + "$TC p4template create action/ptables/test9 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test10 param param1 type bit64", + 0 + ], + [ + "$TC p4template create action/ptables/test11 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test12 param param1 type bit64", + 0 + ], + [ + "$TC p4template create action/ptables/test13 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test14 param param1 type bit64", + 0 + ], + [ + "$TC p4template create action/ptables/test15 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test16 param param1 type bit64", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test17 param param1 type bit64", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ pipeid 22", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "action template" + }, + { + "templates": [ + { + "aname": "ptables/test" + }, + { + "aname": "ptables/test2" + }, + { + "aname": "ptables/test3" + }, + { + "aname": "ptables/test4" + }, + { + "aname": "ptables/test5" + }, + { + "aname": "ptables/test6" + }, + { + "aname": "ptables/test7" + }, + { + "aname": "ptables/test8" + }, + { + "aname": "ptables/test9" + }, + { + "aname": "ptables/test10" + }, + { + "aname": "ptables/test11" + }, + { + "aname": "ptables/test12" + }, + { + "aname": "ptables/test13" + }, + { + "aname": "ptables/test14" + }, + { + "aname": "ptables/test15" + }, + { + "aname": "ptables/test16" + } + ] + }, + { + "pname": "ptables", + "pipeid": 22, + "obj": "action template" + }, + { + "templates": [ + { + "aname": "ptables/test17" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "fd55", + "name": "Flush action templates using pname to find pipeline", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test2 actid 2 param param1 type bit64", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del action/ptables/", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/", + "matchCount": "1", + "matchJSON": [], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7e85", + "name": "Flush action templates using pipeid to find pipeline", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test2 actid 2 param param1 type bit64", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del action/ pipeid 22", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/", + "matchCount": "1", + "matchJSON": [], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f444", + "name": "Try to flush action templates without specifying pname or pipeid", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32", + 0 + ], + [ + "$TC p4template create action/ptables/test2 actid 2 param param1 type bit64", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del action/", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "action template" + }, + { + "templates": [ + { + "aname": "ptables/test" + }, + { + "aname": "ptables/test2" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "fced", + "name": "Delete action template using action name", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del action/ptables/test", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "049e", + "name": "Delete template action by actid", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del action/ pipeid 22 actid 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ pipeid 22 actid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find action by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e6e9", + "name": "Try to delete inexistent action template", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del action/ pipeid 22 actid 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ pipeid 22 actid 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find action by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4817", + "name": "Create valid action template with param type bit32, create an instance of action and try to delete action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC actions add action ptables/test param param1 type bit32 id 1 4294967295", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del action ptables/test", + "expExitCode": "255", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit32", + "value": 4294967295, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template update action/ptables/test state inactive", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4c0f", + "name": "Create valid action template and try to instantiate it without making it active", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type macaddr", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test param param1 type macaddr id 1 AA:BB:CC:DD:EE:FF", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "macaddr", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6756", + "name": "Create valid action template, make it active and try to update it", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type macaddr", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update action/ptables/test param param1 type bit64", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "macaddr", + "id": 1 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template update action/ptables/test state inactive", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a06b", + "name": "Create action template, and try to bind action to a filter", + "category": [ + "p4tc", + "template" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test actid 1 param param1 type bit32 id 1", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC qdisc add dev $DEV1 ingress", + 0 + ] + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 65535 protocol ip matchall action ptables/test param param1 type bit32 id 1 4294967295", + "expExitCode": "2", + "verifyCmd": "$TC -j filter get dev $DEV1 parent ffff: handle 1 prio 65535 protocol ip matchall", + "matchCount": "1", + "matchPattern": "Error: Cannot find specified filter chain.*", + "teardown": [ + [ + "$TC qdisc del dev $DEV1 ingress; sleep 1", + 0 + ], + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template update action/ptables/test state inactive", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3495", + "name": "Create valid action template with param type bit32 and create an instance of action with incorrect param type", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test param param1 type bit64 id 1 4294967295", + "expExitCode": "255", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchPattern": "Error: TC action with specified index not found.*", + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "84ee", + "name": "Create valid action template with cmd that sets skbmark to 4", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark constant.bit32.4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 4 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2fea", + "name": "Create valid action template with cmd that sets tcindex to 23", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.tcindex constant.bit16.23", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 15, + "container": "bit16", + "value": 23 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "51b1", + "name": "Create valid action template with cmd that sets skbptype to 7", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbptype constant.bit3.7", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 0, + "endbit": 2, + "pname": "kernel", + "name": "skbptype", + "id": 10 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 2, + "container": "bit8", + "value": 7 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "eaa2", + "name": "Create valid action template with cmd that sets skbqmap to 7000", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbqmap constant.bit16.7000", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "skbqmap", + "id": 16 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 15, + "container": "bit16", + "value": 7000 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5565", + "name": "Create valid action template with cmd that sets datalen to 80", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.pktlen constant.bit32.80", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "pktlen", + "id": 1 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 80 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0536", + "name": "Create valid action template with cmd that sets datalen to 8080", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.datalen constant.bit32.8080", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "datalen", + "id": 2 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 8080 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f2e0", + "name": "Create valid action template with cmd that sets skbhash to 0x1234", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbhash constant.bit32.0x1234", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbhash", + "id": 5 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 4660 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "49c6", + "name": "Create valid action template with cmd that sets iif to dev.lo", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.iif dev.lo", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "426d", + "name": "Create valid action template with cmd that sets skbproto to 1234", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbproto constant.be16.1234", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "be16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "skbproto", + "id": 9 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 15, + "container": "be16", + "value": 1234 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "590a", + "name": "Create valid action template with cmd that sets skbpeek to 1", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbpeek constant.bit1.1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 4, + "endbit": 4, + "pname": "kernel", + "name": "skbpeek", + "id": 15 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 0, + "container": "bit8", + "value": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "59e2", + "name": "Try to create action template with cmd that sets skbptype with constant.bit16", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbptype constant.bit16.32", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8a6f", + "name": "Try to create action template with cmd that assigns constant.bit3.70", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbptype constant.bit3.70", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1cfa", + "name": "Try to create action template with cmd that assigns constant.bit8[7-9].5", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.ptypeoff[5-7] constant.bit8[7-9].5", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9dba", + "name": "Create valid action template with cmd that sets ptypeoff[5-7] to constant.bit8[3-5].5", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.ptypeoff[5-7] constant.bit8[3-5].5", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 5, + "endbit": 7, + "pname": "kernel", + "name": "ptypeoff", + "id": 17 + }, + "OPB": { + "type": "constant", + "startbit": 3, + "endbit": 5, + "container": "bit8", + "value": 5 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8b9c", + "name": "Try to create action template with cmd that assigns to ptypeoff[7-9]", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.ptypeoff[7-9] constant.bit8[3-5].5", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8cf7", + "name": "Try to create action template with cmd that assigns constant.bit64 to tcindex", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.tcindex constant.bit64.0x5234567890678861", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8598", + "name": "Create valid action template with cmd that sets skbmark to ifindex", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark metadata.kernel.ifindex", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "metadata", + "container": "int32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "ifindex", + "id": 7 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "02e6", + "name": "Create valid action template with cmd that sets skbidf to 0", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbidf constant.bit1[0-0].0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + }, + "OPB": { + "type": "constant", + "container": "bit8", + "startbit": 0, + "endbit": 0, + "value": 0 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7e84", + "name": "Create valid action template with cmd that sets skbidf to skboook", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skboook metadata.kernel.skbidf", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 7, + "endbit": 7, + "pname": "kernel", + "name": "skboook", + "id": 13 + }, + "OPB": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a015", + "name": "Create valid action template with cmd that sets skbpeek to skbidf", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbpeek metadata.kernel.skbidf", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 4, + "endbit": 4, + "pname": "kernel", + "name": "skbpeek", + "id": 15 + }, + "OPB": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b29e", + "name": "Create valid action template with cmd that has two set commands", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark constant.bit32.1234 cmd set metadata.kernel.skbidf constant.bit1.0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "value": 1234 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + }, + "OPB": { + "type": "constant", + "container": "bit8", + "startbit": 0, + "endbit": 0, + "value": 0 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "069c", + "name": "Try to create action template with cmd that assign to skbmark[16-33]", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark[16-33] constant.bit16.0x5678 index 32", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "07f2", + "name": "Create valid action template with cmd that assigns to skbmark[0-15]", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark[0-15] constant.bit16.0x5678", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "value": 22136 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8c4e", + "name": "Create valid action template with cmd that assigns to skbmark[0-15] and skbmark[16-31]", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark[0-15] constant.bit16.0x5678 cmd set metadata.kernel.skbmark[16-31] constant.bit16.0x1234", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "value": 22136 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 16, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "value": 4660 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8b01", + "name": "Try to create action template with cmd that calls action kernel.foo", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd act kernel.foo.1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9cc5", + "name": "Try to create action template with cmd that calls instance of drop that doesn't exist", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd act kernel.drop.3", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2720", + "name": "Create valid action template with cmd that calls pipeline action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC actions add action ptables/test param param1 type bit32 id 1 4294967295 index 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test.1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test2", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test2", + "actid": 2, + "operations": [ + { + "instruction": "act", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "pipeid": 22, + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del action/ptables/test2", + 0 + ], + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "fe49", + "name": "Create valid action template with cmd that calls action ok", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act kernel.ok.1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test2", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test2", + "actid": 1, + "operations": [ + { + "instruction": "act", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "pname": "kernel", + "id": "gact" + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a79b", + "name": "Create valid action template with cmd that sets ptypeoff[0-2] to constant.bit8[1-3].7", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.ptypeoff[0-2] constant.bit8[1-3].7", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 0, + "endbit": 2, + "pname": "kernel", + "name": "ptypeoff", + "id": 17 + }, + "OPB": { + "type": "constant", + "startbit": 1, + "endbit": 3, + "container": "bit8", + "value": 7 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d1d6", + "name": "Create valid action template with cmd that sets ptypeoff[0-2] to constant.bit3.7", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.ptypeoff[0-2] constant.bit3.7", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 0, + "endbit": 2, + "pname": "kernel", + "name": "ptypeoff", + "id": 17 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 2, + "container": "bit8", + "value": 7 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "32e8", + "name": "Try to create action template with cmd that assigns ptypeoff[0-2] to constant.bit8.7", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.ptypeoff[0-2] constant.bit8.7", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b1fd", + "name": "Create valid action template with cmd that sets ptypeoff[4-4] to ptypeoff[3-3]", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.ptypeoff[4-4] metadata.kernel.ptypeoff[3-3]", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 4, + "endbit": 4, + "pname": "kernel", + "name": "ptypeoff", + "id": 17 + }, + "OPB": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "ptypeoff", + "id": 17 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2f48", + "name": "Create valid action template with cmd that uses beq", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd beq metadata.kernel.skbmark constant.bit32.4 control pipe / jump 1 cmd set metadata.kernel.skbmark constant.bit32.123 control ok cmd set metadata.kernel.skbidf constant.bit1.0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "beq", + "control_action": { + "type": "jump", + "jump": 1 + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 4 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 123 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 0, + "container": "bit8", + "value": 0 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d352", + "name": "Try to create action template with cmd that uses beq with incorrect jump value", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd beq metadata.kernel.skbmark constant.bit32.4 control pipe / jump 2 cmd set metadata.kernel.skbmark constant.bit32.123 cmd set metadata.kernel.skbidf constant.bit1.0", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "bf55", + "name": "Create valid action template with cmd that uses bne", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd bne metadata.kernel.skbmark constant.bit32.4 control pipe / jump 1 cmd set metadata.kernel.skbmark constant.bit32.123 control ok cmd set metadata.kernel.skbidf constant.bit1.0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "bne", + "control_action": { + "type": "jump", + "jump": 1 + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 4 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 123 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 0, + "container": "bit8", + "value": 0 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5d35", + "name": "Create valid action template with cmd that uses blt", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd blt metadata.kernel.skbmark constant.bit32.4 control pipe / jump 1 cmd set metadata.kernel.skbmark constant.bit32.123 control ok cmd set metadata.kernel.skbidf constant.bit1.0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "blt", + "control_action": { + "type": "jump", + "jump": 1 + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 4 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 123 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 0, + "container": "bit8", + "value": 0 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "20b3", + "name": "Create valid action template with cmd that uses bgt", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd bgt metadata.kernel.tcindex constant.bit32[0-15].4 control pipe / jump 1 cmd set metadata.kernel.tcindex constant.bit32[0-15].123 control ok cmd set metadata.kernel.skbidf constant.bit1.0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "bgt", + "control_action": { + "type": "jump", + "jump": 1 + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 15, + "container": "bit32", + "value": 4 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 15, + "container": "bit32", + "value": 123 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 0, + "container": "bit8", + "value": 0 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7b3a", + "name": "Create valid action template with cmd that uses bge", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd bge metadata.kernel.tcindex constant.bit32[0-15].4 control pipe / jump 1 cmd set metadata.kernel.tcindex constant.bit32[16-31].123 control ok cmd set metadata.kernel.skbidf constant.bit1.0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "bge", + "control_action": { + "type": "jump", + "jump": 1 + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 15, + "container": "bit32", + "value": 4 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPB": { + "type": "constant", + "startbit": 16, + "endbit": 31, + "container": "bit32", + "value": 123 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 0, + "container": "bit8", + "value": 0 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cff5", + "name": "Create valid action template with cmd that uses ble", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd ble metadata.kernel.tcindex constant.bit32[0-15].4 control pipe / jump 1 cmd set metadata.kernel.tcindex constant.bit32[16-31].123 control ok cmd set metadata.kernel.skbidf constant.bit1.0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "ble", + "control_action": { + "type": "jump", + "jump": 1 + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 15, + "container": "bit32", + "value": 4 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPB": { + "type": "constant", + "startbit": 16, + "endbit": 31, + "container": "bit32", + "value": 123 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 0, + "container": "bit8", + "value": 0 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "44c7", + "name": "Create valid action template with cmd that uses beq preceeded by a a set", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark constant.bit32.4 cmd beq metadata.kernel.skbmark constant.bit32.4 control pipe / jump 1 cmd set metadata.kernel.skbmark constant.bit32.123 control ok cmd set metadata.kernel.skbidf constant.bit1.0", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 4 + } + } + }, + { + "instruction": "beq", + "control_action": { + "type": "jump", + "jump": 1 + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 4 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 123 + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit8", + "startbit": 3, + "endbit": 3, + "pname": "kernel", + "name": "skbidf", + "id": 11 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 0, + "container": "bit8", + "value": 0 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0cca", + "name": "Create valid action template with cmd that uses print without prefix", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark constant.bit32.0x5678 cmd print metadata.kernel.skbmark", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 22136 + } + } + }, + { + "instruction": "print", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6e77", + "name": "Create valid action template with cmd that uses print with prefix", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd print prefix before metadata.kernel.skbmark cmd set metadata.kernel.skbmark constant.bit32.0x5678 cmd print prefix after metadata.kernel.skbmark", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "print", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3, + "prefix": "before" + } + } + }, + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 22136 + } + } + }, + { + "instruction": "print", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3, + "prefix": "after" + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7dbd", + "name": "Try to create action template with cmd that prints constant value", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark constant.bit32.0x5678 cmd print constant.bit32.22", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "516e", + "name": "Create valid action template with cmd that sets skbmark to ptables.mymd", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark metadata.ptables.mymd", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a797", + "name": "Create valid action template with cmd that sets skbmark to ptables.mytest64[0-31]", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark metadata.ptables.mytest64[0-31]", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "metadata", + "container": "bit64", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mytest64", + "id": 3 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f50f", + "name": "Create valid action template with cmd that sets ptables.mytest64[0-31] to skbmark", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.ptables.mytest64[0-31] metadata.kernel.skbmark", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit64", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mytest64", + "id": 3 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8631", + "name": "Create valid action template with cmd that sets ptables.mytest to constant.bit16.0x1234", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest type bit16 mid 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.ptables.mytest constant.bit16.0x1234", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "ptables", + "name": "mytest", + "id": 2 + }, + "OPB": { + "type": "constant", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "value": 4660 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "54b4", + "name": "Create valid action template with cmd that sets ptables.mytest to kernel.tcindex", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest type bit16 mid 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd set metadata.ptables.mytest metadata.kernel.tcindex", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "ptables", + "name": "mytest", + "id": 2 + }, + "OPB": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f66e", + "name": "Create valid action template with cmd that concats kernel.tcindex with kernel.skbmark and stores the result in ptables.mytest64", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest64 metadata.kernel.tcindex metadata.kernel.skbmark", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit64", + "startbit": 0, + "endbit": 63, + "pname": "ptables", + "name": "mytest64", + "id": 3 + }, + "OPB": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPC": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5c94", + "name": "Try to create action template with cmd that concats constant.bit48.0x12 with kernel.skbmark and stores the result in ptables.mytest64", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest64 metadata.kernel.skbmark constant.bit48.0x12", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4fdb", + "name": "Create valid action template with cmd that concats constant.bit32.0x12 with kernel.skbmark and stores the result in ptables.mytest64", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest64 constant.bit32.0x12 metadata.kernel.skbmark", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit64", + "startbit": 0, + "endbit": 63, + "pname": "ptables", + "name": "mytest64", + "id": 3 + }, + "OPB": { + "type": "constant", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "value": 18 + }, + "OPC": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8904", + "name": "Create valid action template with cmd that concats 3 operands", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest64 metadata.kernel.tcindex metadata.kernel.skbmark metadata.kernel.skbproto", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit64", + "startbit": 0, + "endbit": 63, + "pname": "ptables", + "name": "mytest64", + "id": 3 + }, + "OPB": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPC": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPD": { + "type": "metadata", + "container": "be16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "skbproto", + "id": 9 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "bc57", + "name": "Create valid action template with cmd that concats P4TC_CMD_EXTRA_OPERS_MAX + 3 operands", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest128 type bit128 mid 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest128 metadata.kernel.tcindex metadata.kernel.skbproto metadata.kernel.ptclnoff constant.bit8.0x11 constant.bit8.0x12 constant.bit8.0xA constant.bit8.1 constant.bit8.204", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit128", + "startbit": 0, + "endbit": 127, + "pname": "ptables", + "name": "mytest128", + "id": 4 + }, + "OPB": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPC": { + "type": "metadata", + "container": "be16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "skbproto", + "id": 9 + }, + "OPD": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "ptclnoff", + "id": 19 + }, + "OPE": { + "type": "constant", + "container": "bit8", + "startbit": 0, + "endbit": 7, + "value": 17 + }, + "OPF": { + "type": "constant", + "container": "bit8", + "startbit": 0, + "endbit": 7, + "value": 18 + }, + "OPG": { + "type": "constant", + "container": "bit8", + "startbit": 0, + "endbit": 7, + "value": 10 + }, + "OPH": { + "type": "constant", + "container": "bit8", + "startbit": 0, + "endbit": 7, + "value": 1 + }, + "OPI": { + "type": "constant", + "container": "bit8", + "startbit": 0, + "endbit": 7, + "value": 204 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0bd1", + "name": "Try to create action template with cmd that concats more than P4TC_CMD_EXTRA_OPERS_MAX + 3 operands", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest128 type bit128 mid 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest128 metadata.kernel.tcindex metadata.kernel.skbproto metadata.kernel.ptclnoff constant.bit8.0x11 constant.bit8.0x12 constant.bit8.0xA constant.bit8.1 constant.bit8.204 constant.bit8.205", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5ad4", + "name": "Try to create action template with cmd that concats a bit30 operand", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest64 metadata.kernel.skbmark constant.bit30.0x1234", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6779", + "name": "Create valid action template with concats bitslices", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest64 metadata.kernel.tcindex metadata.ptables.mymd[0-15]", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit64", + "startbit": 0, + "endbit": 63, + "pname": "ptables", + "name": "mytest64", + "id": 3 + }, + "OPB": { + "type": "metadata", + "container": "bit16", + "startbit": 0, + "endbit": 15, + "pname": "kernel", + "name": "tcindex", + "id": 4 + }, + "OPC": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 15, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b537", + "name": "Create valid action template which concats metadata to itself", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mymd metadata.ptables.mymd[0-7] metadata.ptables.mymd[8-15] metadata.ptables.mymd[16-23] metadata.ptables.mymd[24-31]", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 7, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPC": { + "type": "metadata", + "container": "bit32", + "startbit": 8, + "endbit": 15, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPD": { + "type": "metadata", + "container": "bit32", + "startbit": 16, + "endbit": 23, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPE": { + "type": "metadata", + "container": "bit32", + "startbit": 24, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a517", + "name": "Try to create action template which concats bitslice size not multiple of 8", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mymd metadata.ptables.mymd[0-7] metadata.ptables.mymd[8-15] metadata.ptables.mymd[16-24] metadata.ptables.mymd[24-31]", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0999", + "name": "Try to create action template with concat cmd which exceeds opA's size in extra operands", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mymd metadata.ptables.mymd[0-15] metadata.ptables.mymd[16-31] metadata.ptables.mymd[0-7]", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "effd", + "name": "Create action template with concat cmd where opA is a bitslice", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mymd[0-23] metadata.ptables.mymd[0-7] metadata.ptables.mymd[8-15] metadata.ptables.mymd[16-23]", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 23, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 7, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPC": { + "type": "metadata", + "container": "bit32", + "startbit": 8, + "endbit": 15, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPD": { + "type": "metadata", + "container": "bit32", + "startbit": 16, + "endbit": 23, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5a3a", + "name": "Create action template with concat cmd where opA is a bitslice not multiple of 8", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mymd[0-25] metadata.ptables.mymd[0-7] metadata.ptables.mymd[8-15] metadata.ptables.mymd[16-23]", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 25, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 7, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPC": { + "type": "metadata", + "container": "bit32", + "startbit": 8, + "endbit": 15, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPD": { + "type": "metadata", + "container": "bit32", + "startbit": 16, + "endbit": 23, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b381", + "name": "Create valid action template with concat and create an instance of action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create action/ptables/test cmd concat metadata.ptables.mymd[0-25] metadata.ptables.mymd[0-7] metadata.ptables.mymd[8-15] metadata.ptables.mymd[16-23]", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action ptables/test index 1", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC actions flush action ptables/test", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d382", + "name": "Try to create action template with cmd concats that's missing operands B and C", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest128 type bit128 mid 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest128", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "51ef", + "name": "Try to create action template with cmd concats that's missing operand C", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest128 type bit128 mid 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest128 constant.bit32.0x42", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "224b", + "name": "Try to create action template with cmd concat that's missing all operands", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest128 type bit128 mid 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test cmd concat metadata.ptables.mytest128 constant.bit32.0x42", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0ada", + "name": "Create action template with concat cmd where opB is a parameter", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd concat metadata.ptables.mytest64 param.param1 metadata.ptables.mymd", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit64", + "startbit": 0, + "endbit": 63, + "pname": "ptables", + "name": "mytest64", + "id": 3 + }, + "OPB": { + "type": "param", + "pipeid": 22, + "actid": 1, + "paramid": 1 + }, + "OPC": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cca5", + "name": "Create action template with concat cmd where opC is a parameter", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd concat metadata.ptables.mytest64 metadata.ptables.mymd param.param1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "concat", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit64", + "startbit": 0, + "endbit": 63, + "pname": "ptables", + "name": "mytest64", + "id": 3 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPC": { + "type": "param", + "pipeid": 22, + "actid": 1, + "paramid": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8b8c", + "name": "Create action template with concat cmd where opA is a parameter", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd concat param.param1 metadata.ptables.mytest64 metadata.ptables.mymd", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8928", + "name": "Create action template with concat cmd where opA is a constant", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd concat constant.bit32.0x12 metadata.ptables.mytest64 metadata.ptables.mymd", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ae2a", + "name": "Create action template with concat cmd where opA is a results.hit", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd concat results.hit metadata.ptables.mytest64 metadata.ptables.mymd", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3cb8", + "name": "Create action template with set cmd where opA is a register", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit32 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd set register.ptables.my_reg[0] metadata.ptables.mymd", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit32", + "id": 1 + } + ], + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "register", + "pid": 22, + "pname": "ptables", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "idx": 0, + "regname": "my_reg", + "regid": 1 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "bb79", + "name": "Create action template with set cmd where opA is a register and try to delete register", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit32 numelems 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32 cmd set register.ptables.my_reg[0] metadata.ptables.mymd", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del register/ptables/my_reg", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit32", + "id": 1 + } + ], + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "register", + "pid": 22, + "pname": "ptables", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "idx": 0, + "regname": "my_reg", + "regid": 1 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "487a", + "name": "Create action template with set cmd where opB is a register", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit32 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd set metadata.ptables.mymd register.ptables.my_reg[1]", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "params": [ + { + "name": "param1", + "type": "bit32", + "id": 1 + } + ], + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPB": { + "type": "register", + "pid": 22, + "pname": "ptables", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "idx": 1, + "regname": "my_reg", + "regid": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f46b", + "name": "Try to create action template with set cmd where opA is a register smaller than opB", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit32 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd set register.ptables.my_reg[1] metadata.ptables.mytest64", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1748", + "name": "Create action template with print cmd where opA is a register out-of-bounds", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit32 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd print register.ptables.my_reg[2]", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b7bf", + "name": "Create action template with concat cmd where opC is a register", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit32 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd concat metadata.ptables.mytest64 metadata.ptables.mymd register.ptables.my_reg[1]", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9164", + "name": "Try to create action template with concat cmd where opB is a register", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit32 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd concat metadata.ptables.mytest64 register.ptables.my_reg[1] metadata.ptables.mymd", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4c51", + "name": "Try to create action template with concat cmd where opA is a register", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create metadata/ptables/mytest64 type bit64 mid 3", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit32 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd concat register.ptables.my_reg[1] metadata.ptables.mytest64 metadata.ptables.mymd", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e175", + "name": "Create act command with runtime params", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32 set metadata.ptables.mymd param.param1", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test metadata.simple_l3_pna.mymd ", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test2", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test2", + "actid": 2, + "operations": [ + { + "instruction": "act", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "action", + "pipeid": 22, + "id": 1 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del action/ptables/test2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "69bf", + "name": "Create act command with runtime params and dump created action instance", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32 set metadata.ptables.mymd param.param1", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test metadata.simple_l3_pna.mymd ", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit32", + "value": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 1, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del action/ptables/test2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8c97", + "name": "Create runtime act command with no params", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create action/ptables/test set metadata.ptables.mymd constant.bit32.0x12", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test2", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test2", + "actid": 2, + "operations": [ + { + "instruction": "act", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "action", + "pipeid": 22, + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del action/ptables/test2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b745", + "name": "Create runtime act command with wrong number of params", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create action/ptables/test params param1 type bit32 set metadata.ptables.mymd param.param1", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test metadata.ptables.mymd constant.bit32.0x12", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test2", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "979d", + "name": "Create act command with P4TC_CMD_OPERS_MAX runtime params", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32 param param2 type bit32 param param3 type bit32 param param4 type bit32 param param5 type bit32 param param6 type bit32 param param7 type bit32 param param8 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test cmd print param.param1 cmd print param.param2 cmd print param.param3 cmd set metadata.ptables.mymd param.param4 cmd set metadata.ptables.mymd param.param5 cmd set metadata.ptables.mymd param.param6 cmd set metadata.ptables.mymd param.param7 cmd set metadata.ptables.mymd param.param8", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test metadata.simple_l3_pna.mymd constant.bit32.0x12 constant.bit32.32 constant.bit32.0x34 constant.bit32.97 metadata.simple_l3_pna.mymd constant.bit32.0x12 constant.bit32.0x34", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get action/ptables/test2", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test2", + "actid": 2, + "operations": [ + { + "instruction": "act", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "action", + "pipeid": 22, + "id": 1 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPC": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 18 + }, + "OPD": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 32 + }, + "OPE": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 52 + }, + "OPF": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 97 + }, + "OPG": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + }, + "OPH": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 18 + }, + "OPI": { + "type": "constant", + "startbit": 0, + "endbit": 31, + "container": "bit32", + "value": 52 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del action/ptables/test2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e0ea", + "name": "Create act command with runtime param of type bit64 and dump created action instance", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit64 print param.param1", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test constant.bit64.62", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "bit64", + "value": { + "type": "constant", + "startbit": 0, + "endbit": 63, + "container": "bit64", + "value": 62 + }, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 1, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del action/ptables/test2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "353d", + "name": "Create act command with runtime param of type macaddr and dump created action instance", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type macaddr print param.param1", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test constant.macaddr.AA:BB:CC:DD:EE:FF", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "macaddr", + "value": { + "type": "constant", + "startbit": 0, + "endbit": 47, + "container": "macaddr", + "value": "aa:bb:cc:dd:ee:ff" + }, + "id": 1 + } + ], + "index": 1, + "ref": 1, + "bind": 1, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del action/ptables/test2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1e47", + "name": "Create act command with 2 runtime params", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type macaddr param param2 type macaddr cmd print param.param1 cmd print param.param2", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test constant.macaddr.AA:BB:CC:DD:EE:FF constant.macaddr.AA:CC:BB:DD:EE:FF", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "macaddr", + "value": { + "type": "constant", + "startbit": 0, + "endbit": 47, + "container": "macaddr", + "value": "aa:bb:cc:dd:ee:ff" + }, + "id": 1 + }, + { + "name": "param2", + "type": "macaddr", + "value": { + "type": "constant", + "startbit": 0, + "endbit": 47, + "container": "macaddr", + "value": "aa:cc:bb:dd:ee:ff" + }, + "id": 2 + } + ], + "index": 1, + "ref": 1, + "bind": 1, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del action/ptables/test2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0479", + "name": "Create act command with 2 runtime params and one is of type dev", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type macaddr param param2 type dev cmd print param.param1 cmd print param.param2", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test2 cmd act ptables.test constant.macaddr.AA:BB:CC:DD:EE:FF dev.lo", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/test index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/test", + "params": [ + { + "name": "param1", + "type": "macaddr", + "value": { + "type": "constant", + "startbit": 0, + "endbit": 47, + "container": "macaddr", + "value": "aa:bb:cc:dd:ee:ff" + }, + "id": 1 + }, + { + "name": "param2", + "type": "dev", + "value": { + "type": "dev", + "dev": "lo" + }, + "id": 2 + } + ], + "index": 1, + "ref": 1, + "bind": 1, + "not_in_hw": true + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del action/ptables/test2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3845", + "name": "Create valid action template with cmd that sets skbmark to ptables.mymd and try to delete ptables.mymd", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create metadata/ptables/mymd type bit32 mid 1", + 0 + ], + [ + "$TC p4template create action/ptables/test cmd set metadata.kernel.skbmark metadata.ptables.mymd", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del metadata/ptables/mymd", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test", + "actid": 1, + "operations": [ + { + "instruction": "set", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "kernel", + "name": "skbmark", + "id": 3 + }, + "OPB": { + "type": "metadata", + "container": "bit32", + "startbit": 0, + "endbit": 31, + "pname": "ptables", + "name": "mymd", + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "62aa", + "name": "Create valid action template with cmd that calls pipeline action and try to delete action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ], + [ + "$TC actions add action ptables/test param param1 type bit32 id 1 4294967295 index 1", + 0 + ], + [ + "$TC p4template create action/ptables/test2 cmd act ptables.test.1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del action/ptables/test", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get action/ptables/test2", + "matchCount": "1", + "matchJSON": [ + { + "obj": "action template", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "aname": "ptables/test2", + "actid": 2, + "operations": [ + { + "instruction": "act", + "control_action": { + "type": "pipe" + }, + "operands": { + "OPA": { + "pipeid": 22, + "id": 1 + } + } + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "fc32", + "name": "Try call unknown pipeline action", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create action/ptables/test param param1 type bit32 cmd act ptables.test2.1", + "expExitCode": "255", + "verifyCmd": "$TC p4template get action/ptables/test", + "matchCount": "1", + "matchPattern": "Error: Action name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "578e", + "name": "Try more complex act dependency graph and delete pipeline", + "category": [ + "p4tc", + "template" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/test4 param param1 type bit32", + 0 + ], + [ + "$TC p4template update action/ptables/test4 state active", + 0 + ], + [ + "$TC actions add action ptables/test4 param param1 type bit32 id 1 4294967295 index 1", + 0 + ], + [ + "$TC p4template create action/ptables/test2 param param1 type bit32 cmd act ptables.test4.1", + 0 + ], + [ + "$TC p4template update action/ptables/test2 state active", + 0 + ], + [ + "$TC actions add action ptables/test2 param param1 type bit32 id 1 4294967295 index 1", + 0 + ], + [ + "$TC p4template create action/ptables/test3 param param1 type bit32 cmd act ptables.test4.1 cmd act ptables.test2.1", + 0 + ], + [ + "$TC p4template update action/ptables/test3 state active", + 0 + ], + [ + "$TC p4template create action/ptables/test param param1 type bit32 cmd act ptables.test2.1", + 0 + ], + [ + "$TC p4template update action/ptables/test state active", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del pipeline/ptables", + "expExitCode": "0", + "verifyCmd": "$TC p4template get pipeline/ptables", + "matchCount": "1", + "matchPattern": "Error: Pipeline name not found.*", + "teardown": [] + } +] From patchwork Wed May 17 11:02:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244707 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF2D41DDDF for ; Wed, 17 May 2023 11:05:46 +0000 (UTC) Received: from mail-qk1-x72a.google.com (mail-qk1-x72a.google.com [IPv6:2607:f8b0:4864:20::72a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8886D7689 for ; Wed, 17 May 2023 04:05:30 -0700 (PDT) Received: by mail-qk1-x72a.google.com with SMTP id af79cd13be357-7577ef2fa31so632552485a.0 for ; Wed, 17 May 2023 04:05:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321529; x=1686913529; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=fUma7lV/3tmSantUd8Ip1FQCsixBu6aFsqKTbSzv9xg=; b=1U6O/Enb/o8iStEDfe46ESwsCKQzqJ8Mq3kjm3eSNcZ/6jrcuQFe5UDYdimX4Df+XU G26iN5KyikXirxGISPwoAugLcsr8DlNvcWSsB0JPpD7eY7u6UaiZns6Z0KwdDIb0TRKF sgU0OgzQbyCZHIqOO81SEaY+JuWHm8AU4dyD2tRKAP+ddZEEVhMvjMJEelBjNx5CUcNe EQ9Wbjjj2EygRyT/d2qLkEXpk2Ga7YFpLk4blp04gnXRr5SAEMa93qIaMxAtTzU9mnFZ j6FRqWoTMWM3lnnNf/n8jzOnIqVSnzte8DGJN59EeKJlLxx5ydRVNUhmjPXrTPmOIVUq /Dxw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321529; x=1686913529; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fUma7lV/3tmSantUd8Ip1FQCsixBu6aFsqKTbSzv9xg=; b=efTyBVIL61UCG8JvG2v0eJpBsN5ESSIB+W4ayG7DorHt81I06oPziCrcFuZITamLaw CiCVBYE/+eUkysGbY0HtFI0Vm1+L3jN1ONX1l537daZdKY2I3Bl8VCeH4aTUz61sEJCD pu+YAHOPyzmLs7/09JjD9VbN7jxpE9WQH022pDVkUZflHLt09HJcOY6AkNrWSWmp0gfM s0pCcNIBeK9uTRzRgadTQveEjKwojD0iCe+StrvnM2cA89GokbBaOcOUUBzpe89YNFvQ u8CrxyVSQ562KLtqEFUptKX6QjSME62W0OIbGJ9LdoIVNKHNBgILorKQx9upSEzMdnpE cNyQ== X-Gm-Message-State: AC+VfDwY+RSabGYf+fgBV1oY/xS66XIQ60jxThAqq89dc6Ir7dlJt2YP Gf5W0zIuydVpine5K3zsXIa1ErLaxTCbNvACSME= X-Google-Smtp-Source: ACHHUZ7WUPUJSMNSg1qC+AVR1n7qov5/RZYhDy0ULBZHbrlVoHKzK1FLaS+fToHriO7SP1xfohOUkg== X-Received: by 2002:a05:622a:28e:b0:3f3:9fbc:321b with SMTP id z14-20020a05622a028e00b003f39fbc321bmr2492917qtw.29.1684321528116; Wed, 17 May 2023 04:05:28 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id p20-20020a05620a15f400b007595267ef0bsm535014qkm.34.2023.05.17.04.05.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:05:27 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 24/28] selftests: tc-testing: add P4TC table control path tdc tests Date: Wed, 17 May 2023 07:02:28 -0400 Message-Id: <20230517110232.29349-24-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Introduce tdc tests for P4TC table, which are focused on the control path. We test table create, update, delete, flush and dump. Here is a basic description of what we test for each operation: Create: - Create valid table - Try to create table without specifying mandatory arguments - Create table without specifying optional arguments and check optional values after creation - Try to create table passing invalid arguments - Try to create table with same name twice - Try to create table with same id twice - Create a table with table id == INX_MAX (2147483647) and check for overflow warning when traversing table IDR - Try to create table with name length > TTYPENAMSIZ - Try to create table without specifying pipeline name or id - Create valid table with more than one key - Try to create table adding more than P4TC_MAXPARSE_KEYS keys - Create table and update pipeline state - Create table, update pipeline state and try to update pipeline after pipeline is sealed - Create table, update pipeline state and try to update table type after pipeline is sealed - Create table with keys with more than one action Update: - Update table with valid argument values - Try to update table with invalid argument values - Try to update table without specifying table name or id - Try to update table without specifying pipeline name or id - Try to update table with invalid values - Check action bind and ref values after table's key's action - Check action bind and ref values after table's postaction update - Update table and add new key without specifying id - Try to update table adding more P4TC_MAXPARSE_KEYS keys - Update table key with more than one action - Try to create more table then numtclass in pipeline Delete: - Delete table by name - Delete table by id - Delete nonexistent table by name - Delete nonexistent table by id - Try to delete table without supplying pipeline name or id - Flush table - Try to flush table without supplying pipeline name or id - Check action bind and ref values after table deletion Dump: - Dump table IDR using pipeline name to find pipeline - Dump table IDR using pipeline id to find pipeline - Try to dump table IDR without specifying pipeline name or id - Dump table IDR which has more than P4TC_MAXMSG_COUNT (16) elements Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- .../tc-testing/tc-tests/p4tc/table.json | 8896 +++++++++++++++++ 1 file changed, 8896 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/table.json diff --git a/tools/testing/selftests/tc-testing/tc-tests/p4tc/table.json b/tools/testing/selftests/tc-testing/tc-tests/p4tc/table.json new file mode 100644 index 000000000000..74f128cc95b9 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/p4tc/table.json @@ -0,0 +1,8896 @@ +[ + { + "id": "60b7", + "name": "Create valid table", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 1, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a540", + "name": "Create valid table without preactions", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 16 key action gact index 3 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 1, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4765", + "name": "Try to create table without name", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/ keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Error: Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3d3c", + "name": "Try to create table without keysz", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Error: Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b48a", + "name": "Try to create table with keysz zero", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 0 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cc89", + "name": "Try to create table with keysz > P4TC_MAX_KEYSZ", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 513 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "efba", + "name": "Try to create table with tentries > P4TC_MAX_TENTRIES", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 16 tentries 16777217 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a24a", + "name": "Create table with tentries = P4TC_MAX_TENTRIES", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 tentries 16777216 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 16777216, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "67b7", + "name": "Try to create table with tentries zero", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 16 tentries 0 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e8e8", + "name": "Try to create table with nummasks > P4TC_MAX_TMASKS", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 16 tmasks 129 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6b5b", + "name": "Create table wth nummasks = P4TC_MAX_TMASKS", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 nummasks 128 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 128, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "615c", + "name": "Try to create table with nummasks zero", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 16 nummasks 0 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ef97", + "name": "Create table with specific tt_id", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 42, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7a0f", + "name": "Try to create table same name twice", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 16 key action gact index 1 preactions gact index 4 postactions gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 1, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "bd8d", + "name": "Try to create table same id twice", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname2 tblid 22 keysz 16 key action gact index 1 preactions gact index 4 postactions gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/ tblid 22", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "eeaf", + "name": "Try to create table without supplying pipeline name or id", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ tblid 1 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f35d", + "name": "Create table without supplying keys", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname keysz 16 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 1, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b3c9", + "name": "Try to create table with name size > TCLASSNAMSIZ", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/7eozFYyaqVCD7H0xS3M5sMnluUqPgZewfSLnYPf4s3k0lbx8lKoR32zSqiGsh84qJ32vnLPdl7f2XcUh5yIdEP7uJy2C3iPtyU7159s9CMB0EtTAlWTVz4U1jkQ5h2advwp3KCVsZ1jlGgStoJL2op5ZxoThTSUQLR61a5RNDovoSFcq86Brh6oW9DSmTbN6SYygbG3JLnEHzRC5hh0jGmJKHq5ivBK9Y9FlNZQXC9wVwX4qTFAd8ITUTj2Au2Jg1 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f3a5", + "name": "Try to create table with invalid action", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname2 keysz 16 key action connmark zone 103 reclassify index 1 action connmark goto chain 42 index 90 cookie c1a0c1a0 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b3ec", + "name": "Try to create table with invalid action index", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname2 keysz 16 key action connmark zone 103 reclassify index 1 action connmark goto chain 42 index 90 cookie c1a0c1a0 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "40b0", + "name": "Create table with tblid of 4 bytes", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action gact pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action gact pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 2147483647 keysz 16 key action gact index 1 preactions gact index 4 postactions gact index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/ tblid 2147483647", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "table" + }, + { + "templates": [ + { + "tblid": 2147483647, + "tname": "cb/tname" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "eea7", + "name": "Update table's key size specifying table name", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/cb/tname keysz 32", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 32, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5d07", + "name": "Update table's key size specifying table id", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ pipeid 22 tblid 22 keysz 32", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 32, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "46f5", + "name": "Try to update table's key size with zero", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 keysz 0", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8306", + "name": "Try to update table's key size with > P4TC_MAX_KEYSZ", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 keysz 513", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0d12", + "name": "Update table's with key size = P4TC_MAX_KEYSZ", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 keysz 512", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 512, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "67c0", + "name": "Try to update table tentries with zero", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 tentries 0", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "dfd1", + "name": "Try to update table wth tentries > P4TC_MAX_TENTRIES", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 tentries 16777217", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "36e3", + "name": "Update table with tentries = P4TC_MAX_TENTRIES", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 tentries 16777216", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 16777216, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "5c80", + "name": "Try to update table masks with zero", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 nummasks 0", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "011b", + "name": "Try to update table with nummasks > P4TC_MAX_TMASKS", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 nummasks 129", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "102b", + "name": "Update table with nummasks = P4TC_MAX_TMASKS", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 nummasks 128", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 128, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ac3d", + "name": "Update table's postaction", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 5", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 postactions gact index 5", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/ tblid 22", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 2, + "bind": 1 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 5, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "64e5", + "name": "Update table's postaction and check old actions ref count and bind", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 5", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 postactions gact index 5", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action gact index 4", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "kind": "gact", + "index": 4, + "ref": 2, + "bind": 1 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "80c9", + "name": "Update table's keys and check old keys's action reference", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 5", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 6", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 key action gact index 5", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action gact index 3", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "kind": "gact", + "index": 3, + "ref": 1, + "bind": 0 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a7f3", + "name": "Delete table by name", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ptables/cb/tname", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Error: Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9524", + "name": "Delete table by id", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ptables/ tblid 22", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/ tblid 22", + "matchCount": "1", + "matchPattern": "Error: Unable to find table by id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "c41b", + "name": "Try to delete inexistent table by name", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ptables/cb/tname2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "faca", + "name": "Try to delete inexistent table by id", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ptables/ tblid 44", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/ tblid 22", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6da7", + "name": "Try to delete table without supplying pipeline name or id", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ tblid 22", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/ tblid 22", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a844", + "name": "Flush table", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ptables/", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Error: Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7f88", + "name": "Try to flush table without supplying pipeline name or id", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 3, + "bind": 2 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 5, + "bind": 4 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 5, + "bind": 4 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "778c", + "name": "Create table with key size > P4TC_MAX_KEYSZ", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 22 keysz 513 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Error: Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "64ed", + "name": "Create table with key size = P4TC_MAX_KEYSZ", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 22 keysz 512 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 512, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "508b", + "name": "Create table and update pipeline state", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ptables state ready", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 2, + "pstate": "ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ac1a", + "name": "Create table, update pipeline state and try to update pipeline after pipeline is sealed", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ptables maxrules 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get pipeline/ptables", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "pipeline" + }, + { + "templates": [ + { + "pmaxrules": 1, + "pnumtables": 2, + "pstate": "ready", + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1, + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + } + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 2, + "ref": 2, + "bind": 1 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0fb8", + "name": "Create table, update pipeline state and try to update table after pipelien is sealed", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/cb/tname2 keysz 32", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname2", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 42, + "tname": "cb/tname2", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 3, + "bind": 2 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 5, + "bind": 4 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 5, + "bind": 4 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "32a6", + "name": "Create table with keys with more than one action", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 42 keysz 16 key action gact index 3 action gact index 4 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 42, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + }, + { + "order": 2, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ade0", + "name": "Update table key with more than one action", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 5", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 42 keysz 16 key action gact index 3 action gact index 4 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/cb/tname key action gact index 4 action gact index 5", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 42, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + }, + { + "order": 2, + "kind": "gact", + "control_action": { + "type": "drop" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 5, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "95f5", + "name": "Update table's key", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 5", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/cb/tname key action gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 42, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "aa0d", + "name": "Update table key with more than one action and check actions after", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 5", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 42 keysz 16 key action gact index 3 action gact index 4 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/cb/tname key action gact index 4 action gact index 5", + "expExitCode": "0", + "verifyCmd": "$TC -j actions ls action gact", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 5 + }, + { + "actions": [ + { + "kind": "gact", + "index": 1, + "ref": 2, + "bind": 1 + }, + { + "kind": "gact", + "index": 2, + "ref": 2, + "bind": 1 + }, + { + "kind": "gact", + "index": 3, + "ref": 1, + "bind": 0 + }, + { + "kind": "gact", + "index": 4, + "ref": 4, + "bind": 3 + }, + { + "kind": "gact", + "index": 5, + "ref": 2, + "bind": 1 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e5e1", + "name": "Dump table using pipeline name to find pipeline", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 3 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname3 tblid 50 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "table" + }, + { + "templates": [ + { + "tname": "cb/tname" + }, + { + "tname": "cb/tname2" + }, + { + "tname": "cb/tname3" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7f04", + "name": "Dump table using pipeline id to find pipeline", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 3 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname3 tblid 50 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ pipeid 22", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "table" + }, + { + "templates": [ + { + "tname": "cb/tname" + }, + { + "tname": "cb/tname2" + }, + { + "tname": "cb/tname3" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "96c5", + "name": "Try to create more table then numtables", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname3 tblid 50 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "table" + }, + { + "templates": [ + { + "tname": "cb/tname" + }, + { + "tname": "cb/tname2" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e3fa", + "name": "Try to dump table without specifying pipeline name or id", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 42 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname3 tblid 50 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/", + "matchCount": "1", + "matchPattern": "Error: Must specify pipeline name or id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6bcf", + "name": "Dump pipeline with amount of table > P4TC_MSGBATCH_SIZE", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action gact pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action gact pass index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action gact pass index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action gact pass index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 17 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname4 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname5 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname6 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname7 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname8 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname9 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname10 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname11 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname12 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname13 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname14 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname15 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname16 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname17 tblid 2147483647 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "table" + }, + { + "templates": [ + { + "tname": "cb/tname" + }, + { + "tname": "cb/tname2" + }, + { + "tname": "cb/tname3" + }, + { + "tname": "cb/tname4" + }, + { + "tname": "cb/tname5" + }, + { + "tname": "cb/tname6" + }, + { + "tname": "cb/tname7" + }, + { + "tname": "cb/tname8" + }, + { + "tname": "cb/tname9" + }, + { + "tname": "cb/tname10" + }, + { + "tname": "cb/tname11" + }, + { + "tname": "cb/tname12" + }, + { + "tname": "cb/tname13" + }, + { + "tname": "cb/tname14" + }, + { + "tname": "cb/tname15" + }, + { + "tname": "cb/tname16" + } + ] + }, + { + "pname": "ptables", + "pipeid": 22, + "obj": "table" + }, + { + "templates": [ + { + "tname": "cb/tname17" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2eb0", + "name": "Try to create valid table without control block name", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/tname keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Error: Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6d73", + "name": "Update table default_hit after pipeline is sealed", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/MyIngress/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/MyIngress/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4 table_acts act name ptables/MyIngress/reclassify flags defaultonly", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 default_hit_action action ptables/MyIngress/reclassify", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "default_hit": { + "actions": [ + { + "order": 1, + "kind": "ptables/MyIngress/reclassify", + "index": 1, + "ref": 1, + "bind": 1, + "params": [] + } + ], + "permissions": "CRUDXCRUDX" + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b0e8", + "name": "Update table default_miss after pipeline is sealed", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/MyIngress/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/MyIngress/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4 table_acts act name ptables/MyIngress/reclassify flags defaultonly", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 default_miss_action permissions 0x37F action ptables/MyIngress/reclassify", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "default_miss": { + "actions": [ + { + "order": 1, + "kind": "ptables/MyIngress/reclassify", + "index": 1, + "ref": 1, + "bind": 1, + "params": [] + } + ], + "permissions": "CR-DXCRUDX" + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d13e", + "name": "Try to update table default_hit with permissions with more than 10 bits", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 default_hit_action permissions 0x337F", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1991", + "name": "Try to update table default_miss with permissions with more than 10 bits", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 default_miss_action permissions 0x337F", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cf57", + "name": "Try to update table default_miss after control update permissions are off", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/MyIngress/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/MyIngress/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4 table_acts act name ptables/MyIngress/reclassify", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4template update table/ptables/ tblid 22 default_miss_action permissions 0x37F action ptables/MyIngress/reclassify", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 default_miss_action action drop", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "default_miss": { + "actions": [ + { + "order": 1, + "kind": "ptables/MyIngress/reclassify", + "index": 1, + "ref": 1, + "bind": 1, + "params": [] + } + ], + "permissions": "CR-DXCRUDX" + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "fa6c", + "name": "Try to update table default_hit after control update permissions are off", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/MyIngress/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/MyIngress/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4 table_acts act name ptables/MyIngress/reclassify", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4template update table/ptables/ tblid 22 default_hit_action permissions 0x37F action ptables/MyIngress/reclassify", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/ tblid 22 default_hit_action action drop", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "default_hit": { + "actions": [ + { + "order": 1, + "kind": "ptables/MyIngress/reclassify", + "index": 1, + "ref": 1, + "bind": 1, + "params": [] + } + ], + "permissions": "CR-DXCRUDX" + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7a70", + "name": "Delete only table default_hit", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/MyIngress/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/MyIngress/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4 table_acts act name ptables/MyIngress/reclassify", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4template update table/ptables/ tblid 22 default_hit_action action ptables/MyIngress/reclassify", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ptables/ tblid 22 default_hit_action", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6afa", + "name": "Try to delete only table default_hit when delete permissions is off", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/MyIngress/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/MyIngress/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4 table_acts act name ptables/MyIngress/reclassify", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4template update table/ptables/ tblid 22 default_hit_action permissions 0x3BF action ptables/MyIngress/reclassify", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ptables/ tblid 22 default_hit_action", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "19cc", + "name": "Delete _only table default_miss", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/MyIngress/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/MyIngress/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4 table_acts act name ptables/MyIngress/reclassify", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4template update table/ptables/ tblid 22 default_miss_action action ptables/MyIngress/reclassify", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ptables/ tblid 22 default_miss_action", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f3b2", + "name": "Try to delete only table default_miss when delete permissions is off", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/MyIngress/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/MyIngress/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4 table_acts act name ptables/MyIngress/reclassify", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4template update table/ptables/ tblid 22 default_miss_action permissions 0x3BF action ptables/MyIngress/reclassify", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del table/ptables/ tblid 22 default_miss_action", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 4, + "bind": 3 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "07b9", + "name": "Create table specifying permissions", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 permissions 0x1FF key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "permissions": "-RUDXCRUDX", + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "07fd", + "name": "Create table specifying permissions with more than 10 bits", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 permissions 0x4FF key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Error: Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b635", + "name": "Update table permissions", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 permissions 0x1FF key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/cb/tname permissions 0x3F key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "permissions": "----XCRUDX", + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a226", + "name": "Try to update table permissions with 0x400", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/cb/tname permissions 0x400 key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "obj": "table", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "tblid": 22, + "tname": "cb/tname", + "keysz": 16, + "max_entries": 256, + "masks": 8, + "permissions": "CRUD--R--X", + "key": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "pass" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 3, + "ref": 2, + "bind": 1 + } + ] + }, + "preactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + }, + "postactions": { + "actions": [ + { + "order": 1, + "kind": "gact", + "control_action": { + "type": "reclassify" + }, + "prob": { + "random_type": "none", + "control_action": { + "type": "pass" + }, + "val": 0 + }, + "index": 4, + "ref": 3, + "bind": 2 + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9539", + "name": "Try to create table without specifying data execute permission", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create table/ptables/cb/tname tblid 22 keysz 16 permissions 0x3FE key action gact index 3 preactions gact index 4 postactions gact index 4", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname", + "matchCount": "1", + "matchPattern": "Error: Table name not found.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + } +] From patchwork Wed May 17 11:02:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244708 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7EC6C1DDDF for ; Wed, 17 May 2023 11:06:04 +0000 (UTC) Received: from mail-qt1-x82f.google.com (mail-qt1-x82f.google.com [IPv6:2607:f8b0:4864:20::82f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 000FE83F3 for ; Wed, 17 May 2023 04:05:37 -0700 (PDT) Received: by mail-qt1-x82f.google.com with SMTP id d75a77b69052e-3f38e1142d0so4193441cf.2 for ; Wed, 17 May 2023 04:05:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321537; x=1686913537; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Hlrz+owYXMH7aAgiJ5DKBA+7qsnsb77hrupC/4RFuO0=; b=zCXt+gCnqDckxiUSXP//MxM9H4SNSGUe8GPRe1THhPg3g2eLgJ1oL1hGOxzYkaat9w b+6ztR4t5keoC2YLIyQ99O3onwteTgLq6akaxlSFaUkU/xncSwhXdl9mRrf1nP+Q+vNY 4JSZrbUEYRDsycNXRBHytch7KADLSCHickJglEMA29Dse9OzJt5EL7YbvE9nVy3J2owP QKlTOOOan/a7E4H+/X5RdWUEh1qwuc9lnK/6/zQ94S+Pu3FVlVwKVKkQZWp8qQLLgctk 883nwreYzEUl5nXWtYxWpju1Y4l5ixPxWufS7QpNm40gcK8mGQt5mpljXuJnFSGSTwNn /S2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321537; x=1686913537; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Hlrz+owYXMH7aAgiJ5DKBA+7qsnsb77hrupC/4RFuO0=; b=dE2yt376pSJt3XlGMzs+S+FWZiVnB2fEvwzPBORv1NZxCLWEmxjBIc+g9/r0sHQqG0 bhqqhDdo6vGfTMw1MiTfftkRDxlk3vT9CV2kfljeYHhn7TE1ckX+kl5VH5I46IHjkgwM rpQwu8o2r7OEac/nr95Ln3MduvCG1dPpFZCLaykvQRZnqrNZrjrhbKnZKxwBpFrTOn6v 48xuJWbTUP5AlbC8xOIoZRGwqbhMxJBaCyUxEoThnkEOSmtwwucX9AlKsptSPtSqZEl5 hzLgWgwMVrlcUKZ1cbB0sRhuBDKtvyGgJRdWgSES2nucInPBbJXx3xZpgAtQqOiN9Stv 0HAg== X-Gm-Message-State: AC+VfDyIkZrYhbQC4F8/OE4ZT8RySwZHGd/5aK3GNjhR0dPcIjJTD11j KSw87Eh7x8w0RKQebnbVT6t7cmUlCoUUQ6wDR/Q= X-Google-Smtp-Source: ACHHUZ6onb8kCLItR0Suxz2fg/f7+SQpGai58fl+Jklmh3C4GUq93y0xIHMMGCjC5J515cGEPv/pnA== X-Received: by 2002:a05:622a:d0:b0:3f4:fe39:f76e with SMTP id p16-20020a05622a00d000b003f4fe39f76emr33673659qtw.18.1684321535442; Wed, 17 May 2023 04:05:35 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id a13-20020aed278d000000b003ef1586721dsm6961276qtd.26.2023.05.17.04.05.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:05:34 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 25/28] selftests: tc-testing: add P4TC table entries control path tdc tests Date: Wed, 17 May 2023 07:02:29 -0400 Message-Id: <20230517110232.29349-25-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Introduce tdc tests for P4TC table entries, which are focused on the control path. We test table instance create, update, delete, flush and dump. Create: - Create valid table entry with all possible key types - Try to create table entry without specifying mandatory arguments - Try to create table entry passing invalid arguments - Try to create table entry with same key and prio twice - Try to create table entry without sealing the pipeline - Try to create table entry with action of unknown kind - Try to exceed max table entries count Update: - Try to update table entry with action of inexistent kind - Try to update table entry with action of unknown kind - Update table entry with new action - Create table entry with action and then update table entry with another action - Create table entry with action, update table entry with another action and check action's refs and binds - Create table entry without action and then update table entry with another action - Try to update inexistent table entry Delete: - Delete table entry - Try to delete inexistent table entry - Try to delete table entry without specifying mandatory arguments - Delete table entry specifying IDs for the pipeline and its components (table class and table instance) - Delete table entry specifying names for the pipeline and its components (table class and table instance) - Delete table entry with action and check action's refs and binds Flush: - Flush table entries - Flush table entries specifying IDS for pipeline and its components (table class and table instance) - Flush table entries specifying names for pipeline and its components (table class and table instance) - Try to flush table entries without specifying mandatory arguments Dump: - Dump table entries - Dump table entries specifying IDS for pipeline and its components (table class and table instance) - Dump table entries specifying names for pipeline and its components (table class and table instance) - Try to dump table entries without specifying mandatory arguments - Dump table instance with zero table entries - Dump table instance with more than P4TC_MAXMSG_COUNT entries Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- .../tc-tests/p4tc/table_entries.json | 4183 +++++++++++++++++ 1 file changed, 4183 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/table_entries.json diff --git a/tools/testing/selftests/tc-testing/tc-tests/p4tc/table_entries.json b/tools/testing/selftests/tc-testing/tc-tests/p4tc/table_entries.json new file mode 100644 index 000000000000..4be49d63f91f --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/p4tc/table_entries.json @@ -0,0 +1,4183 @@ +[ + { + "id": "4bfd", + "name": "Create valid table entry with args bit16", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 2, + "prio": 16, + "key": [ + { + "keyfield": "srcPort", + "id": 1, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 80 + }, + { + "keyfield": "dstPort", + "id": 2, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 443 + } + ], + "create_whodunnit": "tc", + "permissions": "-RUD--R--X" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d574", + "name": "Create valid table entry with args and check entries count", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get table/ptables/cb/tname2", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "table" + }, + { + "templates": [ + { + "tname": "cb/tname2", + "keysz": 32, + "max_entries": 256, + "masks": 8, + "entries": 1 + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6c21", + "name": "Create valid table entry with args ipv4", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 17", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 17", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 1, + "prio": 17, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 17", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a486", + "name": "Create valid table entry with args bit8, bit32, bit64", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 3, + "prio": 1, + "key": [ + { + "keyfield": "randomKey1", + "id": 1, + "width": 8, + "type": "bit8", + "match_type": "exact", + "fieldval": 255 + }, + { + "keyfield": "randomKey2", + "id": 2, + "width": 32, + "type": "bit32", + "match_type": "exact", + "fieldval": 92 + }, + { + "keyfield": "randomKey3", + "id": 3, + "width": 64, + "type": "bit64", + "match_type": "exact", + "fieldval": 127 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "13d9", + "name": "Try to create table entry without table name or id", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/ randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0b7c", + "name": "Try to create table entry without specifying any keys", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname3 prio 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "c2e7", + "name": "Create table entry without specifying priority", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 3, + "prio": 1, + "key": [ + { + "keyfield": "randomKey1", + "id": 1, + "width": 8, + "type": "bit8", + "match_type": "exact", + "fieldval": 255 + }, + { + "keyfield": "randomKey2", + "id": 2, + "width": 32, + "type": "bit32", + "match_type": "exact", + "fieldval": 92 + }, + { + "keyfield": "randomKey3", + "id": 3, + "width": 64, + "type": "bit64", + "match_type": "exact", + "fieldval": 127 + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC -j p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "dff1", + "name": "Try to get table entry without specifying priority", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/cb/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/cb/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4 table_acts act name ptables/cb/reclassify flags tableonly", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1 action ptables/cb/reclassify", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 2 action ptables/cb/reclassify", + "expExitCode": "0", + "verifyCmd": "$TC p4 get ptables/table/cb/tname3/ randomKey1 255 randomKey2 92 randomKey3 127", + "matchCount": "1", + "matchPattern": "Error: Must specify table entry priority.*", + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 2", + 0 + ], + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9a1e", + "name": "Try to create more table entries than allowed", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 tentries 1 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2095", + "name": "Try to create more table entries than allowed after delete", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 tentries 3 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 17", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 18", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4e6a", + "name": "Try to create more table entries than allowed after flush", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 tentries 1 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ], + [ + "$TC p4 del ptables/table/cb/tname", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "65a2", + "name": "Create two entries with same key and different priorities and check first one", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.1.0/16 prio 15", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 1, + "prio": 16, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a49c", + "name": "Create two entries with same key and different priorities and check second one", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.1.0/16 prio 15", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.1.0/16 prio 15", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 1, + "prio": 15, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.1.0/16" + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2314", + "name": "Try to create same entry twice", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.1.0/16 prio 16", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 1, + "prio": 16, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7d41", + "name": "Try to create table entry in unsealed pipeline", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d732", + "name": "Try to create table entry with action of inexistent kind", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16 action noexist index 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "525a", + "name": "Try to update table entry with action of inexistent kind", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + 0 + ] + ], + "cmdUnderTest": "$TC p4 update ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16 action noexist index 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 2, + "prio": 16, + "key": [ + { + "keyfield": "srcPort", + "id": 1, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 80 + }, + { + "keyfield": "dstPort", + "id": 2, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 443 + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ee04", + "name": "Update table entry and add action", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/cb/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/cb/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4 table_acts act name ptables/cb/reclassify flags tableonly", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 update ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1 action ptables/cb/reclassify", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 3, + "prio": 1, + "key": [ + { + "keyfield": "randomKey1", + "id": 1, + "width": 8, + "type": "bit8", + "match_type": "exact", + "fieldval": 255 + }, + { + "keyfield": "randomKey2", + "id": 2, + "width": 32, + "type": "bit32", + "match_type": "exact", + "fieldval": 92 + }, + { + "keyfield": "randomKey3", + "id": 3, + "width": 64, + "type": "bit64", + "match_type": "exact", + "fieldval": 127 + } + ], + "create_whodunnit": "tc", + "update_whodunnit": "tc", + "actions": { + "actions": [ + { + "order": 1, + "kind": "ptables/cb/reclassify", + "index": 1, + "ref": 1, + "bind": 1, + "params": [] + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "10b5", + "name": "Update table entry and replace action", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/cb/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/cb/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4 table_acts act name ptables/cb/reclassify flags tableonly", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1 action ptables/cb/reclassify", + 0 + ] + ], + "cmdUnderTest": "$TC p4 update ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1 action ptables/cb/reclassify index 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 3, + "prio": 1, + "key": [ + { + "keyfield": "randomKey1", + "id": 1, + "width": 8, + "type": "bit8", + "match_type": "exact", + "fieldval": 255 + }, + { + "keyfield": "randomKey2", + "id": 2, + "width": 32, + "type": "bit32", + "match_type": "exact", + "fieldval": 92 + }, + { + "keyfield": "randomKey3", + "id": 3, + "width": 64, + "type": "bit64", + "match_type": "exact", + "fieldval": 127 + } + ], + "create_whodunnit": "tc", + "update_whodunnit": "tc", + "actions": { + "actions": [ + { + "order": 1, + "kind": "ptables/cb/reclassify", + "index": 2, + "ref": 1, + "bind": 1, + "params": [] + } + ] + } + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2d50", + "name": "Update table entry, replace action and check for action refs and binds", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/cb/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/cb/reclassify state active", + 0 + ], + [ + "$TC actions add action ptables/cb/reclassify index 1", + 0, + 1, + 255 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4 table_acts act name ptables/cb/reclassify flags tableonly", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1 action ptables/cb/reclassify index 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 update ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1 action ptables/cb/reclassify index 2; sleep 1;", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/cb/reclassify index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/cb/reclassify", + "index": 1, + "ref": 1, + "bind": 0, + "params": [] + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "99ef", + "name": "Try to update inexistent table entry", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 update ptables/table/cb/tname3 randomKey1 255 randomKey2 1 randomKey3 127 prio 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 3, + "prio": 1, + "key": [ + { + "keyfield": "randomKey1", + "id": 1, + "width": 8, + "type": "bit8", + "match_type": "exact", + "fieldval": 255 + }, + { + "keyfield": "randomKey2", + "id": 2, + "width": 32, + "type": "bit32", + "match_type": "exact", + "fieldval": 92 + }, + { + "keyfield": "randomKey3", + "id": 3, + "width": 64, + "type": "bit64", + "match_type": "exact", + "fieldval": 127 + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8868", + "name": "Try to update table entry without specifying priority", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/cb/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/cb/reclassify state active", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4 table_acts act name ptables/cb/reclassify flags tableonly", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 update ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 action ptables/cb/reclassify", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 3, + "prio": 1, + "key": [ + { + "keyfield": "randomKey1", + "id": 1, + "width": 8, + "type": "bit8", + "match_type": "exact", + "fieldval": 255 + }, + { + "keyfield": "randomKey2", + "id": 2, + "width": 32, + "type": "bit32", + "match_type": "exact", + "fieldval": 92 + }, + { + "keyfield": "randomKey3", + "id": 3, + "width": 64, + "type": "bit64", + "match_type": "exact", + "fieldval": 127 + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "339a", + "name": "Try to update table entry without specifying table name or id", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 update ptables/table/ randomKey1 255 randomKey2 92 randomKey3 127 prio 1 action gact index 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 3, + "prio": 1, + "key": [ + { + "keyfield": "randomKey1", + "id": 1, + "width": 8, + "type": "bit8", + "match_type": "exact", + "fieldval": 255 + }, + { + "keyfield": "randomKey2", + "id": 2, + "width": 32, + "type": "bit32", + "match_type": "exact", + "fieldval": 92 + }, + { + "keyfield": "randomKey3", + "id": 3, + "width": 64, + "type": "bit64", + "match_type": "exact", + "fieldval": 127 + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3962", + "name": "Delete table entry", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "fcc7", + "name": "Try to delete table entry without specyfing tblid or table name", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 del ptables/table/ randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3/ randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 3, + "prio": 1, + "key": [ + { + "keyfield": "randomKey1", + "id": 1, + "width": 8, + "type": "bit8", + "match_type": "exact", + "fieldval": 255 + }, + { + "keyfield": "randomKey2", + "id": 2, + "width": 32, + "type": "bit32", + "match_type": "exact", + "fieldval": 92 + }, + { + "keyfield": "randomKey3", + "id": 3, + "width": 64, + "type": "bit64", + "match_type": "exact", + "fieldval": 127 + } + ] + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "e79d", + "name": "Try to delete table entry without specifying prio", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 2", + "expExitCode": "0", + "verifyCmd": "$TC p4 del ptables/table/cb/tname3/ randomKey1 255 randomKey2 92 randomKey3 127", + "matchCount": "1", + "matchPattern": "Error: Must specify table entry priority.*", + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 2", + 0 + ], + [ + "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "c5be", + "name": "Delete table entry with action and check action's refs and binds", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create action/ptables/cb/reclassify actid 7 cmd act kernel.gact.4", + 0 + ], + [ + "$TC p4template update action/ptables/cb/reclassify state active", + 0 + ], + [ + "$TC actions add action ptables/cb/reclassify index 1", + 0, + 1, + 255 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4 table_acts act name ptables/cb/reclassify flags tableonly", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1 action ptables/cb/reclassify", + 0 + ] + ], + "cmdUnderTest": "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1; sleep 1", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action ptables/cb/reclassify index 1", + "matchCount": "1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "ptables/cb/reclassify", + "index": 1, + "ref": 1, + "bind": 0, + "params": [] + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4ac6", + "name": "Try to delete inexistent table entry", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname3 tblid 3 keysz 104 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 del ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname3 randomKey1 255 randomKey2 92 randomKey3 127 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "24a1", + "name": "Flush table entries", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 del ptables/table/cb/tname", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9770", + "name": "Flush table entries using table name", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 del ptables/table/cb/tname", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "c5b9", + "name": "Flush table entries without specifying table name or id", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4 del ptables/table/", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 1, + "prio": 1, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.56.0/24" + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "03f7", + "name": "Dump table entries", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 1, + "prio": 1, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.56.0/24" + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0caa", + "name": "Try to dump table entries without specifying table name or id", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.56.0/24 prio 1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/", + "matchCount": "1", + "matchPattern": "Error: Must specify table name or id.*", + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6a9e", + "name": "Try to dump table entries when no entries were created", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update pipeline/ptables state ready", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname", + "matchCount": "1", + "matchJSON": [], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1406", + "name": "Dump table with more than P4TC_MAXMSG_COUNT entries", + "category": [ + "p4tc", + "entries" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname tblid 1 keysz 64 key action gact index 3 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 1", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 2", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 3", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 4", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 5", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 6", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 7", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 8", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 9", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 10", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 11", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 12", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 13", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 14", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 15", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 16", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname srcAddr 10.10.10.0/24 dstAddr 192.168.0.0/16 prio 17", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 1, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 16, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 15, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 14, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 13, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 12, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 11, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 10, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 9, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 8, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 7, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 6, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 5, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 4, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 3, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + }, + { + "tblid": 1, + "prio": 2, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + } + ] + }, + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 1, + "key": [ + { + "keyfield": "srcAddr", + "id": 1, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "10.10.10.0/24" + }, + { + "keyfield": "dstAddr", + "id": 2, + "width": 32, + "type": "ipv4", + "match_type": "exact", + "fieldval": "192.168.0.0/16" + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2515", + "name": "Try to create table entry without permission", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 permissions 0x1FF key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "f803", + "name": "Try to create table entry without more permissions than allowed", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 permissions 0x3C9 key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16 permissions 0x1CF", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "matchCount": "1", + "matchPattern": "Error: Unable to find entry.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0de2", + "name": "Try to update table entry without permission", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 permissions 0x3FF key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16 permissions 0x16F", + 0 + ] + ], + "cmdUnderTest": "$TC p4 update ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 2, + "prio": 16, + "key": [ + { + "keyfield": "srcPort", + "id": 1, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 80 + }, + { + "keyfield": "dstPort", + "id": 2, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 443 + } + ], + "create_whodunnit": "tc", + "permissions": "-R-DX-RUDX" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname2", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4540", + "name": "Try to delete table entry without permission", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 permissions 0x3FF key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16 permissions 0x1AF", + 0 + ] + ], + "cmdUnderTest": "$TC p4 del ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 2, + "prio": 16, + "key": [ + { + "keyfield": "srcPort", + "id": 1, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 80 + }, + { + "keyfield": "dstPort", + "id": 2, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 443 + } + ], + "create_whodunnit": "tc", + "permissions": "-RU-X-RUDX" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 update ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16 permissions 0x1EF", + 0 + ], + [ + "$TC p4 del ptables/table/cb/tname2/", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "51cb", + "name": "Simulate constant entries", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 permissions 0x3FF key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update table/ptables/cb/tname2 permissions 0x1FF", + "expExitCode": "0", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname2/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 2, + "prio": 16, + "key": [ + { + "keyfield": "srcPort", + "id": 1, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 80 + }, + { + "keyfield": "dstPort", + "id": 2, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 443 + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname2/", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3ead", + "name": "Simulate constant entries and try to add additional entry", + "category": [ + "p4tc", + "template", + "table" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action drop index 2", + 0, + 1, + 255 + ], + [ + "$TC actions add action ok index 3", + 0, + 1, + 255 + ], + [ + "$TC actions add action reclassify index 4", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 1 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create table/ptables/cb/tname2 tblid 2 keysz 32 permissions 0x3FF key action gact index 3 preactions gact index 4 postactions gact index 4", + 0 + ], + [ + "$TC p4template update pipeline/ptables state ready", + 0 + ], + [ + "$TC p4 create ptables/table/cb/tname2 srcPort 80 dstPort 443 prio 16", + 0 + ], + [ + "$TC p4template update table/ptables/cb/tname2 permissions 0x1FF", + 0 + ] + ], + "cmdUnderTest": "$TC p4 create ptables/table/cb/tname2 srcPort 53 dstPort 53 prio 17", + "expExitCode": "255", + "verifyCmd": "$TC -j p4 get ptables/table/cb/tname2/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22 + }, + { + "entries": [ + { + "tblid": 2, + "prio": 16, + "key": [ + { + "keyfield": "srcPort", + "id": 1, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 80 + }, + { + "keyfield": "dstPort", + "id": 2, + "width": 16, + "type": "bit16", + "match_type": "exact", + "fieldval": 443 + } + ], + "create_whodunnit": "tc" + } + ] + } + ], + "teardown": [ + [ + "$TC p4 del ptables/table/cb/tname2/", + 0 + ], + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + } +] From patchwork Wed May 17 11:02:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244709 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E60671DDDF for ; Wed, 17 May 2023 11:06:18 +0000 (UTC) Received: from mail-qk1-x72e.google.com (mail-qk1-x72e.google.com [IPv6:2607:f8b0:4864:20::72e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F417330F8 for ; Wed, 17 May 2023 04:05:46 -0700 (PDT) Received: by mail-qk1-x72e.google.com with SMTP id af79cd13be357-7576516c81fso67416885a.1 for ; Wed, 17 May 2023 04:05:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321543; x=1686913543; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BL35yyXNwClrPRFha7W8sjO2f0qLjYPdtmb6ayESYhM=; b=BX1DcrXoD4wahrdNMKV71S4WwZ02XHfKYZ1JXyxBP7jCbPeLApWoHCkZWDElJjcXAx SoQEfHXwL5D9f4ChG4gXllDXTqFyiHchat6Ud8ePumJ0vSn/MKsRytoadzESZ8RHICMS njUg3AKHQdglOm9Im+Pu7X4jrJEpUw2HbrMNw4Y3w9JEqHzVvYwqhIUM6eaK28VHB503 zqiFvLi1k5T5Y6tNSwIPOyDJCN22X4jbp37jK3BwFbyvfJ0JlIT6uAm/tIz9xu2CQ8EL ncafof+/NmkQBsyE5I3i78THs/NP8tUDUmxIRdKAICvNMSaQ5cI0aqFepPepk+AJqLwx 79/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321543; x=1686913543; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BL35yyXNwClrPRFha7W8sjO2f0qLjYPdtmb6ayESYhM=; b=GkZdqt+pFcqojVrYXcC4NnQcurHLXhvg8Gne9iIZnsY8gO/JeHwCVtm+YKix9UV54Z zW8kXGyiMuGr/4hrpWrnMxGRXwZ61P5r5e9jai+5+81cRiahbEt+pJPj4hiWO6pK/MwV NmIlo7almFG9xuxPMb1tdntrWeU+Pq4vR1wXhAEJK5GzfBrG7ruOGAQgP7ZLNVK4cpyk WNQZXPfpR0jJ4YSQi+FGsRXSLBBx1XM5TGspDvgQFa5qd5bZILYrec5o997fj3LQaz1d k6wxhDcZSQ12gUa7fw0yDBRRS4MZ6oaEuUULGfINbmoqF5HXhJqn6goU+gyy8p/iUsfR 55Sw== X-Gm-Message-State: AC+VfDx6FipWGO+p3EoVliUV6QzgEUREJGU0WpZJXstzWT/el8w+P2an FVhowJaTAbvdpOMYTudoOZi8TmdhfLg72Oq+W1k= X-Google-Smtp-Source: ACHHUZ5QlFiKdBUa+jQLksuL8zyIAGYJ8IMTtdVuaPncT8cClUD8PHe94ZYD6YorP4h6cKU+WU5uIQ== X-Received: by 2002:a05:622a:1a21:b0:3ef:36d0:c06e with SMTP id f33-20020a05622a1a2100b003ef36d0c06emr75278258qtb.33.1684321542742; Wed, 17 May 2023 04:05:42 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id s16-20020a05622a1a9000b003ef573e24cfsm6945184qtc.12.2023.05.17.04.05.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:05:42 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 26/28] selftests: tc-testing: add P4TC register tdc tests Date: Wed, 17 May 2023 07:02:30 -0400 Message-Id: <20230517110232.29349-26-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- .../tc-testing/tc-tests/p4tc/register.json | 2752 +++++++++++++++++ 1 file changed, 2752 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/register.json diff --git a/tools/testing/selftests/tc-testing/tc-tests/p4tc/register.json b/tools/testing/selftests/tc-testing/tc-tests/p4tc/register.json new file mode 100644 index 000000000000..64c54a493277 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/p4tc/register.json @@ -0,0 +1,2752 @@ +[ + { + "id": "c312", + "name": "Create valid register", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type bit32 numelems 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit32", + "startbit": 0, + "endbit": 31, + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6240", + "name": "Create valid register with num_elems == P4TC_MAX_REGISTER_ELEMS", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type bit32 numelems 128", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit32", + "startbit": 0, + "endbit": 31, + "numelems": 128 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "849c", + "name": "Try to create register with num_elems > P4TC_MAX_REGISTER_ELEMS", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type bit32 numelems 129", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "062d", + "name": "Try to create register with unknown type", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type invalid123 numelems 128", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b811", + "name": "Try to create register with num_elems = 0", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type bit32 numelems 0", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6428", + "name": "Try to create register without specifying type", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg numelems 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "a989", + "name": "Try to create register without specifying register name or id", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables type bit32 numelems 129", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "40a0", + "name": "Try to create register without specifying pipeline name or id", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ type bit32 numelems 129", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "004c", + "name": "Try to create register with name > REGISTERNAMSIZ", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/7eozFYyaqVCD7H0xS3M5sMnluUqPgZewfSLnYPf4s3k0lbx8lKoR32zSqiGsh84qJ32vnLPdl7f2XcUh5yIdEP7uJy2C3iPtyU7159s9CMB0EtTAlWTVz4U1jkQ5h2advwp3KCVsZ1jlGgStoJL2op5ZxoThTSUQLR61a5RNDovoSFcq86Brh6oW9DSmTbN6SYygbG3JLnEHzRC5hh0jGmJKHq5ivBK9Y9FlNZQXC9wVwX4qTFAd8ITUTj2Au2Jg1 type bit32 numelems 127", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6d37", + "name": "Create valid register with type bit 37", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type bit37 numelems 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 36, + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "ec58", + "name": "Create valid register with signed type", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type int37 numelems 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "int64", + "startbit": 0, + "endbit": 36, + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d2ee", + "name": "Try to create register with type int129", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type int129 numelems 1", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "50d1", + "name": "Create valid register with type ipv4", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type ipv4 numelems 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "ipv4", + "startbit": 0, + "endbit": 31, + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "418b", + "name": "Try to create register with same name twice", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg type ipv4 numelems 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 55, + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "095d", + "name": "Try to create register with same id twice", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 regid 1 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/my_reg2 regid 1 type ipv4 numelems 2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 55, + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "4ecf", + "name": "Update register index 0 with value 256", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ptables/my_reg index 0 value constant.bit56.256", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 55, + "values": [ + { + "my_reg[0]": 256 + }, + { + "my_reg[1]": 0 + } + ], + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1af9", + "name": "Update register index 1 with value 62", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit32 regid 1 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ptables/my_reg index 1 value constant.bit32.62", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/ regid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit32", + "startbit": 0, + "endbit": 31, + "values": [ + { + "my_reg[0]": 0 + }, + { + "my_reg[1]": 62 + } + ], + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9f4d", + "name": "Update register specifying pipeid", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 regid 1 numelems 2", + 0 + ], + [ + "$TC p4template update register/ptables/my_reg index 0 value constant.bit56.123", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ pipeid 22 regid 1 index 1 value constant.bit56.0x123", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/ regid 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 55, + "values": [ + { + "my_reg[0]": 123 + }, + { + "my_reg[1]": 291 + } + ], + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6181", + "name": "Update register index 0 and check only value of index 0", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ptables/my_reg index 0 value constant.bit56.256", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg index 0", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "my_reg[0]": 256 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "3d3d", + "name": "Update register index 1 and check only value of index 1", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ptables/my_reg index 1 value constant.bit56.0x123", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg index 1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "my_reg[1]": 291 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cd47", + "name": "Update register index 127 and check only value of index 127", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit44 numelems 128", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ptables/my_reg index 127 value constant.bit44.0x1234", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg index 127", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "my_reg[127]": 4660 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8966", + "name": "Try to update register with index out of range", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit44 numelems 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ptables/my_reg index 0 value constant.bit44.0x1234", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg index 1", + "matchCount": "1", + "matchPattern": "Error: Register index out of bounds", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "77b3", + "name": "Try to update register index 1 and numelems", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ptables/my_reg index 1 value constant.bit56.25 numelems 22", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 55, + "values": [ + { + "my_reg[0]": 0 + }, + { + "my_reg[1]": 0 + } + ], + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "fd51", + "name": "Try to update register index out of bounds", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ptables/my_reg index 2 value constant.bit56.22", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 55, + "values": [ + { + "my_reg[0]": 0 + }, + { + "my_reg[1]": 0 + } + ], + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7b36", + "name": "Try to update inexistent register", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ptables/my_reg index 0 value constant.int32.0x12", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1079", + "name": "Try to update register without specifying pipeline name or id", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ index 0 value constant.bit56.2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 55, + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "8199", + "name": "Try to update register without specifying register name or id", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ pipeid 22 index 0 value constant.bit56.2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 55, + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "6520", + "name": "Try to update register with bitsz bigger than bit64", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg type bit56 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ pipeid 22 index 0 value constant.bit77.2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit64", + "startbit": 0, + "endbit": 55, + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "d3b4", + "name": "Try to update register index with wrong type", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg regid 1 type bit24 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ regid 1 pipeid 22 index 0 value constant.bit33.2", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit32", + "startbit": 0, + "endbit": 23, + "values": [ + { + "my_reg[0]": 0 + }, + { + "my_reg[1]": 0 + } + ], + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "7154", + "name": "Try to update register index with bit32 when type is bit24", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg regid 1 type bit24 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ regid 1 pipeid 22 index 0 value constant.bit32.0xFFFFFFFF", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit32", + "startbit": 0, + "endbit": 23, + "values": [ + { + "my_reg[0]": 0 + }, + { + "my_reg[1]": 0 + } + ], + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "eeef", + "name": "Try to update register index with constant bit24 doesn't fix in bit24", + "category": [ + "p4tc", + "template", + "register" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/my_reg regid 1 type bit24 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template update register/ regid 1 pipeid 22 index 0 value constant.bit24.0xFFFFFFFF", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/my_reg", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "my_reg", + "regid": 1, + "containertype": "bit32", + "startbit": 0, + "endbit": 23, + "values": [ + { + "my_reg[0]": 0 + }, + { + "my_reg[1]": 0 + } + ], + "numelems": 2 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "1f5e", + "name": "Dump registers using pname to find pipeline", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/reg1 type bit8 numelems 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/reg2 type bit27 numelems 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "register" + }, + { + "templates": [ + { + "regname": "reg1" + }, + { + "regname": "reg2" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "08c9", + "name": "Dump registers using pipeid to find pipeline", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/reg1 type bit8 numelems 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/reg2 type bit27 numelems 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ pipeid 22", + "matchCount": "1", + "matchJSON": [ + { + "pname": "ptables", + "pipeid": 22, + "obj": "register" + }, + { + "templates": [ + { + "regname": "reg1" + }, + { + "regname": "reg2" + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "9782", + "name": "Try to dump registers without specifying pipeline name or id", + "category": [ + "p4tc", + "template", + "metadata" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0 + ], + [ + "$TC actions add action pass index 2", + 0 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/reg1 type bit8 numelems 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template create register/ptables/reg2 type bit27 numelems 2", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/", + "matchCount": "1", + "matchPattern": "Must specify pipeline name or id.*", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "2781", + "name": "Delete register by name", + "category": [ + "p4tc", + "template", + "registers" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/register1 type bit8 numelems 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del register/ptables/register1", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/register1", + "matchCount": "1", + "matchPattern": "Error: Register name not found", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "50d2", + "name": "Delete register by id", + "category": [ + "p4tc", + "template", + "registers" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/register1 regid 5 type bit8 numelems 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del register/ptables/ regid 5", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/ regid 5", + "matchCount": "1", + "matchPattern": "Error: Unable to find register by id", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "0b3c", + "name": "Delete register specifying pipeid", + "category": [ + "p4tc", + "template", + "registers" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/register1 regid 5 type bit8 numelems 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del register/ pipeid 22 regid 5", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/ regid 5", + "matchCount": "1", + "matchPattern": "Error: Unable to find register by id", + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "cd7f", + "name": "Try to delete register without specifying pipeline name or id", + "category": [ + "p4tc", + "template", + "registers" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/register1 regid 5 type bit8 numelems 1", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del register/", + "expExitCode": "255", + "verifyCmd": "$TC -j p4template get register/ptables/register1", + "matchCount": "1", + "matchJSON": [ + { + "obj": "register", + "pname": "ptables", + "pipeid": 22 + }, + { + "templates": [ + { + "regname": "register1", + "regid": 5, + "containertype": "bit8", + "startbit": 0, + "endbit": 7, + "numelems": 1 + } + ] + } + ], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "07cf", + "name": "Flush registers", + "category": [ + "p4tc", + "template", + "registers" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/register1 type bit8 numelems 1", + 0 + ], + [ + "$TC p4template create register/ptables/register2 type bit21 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del register/ptables/", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ptables/", + "matchCount": "1", + "matchJSON": [], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + }, + { + "id": "b69d", + "name": "Flush registers specifying pipeline id", + "category": [ + "p4tc", + "template", + "registers" + ], + "setup": [ + [ + "$TC p4template del pipeline/ptables", + 0, + 1, + 255 + ], + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 1", + 0, + 1, + 255 + ], + [ + "$TC actions add action pass index 2", + 0, + 1, + 255 + ], + [ + "$TC p4template create pipeline/ptables pipeid 22 maxrules 1 numtables 2 preactions action gact index 1 postactions action gact index 2", + 0 + ], + [ + "$TC p4template create register/ptables/register1 type bit8 numelems 1", + 0 + ], + [ + "$TC p4template create register/ptables/register2 type bit21 numelems 2", + 0 + ] + ], + "cmdUnderTest": "$TC p4template del register/ pipeid 22", + "expExitCode": "0", + "verifyCmd": "$TC -j p4template get register/ pipeid 22", + "matchCount": "1", + "matchJSON": [], + "teardown": [ + [ + "$TC p4template del pipeline/ptables", + 0 + ], + [ + "$TC actions flush action gact", + 0 + ] + ] + } +] From patchwork Wed May 17 11:02:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244711 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D62361DDDF for ; Wed, 17 May 2023 11:06:26 +0000 (UTC) Received: from mail-qt1-x82b.google.com (mail-qt1-x82b.google.com [IPv6:2607:f8b0:4864:20::82b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3CA066E9A for ; Wed, 17 May 2023 04:05:53 -0700 (PDT) Received: by mail-qt1-x82b.google.com with SMTP id d75a77b69052e-3f4eb166122so4314301cf.3 for ; Wed, 17 May 2023 04:05:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321551; x=1686913551; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=CVlUpHb2wa6E++t32XHblnni3yJWNs5ljUTavffb/N0=; b=sY2+rY9/Dn5ADnHG/jIhMZ12bXxadNsThaypCX/DpU6JqoR+SovgaZIaH8+quioiyu LxWtXexECJRni5IUuQzqKi8P6MH9cJvI7l3IgvehSesppTE/QKRxY+yXZN41grgKi13d NIpWGeTTusFN37VswQyWeK1UWGdoxEiGOX1qIPxn0jWqcj0tkmCwXgbFootPPSd3Y4NU KCkhahSbpLOlXMtP5aVrDmrftZ+94Q3xowUKAeabskAWV9c3H3u02T8iwkoM20SY/7s4 s+OEsEkmVU1lKazrOcGiQtC2muYFDJz/4tzSUt7DbaoRTA7FHBS5HpPpwgYJLBkloj4D 9j0A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321551; x=1686913551; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CVlUpHb2wa6E++t32XHblnni3yJWNs5ljUTavffb/N0=; b=D+gKIzyWs9gzE2vLj3Wec0AQ+etdetUAK49m87xCEWj9/Gz6jn63K8ge/nDnRdvBBh xyNJwOf7M7T0btuYQz9ZGMZVkqjGNu5yHhYV99tDf+32brpKb/qPSrJIzyGDOru0ztjk Cc/ZiFZInrBf5kg0iKnwtbB8GOrKiuGFlO+8Xg7qzmdhUT4uM873InDsf/2DRy4sXgxW eelRSDtKYWFPzgMV7eaMtYiUf3xOBemniWNOEuBud+LyIxjsehi3O/5HnqszyNpsTWMN +yUpz3kBvhqiA3RpAjsjhsBhzJ1WhcUJm+nrZ5G16af3hAu3fp5A8ztnafz2hB7enfHI ywKw== X-Gm-Message-State: AC+VfDwj+cGKf9q3uByeh3xvbVAsZ3A1+xL0nQQ6ex1mjA2Q5m3Brx4x aJfszm8puWNNFHMKLDd/WXDG0p67UQ6PcYHU9xw= X-Google-Smtp-Source: ACHHUZ77322ucpxFoBuXN/adUgNPEjN5D3fhHZZSGdU/XNFHz/aEYQdCU/IR2NaPB74rHw51eAcYcQ== X-Received: by 2002:a05:622a:613:b0:3f1:e81f:288 with SMTP id z19-20020a05622a061300b003f1e81f0288mr62207016qta.68.1684321550195; Wed, 17 May 2023 04:05:50 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id u6-20020a05622a17c600b003ef189ffa82sm6972867qtk.90.2023.05.17.04.05.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:05:49 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 27/28] p4tc: add set of P4TC table lookup kfuncs Date: Wed, 17 May 2023 07:02:31 -0400 Message-Id: <20230517110232.29349-27-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC We add an initial set of kfuncs to allow table lookups from eBPF programs. - bpf_skb_p4tc_tbl_lookup: Used to lookup a table entry from a BPF program installed in TC. To find the table entry we take in an skb, the pipeline ID, the table ID, a key and a key size. We use the skb to get the network namespace structure where all the pipelines are stored. After that we use the pipeline ID and the table ID, to find the table. We then use the key to search for the entry. We return an entry on success and NULL on failure. - bpf_xdp_p4tc_tbl_lookup: Used to lookup a table entry from a BPF program installed in XDP. To find the table entry we take in an skb, the pipeline ID, the table ID, a key and a key size. We use struct xdp_md to get the network namespace structure where all the pipelines are stored. After that we use the pipeline ID and the table ID, to find the table. We then use the key to search for the entry. We return an entry on success and NULL on failure. To load the eBPF program that uses the bpf_skb_p4tc_tbl_lookup kfunc into TC, we issue the following command: tc filter add dev $P0 ingress protocol any prio 1 p4 pname redirect_srcip \ action bpf obj $PROGNAME.o section p4prog/tc To load the eBPF program that uses the bpf_xdp_p4tc_tbl_lookup into XDP, we first need to load it into XDP using, for example, the ip command: ip link set $P0 xdp obj $PROGNAME.o section p4prog/xdp verbose Then we pin it: bpftool prog pin id $ID pin /tmp/ After that we create the P4 filter and reference the XDP program: $TC filter add dev $P0 ingress protocol ip prio 1 p4 pname redirect_srcip \ prog xdp pinned /tmp/xdp_p4prog prog_cookie 22 Note that we also specify a "prog_cookie", which is used to verify whether the eBPF program has executed or not before we reach the P4 classifier. The eBPF program sets this cookie by using the kfunc bpf_p4tc_set_cookie. Co-developed-by: Victor Nogueira Signed-off-by: Victor Nogueira Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- include/linux/bitops.h | 1 + include/linux/filter.h | 3 + include/net/p4tc.h | 94 +++++++++++++++++++- net/core/filter.c | 10 +++ net/sched/Kconfig | 7 ++ net/sched/cls_p4.c | 4 + net/sched/p4tc/Makefile | 8 +- net/sched/p4tc/p4tc_action.c | 90 ++++++++++++++++++- net/sched/p4tc/p4tc_bpf.c | 72 +++++++++++++++ net/sched/p4tc/p4tc_hdrfield.c | 2 + net/sched/p4tc/p4tc_pipeline.c | 135 +++++++++++++++++++++++++++- net/sched/p4tc/p4tc_table.c | 156 ++++++++++++++++++++++++++++++++- net/sched/p4tc/p4tc_tbl_api.c | 115 +++++++++++++++++++++--- net/sched/p4tc/p4tc_tmpl_api.c | 9 ++ 14 files changed, 682 insertions(+), 24 deletions(-) diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 2ba557e067fe..290c2399ad18 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -19,6 +19,7 @@ #define BITS_TO_LONGS(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) #define BITS_TO_U64(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u64)) #define BITS_TO_U32(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u32)) +#define BITS_TO_U16(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u16)) #define BITS_TO_BYTES(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) extern unsigned int __sw_hweight8(unsigned int w); diff --git a/include/linux/filter.h b/include/linux/filter.h index bbce89937fde..ebcc0ac50656 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -577,6 +577,9 @@ typedef unsigned int (*bpf_dispatcher_fn)(const void *ctx, const struct bpf_insn *insnsi, unsigned int (*bpf_func)(const void *, const struct bpf_insn *)); +#ifndef CONFIG_NET_P4_TC_KFUNCS +extern int is_p4tc_kfunc(const struct bpf_reg_state *reg); +#endif static __always_inline u32 __bpf_prog_run(const struct bpf_prog *prog, const void *ctx, diff --git a/include/net/p4tc.h b/include/net/p4tc.h index 53d519149d09..34e78fd3c183 100644 --- a/include/net/p4tc.h +++ b/include/net/p4tc.h @@ -37,11 +37,13 @@ struct p4tc_percpu_scratchpad { u32 prog_cookie; +#ifndef CONFIG_NET_P4_TC_KFUNCS u32 keysz; u32 maskid; u8 key[BITS_TO_BYTES(P4TC_MAX_KEYSZ)]; u8 hdrs[BITS_TO_BYTES(HEADER_MAX_LEN)]; u8 metadata[BITS_TO_BYTES(META_MAX_LEN)]; +#endif }; DECLARE_PER_CPU(struct p4tc_percpu_scratchpad, p4tc_percpu_scratchpad); @@ -105,6 +107,7 @@ struct p4tc_template_common { extern const struct p4tc_template_ops p4tc_pipeline_ops; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_act_dep_edge_node { struct list_head head; u32 act_id; @@ -115,24 +118,31 @@ struct p4tc_act_dep_node { struct list_head head; u32 act_id; }; +#endif struct p4tc_pipeline { struct p4tc_template_common common; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct idr p_meta_idr; +#endif struct idr p_act_idr; struct idr p_tbl_idr; struct idr p_reg_idr; struct rcu_head rcu; struct net *net; struct p4tc_parser *parser; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct tc_action **preacts; int num_preacts; struct tc_action **postacts; int num_postacts; struct list_head act_dep_graph; struct list_head act_topological_order; +#endif u32 max_rules; +#ifndef CONFIG_NET_P4_TC_KFUNCS u32 p_meta_offset; +#endif u32 num_created_acts; refcount_t p_ref; refcount_t p_ctrl_ref; @@ -143,8 +153,28 @@ struct p4tc_pipeline { refcount_t p_hdrs_used; }; +#define P4TC_PIPELINE_MAX_ARRAY 32 + +struct p4tc_table; + +struct p4tc_tbl_cache_key { + u32 pipeid; + u32 tblid; +}; + +extern const struct rhashtable_params tbl_cache_ht_params; + +int p4tc_tbl_cache_insert(struct net *net, u32 pipeid, struct p4tc_table *table); +void p4tc_tbl_cache_remove(struct net *net, struct p4tc_table *table); +struct p4tc_table *p4tc_tbl_cache_lookup(struct net *net, u32 pipeid, u32 tblid); + +#define P4TC_TBLS_CACHE_SIZE 32 + struct p4tc_pipeline_net { - struct idr pipeline_idr; +#ifdef CONFIG_NET_P4_TC_KFUNCS + struct list_head tbls_cache[P4TC_TBLS_CACHE_SIZE]; +#endif + struct idr pipeline_idr; }; int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx, @@ -182,6 +212,7 @@ static inline bool pipeline_sealed(struct p4tc_pipeline *pipeline) return pipeline->p_state == P4TC_STATE_READY; } +#ifndef CONFIG_NET_P4_TC_KFUNCS void tcf_pipeline_add_dep_edge(struct p4tc_pipeline *pipeline, struct p4tc_act_dep_edge_node *edge_node, u32 vertex_id); @@ -194,7 +225,9 @@ int determine_act_topological_order(struct p4tc_pipeline *pipeline, struct p4tc_act; void tcf_pipeline_delete_from_dep_graph(struct p4tc_pipeline *pipeline, struct p4tc_act *act); +#endif +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_metadata { struct p4tc_template_common common; struct rcu_head rcu; @@ -209,6 +242,7 @@ struct p4tc_metadata { }; extern const struct p4tc_template_ops p4tc_meta_ops; +#endif struct p4tc_table_key { struct tc_action **key_acts; @@ -224,8 +258,24 @@ struct p4tc_table_key { #define P4TC_PERMISSIONS_UNINIT (1 << P4TC_PERM_MAX_BIT) +#ifdef CONFIG_NET_P4_TC_KFUNCS +#define P4TC_MAX_PARAM_DATA_SIZE 124 + +struct p4tc_table_entry_act_bpf { + u32 act_id; + u8 params[P4TC_MAX_PARAM_DATA_SIZE]; +} __packed; +#endif + +struct p4tc_parser_buffer_act_bpf { + u16 hdrs[BITS_TO_U16(HEADER_MAX_LEN)]; +}; + struct p4tc_table_defact { struct tc_action **default_acts; +#ifdef CONFIG_NET_P4_TC_KFUNCS + struct p4tc_table_entry_act_bpf *defact_bpf; +#endif /* Will have 2 5 bits blocks containing CRUDX (Create, read, update, * delete, execute) permissions for control plane and data plane. * The first 5 bits are for control and the next five are for data plane. @@ -242,13 +292,18 @@ struct p4tc_table_perm { struct p4tc_table { struct p4tc_template_common common; + struct list_head tbl_cache_node; struct list_head tbl_acts_list; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_table_key *tbl_key; +#endif struct idr tbl_masks_idr; struct ida tbl_prio_idr; struct rhltable tbl_entries; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct tc_action **tbl_preacts; struct tc_action **tbl_postacts; +#endif struct p4tc_table_entry *tbl_const_entry; struct p4tc_table_defact __rcu *tbl_default_hitact; struct p4tc_table_defact __rcu *tbl_default_missact; @@ -280,7 +335,10 @@ struct p4tc_ipv4_param_value { u32 mask; }; + +#ifndef CONFIG_NET_P4_TC_KFUNCS #define P4TC_ACT_PARAM_FLAGS_ISDYN BIT(0) +#endif struct p4tc_act_param { char name[ACTPARAMNAMSIZ]; @@ -305,6 +363,7 @@ struct p4tc_act_param_ops { u32 alloc_len; }; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_label_key { char *label; u32 labelsz; @@ -315,12 +374,15 @@ struct p4tc_label_node { struct p4tc_label_key key; int cmd_offset; }; +#endif struct p4tc_act { struct p4tc_template_common common; struct tc_action_ops ops; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct rhashtable *labels; struct list_head cmd_operations; +#endif struct tc_action_net *tn; struct p4tc_pipeline *pipeline; struct idr params_idr; @@ -345,6 +407,13 @@ void p4tc_label_ht_destroy(void *ptr, void *arg); extern const struct rhashtable_params entry_hlt_params; +#ifdef CONFIG_NET_P4_TC_KFUNCS +struct p4tc_table_entry_act_bpf_params { + u32 pipeid; + u32 tblid; +}; +#endif + struct p4tc_table_entry; struct p4tc_table_entry_work { struct work_struct work; @@ -364,6 +433,9 @@ struct p4tc_table_entry_value { u32 prio; int num_acts; struct tc_action **acts; +#ifdef CONFIG_NET_P4_TC_KFUNCS + struct p4tc_table_entry_act_bpf *act_bpf; +#endif refcount_t entries_ref; u32 permissions; struct p4tc_table_entry_tm __rcu *tm; @@ -395,13 +467,24 @@ static inline void *p4tc_table_entry_value(struct p4tc_table_entry *entry) extern const struct nla_policy p4tc_root_policy[P4TC_ROOT_MAX + 1]; extern const struct nla_policy p4tc_policy[P4TC_MAX + 1]; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_table_entry *p4tc_table_entry_lookup(struct sk_buff *skb, struct p4tc_table *table, u32 keysz); +#endif +struct p4tc_table_entry * +p4tc_table_entry_lookup_direct(struct p4tc_table *table, + struct p4tc_table_entry_key *key); int __tcf_table_entry_del(struct p4tc_pipeline *pipeline, struct p4tc_table *table, struct p4tc_table_entry_key *key, struct p4tc_table_entry_mask *mask, u32 prio); +#ifdef CONFIG_NET_P4_TC_KFUNCS +struct p4tc_table_entry_act_bpf * +tcf_table_entry_create_act_bpf(struct tc_action *action, + struct netlink_ext_ack *extack); +#endif +int register_p4tc_tbl_bpf(void); struct p4tc_parser { char parser_name[PARSERNAMSIZ]; @@ -439,6 +522,7 @@ struct p4tc_register { extern const struct p4tc_template_ops p4tc_register_ops; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_metadata *tcf_meta_find_byid(struct p4tc_pipeline *pipeline, u32 m_id); void tcf_meta_fill_user_offsets(struct p4tc_pipeline *pipeline); @@ -448,6 +532,7 @@ struct p4tc_metadata *tcf_meta_get(struct p4tc_pipeline *pipeline, struct netlink_ext_ack *extack); void tcf_meta_put_ref(struct p4tc_metadata *meta); void *tcf_meta_fetch(struct sk_buff *skb, struct p4tc_metadata *meta); +#endif static inline int p4tc_action_init(struct net *net, struct nlattr *nla, struct tc_action *acts[], u32 pipeid, @@ -553,12 +638,13 @@ struct p4tc_hdrfield *tcf_hdrfield_find_byany(struct p4tc_parser *parser, const char *hdrfield_name, u32 hdrfield_id, struct netlink_ext_ack *extack); +#ifndef CONFIG_NET_P4_TC_KFUNCS void *tcf_hdrfield_fetch(struct sk_buff *skb, struct p4tc_hdrfield *hdrfield); +#endif struct p4tc_hdrfield *tcf_hdrfield_get(struct p4tc_parser *parser, const char *hdrfield_name, u32 hdrfield_id, struct netlink_ext_ack *extack); -void *tcf_hdrfield_fetch(struct sk_buff *skb, struct p4tc_hdrfield *hdrfield); void tcf_hdrfield_put_ref(struct p4tc_hdrfield *hdrfield); int p4tc_init_net_ops(struct net *net, unsigned int id); @@ -595,13 +681,16 @@ struct p4tc_register *tcf_register_find_byany(struct p4tc_pipeline *pipeline, void tcf_register_put_rcu(struct rcu_head *head); #define to_pipeline(t) ((struct p4tc_pipeline *)t) +#ifndef CONFIG_NET_P4_TC_KFUNCS #define to_meta(t) ((struct p4tc_metadata *)t) +#endif #define to_hdrfield(t) ((struct p4tc_hdrfield *)t) #define to_act(t) ((struct p4tc_act *)t) #define to_table(t) ((struct p4tc_table *)t) #define to_register(t) ((struct p4tc_register *)t) /* P4TC COMMANDS */ +#ifndef CONFIG_NET_P4_TC_KFUNCS int p4tc_cmds_parse(struct net *net, struct p4tc_act *act, struct nlattr *nla, bool ovr, struct netlink_ext_ack *extack); int p4tc_cmds_copy(struct p4tc_act *act, struct list_head *new_cmd_operations, @@ -680,5 +769,6 @@ static inline int __p4tc_cmd_run(struct sk_buff *skb, struct p4tc_cmd_operate *o return op->cmd->run(skb, op, cmd, res); } #endif +#endif #endif diff --git a/net/core/filter.c b/net/core/filter.c index d9ce04ca22ce..1bd289c634c9 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -8756,6 +8756,11 @@ static int tc_cls_act_btf_struct_access(struct bpf_verifier_log *log, { int ret = -EACCES; +#ifndef CONFIG_NET_P4_TC_KFUNCS + if (is_p4tc_kfunc(reg)) + return 0; +#endif + mutex_lock(&nf_conn_btf_access_lock); if (nfct_btf_struct_access) ret = nfct_btf_struct_access(log, reg, off, size); @@ -8829,6 +8834,11 @@ static int xdp_btf_struct_access(struct bpf_verifier_log *log, { int ret = -EACCES; +#ifndef CONFIG_NET_P4_TC_KFUNCS + if (is_p4tc_kfunc(reg)) + return 0; +#endif + mutex_lock(&nf_conn_btf_access_lock); if (nfct_btf_struct_access) ret = nfct_btf_struct_access(log, reg, off, size); diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 43d300ef0f5a..ffd06565c606 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -696,6 +696,13 @@ config NET_P4_TC The concept of Pipelines, Tables, metadata will be enabled with this option. +config NET_P4_TC_KFUNCS + bool "P4 TC support for eBPF SW data path" + depends on NET_P4_TC + select NET_CLS_ACT + help + Say Y here if you want to use P4 with eBPF SW data path. + config NET_CLS_ACT bool "Actions" select NET_CLS diff --git a/net/sched/cls_p4.c b/net/sched/cls_p4.c index 25e3f0cc7aa8..f068137336f1 100644 --- a/net/sched/cls_p4.c +++ b/net/sched/cls_p4.c @@ -46,8 +46,10 @@ static int p4_classify(struct sk_buff *skb, const struct tcf_proto *tp, bool at_ingress = skb_at_tc_ingress(skb); int rc = TC_ACT_PIPE; struct p4tc_percpu_scratchpad *pad; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct tcf_result p4res = {}; struct p4tc_pipeline *pipeline; +#endif if (unlikely(!head)) { pr_err("P4 classifier not found\n"); @@ -85,6 +87,7 @@ static int p4_classify(struct sk_buff *skb, const struct tcf_proto *tp, if (rc != TC_ACT_PIPE) goto zero_pad; +#ifndef CONFIG_NET_P4_TC_KFUNCS pipeline = head->pipeline; trace_p4_classify(skb, pipeline); @@ -97,6 +100,7 @@ static int p4_classify(struct sk_buff *skb, const struct tcf_proto *tp, &p4res); if (rc != TC_ACT_PIPE) goto zero_pad; +#endif *res = head->res; diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile index ac118a79cbf4..9ee62cf3f85b 100644 --- a/net/sched/p4tc/Makefile +++ b/net/sched/p4tc/Makefile @@ -2,6 +2,10 @@ CFLAGS_trace.o := -I$(src) -obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.o p4tc_meta.o \ +obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.o \ p4tc_parser_api.o p4tc_hdrfield.o p4tc_action.o p4tc_table.o \ - p4tc_tbl_api.o p4tc_register.o p4tc_cmds.o trace.o + p4tc_tbl_api.o p4tc_register.o p4tc_bpf.o trace.o + +ifndef CONFIG_NET_P4_TC_KFUNCS +obj-y += p4tc_meta.o p4tc_cmds.o +endif diff --git a/net/sched/p4tc/p4tc_action.c b/net/sched/p4tc/p4tc_action.c index 8b69842cc3ce..8e08deb30a2f 100644 --- a/net/sched/p4tc/p4tc_action.c +++ b/net/sched/p4tc/p4tc_action.c @@ -29,12 +29,14 @@ #include #include #include + #include static LIST_HEAD(dynact_list); #define SEPARATOR "/" +#ifndef CONFIG_NET_P4_TC_KFUNCS static u32 label_hash_fn(const void *data, u32 len, u32 seed) { const struct p4tc_label_key *key = data; @@ -73,6 +75,7 @@ const struct rhashtable_params p4tc_label_ht_params = { .key_offset = offsetof(struct p4tc_label_node, key), .automatic_shrinking = true, }; +#endif static void set_param_indices(struct p4tc_act *act) { @@ -131,7 +134,9 @@ static int __tcf_p4_dyna_init(struct net *net, struct nlattr *est, p = to_p4act(*a); p->p_id = pipeline->common.p_id; p->act_id = act->a_id; +#ifndef CONFIG_NET_P4_TC_KFUNCS INIT_LIST_HEAD(&p->cmd_operations); +#endif ret = ACT_P_CREATED; } else { @@ -160,7 +165,7 @@ static int __tcf_p4_dyna_init_set(struct p4tc_act *act, struct tc_action **a, { struct tcf_p4act_params *params_old; struct tcf_p4act *p; - int err; + int err = 0; p = to_p4act(*a); @@ -169,6 +174,7 @@ static int __tcf_p4_dyna_init_set(struct p4tc_act *act, struct tc_action **a, goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); +#ifndef CONFIG_NET_P4_TC_KFUNCS err = p4tc_cmds_copy(act, &p->cmd_operations, exists, extack); if (err < 0) { if (exists) @@ -176,6 +182,7 @@ static int __tcf_p4_dyna_init_set(struct p4tc_act *act, struct tc_action **a, return err; } +#endif params_old = rcu_replace_pointer(p->params, params, 1); if (exists) @@ -375,9 +382,13 @@ static int dev_dump_param_value(struct sk_buff *skb, struct p4tc_act_param *param) { struct nlattr *nest; + u32 *ifindex; int ret; nest = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE); +#ifdef CONFIG_NET_P4_TC_KFUNCS + ifindex = (u32 *)param->value; +#else if (param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN) { struct p4tc_cmd_operand *kopnd; struct nlattr *nla_opnd; @@ -390,13 +401,16 @@ static int dev_dump_param_value(struct sk_buff *skb, } nla_nest_end(skb, nla_opnd); } else { - const u32 *ifindex = param->value; + ifindex = (u32 *)param->value; +#endif if (nla_put_u32(skb, P4TC_ACT_PARAMS_VALUE_RAW, *ifindex)) { ret = -EINVAL; goto out_nla_cancel; } +#ifndef CONFIG_NET_P4_TC_KFUNCS } +#endif nla_nest_end(skb, nest); return 0; @@ -408,8 +422,12 @@ static int dev_dump_param_value(struct sk_buff *skb, static void dev_free_param_value(struct p4tc_act_param *param) { +#ifdef CONFIG_NET_P4_TC_KFUNCS + kfree(param->value); +#else if (!(param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN)) kfree(param->value); +#endif } static int generic_init_param_value(struct p4tc_act_param *nparam, @@ -486,10 +504,15 @@ const struct p4tc_act_param_ops param_ops[P4T_MAX + 1] = { static void generic_free_param_value(struct p4tc_act_param *param) { +#ifdef CONFIG_NET_P4_TC_KFUNCS + kfree(param->value); + kfree(param->mask); +#else if (!(param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN)) { kfree(param->value); kfree(param->mask); } +#endif } int tcf_p4_act_init_params_list(struct tcf_p4act_params *params, @@ -586,12 +609,15 @@ INDIRECT_CALLABLE_SCOPE int tcf_p4_dyna_act(struct sk_buff *skb, { struct tcf_p4act *dynact = to_p4act(a); int ret = 0; +#ifndef CONFIG_NET_P4_TC_KFUNCS int jmp_cnt = 0; struct p4tc_cmd_operate *op; +#endif tcf_lastuse_update(&dynact->tcf_tm); tcf_action_update_bstats(&dynact->common, skb); +#ifndef CONFIG_NET_P4_TC_KFUNCS list_for_each_entry(op, &dynact->cmd_operations, cmd_operations) { if (jmp_cnt-- > 0) continue; @@ -609,6 +635,7 @@ INDIRECT_CALLABLE_SCOPE int tcf_p4_dyna_act(struct sk_buff *skb, break; } } +#endif if (ret == TC_ACT_SHOT) tcf_action_inc_drop_qstats(&dynact->common); @@ -636,7 +663,9 @@ static int tcf_p4_dyna_dump(struct sk_buff *skb, struct tc_action *a, int bind, struct tcf_p4act_params *params; struct p4tc_act_param *parm; struct nlattr *nest_parms; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct nlattr *nest; +#endif struct tcf_t t; int id; @@ -646,10 +675,12 @@ static int tcf_p4_dyna_dump(struct sk_buff *skb, struct tc_action *a, int bind, if (nla_put(skb, P4TC_ACT_OPT, sizeof(opt), &opt)) goto nla_put_failure; +#ifndef CONFIG_NET_P4_TC_KFUNCS nest = nla_nest_start(skb, P4TC_ACT_CMDS_LIST); if (p4tc_cmds_fillup(skb, &dynact->cmd_operations)) goto nla_put_failure; nla_nest_end(skb, nest); +#endif if (nla_put_string(skb, P4TC_ACT_NAME, a->ops->kind)) goto nla_put_failure; @@ -744,7 +775,9 @@ static void tcf_p4_dyna_cleanup(struct tc_action *a) if (refcount_read(&ops->dyn_ref) > 1) refcount_dec(&ops->dyn_ref); +#ifndef CONFIG_NET_P4_TC_KFUNCS p4tc_cmds_release_ope_list(NULL, &m->cmd_operations, false); +#endif if (params) call_rcu(¶ms->rcu, tcf_p4_act_params_destroy_rcu); } @@ -757,6 +790,7 @@ int generic_dump_param_value(struct sk_buff *skb, struct p4tc_type *type, struct nlattr *nla_value; nla_value = nla_nest_start(skb, P4TC_ACT_PARAMS_VALUE); +#ifndef CONFIG_NET_P4_TC_KFUNCS if (param->flags & P4TC_ACT_PARAM_FLAGS_ISDYN) { struct p4tc_cmd_operand *kopnd; struct nlattr *nla_opnd; @@ -767,10 +801,13 @@ int generic_dump_param_value(struct sk_buff *skb, struct p4tc_type *type, goto out_nlmsg_trim; nla_nest_end(skb, nla_opnd); } else { +#endif if (nla_put(skb, P4TC_ACT_PARAMS_VALUE_RAW, bytesz, param->value)) goto out_nlmsg_trim; +#ifndef CONFIG_NET_P4_TC_KFUNCS } +#endif nla_nest_end(skb, nla_value); if (param->mask && @@ -1343,7 +1380,9 @@ static int __tcf_act_put(struct net *net, struct p4tc_pipeline *pipeline, kfree(act_param); } +#ifndef CONFIG_NET_P4_TC_KFUNCS p4tc_cmds_release_ope_list(net, &act->cmd_operations, true); +#endif ret = tcf_unregister_dyn_action(net, &act->ops); if (ret < 0) { @@ -1353,16 +1392,20 @@ static int __tcf_act_put(struct net *net, struct p4tc_pipeline *pipeline, } p4tc_action_net_exit(act->tn); +#ifndef CONFIG_NET_P4_TC_KFUNCS if (act->labels) { rhashtable_free_and_destroy(act->labels, p4tc_label_ht_destroy, NULL); kfree(act->labels); } +#endif idr_remove(&pipeline->p_act_idr, act->a_id); +#ifndef CONFIG_NET_P4_TC_KFUNCS if (!unconditional_purge) tcf_pipeline_delete_from_dep_graph(pipeline, act); +#endif list_del(&act->head); @@ -1378,9 +1421,12 @@ static int _tcf_act_fill_nlmsg(struct net *net, struct sk_buff *skb, { unsigned char *b = nlmsg_get_pos(skb); int i = 1; - struct nlattr *nest, *parms, *cmds; + struct nlattr *nest, *parms; struct p4tc_act_param *param; unsigned long param_id, tmp; +#ifndef CONFIG_NET_P4_TC_KFUNCS + struct nlattr *cmds; +#endif if (nla_put_u32(skb, P4TC_PATH, act->a_id)) goto out_nlmsg_trim; @@ -1417,10 +1463,12 @@ static int _tcf_act_fill_nlmsg(struct net *net, struct sk_buff *skb, } nla_nest_end(skb, parms); +#ifndef CONFIG_NET_P4_TC_KFUNCS cmds = nla_nest_start(skb, P4TC_ACT_CMDS_LIST); if (p4tc_cmds_fillup(skb, &act->cmd_operations)) goto out_nlmsg_trim; nla_nest_end(skb, cmds); +#endif nla_nest_end(skb, nest); @@ -1578,7 +1626,9 @@ static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, u32 a_id = ids[P4TC_AID_IDX]; int num_params = 0; int ret = 0; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_act_dep_node *dep_node; +#endif struct p4tc_act *act; char *act_name; @@ -1649,6 +1699,7 @@ static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, } } +#ifndef CONFIG_NET_P4_TC_KFUNCS dep_node = kzalloc(sizeof(*dep_node), GFP_KERNEL); if (!dep_node) { ret = -ENOMEM; @@ -1657,13 +1708,18 @@ static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, dep_node->act_id = act->a_id; INIT_LIST_HEAD(&dep_node->incoming_egde_list); list_add_tail(&dep_node->head, &pipeline->act_dep_graph); +#endif refcount_set(&act->ops.dyn_ref, 1); ret = tcf_register_dyn_action(net, &act->ops); if (ret < 0) { NL_SET_ERR_MSG(extack, "Unable to register new action template"); +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto idr_rm; +#else goto free_dep_node; +#endif } num_params = p4_act_init(act, tb[P4TC_ACT_PARMS], params, extack); @@ -1675,6 +1731,13 @@ static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, set_param_indices(act); +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_ACT_CMDS_LIST]) { + NL_SET_ERR_MSG(extack, "Commands not supported in kfuncs mode"); + ret = -EOPNOTSUPP; + goto uninit; + } +#else INIT_LIST_HEAD(&act->cmd_operations); act->pipeline = pipeline; if (tb[P4TC_ACT_CMDS_LIST]) { @@ -1683,14 +1746,17 @@ static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, if (ret < 0) goto uninit; } +#endif pipeline->num_created_acts++; +#ifndef CONFIG_NET_P4_TC_KFUNCS ret = determine_act_topological_order(pipeline, true); if (ret < 0) { pipeline->num_created_acts--; goto release_cmds; } +#endif act->common.p_id = pipeline->common.p_id; snprintf(act->common.name, ACTNAMSIZ, "%s/%s", pipeline->common.name, @@ -1703,9 +1769,11 @@ static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, return act; +#ifndef CONFIG_NET_P4_TC_KFUNCS release_cmds: if (tb[P4TC_ACT_CMDS_LIST]) p4tc_cmds_release_ope_list(net, &act->cmd_operations, false); +#endif uninit: p4_put_many_params(&act->params_idr, params, num_params); @@ -1716,9 +1784,11 @@ static struct p4tc_act *tcf_act_create(struct net *net, struct nlattr **tb, tcf_unregister_dyn_action(net, &act->ops); rtnl_lock(); +#ifndef CONFIG_NET_P4_TC_KFUNCS free_dep_node: list_del(&dep_node->head); kfree(dep_node); +#endif idr_rm: idr_remove(&pipeline->p_act_idr, act->a_id); @@ -1785,6 +1855,13 @@ static struct p4tc_act *tcf_act_update(struct net *net, struct nlattr **tb, goto params_del; } +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_ACT_CMDS_LIST]) { + NL_SET_ERR_MSG(extack, "Commands not supported in kfuncs mode"); + ret = -EOPNOTSUPP; + goto params_del; + } +#else if (tb[P4TC_ACT_CMDS_LIST]) { ret = p4tc_cmds_parse(net, act, tb[P4TC_ACT_CMDS_LIST], true, extack); @@ -1795,12 +1872,15 @@ static struct p4tc_act *tcf_act_update(struct net *net, struct nlattr **tb, if (ret < 0) goto release_cmds; } +#endif p4tc_params_replace_many(&act->params_idr, params, num_params); return act; +#ifndef CONFIG_NET_P4_TC_KFUNCS release_cmds: p4tc_cmds_release_ope_list(net, &act->cmd_operations, false); +#endif params_del: p4_put_many_params(&act->params_idr, params, num_params); @@ -1880,7 +1960,9 @@ static int tcf_act_dump_1(struct sk_buff *skb, struct nlattr *param = nla_nest_start(skb, P4TC_PARAMS); unsigned char *b = nlmsg_get_pos(skb); struct p4tc_act *act = to_act(common); +#ifndef CONFIG_NET_P4_TC_KFUNCS struct nlattr *nest; +#endif if (!param) goto out_nlmsg_trim; @@ -1888,10 +1970,12 @@ static int tcf_act_dump_1(struct sk_buff *skb, if (nla_put_string(skb, P4TC_ACT_NAME, act->common.name)) goto out_nlmsg_trim; +#ifndef CONFIG_NET_P4_TC_KFUNCS nest = nla_nest_start(skb, P4TC_ACT_CMDS_LIST); if (p4tc_cmds_fillup(skb, &act->cmd_operations)) goto out_nlmsg_trim; nla_nest_end(skb, nest); +#endif if (nla_put_u8(skb, P4TC_ACT_ACTIVE, act->active)) goto out_nlmsg_trim; diff --git a/net/sched/p4tc/p4tc_bpf.c b/net/sched/p4tc/p4tc_bpf.c index 08d26a6499c5..3e4eb1fd9d97 100644 --- a/net/sched/p4tc/p4tc_bpf.c +++ b/net/sched/p4tc/p4tc_bpf.c @@ -21,8 +21,74 @@ #include BTF_ID_LIST(btf_p4tc_ids) +#ifdef CONFIG_NET_P4_TC_KFUNCS +BTF_ID(struct, p4tc_table_entry_act_bpf) +BTF_ID(struct, p4tc_table_entry_act_bpf_params) +#else BTF_ID(struct, p4tc_parser_buffer_act_bpf) +#endif +#ifdef CONFIG_NET_P4_TC_KFUNCS +#define ENTRY_KEY_OFFSET (offsetof(struct p4tc_table_entry_key, fa_key)) + +struct p4tc_table_entry_act_bpf * +__bpf_p4tc_tbl_lookup(struct net *caller_net, + struct p4tc_table_entry_act_bpf_params *params, + void *key, const u32 key__sz) +{ + struct p4tc_table_entry_key *entry_key = (struct p4tc_table_entry_key *)key; + const u32 pipeid = params->pipeid; + const u32 tblid = params->tblid; + struct p4tc_table_entry_value *value; + struct p4tc_table_entry *entry; + struct p4tc_table *table; + + entry_key->keysz = (key__sz - ENTRY_KEY_OFFSET) << 3; + + table = p4tc_tbl_cache_lookup(caller_net, pipeid, tblid); + if (!table) + return NULL; + + entry = p4tc_table_entry_lookup_direct(table, entry_key); + if (!entry) { + struct p4tc_table_defact *defact; + + defact = rcu_dereference(table->tbl_default_missact); + return defact ? defact->defact_bpf : NULL; + } + + value = p4tc_table_entry_value(entry); + + return value->act_bpf; +} + +struct p4tc_table_entry_act_bpf * +bpf_skb_p4tc_tbl_lookup(struct __sk_buff *skb_ctx, + struct p4tc_table_entry_act_bpf_params *params, + void *key, const u32 key__sz) +{ + struct sk_buff *skb = (struct sk_buff *)skb_ctx; + struct net *caller_net; + + caller_net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk); + + return __bpf_p4tc_tbl_lookup(caller_net, params, key, key__sz); +} + +struct p4tc_table_entry_act_bpf * +bpf_xdp_p4tc_tbl_lookup(struct xdp_md *xdp_ctx, + struct p4tc_table_entry_act_bpf_params *params, + void *key, const u32 key__sz) +{ + struct xdp_buff *ctx = (struct xdp_buff *)xdp_ctx; + struct net *caller_net; + + caller_net = dev_net(ctx->rxq->dev); + + return __bpf_p4tc_tbl_lookup(caller_net, params, key, key__sz); +} + +#else struct p4tc_parser_buffer_act_bpf *bpf_p4tc_get_parser_buffer(void) { struct p4tc_percpu_scratchpad *pad; @@ -45,6 +111,7 @@ int is_p4tc_kfunc(const struct bpf_reg_state *reg) return p4tc_parser_type == t; } +#endif void bpf_p4tc_set_cookie(u32 cookie) { @@ -55,7 +122,12 @@ void bpf_p4tc_set_cookie(u32 cookie) } BTF_SET8_START(p4tc_tbl_kfunc_set) +#ifdef CONFIG_NET_P4_TC_KFUNCS +BTF_ID_FLAGS(func, bpf_skb_p4tc_tbl_lookup, KF_RET_NULL); +BTF_ID_FLAGS(func, bpf_xdp_p4tc_tbl_lookup, KF_RET_NULL); +#else BTF_ID_FLAGS(func, bpf_p4tc_get_parser_buffer, 0); +#endif BTF_ID_FLAGS(func, bpf_p4tc_set_cookie, 0); BTF_SET8_END(p4tc_tbl_kfunc_set) diff --git a/net/sched/p4tc/p4tc_hdrfield.c b/net/sched/p4tc/p4tc_hdrfield.c index d5dd9b5c885d..c7c2fe90ec81 100644 --- a/net/sched/p4tc/p4tc_hdrfield.c +++ b/net/sched/p4tc/p4tc_hdrfield.c @@ -165,6 +165,7 @@ tcf_hdrfield_find_byanyattr(struct p4tc_parser *parser, extack); } +#ifndef CONFIG_NET_P4_TC_KFUNCS void *tcf_hdrfield_fetch(struct sk_buff *skb, struct p4tc_hdrfield *hdrfield) { size_t hdr_offset_len = sizeof(u16); @@ -183,6 +184,7 @@ void *tcf_hdrfield_fetch(struct sk_buff *skb, struct p4tc_hdrfield *hdrfield) return skb_mac_header(skb) + hdr_offset; } +#endif static struct p4tc_hdrfield *tcf_hdrfield_create(struct nlmsghdr *n, struct nlattr *nla, diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c index fafb9c849b13..6d5722f6a298 100644 --- a/net/sched/p4tc/p4tc_pipeline.c +++ b/net/sched/p4tc/p4tc_pipeline.c @@ -37,9 +37,56 @@ static __net_init int pipeline_init_net(struct net *net) idr_init(&pipe_net->pipeline_idr); +#ifdef CONFIG_NET_P4_TC_KFUNCS + for (int i = 0; i < P4TC_TBLS_CACHE_SIZE; i++) + INIT_LIST_HEAD(&pipe_net->tbls_cache[i]); +#endif + return 0; } +#ifdef CONFIG_NET_P4_TC_KFUNCS +static inline size_t p4tc_tbl_cache_hash(u32 pipeid, u32 tblid) +{ + return (pipeid + tblid) % P4TC_TBLS_CACHE_SIZE; +} + +struct p4tc_table *p4tc_tbl_cache_lookup(struct net *net, u32 pipeid, u32 tblid) +{ + size_t hash = p4tc_tbl_cache_hash(pipeid, tblid); + struct p4tc_pipeline_net *pipe_net; + struct p4tc_table *pos, *tmp; + struct net_generic *ng; + + /* RCU read lock is already being held */ + ng = rcu_dereference(net->gen); + pipe_net = ng->ptr[pipeline_net_id]; + + list_for_each_entry_safe(pos, tmp, &pipe_net->tbls_cache[hash], + tbl_cache_node) { + if (pos->common.p_id == pipeid && pos->tbl_id == tblid) + return pos; + } + + return NULL; +} + +int p4tc_tbl_cache_insert(struct net *net, u32 pipeid, struct p4tc_table *table) +{ + struct p4tc_pipeline_net *pipe_net = net_generic(net, pipeline_net_id); + size_t hash = p4tc_tbl_cache_hash(pipeid, table->tbl_id); + + list_add_tail(&table->tbl_cache_node, &pipe_net->tbls_cache[hash]); + + return 0; +} + +void p4tc_tbl_cache_remove(struct net *net, struct p4tc_table *table) +{ + list_del(&table->tbl_cache_node); +} +#endif + static int tcf_pipeline_put(struct net *net, struct p4tc_template_common *template, bool unconditional_purgeline, @@ -73,10 +120,13 @@ static const struct nla_policy tc_pipeline_policy[P4TC_PIPELINE_MAX + 1] = { [P4TC_PIPELINE_NUMTABLES] = NLA_POLICY_RANGE(NLA_U16, P4TC_MINTABLES_COUNT, P4TC_MAXTABLES_COUNT), [P4TC_PIPELINE_STATE] = { .type = NLA_U8 }, +#ifndef CONFIG_NET_P4_TC_KFUNCS [P4TC_PIPELINE_PREACTIONS] = { .type = NLA_NESTED }, [P4TC_PIPELINE_POSTACTIONS] = { .type = NLA_NESTED }, +#endif }; +#ifndef CONFIG_NET_P4_TC_KFUNCS static void __act_dep_graph_free(struct list_head *incoming_egde_list) { struct p4tc_act_dep_edge_node *cursor_edge, *tmp_edge; @@ -291,11 +341,14 @@ int determine_act_topological_order(struct p4tc_pipeline *pipeline, return 0; } +#endif static void tcf_pipeline_destroy(struct p4tc_pipeline *pipeline, bool free_pipeline) { +#ifndef CONFIG_NET_P4_TC_KFUNCS idr_destroy(&pipeline->p_meta_idr); +#endif idr_destroy(&pipeline->p_act_idr); idr_destroy(&pipeline->p_tbl_idr); idr_destroy(&pipeline->p_reg_idr); @@ -324,9 +377,17 @@ static int tcf_pipeline_put(struct net *net, struct p4tc_pipeline_net *pipe_net = net_generic(net, pipeline_net_id); struct p4tc_pipeline *pipeline = to_pipeline(template); struct net *pipeline_net = maybe_get_net(net); +#ifdef CONFIG_NET_P4_TC_KFUNCS + struct p4tc_act *act; + unsigned long iter_act_id; +#else struct p4tc_act_dep_node *act_node, *node_tmp; - unsigned long reg_id, tbl_id, m_id, tmp; +#endif + unsigned long reg_id, tbl_id, tmp; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_metadata *meta; + unsigned long m_id; +#endif struct p4tc_register *reg; struct p4tc_table *table; @@ -349,12 +410,18 @@ static int tcf_pipeline_put(struct net *net, * will use them. So there is no need to free them in the rcu * callback. We can just free them here */ +#ifndef CONFIG_NET_P4_TC_KFUNCS p4tc_action_destroy(pipeline->preacts); p4tc_action_destroy(pipeline->postacts); +#endif idr_for_each_entry_ul(&pipeline->p_tbl_idr, table, tmp, tbl_id) table->common.ops->put(net, &table->common, true, extack); +#ifdef CONFIG_NET_P4_TC_KFUNCS + idr_for_each_entry_ul(&pipeline->p_act_idr, act, tmp, iter_act_id) + act->common.ops->put(net, &act->common, true, extack); +#else act_dep_graph_free(&pipeline->act_dep_graph); list_for_each_entry_safe(act_node, node_tmp, @@ -366,9 +433,12 @@ static int tcf_pipeline_put(struct net *net, list_del(&act_node->head); kfree(act_node); } +#endif +#ifndef CONFIG_NET_P4_TC_KFUNCS idr_for_each_entry_ul(&pipeline->p_meta_idr, meta, tmp, m_id) meta->common.ops->put(net, &meta->common, true, extack); +#endif if (pipeline->parser) tcf_parser_del(net, pipeline, pipeline->parser, extack); @@ -398,6 +468,7 @@ static inline int pipeline_try_set_state_ready(struct p4tc_pipeline *pipeline, return -EINVAL; } +#ifndef CONFIG_NET_P4_TC_KFUNCS if (!pipeline->preacts) { NL_SET_ERR_MSG(extack, "Must specify pipeline preactions before sealing"); @@ -409,12 +480,15 @@ static inline int pipeline_try_set_state_ready(struct p4tc_pipeline *pipeline, "Must specify pipeline postactions before sealing"); return -EINVAL; } +#endif ret = tcf_table_try_set_state_ready(pipeline, extack); if (ret < 0) return ret; +#ifndef CONFIG_NET_P4_TC_KFUNCS /* Will never fail in this case */ determine_act_topological_order(pipeline, false); +#endif pipeline->p_state = P4TC_STATE_READY; return true; @@ -520,6 +594,14 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, else pipeline->num_tables = P4TC_DEFAULT_NUM_TABLES; +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_PIPELINE_PREACTIONS]) { + NL_SET_ERR_MSG(extack, + "Pipeline preactions not supported in kfuncs mode"); + ret = -EOPNOTSUPP; + goto idr_rm; + } +#else if (tb[P4TC_PIPELINE_PREACTIONS]) { pipeline->preacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), @@ -540,7 +622,16 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, pipeline->preacts = NULL; pipeline->num_preacts = 0; } +#endif +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_PIPELINE_POSTACTIONS]) { + NL_SET_ERR_MSG(extack, + "Pipeline postactions not supported in kfuncs mode"); + ret = -EOPNOTSUPP; + goto idr_rm; + } +#else if (tb[P4TC_PIPELINE_POSTACTIONS]) { pipeline->postacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), @@ -561,6 +652,7 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, pipeline->postacts = NULL; pipeline->num_postacts = 0; } +#endif pipeline->parser = NULL; @@ -569,13 +661,17 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, idr_init(&pipeline->p_tbl_idr); pipeline->curr_tables = 0; +#ifndef CONFIG_NET_P4_TC_KFUNCS idr_init(&pipeline->p_meta_idr); pipeline->p_meta_offset = 0; +#endif idr_init(&pipeline->p_reg_idr); +#ifndef CONFIG_NET_P4_TC_KFUNCS INIT_LIST_HEAD(&pipeline->act_dep_graph); INIT_LIST_HEAD(&pipeline->act_topological_order); +#endif pipeline->num_created_acts = 0; pipeline->p_state = P4TC_STATE_NOT_READY; @@ -591,8 +687,10 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net, return pipeline; +#ifndef CONFIG_NET_P4_TC_KFUNCS preactions_destroy: p4tc_action_destroy(pipeline->preacts); +#endif idr_rm: idr_remove(&pipe_net->pipeline_idr, pipeid); @@ -715,7 +813,9 @@ tcf_pipeline_update(struct net *net, struct nlmsghdr *n, struct nlattr *nla, int ret = 0; struct nlattr *tb[P4TC_PIPELINE_MAX + 1]; struct p4tc_pipeline *pipeline; +#ifndef CONFIG_NET_P4_TC_KFUNCS int num_preacts, num_postacts; +#endif ret = nla_parse_nested(tb, P4TC_PIPELINE_MAX, nla, tc_pipeline_policy, extack); @@ -734,6 +834,14 @@ tcf_pipeline_update(struct net *net, struct nlmsghdr *n, struct nlattr *nla, if (tb[P4TC_PIPELINE_MAXRULES]) max_rules = nla_get_u32(tb[P4TC_PIPELINE_MAXRULES]); +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_PIPELINE_PREACTIONS]) { + NL_SET_ERR_MSG(extack, + "Pipeline preactions not supported in kfuncs mode"); + ret = -EOPNOTSUPP; + goto out; + } +#else if (tb[P4TC_PIPELINE_PREACTIONS]) { preacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), GFP_KERNEL); @@ -751,7 +859,16 @@ tcf_pipeline_update(struct net *net, struct nlmsghdr *n, struct nlattr *nla, } num_preacts = ret; } +#endif +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_PIPELINE_POSTACTIONS]) { + NL_SET_ERR_MSG(extack, + "Pipeline preactions not supported in kfuncs mode"); + ret = -EOPNOTSUPP; + goto preactions_destroy; + } +#else if (tb[P4TC_PIPELINE_POSTACTIONS]) { postacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), GFP_KERNEL); @@ -769,18 +886,22 @@ tcf_pipeline_update(struct net *net, struct nlmsghdr *n, struct nlattr *nla, } num_postacts = ret; } +#endif if (tb[P4TC_PIPELINE_STATE]) { ret = pipeline_try_set_state_ready(pipeline, extack); if (ret < 0) goto postactions_destroy; +#ifndef CONFIG_NET_P4_TC_KFUNCS tcf_meta_fill_user_offsets(pipeline); +#endif } if (max_rules) pipeline->max_rules = max_rules; if (num_tables) pipeline->num_tables = num_tables; +#ifndef CONFIG_NET_P4_TC_KFUNCS if (preacts) { p4tc_action_destroy(pipeline->preacts); pipeline->preacts = preacts; @@ -791,6 +912,7 @@ tcf_pipeline_update(struct net *net, struct nlmsghdr *n, struct nlattr *nla, pipeline->postacts = postacts; pipeline->num_postacts = num_postacts; } +#endif return pipeline; @@ -835,7 +957,10 @@ static int _tcf_pipeline_fill_nlmsg(struct sk_buff *skb, const struct p4tc_pipeline *pipeline) { unsigned char *b = nlmsg_get_pos(skb); - struct nlattr *nest, *preacts, *postacts; +#ifndef CONFIG_NET_P4_TC_KFUNCS + struct nlattr *preacts, *postacts; +#endif + struct nlattr *nest; nest = nla_nest_start(skb, P4TC_PARAMS); if (!nest) @@ -848,6 +973,7 @@ static int _tcf_pipeline_fill_nlmsg(struct sk_buff *skb, if (nla_put_u8(skb, P4TC_PIPELINE_STATE, pipeline->p_state)) goto out_nlmsg_trim; +#ifndef CONFIG_NET_P4_TC_KFUNCS if (pipeline->preacts) { preacts = nla_nest_start(skb, P4TC_PIPELINE_PREACTIONS); if (tcf_action_dump(skb, pipeline->preacts, 0, 0, false) < 0) @@ -861,6 +987,7 @@ static int _tcf_pipeline_fill_nlmsg(struct sk_buff *skb, goto out_nlmsg_trim; nla_nest_end(skb, postacts); } +#endif nla_nest_end(skb, nest); @@ -992,7 +1119,9 @@ static void __tcf_pipeline_init(void) strscpy(root_pipeline->common.name, "kernel", PIPELINENAMSIZ); +#ifndef CONFIG_NET_P4_TC_KFUNCS idr_init(&root_pipeline->p_meta_idr); +#endif root_pipeline->common.ops = (struct p4tc_template_ops *)&p4tc_pipeline_ops; @@ -1001,7 +1130,9 @@ static void __tcf_pipeline_init(void) root_pipeline->p_state = P4TC_STATE_READY; +#ifndef CONFIG_NET_P4_TC_KFUNCS tcf_meta_init(root_pipeline); +#endif } static void tcf_pipeline_init(void) diff --git a/net/sched/p4tc/p4tc_table.c b/net/sched/p4tc/p4tc_table.c index e5b1a56aed7d..64f994c7dffc 100644 --- a/net/sched/p4tc/p4tc_table.c +++ b/net/sched/p4tc/p4tc_table.c @@ -31,6 +31,7 @@ #define P4TC_P_UNSPEC 0 #define P4TC_P_CREATED 1 +#ifndef CONFIG_NET_P4_TC_KFUNCS static int tcf_key_try_set_state_ready(struct p4tc_table_key *key, struct netlink_ext_ack *extack) { @@ -42,11 +43,12 @@ static int tcf_key_try_set_state_ready(struct p4tc_table_key *key, return 0; } +#endif static int __tcf_table_try_set_state_ready(struct p4tc_table *table, struct netlink_ext_ack *extack) { - int i; +#ifndef CONFIG_NET_P4_TC_KFUNCS int ret; if (!table->tbl_postacts) { @@ -64,6 +66,7 @@ static int __tcf_table_try_set_state_ready(struct p4tc_table *table, ret = tcf_key_try_set_state_ready(table->tbl_key, extack); if (ret < 0) return ret; +#endif table->tbl_masks_array = kcalloc(table->tbl_max_masks, sizeof(*(table->tbl_masks_array)), @@ -131,15 +134,18 @@ static const struct nla_policy p4tc_table_policy[P4TC_TABLE_MAX + 1] = { [P4TC_TABLE_NAME] = { .type = NLA_STRING, .len = TABLENAMSIZ }, [P4TC_TABLE_INFO] = { .type = NLA_BINARY, .len = sizeof(struct p4tc_table_parm) }, +#ifndef CONFIG_NET_P4_TC_KFUNCS [P4TC_TABLE_PREACTIONS] = { .type = NLA_NESTED }, [P4TC_TABLE_KEY] = { .type = NLA_NESTED }, [P4TC_TABLE_POSTACTIONS] = { .type = NLA_NESTED }, +#endif [P4TC_TABLE_DEFAULT_HIT] = { .type = NLA_NESTED }, [P4TC_TABLE_DEFAULT_MISS] = { .type = NLA_NESTED }, [P4TC_TABLE_ACTS_LIST] = { .type = NLA_NESTED }, [P4TC_TABLE_OPT_ENTRY] = { .type = NLA_NESTED }, }; +#ifndef CONFIG_NET_P4_TC_KFUNCS static const struct nla_policy p4tc_table_key_policy[P4TC_MAXPARSE_KEYS + 1] = { [P4TC_KEY_ACT] = { .type = NLA_NESTED }, }; @@ -160,6 +166,7 @@ static int tcf_table_key_fill_nlmsg(struct sk_buff *skb, return ret; } +#endif static int _tcf_table_fill_nlmsg(struct sk_buff *skb, struct p4tc_table *table) { @@ -172,11 +179,15 @@ static int _tcf_table_fill_nlmsg(struct sk_buff *skb, struct p4tc_table *table) struct nlattr *default_hitact; struct nlattr *nested_count; struct p4tc_table_parm parm; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct nlattr *nest_key; +#endif struct nlattr *nest; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct nlattr *preacts; struct nlattr *postacts; int err; +#endif if (nla_put_u32(skb, P4TC_PATH, table->tbl_id)) goto out_nlmsg_trim; @@ -196,6 +207,7 @@ static int _tcf_table_fill_nlmsg(struct sk_buff *skb, struct p4tc_table *table) tbl_perm = rcu_dereference_rtnl(table->tbl_permissions); parm.tbl_permissions = tbl_perm->permissions; +#ifndef CONFIG_NET_P4_TC_KFUNCS if (table->tbl_key) { nest_key = nla_nest_start(skb, P4TC_TABLE_KEY); err = tcf_table_key_fill_nlmsg(skb, table->tbl_key); @@ -217,6 +229,7 @@ static int _tcf_table_fill_nlmsg(struct sk_buff *skb, struct p4tc_table *table) goto out_nlmsg_trim; nla_nest_end(skb, postacts); } +#endif if (table->tbl_default_hitact) { struct p4tc_table_defact *hitact; @@ -322,16 +335,21 @@ static int tcf_table_fill_nlmsg(struct net *net, struct sk_buff *skb, return 0; } +#ifndef CONFIG_NET_P4_TC_KFUNCS static inline void tcf_table_key_put(struct p4tc_table_key *key) { p4tc_action_destroy(key->key_acts); kfree(key); } +#endif static inline void p4tc_table_defact_destroy(struct p4tc_table_defact *defact) { if (defact) { p4tc_action_destroy(defact->default_acts); +#ifdef CONFIG_NET_P4_TC_KFUNCS + kfree(defact->defact_bpf); +#endif kfree(defact); } } @@ -435,16 +453,21 @@ static inline int _tcf_table_put(struct net *net, struct nlattr **tb, if (default_act_del) return 0; +#ifndef CONFIG_NET_P4_TC_KFUNCS if (table->tbl_key) tcf_table_key_put(table->tbl_key); p4tc_action_destroy(table->tbl_preacts); p4tc_action_destroy(table->tbl_postacts); +#endif tcf_table_acts_list_destroy(&table->tbl_acts_list); rhltable_free_and_destroy(&table->tbl_entries, tcf_table_entry_destroy_hash, table); +#ifdef CONFIG_NET_P4_TC_KFUNCS + p4tc_tbl_cache_remove(net, table); +#endif idr_destroy(&table->tbl_masks_idr); ida_destroy(&table->tbl_prio_idr); @@ -475,6 +498,7 @@ static int tcf_table_put(struct net *net, struct p4tc_template_common *tmpl, extack); } +#ifndef CONFIG_NET_P4_TC_KFUNCS static inline struct p4tc_table_key * tcf_table_key_add(struct net *net, struct p4tc_table *table, struct nlattr *nla, struct netlink_ext_ack *extack) @@ -520,6 +544,7 @@ tcf_table_key_add(struct net *net, struct p4tc_table *table, struct nlattr *nla, out: return ERR_PTR(ret); } +#endif struct p4tc_table *tcf_table_find_byid(struct p4tc_pipeline *pipeline, const u32 tbl_id) @@ -623,6 +648,9 @@ static int tcf_table_init_default_act(struct net *net, struct nlattr **tb, } if (tb[P4TC_TABLE_DEFAULT_ACTION]) { +#ifdef CONFIG_NET_P4_TC_KFUNCS + struct p4tc_table_entry_act_bpf *act_bpf; +#endif struct tc_action **default_acts; if (!p4tc_ctrl_update_ok(curr_permissions)) { @@ -651,6 +679,17 @@ static int tcf_table_init_default_act(struct net *net, struct nlattr **tb, ret = -EINVAL; goto default_act_free; } +#ifdef CONFIG_NET_P4_TC_KFUNCS + act_bpf = tcf_table_entry_create_act_bpf(default_acts[0], + extack); + if (IS_ERR(act_bpf)) { + tcf_action_destroy(default_acts, TCA_ACT_UNBIND); + kfree(default_acts); + ret = -EINVAL; + goto default_act_free; + } + (*default_act)->defact_bpf = act_bpf; +#endif (*default_act)->default_acts = default_acts; } @@ -895,7 +934,9 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, struct netlink_ext_ack *extack) { struct rhashtable_params table_hlt_params = entry_hlt_params; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_table_key *key = NULL; +#endif struct p4tc_table_parm *parm; struct p4tc_table *table; char *tblname; @@ -1086,6 +1127,14 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, goto idr_rm; } +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_TABLE_PREACTIONS]) { + NL_SET_ERR_MSG(extack, + "Table preactions not supported in kfuncs mode"); + ret = -EOPNOTSUPP; + goto table_acts_destroy; + } +#else if (tb[P4TC_TABLE_PREACTIONS]) { table->tbl_preacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), @@ -1106,7 +1155,16 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, } else { table->tbl_preacts = NULL; } +#endif +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_TABLE_POSTACTIONS]) { + NL_SET_ERR_MSG(extack, + "Table postactions not supported in kfuncs mode"); + ret = -EOPNOTSUPP; + goto table_acts_destroy; + } +#else if (tb[P4TC_TABLE_POSTACTIONS]) { table->tbl_postacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), @@ -1128,7 +1186,16 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, table->tbl_postacts = NULL; table->tbl_num_postacts = 0; } +#endif +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_TABLE_KEY]) { + NL_SET_ERR_MSG(extack, + "Mustn't specify key in kfuncs mode"); + ret = -EOPNOTSUPP; + goto table_acts_destroy; + } +#else if (tb[P4TC_TABLE_KEY]) { key = tcf_table_key_add(net, table, tb[P4TC_TABLE_KEY], extack); if (IS_ERR(key)) { @@ -1136,13 +1203,18 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, goto postacts_destroy; } } +#endif ret = tcf_table_init_default_acts(net, tb, table, &table->tbl_default_hitact, &table->tbl_default_missact, &table->tbl_acts_list, extack); if (ret < 0) +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto table_acts_destroy; +#else goto key_put; +#endif table->tbl_curr_used_entries = 0; table->tbl_curr_count = 0; @@ -1164,7 +1236,15 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, goto defaultacts_destroy; } +#ifdef CONFIG_NET_P4_TC_KFUNCS + ret = p4tc_tbl_cache_insert(net, pipeline->common.p_id, table); + if (ret < 0) + goto entries_hashtable_destroy; +#endif + +#ifndef CONFIG_NET_P4_TC_KFUNCS table->tbl_key = key; +#endif pipeline->curr_tables += 1; @@ -1172,8 +1252,14 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, return table; +#ifdef CONFIG_NET_P4_TC_KFUNCS +entries_hashtable_destroy: + rhltable_destroy(&table->tbl_entries); +#endif + defaultacts_destroy: p4tc_table_defact_destroy(table->tbl_default_missact); +#ifndef CONFIG_NET_P4_TC_KFUNCS p4tc_table_defact_destroy(table->tbl_default_hitact); key_put: @@ -1185,6 +1271,7 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb, preactions_destroy: p4tc_action_destroy(table->tbl_preacts); +#endif idr_rm: idr_remove(&pipeline->p_tbl_idr, table->tbl_id); @@ -1208,15 +1295,19 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, u32 flags, struct netlink_ext_ack *extack) { +#ifndef CONFIG_NET_P4_TC_KFUNCS struct p4tc_table_key *key = NULL; int num_postacts = 0, num_preacts = 0; +#endif struct p4tc_table_defact *default_hitact = NULL; struct p4tc_table_defact *default_missact = NULL; struct list_head *tbl_acts_list = NULL; struct p4tc_table_perm *perm = NULL; struct p4tc_table_parm *parm = NULL; +#ifndef CONFIG_NET_P4_TC_KFUNCS struct tc_action **postacts = NULL; struct tc_action **preacts = NULL; +#endif int ret = 0; struct p4tc_table *table; @@ -1238,6 +1329,7 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, goto table_acts_destroy; } +#ifndef CONFIG_NET_P4_TC_KFUNCS if (tb[P4TC_TABLE_PREACTIONS]) { preacts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), GFP_KERNEL); @@ -1271,6 +1363,7 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, } num_postacts = ret; } +#endif if (tbl_acts_list) ret = tcf_table_init_default_acts(net, tb, table, @@ -1284,8 +1377,20 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, &table->tbl_acts_list, extack); if (ret < 0) +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto table_acts_destroy; +#else goto postactions_destroy; +#endif +#ifdef CONFIG_NET_P4_TC_KFUNCS + if (tb[P4TC_TABLE_KEY]) { + NL_SET_ERR_MSG(extack, + "Mustn't specify key in kfuncs mode"); + ret = -EOPNOTSUPP; + goto defaultacts_destroy; + } +#else if (tb[P4TC_TABLE_KEY]) { key = tcf_table_key_add(net, table, tb[P4TC_TABLE_KEY], extack); if (IS_ERR(key)) { @@ -1293,6 +1398,7 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, goto defaultacts_destroy; } } +#endif if (tb[P4TC_TABLE_INFO]) { parm = nla_data(tb[P4TC_TABLE_INFO]); @@ -1301,13 +1407,21 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, NL_SET_ERR_MSG(extack, "Table keysz cannot be zero"); ret = -EINVAL; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } if (parm->tbl_keysz > P4TC_MAX_KEYSZ) { NL_SET_ERR_MSG(extack, "Table keysz exceeds maximum keysz"); ret = -EINVAL; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } table->tbl_keysz = parm->tbl_keysz; } @@ -1317,13 +1431,21 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, NL_SET_ERR_MSG(extack, "Table max_entries cannot be zero"); ret = -EINVAL; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } if (parm->tbl_max_entries > P4TC_MAX_TENTRIES) { NL_SET_ERR_MSG(extack, "Table max_entries exceeds maximum value"); ret = -EINVAL; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } table->tbl_max_entries = parm->tbl_max_entries; } @@ -1333,13 +1455,21 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, NL_SET_ERR_MSG(extack, "Table max_masks cannot be zero"); ret = -EINVAL; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } if (parm->tbl_max_masks > P4TC_MAX_TMASKS) { NL_SET_ERR_MSG(extack, "Table max_masks exceeds maximum value"); ret = -EINVAL; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } table->tbl_max_masks = parm->tbl_max_masks; } @@ -1348,25 +1478,41 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, NL_SET_ERR_MSG(extack, "Permission may only have 10 bits turned on"); ret = -EINVAL; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } if (!p4tc_data_exec_ok(parm->tbl_permissions)) { NL_SET_ERR_MSG(extack, "Table must have execute permissions"); ret = -EINVAL; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } if (!p4tc_data_read_ok(parm->tbl_permissions)) { NL_SET_ERR_MSG(extack, "Data path read permissions must be set"); ret = -EINVAL; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } perm = kzalloc(sizeof(*perm), GFP_KERNEL); if (!perm) { ret = -ENOMEM; +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto defaultacts_destroy; +#else goto key_destroy; +#endif } perm->permissions = parm->tbl_permissions; } @@ -1395,6 +1541,7 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, table->tbl_const_entry = entry; } +#ifndef CONFIG_NET_P4_TC_KFUNCS if (preacts) { p4tc_action_destroy(table->tbl_preacts); table->tbl_preacts = preacts; @@ -1406,6 +1553,7 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, table->tbl_postacts = postacts; table->tbl_num_postacts = num_postacts; } +#endif if (default_hitact) { struct p4tc_table_defact *hitact; @@ -1429,11 +1577,13 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, } } +#ifndef CONFIG_NET_P4_TC_KFUNCS if (key) { if (table->tbl_key) tcf_table_key_put(table->tbl_key); table->tbl_key = key; } +#endif if (perm) { perm = rcu_replace_pointer_rtnl(table->tbl_permissions, perm); @@ -1445,19 +1595,23 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb, free_perm: kfree(perm); +#ifndef CONFIG_NET_P4_TC_KFUNCS key_destroy: if (key) tcf_table_key_put(key); +#endif defaultacts_destroy: p4tc_table_defact_destroy(default_missact); p4tc_table_defact_destroy(default_hitact); +#ifndef CONFIG_NET_P4_TC_KFUNCS postactions_destroy: p4tc_action_destroy(postacts); preactions_destroy: p4tc_action_destroy(preacts); +#endif table_acts_destroy: if (tbl_acts_list) { diff --git a/net/sched/p4tc/p4tc_tbl_api.c b/net/sched/p4tc/p4tc_tbl_api.c index 21784b84864f..fb0a17cab3a7 100644 --- a/net/sched/p4tc/p4tc_tbl_api.c +++ b/net/sched/p4tc/p4tc_tbl_api.c @@ -142,23 +142,15 @@ static void mask_key(const struct p4tc_table_entry_mask *mask, u8 *masked_key, masked_key[i] = skb_key[i] & mask->fa_value[i]; } -struct p4tc_table_entry *p4tc_table_entry_lookup(struct sk_buff *skb, - struct p4tc_table *table, - u32 keysz) +struct p4tc_table_entry * +p4tc_table_entry_lookup_direct(struct p4tc_table *table, + struct p4tc_table_entry_key *key) { - const struct p4tc_table_entry_mask **masks_array; - u32 smallest_prio = U32_MAX; struct p4tc_table_entry *entry = NULL; - struct p4tc_percpu_scratchpad *pad; - struct p4tc_table_entry_key *key; + u32 smallest_prio = U32_MAX; + const struct p4tc_table_entry_mask **masks_array; int i; - pad = this_cpu_ptr(&p4tc_percpu_scratchpad); - - key = (struct p4tc_table_entry_key *)&pad->keysz; - key->keysz = keysz; - key->maskid = 0; - if (table->tbl_type == P4TC_TABLE_TYPE_EXACT) return __p4tc_entry_lookup_fast(table, key); @@ -194,6 +186,24 @@ struct p4tc_table_entry *p4tc_table_entry_lookup(struct sk_buff *skb, return entry; } +#ifndef CONFIG_NET_P4_TC_KFUNCS +struct p4tc_table_entry *p4tc_table_entry_lookup(struct sk_buff *skb, + struct p4tc_table *table, + u32 keysz) +{ + struct p4tc_percpu_scratchpad *pad; + struct p4tc_table_entry_key *key; + + pad = this_cpu_ptr(&p4tc_percpu_scratchpad); + + key = (void *)&pad->keysz; + key->keysz = keysz; + key->maskid = 0; + + return p4tc_table_entry_lookup_direct(table, key); +} +#endif + #define tcf_table_entry_mask_find_byid(table, id) \ (idr_find(&(table)->tbl_masks_idr, id)) @@ -596,6 +606,10 @@ static void tcf_table_entry_put(struct p4tc_table_entry *entry) struct p4tc_pipeline *pipeline = entry_work->pipeline; struct net *net; +#ifdef CONFIG_NET_P4_TC_KFUNCS + kfree(value->act_bpf); +#endif + if (entry_work->defer_deletion) { net = get_net(pipeline->net); refcount_inc(&entry_work->pipeline->p_entry_deferal_ref); @@ -1454,7 +1468,9 @@ static struct p4tc_table_entry *__tcf_table_entry_cu(struct net *net, u32 flags, } if (tb[P4TC_ENTRY_ACT]) { - +#ifdef CONFIG_NET_P4_TC_KFUNCS + struct p4tc_table_entry_act_bpf *act_bpf; +#endif value->acts = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), GFP_KERNEL); if (!value->acts) { @@ -1480,6 +1496,16 @@ static struct p4tc_table_entry *__tcf_table_entry_cu(struct net *net, u32 flags, "Action is not allowed as entry action"); goto free_acts; } + +#ifdef CONFIG_NET_P4_TC_KFUNCS + act_bpf = tcf_table_entry_create_act_bpf(value->acts[0], + extack); + if (IS_ERR(act_bpf)) { + ret = PTR_ERR(act_bpf); + goto free_acts; + } + value->act_bpf = act_bpf; +#endif } rcu_read_lock(); @@ -1491,12 +1517,21 @@ static struct p4tc_table_entry *__tcf_table_entry_cu(struct net *net, u32 flags, whodunnit, true); if (ret < 0) { rcu_read_unlock(); +#ifdef CONFIG_NET_P4_TC_KFUNCS + goto free_act_bpf; +#else goto free_acts; +#endif } rcu_read_unlock(); return entry; +#ifdef CONFIG_NET_P4_TC_KFUNCS +free_act_bpf: + kfree(value->act_bpf); +#endif + free_acts: p4tc_action_destroy(value->acts); @@ -1510,6 +1545,58 @@ static struct p4tc_table_entry *__tcf_table_entry_cu(struct net *net, u32 flags, return ERR_PTR(ret); } +#ifdef CONFIG_NET_P4_TC_KFUNCS +struct p4tc_table_entry_act_bpf * +tcf_table_entry_create_act_bpf(struct tc_action *action, + struct netlink_ext_ack *extack) +{ + size_t tot_params_sz = 0; + int num_params = 0; + struct p4tc_act_param *params[P4TC_MSGBATCH_SIZE]; + struct p4tc_table_entry_act_bpf *act_bpf; + struct p4tc_act_param *param; + unsigned long param_id, tmp; + struct tcf_p4act *p4act; + struct tcf_p4act_params *act_params; + u8 *params_cursor; + int i; + + p4act = to_p4act(action); + + act_params = rcu_dereference(p4act->params); + + idr_for_each_entry_ul(&act_params->params_idr, param, tmp, param_id) { + const struct p4tc_type *type = param->type; + + if (tot_params_sz > P4TC_MAX_PARAM_DATA_SIZE) { + NL_SET_ERR_MSG(extack, "Maximum parameter byte size reached"); + return ERR_PTR(-EINVAL); + } + + tot_params_sz += BITS_TO_BYTES(type->container_bitsz); + params[num_params] = param; + num_params++; + } + + act_bpf = kzalloc(sizeof(*act_bpf), GFP_KERNEL); + if (!act_bpf) + return ERR_PTR(-ENOMEM); + + act_bpf->act_id = p4act->act_id; + params_cursor = (u8 *)act_bpf + sizeof(act_bpf->act_id); + for (i = 0; i < num_params; i++) { + const struct p4tc_act_param *param = params[i]; + const struct p4tc_type *type = param->type; + const u32 type_bytesz = BITS_TO_BYTES(type->container_bitsz); + + memcpy(params_cursor, param->value, type_bytesz); + params_cursor += type_bytesz; + } + + return act_bpf; +} +#endif + static int tcf_table_entry_cu(struct sk_buff *skb, struct net *net, u32 flags, struct nlattr *arg, u32 *ids, struct p4tc_nl_pname *nl_pname, diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c index e8f2ad250256..8e9d3cda44a3 100644 --- a/net/sched/p4tc/p4tc_tmpl_api.c +++ b/net/sched/p4tc/p4tc_tmpl_api.c @@ -42,7 +42,9 @@ static bool obj_is_valid(u32 obj) { switch (obj) { case P4TC_OBJ_PIPELINE: +#ifndef CONFIG_NET_P4_TC_KFUNCS case P4TC_OBJ_META: +#endif case P4TC_OBJ_HDR_FIELD: case P4TC_OBJ_ACT: case P4TC_OBJ_TABLE: @@ -55,7 +57,9 @@ static bool obj_is_valid(u32 obj) static const struct p4tc_template_ops *p4tc_ops[P4TC_OBJ_MAX] = { [P4TC_OBJ_PIPELINE] = &p4tc_pipeline_ops, +#ifndef CONFIG_NET_P4_TC_KFUNCS [P4TC_OBJ_META] = &p4tc_meta_ops, +#endif [P4TC_OBJ_HDR_FIELD] = &p4tc_hdrfield_ops, [P4TC_OBJ_ACT] = &p4tc_act_ops, [P4TC_OBJ_TABLE] = &p4tc_table_ops, @@ -576,6 +580,9 @@ static int __init p4tc_template_init(void) for (obj = P4TC_OBJ_PIPELINE; obj < P4TC_OBJ_MAX; obj++) { const struct p4tc_template_ops *op = p4tc_ops[obj]; + if (!op) + continue; + if (!obj_is_valid(obj)) continue; @@ -583,6 +590,8 @@ static int __init p4tc_template_init(void) op->init(); } + register_p4tc_tbl_bpf(); + return 0; } From patchwork Wed May 17 11:02:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamal Hadi Salim X-Patchwork-Id: 13244710 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CC5201DDDF for ; Wed, 17 May 2023 11:06:25 +0000 (UTC) Received: from mail-qv1-xf2c.google.com (mail-qv1-xf2c.google.com [IPv6:2607:f8b0:4864:20::f2c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 64A1C3AA2 for ; Wed, 17 May 2023 04:06:01 -0700 (PDT) Received: by mail-qv1-xf2c.google.com with SMTP id 6a1803df08f44-62382e86f81so2647686d6.2 for ; Wed, 17 May 2023 04:06:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20221208.gappssmtp.com; s=20221208; t=1684321558; x=1686913558; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=F359foBVI4KeTkwCPYpfU3IQkrtdQV05u9sCGLSOEpE=; b=XB/2snwuApR+43tpojuto8RTZ41a3zEUHypcAYUpO04MtDNNRdD13Vr5qpbMf4lghP EtVGblvbQhhZF6cktlrg2+WHKWlDZ3a2LOsmxXNW2crsPafKq0cB+93zY/+9L07GeyNq xeT1d5I6x/cJalzYD8ZtPZ2z+Gk9gl5c202SYmk48qdlFww+zmwFtturxXJFz5gvZUUj yItxMEfDQ0md+QbQ/nOyTC2pJbEMKM8V8g01tM6VQyz71EVmLTUU1rWFKBTLv8irX1yJ dSn+pwrjiHRCqul6wH/TBdIArh1wRstEl8MUf76LAQNGmhZZiPsrT3FVedWxBHfHkcMN tx2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684321558; x=1686913558; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=F359foBVI4KeTkwCPYpfU3IQkrtdQV05u9sCGLSOEpE=; b=MrZDjYgCA8Jd/9XqvxbxSeALmZLocyAxsfJ8BjXYd+yEXq7ff966UU/dgX+CRoz8xI Dhp1TiQbYfMs49uaw8qDeV3fLw9xMh28emImx/Z8vEMZLMVULIgsRvrqEx+ShVVxhbb+ 6HfdqL7fbrZS7onuM1n0Nqt9W92B6a0cryKuMNjPVMLfcT66HAYHnMQWnaBIPUHhSRew db1+ubmmsVjK8yHrwGA4MeBRXTfdaWkRvPoe68vPWCR5xWyBj4xp6V3Jr9OHSFg35QpF GPpc94kK7mrtAm0GdNulw6KesSQf8ZVq1+XsihfkvFGwhL++QZ++4I5hw1yOramiOjXB uCqg== X-Gm-Message-State: AC+VfDxpZRTqjZk0KrROftSMZspks9LtxEE2K7Mmn4+M5gaL6qDPRG5Z 1kNHZ0rknUiTxmaaHrwNodmv1Wepl2Qc2qq2BuQ= X-Google-Smtp-Source: ACHHUZ4e2SOL+4l/Q5s/3EsLDiBkv/PPn1pTT58JPwEuU4zHqcPoqwRLpj87nBJRZ/vVj7dEAd3FGA== X-Received: by 2002:a05:6214:c43:b0:621:23f3:5815 with SMTP id r3-20020a0562140c4300b0062123f35815mr53675368qvj.45.1684321557109; Wed, 17 May 2023 04:05:57 -0700 (PDT) Received: from majuu.waya (cpe688f2e2c8c63-cm688f2e2c8c60.cpe.net.cable.rogers.com. [174.112.105.47]) by smtp.gmail.com with ESMTPSA id m24-20020aed27d8000000b003f364778b2bsm7060305qtg.4.2023.05.17.04.05.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 04:05:56 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: deb.chatterjee@intel.com, anjali.singhai@intel.com, namrata.limaye@intel.com, tom@sipanda.io, p4tc-discussions@netdevconf.info, mleitner@redhat.com, Mahesh.Shirshyad@amd.com, Vipin.Jain@amd.com, tomasz.osinski@intel.com, jiri@resnulli.us, xiyou.wangcong@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, vladbu@nvidia.com, simon.horman@corigine.com, khalidm@nvidia.com, toke@redhat.com Subject: [PATCH RFC v2 net-next 28/28] MAINTAINERS: add p4tc entry Date: Wed, 17 May 2023 07:02:32 -0400 Message-Id: <20230517110232.29349-28-jhs@mojatatu.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230517110232.29349-1-jhs@mojatatu.com> References: <20230517110232.29349-1-jhs@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC P4TC is currently maintained by Mojatatu Networks. Signed-off-by: Victor Nogueira Signed-off-by: Pedro Tammela Signed-off-by: Jamal Hadi Salim --- MAINTAINERS | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ebd26b3ca90e..32f6cd30a855 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15782,6 +15782,20 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git F: Documentation/filesystems/overlayfs.rst F: fs/overlayfs/ +P4TC +M: Victor Nogueira +M: Jamal Hadi Salim +M: Pedro Tammela +L: netdev@vger.kernel.org +S: Supported +F: include/net/p4tc.h +F: include/net/p4tc_types.h +F: include/net/tc_act/p4tc.h +F: include/uapi/linux/p4tc.h +F: net/sched/cls_p4.c +F: net/sched/p4tc/ +F: tools/testing/selftests/tc-testing/tc-tests/p4tc/ + P54 WIRELESS DRIVER M: Christian Lamparter L: linux-wireless@vger.kernel.org