All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC v3 net-next 00/21] Introducing P4TC
@ 2023-06-29 10:45 Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 01/21] net: sched: act_api: Add dynamic actions IDR Jamal Hadi Salim
                   ` (20 more replies)
  0 siblings, 21 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, dan.daly,
	john.andy.fingerhut

We are seeking community feedback on P4TC patches.

Please do note that > 50% of LOC are testcases.

Changes In Version 2
--------------------

Version 2 was the initial integration of the eBPF s/w datapath.
We took into consideration suggestions provided and added eBPF S/W datapath
support after extensive testing. We implemented 6 approaches with eBPF and ran
performance analysis and presented our results at the P4 2023 workshop in Santa
Clara[see: 1, 3] on each of the 6 vs scriptable P4TC and concluded that 2 of the
approaches are sensible (4 if you account for XDP or TC separately).

Conclusions from the exercise: We lose the simple operational model we had
prior to integrating eBPF. We do gain performance in most cases where the
datapath is less compute-bound.
For more discussion on our requirements vs journeying the ebpf path please
scroll down to "Restating Our Requirements" and "Challenges".

This patch set presented two modes.
mode1: the parser is entirely based on ebpf - whereas the rest of the
SW datapath stays as _scriptable_ as in Version 1.
mode2: All of the kernel s/w datapath (including parser) is in eBPF.

The key ingredient for eBPF, that we did not have access to in the past, is
kfunc (it made a big difference for us to reconsider eBPF).

In V2 the two modes are mutually exclusive (IOW, you get to choose one
or the other via Kconfig).

Changes in This version 3
-------------------------

These patches are still in a little bit of flux as we adjust to integrating
ebpf. So there are small constructs that are used in V1 and 2 but no longer
used in this version. We will make a V4 which will remove those.
The changes from V2 are as follows:

1) Feedback we got in V2 is to try stick to one of the two modes. In this version
we are taking one more step and going the path of mode2 vs v2 where we had 2 modes.

2) The P4 Register extern is no longer standalone. Instead, as part of integrating
into eBPF we introduce another kfunc which encapsulates Register as part of the
extern interface.

3) We have improved our CICD to include tools pointed to us by Simon. See
   "Testing" further below. Thanks to Simon for that and other issues he caught.
   Simon, we discussed on issue [7] but decided to keep that log since we think
   it is useful.

4) A lot of small cleanups. Thanks Marcelo. There are two things we need to
   rediscuss though; see: [5], [6].

5) We removed the need for a range of IDs for dynamic actions. Thanks Jakub.

6) Clarify ambiguity caused by smatch in an if(A) else if(B) condition. We are
   guaranteed that either A or B must exist; however, lets make smatch happy.
   Thanks to Simon and Dan Carpenter.

What is P4?
-----------

The Programming Protocol-independent Packet Processors (P4) is an open source,
domain-specific programming language for specifying data plane behavior.

The P4 ecosystem includes an extensive range of deployements, products, projects
and services, etc. For Details, visit: https://p4.org/

__What is P4TC?__

P4TC is an implementation of P4 building on top of many years of Linux TC
experiences. On why P4 - see small treatise here:[4].

There have been many discussions and meetings since about 2015 in regards to
P4 over TC [2] and we are finally proving the naysayers that we do get stuff
done!

A lot more of the P4TC motivation is captured at:
https://github.com/p4tc-dev/docs/blob/main/why-p4tc.md
XXX: To be updated to describe integration with eBPF s/w datapath.

In this patch series we focus on s/w datapath only.

__P4TC Workflow__

These patches enable kernel and user space code change _independency_ for any
new P4 program that describes a new datapath. The workflow is as follows:

  1) A developer writes a P4 program, "myprog"

  2) Compiles it using the P4C compiler[8]. The compiler generates 3 outputs:
     a) shell script(s) which form template definitions for the different P4
     objects "myprog" utilizes (tables, externs, actions etc).
     b) the parser and the rest of the sw datapath are generated
     in ebpf and need to be compiled into binaries.
     c) A json introspection file used for control plane (by iproute2/tc).

  3) The developer (or operator) executes the shell script(s) to manifest the
     functional s/w equivalent of "myprog" into the kernel.

  4) The developer (or operator) instantiates "myprog" via the tc P4 filter
     to ingress/egress (depending on P4 arch) of one or more netdevs/ports.

     Example1: parser is an action:
       "tc filter add block 22 ingress protocol any prio 1 p4 pname myprog \
        action bpf obj $PARSER.o section parser/tc-ingress \
        action bpf obj $PROGNAME.o section p4prog/tc"

     Example2: parser explicitly bound and rest of sw dpath as an action:
       "tc filter add block 22 ingress protocol any prio 1 p4 pname myprog \
        prog tc obj $PARSER.o section parser/tc-ingress \
        action bpf obj $PROGNAME.o section p4prog/tc"

     Example3: parser is at XDP, rest of sw dpath as an action:
       "tc filter add block 22 ingress protocol any prio 1 p4 pname myprog \
        prog xdp obj $PARSER.o section parser/xdp-ingress \
        action bpf obj $PROGNAME.o section p4prog/tc"

     Example4: parser+prog at XDP:
       "tc filter add block 22 ingress protocol any prio 1 p4 pname myprog \
        prog xdp obj $PROGNAME.o section p4prog/xdp"

    see individual patches for more examples tc vs xdp etc. Also see section on
    "challenges".

Once "myprog" is instantiated one can start updating table entries that are
associated with "myprog". Example:
  tc p4runtime create myprog/mytable dstAddr 10.0.1.2/32 \
    action send_to_port param port eno1

A packet arriving on ingress of any of the ports on block 22 will first be
exercised via the (ebpf) parser to find the headers pointing to the ip
destination address.
The remainder ebpf datapath uses the result dstAddr as a key to (kfunc) lookup
myprog's mytable which returns the action params which are then used to execute
the action in the ebpf datapath (eventually sending out packets to eno1).
On a miss, mytable's default miss action is executed.

__Description of Patches__

P4TC is designed to have no impact on the core code for other users
of TC. IOW, you can compile it out or as a module and if you dont use
it then there should be no impact on your performance.

We do make core kernel changes. Patch #1 introduces new "dynamic" actions
that can be created on "the fly" based on the P4 program requirement.
This patch makes a small incision into act_api which shouldnt affect the
performance of the existing actions. Patches 2-6 are minimalist enablers for
P4TC and have no effect the classical tc action.

The core P4TC code implements several P4 objects.

1) Patch #7 introduces P4 data types which are consumed by the rest of the code
2) Patch #8 introduces the concept of templating Pipelines. i.e CRUD commands
   for P4 pipelines.
3) Patch #9 introduces the concept of P4 header fields and associated CRUD
   template commands.
4) Patch #10 introduces the concept of action templates and associated
   CRUD commands.
5) Patch #11 introduces the concept of P4 table templates and associated
   CRUD commands for tables
6) Patch #12 introduces table entries and associated CRUD commands.
7) Patch #13 introduces interaction of eBPF to P4TC domain via kfunc.
8) Patch #14 introduces the TC classifier P4 used at runtime. Only with
    mode1 support.
9) Patch #15 introduces extern interfacing
10) Patches #16-20 are control tests for the different objects

__Testing__

Speaking of testing - we have about 400 tdc test cases. This number is growing.
These tests are run on our CICD system on pull requests and after commits are
approved. The CICD does a lot of other tests (more since v2) including:
checkpatch, sparse, smatch, coccinelle, 32 bit and 64 bit builds tested on both
X86, ARM 64 and emulated BE via qemu s390. We trigger performance testing in the
CICD to catch performance regressions (currently only on the control path, but
in the future for the datapath).
Syzkaller runs 24/7 on dedicated hardware, originally we focussed only on memory
sanitizer but recently added support for concurency sanitizer.
Before main releases we ensure each patch will compile on its own to help in
git bisect and run the xmas tree tool. We eventually put the code via coverity.

In addition we are working on a tool that will take a p4 program, run it through
the compiler, and generate permutations of traffic patterns via symbolic
execution that will test both positive and negative datapath code paths. The
test generator tool is still work in progress and will be generated by the P4
compiler.
Note: We have other code that test parallelization etc which we are trying to
find a fit for in the kernel tree.

__Restating Our Requirements__

Our original intent was to target the TC crowd for both s/w and h/w offload.
Essentially developers and ops people deploying TC based infra.
More importantly the original intent for P4TC was to enable ops folks more than
devs.

With TC we get whole "familiar" package of match-action pipeline abstraction ++:
from the control plane to the tooling infra, netlink messaging to s/w and h/w
symbiosis, the autonomous kernel control, etc. The advantage is that we have a
singular vendor-neutral interface via the kernel using well understood
mechanisms based on deployment experience.

1) Supporting expressibility of universe set of P4 progs

It is a must to support 100% of all possible P4 programs. In the past the eBPF
verifier had to be worked around and even then there are cases where we couldnt
avoid path explosion when branching is involved. Kfunc-ing solves these issues
for us. Note, there are still challenges running all potential P4 programs at
the XDP level - the solution to that is to have the compiler generate XDP based
code only if it possible to map it to that layer.

2) Support for P4 HW and SW equivalence.

This feature continues to work even in the presence of eBPF as the s/w
datapath. There are cases of square-hole-round-peg scenarios but
those are implementation issues we can live with.

3) Operational usability

By maintaining the TC control plane (even in presence of eBPF s/w datapath)
runtime aspects remain unchanged. So for our target audience of folks
who have deployed tc including offloads - the comfort zone is unchanged.

There is some loss in operational usability because we now have more knobs:
the extra compilation, loading and syncing of binaries, etc.
IOW, I can no longer just ship someone a shell script in an email to
say go run this and "myprog" will just work.

4) Operational and development Debuggability

If something goes wrong, the tc craftsperson is now required to have additional
knowledge of eBPF code and process. This applies to both the operational person
as well as someone who wrote a driver. We dont believe this is solvable.

5) Opportunity for rapid protoyping of new ideas

During the P4TC development phase something that came naturally was to often
handcode the template scripts because the compiler backend (which is P4 arch
specific) wasnt ready to generate certain things. Then you would read back the
template and diff to ensure the kernel didnt get something wrong. So this
started as a debug feature. During development, we wrote scripts that
covered a range of P4 architectures(PSA, V1, etc) which required no kernel code
changes.

In its basic form it boils down to the old adage of a niche DSL script vs a
compiled general purpose language such as eBPF. Given our target audience who
know P4/TC, and understand our hooks, the shell script whose command set is more
aligned to P4 is a natural fit compared to handcoding eBPF.

Over time the debug feature morphed into: start by handcoding scripts then
read it back and then generate the P4 code.
It means one could start with the template scripts outside of the constraints
of a P4 architecture spec(PNA/PSA) or even within a P4 architecture then test
some ideas and eventually feed back the concepts to the compiler authors or
modify or create a new P4 architecure and share with the P4 standards folks.

To summarize in presence of eBPF: The debugging idea is still alive.
One could dump with proper tooling(bpftool for example) the loaded eBPF code
and be able to check for differences.
The concept of going back from whats in the kernel to P4 is a lot more difficult
to implement mostly due to scoping of DSL vs general purpose. It may be lost.
We have been thinking of ways to use BTF and embedding annotations in the eBPF
code and binary but more thought is required and we welcome suggestions.

6) Performance

It is clear you gain better performance for the sw datapath with eBPF. Refer to
our results for the tests we did[1].
Note: for computationaly complex programs this value diminishes i.e the
gap between XDP and TC eBPF or even in some cases scriptable approach is not
prominent; however, we do acknowledge there is an observable performance gain
as expected (compiled vs interpreted approach).

__Challenges__

1) When we have either the parser or part/whole of s/w datapath running in XDP
   then we need to make sure that the instantiation at the TC level is aware.
   For this we reason we need a mechanism for ensuring that the XDP program
   stays alive. Unfortunately we dont have a clean way of doing this at the
   moment i.e the program could be removed under us. It would be useful to have
   a refcount mechanism where the program cant be unbound from a port/netdev.
   Andrii Nakryiko made a suggestion to use bpf link for XDP which we are going
   to try out.

2) Concept of tc block in XDP is tedious to implement.

3) Right now we are using "packed" construct to enforce alignment in kfunc data
   exchange; but we're wondering if there is potential to use BTF to understand
   parameters and their offsets and encode this information at the compiler
   level.

4) At the moment we are creating a static buffer of 128B to retrieve the action
   parameters. If you have a lot of table entries and individual(non-shared)
   action instances with actions that require very little (or no) param space
   a lot of memory is wasted. If we can have dynamic pointers instead for
   kfunc fixed length parametrization then this issue is resolvable.

5) See "Restating Our Requirements" #5.
   We would really appreciate ideas/suggestions, etc.

__References__

[1]https://github.com/p4tc-dev/docs/blob/main/p4-conference-2023/2023P4WorkshopP4TC.pdf
[2]https://github.com/p4tc-dev/docs/blob/main/why-p4tc.md#historical-perspective-for-p4tc
[3]https://2023p4workshop.sched.com/event/1KsAe/p4tc-linux-kernel-p4-implementation-approaches-and-evaluation
[4]https://github.com/p4tc-dev/docs/blob/main/why-p4tc.md#so-why-p4-and-how-does-p4-help-here
[5]https://lore.kernel.org/netdev/20230517110232.29349-3-jhs@mojatatu.com/T/#mf59be7abc5df3473cff3879c8cc3e2369c0640a6
[6]https://lore.kernel.org/netdev/20230517110232.29349-3-jhs@mojatatu.com/T/#m783cfd79e9d755cf0e7afc1a7d5404635a5b1919
[7]https://lore.kernel.org/netdev/20230517110232.29349-3-jhs@mojatatu.com/T/#ma8c84df0f7043d17b98f3d67aab0f4904c600469
[8]https://github.com/p4lang/p4c/tree/main/backends/tc

Jamal Hadi Salim (21):
  net: sched: act_api: Add dynamic actions IDR
  net/sched: act_api: increase action kind string length
  net/sched: act_api: add init_ops to struct tc_action_op
  net/sched: act_api: export generic tc action searcher
  net/sched: act_api: add struct p4tc_action_ops as a parameter to
    lookup callback
  net: introduce rcu_replace_pointer_rtnl
  p4tc: add P4 data types
  p4tc: add pipeline create, get, update, delete
  p4tc: add header field create, get, delete, flush and dump
  p4tc: add action template create, update, delete, get, flush and dump
  p4tc: add table create, update, delete, get, flush and dump
  p4tc: add table entry create, update, get, delete, flush and dump
  p4tc: add set of P4TC table lookup kfuncs
  p4tc: add P4 classifier
  p4tc: Add P4 externs
  selftests: tc-testing: add JSON introspection file directory for P4TC
  selftests: tc-testing: add P4TC pipeline control path tdc tests
  selftests: tc-testing: add P4TC action templates tdc tests
  selftests: tc-testing: add P4TC table control path tdc tests
  selftests: tc-testing: add P4TC table entries control path tdc tests
  MAINTAINERS: add p4tc entry

 MAINTAINERS                                   |    14 +
 include/linux/bitops.h                        |     1 +
 include/linux/rtnetlink.h                     |    12 +
 include/net/act_api.h                         |    20 +-
 include/net/p4tc.h                            |   649 +
 include/net/p4tc_ext_api.h                    |    87 +
 include/net/p4tc_types.h                      |    87 +
 include/net/tc_act/p4tc.h                     |    25 +
 include/uapi/linux/p4tc.h                     |   389 +
 include/uapi/linux/p4tc_ext.h                 |    38 +
 include/uapi/linux/pkt_cls.h                  |    21 +-
 include/uapi/linux/rtnetlink.h                |    14 +
 net/sched/Kconfig                             |    21 +
 net/sched/Makefile                            |     3 +
 net/sched/act_api.c                           |   158 +-
 net/sched/cls_api.c                           |     2 +-
 net/sched/cls_p4.c                            |   497 +
 net/sched/p4tc/Makefile                       |     8 +
 net/sched/p4tc/p4tc_action.c                  |  1725 +++
 net/sched/p4tc/p4tc_bpf.c                     |   129 +
 net/sched/p4tc/p4tc_ext.c                     |  1978 +++
 net/sched/p4tc/p4tc_hdrfield.c                |   597 +
 net/sched/p4tc/p4tc_parser_api.c              |   146 +
 net/sched/p4tc/p4tc_pipeline.c                |   694 +
 net/sched/p4tc/p4tc_runtime_api.c             |   144 +
 net/sched/p4tc/p4tc_table.c                   |  1451 ++
 net/sched/p4tc/p4tc_tbl_entry.c               |  2068 +++
 net/sched/p4tc/p4tc_tmpl_api.c                |   594 +
 net/sched/p4tc/p4tc_tmpl_ext.c                |  2256 +++
 net/sched/p4tc/p4tc_types.c                   |  1255 ++
 net/sched/p4tc/trace.c                        |    10 +
 net/sched/p4tc/trace.h                        |    44 +
 security/selinux/nlmsgtab.c                   |     8 +-
 .../introspection-examples/example_pipe.json  |    92 +
 .../tc-tests/p4tc/action_templates.json       | 12378 ++++++++++++++++
 .../tc-testing/tc-tests/p4tc/pipeline.json    |  3212 ++++
 .../tc-testing/tc-tests/p4tc/table.json       |  8956 +++++++++++
 .../tc-tests/p4tc/table_entries.json          |  3818 +++++
 38 files changed, 43572 insertions(+), 29 deletions(-)
 create mode 100644 include/net/p4tc.h
 create mode 100644 include/net/p4tc_ext_api.h
 create mode 100644 include/net/p4tc_types.h
 create mode 100644 include/net/tc_act/p4tc.h
 create mode 100644 include/uapi/linux/p4tc.h
 create mode 100644 include/uapi/linux/p4tc_ext.h
 create mode 100644 net/sched/cls_p4.c
 create mode 100644 net/sched/p4tc/Makefile
 create mode 100644 net/sched/p4tc/p4tc_action.c
 create mode 100644 net/sched/p4tc/p4tc_bpf.c
 create mode 100644 net/sched/p4tc/p4tc_ext.c
 create mode 100644 net/sched/p4tc/p4tc_hdrfield.c
 create mode 100644 net/sched/p4tc/p4tc_parser_api.c
 create mode 100644 net/sched/p4tc/p4tc_pipeline.c
 create mode 100644 net/sched/p4tc/p4tc_runtime_api.c
 create mode 100644 net/sched/p4tc/p4tc_table.c
 create mode 100644 net/sched/p4tc/p4tc_tbl_entry.c
 create mode 100644 net/sched/p4tc/p4tc_tmpl_api.c
 create mode 100644 net/sched/p4tc/p4tc_tmpl_ext.c
 create mode 100644 net/sched/p4tc/p4tc_types.c
 create mode 100644 net/sched/p4tc/trace.c
 create mode 100644 net/sched/p4tc/trace.h
 create mode 100644 tools/testing/selftests/tc-testing/introspection-examples/example_pipe.json
 create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/action_templates.json
 create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/pipeline.json
 create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/table.json
 create mode 100644 tools/testing/selftests/tc-testing/tc-tests/p4tc/table_entries.json

-- 
2.34.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 01/21] net: sched: act_api: Add dynamic actions IDR
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 02/21] net/sched: act_api: increase action kind string length Jamal Hadi Salim
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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. 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 <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/net/act_api.h        |   6 +-
 include/uapi/linux/pkt_cls.h |   2 +-
 net/sched/act_api.c          | 130 +++++++++++++++++++++++++++++++----
 net/sched/cls_api.c          |   2 +-
 4 files changed, 124 insertions(+), 16 deletions(-)

diff --git a/include/net/act_api.h b/include/net/act_api.h
index 4ae0580b6..54754deed 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/net/sched/act_api.c b/net/sched/act_api.c
index f7887f42d..5e5f299d2 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,29 @@ 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);
+
+	/* Dynamic actions start counting after TCA_ID_MAX + 1*/
+	act->id = TCA_ID_MAX + 1;
+
+	ret = idr_alloc_u32(&dyn_base_net->act_base, act, &act->id,
+			    USHRT_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 +1070,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 +1398,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 +1430,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 +1439,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 +1549,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 +1760,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 +1808,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 +2214,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 +2281,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 2621550bf..4af48f76f 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))
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 02/21] net/sched: act_api: increase action kind string length
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 01/21] net: sched: act_api: Add dynamic actions IDR Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 03/21] net/sched: act_api: add init_ops to struct tc_action_op Jamal Hadi Salim
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, kernel, mattyk, john.andy.fingerhut

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 <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 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 54754deed..a414c0f94 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 142fd152b..818e71e13 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -6,6 +6,7 @@
 #include <linux/pkt_sched.h>
 
 #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 5e5f299d2..420cf2617 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 */
@@ -1404,7 +1404,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;
 
@@ -1419,7 +1419,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);
 		}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 03/21] net/sched: act_api: add init_ops to struct tc_action_op
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 01/21] net: sched: act_api: Add dynamic actions IDR Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 02/21] net/sched: act_api: increase action kind string length Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 04/21] net/sched: act_api: export generic tc action searcher Jamal Hadi Salim
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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 and the action name. 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 <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/net/act_api.h |  6 ++++++
 net/sched/act_api.c   | 14 +++++++++++---
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/include/net/act_api.h b/include/net/act_api.h
index a414c0f94..363f7f8b5 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 420cf2617..6749f8d94 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1007,7 +1007,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,
@@ -1495,8 +1495,16 @@ 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);
+		/* When we arrive here we guarantee that a_o->init or
+		 * a_o->init_ops exist.
+		 */
+		if (a_o->init)
+			err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, tp,
+					userflags.value | flags, extack);
+		else
+			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);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 04/21] net/sched: act_api: export generic tc action searcher
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (2 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 03/21] net/sched: act_api: add init_ops to struct tc_action_op Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 05/21] net/sched: act_api: add struct p4tc_action_ops as a parameter to lookup callback Jamal Hadi Salim
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

In P4TC we need to query the tc actions directly in a net namespace.
Therefore export __tcf_idr_search().

Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 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 363f7f8b5..c2236274a 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 6749f8d94..19d948fd0 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)
 {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 05/21] net/sched: act_api: add struct p4tc_action_ops as a parameter to lookup callback
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (3 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 04/21] net/sched: act_api: export generic tc action searcher Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 06/21] net: introduce rcu_replace_pointer_rtnl Jamal Hadi Salim
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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 <victor@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 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 c2236274a..19770e8af 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 19d948fd0..42af73eaa 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);
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 06/21] net: introduce rcu_replace_pointer_rtnl
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (4 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 05/21] net/sched: act_api: add struct p4tc_action_ops as a parameter to lookup callback Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 07/21] p4tc: add P4 data types Jamal Hadi Salim
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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 <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/linux/rtnetlink.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 3d6cf306c..971055e66 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
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 07/21] p4tc: add P4 data types
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (5 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 06/21] net: introduce rcu_replace_pointer_rtnl Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 08/21] p4tc: add pipeline create, get, update, delete Jamal Hadi Salim
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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[4-9]. A 4-bit slice from bits 0-3 and a 6-bit slice from bits
   4-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 <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 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 | 1255 +++++++++++++++++++++++++++++++++++
 6 files changed, 1395 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 000000000..232399533
--- /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 <linux/netlink.h>
+#include <linux/pkt_cls.h>
+#include <linux/types.h>
+
+#include <uapi/linux/p4tc.h>
+
+#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);
+	void (*host_read)(struct p4tc_type *container,
+			  struct p4tc_type_mask_shift *mask_shift, void *sval,
+			  void *dval);
+	void (*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_is_type_unsigned(int typeid);
+
+void 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
+void __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);
+void __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 void __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 void __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 000000000..2b6f126db
--- /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 4b95cb1ac..ea57a4c7b 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 b5fd49641..937b8f8a9 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 000000000..dd1358c9e
--- /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 000000000..4bc36d2e4
--- /dev/null
+++ b/net/sched/p4tc/p4tc_types.c
@@ -0,0 +1,1255 @@
+// 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 <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <net/net_namespace.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
+#include <net/act_api.h>
+#include <net/p4tc_types.h>
+#include <linux/etherdevice.h>
+
+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)
+{
+	unsigned long tmp, typeid;
+	struct p4tc_type *type;
+
+	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_is_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;
+	}
+}
+
+void 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);
+}
+
+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;
+	}
+
+	if (bitstart > bitend) {
+		NL_SET_ERR_MSG_MOD(extack, "bitstart > bitend");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+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 void p4t_u32_write(struct p4tc_type *container,
+			  struct p4tc_type_mask_shift *mask_shift, void *sval,
+			  void *dval)
+{
+	u32 maskedst = 0;
+	u32 *dst = dval;
+	u32 *src = sval;
+	u8 shift = 0;
+
+	if (mask_shift) {
+		u32 *dmask = mask_shift->mask;
+
+		maskedst = *dst & ~*dmask;
+		shift = mask_shift->shift;
+	}
+
+	*dst = maskedst | (*src << shift);
+}
+
+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 void 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;
+	}
+}
+
+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 void 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;
+}
+
+static void 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;
+}
+
+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;
+	__be32 *val_u32 = value;
+	__u32 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_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 void p4t_be32_hread(struct p4tc_type *container,
+			   struct p4tc_type_mask_shift *mask_shift, void *sval,
+			   void *dval)
+{
+	__be32 *src = sval;
+	u32 *dst = dval;
+
+	*dst = be32_to_cpu(*src);
+}
+
+static void p4t_be32_write(struct p4tc_type *container,
+			   struct p4tc_type_mask_shift *mask_shift, void *sval,
+			   void *dval)
+{
+	__be32 *dst = dval;
+	u32 *src = sval;
+
+	*dst = cpu_to_be32(*src);
+}
+
+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 void p4t_be64_hread(struct p4tc_type *container,
+			   struct p4tc_type_mask_shift *mask_shift, void *sval,
+			   void *dval)
+{
+	__be64 *src = sval;
+	u64 *dst = dval;
+
+	*dst = be64_to_cpu(*src);
+}
+
+static void p4t_be64_write(struct p4tc_type *container,
+			   struct p4tc_type_mask_shift *mask_shift, void *sval,
+			   void *dval)
+{
+	__be64 *dst = dval;
+	u64 *src = sval;
+
+	*dst = cpu_to_be64(*src);
+}
+
+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 void p4t_u16_write(struct p4tc_type *container,
+			  struct p4tc_type_mask_shift *mask_shift, void *sval,
+			  void *dval)
+{
+	u16 maskedst = 0;
+	u16 *dst = dval;
+	u16 *src = sval;
+	u8 shift = 0;
+
+	if (mask_shift) {
+		u16 *dmask = mask_shift->mask;
+
+		maskedst = *dst & ~*dmask;
+		shift = mask_shift->shift;
+	}
+
+	*dst = maskedst | (*src << shift);
+}
+
+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 void 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;
+	}
+}
+
+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 void 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;
+}
+
+static void 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;
+}
+
+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)
+{
+	u16 container_maxsz = U16_MAX;
+	__be16 *val_u16 = value;
+	u16 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_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 void p4t_be16_hread(struct p4tc_type *container,
+			   struct p4tc_type_mask_shift *mask_shift, void *sval,
+			   void *dval)
+{
+	__be16 *src = sval;
+	u16 *dst = dval;
+
+	*dst = be16_to_cpu(*src);
+}
+
+static void p4t_be16_write(struct p4tc_type *container,
+			   struct p4tc_type_mask_shift *mask_shift, void *sval,
+			   void *dval)
+{
+	__be16 *dst = dval;
+	u16 *src = sval;
+
+	*dst = cpu_to_be16(*src);
+}
+
+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)
+{
+	size_t container_maxsz = U8_MAX;
+	u8 *val = value;
+	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 void p4t_u8_write(struct p4tc_type *container,
+			 struct p4tc_type_mask_shift *mask_shift, void *sval,
+			 void *dval)
+{
+	u8 maskedst = 0;
+	u8 *dst = dval;
+	u8 *src = sval;
+	u8 shift = 0;
+
+	if (mask_shift) {
+		u8 *dmask = (u8 *)mask_shift->mask;
+
+		maskedst = *dst & ~*dmask;
+		shift = mask_shift->shift;
+	}
+
+	*dst = maskedst | (*src << shift);
+}
+
+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 void 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;
+	}
+}
+
+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 void 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;
+}
+
+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 void p4t_u64_write(struct p4tc_type *container,
+			  struct p4tc_type_mask_shift *mask_shift, void *sval,
+			  void *dval)
+{
+	u64 maskedst = 0;
+	u64 *dst = dval;
+	u64 *src = sval;
+	u8 shift = 0;
+
+	if (mask_shift) {
+		u64 *dmask = (u64 *)mask_shift->mask;
+
+		maskedst = *dst & ~*dmask;
+		shift = mask_shift->shift;
+	}
+
+	*dst = maskedst | (*src << shift);
+}
+
+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 void 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;
+	}
+}
+
+/* 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 void p4t_u128_hread(struct p4tc_type *container,
+			   struct p4tc_type_mask_shift *mask_shift, void *sval,
+			   void *dval)
+{
+	memcpy(sval, dval, sizeof(__u64) * 2);
+}
+
+static void p4t_u128_write(struct p4tc_type *container,
+			   struct p4tc_type_mask_shift *mask_shift, void *sval,
+			   void *dval)
+{
+	memcpy(sval, dval, sizeof(__u64) * 2);
+}
+
+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 *v32h = val;
+	__be32 v32;
+	u8 *v;
+
+	v32 = cpu_to_be32(*v32h);
+	v = (u8 *)&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 void 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;
+}
+
+static void 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;
+}
+
+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 = dev_get_by_index_rcu(net, *ifindex);
+
+	pr_info("%s %s\n", prefix, dev->name);
+}
+
+static void 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));
+}
+
+static void 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));
+}
+
+static void p4t_key_print(struct net *net, struct p4tc_type *container,
+			  const char *prefix, void *val)
+{
+	u16 bitstart = 0, bitend = 63;
+	u64 *v = val;
+	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 void 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;
+}
+
+static void 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;
+}
+
+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
+void __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);
+}
+
+void __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();
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 08/21] p4tc: add pipeline create, get, update, delete
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (6 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 07/21] p4tc: add P4 data types Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 09/21] p4tc: add header field create, get, delete, flush and dump Jamal Hadi Salim
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

__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 use 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.

Co-developed-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/net/p4tc.h             | 109 ++++++
 include/uapi/linux/p4tc.h      |  66 ++++
 include/uapi/linux/rtnetlink.h |   7 +
 net/sched/p4tc/Makefile        |   2 +-
 net/sched/p4tc/p4tc_pipeline.c | 590 +++++++++++++++++++++++++++++++++
 net/sched/p4tc/p4tc_tmpl_api.c | 565 +++++++++++++++++++++++++++++++
 security/selinux/nlmsgtab.c    |   5 +-
 7 files changed, 1342 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 000000000..a2c9d6cc1
--- /dev/null
+++ b/include/net/p4tc.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __NET_P4TC_H
+#define __NET_P4TC_H
+
+#include <uapi/linux/p4tc.h>
+#include <linux/workqueue.h>
+#include <net/sch_generic.h>
+#include <net/net_namespace.h>
+#include <linux/refcount.h>
+#include <linux/rhashtable.h>
+#include <linux/rhashtable-types.h>
+
+#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;
+
+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;
+	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 2b6f126db..ef9e51b31 100644
--- a/include/uapi/linux/p4tc.h
+++ b/include/uapi/linux/p4tc.h
@@ -2,8 +2,71 @@
 #ifndef __LINUX_P4TC_H
 #define __LINUX_P4TC_H
 
+#include <linux/types.h>
+#include <linux/pkt_sched.h>
+
+/* pipeline header */
+struct p4tcmsg {
+	__u32 pipeid;
+	__u32 obj;
+};
+
+#define P4TC_MAXPIPELINE_COUNT 32
+#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_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 +100,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 51c13cf9c..41a4046e7 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 dd1358c9e..0881a7563 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 000000000..4506ff2e1
--- /dev/null
+++ b/net/sched/p4tc/p4tc_pipeline.c
@@ -0,0 +1,590 @@
+// 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 <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/netlink.h>
+#include <net/flow_offload.h>
+#include <net/p4tc_types.h>
+
+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_NUMTABLES] =
+		NLA_POLICY_RANGE(NLA_U16, P4TC_MINTABLES_COUNT, P4TC_MAXTABLES_COUNT),
+	[P4TC_PIPELINE_STATE] = { .type = NLA_U8 },
+};
+
+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);
+
+	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;
+	}
+
+	pipeline->p_state = P4TC_STATE_READY;
+	return true;
+}
+
+static inline bool pipeline_sealed(struct p4tc_pipeline *pipeline)
+{
+	return pipeline->p_state == P4TC_STATE_READY;
+}
+
+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 idr_rm;
+	}
+
+	pipeline->common.p_id = pipeid;
+
+	if (tb[P4TC_PIPELINE_NUMTABLES])
+		pipeline->num_tables =
+			nla_get_u16(tb[P4TC_PIPELINE_NUMTABLES]);
+	else
+		pipeline->num_tables = P4TC_DEFAULT_NUM_TABLES;
+
+	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;
+
+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)
+{
+	u16 num_tables = 0;
+	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)
+		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_STATE]) {
+		ret = pipeline_try_set_state_ready(pipeline, extack);
+		if (ret < 0)
+			goto out;
+	}
+
+	if (num_tables)
+		pipeline->num_tables = num_tables;
+
+	return pipeline;
+
+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;
+
+	nest = nla_nest_start(skb, P4TC_PARAMS);
+	if (!nest)
+		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;
+
+	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];
+	int ret = 0;
+	struct p4tc_template_common *tmpl;
+	struct p4tc_pipeline *pipeline;
+
+	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;
+
+	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 000000000..f844b7c29
--- /dev/null
+++ b/net/sched/p4tc/p4tc_tmpl_api.c
@@ -0,0 +1,565 @@
+// 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 <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/netlink.h>
+#include <net/flow_offload.h>
+
+static const struct nla_policy p4tc_root_policy[P4TC_ROOT_MAX + 1] = {
+	[P4TC_ROOT] = { .type = NLA_NESTED },
+	[P4TC_ROOT_PNAME] = { .type = NLA_STRING, .len = PIPELINENAMSIZ },
+};
+
+static 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 p4tc_template_common *tmpl;
+	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");
+		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 (!op)
+			continue;
+
+		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 2ee7b4ed4..0a8daf2f8 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;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 09/21] p4tc: add header field create, get, delete, flush and dump
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (7 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 08/21] p4tc: add pipeline create, get, update, delete Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 10/21] p4tc: add action template create, update, delete, get, " Jamal Hadi Salim
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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.

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 <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/net/p4tc.h               |  53 +++
 include/uapi/linux/p4tc.h        |  21 ++
 net/sched/p4tc/Makefile          |   3 +-
 net/sched/p4tc/p4tc_hdrfield.c   | 597 +++++++++++++++++++++++++++++++
 net/sched/p4tc/p4tc_parser_api.c | 146 ++++++++
 net/sched/p4tc/p4tc_pipeline.c   |   4 +
 net/sched/p4tc/p4tc_tmpl_api.c   |  19 +
 7 files changed, 842 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 a2c9d6cc1..5b8df17fb 100644
--- a/include/net/p4tc.h
+++ b/include/net/p4tc.h
@@ -17,6 +17,10 @@
 #define P4TC_KERNEL_PIPEID 0
 
 #define P4TC_PID_IDX 0
+#define P4TC_PARSEID_IDX 1
+#define P4TC_HDRFIELDID_IDX 2
+
+#define P4TC_HDRFIELD_IS_VALIDITY_BIT 0x1
 
 struct p4tc_dump_ctx {
 	u32 ids[P4TC_PATH_MAX];
@@ -63,6 +67,7 @@ struct p4tc_pipeline {
 	struct p4tc_template_common common;
 	struct rcu_head             rcu;
 	struct net                  *net;
+	struct p4tc_parser          *parser;
 	refcount_t                  p_ref;
 	refcount_t                  p_ctrl_ref;
 	u16                         num_tables;
@@ -104,6 +109,54 @@ static inline int p4tc_action_destroy(struct tc_action **acts)
 	return ret;
 }
 
+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_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);
+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_hdrfield(t) ((struct p4tc_hdrfield *)t)
 
 #endif
diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h
index ef9e51b31..9c063235d 100644
--- a/include/uapi/linux/p4tc.h
+++ b/include/uapi/linux/p4tc.h
@@ -19,9 +19,12 @@ struct p4tcmsg {
 #define P4TC_MSGBATCH_SIZE 16
 
 #define P4TC_MAX_KEYSZ 512
+#define HEADER_MAX_LEN 512
 
 #define TEMPLATENAMSZ 256
 #define PIPELINENAMSIZ TEMPLATENAMSZ
+#define PARSERNAMSIZ TEMPLATENAMSZ
+#define HDRFIELDNAMSIZ TEMPLATENAMSZ
 
 /* Root attributes */
 enum {
@@ -48,6 +51,7 @@ enum {
 enum {
 	P4TC_OBJ_UNSPEC,
 	P4TC_OBJ_PIPELINE,
+	P4TC_OBJ_HDR_FIELD,
 	__P4TC_OBJ_MAX,
 };
 #define P4TC_OBJ_MAX __P4TC_OBJ_MAX
@@ -57,6 +61,7 @@ enum {
 	P4TC_UNSPEC,
 	P4TC_PATH,
 	P4TC_PARAMS,
+	P4TC_COUNT,
 	__P4TC_MAX,
 };
 #define P4TC_MAX __P4TC_MAX
@@ -100,6 +105,22 @@ enum {
 };
 #define P4T_MAX (__P4T_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 0881a7563..2bcafcc2b 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
+obj-y := p4tc_types.o p4tc_pipeline.o p4tc_tmpl_api.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 000000000..70565263a
--- /dev/null
+++ b/net/sched/p4tc/p4tc_hdrfield.c
@@ -0,0 +1,597 @@
+// 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 <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/netlink.h>
+#include <net/p4tc_types.h>
+#include <net/sock.h>
+
+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);
+}
+
+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];
+	const char *parser_name = NULL;
+	char *hdrfield_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 = {0};
+	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;
+	unsigned long tmp, hdrfield_id;
+	u32 path[2];
+
+	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)
+{
+	u32 parser_inst_id = ids[P4TC_PARSEID_IDX];
+	u32 hdrfield_id = ids[P4TC_HDRFIELDID_IDX];
+	unsigned char *b = nlmsg_get_pos(skb);
+	u32 pipeid = ids[P4TC_PID_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 nlattr *param = nla_nest_start(skb, P4TC_PARAMS);
+	struct p4tc_hdrfield *hdrfield = to_hdrfield(common);
+	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 000000000..13e2a1d0e
--- /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 <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/netlink.h>
+
+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)
+{
+	unsigned long hdr_field_id, tmp;
+	struct p4tc_hdrfield *hdrfield;
+
+	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 4506ff2e1..8068a21f3 100644
--- a/net/sched/p4tc/p4tc_pipeline.c
+++ b/net/sched/p4tc/p4tc_pipeline.c
@@ -107,6 +107,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);
 
 	if (pipeline_net)
 		call_rcu(&pipeline->rcu, tcf_pipeline_destroy_rcu);
@@ -229,6 +231,8 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net,
 	else
 		pipeline->num_tables = P4TC_DEFAULT_NUM_TABLES;
 
+	pipeline->parser = NULL;
+
 	pipeline->p_state = P4TC_STATE_NOT_READY;
 
 	pipeline->net = net;
diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c
index f844b7c29..a3d755bd2 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_HDR_FIELD:
 		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_HDR_FIELD] = &p4tc_hdrfield_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_PID_IDX + 1], 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_PID_IDX + 1], 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_PID_IDX + 1], 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);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 10/21] p4tc: add action template create, update, delete, get, flush and dump
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (8 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 09/21] p4tc: add header field create, get, delete, flush and dump Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 11/21] p4tc: add table " Jamal Hadi Salim
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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.

___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 classical approach used to bind ordinary actions to filters, 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

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

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" <mohd.arif.khan@intel.com>
Tested-by: "Pottimurthy, Sathya Narayana" <sathya.narayana.pottimurthy@intel.com>
Co-developed-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/net/act_api.h          |    1 +
 include/net/p4tc.h             |  133 +++
 include/net/tc_act/p4tc.h      |   25 +
 include/uapi/linux/p4tc.h      |   43 +
 net/sched/p4tc/Makefile        |    2 +-
 net/sched/p4tc/p4tc_action.c   | 1724 ++++++++++++++++++++++++++++++++
 net/sched/p4tc/p4tc_pipeline.c |   17 +-
 net/sched/p4tc/p4tc_tmpl_api.c |    2 +
 8 files changed, 1944 insertions(+), 3 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 19770e8af..57d3d8272 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 5b8df17fb..57a935ef0 100644
--- a/include/net/p4tc.h
+++ b/include/net/p4tc.h
@@ -9,6 +9,8 @@
 #include <linux/refcount.h>
 #include <linux/rhashtable.h>
 #include <linux/rhashtable-types.h>
+#include <net/tc_act/p4tc.h>
+#include <net/p4tc_types.h>
 
 #define P4TC_DEFAULT_NUM_TABLES P4TC_MINTABLES_COUNT
 #define P4TC_DEFAULT_MAX_RULES 1
@@ -17,6 +19,7 @@
 #define P4TC_KERNEL_PIPEID 0
 
 #define P4TC_PID_IDX 0
+#define P4TC_AID_IDX 1
 #define P4TC_PARSEID_IDX 1
 #define P4TC_HDRFIELDID_IDX 2
 
@@ -24,6 +27,7 @@
 
 struct p4tc_dump_ctx {
 	u32 ids[P4TC_PATH_MAX];
+	struct rhashtable_iter *iter;
 };
 
 struct p4tc_template_common;
@@ -65,14 +69,17 @@ extern const struct p4tc_template_ops p4tc_pipeline_ops;
 
 struct p4tc_pipeline {
 	struct p4tc_template_common common;
+	struct idr                  p_act_idr;
 	struct rcu_head             rcu;
 	struct net                  *net;
 	struct p4tc_parser          *parser;
+	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 {
@@ -109,6 +116,50 @@ static inline int p4tc_action_destroy(struct tc_action **acts)
 	return ret;
 }
 
+struct p4tc_ipv4_param_value {
+	u32 value;
+	u32 mask;
+};
+
+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_act {
+	struct p4tc_template_common common;
+	struct tc_action_ops        ops;
+	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;
+
 struct p4tc_parser {
 	char parser_name[PARSERNAMSIZ];
 	struct idr hdr_fields_idr;
@@ -130,6 +181,68 @@ struct p4tc_hdrfield {
 
 extern const struct p4tc_template_ops p4tc_hdrfield_ops;
 
+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_MAX)
+			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,
 				      u32 parser_inst_id,
@@ -156,7 +269,27 @@ 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_hdrfield(t) ((struct p4tc_hdrfield *)t)
+#define to_act(t) ((struct p4tc_act *)t)
 
 #endif
diff --git a/include/net/tc_act/p4tc.h b/include/net/tc_act/p4tc.h
new file mode 100644
index 000000000..2eff11135
--- /dev/null
+++ b/include/net/tc_act/p4tc.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __NET_TC_ACT_P4_H
+#define __NET_TC_ACT_P4_H
+
+#include <net/pkt_cls.h>
+#include <net/act_api.h>
+
+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;
+	/* 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 9c063235d..b3c1d8cce 100644
--- a/include/uapi/linux/p4tc.h
+++ b/include/uapi/linux/p4tc.h
@@ -4,6 +4,7 @@
 
 #include <linux/types.h>
 #include <linux/pkt_sched.h>
+#include <linux/pkt_cls.h>
 
 /* pipeline header */
 struct p4tcmsg {
@@ -25,6 +26,9 @@ struct p4tcmsg {
 #define PIPELINENAMSIZ TEMPLATENAMSZ
 #define PARSERNAMSIZ TEMPLATENAMSZ
 #define HDRFIELDNAMSIZ TEMPLATENAMSZ
+#define ACTPARAMNAMSIZ TEMPLATENAMSZ
+
+#define LABELNAMSIZ 32
 
 /* Root attributes */
 enum {
@@ -52,6 +56,7 @@ enum {
 	P4TC_OBJ_UNSPEC,
 	P4TC_OBJ_PIPELINE,
 	P4TC_OBJ_HDR_FIELD,
+	P4TC_OBJ_ACT,
 	__P4TC_OBJ_MAX,
 };
 #define P4TC_OBJ_MAX __P4TC_OBJ_MAX
@@ -121,6 +126,44 @@ 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_ACTIVE, /* u8 */
+	P4TC_ACT_PAD,
+	__P4TC_ACT_MAX
+};
+#define P4TC_ACT_MAX __P4TC_ACT_MAX
+
+/* 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 2bcafcc2b..f4a96efca 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_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 000000000..676e1b0d9
--- /dev/null
+++ b/net/sched/p4tc/p4tc_action.c
@@ -0,0 +1,1724 @@
+// 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 <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <net/flow_offload.h>
+#include <net/net_namespace.h>
+#include <net/netlink.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/sch_generic.h>
+#include <net/sock.h>
+#include <net/tc_act/p4tc.h>
+
+static LIST_HEAD(dynact_list);
+
+#define SEPARATOR "/"
+
+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;
+
+		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;
+
+	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(&params_old->rcu, tcf_p4_act_params_destroy_rcu);
+
+	return 0;
+}
+
+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(&params->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 = kmemdup(ifindex, sizeof(*ifindex), GFP_KERNEL);
+	if (!nparam->value)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int dev_dump_param_value(struct sk_buff *skb,
+				struct p4tc_act_param_ops *op,
+				struct p4tc_act_param *param)
+{
+	const u32 *ifindex = param->value;
+	struct nlattr *nest;
+	int ret;
+
+	nest = nla_nest_start(skb, P4TC_ACT_PARAMS_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)
+{
+	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)
+{
+	kfree(param->value);
+	kfree(param->mask);
+}
+
+static 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(&params->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(&params->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);
+
+	tcf_lastuse_update(&dynact->tcf_tm);
+	tcf_action_update_bstats(&dynact->common, skb);
+
+	return 0;
+}
+
+static int tcf_p4_dyna_dump(struct sk_buff *skb, struct tc_action *a, int bind,
+			    int ref)
+{
+	struct tcf_p4act *dynact = to_p4act(a);
+	unsigned char *b = nlmsg_get_pos(skb);
+	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 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;
+
+	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(&params->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 *)&param_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(&params->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 (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(&params->params_idr, param, tmp, param_id) {
+		struct p4tc_act_param_ops *op;
+
+		idr_remove(&params->params_idr, param_id);
+		op = (struct p4tc_act_param_ops *)&param_ops[param->type->typeid];
+		if (op->free)
+			op->free(param);
+		else
+			generic_free_param_value(param);
+		kfree(param);
+	}
+
+	kfree(params->params_array);
+	idr_destroy(&params->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 *)&param_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(&params->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];
+	unsigned long tmp, id;
+	struct p4tc_act *act;
+
+	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, &param_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, &param->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_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;
+	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_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);
+
+	idr_remove(&pipeline->p_act_idr, act->a_id);
+
+	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 p4tc_act_param *param;
+	struct nlattr *nest, *parms;
+	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);
+
+	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);
+	unsigned long tmp, act_id;
+	struct p4tc_act *act;
+	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 *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;
+		}
+	}
+
+	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 idr_rm;
+	}
+
+	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);
+
+	act->pipeline = pipeline;
+
+	pipeline->num_created_acts++;
+
+	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;
+
+unregister:
+	rtnl_unlock();
+	tcf_unregister_dyn_action(net, &act->ops);
+	rtnl_lock();
+
+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;
+	}
+
+	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_pipeline *pipeline;
+	struct p4tc_act *act;
+	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);
+
+	if (!param)
+		goto out_nlmsg_trim;
+
+	if (nla_put_string(skb, P4TC_ACT_NAME, act->common.name))
+		goto out_nlmsg_trim;
+
+	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_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c
index 8068a21f3..0104201d6 100644
--- a/net/sched/p4tc/p4tc_pipeline.c
+++ b/net/sched/p4tc/p4tc_pipeline.c
@@ -76,6 +76,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_act_idr);
+
 	if (free_pipeline)
 		kfree(pipeline);
 }
@@ -100,16 +102,22 @@ 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);
+	unsigned long iter_act_id, tmp;
+	struct p4tc_act *act;
 
 	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);
+	idr_for_each_entry_ul(&pipeline->p_act_idr, act, tmp, iter_act_id)
+		act->common.ops->put(net, &act->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
@@ -233,6 +241,10 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net,
 
 	pipeline->parser = NULL;
 
+	idr_init(&pipeline->p_act_idr);
+
+	pipeline->num_created_acts = 0;
+
 	pipeline->p_state = P4TC_STATE_NOT_READY;
 
 	pipeline->net = net;
@@ -486,7 +498,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 a3d755bd2..7e05ce85e 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_HDR_FIELD:
+	case P4TC_OBJ_ACT:
 		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_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,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 11/21] p4tc: add table create, update, delete, get, flush and dump
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (9 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 10/21] p4tc: add action template create, update, delete, get, " Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 12/21] p4tc: add table entry create, update, get, delete, " Jamal Hadi Salim
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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. Table1's key size is 32 bits wide
and it can have up to 8 associted masks and 8192 entries. 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 type lpm
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:

        entry priority 17[permissions-RUD--R--X]
        entry key
            srcAddr id:1 size:32b type:ipv4 exact fieldval  10.10.10.10/32
            dstAddr id:2 size:32b type:ipv4 exact fieldval  1.1.1.0/24

___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 (binary 1100001111) 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.
Note: above permissions dont seem very practical and merely shown to
exemplify permission usage.

Co-developed-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/net/p4tc.h             |   88 ++
 include/net/p4tc_types.h       |    2 +-
 include/uapi/linux/p4tc.h      |  113 +++
 net/sched/p4tc/Makefile        |    2 +-
 net/sched/p4tc/p4tc_pipeline.c |   20 +-
 net/sched/p4tc/p4tc_table.c    | 1389 ++++++++++++++++++++++++++++++++
 net/sched/p4tc/p4tc_tmpl_api.c |    2 +
 7 files changed, 1609 insertions(+), 7 deletions(-)
 create mode 100644 net/sched/p4tc/p4tc_table.c

diff --git a/include/net/p4tc.h b/include/net/p4tc.h
index 57a935ef0..ca16c79ff 100644
--- a/include/net/p4tc.h
+++ b/include/net/p4tc.h
@@ -15,10 +15,17 @@
 #define P4TC_DEFAULT_NUM_TABLES P4TC_MINTABLES_COUNT
 #define P4TC_DEFAULT_MAX_RULES 1
 #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_TBLID_IDX 1
 #define P4TC_AID_IDX 1
 #define P4TC_PARSEID_IDX 1
 #define P4TC_HDRFIELDID_IDX 2
@@ -70,6 +77,7 @@ extern const struct p4tc_template_ops p4tc_pipeline_ops;
 struct p4tc_pipeline {
 	struct p4tc_template_common common;
 	struct idr                  p_act_idr;
+	struct idr                  p_tbl_idr;
 	struct rcu_head             rcu;
 	struct net                  *net;
 	struct p4tc_parser          *parser;
@@ -104,6 +112,11 @@ tcf_pipeline_find_byany_unsealed(struct net *net, const char *p_name,
 				 const u32 pipeid,
 				 struct netlink_ext_ack *extack);
 
+static inline bool pipeline_sealed(struct p4tc_pipeline *pipeline)
+{
+	return pipeline->p_state == P4TC_STATE_READY;
+}
+
 static inline int p4tc_action_destroy(struct tc_action **acts)
 {
 	int ret = 0;
@@ -116,6 +129,62 @@ static inline int p4tc_action_destroy(struct tc_action **acts)
 	return ret;
 }
 
+#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 idr                          tbl_masks_idr;
+	struct idr                          tbl_prio_idr;
+	struct rhltable                     tbl_entries;
+	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;
@@ -158,6 +227,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;
 
 struct p4tc_parser {
@@ -243,6 +318,18 @@ 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);
+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,
@@ -291,5 +378,6 @@ int generic_dump_param_value(struct sk_buff *skb, struct p4tc_type *type,
 #define to_pipeline(t) ((struct p4tc_pipeline *)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 232399533..254ddad9f 100644
--- a/include/net/p4tc_types.h
+++ b/include/net/p4tc_types.h
@@ -8,7 +8,7 @@
 
 #include <uapi/linux/p4tc.h>
 
-#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 b3c1d8cce..acde500cd 100644
--- a/include/uapi/linux/p4tc.h
+++ b/include/uapi/linux/p4tc.h
@@ -27,6 +27,71 @@ 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_TERNARY = 3,
+	__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
 
@@ -57,6 +122,7 @@ enum {
 	P4TC_OBJ_PIPELINE,
 	P4TC_OBJ_HDR_FIELD,
 	P4TC_OBJ_ACT,
+	P4TC_OBJ_TABLE,
 	__P4TC_OBJ_MAX,
 };
 #define P4TC_OBJ_MAX __P4TC_OBJ_MAX
@@ -110,6 +176,53 @@ enum {
 };
 #define P4T_MAX (__P4T_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 f4a96efca..182ad141b 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_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 0104201d6..04505dbc5 100644
--- a/net/sched/p4tc/p4tc_pipeline.c
+++ b/net/sched/p4tc/p4tc_pipeline.c
@@ -77,6 +77,7 @@ static void tcf_pipeline_destroy(struct p4tc_pipeline *pipeline,
 				 bool free_pipeline)
 {
 	idr_destroy(&pipeline->p_act_idr);
+	idr_destroy(&pipeline->p_tbl_idr);
 
 	if (free_pipeline)
 		kfree(pipeline);
@@ -103,13 +104,18 @@ static int tcf_pipeline_put(struct net *net,
 	struct p4tc_pipeline *pipeline = to_pipeline(template);
 	struct net *pipeline_net = maybe_get_net(net);
 	unsigned long iter_act_id, tmp;
+	struct p4tc_table *table;
 	struct p4tc_act *act;
+	unsigned long tbl_id;
 
 	if (pipeline_net && !refcount_dec_if_one(&pipeline->p_ref)) {
 		NL_SET_ERR_MSG(extack, "Can't delete referenced pipeline");
 		return -EBUSY;
 	}
 
+	idr_for_each_entry_ul(&pipeline->p_tbl_idr, table, tmp, tbl_id)
+		table->common.ops->put(net, &table->common, true, extack);
+
 	idr_for_each_entry_ul(&pipeline->p_act_idr, act, tmp, iter_act_id)
 		act->common.ops->put(net, &act->common, true, extack);
 
@@ -130,21 +136,22 @@ 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");
 		return -EINVAL;
 	}
 
+	ret = tcf_table_try_set_state_ready(pipeline, extack);
+	if (ret < 0)
+		return ret;
+
 	pipeline->p_state = P4TC_STATE_READY;
 	return true;
 }
 
-static inline bool pipeline_sealed(struct p4tc_pipeline *pipeline)
-{
-	return pipeline->p_state == P4TC_STATE_READY;
-}
-
 struct p4tc_pipeline *tcf_pipeline_find_byid(struct net *net, const u32 pipeid)
 {
 	struct p4tc_pipeline_net *pipe_net;
@@ -243,6 +250,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;
+
 	pipeline->num_created_acts = 0;
 
 	pipeline->p_state = P4TC_STATE_NOT_READY;
diff --git a/net/sched/p4tc/p4tc_table.c b/net/sched/p4tc/p4tc_table.c
new file mode 100644
index 000000000..3ed19ad79
--- /dev/null
+++ b/net/sched/p4tc/p4tc_table.c
@@ -0,0 +1,1389 @@
+// 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 <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitmap.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/netlink.h>
+#include <net/flow_offload.h>
+
+#define P4TC_P_UNSPEC 0
+#define P4TC_P_CREATED 1
+
+static int __tcf_table_try_set_state_ready(struct p4tc_table *table,
+					   struct netlink_ext_ack *extack)
+{
+	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;
+}
+
+static 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_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 int _tcf_table_fill_nlmsg(struct sk_buff *skb, struct p4tc_table *table)
+{
+	unsigned char *b = nlmsg_get_pos(skb);
+	struct p4tc_table_parm parm = {0};
+	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 nlattr *nest;
+
+	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_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 p4tc_table_defact_destroy(struct p4tc_table_defact *defact)
+{
+	if (defact) {
+		p4tc_action_destroy(defact->default_acts);
+		kfree(defact);
+	}
+}
+
+static 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;
+
+	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);
+}
+
+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_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;
+	}
+
+	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 idr_rm;
+
+	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);
+
+	pipeline->curr_tables += 1;
+
+	table->common.ops = (struct p4tc_template_ops *)&p4tc_table_ops;
+
+	return table;
+
+idr_rm:
+	idr_remove(&pipeline->p_tbl_idr, table->tbl_id);
+
+free_permissions:
+	kfree(table->tbl_permissions);
+
+	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_defact *default_missact = NULL;
+	struct p4tc_table_defact *default_hitact = NULL;
+	struct list_head *tbl_acts_list = NULL;
+	struct p4tc_table_perm *perm = NULL;
+	struct p4tc_table_parm *parm = 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 (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 table_acts_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 defaultacts_destroy;
+			}
+			if (parm->tbl_keysz > P4TC_MAX_KEYSZ) {
+				NL_SET_ERR_MSG(extack,
+					       "Table keysz exceeds maximum keysz");
+				ret = -EINVAL;
+				goto defaultacts_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 defaultacts_destroy;
+			}
+			if (parm->tbl_max_entries > P4TC_MAX_TENTRIES) {
+				NL_SET_ERR_MSG(extack,
+					       "Table max_entries exceeds maximum value");
+				ret = -EINVAL;
+				goto defaultacts_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 defaultacts_destroy;
+			}
+			if (parm->tbl_max_masks > P4TC_MAX_TMASKS) {
+				NL_SET_ERR_MSG(extack,
+					       "Table max_masks exceeds maximum value");
+				ret = -EINVAL;
+				goto defaultacts_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 defaultacts_destroy;
+			}
+			if (!p4tc_data_exec_ok(parm->tbl_permissions)) {
+				NL_SET_ERR_MSG(extack,
+					       "Table must have execute permissions");
+				ret = -EINVAL;
+				goto defaultacts_destroy;
+			}
+			if (!p4tc_data_read_ok(parm->tbl_permissions)) {
+				NL_SET_ERR_MSG(extack,
+					       "Data path read permissions must be set");
+				ret = -EINVAL;
+				goto defaultacts_destroy;
+			}
+
+			perm = kzalloc(sizeof(*perm), GFP_KERNEL);
+			if (!perm) {
+				ret = -ENOMEM;
+				goto defaultacts_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 free_perm;
+			}
+			table->tbl_type = parm->tbl_type;
+		}
+	}
+
+	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 (perm) {
+		perm = rcu_replace_pointer_rtnl(table->tbl_permissions, perm);
+		kfree_rcu(perm, rcu);
+	}
+
+	return table;
+
+free_perm:
+	kfree(perm);
+
+defaultacts_destroy:
+	p4tc_table_defact_destroy(default_missact);
+	p4tc_table_defact_destroy(default_hitact);
+
+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);
+	unsigned long tmp, tbl_id;
+	struct p4tc_table *table;
+	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_TBLID_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 nlattr *nest = nla_nest_start(skb, P4TC_PARAMS);
+	struct p4tc_table *table = to_table(common);
+
+	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 7e05ce85e..7776cbf81 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_HDR_FIELD:
 	case P4TC_OBJ_ACT:
+	case P4TC_OBJ_TABLE:
 		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_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,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 12/21] p4tc: add table entry create, update, get, delete, flush and dump
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (10 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 11/21] p4tc: add table " Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 13/21] p4tc: add set of P4TC table lookup kfuncs Jamal Hadi Salim
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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 <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/net/p4tc.h                |   79 +-
 include/uapi/linux/p4tc.h         |   45 +-
 include/uapi/linux/rtnetlink.h    |    7 +
 net/sched/p4tc/Makefile           |    3 +-
 net/sched/p4tc/p4tc_pipeline.c    |   12 +
 net/sched/p4tc/p4tc_runtime_api.c |  136 ++
 net/sched/p4tc/p4tc_table.c       |   51 +-
 net/sched/p4tc/p4tc_tbl_entry.c   | 1906 +++++++++++++++++++++++++++++
 net/sched/p4tc/p4tc_tmpl_api.c    |    4 +-
 security/selinux/nlmsgtab.c       |    5 +-
 10 files changed, 2237 insertions(+), 11 deletions(-)
 create mode 100644 net/sched/p4tc/p4tc_runtime_api.c
 create mode 100644 net/sched/p4tc/p4tc_tbl_entry.c

diff --git a/include/net/p4tc.h b/include/net/p4tc.h
index ca16c79ff..2b2e80f98 100644
--- a/include/net/p4tc.h
+++ b/include/net/p4tc.h
@@ -84,6 +84,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;
@@ -158,15 +159,15 @@ struct p4tc_table {
 	struct p4tc_template_common         common;
 	struct list_head                    tbl_acts_list;
 	struct idr                          tbl_masks_idr;
-	struct idr                          tbl_prio_idr;
+	struct ida                          tbl_prio_idr;
 	struct rhltable                     tbl_entries;
+	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;
@@ -181,6 +182,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;
@@ -235,6 +237,64 @@ struct p4tc_table_act {
 
 extern const struct p4tc_template_ops p4tc_act_ops;
 
+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];
+
+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;
@@ -330,6 +390,21 @@ 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);
+int p4tc_ctl_table_n(struct sk_buff *skb, struct nlmsghdr *n,
+		     int cmd, char *p_name, struct nlattr *nla,
+		     struct netlink_ext_ack *extack);
+int p4tc_ctl_dump_1(struct sk_buff *skb, struct netlink_callback *cb,
+		    struct nlattr *arg, char *p_name);
+
 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 acde500cd..2dc36e8c7 100644
--- a/include/uapi/linux/p4tc.h
+++ b/include/uapi/linux/p4tc.h
@@ -123,10 +123,19 @@ 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
 
+/* P4 runtime Object types */
+enum {
+	P4TC_OBJ_RUNTIME_UNSPEC,
+	P4TC_OBJ_RUNTIME_TABLE,
+	__P4TC_OBJ_RUNTIME_MAX,
+};
+#define P4TC_OBJ_RUNTIMEMAX __P4TC_OBJ_RUNTIMEMAX
+
 /* P4 attributes */
 enum {
 	P4TC_UNSPEC,
@@ -217,7 +226,7 @@ enum {
 	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_CONST_ENTRY, /* nested const table entry*/
 	P4TC_TABLE_ACTS_LIST, /* nested table actions list */
 	__P4TC_TABLE_MAX
 };
@@ -277,6 +286,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 41a4046e7..c06fe3d8f 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 182ad141b..c9e2555a8 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_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_entry.o p4tc_runtime_api.o
diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c
index 04505dbc5..6c687ee54 100644
--- a/net/sched/p4tc/p4tc_pipeline.c
+++ b/net/sched/p4tc/p4tc_pipeline.c
@@ -108,7 +108,16 @@ static int tcf_pipeline_put(struct net *net,
 	struct p4tc_act *act;
 	unsigned long tbl_id;
 
+	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;
 	}
@@ -260,6 +269,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_runtime_api.c b/net/sched/p4tc/p4tc_runtime_api.c
new file mode 100644
index 000000000..a4050096b
--- /dev/null
+++ b/net/sched/p4tc/p4tc_runtime_api.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * net/sched/p4tc_runtime_api.c P4 TC RUNTIME API
+ *
+ * Copyright (c) 2022-2023, Mojatatu Networks
+ * Copyright (c) 2022-2023, Intel Corporation.
+ * Authors:     Jamal Hadi Salim <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitmap.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/netlink.h>
+#include <net/flow_offload.h>
+
+static int tc_ctl_p4_root(struct sk_buff *skb, struct nlmsghdr *n, int cmd,
+			  struct netlink_ext_ack *extack)
+{
+	struct p4tcmsg *t = (struct p4tcmsg *)nlmsg_data(n);
+	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]);
+
+	switch (t->obj) {
+	case P4TC_OBJ_RUNTIME_TABLE:
+		return p4tc_ctl_table_n(skb, n, cmd, p_name, tb[P4TC_ROOT],
+					extack);
+	default:
+		NL_SET_ERR_MSG(extack, "Unknown P4 runtime object type");
+		return -EOPNOTSUPP;
+	}
+}
+
+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 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];
+	struct p4tcmsg *t;
+
+	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 Runtime attributes missing");
+		return -EINVAL;
+	}
+
+	if (tb[P4TC_ROOT_PNAME])
+		p_name = nla_data(tb[P4TC_ROOT_PNAME]);
+
+	t = nlmsg_data(cb->nlh);
+
+	switch (t->obj) {
+	case P4TC_OBJ_RUNTIME_TABLE:
+		return p4tc_ctl_dump_1(skb, cb, tb[P4TC_ROOT], p_name);
+	default:
+		NL_SET_ERR_MSG_FMT(cb->extack,
+				   "Unknown p4 runtime object type %u\n",
+				   t->obj);
+		return -ENOENT;
+	}
+}
+
+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/net/sched/p4tc/p4tc_table.c b/net/sched/p4tc/p4tc_table.c
index 3ed19ad79..3ef76a84e 100644
--- a/net/sched/p4tc/p4tc_table.c
+++ b/net/sched/p4tc/p4tc_table.c
@@ -103,7 +103,7 @@ static const struct nla_policy p4tc_table_policy[P4TC_TABLE_MAX + 1] = {
 	[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 },
+	[P4TC_TABLE_CONST_ENTRY] = { .type = NLA_NESTED },
 };
 
 static int _tcf_table_fill_nlmsg(struct sk_buff *skb, struct p4tc_table *table)
@@ -204,6 +204,16 @@ 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_CONST_ENTRY);
+		p4tca_table_get_entry_fill(skb, table, table->tbl_const_entry,
+					   table->tbl_id);
+		nla_nest_end(skb, const_nest);
+	}
+	table->tbl_const_entry = NULL;
+
 	if (nla_put(skb, P4TC_TABLE_INFO, sizeof(parm), &parm))
 		goto out_nlmsg_trim;
 	nla_nest_end(skb, nest);
@@ -339,8 +349,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);
@@ -741,6 +754,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_parm *parm;
 	struct p4tc_table *table;
 	char *tblname;
@@ -944,9 +958,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;
+	}
 
 	pipeline->curr_tables += 1;
 
@@ -954,6 +978,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);
+
 idr_rm:
 	idr_remove(&pipeline->p_tbl_idr, table->tbl_id);
 
@@ -1102,6 +1130,21 @@ static struct p4tc_table *tcf_table_update(struct net *net, struct nlattr **tb,
 		}
 	}
 
+	if (tb[P4TC_TABLE_CONST_ENTRY]) {
+		struct p4tc_table_entry *entry;
+
+		/* Workaround to make this work */
+		entry = tcf_table_const_entry_cu(net,
+						 tb[P4TC_TABLE_CONST_ENTRY],
+						 pipeline, table, extack);
+		if (IS_ERR(entry)) {
+			ret = PTR_ERR(entry);
+			goto free_perm;
+		}
+
+		table->tbl_const_entry = entry;
+	}
+
 	if (default_hitact) {
 		struct p4tc_table_defact *hitact;
 
diff --git a/net/sched/p4tc/p4tc_tbl_entry.c b/net/sched/p4tc/p4tc_tbl_entry.c
new file mode 100644
index 000000000..999167a10
--- /dev/null
+++ b/net/sched/p4tc/p4tc_tbl_entry.c
@@ -0,0 +1,1906 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * net/sched/p4tc_tbl_entry.c P4 TC TABLE ENTRY
+ *
+ * Copyright (c) 2022-2023, Mojatatu Networks
+ * Copyright (c) 2022-2023, Intel Corporation.
+ * Authors:     Jamal Hadi Salim <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitmap.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/netlink.h>
+#include <net/flow_offload.h>
+
+#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;
+	u32 keysz;
+
+	/* The key memory area is always zero allocated aligned to 8 */
+	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;
+
+	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 rhlist_head *tmp, *bucket_list;
+	struct p4tc_table_entry *entry;
+
+	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;
+}
+
+#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 p4tc_table_entry_tm dtm, *tm;
+	struct nlattr *nest, *nest_acts;
+	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;
+			u8 *fa_value;
+
+			fa_value = table->tbl_masks_array[pos]->fa_value;
+
+			array_mask_value = find_lpm_mask(table, 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);
+
+	if (remove_from_hash)
+		rhltable_remove(&table->tbl_entries, &entry->ht_node,
+				entry_hlt_params);
+
+	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;
+}
+
+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;
+
+	ida_free(&table->tbl_prio_idr, value->prio);
+
+	return __tcf_table_entry_destroy(table, entry, remove_from_hash);
+}
+
+static int tcf_table_entry_destroy_noida(struct p4tc_table *table,
+					 struct p4tc_table_entry *entry)
+{
+	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;
+
+	return __tcf_table_entry_destroy(table, entry, true);
+}
+
+/* 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_entry *entry = ptr;
+	struct p4tc_table *table = arg;
+	struct p4tc_table_entry_value *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_mask *mask = NULL;
+	struct p4tc_table_entry *entry = NULL;
+	struct p4tc_pipeline *pipeline = NULL;
+	struct p4tc_table_entry_mask *new_mask;
+	struct p4tc_table_entry_value *value;
+	struct p4tc_table_entry_key *key;
+	struct p4tc_table *table;
+	u32 keysz_bytes;
+	u32 keysz_bits;
+	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;
+	u32 arg_ids[P4TC_PATH_MAX - 1];
+	struct p4tc_pipeline *pipeline;
+	struct p4tc_table_entry *entry;
+	struct rhashtable_iter iter;
+	struct p4tc_table *table;
+
+	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_entry_mask *mask_found = NULL;
+	struct p4tc_table_entry_work *entry_work;
+	struct p4tc_table_entry_value *value;
+	struct p4tc_table_perm *tbl_perm;
+	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_noida(table, entry_old) < 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_bytes;
+	u32 keysz_bits;
+	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_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_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_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);
+}
+
+int p4tc_ctl_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;
+	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 ret_send;
+	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;
+}
+
+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;
+}
+
+int p4tc_ctl_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;
+}
diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c
index 7776cbf81..ddc7a3ea8 100644
--- a/net/sched/p4tc/p4tc_tmpl_api.c
+++ b/net/sched/p4tc/p4tc_tmpl_api.c
@@ -27,12 +27,12 @@
 #include <net/netlink.h>
 #include <net/flow_offload.h>
 
-static const struct nla_policy p4tc_root_policy[P4TC_ROOT_MAX + 1] = {
+const struct nla_policy p4tc_root_policy[P4TC_ROOT_MAX + 1] = {
 	[P4TC_ROOT] = { .type = NLA_NESTED },
 	[P4TC_ROOT_PNAME] = { .type = NLA_STRING, .len = PIPELINENAMSIZ },
 };
 
-static const struct nla_policy p4tc_policy[P4TC_MAX + 1] = {
+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 },
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 0a8daf2f8..208e5e258 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;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 13/21] p4tc: add set of P4TC table lookup kfuncs
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (11 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 12/21] p4tc: add table entry create, update, get, delete, " Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 14/21] p4tc: add P4 classifier Jamal Hadi Salim
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

We add an initial set of kfuncs to allow interactions from eBPF programs
to the P4TC domain.

- 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 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 <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/linux/bitops.h          |   1 +
 include/net/p4tc.h              |  54 ++++++++++-
 net/sched/Kconfig               |   1 +
 net/sched/p4tc/Makefile         |   2 +-
 net/sched/p4tc/p4tc_action.c    |   1 +
 net/sched/p4tc/p4tc_bpf.c       | 115 ++++++++++++++++++++++
 net/sched/p4tc/p4tc_pipeline.c  |  46 +++++++++
 net/sched/p4tc/p4tc_table.c     |  19 ++++
 net/sched/p4tc/p4tc_tbl_entry.c | 164 +++++++++++++++++++++++++++++++-
 net/sched/p4tc/p4tc_tmpl_api.c  |   2 +
 10 files changed, 402 insertions(+), 3 deletions(-)
 create mode 100644 net/sched/p4tc/p4tc_bpf.c

diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 2ba557e06..290c2399a 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/net/p4tc.h b/include/net/p4tc.h
index 2b2e80f98..544a2cf8a 100644
--- a/include/net/p4tc.h
+++ b/include/net/p4tc.h
@@ -32,6 +32,12 @@
 
 #define P4TC_HDRFIELD_IS_VALIDITY_BIT 0x1
 
+struct p4tc_percpu_scratchpad {
+	u32 prog_cookie;
+};
+
+DECLARE_PER_CPU(struct p4tc_percpu_scratchpad, p4tc_percpu_scratchpad);
+
 struct p4tc_dump_ctx {
 	u32 ids[P4TC_PATH_MAX];
 	struct rhashtable_iter *iter;
@@ -91,8 +97,26 @@ 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;
+	struct list_head  tbls_cache[P4TC_TBLS_CACHE_SIZE];
+	struct idr        pipeline_idr;
 };
 
 int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx,
@@ -139,8 +163,20 @@ static inline int p4tc_action_destroy(struct tc_action **acts)
 
 #define P4TC_PERMISSIONS_UNINIT (1 << P4TC_PERM_MAX_BIT)
 
+#define P4TC_MAX_PARAM_DATA_SIZE 124
+
+struct p4tc_table_entry_act_bpf {
+	u32 act_id;
+	u8 params[P4TC_MAX_PARAM_DATA_SIZE];
+} __packed;
+
+struct p4tc_parser_buffer_act_bpf {
+	u16 hdrs[BITS_TO_U16(HEADER_MAX_LEN)];
+};
+
 struct p4tc_table_defact {
 	struct tc_action **default_acts;
+	struct p4tc_table_entry_act_bpf *defact_bpf;
 	/* 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.
@@ -157,6 +193,7 @@ struct p4tc_table_perm {
 
 struct p4tc_table {
 	struct p4tc_template_common         common;
+	struct list_head                    tbl_cache_node;
 	struct list_head                    tbl_acts_list;
 	struct idr                          tbl_masks_idr;
 	struct ida                          tbl_prio_idr;
@@ -239,6 +276,11 @@ extern const struct p4tc_template_ops p4tc_act_ops;
 
 extern const struct rhashtable_params entry_hlt_params;
 
+struct p4tc_table_entry_act_bpf_params {
+	u32 pipeid;
+	u32 tblid;
+};
+
 struct p4tc_table_entry;
 struct p4tc_table_entry_work {
 	struct work_struct   work;
@@ -258,6 +300,7 @@ struct p4tc_table_entry_value {
 	u32                              prio;
 	int                              num_acts;
 	struct tc_action                 **acts;
+	struct p4tc_table_entry_act_bpf  *act_bpf;
 	refcount_t                       entries_ref;
 	u32                              permissions;
 	struct p4tc_table_entry_tm __rcu *tm;
@@ -290,10 +333,19 @@ 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];
 
+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);
+struct p4tc_table_entry_act_bpf *
+tcf_table_entry_create_act_bpf(struct tc_action *action,
+			       struct netlink_ext_ack *extack);
+int register_p4tc_tbl_bpf(void);
 
 struct p4tc_parser {
 	char parser_name[PARSERNAMSIZ];
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index ea57a4c7b..d071f9075 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -678,6 +678,7 @@ config NET_EMATCH_IPT
 
 config NET_P4_TC
 	bool "P4 TC support"
+	depends on DEBUG_INFO_BTF
 	select NET_CLS_ACT
 	help
 	  Say Y here if you want to use P4 features on top of TC.
diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile
index c9e2555a8..161a515ad 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_parser_api.o p4tc_hdrfield.o p4tc_action.o p4tc_table.o \
-	p4tc_tbl_entry.o p4tc_runtime_api.o
+	p4tc_tbl_entry.o p4tc_runtime_api.o p4tc_bpf.o
diff --git a/net/sched/p4tc/p4tc_action.c b/net/sched/p4tc/p4tc_action.c
index 676e1b0d9..abbf8cb83 100644
--- a/net/sched/p4tc/p4tc_action.c
+++ b/net/sched/p4tc/p4tc_action.c
@@ -28,6 +28,7 @@
 #include <net/p4tc.h>
 #include <net/sch_generic.h>
 #include <net/sock.h>
+
 #include <net/tc_act/p4tc.h>
 
 static LIST_HEAD(dynact_list);
diff --git a/net/sched/p4tc/p4tc_bpf.c b/net/sched/p4tc/p4tc_bpf.c
new file mode 100644
index 000000000..adfdc678f
--- /dev/null
+++ b/net/sched/p4tc/p4tc_bpf.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Mojatatu Networks
+ * Copyright (c) 2022, Intel Corporation.
+ * Authors:     Jamal Hadi Salim <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/bpf_verifier.h>
+#include <linux/bpf.h>
+#include <linux/btf.h>
+#include <linux/filter.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/btf_ids.h>
+#include <linux/net_namespace.h>
+#include <net/p4tc.h>
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <linux/filter.h>
+
+BTF_ID_LIST(btf_p4tc_ids)
+BTF_ID(struct, p4tc_table_entry_act_bpf)
+BTF_ID(struct, p4tc_table_entry_act_bpf_params)
+
+#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);
+}
+
+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_skb_p4tc_tbl_lookup, KF_RET_NULL);
+BTF_ID_FLAGS(func, bpf_xdp_p4tc_tbl_lookup, KF_RET_NULL);
+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/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c
index 6c687ee54..b36035840 100644
--- a/net/sched/p4tc/p4tc_pipeline.c
+++ b/net/sched/p4tc/p4tc_pipeline.c
@@ -37,9 +37,52 @@ static __net_init int pipeline_init_net(struct net *net)
 
 	idr_init(&pipe_net->pipeline_idr);
 
+	for (int i = 0; i < P4TC_TBLS_CACHE_SIZE; i++)
+		INIT_LIST_HEAD(&pipe_net->tbls_cache[i]);
+
+	return 0;
+}
+
+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);
+}
+
 static int tcf_pipeline_put(struct net *net,
 			    struct p4tc_template_common *template,
 			    bool unconditional_purgeline,
@@ -618,6 +661,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_table.c b/net/sched/p4tc/p4tc_table.c
index 3ef76a84e..dfc93278b 100644
--- a/net/sched/p4tc/p4tc_table.c
+++ b/net/sched/p4tc/p4tc_table.c
@@ -244,6 +244,7 @@ static inline void p4tc_table_defact_destroy(struct p4tc_table_defact *defact)
 {
 	if (defact) {
 		p4tc_action_destroy(defact->default_acts);
+		kfree(defact->defact_bpf);
 		kfree(defact);
 	}
 }
@@ -351,6 +352,7 @@ static inline int _tcf_table_put(struct net *net, struct nlattr **tb,
 
 	rhltable_free_and_destroy(&table->tbl_entries,
 				  tcf_table_entry_destroy_hash, table);
+	p4tc_tbl_cache_remove(net, table);
 
 	idr_destroy(&table->tbl_masks_idr);
 	ida_destroy(&table->tbl_prio_idr);
@@ -483,6 +485,7 @@ static int tcf_table_init_default_act(struct net *net, struct nlattr **tb,
 	}
 
 	if (tb[P4TC_TABLE_DEFAULT_ACTION]) {
+		struct p4tc_table_entry_act_bpf *act_bpf;
 		struct tc_action **default_acts;
 
 		if (!p4tc_ctrl_update_ok(curr_permissions)) {
@@ -511,6 +514,15 @@ static int tcf_table_init_default_act(struct net *net, struct nlattr **tb,
 			ret = -EINVAL;
 			goto default_act_free;
 		}
+		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;
 		(*default_act)->default_acts = default_acts;
 	}
 
@@ -972,12 +984,19 @@ static struct p4tc_table *tcf_table_create(struct net *net, struct nlattr **tb,
 		goto defaultacts_destroy;
 	}
 
+	ret = p4tc_tbl_cache_insert(net, pipeline->common.p_id, table);
+	if (ret < 0)
+		goto entries_hashtable_destroy;
+
 	pipeline->curr_tables += 1;
 
 	table->common.ops = (struct p4tc_template_ops *)&p4tc_table_ops;
 
 	return table;
 
+entries_hashtable_destroy:
+	rhltable_destroy(&table->tbl_entries);
+
 defaultacts_destroy:
 	p4tc_table_defact_destroy(table->tbl_default_missact);
 	p4tc_table_defact_destroy(table->tbl_default_hitact);
diff --git a/net/sched/p4tc/p4tc_tbl_entry.c b/net/sched/p4tc/p4tc_tbl_entry.c
index 999167a10..f8acff389 100644
--- a/net/sched/p4tc/p4tc_tbl_entry.c
+++ b/net/sched/p4tc/p4tc_tbl_entry.c
@@ -94,6 +94,103 @@ p4tc_entry_lookup(struct p4tc_table *table, struct p4tc_table_entry_key *key,
 	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 p4tc_table_entry *entry_curr;
+	struct rhlist_head *bucket_list;
+
+	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_direct(struct p4tc_table *table,
+			       struct p4tc_table_entry_key *key)
+{
+	struct p4tc_table_entry *entry = NULL;
+	u32 smallest_prio = U32_MAX;
+	const struct p4tc_table_entry_mask **masks_array;
+	int i;
+
+	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))
 
@@ -498,6 +595,8 @@ static void tcf_table_entry_put(struct p4tc_table_entry *entry)
 		struct p4tc_pipeline *pipeline = entry_work->pipeline;
 		struct net *net;
 
+		kfree(value->act_bpf);
+
 		if (entry_work->defer_deletion) {
 			net = get_net(pipeline->net);
 			refcount_inc(&entry_work->pipeline->p_entry_deferal_ref);
@@ -1379,6 +1478,8 @@ static struct p4tc_table_entry *__tcf_table_entry_cu(struct net *net, u32 flags,
 	}
 
 	if (tb[P4TC_ENTRY_ACT]) {
+		struct p4tc_table_entry_act_bpf *act_bpf;
+
 		value->acts = kcalloc(TCA_ACT_MAX_PRIO,
 				      sizeof(struct tc_action *), GFP_KERNEL);
 		if (!value->acts) {
@@ -1404,6 +1505,14 @@ static struct p4tc_table_entry *__tcf_table_entry_cu(struct net *net, u32 flags,
 				       "Action is not allowed as entry action");
 			goto free_acts;
 		}
+
+		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;
 	}
 
 	rcu_read_lock();
@@ -1415,12 +1524,15 @@ static struct p4tc_table_entry *__tcf_table_entry_cu(struct net *net, u32 flags,
 					       whodunnit, true);
 	if (ret < 0) {
 		rcu_read_unlock();
-		goto free_acts;
+		goto free_act_bpf;
 	}
 	rcu_read_unlock();
 
 	return entry;
 
+free_act_bpf:
+	kfree(value->act_bpf);
+
 free_acts:
 	p4tc_action_destroy(value->acts);
 
@@ -1434,6 +1546,56 @@ static struct p4tc_table_entry *__tcf_table_entry_cu(struct net *net, u32 flags,
 	return ERR_PTR(ret);
 }
 
+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 tcf_p4act_params *act_params;
+	struct p4tc_act_param *param;
+	unsigned long param_id, tmp;
+	struct tcf_p4act *p4act;
+	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;
+}
+
 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 ddc7a3ea8..71d7b2a78 100644
--- a/net/sched/p4tc/p4tc_tmpl_api.c
+++ b/net/sched/p4tc/p4tc_tmpl_api.c
@@ -582,6 +582,8 @@ static int __init p4tc_template_init(void)
 			op->init();
 	}
 
+	register_p4tc_tbl_bpf();
+
 	return 0;
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 14/21] p4tc: add P4 classifier
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (12 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 13/21] p4tc: add set of P4TC table lookup kfuncs Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 15/21] p4tc: Add P4 extern interface Jamal Hadi Salim
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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 created via a template.
For example, if we were to add a filter to ingress 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.
Note: the different headers and their IDs are already described in the
templating definition and the generated ebpf code.

The parser could be a separate progman or integrated into the ebpf program.
For example, when we have a separate parser program which is loaded into
XDP, we first need to load it into XDP using with 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 reference 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. The eBPF program sets this cookie by using the kfunc
bpf_p4tc_set_cookie.

=============================FILTER ACTIONS=============================

Filter actions will be where the eBPF program that implements the
remaining P4 program components, aside from the parser, will reside in
the form of a TC BPF action. Of course, the user can choose to not
specify a separate eBPF program as a parser and simply implement all the
P4 program components in one eBPF program, which will be the filter
action.

The filter will return the op code returned by this action.

Co-developed-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/uapi/linux/pkt_cls.h |  18 ++
 net/sched/Kconfig            |  12 +
 net/sched/Makefile           |   1 +
 net/sched/cls_p4.c           | 497 +++++++++++++++++++++++++++++++++++
 net/sched/p4tc/Makefile      |   4 +-
 net/sched/p4tc/trace.c       |  10 +
 net/sched/p4tc/trace.h       |  44 ++++
 7 files changed, 585 insertions(+), 1 deletion(-)
 create mode 100644 net/sched/cls_p4.c
 create mode 100644 net/sched/p4tc/trace.c
 create mode 100644 net/sched/p4tc/trace.h

diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index 818e71e13..358e3ca4c 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -723,6 +723,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 d071f9075..5cd43a952 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 937b8f8a9..15bd59ae3 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 000000000..570c6b157
--- /dev/null
+++ b/net/sched/cls_p4.c
@@ -0,0 +1,497 @@
+// 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 <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/bpf.h>
+#include <linux/filter.h>
+
+#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
+
+#include <net/p4tc.h>
+
+#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;
+
+	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;
+
+	trace_p4_classify(skb, head->pipeline);
+
+	*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(sizeof(*prog), GFP_KERNEL);
+		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 161a515ad..03fd265a1 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_parser_api.o p4tc_hdrfield.o p4tc_action.o p4tc_table.o \
-	p4tc_tbl_entry.o p4tc_runtime_api.o p4tc_bpf.o
+	p4tc_tbl_entry.o p4tc_runtime_api.o p4tc_bpf.o trace.o
diff --git a/net/sched/p4tc/trace.c b/net/sched/p4tc/trace.c
new file mode 100644
index 000000000..683313407
--- /dev/null
+++ b/net/sched/p4tc/trace.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+#include <net/p4tc.h>
+
+#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 000000000..80abec13b
--- /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 <linux/tracepoint.h>
+
+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 <trace/define_trace.h>
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 15/21] p4tc: Add P4 extern interface
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (13 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 14/21] p4tc: add P4 classifier Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 16/21] selftests: tc-testing: add JSON introspection file directory for P4TC Jamal Hadi Salim
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut


P4 externs are an abstraction in the language to call for extending language
functionality. For example, the function that sends a packet to a specific
port (send_to_port) in P4 PNA is an extern.

Externs can be seen as classes, which have constructors and methods.
Take, for example, the Register extern definition:

extern Register<T> {
    @tc_md_construct Register(@tc_numel bit<32> size);
    @tc_md_read T read(@tc_key bit<32> index);
    @tc_md_write void write(@tc_key bit<32> index, @tc_data T value);
}

Which can then be instantiated within a P4 program as:
Register<bit<32>>(128) reg1;
Register<bit<16>>(1024) reg2;

Will be abstracted into the template by the P4C compiler for "reg1" as
follows:

tc p4template create extern/register extid 10 numinstances 2
tc p4template create extern_inst/aP4Proggie/register/reg1 instid 1 \
method read method_id 1 param index type bit32 \
method write method_id 2 param index type bit32 param value type bit32 \
control_path tc_key index type bit32 tc_data value type bit32 \
numelemens 128

=========================EXTERN RUNTIME COMMANDS=========================

Once we seal the pipeline, we can populate those indexes
through runtime commands. For example, if we were to populate index 2
with the value 22, we'd issue the following command:

$TC p4runtime create aP4proggie/extern/register/reg1 tc_key index 2 \
tc_data value 22

We can also update this index with another value:

$TC p4runtime update aP4proggie/extern/register/reg1 tc_key index 2 \
tc_data value 33

Or get its value:

$TC p4runtime get aP4proggie/extern/register/reg1 tc_key index 2

Which will yield the following output:

total exts 0
        extern order 1:
          tc_key index id 1 type bit32 value: 1
          tc_data value id 2 type bit32 value: 33

We can also dump all of the elements in this register:

$TC p4runtime get aP4proggie/extern/register/reg1

=========================EXTERN P4 Runtime =========================

The generated ebpf code invokes the externs in the P4TC domain
using the bpf_skb_p4tc_run_extern() kfunc, for example:
if the P4 progran had this invocation:

tmp1 = reg1.read(index1);

Then equivalent generated ebpf code is as follows:

param.pipe_id = aP4Proggie_ID;
param.ext_id = EXTERN_REGISTER;
param.ext_inst_id = EXTERN_REGISTER_INSTANCE_ID1;
param.ext_index = index1;
param.ext_method_id = EXTERN_REGISTER_READ;
param.ext_flags = P4TC_EXT_MD_READ;
bpf_skb_p4tc_run_extern(skb, &param, &res);
tmp1 = (u32 *)res.params;

Co-developed-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/net/p4tc.h                |  139 ++
 include/net/p4tc_ext_api.h        |   87 ++
 include/uapi/linux/p4tc.h         |   63 +
 include/uapi/linux/p4tc_ext.h     |   38 +
 net/sched/p4tc/Makefile           |    3 +-
 net/sched/p4tc/p4tc_bpf.c         |   14 +
 net/sched/p4tc/p4tc_ext.c         | 1978 +++++++++++++++++++++++++
 net/sched/p4tc/p4tc_pipeline.c    |   21 +-
 net/sched/p4tc/p4tc_runtime_api.c |    8 +
 net/sched/p4tc/p4tc_tmpl_api.c    |    4 +
 net/sched/p4tc/p4tc_tmpl_ext.c    | 2256 +++++++++++++++++++++++++++++
 11 files changed, 4609 insertions(+), 2 deletions(-)
 create mode 100644 include/net/p4tc_ext_api.h
 create mode 100644 include/uapi/linux/p4tc_ext.h
 create mode 100644 net/sched/p4tc/p4tc_ext.c
 create mode 100644 net/sched/p4tc/p4tc_tmpl_ext.c

diff --git a/include/net/p4tc.h b/include/net/p4tc.h
index 544a2cf8a..2dc3ceadd 100644
--- a/include/net/p4tc.h
+++ b/include/net/p4tc.h
@@ -19,6 +19,25 @@
 #define P4TC_DEFAULT_TENTRIES 256
 #define P4TC_MAX_TMASKS 1024
 #define P4TC_DEFAULT_TMASKS 8
+#define P4TC_DEFAULT_NUM_EXT_INSTS 1
+#define P4TC_MAX_NUM_EXT_INSTS (1 << 10)
+#define P4TC_DEFAULT_NUM_EXT_INST_ELEMS 1
+/* Can't be 1 << 16 because the max field in the policy definition is an s16:
+ * struct nla_policy {
+ *	u8 type;
+ *	u8 validation_type;
+ *	...
+ *	union {
+ *		...
+ *		struct {
+ *			s16 min, max;
+ *		};
+ *		...
+ *	};
+ *	...
+ * };
+ */
+#define P4TC_MAX_NUM_EXT_INST_ELEMS (1 << 10)
 
 #define P4TC_MAX_PERMISSION (GENMASK(P4TC_PERM_MAX_BIT, 0))
 
@@ -29,6 +48,8 @@
 #define P4TC_AID_IDX 1
 #define P4TC_PARSEID_IDX 1
 #define P4TC_HDRFIELDID_IDX 2
+#define P4TC_TMPL_EXT_IDX 1
+#define P4TC_TMPL_EXT_INST_IDX 2
 
 #define P4TC_HDRFIELD_IS_VALIDITY_BIT 0x1
 
@@ -84,6 +105,10 @@ struct p4tc_pipeline {
 	struct p4tc_template_common common;
 	struct idr                  p_act_idr;
 	struct idr                  p_tbl_idr;
+	/* IDR where the externs are stored globally in the root pipeline */
+	struct idr                  p_ext_idr;
+	/* IDR where the per user pipeline data related to externs is stored */
+	struct idr                  user_ext_idr;
 	struct rcu_head             rcu;
 	struct net                  *net;
 	struct p4tc_parser          *parser;
@@ -174,6 +199,26 @@ struct p4tc_parser_buffer_act_bpf {
 	u16 hdrs[BITS_TO_U16(HEADER_MAX_LEN)];
 };
 
+#define P4TC_EXT_FLAGS_CONTROL_READ 0x1
+#define P4TC_EXT_FLAGS_CONTROL_WRITE 0x2
+
+struct p4tc_ext_bpf_params {
+	u32 pipe_id;
+	u32 ext_id;
+	u32 inst_id;
+	u32 index;
+	u32 method_id;
+	u32 flags;
+	u8  in_params[128]; /* extern specific params if any */
+};
+
+struct p4tc_ext_bpf_res {
+	u32 ext_id;
+	u32 index_id;
+	u32 verdict;
+	u8 out_params[128]; /* specific values if any */
+};
+
 struct p4tc_table_defact {
 	struct tc_action **default_acts;
 	struct p4tc_table_entry_act_bpf *defact_bpf;
@@ -502,9 +547,103 @@ 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_user_pipeline_extern {
+	char			ext_name[EXTERNNAMSIZ];
+	struct idr		e_inst_idr;
+	struct p4tc_tmpl_extern	*tmpl_ext;
+	void (*free)(struct p4tc_user_pipeline_extern *pipe_ext,
+		     struct idr *tmpl_exts_idr);
+	u32			ext_id;
+	refcount_t		ext_ref;
+	refcount_t              curr_insts_num;
+};
+
+struct p4tc_tmpl_extern {
+	struct p4tc_template_common  common;
+	struct idr                   params_idr;
+	char                         mod_name[MODULE_NAME_LEN];
+	const struct p4tc_extern_ops *ops;
+	u32                          ext_id;
+	u32                          num_params;
+	u32                          max_num_insts;
+	refcount_t                   tmpl_ref;
+};
+
+struct p4tc_extern_method {
+	char		method_name[METHODNAMSIZ];
+	struct idr	params_idr;
+	struct rcu_head	rcu;
+	u32		method_id;
+	u32		num_params;
+};
+
+struct p4tc_extern_inst_common {
+	struct idr methods_idr;
+	struct idr control_params_idr;
+	struct idr control_elems_idr;
+	u32	   num_control_params;
+	u32        num_elems;
+	u32	   num_methods;
+};
+
+struct p4tc_ext_bpf_params_exec {
+	u8 *data; /* extern specific params if any */
+	u32 index;
+	u32 method_id;
+};
+
+struct p4tc_extern_inst {
+	struct p4tc_template_common	common;
+	struct p4tc_extern_inst_common	*inst_common;
+	const struct p4tc_extern_ops	*ops;
+	struct p4tc_user_pipeline_extern	*pipe_ext;
+	u32				ext_id;
+	u32				ext_inst_id;
+	u32                             max_num_elems;
+	refcount_t                      curr_num_elems;
+	refcount_t			inst_ref;
+};
+
+int p4tc_pipeline_create_extern_net(struct p4tc_tmpl_extern *tmpl_ext);
+int p4tc_pipeline_del_extern_net(struct p4tc_tmpl_extern *tmpl_ext);
+struct p4tc_user_pipeline_extern *
+p4tc_tmpl_extern_net_find_byid(struct net *net, const u32 ext_id);
+struct p4tc_extern_inst *
+p4tc_ext_inst_find_bynames(struct net *net, struct p4tc_pipeline *pipeline,
+			   const char *extname, const char *instname,
+			   struct netlink_ext_ack *extack);
+struct p4tc_extern_inst *
+p4tc_ext_inst_get_byids(struct net *net, struct p4tc_pipeline **pipeline,
+			const u32 pipe_id,
+			struct p4tc_user_pipeline_extern **pipe_ext,
+			const u32 ext_id, const u32 inst_id);
+struct p4tc_extern_ops *p4tc_extern_ops_get(char *kind);
+void p4tc_extern_ops_put(const struct p4tc_extern_ops *ops);
+
+int p4tc_register_extern(struct p4tc_extern_ops *ext);
+int p4tc_unregister_extern(struct p4tc_extern_ops *ext);
+
+extern const struct p4tc_template_ops p4tc_tmpl_ext_ops;
+extern const struct p4tc_template_ops p4tc_tmpl_ext_inst_ops;
+
+struct p4tc_extern_param {
+	char				name[EXTPARAMNAMSIZ];
+	struct rcu_head			rcu;
+	void				*value;
+	struct p4tc_type		*type;
+	struct p4tc_type_mask_shift	*mask_shift;
+	u32				id;
+	u32				index;
+	u8				flags;
+};
+
 #define to_pipeline(t) ((struct p4tc_pipeline *)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_extern(t) ((struct p4tc_tmpl_extern *)t)
+#define to_extern_inst(t) ((struct p4tc_extern_inst *)t)
+
+
 #endif
diff --git a/include/net/p4tc_ext_api.h b/include/net/p4tc_ext_api.h
new file mode 100644
index 000000000..2c64f4814
--- /dev/null
+++ b/include/net/p4tc_ext_api.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __NET_P4TC_EXT_API_H
+#define __NET_P4TC_EXT_API_H
+
+/*
+ * Public extern P4TC_EXT API
+ */
+
+#include <uapi/linux/p4tc_ext.h>
+#include <linux/refcount.h>
+#include <net/flow_offload.h>
+#include <net/sch_generic.h>
+#include <net/pkt_sched.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include <net/p4tc.h>
+
+struct p4tc_extern_ops;
+
+struct p4tc_extern_params {
+	struct idr params_idr;
+	spinlock_t params_lock;
+	u32 num_params;
+};
+
+struct p4tc_extern {
+	struct p4tc_extern_params	*params;
+	struct idr			*elems_idr;
+	const struct p4tc_extern_ops	*ops;
+	struct p4tc_extern_inst		*inst;
+	struct rcu_head			rcu;
+	size_t				attrs_size;
+	spinlock_t			p4tc_ext_lock;
+	u32				p4tc_ext_key;
+	refcount_t			p4tc_ext_refcnt;
+	u32				p4tc_ext_flags;
+};
+
+/* Reserve 16 bits for user-space. See P4TC_EXT_FLAGS_NO_PERCPU_STATS. */
+#define P4TC_EXT_FLAGS_USER_BITS 16
+#define P4TC_EXT_FLAGS_USER_MASK 0xffff
+#define P4TC_EXT_FLAGS_REPLACE	(1U << (P4TC_EXT_FLAGS_USER_BITS + 1))
+
+struct p4tc_extern_ops {
+	struct list_head head;
+	char kind[P4TC_EXT_NAMSIZ];
+	size_t size;
+	struct module *owner;
+	struct p4tc_tmpl_extern *tmpl_ext;
+	int     (*exec)(struct sk_buff *skb,
+			struct p4tc_extern_inst_common *common,
+			struct p4tc_extern *e,
+			struct p4tc_ext_bpf_params_exec *params,
+			struct p4tc_ext_bpf_res *res);
+	u32 id; /* identifier should match kind */
+};
+
+#define P4TC_EXT_P_CREATED 1
+#define P4TC_EXT_P_DELETED 1
+
+
+int p4tc_register_extern(struct p4tc_extern_ops *ext);
+int p4tc_unregister_extern(struct p4tc_extern_ops *ext);
+
+int p4tc_ctl_extern_dump(struct sk_buff *skb, struct netlink_callback *cb,
+			 struct nlattr **tb, const char *pname);
+void p4tc_ext_purge(struct idr *idr);
+
+int p4tc_ctl_extern(struct sk_buff *skb, struct nlmsghdr *n, const char *pname,
+		    struct nlattr *nla, struct netlink_ext_ack *extack);
+struct p4tc_extern_param *
+p4tc_extern_param_find_byanyattr(struct idr *params_idr,
+				 struct nlattr *name_attr,
+				 const u32 param_id,
+				 struct netlink_ext_ack *extack);
+struct p4tc_tmpl_extern *
+p4tc_tmpl_ext_find_byany(struct p4tc_pipeline *pipeline,
+			 const char *extern_name, u32 ext_id,
+			 struct netlink_ext_ack *extack);
+struct p4tc_extern_param *
+p4tc_extern_param_find_byid(struct idr *params_idr, const u32 param_id);
+
+int
+p4tc_extern_exec_bpf(struct sk_buff *skb, struct p4tc_ext_bpf_params *params,
+		     struct p4tc_ext_bpf_res *res);
+
+#endif
diff --git a/include/uapi/linux/p4tc.h b/include/uapi/linux/p4tc.h
index 2dc36e8c7..6d0ba2c58 100644
--- a/include/uapi/linux/p4tc.h
+++ b/include/uapi/linux/p4tc.h
@@ -19,6 +19,9 @@ struct p4tcmsg {
 #define P4TC_MAXMETA_SZ 128
 #define P4TC_MSGBATCH_SIZE 16
 
+#define EXTPARAMNAMSIZ 256
+#define P4TC_MAX_EXTERN_METHODS 32
+
 #define P4TC_MAX_KEYSZ 512
 #define HEADER_MAX_LEN 512
 
@@ -28,6 +31,9 @@ struct p4tcmsg {
 #define HDRFIELDNAMSIZ TEMPLATENAMSZ
 #define ACTPARAMNAMSIZ TEMPLATENAMSZ
 #define TABLENAMSIZ TEMPLATENAMSZ
+#define EXTERNNAMSIZ TEMPLATENAMSZ
+#define EXTERNINSTNAMSIZ TEMPLATENAMSZ
+#define METHODNAMSIZ 128
 
 #define P4TC_TABLE_FLAGS_KEYSZ 0x01
 #define P4TC_TABLE_FLAGS_MAX_ENTRIES 0x02
@@ -100,6 +106,8 @@ enum {
 	P4TC_ROOT_UNSPEC,
 	P4TC_ROOT, /* nested messages */
 	P4TC_ROOT_PNAME, /* string */
+	P4TC_ROOT_COUNT,
+	P4TC_ROOT_FLAGS,
 	__P4TC_ROOT_MAX,
 };
 #define P4TC_ROOT_MAX __P4TC_ROOT_MAX
@@ -124,6 +132,8 @@ enum {
 	P4TC_OBJ_ACT,
 	P4TC_OBJ_TABLE,
 	P4TC_OBJ_TABLE_ENTRY,
+	P4TC_OBJ_EXT,
+	P4TC_OBJ_EXT_INST,
 	__P4TC_OBJ_MAX,
 };
 #define P4TC_OBJ_MAX __P4TC_OBJ_MAX
@@ -132,6 +142,7 @@ enum {
 enum {
 	P4TC_OBJ_RUNTIME_UNSPEC,
 	P4TC_OBJ_RUNTIME_TABLE,
+	P4TC_OBJ_RUNTIME_EXTERN,
 	__P4TC_OBJ_RUNTIME_MAX,
 };
 #define P4TC_OBJ_RUNTIMEMAX __P4TC_OBJ_RUNTIMEMAX
@@ -320,6 +331,58 @@ enum {
 	P4TC_ENTITY_MAX
 };
 
+/* P4 Extern attributes */
+enum {
+	P4TC_TMPL_EXT_UNSPEC,
+	P4TC_TMPL_EXT_NAME, /* string */
+	P4TC_TMPL_EXT_NUM_INSTS, /* u16 */
+	__P4TC_TMPL_EXT_MAX
+};
+#define P4TC_TMPL_EXT_MAX (__P4TC_TMPL_EXT_MAX - 1)
+
+enum {
+	P4TC_TMPL_EXT_INST_UNSPEC,
+	P4TC_TMPL_EXT_INST_EXT_NAME, /* string */
+	P4TC_TMPL_EXT_INST_NAME, /* string */
+	P4TC_TMPL_EXT_INST_NUM_ELEMS, /* u32 */
+	P4TC_TMPL_EXT_INST_METHODS, /* nested methods */
+	P4TC_TMPL_EXT_INST_CONTROL_PARAMS, /* nested control params */
+	__P4TC_TMPL_EXT_INST_MAX
+};
+#define P4TC_TMPL_EXT_INST_MAX (__P4TC_TMPL_EXT_INST_MAX - 1)
+
+enum {
+	P4TC_TMPL_EXT_INST_METHOD_UNSPEC,
+	P4TC_TMPL_EXT_INST_METHOD_NAME, /* string */
+	P4TC_TMPL_EXT_INST_METHOD_ID, /* u32 */
+	P4TC_TMPL_EXT_INST_METHOD_PARAMS, /* nested params */
+	__P4TC_TMPL_EXT_INST_METHOD_MAX
+};
+#define P4TC_TMPL_EXT_INST_METHOD_MAX (__P4TC_TMPL_EXT_INST_METHOD_MAX - 1)
+
+/* Extern params attributes */
+enum {
+	P4TC_EXT_PARAMS_VALUE_UNSPEC,
+	P4TC_EXT_PARAMS_VALUE_RAW, /* binary */
+	__P4TC_EXT_PARAMS_VALUE_MAX
+};
+#define P4TC_EXT_VALUE_PARAMS_MAX __P4TC_EXT_PARAMS_VALUE_MAX
+
+#define P4TC_EXT_PARAMS_FLAG_ISKEY 0x1
+
+/* Extern params attributes */
+enum {
+	P4TC_EXT_PARAMS_UNSPEC,
+	P4TC_EXT_PARAMS_NAME, /* string */
+	P4TC_EXT_PARAMS_ID, /* u32 */
+	P4TC_EXT_PARAMS_VALUE, /* bytes */
+	P4TC_EXT_PARAMS_TYPE, /* u32 */
+	P4TC_EXT_PARAMS_BITSZ, /* u16 */
+	P4TC_EXT_PARAMS_FLAGS, /* u8 */
+	__P4TC_EXT_PARAMS_MAX
+};
+#define P4TC_EXT_PARAMS_MAX __P4TC_EXT_PARAMS_MAX
+
 #define P4TC_RTA(r) \
 	((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct p4tcmsg))))
 
diff --git a/include/uapi/linux/p4tc_ext.h b/include/uapi/linux/p4tc_ext.h
new file mode 100644
index 000000000..12f80007e
--- /dev/null
+++ b/include/uapi/linux/p4tc_ext.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_P4TC_EXT_H
+#define __LINUX_P4TC_EXT_H
+
+#include <linux/types.h>
+#include <linux/pkt_sched.h>
+
+#define P4TC_EXT_NAMSIZ 64
+
+/* Extern attributes */
+enum {
+	P4TC_EXT_UNSPEC,
+	P4TC_EXT_INST_NAME,
+	P4TC_EXT_KIND,
+	P4TC_EXT_PARAMS,
+	P4TC_EXT_FCNT,
+	P4TC_EXT_PAD,
+	P4TC_EXT_FLAGS,
+	__P4TC_EXT_MAX
+};
+
+#define P4TC_EXT_ID_DYN 0x01
+#define P4TC_EXT_ID_MAX 1023
+
+/* See other P4TC_EXT_FLAGS_ * flags in include/net/act_api.h. */
+#define P4TC_EXT_FLAGS_NO_PERCPU_STATS (1 << 0) /* Don't use percpu allocator
+						 * for externs stats.
+						 */
+#define P4TC_EXT_FLAGS_SKIP_HW	(1 << 1) /* don't offload action to HW */
+#define P4TC_EXT_FLAGS_SKIP_SW	(1 << 2) /* don't use action in SW */
+
+#define P4TC_EXT_FLAG_LARGE_DUMP_ON	(1 << 0)
+
+#define P4TC_EXT_MAX __P4TC_EXT_MAX
+#define P4TC_EXT_REPLACE		1
+#define P4TC_EXT_NOREPLACE	0
+
+#endif
diff --git a/net/sched/p4tc/Makefile b/net/sched/p4tc/Makefile
index 03fd265a1..57f20b3f3 100644
--- a/net/sched/p4tc/Makefile
+++ b/net/sched/p4tc/Makefile
@@ -4,4 +4,5 @@ CFLAGS_trace.o := -I$(src)
 
 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_entry.o p4tc_runtime_api.o p4tc_bpf.o trace.o
+	p4tc_tbl_entry.o p4tc_runtime_api.o p4tc_bpf.o trace.o p4tc_ext.o \
+	p4tc_tmpl_ext.o
diff --git a/net/sched/p4tc/p4tc_bpf.c b/net/sched/p4tc/p4tc_bpf.c
index adfdc678f..02f039210 100644
--- a/net/sched/p4tc/p4tc_bpf.c
+++ b/net/sched/p4tc/p4tc_bpf.c
@@ -16,6 +16,7 @@
 #include <linux/btf_ids.h>
 #include <linux/net_namespace.h>
 #include <net/p4tc.h>
+#include <net/p4tc_ext_api.h>
 #include <linux/netdevice.h>
 #include <net/sock.h>
 #include <linux/filter.h>
@@ -23,6 +24,8 @@
 BTF_ID_LIST(btf_p4tc_ids)
 BTF_ID(struct, p4tc_table_entry_act_bpf)
 BTF_ID(struct, p4tc_table_entry_act_bpf_params)
+BTF_ID(struct, p4tc_ext_bpf_params)
+BTF_ID(struct, p4tc_ext_bpf_res)
 
 #define ENTRY_KEY_OFFSET (offsetof(struct p4tc_table_entry_key, fa_key))
 
@@ -91,10 +94,21 @@ void bpf_p4tc_set_cookie(u32 cookie)
 	pad->prog_cookie = cookie;
 }
 
+int
+bpf_skb_p4tc_run_extern(struct __sk_buff *skb_ctx,
+			struct p4tc_ext_bpf_params *params,
+			struct p4tc_ext_bpf_res *res)
+{
+	struct sk_buff *skb = (struct sk_buff *)skb_ctx;
+
+	return p4tc_extern_exec_bpf(skb, params, res);
+}
+
 BTF_SET8_START(p4tc_tbl_kfunc_set)
 BTF_ID_FLAGS(func, bpf_skb_p4tc_tbl_lookup, KF_RET_NULL);
 BTF_ID_FLAGS(func, bpf_xdp_p4tc_tbl_lookup, KF_RET_NULL);
 BTF_ID_FLAGS(func, bpf_p4tc_set_cookie, 0);
+BTF_ID_FLAGS(func, bpf_skb_p4tc_run_extern, KF_TRUSTED_ARGS);
 BTF_SET8_END(p4tc_tbl_kfunc_set)
 
 static const struct btf_kfunc_id_set p4tc_table_kfunc_set = {
diff --git a/net/sched/p4tc/p4tc_ext.c b/net/sched/p4tc/p4tc_ext.c
new file mode 100644
index 000000000..b3c374d2f
--- /dev/null
+++ b/net/sched/p4tc/p4tc_ext.c
@@ -0,0 +1,1978 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * net/sched/p4tc_ext.c	P4 TC EXTERN API
+ *
+ * Copyright (c) 2022-2023, Mojatatu Networks
+ * Copyright (c) 2022-2023, Intel Corporation.
+ * Authors:     Jamal Hadi Salim <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/p4tc_types.h>
+#include <net/p4tc_ext_api.h>
+#include <net/netlink.h>
+#include <net/flow_offload.h>
+#include <net/tc_wrapper.h>
+#include <uapi/linux/p4tc.h>
+
+static void p4tc_ext_put_param(struct p4tc_extern_param *param)
+{
+	kfree(param->value);
+	kfree(param);
+}
+
+static void p4tc_ext_put_many_params(struct idr *params_idr,
+				     struct p4tc_extern_param *params[],
+				     int params_count)
+{
+	int i;
+
+	for (i = 0; i < params_count; i++)
+		p4tc_ext_put_param(params[i]);
+}
+
+static void p4tc_ext_insert_param(struct idr *params_idr,
+				  struct p4tc_extern_param *param)
+{
+	struct p4tc_extern_param *param_old;
+
+	param_old = idr_replace(params_idr, param, param->id);
+	if (param_old != ERR_PTR(-EBUSY))
+		p4tc_ext_put_param(param_old);
+}
+
+static void p4tc_ext_insert_many_params(struct idr *params_idr,
+					struct p4tc_extern_param *params[],
+					int params_count)
+{
+	int i;
+
+	for (i = 0; i < params_count; i++)
+		p4tc_ext_insert_param(params_idr, params[i]);
+}
+
+static void free_p4tc_ext_params(struct p4tc_extern_params *params)
+{
+	struct p4tc_extern_param *parm;
+	unsigned long tmp, id;
+
+	idr_for_each_entry_ul(&params->params_idr, parm, tmp, id) {
+		idr_remove(&params->params_idr, id);
+		p4tc_ext_put_param(parm);
+	}
+
+	kfree(params);
+}
+
+static void free_p4tc_ext(struct p4tc_extern *p)
+{
+	if (p->params)
+		free_p4tc_ext_params(p->params);
+	refcount_dec(&p->inst->inst_ref);
+
+	kfree(p);
+}
+
+static void free_p4tc_ext_rcu(struct rcu_head *rcu)
+{
+	struct p4tc_extern *p;
+
+	p = container_of(rcu, struct p4tc_extern, rcu);
+
+	free_p4tc_ext(p);
+}
+
+static void p4tc_extern_cleanup(struct p4tc_extern *p)
+{
+	free_p4tc_ext_rcu(&p->rcu);
+}
+
+static int __p4tc_extern_put(struct p4tc_extern *p)
+{
+	if (refcount_dec_and_test(&p->p4tc_ext_refcnt)) {
+		idr_remove(p->elems_idr, p->p4tc_ext_key);
+
+		refcount_dec(&p->inst->curr_num_elems);
+		p4tc_extern_cleanup(p);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static int __p4tc_ext_idr_release(struct p4tc_extern *p)
+{
+	int ret = 0;
+
+	if (p) {
+		if (__p4tc_extern_put(p))
+			ret = ACT_P_DELETED;
+	}
+
+	return ret;
+}
+
+static int p4tc_ext_idr_release(struct p4tc_extern *e)
+{
+	const struct p4tc_extern_ops *ops = e->ops;
+	struct p4tc_extern_inst *inst = e->inst;
+	int ret;
+
+	ret = __p4tc_ext_idr_release(e);
+	if (ret == ACT_P_DELETED) {
+		refcount_dec(&inst->curr_num_elems);
+		p4tc_extern_ops_put(ops);
+	}
+
+	return ret;
+}
+
+static size_t p4tc_extern_shared_attrs_size(const struct p4tc_extern *ext)
+{
+	return  nla_total_size(0) /* extern number nested */
+		+ nla_total_size(EXTERNNAMSIZ)  /* P4TC_EXT_KIND */
+		+ nla_total_size(EXTERNINSTNAMSIZ) /* P4TC_EXT_INST_NAME */
+		+ nla_total_size(sizeof(struct nla_bitfield32)); /* P4TC_EXT_FLAGS */
+}
+
+static size_t p4tc_extern_full_attrs_size(size_t sz)
+{
+	return NLMSG_HDRLEN                     /* struct nlmsghdr */
+		+ sizeof(struct p4tcmsg)
+		+ nla_total_size(0)             /* P4TC_ROOT nested */
+		+ sz;
+}
+
+static size_t p4tc_extern_fill_size(const struct p4tc_extern *ext)
+{
+	size_t sz = p4tc_extern_shared_attrs_size(ext);
+
+	return sz;
+}
+
+struct p4tc_extern_param_ops {
+	int (*init_value)(struct net *net, struct p4tc_extern_param_ops *op,
+			  struct p4tc_extern_param *nparam, struct nlattr **tb,
+			  struct netlink_ext_ack *extack);
+	int (*dump_value)(struct sk_buff *skb, struct p4tc_extern_param_ops *op,
+			  struct p4tc_extern_param *param);
+	void (*free)(struct p4tc_extern_param *param);
+	u32 len;
+	u32 alloc_len;
+};
+
+static int
+generic_dump_ext_param_value(struct sk_buff *skb, struct p4tc_type *type,
+			     struct p4tc_extern_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_EXT_PARAMS_VALUE);
+	if (nla_put(skb, P4TC_EXT_PARAMS_VALUE_RAW, bytesz,
+		    param->value))
+		goto out_nlmsg_trim;
+	nla_nest_end(skb, nla_value);
+
+	return 0;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static const struct nla_policy p4tc_extern_params_value_policy[P4TC_EXT_VALUE_PARAMS_MAX + 1] = {
+	[P4TC_EXT_PARAMS_VALUE_RAW] = { .type = NLA_BINARY },
+};
+
+static int dev_init_param_value(struct net *net, struct p4tc_extern_param_ops *op,
+				struct p4tc_extern_param *nparam,
+				struct nlattr **tb,
+				struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb_value[P4TC_EXT_VALUE_PARAMS_MAX + 1];
+	u32 value_len;
+	u32 *ifindex;
+	int err;
+
+	if (!tb[P4TC_EXT_PARAMS_VALUE]) {
+		NL_SET_ERR_MSG(extack, "Must specify param value");
+		return -EINVAL;
+	}
+	err = nla_parse_nested(tb_value, P4TC_EXT_VALUE_PARAMS_MAX,
+			       tb[P4TC_EXT_PARAMS_VALUE],
+			       p4tc_extern_params_value_policy, extack);
+	if (err < 0)
+		return err;
+
+	value_len = nla_len(tb_value[P4TC_EXT_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_EXT_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_extern_param_ops *op,
+				struct p4tc_extern_param *param)
+{
+	struct nlattr *nest;
+	u32 *ifindex;
+	int ret;
+
+	nest = nla_nest_start(skb, P4TC_EXT_PARAMS_VALUE);
+	ifindex = (u32 *)param->value;
+
+	if (nla_put_u32(skb, P4TC_EXT_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_extern_param *param)
+{
+	kfree(param->value);
+}
+
+static const struct p4tc_extern_param_ops ext_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 int
+p4tc_extern_dump_1(struct sk_buff *skb, struct p4tc_extern *e, int ref)
+{
+	unsigned char *b = skb_tail_pointer(skb);
+	struct p4tc_extern_param *parm;
+	struct nlattr *nest_parms;
+	u32 flags;
+	int id;
+
+	if (nla_put_string(skb, P4TC_EXT_KIND, e->ops->kind))
+		goto nla_put_failure;
+
+	flags = e->p4tc_ext_flags & P4TC_EXT_FLAGS_USER_MASK;
+	if (flags &&
+	    nla_put_bitfield32(skb, P4TC_EXT_FLAGS,
+			       flags, flags))
+		goto nla_put_failure;
+
+	nest_parms = nla_nest_start(skb, P4TC_EXT_PARAMS);
+	if (e->params) {
+		int i = 1;
+
+		idr_for_each_entry(&e->params->params_idr, parm, id) {
+			struct p4tc_extern_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_EXT_PARAMS_NAME,
+					   parm->name))
+				goto nla_put_failure;
+
+			if (nla_put_u32(skb, P4TC_EXT_PARAMS_ID, parm->id))
+				goto nla_put_failure;
+
+			op = (struct p4tc_extern_param_ops *)&ext_param_ops[parm->type->typeid];
+			spin_lock(&e->params->params_lock);
+			if (op->dump_value) {
+				if (op->dump_value(skb, op, parm) < 0) {
+					spin_unlock(&e->params->params_lock);
+					goto nla_put_failure;
+				}
+			} else {
+				if (generic_dump_ext_param_value(skb, parm->type, parm)) {
+					spin_unlock(&e->params->params_lock);
+					goto nla_put_failure;
+				}
+			}
+			spin_unlock(&e->params->params_lock);
+
+			if (nla_put_u32(skb, P4TC_EXT_PARAMS_TYPE, parm->type->typeid))
+				goto nla_put_failure;
+
+			if (nla_put_u32(skb, P4TC_EXT_PARAMS_FLAGS,
+					parm->flags))
+				goto nla_put_failure;
+
+			nla_nest_end(skb, nest_count);
+			i++;
+		}
+	}
+	nla_nest_end(skb, nest_parms);
+
+	return skb->len;
+
+nla_put_failure:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static int p4tc_ext_dump_walker(struct p4tc_extern_inst *inst,
+				struct sk_buff *skb,
+				struct netlink_callback *cb)
+{
+	struct idr *idr = &inst->inst_common->control_elems_idr;
+	int err = 0, s_i = 0, n_i = 0;
+	u32 ext_flags = cb->args[2];
+	unsigned long id = 1;
+	struct p4tc_extern *p;
+	struct nlattr *nest;
+	unsigned long tmp;
+	int key = -1;
+
+	s_i = cb->args[0];
+
+	idr_for_each_entry_ul(idr, p, tmp, id) {
+		key++;
+		if (key < s_i)
+			continue;
+		if (IS_ERR(p))
+			continue;
+
+		nest = nla_nest_start_noflag(skb, n_i);
+		if (!nest) {
+			key--;
+			goto nla_put_failure;
+		}
+
+		err = p4tc_extern_dump_1(skb, p, 0);
+		if (err < 0) {
+			key--;
+			nlmsg_trim(skb, nest);
+			goto done;
+		}
+		nla_nest_end(skb, nest);
+		n_i++;
+		if (!(ext_flags & P4TC_EXT_FLAG_LARGE_DUMP_ON) &&
+		    n_i >= P4TC_MSGBATCH_SIZE)
+			goto done;
+	}
+done:
+	if (key >= 0)
+		cb->args[0] = key + 1;
+
+	if (n_i) {
+		if (ext_flags & P4TC_EXT_FLAG_LARGE_DUMP_ON)
+			cb->args[1] = n_i;
+	}
+	return n_i;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nest);
+	goto done;
+}
+
+static void p4tc_ext_idr_purge(struct p4tc_extern *p)
+{
+	idr_remove(p->elems_idr, p->p4tc_ext_key);
+	p4tc_extern_ops_put(p->ops);
+	refcount_dec(&p->inst->curr_num_elems);
+	p4tc_extern_cleanup(p);
+}
+
+static int p4tc_ext_idr_release_unsafe(struct p4tc_extern *p)
+{
+	if (refcount_dec_and_test(&p->p4tc_ext_refcnt)) {
+		idr_remove(p->elems_idr, p->p4tc_ext_key);
+		p4tc_extern_cleanup(p);
+		return ACT_P_DELETED;
+	}
+
+	return 0;
+}
+
+/* Called when pipeline is being purged */
+void p4tc_ext_purge(struct idr *idr)
+{
+	struct p4tc_extern *p;
+	unsigned long tmp, id;
+
+	idr_for_each_entry_ul(idr, p, tmp, id) {
+		if (IS_ERR(p))
+			continue;
+		p4tc_ext_idr_purge(p);
+	}
+}
+
+static int p4tc_ext_del_walker(struct p4tc_extern_inst *inst,
+			       struct sk_buff *skb,
+			       const struct p4tc_extern_ops *ops,
+			       struct netlink_ext_ack *extack)
+{
+	struct idr *idr = &inst->inst_common->control_elems_idr;
+	unsigned long id = 1;
+	int ret = -EINVAL;
+	int n_i = 0;
+	struct p4tc_extern *p;
+	struct nlattr *nest;
+	unsigned long tmp;
+
+	nest = nla_nest_start_noflag(skb, 0);
+	if (!nest)
+		goto nla_put_failure;
+	if (nla_put_string(skb, P4TC_EXT_KIND, ops->kind))
+		goto nla_put_failure;
+
+	ret = 0;
+	idr_for_each_entry_ul(idr, p, tmp, id) {
+		if (IS_ERR(p))
+			continue;
+		ret = p4tc_ext_idr_release_unsafe(p);
+		if (ret == ACT_P_DELETED) {
+			refcount_dec(&inst->curr_num_elems);
+			p4tc_extern_ops_put(ops);
+		} else if (ret < 0) {
+			break;
+		}
+		n_i++;
+	}
+	if (ret < 0) {
+		if (n_i)
+			NL_SET_ERR_MSG(extack, "Unable to flush all TC externs");
+		else
+			goto nla_put_failure;
+	}
+
+	ret = nla_put_u32(skb, P4TC_EXT_FCNT, n_i);
+	if (ret)
+		goto nla_put_failure;
+	nla_nest_end(skb, nest);
+
+	return n_i;
+nla_put_failure:
+	nla_nest_cancel(skb, nest);
+	return ret;
+}
+
+static int p4tc_ext_generic_walker(struct p4tc_extern_inst *inst,
+				   struct sk_buff *skb,
+				   struct netlink_callback *cb, int type,
+				   const struct p4tc_extern_ops *ops,
+				   struct netlink_ext_ack *extack)
+{
+	if (type == RTM_P4TC_DEL)
+		return p4tc_ext_del_walker(inst, skb, ops, extack);
+	else if (type == RTM_P4TC_GET)
+		return p4tc_ext_dump_walker(inst, skb, cb);
+
+	WARN(1, "%s: unknown command %d\n", __func__, type);
+	NL_SET_ERR_MSG_FMT(extack, "%s: unknown command", __func__);
+	return -EINVAL;
+}
+
+static int p4tc_ext_idr_search(struct p4tc_extern_inst *inst,
+			       struct p4tc_extern **e, u32 key)
+{
+	struct idr *elems_idr = &inst->inst_common->control_elems_idr;
+	struct p4tc_extern *p;
+
+	p = idr_find(elems_idr, key);
+	if (IS_ERR(p))
+		p = NULL;
+
+	if (p) {
+		*e = p;
+		return true;
+	}
+	return false;
+}
+
+static int __p4tc_ext_generic_walker(struct sk_buff *skb,
+				     struct netlink_callback *cb, int type,
+				     struct p4tc_extern_inst *inst,
+				     const struct p4tc_extern_ops *ops,
+				     struct netlink_ext_ack *extack)
+{
+	return p4tc_ext_generic_walker(inst, skb, cb, type, ops, extack);
+}
+
+static int __p4tc_ext_idr_search(struct p4tc_extern_inst *inst,
+				 struct p4tc_extern **e, u32 key)
+{
+	if (p4tc_ext_idr_search(inst, e, key)) {
+		refcount_inc(&((*e)->p4tc_ext_refcnt));
+		return true;
+	}
+
+	return false;
+}
+
+static int p4tc_ext_idr_delete_key(struct idr *elems_idr, u32 key)
+{
+	struct p4tc_extern *p;
+	int ret = 0;
+
+	p = idr_find(elems_idr, key);
+	if (!p)
+		return -ENOENT;
+
+	if (refcount_dec_and_test(&p->p4tc_ext_refcnt)) {
+		WARN_ON(p != idr_remove(elems_idr, p->p4tc_ext_key));
+
+		refcount_dec(&p->inst->curr_num_elems);
+		p4tc_extern_ops_put(p->ops);
+		p4tc_extern_cleanup(p);
+		return 0;
+	}
+
+	return ret;
+}
+
+static int p4tc_ext_copy(struct p4tc_extern_inst *inst,
+			 u32 key, struct p4tc_extern **e,
+			 struct p4tc_extern *e_orig,
+			 const struct p4tc_extern_ops *ops,
+			 u32 flags)
+{
+	struct p4tc_extern *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+	if (unlikely(!p))
+		return -ENOMEM;
+
+	spin_lock_init(&p->p4tc_ext_lock);
+	p->p4tc_ext_key = key;
+	spin_lock(&e_orig->p4tc_ext_lock);
+	spin_unlock(&e_orig->p4tc_ext_lock);
+	p->p4tc_ext_flags = flags;
+	refcount_set(&p->p4tc_ext_refcnt,
+		     refcount_read(&e_orig->p4tc_ext_refcnt));
+
+	p->elems_idr = e_orig->elems_idr;
+	refcount_inc(&inst->inst_ref);
+	p->inst = inst;
+	p->ops = ops;
+	*e = p;
+	return 0;
+}
+
+static int p4tc_ext_idr_create(struct p4tc_extern_inst *inst,
+			       u32 key, struct p4tc_extern **e,
+			       const struct p4tc_extern_ops *ops,
+			       u32 flags)
+{
+	struct p4tc_extern *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+	if (unlikely(!p))
+		return -ENOMEM;
+
+	if (refcount_read(&inst->curr_num_elems) - 1 == inst->max_num_elems) {
+		kfree(p);
+		return -E2BIG;
+	}
+
+	refcount_inc(&inst->curr_num_elems);
+
+	refcount_set(&p->p4tc_ext_refcnt, 1);
+
+	spin_lock_init(&p->p4tc_ext_lock);
+	p->p4tc_ext_key = key;
+	p->p4tc_ext_flags = flags;
+
+	p->elems_idr = &inst->inst_common->control_elems_idr;
+	__module_get(ops->owner);
+	inst->ops = ops;
+	refcount_inc(&inst->inst_ref);
+	p->inst = inst;
+	p->ops = ops;
+	*e = p;
+	return 0;
+}
+
+/* Cleanup idr key that was allocated but not initialized. */
+
+static void p4tc_ext_idr_cleanup(struct p4tc_extern_inst_common *inst_common,
+				 u32 key)
+{
+	/* Remove ERR_PTR(-EBUSY) allocated by p4tc_ext_idr_check_alloc */
+	WARN_ON(!IS_ERR(idr_remove(&inst_common->control_elems_idr, key)));
+}
+
+/* Check if extern with specified key exists. If externs is found, increments
+ * its reference, and return 1. Otherwise insert temporary error pointer
+ * (to prevent concurrent users from inserting externs with same key) and
+ * return 0.
+ */
+
+static int p4tc_ext_idr_check_alloc(struct p4tc_extern_inst *inst,
+				    u32 *key, struct p4tc_extern **e)
+{
+	struct idr *elems_idr = &inst->inst_common->control_elems_idr;
+	struct p4tc_extern *p;
+	int ret;
+
+again:
+	if (*key) {
+		p = idr_find(elems_idr, *key);
+		if (IS_ERR(p)) {
+			/* This means that another process allocated
+			 * key but did not assign the pointer yet.
+			 */
+			goto again;
+		}
+
+		if (p) {
+			refcount_inc(&p->p4tc_ext_refcnt);
+			*e = p;
+			ret = 1;
+		} else {
+			*e = NULL;
+			ret = idr_alloc_u32(elems_idr, NULL, key,
+					    *key, GFP_KERNEL);
+			if (!ret)
+				idr_replace(elems_idr,
+					    ERR_PTR(-EBUSY), *key);
+		}
+	} else {
+		*key = 1;
+		*e = NULL;
+		ret = idr_alloc_u32(elems_idr, NULL, key, UINT_MAX,
+				    GFP_KERNEL);
+		if (!ret)
+			idr_replace(elems_idr, ERR_PTR(-EBUSY), *key);
+	}
+	return ret;
+}
+
+static inline void *read_control_value(struct idr *params_idr, const u32 index)
+{
+	struct p4tc_extern_param *param = idr_find(params_idr, index);
+
+	return param->value;
+}
+
+static int p4tc_extern_exec_write(struct p4tc_extern *e,
+				  struct p4tc_ext_bpf_params *params)
+{
+	u8 *params_data = params->in_params;
+	struct p4tc_extern_param *param;
+	struct p4tc_type *type;
+
+	/* When it's method P4TC_EXT_FLAGS_CONTROL_WRITE, we assume the first
+	 * parameter is the index and the second is the value we wish to write
+	 * to.
+	 */
+	spin_lock(&e->params->params_lock);
+
+	param = idr_find(&e->params->params_idr, 2);
+	type = param->type;
+
+	p4t_copy(param->mask_shift, type, param->value,
+		 param->mask_shift, type, params_data);
+
+	spin_unlock(&e->params->params_lock);
+
+	return 0;
+}
+
+static int p4tc_extern_exec_read(struct p4tc_extern *e,
+				 struct p4tc_ext_bpf_res *res, u32 index)
+{
+	int ret = 0;
+	struct p4tc_extern_param *param;
+	const struct p4tc_type_ops *ops;
+
+	/* When it's method P4TC_EXT_FLAGS_CONTROL_READ, we assume the first
+	 * parameter is the index and the second is the value we want to read.
+	 */
+	spin_lock(&e->params->params_lock);
+	param = idr_find(&e->params->params_idr, 2);
+	ops = param->type->ops;
+
+	if (unlikely(!ops->host_read)) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	ops->host_read(param->type, param->mask_shift, param->value,
+		       res->out_params);
+
+unlock:
+	spin_unlock(&e->params->params_lock);
+
+	return ret;
+}
+
+int
+p4tc_extern_exec_bpf(struct sk_buff *skb, struct p4tc_ext_bpf_params *params,
+		     struct p4tc_ext_bpf_res *res)
+{
+	struct net *net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk);
+	struct p4tc_ext_bpf_params_exec exec_params = {0};
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	struct p4tc_pipeline *pipeline;
+	struct p4tc_extern_inst *inst;
+	struct p4tc_extern *e;
+	int ret;
+
+	inst = p4tc_ext_inst_get_byids(net, &pipeline, params->pipe_id,
+				       &pipe_ext, params->ext_id,
+				       params->inst_id);
+	if (IS_ERR(inst))
+		return PTR_ERR(inst);
+
+	e = idr_find(&inst->inst_common->control_elems_idr, params->index);
+	if (!e)
+		return -ENOENT;
+
+	if (params->flags & P4TC_EXT_FLAGS_CONTROL_READ) {
+		ret = p4tc_extern_exec_read(e, res, params->index);
+	} else if (params->flags & P4TC_EXT_FLAGS_CONTROL_WRITE) {
+		ret = p4tc_extern_exec_write(e, params);
+	} else {
+		exec_params.data = (u8 *)params->in_params;
+		exec_params.method_id = params->method_id;
+		ret = inst->ops->exec(skb, inst->inst_common, e, &exec_params,
+				      res);
+	}
+
+	refcount_dec(&inst->inst_ref);
+	refcount_dec(&pipe_ext->ext_ref);
+	refcount_dec(&pipeline->p_ref);
+
+	return ret;
+}
+
+static int p4tc_extern_destroy(struct p4tc_extern *externs[], int init_res[])
+{
+	const struct p4tc_extern_ops *ops;
+	struct p4tc_extern *e;
+	int ret = 0, i;
+
+	for (i = 0; i < P4TC_MSGBATCH_SIZE && externs[i]; i++) {
+		e = externs[i];
+		externs[i] = NULL;
+		ops = e->ops;
+		if (init_res[i] == P4TC_EXT_P_CREATED) {
+			struct p4tc_extern_inst *inst = e->inst;
+
+			ret = __p4tc_ext_idr_release(e);
+			if (ret == ACT_P_DELETED) {
+				refcount_dec(&inst->curr_num_elems);
+				p4tc_extern_ops_put(ops);
+			} else if (ret < 0) {
+				return ret;
+			}
+		} else {
+			p4tc_extern_ops_put(ops);
+			free_p4tc_ext_rcu(&e->rcu);
+		}
+	}
+	return ret;
+}
+
+static int p4tc_extern_put(struct p4tc_extern *p)
+{
+	return __p4tc_extern_put(p);
+}
+
+/* Put all externs in this array, skip those NULL's. */
+static void p4tc_extern_put_many(struct p4tc_extern *externs[])
+{
+	int i;
+
+	for (i = 0; i < P4TC_MSGBATCH_SIZE; i++) {
+		struct p4tc_extern *e = externs[i];
+		const struct p4tc_extern_ops *ops;
+
+		if (!e)
+			continue;
+		ops = e->ops;
+		if (p4tc_extern_put(e))
+			p4tc_extern_ops_put(ops);
+	}
+}
+
+static int p4tc_extern_dump(struct sk_buff *skb, struct p4tc_extern *externs[],
+			    int ref)
+{
+	struct p4tc_extern *e;
+	int err = -EINVAL, i;
+	struct nlattr *nest;
+
+	for (i = 0; i < P4TC_MSGBATCH_SIZE && externs[i]; i++) {
+		e = externs[i];
+		nest = nla_nest_start_noflag(skb, i + 1);
+		if (!nest)
+			goto nla_put_failure;
+		err = p4tc_extern_dump_1(skb, e, ref);
+		if (err < 0)
+			goto errout;
+		nla_nest_end(skb, nest);
+	}
+
+	return 0;
+
+nla_put_failure:
+	err = -EINVAL;
+errout:
+	nla_nest_cancel(skb, nest);
+	return err;
+}
+
+static void generic_free_param_value(struct p4tc_extern_param *param)
+{
+	kfree(param->value);
+}
+
+static int generic_init_param_value(struct p4tc_extern_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_EXT_VALUE_PARAMS_MAX + 1];
+	void *value;
+	int err;
+
+	if (!tb[P4TC_EXT_PARAMS_VALUE]) {
+		NL_SET_ERR_MSG(extack, "Must specify param value");
+		return -EINVAL;
+	}
+
+	err = nla_parse_nested(tb_value, P4TC_EXT_VALUE_PARAMS_MAX,
+			       tb[P4TC_EXT_PARAMS_VALUE],
+			       p4tc_extern_params_value_policy, extack);
+	if (err < 0)
+		return err;
+
+	value = nla_data(tb_value[P4TC_EXT_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_EXT_PARAMS_VALUE_RAW]) != len)
+		return -EINVAL;
+
+	nparam->value = kzalloc(alloc_len, GFP_KERNEL);
+	if (!nparam->value)
+		return -ENOMEM;
+
+	memcpy(nparam->value, value, len);
+
+	return 0;
+}
+
+static const struct nla_policy p4tc_extern_policy[P4TC_EXT_MAX + 1] = {
+	[P4TC_EXT_KIND]		= { .type = NLA_STRING },
+	[P4TC_EXT_PARAMS]	= { .type = NLA_NESTED },
+	[P4TC_EXT_FLAGS]	= { .type = NLA_BITFIELD32 },
+	[P4TC_EXT_INST_NAME]	= {
+		.type = NLA_STRING,
+		.len = EXTERNINSTNAMSIZ
+	},
+};
+
+static const struct nla_policy p4tc_extern_params_policy[P4TC_EXT_PARAMS_MAX + 1] = {
+	[P4TC_EXT_PARAMS_NAME] = { .type = NLA_STRING, .len = EXTPARAMNAMSIZ },
+	[P4TC_EXT_PARAMS_ID] = { .type = NLA_U32 },
+	[P4TC_EXT_PARAMS_VALUE] = { .type = NLA_NESTED },
+	[P4TC_EXT_PARAMS_TYPE] = { .type = NLA_U32 },
+	[P4TC_EXT_PARAMS_BITSZ] = { .type = NLA_U16 },
+	[P4TC_EXT_PARAMS_FLAGS] = { .type = NLA_U8 },
+};
+
+static struct p4tc_extern_param *
+p4tc_ext_create_param(struct net *net, struct p4tc_extern_params *params,
+		      struct p4tc_extern_inst_common *inst_common,
+		      struct nlattr **tb, size_t *attrs_size,
+		      struct netlink_ext_ack *extack)
+{
+	struct idr *params_idr = &inst_common->control_params_idr;
+	u32 param_id = 0;
+	struct p4tc_extern_param *param, *nparam;
+	struct p4tc_extern_param_ops *op;
+	int err;
+
+	if (tb[P4TC_EXT_PARAMS_ID])
+		param_id = nla_get_u32(tb[P4TC_EXT_PARAMS_ID]);
+	*attrs_size += nla_total_size(sizeof(u32));
+
+	param = p4tc_extern_param_find_byanyattr(params_idr,
+						 tb[P4TC_EXT_PARAMS_NAME],
+						 param_id, extack);
+	if (IS_ERR(param))
+		return param;
+
+	if (tb[P4TC_EXT_PARAMS_TYPE]) {
+		u32 typeid = nla_get_u32(tb[P4TC_EXT_PARAMS_TYPE]);
+
+		if (param->type->typeid != typeid) {
+			NL_SET_ERR_MSG(extack,
+				       "Param type differs from template");
+			return ERR_PTR(-EINVAL);
+		}
+	} else {
+		NL_SET_ERR_MSG(extack, "Must specify param type");
+		return ERR_PTR(-EINVAL);
+	}
+	*attrs_size += nla_total_size(sizeof(u32));
+
+	nparam = kzalloc(sizeof(*nparam), GFP_KERNEL);
+	if (!nparam)
+		return ERR_PTR(-ENOMEM);
+
+	strscpy(nparam->name, param->name, EXTPARAMNAMSIZ);
+	nparam->type = param->type;
+
+	op = (struct p4tc_extern_param_ops *)&ext_param_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);
+	*attrs_size += nla_total_size(BITS_TO_BYTES(param->type->container_bitsz));
+
+	if (err < 0)
+		goto free;
+
+	nparam->id = param->id;
+
+	err = idr_alloc_u32(&params->params_idr, ERR_PTR(-EBUSY), &nparam->id,
+			    nparam->id, GFP_KERNEL);
+	if (err < 0)
+		goto free_val;
+
+	return nparam;
+
+free_val:
+	if (op->free)
+		op->free(nparam);
+	else
+		generic_free_param_value(nparam);
+
+free:
+	kfree(nparam);
+	return ERR_PTR(err);
+}
+
+static struct p4tc_extern_param *
+p4tc_ext_init_param(struct net *net, struct p4tc_extern_inst *inst,
+		    struct p4tc_extern_params *params, struct nlattr *nla,
+		    size_t *attrs_size, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_inst_common *inst_common = inst->inst_common;
+	struct nlattr *tb[P4TC_EXT_PARAMS_MAX + 1];
+	int err;
+
+	err = nla_parse_nested(tb, P4TC_EXT_PARAMS_MAX, nla,
+			       p4tc_extern_params_policy, extack);
+	if (err < 0)
+		return ERR_PTR(err);
+
+	return p4tc_ext_create_param(net, params, inst_common, tb, attrs_size,
+				     extack);
+}
+
+static int __p4tc_ext_get_key_param(struct p4tc_extern_inst *inst,
+				    struct nlattr *nla, u32 *key,
+				    struct netlink_ext_ack *extack)
+{
+	struct idr *params_idr = &inst->inst_common->control_params_idr;
+	struct nlattr *tb[P4TC_EXT_PARAMS_MAX + 1];
+	struct p4tc_extern_param *index_param;
+	int err;
+
+	err = nla_parse_nested(tb, P4TC_EXT_PARAMS_MAX, nla,
+			       p4tc_extern_params_policy, extack);
+	if (err < 0)
+		return err;
+
+	if (!tb[P4TC_EXT_PARAMS_NAME]) {
+		NL_SET_ERR_MSG(extack, "Must specify key param name");
+		return -EINVAL;
+	}
+
+	if (!tb[P4TC_EXT_PARAMS_VALUE]) {
+		NL_SET_ERR_MSG(extack, "Must specify key param value");
+		return -EINVAL;
+	}
+
+	index_param = p4tc_extern_param_find_byanyattr(params_idr,
+						       tb[P4TC_EXT_PARAMS_NAME],
+						       0, extack);
+	if (IS_ERR(index_param)) {
+		NL_SET_ERR_MSG(extack, "Key param name not found");
+		return -EINVAL;
+	}
+
+	if (index_param->flags & P4TC_EXT_PARAMS_FLAG_ISKEY) {
+		struct nlattr *tb2[P4TC_EXT_VALUE_PARAMS_MAX];
+		u32 *value;
+		int err;
+
+		err = nla_parse_nested(tb2, P4TC_EXT_VALUE_PARAMS_MAX,
+				       tb[P4TC_EXT_PARAMS_VALUE], NULL, extack);
+		if (err < 0)
+			return err;
+
+		if (!tb2[P4TC_EXT_PARAMS_VALUE_RAW]) {
+			NL_SET_ERR_MSG(extack, "Must specify raw value attr");
+			return -EINVAL;
+		}
+
+		if (nla_len(tb2[P4TC_EXT_PARAMS_VALUE_RAW]) > sizeof(*key)) {
+			NL_SET_ERR_MSG(extack,
+				       "Param value is bigger than 64 bits");
+			return -EINVAL;
+		}
+
+		value = nla_data(tb2[P4TC_EXT_PARAMS_VALUE_RAW]);
+
+		*key = *value;
+
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+static int p4tc_ext_get_key_param(struct p4tc_extern_inst *inst,
+				  struct nlattr *nla, u32 *key,
+				  struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1] = {NULL};
+	int err = -EINVAL;
+	int i;
+
+	err = nla_parse_nested(tb, P4TC_MSGBATCH_SIZE, nla, NULL, extack);
+	if (!tb[1]) {
+		NL_SET_ERR_MSG(extack, "Must specify at least one parameter");
+		return -EINVAL;
+	}
+
+	for (i = 1; i < P4TC_MSGBATCH_SIZE + 1 && tb[i]; i++) {
+		err = __p4tc_ext_get_key_param(inst, tb[i], key, extack);
+		if (!err)
+			return err;
+	}
+
+	return err;
+}
+
+static int p4tc_ext_init_params(struct net *net, struct p4tc_extern_inst *inst,
+				struct p4tc_extern_params **params,
+				struct nlattr *nla, size_t *attrs_size,
+				struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_param *params_array[P4TC_MSGBATCH_SIZE] = { NULL };
+	struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1];
+	int err;
+	int i;
+
+	if (!*params) {
+		*params = kzalloc(sizeof(*(*params)), GFP_KERNEL);
+		if (!*params)
+			return -ENOMEM;
+
+		idr_init(&((*params)->params_idr));
+		spin_lock_init(&((*params)->params_lock));
+	}
+
+	err = nla_parse_nested(tb, P4TC_MSGBATCH_SIZE, nla, NULL, extack);
+	if (err < 0) {
+		kfree(*params);
+		*params = NULL;
+		return err;
+	}
+
+	for (i = 1; i < P4TC_MSGBATCH_SIZE + 1 && tb[i]; i++) {
+		struct p4tc_extern_param *param;
+
+		param = p4tc_ext_init_param(net, inst, *params, tb[i],
+					    attrs_size, extack);
+		if (IS_ERR(param)) {
+			err = PTR_ERR(param);
+			goto params_del;
+		}
+		params_array[i - 1] = param;
+		*attrs_size = nla_total_size(0);  /* params array element nested */
+	}
+
+	p4tc_ext_insert_many_params(&((*params)->params_idr), params_array,
+				    i - 1);
+	return 0;
+
+params_del:
+	p4tc_ext_put_many_params(&((*params)->params_idr), params_array, i - 1);
+	kfree(*params);
+	*params = NULL;
+	return err;
+}
+
+static void p4tc_ext_idr_insert_many(struct p4tc_extern *externs[])
+{
+	int i;
+
+	for (i = 0; i < P4TC_MSGBATCH_SIZE; i++) {
+		struct p4tc_extern *e = externs[i];
+
+		if (!e)
+			continue;
+		/* Replace ERR_PTR(-EBUSY) allocated by p4tc_ext_idr_check_alloc
+		 * if it is just created. If it's updated, free previous extern.
+		 */
+		e = idr_replace(e->elems_idr, e, e->p4tc_ext_key);
+		if (e != ERR_PTR(-EBUSY))
+			call_rcu(&e->rcu, free_p4tc_ext_rcu);
+	}
+}
+
+static struct p4tc_extern_ops *
+p4tc_ext_load_ops(struct net *net, struct nlattr *nla,
+		  struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[P4TC_EXT_MAX + 1];
+	struct p4tc_extern_ops *a_o;
+	char ext_name[EXTERNNAMSIZ];
+	struct nlattr *kind;
+	int err;
+
+	err = nla_parse_nested_deprecated(tb, P4TC_EXT_MAX, nla,
+					  p4tc_extern_policy, extack);
+	if (err < 0)
+		return ERR_PTR(err);
+	err = -EINVAL;
+	kind = tb[P4TC_EXT_KIND];
+	if (!kind) {
+		NL_SET_ERR_MSG(extack, "TC extern must be specified");
+		return ERR_PTR(err);
+	}
+	if (nla_strscpy(ext_name, kind, EXTERNNAMSIZ) < 0) {
+		NL_SET_ERR_MSG(extack, "TC extern name too long");
+		return ERR_PTR(err);
+	}
+
+	a_o = p4tc_extern_ops_get(ext_name);
+	if (!a_o) {
+#ifdef CONFIG_MODULES
+		rtnl_unlock();
+		request_module("ext_%s", ext_name);
+		rtnl_lock();
+
+		a_o = p4tc_extern_ops_get(ext_name);
+
+		/* We dropped the RTNL semaphore in order to
+		 * perform the module load.  So, even if we
+		 * succeeded in loading the module we have to
+		 * tell the caller to replay the request.  We
+		 * indicate this using -EAGAIN.
+		 */
+		if (a_o) {
+			p4tc_extern_ops_put(a_o);
+			return ERR_PTR(-EAGAIN);
+		}
+#endif
+		NL_SET_ERR_MSG(extack, "Failed to load TC extern module");
+		return ERR_PTR(-ENOENT);
+	}
+
+	return a_o;
+}
+
+static int p4tc_ext_init(struct net *net, struct nlattr **tb,
+			 struct p4tc_extern **e,
+			 struct p4tc_extern_inst *inst,
+			 u32 flags, size_t *attrs_size,
+			 struct netlink_ext_ack *extack)
+{
+	const struct p4tc_extern_ops *e_o = inst->ops;
+	struct p4tc_extern_params *params = NULL;
+	struct p4tc_extern *e_orig = NULL;
+	bool exists = false;
+	int ret = 0, err;
+	u32 key;
+
+	if (tb[P4TC_EXT_PARAMS]) {
+		err = p4tc_ext_get_key_param(inst, tb[P4TC_EXT_PARAMS], &key,
+					     extack);
+	} else {
+		NL_SET_ERR_MSG(extack, "Must specify extern params");
+		return -EINVAL;
+	}
+
+	if (err < 0) {
+		if (err == -ENOENT)
+			NL_SET_ERR_MSG(extack, "Unable to find key param");
+		return err;
+	}
+
+	err = p4tc_ext_idr_check_alloc(inst, &key, &e_orig);
+	if (err < 0)
+		return err;
+
+	exists = err;
+
+	if (!exists) {
+		err = p4tc_ext_idr_create(inst, key, e, e_o, flags);
+		if (err < 0) {
+			p4tc_ext_idr_cleanup(inst->inst_common, key);
+			return err;
+		}
+
+		ret = P4TC_EXT_P_CREATED;
+	} else {
+		err = p4tc_ext_copy(inst, key, e, e_orig, e_o, flags);
+		if (err < 0)
+			return err;
+
+		if (!(flags & P4TC_EXT_FLAGS_REPLACE)) {
+			err = -EEXIST;
+			goto release_idr;
+		}
+	}
+
+	err = p4tc_ext_init_params(net, inst, &params, tb[P4TC_EXT_PARAMS],
+				   attrs_size, extack);
+	if (err < 0)
+		goto release_idr;
+	*attrs_size = nla_total_size(0);  /* P4TC_EXT_PARAMS nested */
+
+	(*e)->params = params;
+
+	return ret;
+
+release_idr:
+	p4tc_ext_idr_release(*e);
+	return err;
+}
+
+static struct p4tc_extern_inst *
+__p4tc_ext_inst_find_bynames(struct net *net, struct p4tc_pipeline *pipeline,
+			     const char *modextname, const char *instname,
+			     struct netlink_ext_ack *extack)
+{
+	const char *extname = &modextname[4];
+
+	return p4tc_ext_inst_find_bynames(net, pipeline, extname, instname,
+					  extack);
+}
+
+static struct p4tc_extern *
+p4tc_extern_init_1(struct net *net, struct p4tc_pipeline *pipeline,
+		   struct nlattr *nla, struct p4tc_extern_ops *a_o,
+		   int *init_res, u32 flags, size_t *attrs_size,
+		   struct netlink_ext_ack *extack)
+{
+	struct nla_bitfield32 userflags = { 0, 0 };
+	struct nlattr *tb[P4TC_EXT_MAX + 1];
+	struct p4tc_extern_inst *inst;
+	struct p4tc_extern *e;
+	char *instname;
+	int err;
+
+	err = nla_parse_nested_deprecated(tb, P4TC_EXT_MAX, nla,
+					  p4tc_extern_policy, extack);
+	if (err < 0)
+		return ERR_PTR(err);
+	if (tb[P4TC_EXT_FLAGS])
+		userflags = nla_get_bitfield32(tb[P4TC_EXT_FLAGS]);
+
+	if (!tb[P4TC_EXT_INST_NAME]) {
+		NL_SET_ERR_MSG(extack,
+			       "TC extern inst name must be specified");
+		return ERR_PTR(-EINVAL);
+	}
+	instname = nla_data(tb[P4TC_EXT_INST_NAME]);
+
+	inst = __p4tc_ext_inst_find_bynames(net, pipeline, a_o->kind, instname,
+					    extack);
+	if (IS_ERR(inst))
+		return (void *)inst;
+
+	inst->ops = a_o;
+
+	err = p4tc_ext_init(net, tb, &e, inst, userflags.value | flags,
+			    attrs_size, extack);
+	*init_res = err;
+
+	if (err < 0)
+		return ERR_PTR(err);
+
+	return e;
+}
+
+/* Returns numbers of initialized externs or negative error. */
+static int p4tc_extern_init(struct net *net, struct p4tc_pipeline *pipeline,
+			    struct nlattr *nla, struct p4tc_extern *externs[],
+			    int init_res[], size_t *attrs_size, u32 flags,
+			    struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_ops *ops[P4TC_MSGBATCH_SIZE] = {};
+	struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1];
+	struct p4tc_extern *ext;
+	size_t sz = 0;
+	int err;
+	int i;
+
+	err = nla_parse_nested_deprecated(tb, P4TC_MSGBATCH_SIZE, nla, NULL,
+					  extack);
+	if (err < 0)
+		return err;
+
+	for (i = 1; i <= P4TC_MSGBATCH_SIZE && tb[i]; i++) {
+		struct p4tc_extern_ops *a_o;
+
+		a_o = p4tc_ext_load_ops(net, tb[i], extack);
+		if (IS_ERR(a_o)) {
+			err = PTR_ERR(a_o);
+			goto err_mod;
+		}
+		ops[i - 1] = a_o;
+	}
+
+	for (i = 1; i <= P4TC_MSGBATCH_SIZE && tb[i]; i++) {
+		size_t attrs_size_before = *attrs_size;
+		size_t extern_fill_size;
+
+		ext = p4tc_extern_init_1(net, pipeline, tb[i], ops[i - 1],
+					 &init_res[i - 1], flags, attrs_size,
+					 extack);
+		if (IS_ERR(ext)) {
+			err = PTR_ERR(ext);
+			goto err;
+		}
+		extern_fill_size = p4tc_extern_fill_size(ext);
+		ext->attrs_size = *attrs_size - attrs_size_before + extern_fill_size;
+		sz += extern_fill_size;
+		/* Start from key 0 */
+		externs[i - 1] = ext;
+	}
+
+	/* We have to commit them all together, because if any error happened in
+	 * between, we could not handle the failure gracefully.
+	 */
+	p4tc_ext_idr_insert_many(externs);
+
+	*attrs_size = p4tc_extern_full_attrs_size(sz);
+	err = i - 1;
+	goto err_mod;
+
+err:
+	p4tc_extern_destroy(externs, init_res);
+err_mod:
+	for (i = 0; i < P4TC_MSGBATCH_SIZE; i++) {
+		if (ops[i])
+			p4tc_extern_ops_put(ops[i]);
+	}
+	return err;
+}
+
+static int tce_get_fill(struct sk_buff *skb, struct p4tc_extern *externs[],
+			u32 portid, u32 seq, u16 flags, u32 pipeid, int cmd,
+			int ref, struct netlink_ext_ack *extack)
+{
+	unsigned char *b = skb_tail_pointer(skb);
+	struct nlmsghdr *nlh;
+	struct nlattr *nest;
+	struct p4tcmsg *t;
+
+	nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*t), flags);
+	if (!nlh)
+		goto out_nlmsg_trim;
+	t = nlmsg_data(nlh);
+	t->pipeid = pipeid;
+	t->obj = P4TC_OBJ_RUNTIME_EXTERN;
+
+	nest = nla_nest_start(skb, P4TC_ROOT);
+	if (p4tc_extern_dump(skb, externs, ref) < 0)
+		goto out_nlmsg_trim;
+
+	nla_nest_end(skb, nest);
+
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
+
+	return skb->len;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static int
+p4tc_extern_get_respond(struct net *net, u32 portid, struct nlmsghdr *n,
+			struct p4tc_extern *externs[], u32 pipeid, int cmd,
+			size_t attr_size, struct netlink_ext_ack *extack)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(attr_size <= NLMSG_GOODSIZE ? NLMSG_GOODSIZE : attr_size,
+			GFP_KERNEL);
+	if (!skb)
+		return -ENOBUFS;
+	if (tce_get_fill(skb, externs, portid, n->nlmsg_seq, 0, pipeid, cmd,
+			 1, NULL) <= 0) {
+		NL_SET_ERR_MSG(extack,
+			       "Failed to fill netlink attributes while adding TC extern");
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	return rtnl_unicast(skb, net, portid);
+}
+
+static struct p4tc_extern *
+p4tc_extern_get_1(struct net *net, struct p4tc_pipeline *pipeline,
+		  struct nlattr *nla, struct nlmsghdr *n, u32 portid,
+		  struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[P4TC_EXT_MAX + 1];
+	const struct p4tc_extern_ops *ops;
+	struct p4tc_extern_inst *inst;
+	char *kind, *instname;
+	struct p4tc_extern *e;
+	u32 key;
+	int err;
+
+	err = nla_parse_nested_deprecated(tb, P4TC_EXT_MAX, nla,
+					  p4tc_extern_policy, extack);
+	if (err < 0)
+		goto err_out;
+
+	if (!tb[P4TC_EXT_KIND]) {
+		NL_SET_ERR_MSG(extack,
+			       "TC extern inst name must be specified");
+		err = -EINVAL;
+		goto err_out;
+	}
+	kind = nla_data(tb[P4TC_EXT_KIND]);
+
+	if (!tb[P4TC_EXT_INST_NAME]) {
+		NL_SET_ERR_MSG(extack,
+			       "TC extern inst name must be specified");
+		return ERR_PTR(-EINVAL);
+	}
+	instname = nla_data(tb[P4TC_EXT_INST_NAME]);
+
+	err = -EINVAL;
+	ops = p4tc_extern_ops_get(kind);
+	if (!ops) { /* could happen in batch of externs */
+		NL_SET_ERR_MSG(extack, "Specified TC extern kind not found");
+		goto err_out;
+	}
+
+	inst = __p4tc_ext_inst_find_bynames(net, pipeline, ops->kind, instname,
+					    extack);
+	if (IS_ERR(inst)) {
+		err = PTR_ERR(inst);
+		goto err_mod;
+	}
+	if (tb[P4TC_EXT_PARAMS]) {
+		err = p4tc_ext_get_key_param(inst, tb[P4TC_EXT_PARAMS], &key,
+					     extack);
+		if (err < 0)
+			goto err_mod;
+	} else {
+		/* Assume key 1 when none is specified */
+		key = 1;
+	}
+
+	if (__p4tc_ext_idr_search(inst, &e, key) == 0) {
+		err = -ENOENT;
+		NL_SET_ERR_MSG(extack, "TC extern with specified key not found");
+		goto err_mod;
+	}
+
+	p4tc_extern_ops_put(ops);
+	return e;
+
+err_mod:
+	p4tc_extern_ops_put(ops);
+err_out:
+	return ERR_PTR(err);
+}
+
+static int p4tc_extern_flush(struct net *net, struct p4tc_pipeline *pipeline,
+			     struct nlattr *nla, struct nlmsghdr *n,
+			     u32 portid, struct netlink_ext_ack *extack)
+{
+	int err = -ENOMEM;
+	struct nlattr *tb[P4TC_EXT_MAX + 1];
+	const struct p4tc_extern_ops *ops;
+	struct p4tc_extern_inst *inst;
+	struct netlink_callback dcb;
+	char *kind, *instname;
+	struct nlmsghdr *nlh;
+	struct sk_buff *skb;
+	struct nlattr *nest;
+	struct p4tcmsg *t;
+	unsigned char *b;
+
+	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!skb)
+		return err;
+
+	b = skb_tail_pointer(skb);
+
+	err = nla_parse_nested_deprecated(tb, P4TC_EXT_MAX, nla,
+					  p4tc_extern_policy, extack);
+	if (err < 0)
+		goto err_out;
+
+	err = -EINVAL;
+	if (!tb[P4TC_EXT_KIND]) {
+		NL_SET_ERR_MSG(extack,
+			       "TC extern name must be specified");
+		err = -EINVAL;
+		goto err_out;
+	}
+	kind = nla_data(tb[P4TC_EXT_KIND]);
+
+	ops = p4tc_extern_ops_get(kind);
+	if (!ops) { /*some idjot trying to flush unknown extern */
+		NL_SET_ERR_MSG(extack, "Cannot flush unknown TC extern");
+		goto err_out;
+	}
+
+	if (!tb[P4TC_EXT_INST_NAME]) {
+		NL_SET_ERR_MSG(extack,
+			       "TC extern inst name must be specified");
+		err = -EINVAL;
+		goto out_ops_put;
+	}
+	instname = nla_data(tb[P4TC_EXT_INST_NAME]);
+
+	inst = __p4tc_ext_inst_find_bynames(net, pipeline, ops->kind, instname,
+					    extack);
+	if (IS_ERR(inst)) {
+		err = PTR_ERR(inst);
+		goto out_ops_put;
+	}
+
+	nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_P4TC_DEL,
+			sizeof(*t), 0);
+	if (!nlh) {
+		NL_SET_ERR_MSG(extack, "Failed to create TC extern flush notification");
+		goto out_ops_put;
+	}
+	t = nlmsg_data(nlh);
+	t->obj = P4TC_OBJ_RUNTIME_EXTERN;
+	t->pipeid = pipeline->common.p_id;
+
+	nest = nla_nest_start_noflag(skb, P4TC_ROOT);
+	if (!nest) {
+		NL_SET_ERR_MSG(extack, "Failed to add new netlink message");
+		goto out_ops_put;
+	}
+
+	err = __p4tc_ext_generic_walker(skb, &dcb, RTM_P4TC_DEL, inst, ops,
+					extack);
+	if (err <= 0) {
+		nla_nest_cancel(skb, nest);
+		goto out_ops_put;
+	}
+
+	nla_nest_end(skb, nest);
+
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
+	nlh->nlmsg_flags |= NLM_F_ROOT;
+	p4tc_extern_ops_put(ops);
+	err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
+			     n->nlmsg_flags & NLM_F_ECHO);
+	if (err < 0)
+		NL_SET_ERR_MSG(extack, "Failed to send TC extern flush notification");
+
+	return err;
+
+out_ops_put:
+	p4tc_extern_ops_put(ops);
+err_out:
+	kfree_skb(skb);
+	return err;
+}
+
+static int p4tc_extern_delete(struct net *net, struct p4tc_extern *externs[])
+{
+	int i;
+
+	for (i = 0; i < P4TC_MSGBATCH_SIZE && externs[i]; i++) {
+		struct p4tc_extern *e = externs[i];
+		const struct p4tc_extern_ops *ops = e->ops;
+		u32 ext_key = e->p4tc_ext_key;
+		/* Actions can be deleted concurrently so we must save their
+		 * type and id to search again after reference is released.
+		 */
+		struct idr *elems_idr = e->elems_idr;
+
+		externs[i] = NULL;
+		if (p4tc_extern_put(e)) {
+			/* last reference, extern was deleted concurrently */
+			p4tc_extern_ops_put(ops);
+		} else  {
+			int ret;
+
+			/* now do the delete */
+			ret = p4tc_ext_idr_delete_key(elems_idr, ext_key);
+			if (ret < 0)
+				return ret;
+		}
+	}
+	return 0;
+}
+
+static int
+p4tc_extern_del_notify(struct net *net, struct nlmsghdr *n,
+		       struct p4tc_extern *externs[], u32 portid, u32 pipeid,
+		       size_t attr_size, struct netlink_ext_ack *extack)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	skb = alloc_skb(attr_size <= NLMSG_GOODSIZE ? NLMSG_GOODSIZE : attr_size,
+			GFP_KERNEL);
+	if (!skb)
+		return -ENOBUFS;
+
+	if (tce_get_fill(skb, externs, portid, n->nlmsg_seq, 0, pipeid,
+			 RTM_P4TC_DEL, 2, extack) <= 0) {
+		NL_SET_ERR_MSG(extack,
+			       "Failed to fill netlink TC extern attributes");
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	/* now do the delete */
+	ret = p4tc_extern_delete(net, externs);
+	if (ret < 0) {
+		NL_SET_ERR_MSG(extack, "Failed to delete TC extern");
+		kfree_skb(skb);
+		return ret;
+	}
+
+	ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
+			     n->nlmsg_flags & NLM_F_ECHO);
+	return ret;
+}
+
+static int
+p4tc_extern_gd(struct net *net, struct p4tc_pipeline *pipeline,
+	       struct nlattr *nla, struct nlmsghdr *n,
+	       u32 portid, int cmd, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern *externs[P4TC_MSGBATCH_SIZE] = {};
+	size_t attr_size = 0;
+	struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1];
+	struct p4tc_extern *ext;
+	u32 pipeid;
+	int i, ret;
+
+	ret = nla_parse_nested_deprecated(tb, P4TC_MSGBATCH_SIZE, nla, NULL,
+					  extack);
+	if (ret < 0)
+		return ret;
+
+	if (cmd == RTM_P4TC_DEL && n->nlmsg_flags & NLM_F_ROOT) {
+		if (tb[1])
+			return p4tc_extern_flush(net, pipeline, tb[1], n,
+						 portid, extack);
+
+		NL_SET_ERR_MSG(extack,
+			       "Invalid netlink attributes while flushing TC extern");
+		return -EINVAL;
+	}
+
+	for (i = 1; i <= P4TC_MSGBATCH_SIZE && tb[i]; i++) {
+		ext = p4tc_extern_get_1(net, pipeline, tb[i], n, portid,
+					extack);
+		if (IS_ERR(ext)) {
+			ret = PTR_ERR(ext);
+			goto err;
+		}
+		attr_size += ext->attrs_size;
+		externs[i - 1] = ext;
+	}
+
+	attr_size = p4tc_extern_full_attrs_size(attr_size);
+
+	pipeid = pipeline->common.p_id;
+	if (cmd == RTM_P4TC_GET) {
+		ret = p4tc_extern_get_respond(net, portid, n, externs, pipeid,
+					      cmd, attr_size, extack);
+	} else { /* delete */
+		ret = p4tc_extern_del_notify(net, n, externs, portid, pipeid,
+					     attr_size, extack);
+		if (ret)
+			goto err;
+		return 0;
+	}
+err:
+	p4tc_extern_put_many(externs);
+	return ret;
+}
+
+static int
+p4tc_extern_add_notify(struct net *net, struct nlmsghdr *n,
+		       struct p4tc_extern *externs[], u32 portid, u32 pipeid,
+		       size_t attr_size, struct netlink_ext_ack *extack)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(attr_size <= NLMSG_GOODSIZE ? NLMSG_GOODSIZE : attr_size,
+			GFP_KERNEL);
+	if (!skb)
+		return -ENOBUFS;
+
+	if (tce_get_fill(skb, externs, portid, n->nlmsg_seq, n->nlmsg_flags,
+			 pipeid, RTM_P4TC_CREATE, 0, extack) <= 0) {
+		NL_SET_ERR_MSG(extack,
+			       "Failed to fill netlink attributes while adding TC extern");
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
+			      n->nlmsg_flags & NLM_F_ECHO);
+}
+
+static int p4tc_extern_add(struct net *net, struct p4tc_pipeline *pipeline,
+			   struct nlattr *nla, struct nlmsghdr *n, u32 portid,
+			   u32 flags, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern *externs[P4TC_MSGBATCH_SIZE] = {};
+	int init_res[P4TC_MSGBATCH_SIZE] = {};
+	size_t attr_size = 0;
+	int loop, ret, i;
+	u32 pipeid;
+
+	for (loop = 0; loop < 10; loop++) {
+		ret = p4tc_extern_init(net, pipeline, nla, externs,
+				       init_res, &attr_size, flags, extack);
+		if (ret != -EAGAIN)
+			break;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	pipeid = pipeline->common.p_id;
+	ret = p4tc_extern_add_notify(net, n, externs, portid, pipeid, attr_size,
+				     extack);
+
+	/* only put existing externs */
+	for (i = 0; i < P4TC_MSGBATCH_SIZE; i++)
+		if (init_res[i] == P4TC_EXT_P_CREATED)
+			externs[i] = NULL;
+	p4tc_extern_put_many(externs);
+
+	return ret;
+}
+
+static int parse_dump_ext_attrs(struct nlattr *nla,
+				struct nlattr **tb2)
+{
+	struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1];
+
+	if (nla_parse_nested_deprecated(tb, P4TC_MSGBATCH_SIZE, nla, NULL,
+					NULL) < 0)
+		return -EINVAL;
+
+	if (!tb[1])
+		return -EINVAL;
+	if (nla_parse_nested_deprecated(tb2, P4TC_EXT_MAX, tb[1],
+					p4tc_extern_policy, NULL) < 0)
+		return -EINVAL;
+
+	if (!tb2[P4TC_EXT_KIND])
+		return -EINVAL;
+
+	if (!tb2[P4TC_EXT_INST_NAME])
+		return -EINVAL;
+
+	return 0;
+}
+
+int p4tc_ctl_extern_dump(struct sk_buff *skb, struct netlink_callback *cb,
+			 struct nlattr **tb, const char *pname)
+{
+	struct netlink_ext_ack *extack = cb->extack;
+	unsigned char *b = skb_tail_pointer(skb);
+	struct net *net = sock_net(skb->sk);
+	struct nlattr *count_attr = NULL;
+	struct nla_bitfield32 bf;
+	u32 ext_count = 0;
+	int ret = 0;
+	struct nlattr *tb2[P4TC_EXT_MAX + 1];
+	struct p4tc_pipeline *pipeline;
+	struct p4tc_extern_inst *inst;
+	struct p4tc_extern_ops *a_o;
+	char *kind_str, *instname;
+	struct nlmsghdr *nlh;
+	struct nlattr *nest;
+	struct p4tcmsg *t;
+
+	pipeline = tcf_pipeline_find_byany(net, pname, 0, extack);
+	if (IS_ERR(pipeline))
+		return PTR_ERR(pipeline);
+
+	if (!pipeline_sealed(pipeline)) {
+		NL_SET_ERR_MSG(extack,
+			       "Pipeline must be sealed for extern runtime ops");
+		return -EINVAL;
+	}
+
+	ret = parse_dump_ext_attrs(tb[P4TC_ROOT], tb2);
+	if (ret < 0)
+		return ret;
+
+	kind_str = nla_data(tb2[P4TC_EXT_KIND]);
+
+	a_o = p4tc_extern_ops_get(kind_str);
+	if (!a_o)
+		return 0;
+
+	instname = nla_data(tb2[P4TC_EXT_INST_NAME]);
+
+	inst = __p4tc_ext_inst_find_bynames(net, pipeline, a_o->kind, instname,
+					    extack);
+	if (IS_ERR(inst))
+		return PTR_ERR(inst);
+
+	cb->args[2] = 0;
+	if (tb[P4TC_ROOT_FLAGS]) {
+		bf = nla_get_bitfield32(tb[P4TC_ROOT_FLAGS]);
+		cb->args[2] = bf.value;
+	}
+
+	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
+			cb->nlh->nlmsg_type, sizeof(*t), 0);
+	if (!nlh)
+		goto out_ops_put;
+
+	t = nlmsg_data(nlh);
+	t->pipeid = pipeline->common.p_id;
+	t->obj = P4TC_OBJ_RUNTIME_EXTERN;
+	count_attr = nla_reserve(skb, P4TC_ROOT_COUNT, sizeof(u32));
+	if (!count_attr)
+		goto out_ops_put;
+
+	nest = nla_nest_start_noflag(skb, P4TC_ROOT);
+	if (!nest)
+		goto out_ops_put;
+
+	ret = __p4tc_ext_generic_walker(skb, cb, RTM_P4TC_GET, inst, a_o, NULL);
+	if (ret < 0)
+		goto out_ops_put;
+
+	if (ret > 0) {
+		nla_nest_end(skb, nest);
+		ret = skb->len;
+		ext_count = cb->args[1];
+		memcpy(nla_data(count_attr), &ext_count, sizeof(u32));
+		cb->args[1] = 0;
+	} else {
+		nlmsg_trim(skb, b);
+	}
+
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
+	if (NETLINK_CB(cb->skb).portid && ret)
+		nlh->nlmsg_flags |= NLM_F_MULTI;
+	p4tc_extern_ops_put(a_o);
+	return skb->len;
+
+out_ops_put:
+	p4tc_extern_ops_put(a_o);
+	nlmsg_trim(skb, b);
+	return skb->len;
+}
+
+int p4tc_ctl_extern(struct sk_buff *skb, struct nlmsghdr *n, const char *pname,
+		    struct nlattr *nla, struct netlink_ext_ack *extack)
+{
+	struct net *net = sock_net(skb->sk);
+	u32 portid = NETLINK_CB(skb).portid;
+	u32 flags = 0;
+	int ret = 0;
+	struct p4tc_pipeline *pipeline;
+
+	if (n->nlmsg_type != RTM_P4TC_GET &&
+	    !netlink_capable(skb, CAP_NET_ADMIN))
+		return -EPERM;
+
+	pipeline = tcf_pipeline_find_byany(net, pname, 0, extack);
+	if (IS_ERR(pipeline))
+		return PTR_ERR(pipeline);
+
+	if (!pipeline_sealed(pipeline)) {
+		NL_SET_ERR_MSG(extack,
+			       "Pipeline must be sealed for extern runtime ops");
+		return -EINVAL;
+	}
+
+	/* n->nlmsg_flags & NLM_F_CREATE */
+	switch (n->nlmsg_type) {
+	case RTM_P4TC_CREATE:
+		/* we are going to assume all other flags
+		 * imply create only if it doesn't exist
+		 * Note that CREATE | EXCL implies that
+		 * but since we want avoid ambiguity (eg when flags
+		 * is zero) then just set this
+		 */
+		if (n->nlmsg_flags & NLM_F_REPLACE)
+			flags |= P4TC_EXT_FLAGS_REPLACE;
+		ret = p4tc_extern_add(net, pipeline, nla, n, portid, flags,
+				      extack);
+		break;
+	case RTM_P4TC_DEL:
+		ret = p4tc_extern_gd(net, pipeline, nla, n, portid,
+				     RTM_P4TC_DEL, extack);
+		break;
+	case RTM_P4TC_GET:
+		ret = p4tc_extern_gd(net, pipeline, nla, n, portid,
+				     RTM_P4TC_GET, extack);
+		break;
+	default:
+		WARN_ON_ONCE("Unknown extern command");
+	}
+
+	return ret;
+}
diff --git a/net/sched/p4tc/p4tc_pipeline.c b/net/sched/p4tc/p4tc_pipeline.c
index b36035840..04dc2746b 100644
--- a/net/sched/p4tc/p4tc_pipeline.c
+++ b/net/sched/p4tc/p4tc_pipeline.c
@@ -100,6 +100,7 @@ static void __net_exit pipeline_exit_net(struct net *net)
 		tcf_pipeline_put(net, &pipeline->common, true, NULL);
 	}
 	idr_destroy(&pipe_net->pipeline_idr);
+
 	rtnl_unlock();
 }
 
@@ -121,6 +122,7 @@ static void tcf_pipeline_destroy(struct p4tc_pipeline *pipeline,
 {
 	idr_destroy(&pipeline->p_act_idr);
 	idr_destroy(&pipeline->p_tbl_idr);
+	idr_destroy(&pipeline->user_ext_idr);
 
 	if (free_pipeline)
 		kfree(pipeline);
@@ -146,7 +148,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);
-	unsigned long iter_act_id, tmp;
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	unsigned long iter_act_id, ext_id, tmp;
 	struct p4tc_table *table;
 	struct p4tc_act *act;
 	unsigned long tbl_id;
@@ -171,6 +174,17 @@ static int tcf_pipeline_put(struct net *net,
 	idr_for_each_entry_ul(&pipeline->p_act_idr, act, tmp, iter_act_id)
 		act->common.ops->put(net, &act->common, true, extack);
 
+	idr_for_each_entry_ul(&pipeline->user_ext_idr, pipe_ext, tmp, ext_id) {
+		unsigned long tmp_in, inst_id;
+		struct p4tc_extern_inst *inst;
+
+		idr_for_each_entry_ul(&pipe_ext->e_inst_idr, inst, tmp_in, inst_id) {
+			inst->common.ops->put(net, &inst->common, true, extack);
+		}
+
+		pipe_ext->free(pipe_ext, &pipeline->user_ext_idr);
+	}
+
 	if (pipeline->parser)
 		tcf_parser_del(net, pipeline, pipeline->parser, extack);
 
@@ -304,6 +318,9 @@ static struct p4tc_pipeline *tcf_pipeline_create(struct net *net,
 
 	idr_init(&pipeline->p_tbl_idr);
 	pipeline->curr_tables = 0;
+	idr_init(&pipeline->p_tbl_idr);
+
+	idr_init(&pipeline->user_ext_idr);
 
 	pipeline->num_created_acts = 0;
 
@@ -642,6 +659,8 @@ static void __tcf_pipeline_init(void)
 
 	strscpy(root_pipeline->common.name, "kernel", PIPELINENAMSIZ);
 
+	idr_init(&root_pipeline->p_ext_idr);
+
 	root_pipeline->common.ops =
 		(struct p4tc_template_ops *)&p4tc_pipeline_ops;
 
diff --git a/net/sched/p4tc/p4tc_runtime_api.c b/net/sched/p4tc/p4tc_runtime_api.c
index a4050096b..d44f7722a 100644
--- a/net/sched/p4tc/p4tc_runtime_api.c
+++ b/net/sched/p4tc/p4tc_runtime_api.c
@@ -27,6 +27,7 @@
 #include <net/p4tc.h>
 #include <net/netlink.h>
 #include <net/flow_offload.h>
+#include <net/p4tc_ext_api.h>
 
 static int tc_ctl_p4_root(struct sk_buff *skb, struct nlmsghdr *n, int cmd,
 			  struct netlink_ext_ack *extack)
@@ -53,6 +54,11 @@ static int tc_ctl_p4_root(struct sk_buff *skb, struct nlmsghdr *n, int cmd,
 	case P4TC_OBJ_RUNTIME_TABLE:
 		return p4tc_ctl_table_n(skb, n, cmd, p_name, tb[P4TC_ROOT],
 					extack);
+	case P4TC_OBJ_RUNTIME_EXTERN:
+		rtnl_lock();
+		ret = p4tc_ctl_extern(skb, n, p_name, tb[P4TC_ROOT], extack);
+		rtnl_unlock();
+		return ret;
 	default:
 		NL_SET_ERR_MSG(extack, "Unknown P4 runtime object type");
 		return -EOPNOTSUPP;
@@ -113,6 +119,8 @@ static int tc_ctl_p4_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	switch (t->obj) {
 	case P4TC_OBJ_RUNTIME_TABLE:
 		return p4tc_ctl_dump_1(skb, cb, tb[P4TC_ROOT], p_name);
+	case P4TC_OBJ_RUNTIME_EXTERN:
+		return p4tc_ctl_extern_dump(skb, cb, tb, p_name);
 	default:
 		NL_SET_ERR_MSG_FMT(cb->extack,
 				   "Unknown p4 runtime object type %u\n",
diff --git a/net/sched/p4tc/p4tc_tmpl_api.c b/net/sched/p4tc/p4tc_tmpl_api.c
index 71d7b2a78..338f5f161 100644
--- a/net/sched/p4tc/p4tc_tmpl_api.c
+++ b/net/sched/p4tc/p4tc_tmpl_api.c
@@ -45,6 +45,8 @@ static bool obj_is_valid(u32 obj)
 	case P4TC_OBJ_HDR_FIELD:
 	case P4TC_OBJ_ACT:
 	case P4TC_OBJ_TABLE:
+	case P4TC_OBJ_EXT:
+	case P4TC_OBJ_EXT_INST:
 		return true;
 	default:
 		return false;
@@ -56,6 +58,8 @@ 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_EXT] = &p4tc_tmpl_ext_ops,
+	[P4TC_OBJ_EXT_INST] = &p4tc_tmpl_ext_inst_ops,
 };
 
 int tcf_p4_tmpl_generic_dump(struct sk_buff *skb, struct p4tc_dump_ctx *ctx,
diff --git a/net/sched/p4tc/p4tc_tmpl_ext.c b/net/sched/p4tc/p4tc_tmpl_ext.c
new file mode 100644
index 000000000..692133cc1
--- /dev/null
+++ b/net/sched/p4tc/p4tc_tmpl_ext.c
@@ -0,0 +1,2256 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * net/sched/p4tc_tmpl_extern.c	P4 TC EXTERN TEMPLATE
+ *
+ * Copyright (c) 2022-2023, Mojatatu Networks
+ * Copyright (c) 2022-2023, Intel Corporation.
+ * Authors:     Jamal Hadi Salim <jhs@mojatatu.com>
+ *              Victor Nogueira <victor@mojatatu.com>
+ *              Pedro Tammela <pctammela@mojatatu.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <net/pkt_cls.h>
+#include <net/p4tc.h>
+#include <net/netlink.h>
+#include <net/p4tc_types.h>
+#include <net/sock.h>
+#include <net/p4tc_ext_api.h>
+
+static LIST_HEAD(ext_base);
+static DEFINE_RWLOCK(ext_mod_lock);
+
+static const struct nla_policy tc_extern_inst_policy[P4TC_TMPL_EXT_INST_MAX + 1] = {
+	[P4TC_TMPL_EXT_INST_EXT_NAME] = {
+		.type = NLA_STRING,
+		.len =  EXTERNNAMSIZ
+	},
+	[P4TC_TMPL_EXT_INST_NAME] = {
+		.type = NLA_STRING,
+		.len =  EXTERNINSTNAMSIZ
+	},
+	[P4TC_TMPL_EXT_INST_NUM_ELEMS] = NLA_POLICY_RANGE(NLA_U32, 1,
+							  P4TC_MAX_NUM_EXT_INST_ELEMS),
+	[P4TC_TMPL_EXT_INST_METHODS] = { .type = NLA_NESTED },
+	[P4TC_TMPL_EXT_INST_CONTROL_PARAMS] = { .type = NLA_NESTED }
+};
+
+static const struct nla_policy tc_extern_policy[P4TC_TMPL_EXT_MAX + 1] = {
+	[P4TC_TMPL_EXT_NAME] = { .type = NLA_STRING, .len =  EXTERNNAMSIZ },
+	[P4TC_TMPL_EXT_NUM_INSTS] = NLA_POLICY_RANGE(NLA_U16, 1,
+						     P4TC_MAX_NUM_EXT_INSTS),
+};
+
+static void p4tc_extern_put_param(struct p4tc_extern_param *param)
+{
+	if (param->mask_shift)
+		p4t_release(param->mask_shift);
+	kfree(param);
+}
+
+static void p4tc_extern_put_method(struct p4tc_extern_method *method)
+{
+	struct p4tc_extern_param *param;
+	unsigned long tmp, id;
+
+	idr_for_each_entry_ul(&method->params_idr, param, tmp, id) {
+		idr_remove(&method->params_idr, id);
+		p4tc_extern_put_param(param);
+	}
+	idr_destroy(&method->params_idr);
+	kfree(method);
+}
+
+static void
+p4tc_user_pipeline_ext_free(struct p4tc_user_pipeline_extern *pipe_ext,
+			    struct idr *tmpl_exts_idr)
+{
+	idr_remove(tmpl_exts_idr, pipe_ext->ext_id);
+	idr_destroy(&pipe_ext->e_inst_idr);
+	refcount_dec(&pipe_ext->tmpl_ext->tmpl_ref);
+	kfree(pipe_ext);
+}
+
+static void
+p4tc_user_pipeline_ext_put(struct p4tc_pipeline *pipeline,
+			   struct p4tc_user_pipeline_extern *pipe_ext,
+			   bool release, struct idr *tmpl_exts_idr)
+{
+	if (refcount_dec_and_test(&pipe_ext->ext_ref) && release)
+		p4tc_user_pipeline_ext_free(pipe_ext, tmpl_exts_idr);
+}
+
+static void
+_p4tc_tmpl_ext_inst_common_put(struct p4tc_extern_inst_common *common)
+{
+	struct p4tc_extern_method *method;
+	struct p4tc_extern_param *param;
+	unsigned long tmp, id;
+
+	p4tc_ext_purge(&common->control_elems_idr);
+
+	idr_for_each_entry_ul(&common->methods_idr, method, tmp, id) {
+		idr_remove(&common->methods_idr, id);
+		p4tc_extern_put_method(method);
+	}
+
+	idr_for_each_entry_ul(&common->control_params_idr, param, tmp, id) {
+		idr_remove(&common->control_params_idr, id);
+		p4tc_extern_put_param(param);
+	}
+
+	kfree(common);
+}
+
+static int _p4tc_tmpl_ext_inst_put(struct p4tc_pipeline *pipeline,
+				   struct p4tc_user_pipeline_extern *pipe_ext,
+				   struct p4tc_extern_inst *inst,
+				   bool unconditional_purge, bool release,
+				   struct netlink_ext_ack *extack)
+{
+	if (!unconditional_purge && !refcount_dec_if_one(&inst->inst_ref)) {
+		NL_SET_ERR_MSG(extack,
+			       "Can't delete referenced extern instance template");
+		return -EBUSY;
+	}
+
+	_p4tc_tmpl_ext_inst_common_put(inst->inst_common);
+
+	idr_remove(&pipe_ext->e_inst_idr, inst->ext_inst_id);
+	refcount_dec(&pipe_ext->curr_insts_num);
+
+	p4tc_user_pipeline_ext_put(pipeline, pipe_ext, release,
+				   &pipeline->user_ext_idr);
+
+	kfree(inst);
+
+	return 0;
+}
+
+static int _p4tc_tmpl_ext_put(struct p4tc_pipeline *pipeline,
+			      struct p4tc_tmpl_extern *ext,
+			      bool unconditional_purge,
+			      struct netlink_ext_ack *extack)
+{
+	if (!unconditional_purge && !refcount_dec_if_one(&ext->tmpl_ref)) {
+		NL_SET_ERR_MSG(extack,
+			       "Can't delete referenced extern template");
+		return -EBUSY;
+	}
+
+	idr_remove(&pipeline->p_ext_idr, ext->ext_id);
+	p4tc_extern_ops_put(ext->ops);
+
+	kfree(ext);
+
+	return 0;
+}
+
+static int p4tc_tmpl_ext_put(struct net *net, struct p4tc_template_common *tmpl,
+			     bool unconditional_purge,
+			     struct netlink_ext_ack *extack)
+{
+	struct p4tc_pipeline *pipeline;
+	struct p4tc_tmpl_extern *ext;
+
+	pipeline = tcf_pipeline_find_byid(net, P4TC_KERNEL_PIPEID);
+
+	ext = to_extern(tmpl);
+
+	return _p4tc_tmpl_ext_put(pipeline, ext, unconditional_purge, extack);
+}
+
+static int p4tc_tmpl_ext_inst_put(struct net *net,
+				  struct p4tc_template_common *tmpl,
+				  bool unconditional_purge,
+				  struct netlink_ext_ack *extack)
+{
+	struct p4tc_pipeline *pipeline;
+	struct p4tc_extern_inst *inst;
+
+	inst = to_extern_inst(tmpl);
+
+	pipeline = tcf_pipeline_find_byid(net, inst->common.p_id);
+
+	return _p4tc_tmpl_ext_inst_put(pipeline, inst->pipe_ext, inst,
+				       unconditional_purge,
+				       !unconditional_purge, extack);
+}
+
+static struct p4tc_tmpl_extern *
+p4tc_tmpl_ext_find_name(struct p4tc_pipeline *pipeline, const char *extern_name)
+{
+	struct p4tc_tmpl_extern *ext;
+	unsigned long tmp, id;
+
+	idr_for_each_entry_ul(&pipeline->p_ext_idr, ext, tmp, id)
+		if (ext->common.name[0] &&
+		    strncmp(ext->common.name, extern_name,
+			    EXTERNNAMSIZ) == 0)
+			return ext;
+
+	return NULL;
+}
+
+static struct p4tc_tmpl_extern *
+p4tc_tmpl_ext_find_byid(struct p4tc_pipeline *pipeline, const u32 ext_id)
+{
+	return idr_find(&pipeline->p_ext_idr, ext_id);
+}
+
+struct p4tc_tmpl_extern *
+p4tc_tmpl_ext_find_byany(struct p4tc_pipeline *pipeline,
+			 const char *extern_name, u32 ext_id,
+			 struct netlink_ext_ack *extack)
+{
+	struct p4tc_tmpl_extern *ext;
+	int err;
+
+	if (ext_id) {
+		ext = p4tc_tmpl_ext_find_byid(pipeline, ext_id);
+		if (!ext) {
+			NL_SET_ERR_MSG(extack, "Unable to find ext by id");
+			err = -EINVAL;
+			goto out;
+		}
+	} else {
+		if (extern_name) {
+			ext = p4tc_tmpl_ext_find_name(pipeline, extern_name);
+			if (!ext) {
+				NL_SET_ERR_MSG(extack,
+					       "Extern name not found");
+				err = -EINVAL;
+				goto out;
+			}
+		} else {
+			NL_SET_ERR_MSG(extack,
+				       "Must specify ext name or id");
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
+	return ext;
+
+out:
+	return ERR_PTR(err);
+}
+
+static struct p4tc_extern_inst *
+p4tc_ext_inst_find_byid(struct p4tc_user_pipeline_extern *pipe_ext,
+			const u32 inst_id)
+{
+	struct p4tc_extern_inst *ext_inst;
+
+	ext_inst = idr_find(&pipe_ext->e_inst_idr, inst_id);
+
+	return ext_inst;
+}
+
+static struct p4tc_extern_inst *
+p4tc_ext_inst_find_byname(struct p4tc_user_pipeline_extern *pipe_ext,
+			  const char *instname)
+{
+	struct p4tc_extern_inst *ext_inst;
+	unsigned long tmp, inst_id;
+
+	idr_for_each_entry_ul(&pipe_ext->e_inst_idr, ext_inst, tmp, inst_id) {
+		if (strncmp(ext_inst->common.name, instname, EXTERNINSTNAMSIZ) == 0)
+			return ext_inst;
+	}
+
+	return NULL;
+}
+
+static struct p4tc_extern_inst *
+p4tc_ext_inst_find_byany(struct p4tc_user_pipeline_extern *pipe_ext,
+			 const char *instname, u32 instid,
+			 struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_inst *inst;
+	int err;
+
+	if (instid) {
+		inst = p4tc_ext_inst_find_byid(pipe_ext, instid);
+		if (!inst) {
+			NL_SET_ERR_MSG(extack, "Unable to find instance by id");
+			err = -EINVAL;
+			goto out;
+		}
+	} else {
+		if (instname) {
+			inst = p4tc_ext_inst_find_byname(pipe_ext, instname);
+			if (!inst) {
+				NL_SET_ERR_MSG_FMT(extack,
+						   "Instance name not found %s\n",
+						   instname);
+				err = -EINVAL;
+				goto out;
+			}
+		} else {
+			NL_SET_ERR_MSG(extack,
+				       "Must specify instance name or id");
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
+	return inst;
+
+out:
+	return ERR_PTR(err);
+}
+
+static struct p4tc_extern_inst *
+p4tc_ext_inst_find_byanyattr(struct p4tc_user_pipeline_extern *pipe_ext,
+			     struct nlattr *name_attr, u32 instid,
+			     struct netlink_ext_ack *extack)
+{
+	char *instname = NULL;
+
+	if (name_attr)
+		instname = nla_data(name_attr);
+
+	return p4tc_ext_inst_find_byany(pipe_ext, instname, instid,
+					extack);
+}
+
+static void p4tc_extern_put_many_params(struct idr *params_idr,
+					struct p4tc_extern_param *params[],
+					bool remove_from_idr,
+					int params_count)
+{
+	int i;
+
+	for (i = 0; i < params_count; i++) {
+		if (remove_from_idr)
+			idr_remove(params_idr, params[i]->id);
+		p4tc_extern_put_param(params[i]);
+	}
+}
+
+static void p4tc_extern_put_many_methods(struct idr *methods_idr,
+					 struct p4tc_extern_method *methods[],
+					 bool remove_from_idr,
+					 int methods_count)
+{
+	int i;
+
+	for (i = 0; i < methods_count; i++) {
+		if (remove_from_idr)
+			idr_remove(methods_idr, methods[i]->method_id);
+		p4tc_extern_put_method(methods[i]);
+	}
+}
+
+static struct p4tc_extern_param *
+p4tc_extern_param_find_byname(struct idr *params_idr, const char *param_name)
+{
+	struct p4tc_extern_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, EXTPARAMNAMSIZ) == 0)
+			return param;
+	}
+
+	return NULL;
+}
+
+struct p4tc_extern_param *
+p4tc_extern_param_find_byid(struct idr *params_idr, const u32 param_id)
+{
+	return idr_find(params_idr, param_id);
+}
+EXPORT_SYMBOL(p4tc_extern_param_find_byid);
+
+static struct p4tc_extern_param *
+p4tc_extern_param_find_byany(struct idr *params_idr, const char *param_name,
+			     const u32 param_id, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_param *param;
+	int err;
+
+	if (param_id) {
+		param = p4tc_extern_param_find_byid(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 = p4tc_extern_param_find_byname(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);
+}
+
+struct p4tc_extern_param *
+p4tc_extern_param_find_byanyattr(struct idr *params_idr,
+				 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 p4tc_extern_param_find_byany(params_idr, param_name, param_id,
+					    extack);
+}
+
+static void p4tc_extern_params_replace_many(struct idr *params_idr,
+					    struct p4tc_extern_param *params[],
+					    int params_count)
+{
+	int i;
+
+	for (i = 0; i < params_count; i++) {
+		struct p4tc_extern_param *param;
+
+		param = idr_replace(params_idr, params[i], params[i]->id);
+		if (param != ERR_PTR(-EBUSY))
+			p4tc_extern_put_param(param);
+	}
+}
+
+static struct p4tc_extern_param *
+p4tc_extern_create_param(struct idr *params_idr, struct nlattr **tb,
+			 u32 param_id, struct netlink_ext_ack *extack)
+{
+	u8 *flags = NULL;
+	struct p4tc_extern_param *param;
+	char *name;
+	int ret;
+
+	if (tb[P4TC_EXT_PARAMS_NAME]) {
+		name = nla_data(tb[P4TC_EXT_PARAMS_NAME]);
+	} else {
+		NL_SET_ERR_MSG(extack, "Must specify param name");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	param = kzalloc(sizeof(*param), GFP_KERNEL);
+	if (!param) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if ((param_id && p4tc_extern_param_find_byid(params_idr, param_id)) ||
+	    p4tc_extern_param_find_byname(params_idr, name)) {
+		NL_SET_ERR_MSG_FMT(extack, "Param already exists %s", name);
+		ret = -EEXIST;
+		goto free;
+	}
+
+	if ((tb[P4TC_EXT_PARAMS_TYPE] && !tb[P4TC_EXT_PARAMS_BITSZ]) ||
+	    (!tb[P4TC_EXT_PARAMS_TYPE] && tb[P4TC_EXT_PARAMS_BITSZ])) {
+		NL_SET_ERR_MSG(extack, "Must specify type with bit size");
+		ret = -EINVAL;
+		goto free;
+	}
+
+	if (tb[P4TC_EXT_PARAMS_TYPE]) {
+		struct p4tc_type_mask_shift *mask_shift = NULL;
+		struct p4tc_type *type;
+		u32 typeid;
+		u16 bitsz;
+
+		typeid = nla_get_u32(tb[P4TC_EXT_PARAMS_TYPE]);
+		bitsz = nla_get_u16(tb[P4TC_EXT_PARAMS_BITSZ]);
+
+		type = p4type_find_byid(typeid);
+		if (!type) {
+			NL_SET_ERR_MSG(extack, "Param type is invalid");
+			ret = -EINVAL;
+			goto free;
+		}
+		param->type = type;
+		if (bitsz > param->type->bitsz) {
+			NL_SET_ERR_MSG(extack, "Bit size is bigger than type");
+			ret = -EINVAL;
+			goto free;
+		}
+		if (type->ops->create_bitops) {
+			mask_shift = type->ops->create_bitops(bitsz, 0,
+							      bitsz - 1,
+							      extack);
+			if (IS_ERR(mask_shift)) {
+				ret = PTR_ERR(mask_shift);
+				goto free;
+			}
+		}
+		param->mask_shift = mask_shift;
+	} else {
+		NL_SET_ERR_MSG(extack, "Must specify param type");
+		ret = -EINVAL;
+		goto free;
+	}
+
+	if (tb[P4TC_EXT_PARAMS_FLAGS]) {
+		flags = nla_data(tb[P4TC_EXT_PARAMS_FLAGS]);
+		param->flags = *flags;
+	}
+
+	if (flags && (*flags & P4TC_EXT_PARAMS_FLAG_ISKEY)) {
+		switch (param->type->typeid) {
+		case P4T_U8:
+		case P4T_U16:
+		case P4T_U32:
+			break;
+		default: {
+			NL_SET_ERR_MSG(extack,
+				       "Key must be an unsigned integer");
+			ret = -EINVAL;
+			goto free_mask_shift;
+		}
+		}
+	}
+
+	if (param_id) {
+		ret = idr_alloc_u32(params_idr, ERR_PTR(-EBUSY), &param_id,
+				    param_id, GFP_KERNEL);
+		if (ret < 0) {
+			NL_SET_ERR_MSG(extack, "Unable to allocate param id");
+			goto free_mask_shift;
+		}
+		param->id = param_id;
+	} else {
+		param->id = 1;
+
+		ret = idr_alloc_u32(params_idr, ERR_PTR(-EBUSY), &param->id,
+				    UINT_MAX, GFP_KERNEL);
+		if (ret < 0) {
+			NL_SET_ERR_MSG(extack, "Unable to allocate param id");
+			goto free_mask_shift;
+		}
+	}
+
+	strscpy(param->name, name, EXTPARAMNAMSIZ);
+
+	return param;
+
+free_mask_shift:
+	kfree(param->mask_shift);
+
+free:
+	kfree(param);
+
+out:
+	return ERR_PTR(ret);
+}
+
+static struct p4tc_extern_param *
+p4tc_extern_update_param(struct idr *params_idr, struct nlattr **tb,
+			 const u32 param_id, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_param *param_old, *param;
+	int ret;
+
+	param_old = p4tc_extern_param_find_byanyattr(params_idr,
+						     tb[P4TC_EXT_PARAMS_NAME],
+						     param_id, extack);
+	if (IS_ERR(param_old))
+		return param_old;
+
+	param = kzalloc(sizeof(*param), GFP_KERNEL);
+	if (!param) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	strscpy(param->name, param_old->name, EXTPARAMNAMSIZ);
+	param->id = param_old->id;
+
+	if (tb[P4TC_EXT_PARAMS_TYPE]) {
+		u32 typeid;
+
+		typeid = nla_get_u32(tb[P4TC_EXT_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_old->flags & P4TC_EXT_PARAMS_FLAG_ISKEY) {
+		switch (param->type->typeid) {
+		case P4T_U8:
+		case P4T_U16:
+		case P4T_U32:
+			break;
+		default: {
+			NL_SET_ERR_MSG(extack,
+				       "Key must be an unsigned integer");
+			ret = -EINVAL;
+			goto free;
+		}
+		}
+	}
+
+	return param;
+
+free:
+	kfree(param);
+out:
+	return ERR_PTR(ret);
+}
+
+static struct p4tc_extern_param *
+p4tc_extern_init_param(struct idr *params_idr, struct nlattr *nla,
+		       bool update, struct netlink_ext_ack *extack)
+{
+	u32 param_id = 0;
+	struct nlattr *tb[P4TC_EXT_PARAMS_MAX + 1];
+	int ret;
+
+	ret = nla_parse_nested(tb, P4TC_EXT_PARAMS_MAX, nla, NULL, extack);
+	if (ret < 0) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (tb[P4TC_EXT_PARAMS_ID])
+		param_id = nla_get_u32(tb[P4TC_EXT_PARAMS_ID]);
+
+	if (update)
+		return p4tc_extern_update_param(params_idr, tb, param_id,
+						extack);
+	else
+		return p4tc_extern_create_param(params_idr, tb, param_id,
+						extack);
+
+out:
+	return ERR_PTR(ret);
+}
+
+static int p4tc_extern_init_params(struct idr *params_idr, struct nlattr *nla,
+				   struct p4tc_extern_param *params[],
+				   bool update, struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[P4TC_MSGBATCH_SIZE + 1];
+	bool has_key_param = false;
+	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_extern_param *param;
+
+		param = p4tc_extern_init_param(params_idr, tb[i], update,
+					       extack);
+		if (IS_ERR(param)) {
+			ret = PTR_ERR(param);
+			goto params_del;
+		}
+		params[i - 1] = param;
+		if (has_key_param) {
+			if (param->flags & P4TC_EXT_PARAMS_FLAGS) {
+				NL_SET_ERR_MSG(extack,
+					       "There can't be 2 key params");
+				goto params_del;
+			}
+		} else {
+			has_key_param = param->flags & P4TC_EXT_PARAMS_FLAGS;
+		}
+	}
+
+	return i - 1;
+
+params_del:
+	p4tc_extern_put_many_params(params_idr, params, !update, i - 1);
+	return ret;
+}
+
+static void
+p4tc_extern_methods_replace_many(struct idr *methods_idr,
+				 struct p4tc_extern_method *methods[],
+				 int methods_count)
+{
+	int i;
+
+	for (i = 0; i < methods_count; i++) {
+		struct p4tc_extern_method *method = methods[i];
+
+		method = idr_replace(methods_idr, method, method->method_id);
+		if (method != ERR_PTR(-EBUSY))
+			p4tc_extern_put_method(method);
+	}
+}
+
+static struct p4tc_extern_method *
+method_find_byid(struct idr *methods_idr, const u32 method_id)
+{
+	return idr_find(methods_idr, method_id);
+}
+
+static struct p4tc_extern_method *
+method_find_byname(struct idr *methods_idr, const char *method_name)
+{
+	struct p4tc_extern_method *method;
+	unsigned long tmp, id;
+
+	idr_for_each_entry_ul(methods_idr, method, tmp, id) {
+		if (method == ERR_PTR(-EBUSY))
+			continue;
+		if (strncmp(method->method_name, method_name,
+			    METHODNAMSIZ) == 0)
+			return method;
+	}
+
+	return NULL;
+}
+
+static struct p4tc_extern_method *
+method_find_byany(struct idr *methods_idr, const char *method_name,
+		  const u32 method_id, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_method *method;
+	int err;
+
+	if (method_id) {
+		method = method_find_byid(methods_idr, method_id);
+		if (!method) {
+			NL_SET_ERR_MSG(extack, "Unable to find method by id");
+			err = -EINVAL;
+			goto out;
+		}
+	} else {
+		if (method_name) {
+			method = method_find_byname(methods_idr, method_name);
+			if (!method) {
+				NL_SET_ERR_MSG(extack,
+					       "Method name not found");
+				err = -EINVAL;
+				goto out;
+			}
+		} else {
+			NL_SET_ERR_MSG(extack,
+				       "Must specify method name or id");
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
+	return method;
+
+out:
+	return ERR_PTR(err);
+}
+
+static struct p4tc_extern_method *
+p4tc_extern_create_method(struct idr *methods_idr, struct nlattr **tb,
+			  u32 method_id, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_param *params[P4TC_MSGBATCH_SIZE] = { NULL };
+	struct p4tc_extern_method *method;
+	int num_params;
+	char *name;
+	int ret;
+
+	if (tb[P4TC_TMPL_EXT_INST_METHOD_NAME]) {
+		name = nla_data(tb[P4TC_TMPL_EXT_INST_METHOD_NAME]);
+	} else {
+		NL_SET_ERR_MSG(extack, "Must specify method name");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	method = kzalloc(sizeof(*method), GFP_KERNEL);
+	if (!method) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (method_find_byid(methods_idr, method_id) ||
+	    (method_find_byname(methods_idr, name))) {
+		NL_SET_ERR_MSG(extack, "Method already exists");
+		ret = -EEXIST;
+		goto free_method;
+	}
+
+	idr_init(&method->params_idr);
+	if (method_id) {
+		ret = idr_alloc_u32(methods_idr, ERR_PTR(-EBUSY), &method_id,
+				    method_id, GFP_KERNEL);
+		if (ret < 0) {
+			NL_SET_ERR_MSG(extack, "Unable to allocate method id");
+			goto free_method;
+		}
+		method->method_id = method_id;
+	} else {
+		method->method_id = 1;
+
+		ret = idr_alloc_u32(methods_idr, ERR_PTR(-EBUSY),
+				    &method->method_id, UINT_MAX, GFP_KERNEL);
+		if (ret < 0) {
+			NL_SET_ERR_MSG(extack, "Unable to allocate method id");
+			goto free_method;
+		}
+	}
+
+	if (tb[P4TC_TMPL_EXT_INST_METHOD_PARAMS]) {
+		num_params = p4tc_extern_init_params(&method->params_idr,
+						     tb[P4TC_TMPL_EXT_INST_METHOD_PARAMS],
+						     params, false, extack);
+		if (num_params < 0) {
+			ret = num_params;
+			goto idr_rm;
+		}
+	} else {
+		NL_SET_ERR_MSG(extack, "Must specify method name");
+		ret = -EINVAL;
+		goto free_method;
+	}
+
+	strscpy(method->method_name, name, METHODNAMSIZ);
+	p4tc_extern_params_replace_many(&method->params_idr, params,
+					num_params);
+
+	return method;
+
+idr_rm:
+	idr_remove(methods_idr, method->method_id);
+
+free_method:
+	kfree(method);
+
+out:
+	return ERR_PTR(ret);
+}
+
+static struct p4tc_extern_method *
+p4tc_extern_update_method(struct idr *methods_idr, struct nlattr **tb,
+			  u32 method_id, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_param *params[P4TC_MSGBATCH_SIZE] = { NULL };
+	struct p4tc_extern_method *method_old, *method;
+	char *method_name;
+	int num_params;
+	int ret;
+
+	if (tb[P4TC_TMPL_EXT_INST_METHOD_NAME]) {
+		method_name = nla_data(tb[P4TC_TMPL_EXT_INST_METHOD_NAME]);
+	} else {
+		NL_SET_ERR_MSG(extack, "Must specify method name");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	method_old = method_find_byany(methods_idr, method_name, method_id,
+				       extack);
+	if (IS_ERR(method_old))
+		return method_old;
+
+	method = kzalloc(sizeof(*method), GFP_KERNEL);
+	if (!method) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	strscpy(method->method_name, method_old->method_name, METHODNAMSIZ);
+	method->method_id = method_old->method_id;
+
+	idr_init(&method->params_idr);
+	if (tb[P4TC_TMPL_EXT_INST_METHOD_PARAMS]) {
+		num_params = p4tc_extern_init_params(&method->params_idr,
+						     tb[P4TC_TMPL_EXT_INST_METHOD_PARAMS],
+						     params, false, extack);
+		if (num_params < 0) {
+			ret = num_params;
+			goto free_method;
+		}
+	} else {
+		NL_SET_ERR_MSG(extack, "Must specify method name");
+		ret = -EINVAL;
+		goto free_method;
+	}
+
+	p4tc_extern_params_replace_many(&method->params_idr, params,
+					num_params);
+
+	return method;
+
+free_method:
+	kfree(method);
+
+out:
+	return ERR_PTR(ret);
+}
+
+static struct p4tc_extern_method *
+p4tc_extern_init_method(struct idr *methods_idr, struct nlattr *nla,
+			bool update, struct netlink_ext_ack *extack)
+{
+	u32 method_id = 0;
+	struct nlattr *tb[P4TC_TMPL_EXT_INST_METHOD_MAX + 1];
+	int ret;
+
+	ret = nla_parse_nested(tb, P4TC_TMPL_EXT_INST_METHOD_MAX, nla, NULL,
+			       extack);
+	if (ret < 0) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (tb[P4TC_TMPL_EXT_INST_METHOD_ID])
+		method_id = nla_get_u32(tb[P4TC_TMPL_EXT_INST_METHOD_ID]);
+
+	if (update)
+		return p4tc_extern_update_method(methods_idr, tb, method_id,
+						extack);
+	else
+		return p4tc_extern_create_method(methods_idr, tb, method_id,
+						 extack);
+
+out:
+	return ERR_PTR(ret);
+}
+
+static int p4tc_extern_init_methods(struct idr *methods_idr,
+				    struct p4tc_extern_method **methods,
+				    struct nlattr *nla, 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_extern_method *method;
+
+		method = p4tc_extern_init_method(methods_idr, tb[i], update,
+						 extack);
+		if (IS_ERR(method)) {
+			ret = PTR_ERR(method);
+			goto methods_del;
+		}
+		methods[i - 1] = method;
+	}
+
+	return i - 1;
+
+methods_del:
+	p4tc_extern_put_many_methods(methods_idr, methods, !update, i - 1);
+	return ret;
+}
+
+static struct p4tc_tmpl_extern *
+p4tc_tmpl_ext_find_byanyattr(struct p4tc_pipeline *pipeline,
+			     struct nlattr *name_attr, u32 ext_id,
+			     struct netlink_ext_ack *extack)
+{
+	char *extern_name = NULL;
+
+	if (name_attr)
+		extern_name = nla_data(name_attr);
+
+	return p4tc_tmpl_ext_find_byany(pipeline, extern_name, ext_id,
+				       extack);
+}
+
+static struct p4tc_extern_ops *p4tc_extern_lookup_n(char *kind)
+{
+	struct p4tc_extern_ops *a = NULL;
+
+	read_lock(&ext_mod_lock);
+	list_for_each_entry(a, &ext_base, head) {
+		if (strcmp(kind, a->kind) == 0) {
+			read_unlock(&ext_mod_lock);
+			return a;
+		}
+	}
+	read_unlock(&ext_mod_lock);
+
+	return NULL;
+}
+
+/* lookup by name */
+struct p4tc_extern_ops *p4tc_extern_ops_get(char *kind)
+{
+	char prepended_kind[EXTERNNAMSIZ] = {0};
+	struct p4tc_extern_ops *a = NULL;
+	int num_bytes_written;
+
+	if (!kind)
+		return NULL;
+
+	num_bytes_written = snprintf(prepended_kind, EXTERNNAMSIZ, "ext_%s",
+				     kind);
+	/* Extern name was too long */
+	if (num_bytes_written == EXTERNNAMSIZ)
+		return NULL;
+
+	a = p4tc_extern_lookup_n(prepended_kind);
+	if (a) {
+		if (try_module_get(a->owner))
+			return a;
+	}
+
+	return a;
+}
+
+void p4tc_extern_ops_put(const struct p4tc_extern_ops *ops)
+{
+	module_put(ops->owner);
+}
+
+int p4tc_register_extern(struct p4tc_extern_ops *ext)
+{
+	if (p4tc_extern_lookup_n(ext->kind))
+		return -EEXIST;
+
+	write_lock(&ext_mod_lock);
+	list_add_tail(&ext->head, &ext_base);
+	write_unlock(&ext_mod_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(p4tc_register_extern);
+
+int p4tc_unregister_extern(struct p4tc_extern_ops *ext)
+{
+	struct p4tc_extern_ops *a;
+	int err = -ENOENT;
+
+	write_lock(&ext_mod_lock);
+	list_for_each_entry(a, &ext_base, head) {
+		if (a == ext) {
+			list_del(&ext->head);
+			err = 0;
+			break;
+		}
+	}
+	write_unlock(&ext_mod_lock);
+	return err;
+}
+EXPORT_SYMBOL(p4tc_unregister_extern);
+
+static struct p4tc_user_pipeline_extern *
+p4tc_user_pipeline_ext_find_byid(struct p4tc_pipeline *pipeline,
+				 const u32 ext_id)
+{
+	struct p4tc_user_pipeline_extern *pipe_ext;
+
+	pipe_ext = idr_find(&pipeline->user_ext_idr, ext_id);
+
+	return pipe_ext;
+}
+
+static struct p4tc_user_pipeline_extern *
+p4tc_user_pipeline_ext_find_byname(struct p4tc_pipeline *pipeline,
+				   const char *extname)
+{
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	unsigned long tmp, ext_id;
+
+	idr_for_each_entry_ul(&pipeline->user_ext_idr, pipe_ext, tmp, ext_id) {
+		if (strncmp(pipe_ext->ext_name, extname, EXTERNNAMSIZ) == 0)
+			return pipe_ext;
+	}
+
+	return NULL;
+}
+
+static struct p4tc_user_pipeline_extern *
+p4tc_user_pipeline_ext_find_byany(struct p4tc_pipeline *pipeline,
+				  const char *extname, u32 ext_id,
+				  struct netlink_ext_ack *extack)
+{
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	int err;
+
+	if (ext_id) {
+		pipe_ext = p4tc_user_pipeline_ext_find_byid(pipeline, ext_id);
+		if (!pipe_ext) {
+			NL_SET_ERR_MSG(extack, "Unable to find extern");
+			err = -EINVAL;
+			goto out;
+		}
+	} else {
+		if (extname) {
+			pipe_ext = p4tc_user_pipeline_ext_find_byname(pipeline,
+								      extname);
+			if (!pipe_ext) {
+				NL_SET_ERR_MSG(extack,
+					       "Extern name not found");
+				err = -EINVAL;
+				goto out;
+			}
+		} else {
+			NL_SET_ERR_MSG(extack,
+				       "Must specify extern name or id");
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
+	return pipe_ext;
+
+out:
+	return ERR_PTR(err);
+}
+
+static struct p4tc_user_pipeline_extern *
+p4tc_user_pipeline_ext_find_byanyattr(struct p4tc_pipeline *pipeline,
+				      struct nlattr *name_attr, u32 ext_id,
+				      struct netlink_ext_ack *extack)
+{
+	char *extname = NULL;
+
+	if (name_attr)
+		extname = nla_data(name_attr);
+
+	return p4tc_user_pipeline_ext_find_byany(pipeline, extname, ext_id,
+						 extack);
+}
+
+static inline bool
+p4tc_user_pipeline_insts_exceeded(struct p4tc_user_pipeline_extern *pipe_ext)
+{
+	const u32 max_num_insts = pipe_ext->tmpl_ext->max_num_insts;
+
+	if (refcount_read(&pipe_ext->curr_insts_num) - 1 == max_num_insts)
+		return true;
+
+	return false;
+}
+
+static struct p4tc_user_pipeline_extern *
+p4tc_user_pipeline_ext_find_or_create(struct p4tc_pipeline *pipeline,
+				      struct p4tc_tmpl_extern *tmpl_ext,
+				      bool *allocated_pipe_ext,
+				      struct netlink_ext_ack *extack)
+{
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	int err;
+
+	pipe_ext = p4tc_user_pipeline_ext_find_byid(pipeline, tmpl_ext->ext_id);
+	if (pipe_ext) {
+		bool exceeded_max_insts;
+
+		exceeded_max_insts = p4tc_user_pipeline_insts_exceeded(pipe_ext);
+		if (exceeded_max_insts) {
+			NL_SET_ERR_MSG(extack,
+				       "Maximum number of instances exceeded");
+			return ERR_PTR(-EINVAL);
+		}
+
+		refcount_inc(&pipe_ext->ext_ref);
+		refcount_inc(&pipe_ext->curr_insts_num);
+		return pipe_ext;
+	}
+
+	pipe_ext = kzalloc(sizeof(*pipe_ext), GFP_KERNEL);
+	if (!pipe_ext)
+		return ERR_PTR(-ENOMEM);
+	pipe_ext->ext_id = tmpl_ext->ext_id;
+	err = idr_alloc_u32(&pipeline->user_ext_idr, pipe_ext,
+			    &pipe_ext->ext_id, pipe_ext->ext_id, GFP_KERNEL);
+	if (err < 0)
+		goto free_pipe_ext;
+
+	strscpy(pipe_ext->ext_name, tmpl_ext->common.name, EXTERNNAMSIZ);
+	idr_init(&pipe_ext->e_inst_idr);
+	refcount_set(&pipe_ext->ext_ref, 1);
+	refcount_set(&pipe_ext->curr_insts_num, 1);
+	refcount_inc(&tmpl_ext->tmpl_ref);
+	pipe_ext->tmpl_ext = tmpl_ext;
+	pipe_ext->free = p4tc_user_pipeline_ext_free;
+
+	*allocated_pipe_ext = true;
+
+	return pipe_ext;
+
+free_pipe_ext:
+	kfree(pipe_ext);
+	return ERR_PTR(err);
+}
+
+struct p4tc_extern_inst *
+p4tc_ext_inst_find_bynames(struct net *net, struct p4tc_pipeline *pipeline,
+			   const char *extname, const char *instname,
+			   struct netlink_ext_ack *extack)
+{
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	struct p4tc_extern_inst *inst;
+
+	pipe_ext = p4tc_user_pipeline_ext_find_byany(pipeline, extname, 0,
+						     extack);
+	if (IS_ERR(pipe_ext))
+		return (void *)pipe_ext;
+
+	inst = p4tc_ext_inst_find_byany(pipe_ext, instname, 0, extack);
+	if (IS_ERR(inst))
+		return inst;
+
+	return inst;
+}
+
+struct p4tc_extern_inst *
+p4tc_ext_inst_get_byids(struct net *net, struct p4tc_pipeline **pipeline,
+			const u32 pipe_id,
+			struct p4tc_user_pipeline_extern **pipe_ext,
+			const u32 ext_id, const u32 inst_id)
+{
+	struct p4tc_extern_inst *inst;
+	int err;
+
+	*pipeline = tcf_pipeline_find_byid(net, pipe_id);
+	if (!*pipeline)
+		return ERR_PTR(-ENOENT);
+
+	/* Pipeline was deleted in parallel */
+	if (!refcount_inc_not_zero(&((*pipeline)->p_ref)))
+		return ERR_PTR(-EBUSY);
+
+	*pipe_ext = p4tc_user_pipeline_ext_find_byid(*pipeline, ext_id);
+	if (!*pipe_ext) {
+		err = -ENOENT;
+		goto refcount_dec_pipeline;
+	}
+
+	/* Pipeline extern template was deleted in parallel */
+	if (!refcount_inc_not_zero(&((*pipe_ext)->ext_ref))) {
+		err = -EBUSY;
+		goto refcount_dec_pipeline;
+	}
+
+	inst = p4tc_ext_inst_find_byid(*pipe_ext, inst_id);
+	if (!inst) {
+		err = -EBUSY;
+		goto refcount_dec_pipe_tmpl_ext;
+	}
+
+	/* Extern instance was deleted in parallel */
+	if (!refcount_inc_not_zero(&inst->inst_ref)) {
+		err = -EBUSY;
+		goto refcount_dec_pipe_tmpl_ext;
+	}
+
+	return inst;
+
+refcount_dec_pipe_tmpl_ext:
+	refcount_dec(&((*pipe_ext)->ext_ref));
+
+refcount_dec_pipeline:
+	refcount_dec(&((*pipeline)->p_ref));
+
+	return ERR_PTR(err);
+}
+
+static struct p4tc_extern_inst *
+p4tc_tmpl_ext_inst_update(struct net *net, struct nlmsghdr *n,
+			  struct nlattr *nla, struct p4tc_pipeline *pipeline,
+			  u32 *ids, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_param *control_params[P4TC_MSGBATCH_SIZE] = { NULL };
+	struct p4tc_extern_method *methods[P4TC_MAX_EXTERN_METHODS] = { NULL };
+	int num_params = 0, num_methods = 0;
+	u32 ext_id = 0, inst_id = 0;
+	char *inst_name = NULL;
+	struct nlattr *tb[P4TC_TMPL_EXT_INST_MAX + 1];
+	struct p4tc_extern_inst_common *inst_common;
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	struct p4tc_pipeline *root_pipeline;
+	struct p4tc_extern_inst *inst;
+	struct p4tc_tmpl_extern *ext;
+	int ret;
+
+	ret = nla_parse_nested(tb, P4TC_TMPL_EXT_INST_MAX, nla,
+			       tc_extern_inst_policy, extack);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	ext_id = ids[P4TC_TMPL_EXT_IDX];
+
+	root_pipeline = tcf_pipeline_find_byid(net, P4TC_KERNEL_PIPEID);
+
+	ext = p4tc_tmpl_ext_find_byanyattr(root_pipeline,
+					   tb[P4TC_TMPL_EXT_INST_EXT_NAME],
+					   ext_id, extack);
+	if (IS_ERR(ext))
+		return (struct p4tc_extern_inst *)ext;
+
+	if (tb[P4TC_TMPL_EXT_INST_NAME])
+		inst_name = nla_data(tb[P4TC_TMPL_EXT_INST_NAME]);
+
+	inst_id = ids[P4TC_TMPL_EXT_INST_IDX];
+
+	pipe_ext = p4tc_user_pipeline_ext_find_byid(pipeline, ext->ext_id);
+	if (!pipe_ext) {
+		NL_SET_ERR_MSG(extack, "Unable to find pipeline extern by id");
+		return ERR_PTR(-ENOENT);
+	}
+	inst = p4tc_ext_inst_find_byanyattr(pipe_ext,
+					    tb[P4TC_TMPL_EXT_INST_NAME],
+					    inst_id, extack);
+	if (IS_ERR(inst))
+		return ERR_PTR(-ENOMEM);
+
+	if (tb[P4TC_TMPL_EXT_INST_NUM_ELEMS]) {
+		u32 *num_elems;
+
+		num_elems = nla_data(tb[P4TC_TMPL_EXT_INST_NUM_ELEMS]);
+		inst->max_num_elems = *num_elems;
+	}
+
+	inst_common = inst->inst_common;
+	if (tb[P4TC_TMPL_EXT_INST_METHODS]) {
+		num_methods = p4tc_extern_init_methods(&inst_common->methods_idr,
+						       methods,
+						       tb[P4TC_TMPL_EXT_INST_METHODS],
+						       true, extack);
+		if (num_methods < 0)
+			return ERR_PTR(num_methods);
+		inst_common->num_methods = num_methods;
+	}
+
+	if (tb[P4TC_TMPL_EXT_INST_CONTROL_PARAMS]) {
+		num_params = p4tc_extern_init_params(&inst_common->control_params_idr,
+						     tb[P4TC_TMPL_EXT_INST_CONTROL_PARAMS],
+						     control_params, true,
+						     extack);
+		if (num_params < 0) {
+			ret = num_params;
+			goto free_methods;
+		}
+		inst_common->num_control_params = num_params;
+	}
+	inst->inst_common = inst_common;
+
+	inst->ext_id = ext->ext_id;
+	inst->ext_inst_id = inst_id;
+	inst->ops = ext->ops;
+
+	strscpy(inst->common.name, inst_name, EXTERNINSTNAMSIZ);
+
+	inst->common.p_id = pipeline->common.p_id;
+	inst->common.ops = (struct p4tc_template_ops *)&p4tc_tmpl_ext_inst_ops;
+	inst->pipe_ext = pipe_ext;
+	refcount_set(&inst->inst_ref, 1);
+
+	p4tc_extern_methods_replace_many(&inst_common->methods_idr, methods,
+					 num_methods);
+	p4tc_extern_params_replace_many(&inst_common->control_params_idr,
+					control_params, num_params);
+
+	return inst;
+
+free_methods:
+	p4tc_extern_put_many_methods(&inst_common->methods_idr, methods, false,
+				     num_methods);
+
+	return ERR_PTR(ret);
+}
+
+static struct p4tc_extern_inst *
+p4tc_tmpl_ext_inst_create(struct net *net, struct nlmsghdr *n,
+			  struct nlattr *nla, struct p4tc_pipeline *pipeline,
+			  u32 *ids, struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_param *control_params[P4TC_MSGBATCH_SIZE] = { NULL };
+	struct p4tc_extern_method *methods[P4TC_MAX_EXTERN_METHODS] = { NULL };
+	int num_params = 0, num_methods = 0;
+	bool allocated_pipe_ext = false;
+	u32 ext_id = 0, inst_id = 0;
+	char *inst_name = NULL;
+	struct nlattr *tb[P4TC_TMPL_EXT_INST_MAX + 1];
+	struct p4tc_extern_inst_common *inst_common;
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	struct p4tc_pipeline *root_pipeline;
+	struct p4tc_extern_inst *inst;
+	struct p4tc_tmpl_extern *ext;
+	int ret;
+
+	ret = nla_parse_nested(tb, P4TC_TMPL_EXT_INST_MAX, nla,
+			       tc_extern_inst_policy, extack);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	ext_id = ids[P4TC_TMPL_EXT_IDX];
+
+	root_pipeline = tcf_pipeline_find_byid(net, P4TC_KERNEL_PIPEID);
+
+	ext = p4tc_tmpl_ext_find_byanyattr(root_pipeline,
+					   tb[P4TC_TMPL_EXT_INST_EXT_NAME],
+					   ext_id, extack);
+	if (IS_ERR(ext))
+		return (struct p4tc_extern_inst *)ext;
+
+	if (tb[P4TC_TMPL_EXT_INST_NAME]) {
+		inst_name = nla_data(tb[P4TC_TMPL_EXT_INST_NAME]);
+	} else {
+		NL_SET_ERR_MSG(extack,
+			       "Must specify extern name");
+		return ERR_PTR(-EEXIST);
+	}
+
+	inst_id = ids[P4TC_TMPL_EXT_INST_IDX];
+	if (!inst_id) {
+		NL_SET_ERR_MSG(extack, "Must specify extern instance id");
+		return ERR_PTR(-EINVAL);
+	}
+
+	pipe_ext = p4tc_user_pipeline_ext_find_or_create(pipeline, ext,
+							 &allocated_pipe_ext,
+							 extack);
+	if (IS_ERR(pipe_ext))
+		return (struct p4tc_extern_inst *)pipe_ext;
+
+	if (p4tc_ext_inst_find_byname(pipe_ext, inst_name) ||
+	    p4tc_ext_inst_find_byid(pipe_ext, inst_id)) {
+		NL_SET_ERR_MSG(extack,
+			       "Extern instance with same name or ID already exists");
+		ret = -EEXIST;
+		goto dec_pipe_ext_ref;
+	}
+
+	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+	if (!inst) {
+		NL_SET_ERR_MSG(extack, "Failed to allocate ext inst");
+		ret = -ENOMEM;
+		goto dec_pipe_ext_ref;
+	}
+
+	inst_common = kzalloc(sizeof(*inst_common), GFP_KERNEL);
+	if (!inst_common) {
+		ret = -ENOMEM;
+		goto free_extern;
+	}
+
+	if (tb[P4TC_TMPL_EXT_INST_NUM_ELEMS]) {
+		u32 *num_elems;
+
+		num_elems = nla_data(tb[P4TC_TMPL_EXT_INST_NUM_ELEMS]);
+		inst->max_num_elems = *num_elems;
+	} else {
+		inst->max_num_elems = P4TC_DEFAULT_NUM_EXT_INST_ELEMS;
+	}
+	refcount_set(&inst->curr_num_elems, 1);
+
+	idr_init(&inst_common->methods_idr);
+	if (tb[P4TC_TMPL_EXT_INST_METHODS]) {
+		num_methods = p4tc_extern_init_methods(&inst_common->methods_idr,
+						       methods,
+						       tb[P4TC_TMPL_EXT_INST_METHODS],
+						       false, extack);
+		if (num_methods < 0) {
+			idr_destroy(&inst_common->methods_idr);
+			ret = num_methods;
+			goto free_extern_common;
+		}
+		inst_common->num_methods = num_methods;
+	}
+
+	idr_init(&inst_common->control_params_idr);
+	idr_init(&inst_common->control_elems_idr);
+	if (tb[P4TC_TMPL_EXT_INST_CONTROL_PARAMS]) {
+		num_params = p4tc_extern_init_params(&inst_common->control_params_idr,
+						     tb[P4TC_TMPL_EXT_INST_CONTROL_PARAMS],
+						     control_params, false,
+						     extack);
+		if (num_params < 0) {
+			ret = num_params;
+			idr_destroy(&inst_common->control_params_idr);
+			goto free_methods;
+		}
+		inst_common->num_control_params = num_params;
+	}
+	inst->inst_common = inst_common;
+
+	inst->ext_inst_id = inst_id;
+	ret = idr_alloc_u32(&pipe_ext->e_inst_idr, inst, &inst->ext_inst_id,
+			    inst->ext_inst_id, GFP_KERNEL);
+	if (ret < 0) {
+		NL_SET_ERR_MSG(extack,
+			       "Unable to allocate ID for extern instance");
+		goto free_control_params;
+	}
+
+	if (allocated_pipe_ext)
+		refcount_inc(&pipe_ext->curr_insts_num);
+
+	inst->ext_id = ext->ext_id;
+	inst->ext_inst_id = inst_id;
+	inst->ops = ext->ops;
+
+	strscpy(inst->common.name, inst_name, EXTERNINSTNAMSIZ);
+
+	inst->common.p_id = pipeline->common.p_id;
+	inst->common.ops = (struct p4tc_template_ops *)&p4tc_tmpl_ext_inst_ops;
+	inst->pipe_ext = pipe_ext;
+	refcount_set(&inst->inst_ref, 1);
+
+	p4tc_extern_methods_replace_many(&inst_common->methods_idr, methods,
+					 num_methods);
+	p4tc_extern_params_replace_many(&inst_common->control_params_idr,
+					control_params, num_params);
+
+	return inst;
+
+free_control_params:
+	p4tc_extern_put_many_params(&inst_common->control_params_idr,
+				    control_params, true, num_params);
+	idr_destroy(&inst_common->control_elems_idr);
+
+free_methods:
+	p4tc_extern_put_many_methods(&inst_common->methods_idr, methods, true,
+				     num_methods);
+	idr_destroy(&inst_common->methods_idr);
+
+free_extern_common:
+	kfree(inst_common);
+
+free_extern:
+	kfree(inst);
+
+dec_pipe_ext_ref:
+	if (!allocated_pipe_ext)
+		refcount_dec(&pipe_ext->ext_ref);
+
+	return ERR_PTR(ret);
+}
+
+static struct p4tc_template_common *
+p4tc_tmpl_ext_inst_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;
+	struct p4tc_extern_inst *inst;
+
+	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)
+		inst = p4tc_tmpl_ext_inst_update(net, n, nla, pipeline, ids,
+						 extack);
+	else
+		inst = p4tc_tmpl_ext_inst_create(net, n, nla, pipeline, ids,
+						 extack);
+
+	if (IS_ERR(inst))
+		goto out;
+
+out:
+	return (struct p4tc_template_common *)inst;
+}
+
+static struct p4tc_tmpl_extern *
+p4tc_tmpl_ext_create(struct nlmsghdr *n, struct nlattr *nla,
+		     struct p4tc_pipeline *pipeline, u32 *ids,
+		     struct netlink_ext_ack *extack)
+{
+	char *extern_name = NULL;
+	u32 ext_id = 0;
+	struct nlattr *tb[P4TC_TMPL_EXT_MAX + 1];
+	struct p4tc_tmpl_extern *ext;
+	struct p4tc_extern_ops *ops;
+	int ret;
+
+	ret = nla_parse_nested(tb, P4TC_TMPL_EXT_MAX, nla, tc_extern_policy,
+			       extack);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	ext_id = ids[P4TC_TMPL_EXT_IDX];
+	if (!ext_id) {
+		NL_SET_ERR_MSG(extack, "Must specify extern id");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (tb[P4TC_TMPL_EXT_NAME]) {
+		extern_name = nla_data(tb[P4TC_TMPL_EXT_NAME]);
+	} else {
+		NL_SET_ERR_MSG(extack,
+			       "Must specify extern name");
+		return ERR_PTR(-EEXIST);
+	}
+
+	if ((p4tc_tmpl_ext_find_name(pipeline, extern_name)) ||
+	    p4tc_tmpl_ext_find_byid(pipeline, ext_id)) {
+		NL_SET_ERR_MSG(extack,
+			       "Extern with same id or name was already inserted");
+		return ERR_PTR(-EEXIST);
+	}
+
+	ext = kzalloc(sizeof(*ext), GFP_KERNEL);
+	if (!ext) {
+		NL_SET_ERR_MSG(extack, "Failed to allocate ext");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (tb[P4TC_TMPL_EXT_NUM_INSTS]) {
+		u16 *num_insts = nla_data(tb[P4TC_TMPL_EXT_NUM_INSTS]);
+
+		ext->max_num_insts = *num_insts;
+	} else {
+		ext->max_num_insts = P4TC_DEFAULT_NUM_EXT_INSTS;
+	}
+
+	ret = idr_alloc_u32(&pipeline->p_ext_idr, ext, &ext_id,
+			    ext_id, GFP_KERNEL);
+	if (ret < 0) {
+		NL_SET_ERR_MSG(extack, "Unable to allocate ID for extern");
+		goto free_extern;
+	}
+
+	ext->ext_id = ext_id;
+
+	strscpy(ext->common.name, extern_name, EXTERNNAMSIZ);
+
+	refcount_set(&ext->tmpl_ref, 1);
+
+	ext->common.p_id = pipeline->common.p_id;
+	ext->common.ops = (struct p4tc_template_ops *)&p4tc_tmpl_ext_ops;
+
+	ops = p4tc_extern_ops_get(extern_name);
+	if (ops) {
+		ext->ops = ops;
+		return ext;
+	}
+
+#ifdef CONFIG_MODULES
+	rtnl_unlock();
+	request_module("ext_%s", extern_name);
+	rtnl_lock();
+#endif
+
+	ops = p4tc_extern_ops_get(extern_name);
+	if (!ops) {
+		NL_SET_ERR_MSG(extack, "Failed to load TC extern module");
+		ret = -ENOENT;
+		goto idr_rm;
+	}
+	ext->ops = ops;
+
+	return ext;
+
+idr_rm:
+	idr_remove(&pipeline->p_ext_idr, ext->ext_id);
+
+free_extern:
+	kfree(ext);
+	return ERR_PTR(ret);
+}
+
+static struct p4tc_template_common *
+p4tc_tmpl_ext_cu(struct net *net, struct nlmsghdr *n, struct nlattr *nla,
+		 struct p4tc_nl_pname *nl_pname, u32 *ids,
+		 struct netlink_ext_ack *extack)
+{
+	struct p4tc_pipeline *pipeline;
+	struct p4tc_tmpl_extern *ext;
+
+	if (n->nlmsg_flags & NLM_F_REPLACE) {
+		NL_SET_ERR_MSG(extack, "Extern update not supported");
+		return ERR_PTR(-EOPNOTSUPP);
+	}
+
+	pipeline = tcf_pipeline_find_byid(net, P4TC_KERNEL_PIPEID);
+	if (IS_ERR(pipeline))
+		return (void *)pipeline;
+
+	ext = p4tc_tmpl_ext_create(n, nla, pipeline, ids, extack);
+	if (IS_ERR(ext))
+		goto out;
+
+out:
+	return (struct p4tc_template_common *)ext;
+}
+
+static int ext_inst_param_fill_nlmsg(struct sk_buff *skb,
+				     struct idr *params_idr)
+{
+	unsigned char *b = nlmsg_get_pos(skb);
+	struct p4tc_extern_param *param;
+	struct nlattr *nest_count;
+	unsigned long id, tmp;
+	int i = 1;
+
+	idr_for_each_entry_ul(params_idr, param, tmp, id) {
+		nest_count = nla_nest_start(skb, i);
+		if (!nest_count)
+			goto out_nlmsg_trim;
+
+		if (nla_put_string(skb, P4TC_EXT_PARAMS_NAME, param->name))
+			goto out_nlmsg_trim;
+
+		if (nla_put_u32(skb, P4TC_EXT_PARAMS_ID, param->id))
+			goto out_nlmsg_trim;
+
+		if (nla_put_u32(skb, P4TC_EXT_PARAMS_TYPE, param->type->typeid))
+			goto out_nlmsg_trim;
+
+		nla_nest_end(skb, nest_count);
+		i++;
+	}
+
+	return skb->len;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static int ext_method_fill_nlmsg(struct sk_buff *skb,
+				 struct p4tc_extern_method *method)
+{
+	unsigned char *b = nlmsg_get_pos(skb);
+	struct nlattr *parms;
+
+	if (nla_put_string(skb, P4TC_TMPL_EXT_INST_METHOD_NAME,
+			   method->method_name))
+		goto out_nlmsg_trim;
+
+	if (nla_put_u32(skb, P4TC_TMPL_EXT_INST_METHOD_ID, method->method_id))
+		goto out_nlmsg_trim;
+
+	parms = nla_nest_start(skb, P4TC_TMPL_EXT_INST_METHOD_PARAMS);
+	if (!parms)
+		goto out_nlmsg_trim;
+
+	if (ext_inst_param_fill_nlmsg(skb, &method->params_idr) < 0)
+		goto out_nlmsg_trim;
+
+	nla_nest_end(skb, parms);
+
+	return skb->len;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static int _p4tc_tmpl_ext_inst_fill_nlmsg(struct sk_buff *skb,
+					  struct p4tc_extern_inst *inst)
+{
+	struct p4tc_extern_inst_common *common = inst->inst_common;
+	unsigned char *b = nlmsg_get_pos(skb);
+	int i = 1;
+	struct nlattr *nest, *methods, *parms;
+	struct p4tc_user_pipeline_extern *ext;
+	struct p4tc_extern_method *method;
+	unsigned long method_id, tmp;
+	/* Parser instance id + header field id */
+	u32 ids[2];
+
+	ids[0] = inst->ext_id;
+	ids[1] = inst->ext_inst_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;
+
+	ext = inst->pipe_ext;
+	if (ext->ext_name[0]) {
+		if (nla_put_string(skb, P4TC_TMPL_EXT_INST_EXT_NAME,
+				   ext->ext_name))
+			goto out_nlmsg_trim;
+	}
+
+	if (inst->common.name[0]) {
+		if (nla_put_string(skb, P4TC_TMPL_EXT_INST_NAME,
+				   inst->common.name))
+			goto out_nlmsg_trim;
+	}
+
+	if (nla_put_u32(skb, P4TC_TMPL_EXT_INST_NUM_ELEMS, inst->max_num_elems))
+		goto out_nlmsg_trim;
+
+	methods = nla_nest_start(skb, P4TC_TMPL_EXT_INST_METHODS);
+	if (!methods)
+		goto out_nlmsg_trim;
+
+	idr_for_each_entry_ul(&common->methods_idr, method, tmp, method_id) {
+		struct nlattr *nest_count = nla_nest_start(skb, i);
+
+		if (ext_method_fill_nlmsg(skb, method) <= 0)
+			goto out_nlmsg_trim;
+
+		nla_nest_end(skb, nest_count);
+		i++;
+	}
+	nla_nest_end(skb, methods);
+
+	parms = nla_nest_start(skb, P4TC_TMPL_EXT_INST_CONTROL_PARAMS);
+	if (!parms)
+		goto out_nlmsg_trim;
+
+	if (ext_inst_param_fill_nlmsg(skb, &common->control_params_idr) < 0)
+		goto out_nlmsg_trim;
+
+	nla_nest_end(skb, parms);
+	nla_nest_end(skb, nest);
+
+	return skb->len;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static int _p4tc_tmpl_ext_fill_nlmsg(struct sk_buff *skb,
+				     struct p4tc_tmpl_extern *ext)
+{
+	unsigned char *b = nlmsg_get_pos(skb);
+	struct nlattr *nest;
+	/* Parser instance id + header field id */
+	u32 id;
+
+	id = ext->ext_id;
+
+	if (nla_put(skb, P4TC_PATH, sizeof(id), &id))
+		goto out_nlmsg_trim;
+
+	nest = nla_nest_start(skb, P4TC_PARAMS);
+	if (!nest)
+		goto out_nlmsg_trim;
+
+	if (ext->common.name[0]) {
+		if (nla_put_string(skb, P4TC_TMPL_EXT_NAME, ext->common.name))
+			goto out_nlmsg_trim;
+	}
+
+	if (nla_put_u16(skb, P4TC_TMPL_EXT_NUM_INSTS, ext->max_num_insts))
+		goto out_nlmsg_trim;
+
+	nla_nest_end(skb, nest);
+
+	return skb->len;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static int p4tc_tmpl_ext_inst_fill_nlmsg(struct net *net, struct sk_buff *skb,
+					 struct p4tc_template_common *template,
+					 struct netlink_ext_ack *extack)
+{
+	struct p4tc_extern_inst *inst = to_extern_inst(template);
+
+	if (_p4tc_tmpl_ext_inst_fill_nlmsg(skb, inst) <= 0) {
+		NL_SET_ERR_MSG(extack,
+			       "Failed to fill notification attributes for extern instance");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int p4tc_tmpl_ext_fill_nlmsg(struct net *net, struct sk_buff *skb,
+				    struct p4tc_template_common *template,
+				    struct netlink_ext_ack *extack)
+{
+	struct p4tc_tmpl_extern *ext = to_extern(template);
+
+	if (_p4tc_tmpl_ext_fill_nlmsg(skb, ext) <= 0) {
+		NL_SET_ERR_MSG(extack,
+			       "Failed to fill notification attributes for extern");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int p4tc_tmpl_ext_flush(struct sk_buff *skb,
+			       struct p4tc_pipeline *pipeline,
+			       struct netlink_ext_ack *extack)
+{
+	unsigned char *b = nlmsg_get_pos(skb);
+	int ret = 0;
+	int i = 0;
+	struct p4tc_tmpl_extern *ext;
+	unsigned long tmp, ext_id;
+	u32 path[1];
+
+	path[0] = 0;
+
+	if (idr_is_empty(&pipeline->p_ext_idr)) {
+		NL_SET_ERR_MSG(extack, "There are no externs to flush");
+		goto out_nlmsg_trim;
+	}
+
+	if (nla_put(skb, P4TC_PATH, sizeof(path), path))
+		goto out_nlmsg_trim;
+
+	idr_for_each_entry_ul(&pipeline->p_ext_idr, ext, tmp, ext_id) {
+		if (_p4tc_tmpl_ext_put(pipeline, ext, 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 externs");
+			goto out_nlmsg_trim;
+		} else {
+			NL_SET_ERR_MSG(extack,
+				       "Unable to flush all externs");
+		}
+	}
+
+	return i;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return 0;
+}
+
+static int p4tc_tmpl_ext_inst_flush(struct sk_buff *skb,
+				    struct p4tc_pipeline *pipeline,
+				    struct p4tc_user_pipeline_extern *pipe_ext,
+				    struct netlink_ext_ack *extack)
+{
+	unsigned char *b = nlmsg_get_pos(skb);
+	int ret = 0;
+	int i = 0;
+	struct p4tc_extern_inst *inst;
+	unsigned long tmp, inst_id;
+	u32 path[2];
+
+	path[0] = pipe_ext->ext_id;
+	path[1] = 0;
+
+	if (idr_is_empty(&pipe_ext->e_inst_idr)) {
+		NL_SET_ERR_MSG(extack, "There are no externs to flush");
+		goto out_nlmsg_trim;
+	}
+
+	if (nla_put(skb, P4TC_PATH, sizeof(path), path))
+		goto out_nlmsg_trim;
+
+	idr_for_each_entry_ul(&pipe_ext->e_inst_idr, inst, tmp, inst_id) {
+		if (_p4tc_tmpl_ext_inst_put(pipeline, pipe_ext, inst, false,
+					    false, extack) < 0) {
+			ret = -EBUSY;
+			continue;
+		}
+		i++;
+	}
+
+	/* We don't release pipe_ext in the loop to avoid use-after-free whilst
+	 * iterating through e_inst_idr. We free it here only if flush
+	 * succeeded, that is, all instances were deleted and thus ext_ref == 1
+	 */
+	if (refcount_read(&pipe_ext->ext_ref) == 1)
+		p4tc_user_pipeline_ext_free(pipe_ext, &pipeline->user_ext_idr);
+
+	nla_put_u32(skb, P4TC_COUNT, i);
+
+	if (ret < 0) {
+		if (i == 0) {
+			NL_SET_ERR_MSG(extack,
+				       "Unable to flush any externs instance");
+			goto out_nlmsg_trim;
+		} else {
+			NL_SET_ERR_MSG(extack,
+				       "Unable to flush all extern instances");
+		}
+	}
+
+	return i;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return 0;
+}
+
+static int p4tc_tmpl_ext_inst_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)
+{
+	struct nlattr *tb[P4TC_TMPL_EXT_INST_MAX + 1] = {NULL};
+	u32 inst_id = ids[P4TC_TMPL_EXT_INST_IDX];
+	unsigned char *b = nlmsg_get_pos(skb);
+	u32 ext_id = ids[P4TC_TMPL_EXT_IDX];
+	u32 pipe_id = ids[P4TC_PID_IDX];
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	struct p4tc_pipeline *pipeline;
+	struct p4tc_extern_inst *inst;
+	int ret;
+
+	if (n->nlmsg_type == RTM_GETP4TEMPLATE)
+		pipeline = tcf_pipeline_find_byany(net, nl_pname->data,
+						   pipe_id, extack);
+	else
+		pipeline = tcf_pipeline_find_byany_unsealed(net, nl_pname->data,
+							    pipe_id, extack);
+	if (IS_ERR(pipeline))
+		return PTR_ERR(pipeline);
+
+	if (nla) {
+		ret = nla_parse_nested(tb, P4TC_TMPL_EXT_MAX, nla,
+				       tc_extern_inst_policy, extack);
+		if (ret < 0)
+			return ret;
+	}
+
+	pipe_ext = p4tc_user_pipeline_ext_find_byanyattr(pipeline,
+							 tb[P4TC_TMPL_EXT_INST_EXT_NAME],
+							 ext_id, extack);
+	if (IS_ERR(pipe_ext))
+		return PTR_ERR(pipe_ext);
+
+	if (n->nlmsg_type == RTM_DELP4TEMPLATE && n->nlmsg_flags & NLM_F_ROOT)
+		return p4tc_tmpl_ext_inst_flush(skb, pipeline, pipe_ext,
+						extack);
+
+	inst = p4tc_ext_inst_find_byanyattr(pipe_ext,
+					    tb[P4TC_TMPL_EXT_INST_NAME],
+					    inst_id, extack);
+	if (IS_ERR(inst))
+		return PTR_ERR(inst);
+
+	ret = _p4tc_tmpl_ext_inst_fill_nlmsg(skb, inst);
+	if (ret < 0)
+		return -ENOMEM;
+
+	if (n->nlmsg_type == RTM_DELP4TEMPLATE) {
+		ret = _p4tc_tmpl_ext_inst_put(pipeline, pipe_ext, inst, false,
+					      true, extack);
+		if (ret < 0)
+			goto out_nlmsg_trim;
+	}
+
+	return 0;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return ret;
+}
+
+static int p4tc_tmpl_ext_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)
+{
+	struct nlattr *tb[P4TC_TMPL_EXT_MAX + 1] = {NULL};
+	unsigned char *b = nlmsg_get_pos(skb);
+	u32 ext_id = ids[P4TC_TMPL_EXT_IDX];
+	struct p4tc_pipeline *pipeline;
+	struct p4tc_tmpl_extern *ext;
+	int ret;
+
+	pipeline = tcf_pipeline_find_byid(net, P4TC_KERNEL_PIPEID);
+	if (IS_ERR(pipeline))
+		return PTR_ERR(pipeline);
+
+	if (nla) {
+		ret = nla_parse_nested(tb, P4TC_TMPL_EXT_MAX, nla,
+				       tc_extern_policy, extack);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (n->nlmsg_type == RTM_DELP4TEMPLATE && n->nlmsg_flags & NLM_F_ROOT)
+		return p4tc_tmpl_ext_flush(skb, pipeline, extack);
+
+	ext = p4tc_tmpl_ext_find_byanyattr(pipeline, tb[P4TC_TMPL_EXT_NAME],
+					   ext_id, extack);
+	if (IS_ERR(ext))
+		return PTR_ERR(ext);
+
+	ret = _p4tc_tmpl_ext_fill_nlmsg(skb, ext);
+	if (ret < 0)
+		return -ENOMEM;
+
+	if (n->nlmsg_type == RTM_DELP4TEMPLATE) {
+		ret = _p4tc_tmpl_ext_put(pipeline, ext, false, extack);
+		if (ret < 0)
+			goto out_nlmsg_trim;
+	}
+
+	return 0;
+
+out_nlmsg_trim:
+	nlmsg_trim(skb, b);
+	return ret;
+}
+
+static int p4tc_tmpl_ext_dump_1(struct sk_buff *skb,
+				struct p4tc_template_common *common)
+{
+	struct nlattr *param = nla_nest_start(skb, P4TC_PARAMS);
+	struct p4tc_tmpl_extern *ext = to_extern(common);
+	unsigned char *b = nlmsg_get_pos(skb);
+	u32 path[2];
+
+	if (!param)
+		goto out_nlmsg_trim;
+
+	if (ext->common.name[0] &&
+	    nla_put_string(skb, P4TC_TMPL_EXT_NAME, ext->common.name))
+		goto out_nlmsg_trim;
+
+	nla_nest_end(skb, param);
+
+	path[0] = ext->ext_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 p4tc_tmpl_ext_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;
+
+	pipeline = tcf_pipeline_find_byid(net, P4TC_KERNEL_PIPEID);
+
+	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_ext_idr,
+					P4TC_TMPL_EXT_IDX, extack);
+}
+
+static int p4tc_tmpl_ext_inst_dump_1(struct sk_buff *skb,
+				     struct p4tc_template_common *common)
+{
+	struct nlattr *param = nla_nest_start(skb, P4TC_PARAMS);
+	struct p4tc_extern_inst *inst = to_extern_inst(common);
+	unsigned char *b = nlmsg_get_pos(skb);
+	u32 path[2];
+
+	if (!param)
+		goto out_nlmsg_trim;
+
+	if (inst->common.name[0] &&
+	    nla_put_string(skb, P4TC_TMPL_EXT_NAME, inst->common.name))
+		goto out_nlmsg_trim;
+
+	nla_nest_end(skb, param);
+
+	path[0] = inst->pipe_ext->ext_id;
+	path[1] = inst->ext_inst_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 p4tc_tmpl_ext_inst_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_TMPL_EXT_INST_MAX + 1] = {NULL};
+	u32 ext_id = ids[P4TC_TMPL_EXT_IDX];
+	struct net *net = sock_net(skb->sk);
+	struct p4tc_user_pipeline_extern *pipe_ext;
+	struct p4tc_pipeline *pipeline;
+	u32 pipeid = ids[P4TC_PID_IDX];
+	int ret;
+
+	pipeline = tcf_pipeline_find_byany_unsealed(net, *p_name,
+						    pipeid, extack);
+	if (IS_ERR(pipeline))
+		return PTR_ERR(pipeline);
+
+	if (!ids[P4TC_PID_IDX])
+		ids[P4TC_PID_IDX] = pipeline->common.p_id;
+
+	if (!(*p_name))
+		*p_name = pipeline->common.name;
+
+	if (nla) {
+		ret = nla_parse_nested(tb, P4TC_TMPL_EXT_INST_MAX, nla,
+				       tc_extern_inst_policy, extack);
+		if (ret < 0)
+			return ret;
+	}
+
+	pipe_ext = p4tc_user_pipeline_ext_find_byanyattr(pipeline,
+							 tb[P4TC_TMPL_EXT_INST_EXT_NAME],
+							 ext_id, extack);
+	if (IS_ERR(pipe_ext))
+		return PTR_ERR(pipe_ext);
+
+	return tcf_p4_tmpl_generic_dump(skb, ctx, &pipe_ext->e_inst_idr,
+					P4TC_TMPL_EXT_INST_IDX, extack);
+}
+
+const struct p4tc_template_ops p4tc_tmpl_ext_inst_ops = {
+	.cu = p4tc_tmpl_ext_inst_cu,
+	.fill_nlmsg = p4tc_tmpl_ext_inst_fill_nlmsg,
+	.gd = p4tc_tmpl_ext_inst_gd,
+	.put = p4tc_tmpl_ext_inst_put,
+	.dump = p4tc_tmpl_ext_inst_dump,
+	.dump_1 = p4tc_tmpl_ext_inst_dump_1,
+};
+
+const struct p4tc_template_ops p4tc_tmpl_ext_ops = {
+	.cu = p4tc_tmpl_ext_cu,
+	.fill_nlmsg = p4tc_tmpl_ext_fill_nlmsg,
+	.gd = p4tc_tmpl_ext_gd,
+	.put = p4tc_tmpl_ext_put,
+	.dump = p4tc_tmpl_ext_dump,
+	.dump_1 = p4tc_tmpl_ext_dump_1,
+};
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 16/21] selftests: tc-testing: add JSON introspection file directory for P4TC
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (14 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 15/21] p4tc: Add P4 extern interface Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 17/21] selftests: tc-testing: add P4TC pipeline control path tdc tests Jamal Hadi Salim
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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 <victor@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 .../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 000000000..3cc26fc8d
--- /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" : "be16",
+                    "match_type" : "exact",
+                    "bitwidth" : 16
+                },
+                {
+                    "id" : 2,
+                    "name" : "dstPort",
+                    "type" : "be16",
+                    "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" : [
+            ]
+        }
+    ]
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 17/21] selftests: tc-testing: add P4TC pipeline control path tdc tests
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (15 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 16/21] selftests: tc-testing: add JSON introspection file directory for P4TC Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 18/21] selftests: tc-testing: add P4TC action templates " Jamal Hadi Salim
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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 <victor@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 .../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 000000000..7b97d375b
--- /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
+            ]
+        ]
+    }
+]
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 18/21] selftests: tc-testing: add P4TC action templates tdc tests
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (16 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 17/21] selftests: tc-testing: add P4TC pipeline control path tdc tests Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 19/21] selftests: tc-testing: add P4TC table control path " Jamal Hadi Salim
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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" <mohd.arif.khan@intel.com>
Tested-by: "Pottimurthy, Sathya Narayana" <sathya.narayana.pottimurthy@intel.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 .../tc-tests/p4tc/action_templates.json       | 12378 ++++++++++++++++
 1 file changed, 12378 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 000000000..3a47a5b3c
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/tc-tests/p4tc/action_templates.json
@@ -0,0 +1,12378 @@
+[
+    {
+        "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",
+                                "raw 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",
+                                "raw 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",
+                                "raw 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",
+                                "raw 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",
+                                "raw 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",
+                                "raw 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",
+                                "raw 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",
+                                "raw value": 4294967295,
+                                "id": 1
+                            }
+                        ],
+                        "index": 1,
+                        "ref": 1,
+                        "bind": 0,
+                        "not_in_hw": true
+                    },
+                    {
+                        "order": 1,
+                        "kind": "ptables/test",
+                        "params": [
+                            {
+                                "name": "param1",
+                                "type": "bit32",
+                                "raw 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",
+                                "raw 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,
+                        "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
+                                    }
+                                }
+                            }
+                        ],
+                        "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": []
+    }
+]
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 19/21] selftests: tc-testing: add P4TC table control path tdc tests
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (17 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 18/21] selftests: tc-testing: add P4TC action templates " Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 20/21] selftests: tc-testing: add P4TC table entries " Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 21/21] MAINTAINERS: add p4tc entry Jamal Hadi Salim
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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 <victor@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 .../tc-testing/tc-tests/p4tc/table.json       | 8956 +++++++++++++++++
 1 file changed, 8956 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 000000000..b1418e9eb
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/tc-tests/p4tc/table.json
@@ -0,0 +1,8956 @@
+[
+    {
+        "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": [],
+                                "operations": [
+                                  {
+                                    "instruction": "act",
+                                    "control_action": {
+                                      "type": "pipe"
+                                    },
+                                    "operands": {
+                                      "OPA": {
+                                        "type": "action",
+                                        "pname": "kernel",
+                                        "id": "gact"
+                                      }
+                                    }
+                                  }
+                                ]
+                            }
+                            ],
+                            "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": [],
+                                "operations": [
+                                  {
+                                    "instruction": "act",
+                                    "control_action": {
+                                      "type": "pipe"
+                                    },
+                                    "operands": {
+                                      "OPA": {
+                                        "type": "action",
+                                        "pname": "kernel",
+                                        "id": "gact"
+                                      }
+                                    }
+                                  }
+                                ]
+                            }
+                            ],
+                            "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": [],
+                                "operations": [
+                                  {
+                                    "instruction": "act",
+                                    "control_action": {
+                                      "type": "pipe"
+                                    },
+                                    "operands": {
+                                      "OPA": {
+                                        "type": "action",
+                                        "pname": "kernel",
+                                        "id": "gact"
+                                      }
+                                    }
+                                  }
+                                ]
+                            }
+                            ],
+                            "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": [],
+                                "operations": [
+                                  {
+                                    "instruction": "act",
+                                    "control_action": {
+                                      "type": "pipe"
+                                    },
+                                    "operands": {
+                                      "OPA": {
+                                        "type": "action",
+                                        "pname": "kernel",
+                                        "id": "gact"
+                                      }
+                                    }
+                                  }
+                                ]
+                            }
+                            ],
+                            "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
+            ]
+        ]
+    }
+]
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 20/21] selftests: tc-testing: add P4TC table entries control path tdc tests
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (18 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 19/21] selftests: tc-testing: add P4TC table control path " Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 21/21] MAINTAINERS: add p4tc entry Jamal Hadi Salim
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

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 <victor@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 .../tc-tests/p4tc/table_entries.json          | 3818 +++++++++++++++++
 1 file changed, 3818 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 000000000..231e3ae48
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/tc-tests/p4tc/table_entries.json
@@ -0,0 +1,3818 @@
+[
+    {
+        "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 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": 1,
+                        "prio": 16,
+                        "key": "0x1bb0050",
+                        "mask": "0xffffffff",
+                        "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 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 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": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "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 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": 1,
+                        "prio": 1,
+                        "key1": "0x7f0000005cff",
+                        "key2": "0",
+                        "mask1": "0xffffffffffffffff",
+                        "mask2": "0xffffffffff"
+                    }
+                ]
+            }
+        ],
+        "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 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/ tblid 3 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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+        "matchCount": "1",
+        "matchJSON": [
+            {
+                "pname": "ptables",
+                "pipeid": 22
+            },
+            {
+                "entries": [
+                    {
+                        "tblid": 3,
+                        "prio": 1,
+                        "key1": "0x7f0000005cff",
+                        "key2": "0",
+                        "mask1": "0xffffffffffffffff",
+                        "mask2": "0xffffffffff",
+                        "create_whodunnit": "tc"
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            [
+                "$TC -j p4 del ptables/table/ tblid 3 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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1 action ptables/cb/reclassify",
+                0
+            ]
+        ],
+        "cmdUnderTest": "$TC p4 create ptables/table/ tblid 3 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 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 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 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 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": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "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 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": "0x1a8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "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 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": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "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 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 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 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": 1,
+                        "prio": 16,
+                        "key": "0x1bb0050",
+                        "mask": "0xffffffff",
+                        "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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+                0
+            ]
+        ],
+        "cmdUnderTest": "$TC p4 update ptables/table/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1 action ptables/cb/reclassify",
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j p4 get ptables/table/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+        "matchCount": "1",
+        "matchJSON": [
+            {
+                "pname": "ptables",
+                "pipeid": 22
+            },
+            {
+                "entries": [
+                    {
+                        "tblid": 3,
+                        "prio": 1,
+                        "key1": "0x7f0000005cff",
+                        "key2": "0",
+                        "mask1": "0xffffffffffffffff",
+                        "mask2": "0xffffffffff",
+                        "create_whodunnit": "tc",
+                        "update_whodunnit": "tc",
+                        "actions": {
+                            "actions": [
+                                {
+                                    "order": 1,
+                                    "kind": "ptables/cb/reclassify",
+                                    "index": 1,
+                                    "ref": 1,
+                                    "bind": 1,
+                                    "params": [],
+                                    "operations": [
+                                      {
+                                        "instruction": "act",
+                                        "control_action": {
+                                          "type": "pipe"
+                                        },
+                                        "operands": {
+                                          "OPA": {
+                                            "type": "action",
+                                            "pname": "kernel",
+                                            "id": "gact"
+                                          }
+                                        }
+                                      }
+                                    ]
+                                }
+                            ]
+                        }
+                    }
+                ]
+            }
+        ],
+        "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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1 action ptables/cb/reclassify",
+                0
+            ]
+        ],
+        "cmdUnderTest": "$TC p4 update ptables/table/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1 action ptables/cb/reclassify index 2",
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j p4 get ptables/table/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+        "matchCount": "1",
+        "matchJSON": [
+            {
+                "pname": "ptables",
+                "pipeid": 22
+            },
+            {
+                "entries": [
+                    {
+                        "tblid": 3,
+                        "prio": 1,
+                        "key1": "0x7f0000005cff",
+                        "key2": "0",
+                        "mask1": "0xffffffffffffffff",
+                        "mask2": "0xffffffffff",
+                        "create_whodunnit": "tc",
+                        "update_whodunnit": "tc",
+                        "actions": {
+                            "actions": [
+                            {
+                                "order": 1,
+                                "kind": "ptables/cb/reclassify",
+                                "index": 2,
+                                "ref": 1,
+                                "bind": 1,
+                                "params": [],
+                                "operations": [
+                                  {
+                                    "instruction": "act",
+                                    "control_action": {
+                                      "type": "pipe"
+                                    },
+                                    "operands": {
+                                      "OPA": {
+                                        "type": "action",
+                                        "pname": "kernel",
+                                        "id": "gact"
+                                      }
+                                    }
+                                  }
+                                ]
+                            }
+                            ]
+                        }
+                    }
+                ]
+            }
+        ],
+        "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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1 action ptables/cb/reclassify index 1",
+                0
+            ]
+        ],
+        "cmdUnderTest": "$TC p4 update ptables/table/ tblid 3 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": [],
+                        "operations": [
+                          {
+                            "instruction": "act",
+                            "control_action": {
+                              "type": "pipe"
+                            },
+                            "operands": {
+                              "OPA": {
+                                "type": "action",
+                                "pname": "kernel",
+                                "id": "gact"
+                              }
+                            }
+                          }
+                        ]
+                    }
+                ]
+            }
+        ],
+        "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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+                0
+            ]
+        ],
+        "cmdUnderTest": "$TC p4 update ptables/table/ tblid 3 randomKey1  255 randomKey2  1 randomKey3  127 prio 1",
+        "expExitCode": "255",
+        "verifyCmd": "$TC -j p4 get ptables/table/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+        "matchCount": "1",
+        "matchJSON": [
+            {
+                "pname": "ptables",
+                "pipeid": 22
+            },
+            {
+                "entries": [
+                    {
+                        "tblid": 3,
+                        "prio": 1,
+                        "key1": "0x7f0000005cff",
+                        "key2": "0",
+                        "mask1": "0xffffffffffffffff",
+                        "mask2": "0xffffffffff",
+                        "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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+                0
+            ]
+        ],
+        "cmdUnderTest": "$TC p4 update ptables/table/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 action ptables/cb/reclassify",
+        "expExitCode": "255",
+        "verifyCmd": "$TC -j p4 get ptables/table/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+        "matchCount": "1",
+        "matchJSON": [
+            {
+                "pname": "ptables",
+                "pipeid": 22
+            },
+            {
+                "entries": [
+                    {
+                        "tblid": 3,
+                        "prio": 1,
+                        "key1": "0x7f0000005cff",
+                        "key2": "0",
+                        "mask1": "0xffffffffffffffff",
+                        "mask2": "0xffffffffff",
+                        "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 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/ tblid 3 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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+        "matchCount": "1",
+        "matchJSON": [
+            {
+                "pname": "ptables",
+                "pipeid": 22
+            },
+            {
+                "entries": [
+                    {
+                        "tblid": 3,
+                        "prio": 1,
+                        "key1": "0x7f0000005cff",
+                        "key2": "0",
+                        "mask1": "0xffffffffffffffff",
+                        "mask2": "0xffffffffff",
+                        "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/ tblid 3 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": "9bb5",
+        "name": "Delete table entry specifying tblid",
+        "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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+                0
+            ]
+        ],
+        "cmdUnderTest": "$TC p4 del ptables/table/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j p4 get ptables/table/ tblid 3 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/ tblid 3 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,
+                        "key1": "0x7f0000005cff",
+                        "key2": "0",
+                        "mask1": "0xffffffffffffffff",
+                        "mask2": "0xffffffffff"
+                    }
+                ]
+            }
+        ],
+        "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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+                0
+            ]
+        ],
+        "cmdUnderTest": "$TC p4 create ptables/table/ tblid 3 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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1 action ptables/cb/reclassify",
+                0
+            ]
+        ],
+        "cmdUnderTest": "$TC p4 del ptables/table/ tblid 3 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": [],
+                        "operations": [
+                          {
+                            "instruction": "act",
+                            "control_action": {
+                              "type": "pipe"
+                            },
+                            "operands": {
+                              "OPA": {
+                                "type": "action",
+                                "pname": "kernel",
+                                "id": "gact"
+                              }
+                            }
+                          }
+                        ]
+                    }
+                ]
+            }
+        ],
+        "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/ tblid 3 randomKey1  255 randomKey2  92 randomKey3  127 prio 1",
+        "expExitCode": "255",
+        "verifyCmd": "$TC -j p4 get ptables/table/ tblid 3 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 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 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": "5618",
+        "name": "Flush table entries using tblid",
+        "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 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 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": "0x38a8c0000a0a0a",
+                        "mask": "0xffffff00ffffff",
+                        "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 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": "0x38a8c0000a0a0a",
+                        "mask": "0xffffff00ffffff",
+                        "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": "044c",
+        "name": "Dump table entries specifying tblid",
+        "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 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/ tblid 1",
+        "matchCount": "1",
+        "matchJSON": [
+            {
+                "pname": "ptables",
+                "pipeid": 22
+            },
+            {
+                "entries": [
+                    {
+                        "tblid": 1,
+                        "prio": 1,
+                        "key": "0x38a8c0000a0a0a",
+                        "mask": "0xffffff00ffffff",
+                        "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 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 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 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": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 16,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 15,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 14,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 13,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 12,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 11,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 10,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 9,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 8,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 7,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 6,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 5,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 4,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 3,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    },
+                    {
+                        "tblid": 1,
+                        "prio": 2,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "create_whodunnit": "tc"
+                    }
+                ]
+            },
+            {
+                "pname": "ptables",
+                "pipeid": 22
+            },
+            {
+                "entries": [
+                    {
+                        "tblid": 1,
+                        "key": "0xa8c0000a0a0a",
+                        "mask": "0xffff00ffffff",
+                        "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 22 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 22 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 22 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": 22,
+                        "prio": 16,
+                        "key": "0x1bb0050",
+                        "mask": "0xffffffff",
+                        "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 22 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": 22,
+                        "prio": 16,
+                        "key": "0x1bb0050",
+                        "mask": "0xffffffff",
+                        "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 22 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": 22,
+                        "prio": 16,
+                        "key": "0x1bb0050",
+                        "mask": "0xffffffff",
+                        "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 22 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": 22,
+                        "prio": 16,
+                        "key": "0x1bb0050",
+                        "mask": "0xffffffff",
+                        "create_whodunnit": "tc"
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            [
+                "$TC p4 del ptables/table/cb/tname2/",
+                0
+            ],
+            [
+                "$TC p4template del pipeline/ptables",
+                0
+            ],
+            [
+                "$TC actions flush action gact",
+                0
+            ]
+        ]
+    }
+]
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v3 net-next 21/21] MAINTAINERS: add p4tc entry
  2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
                   ` (19 preceding siblings ...)
  2023-06-29 10:45 ` [PATCH RFC v3 net-next 20/21] selftests: tc-testing: add P4TC table entries " Jamal Hadi Salim
@ 2023-06-29 10:45 ` Jamal Hadi Salim
  20 siblings, 0 replies; 22+ messages in thread
From: Jamal Hadi Salim @ 2023-06-29 10:45 UTC (permalink / raw)
  To: netdev
  Cc: deb.chatterjee, anjali.singhai, namrata.limaye, tom, mleitner,
	Mahesh.Shirshyad, Vipin.Jain, tomasz.osinski, jiri,
	xiyou.wangcong, davem, edumazet, kuba, pabeni, vladbu,
	simon.horman, khalidm, toke, mattyk, kernel, john.andy.fingerhut

P4TC is currently maintained by Mojatatu Networks.

Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 MAINTAINERS | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index ebd26b3ca..32f6cd30a 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 <victor@mojatatu.com>
+M:	Jamal Hadi Salim <jhs@mojatatu.com>
+M:	Pedro Tammela <pctammela@mojatatu.com>
+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 <chunkeey@googlemail.com>
 L:	linux-wireless@vger.kernel.org
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2023-06-29 10:46 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-29 10:45 [PATCH RFC v3 net-next 00/21] Introducing P4TC Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 01/21] net: sched: act_api: Add dynamic actions IDR Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 02/21] net/sched: act_api: increase action kind string length Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 03/21] net/sched: act_api: add init_ops to struct tc_action_op Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 04/21] net/sched: act_api: export generic tc action searcher Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 05/21] net/sched: act_api: add struct p4tc_action_ops as a parameter to lookup callback Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 06/21] net: introduce rcu_replace_pointer_rtnl Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 07/21] p4tc: add P4 data types Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 08/21] p4tc: add pipeline create, get, update, delete Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 09/21] p4tc: add header field create, get, delete, flush and dump Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 10/21] p4tc: add action template create, update, delete, get, " Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 11/21] p4tc: add table " Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 12/21] p4tc: add table entry create, update, get, delete, " Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 13/21] p4tc: add set of P4TC table lookup kfuncs Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 14/21] p4tc: add P4 classifier Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 15/21] p4tc: Add P4 extern interface Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 16/21] selftests: tc-testing: add JSON introspection file directory for P4TC Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 17/21] selftests: tc-testing: add P4TC pipeline control path tdc tests Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 18/21] selftests: tc-testing: add P4TC action templates " Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 19/21] selftests: tc-testing: add P4TC table control path " Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 20/21] selftests: tc-testing: add P4TC table entries " Jamal Hadi Salim
2023-06-29 10:45 ` [PATCH RFC v3 net-next 21/21] MAINTAINERS: add p4tc entry Jamal Hadi Salim

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.