diff --git a/include/net/kparser.h b/include/net/kparser.h
new file mode 100644
index 000000000..89575a519
--- /dev/null
+++ b/include/net/kparser.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser.h - kParser global net header file
+ *
+ * Authors:     Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#ifndef _NET_KPARSER_H
+#define _NET_KPARSER_H
+
+#include <linux/kparser.h>
+#include <linux/skbuff.h>
+
+/* The kParser data path API can consume max 512 bytes */
+#define KPARSER_MAX_SKB_PACKET_LEN	512
+
+/* kparser_parse(): Function to parse a skb using a parser instance key.
+ *
+ * skb: input packet skb
+ * kparser_key: key of the associated kParser parser object which must be
+ *              already created via CLI.
+ * _metadata: User provided metadata buffer. It must be same as configured
+ *            metadata objects in CLI.
+ * metadata_len: Total length of the user provided metadata buffer.
+ * avoid_ref: Set this flag in case caller wants to avoid holding the reference
+ *            of the active parser object to save performance on the data path.
+ *            But please be advised, caller should hold the reference of the
+ *            parser object while using this data path. In this case, the CLI
+ *            can be used in advance to get the reference, and caller will also
+ *            need to release the reference via CLI once it is done with the
+ *            data path.
+ *
+ * return: kParser error code as defined in include/uapi/linux/kparser.h
+ */
+extern int kparser_parse(struct sk_buff *skb,
+			 const struct kparser_hkey *kparser_key,
+			 void *_metadata, size_t metadata_len,
+			 bool avoid_ref);
+
+/* __kparser_parse(): Function to parse a void * packet buffer using a parser instance key.
+ *
+ * parser: Non NULL kparser_get_parser() returned and cached opaque pointer
+ * referencing a valid parser instance.
+ * _hdr: input packet buffer
+ * parse_len: length of input packet buffer
+ * _metadata: User provided metadata buffer. It must be same as configured
+ * metadata objects in CLI.
+ * metadata_len: Total length of the user provided metadata buffer.
+ *
+ * return: kParser error code as defined in include/uapi/linux/kparser.h
+ */
+extern int __kparser_parse(const void *parser, void *_hdr,
+			   size_t parse_len, void *_metadata, size_t metadata_len);
+
+/* kparser_get_parser(): Function to get an opaque reference of a parser instance and mark it
+ * immutable so that while actively using, it can not be deleted. The parser is identified by a key.
+ * It marks the associated parser and whole parse tree immutable so that when it is locked, it can
+ * not be deleted.
+ *
+ * kparser_key: key of the associated kParser parser object which must be
+ * already created via CLI.
+ * avoid_ref: Set this flag in case caller wants to avoid holding the reference
+ *            of the active parser object to save performance on the data path.
+ *            But please be advised, caller should hold the reference of the
+ *            parser object while using this data path. In this case, the CLI
+ *            can be used in advance to get the reference, and caller will also
+ *            need to release the reference via CLI once it is done with the
+ *            data path.
+ *
+ * return: NULL if key not found, else an opaque parser instance pointer which
+ * can be used in the following APIs 3 and 4.
+ *
+ * NOTE: This call makes the whole parser tree immutable. If caller calls this
+ * more than once, later caller will need to release the same parser exactly that
+ * many times using the API kparser_put_parser().
+ */
+extern const void *kparser_get_parser(const struct kparser_hkey *kparser_key,
+				      bool avoid_ref);
+
+/* kparser_put_parser(): Function to return and undo the read only operation done previously by
+ * kparser_get_parser(). The parser instance is identified by using a previously obtained opaque
+ * parser pointer via API kparser_get_parser(). This undo the immutable change so that any component
+ * of the whole parse tree can be deleted again.
+ *
+ * parser: void *, Non NULL opaque pointer which was previously returned by kparser_get_parser().
+ * Caller can use cached opaque pointer as long as system does not restart and kparser.ko is not
+ * reloaded.
+ * avoid_ref: Set this flag only when this was used in the prio call to
+ *            kparser_get_parser(). Incorrect usage of this flag might cause
+ *            error and make the parser state unstable.
+ *
+ * return: boolean, true if put operation is success, else false.
+ *
+ * NOTE: This call makes the whole parser tree deletable for the very last call.
+ */
+extern bool kparser_put_parser(const void *parser, bool avoid_ref);
+
+/* net/core/filter.c's callback hook structure to use kParser APIs if kParser enabled */
+struct get_kparser_funchooks {
+	const void * (*kparser_get_parser_hook)(const struct kparser_hkey
+						*kparser_key, bool avoid_ref);
+	int (*__kparser_parse_hook)(const void *parser, void *_hdr,
+				    size_t parse_len, void *_metadata, size_t metadata_len);
+	bool (*kparser_put_parser_hook)(const void *parser, bool avoid_ref);
+};
+
+extern struct get_kparser_funchooks kparser_funchooks;
+
+#endif /* _NET_KPARSER_H */
diff --git a/include/uapi/linux/kparser.h b/include/uapi/linux/kparser.h
new file mode 100644
index 000000000..dad9621ee
--- /dev/null
+++ b/include/uapi/linux/kparser.h
@@ -0,0 +1,674 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser.h - kParser global Linux header file
+ *
+ * Authors:     Tom Herbert <tom@sipanda.io>
+ *              Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#ifndef _LINUX_KPARSER_H
+#define _LINUX_KPARSER_H
+
+#include <linux/string.h>
+#include <linux/types.h>
+
+/* *********************** NETLINK_GENERIC *********************** */
+#define KPARSER_GENL_NAME		"kParser"
+#define KPARSER_GENL_VERSION		0x1
+
+/* *********************** NETLINK CLI *********************** */
+/* *********************** Namespaces/objects *********************** */
+enum kparser_global_namespace_ids {
+	KPARSER_NS_INVALID,
+	KPARSER_NS_CONDEXPRS,
+	KPARSER_NS_CONDEXPRS_TABLE,
+	KPARSER_NS_CONDEXPRS_TABLES,
+	KPARSER_NS_COUNTER,
+	KPARSER_NS_COUNTER_TABLE,
+	KPARSER_NS_METADATA,
+	KPARSER_NS_METALIST,
+	KPARSER_NS_NODE_PARSE,
+	KPARSER_NS_PROTO_TABLE,
+	KPARSER_NS_TLV_NODE_PARSE,
+	KPARSER_NS_TLV_PROTO_TABLE,
+	KPARSER_NS_FLAG_FIELD,
+	KPARSER_NS_FLAG_FIELD_TABLE,
+	KPARSER_NS_FLAG_FIELD_NODE_PARSE,
+	KPARSER_NS_FLAG_FIELD_PROTO_TABLE,
+	KPARSER_NS_PARSER,
+	KPARSER_NS_OP_PARSER_LOCK_UNLOCK,
+	KPARSER_NS_MAX
+};
+
+#define KPARSER_ATTR_RSP(id)		KPARSER_ATTR_RSP_##id
+
+#define KPARSER_DEFINE_ATTR_IDS(id)			\
+	KPARSER_ATTR_CREATE_##id,	/* NLA_BINARY */\
+	KPARSER_ATTR_UPDATE_##id,	/* NLA_BINARY */\
+	KPARSER_ATTR_READ_##id,		/* NLA_BINARY */\
+	KPARSER_ATTR_DELETE_##id,	/* NLA_BINARY */\
+	KPARSER_ATTR_RSP(id)
+
+enum {
+	KPARSER_ATTR_UNSPEC,	/* Add more entries after this */
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_CONDEXPRS),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_CONDEXPRS_TABLE),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_CONDEXPRS_TABLES),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_COUNTER),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_COUNTER_TABLE),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_METADATA),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_METALIST),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_NODE_PARSE),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_PROTO_TABLE),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_TLV_NODE_PARSE),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_TLV_PROTO_TABLE),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_FLAG_FIELD),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_FLAG_FIELD_TABLE),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_FLAG_FIELD_NODE_PARSE),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_FLAG_FIELD_PROTO_TABLE),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_PARSER),
+	KPARSER_DEFINE_ATTR_IDS(KPARSER_NS_OP_PARSER_LOCK_UNLOCK),
+	KPARSER_ATTR_MAX	/* Add more entries before this */
+};
+
+enum {
+	KPARSER_CMD_UNSPEC,
+	KPARSER_CMD_CONFIGURE,
+	KPARSER_CMD_MAX
+};
+
+/* *********************** kparser hash key (hkey) *********************** */
+#define KPARSER_INVALID_ID		0xffff
+
+#define KPARSER_USER_ID_MIN		0
+#define KPARSER_USER_ID_MAX		0x8000
+#define KPARSER_KMOD_ID_MIN		0x8001
+#define KPARSER_KMOD_ID_MAX		0xfffe
+
+#define KPARSER_MAX_NAME		128
+#define KPARSER_MAX_DIGIT_STR_LEN	16
+#define KPARSER_DEF_NAME_PREFIX		"kparser_default_name"
+#define KPARSER_USER_ID_MIN		0
+#define KPARSER_USER_ID_MAX		0x8000
+#define KPARSER_KMOD_ID_MIN		0x8001
+#define KPARSER_KMOD_ID_MAX		0xfffe
+
+struct kparser_hkey {
+	__u16 id;
+	char name[KPARSER_MAX_NAME];
+};
+
+/* *********************** conditional expressions *********************** */
+enum kparser_condexpr_types {
+	KPARSER_CONDEXPR_TYPE_OR,
+	KPARSER_CONDEXPR_TYPE_AND,
+};
+
+enum kparser_expr_types {
+	KPARSER_CONDEXPR_TYPE_EQUAL,
+	KPARSER_CONDEXPR_TYPE_NOTEQUAL,
+	KPARSER_CONDEXPR_TYPE_LT,
+	KPARSER_CONDEXPR_TYPE_LTE,
+	KPARSER_CONDEXPR_TYPE_GT,
+	KPARSER_CONDEXPR_TYPE_GTE,
+};
+
+/* One boolean condition expressions */
+struct kparser_condexpr_expr {
+	enum kparser_expr_types type;
+	__u16 src_off;
+	__u8 length;
+	__u32 mask;
+	__u32 value;
+};
+
+struct kparser_conf_condexpr {
+	struct kparser_hkey key;
+	struct kparser_condexpr_expr config;
+};
+
+struct kparser_conf_condexpr_table {
+	struct kparser_hkey key;
+	int idx;
+	int default_fail;
+	enum kparser_condexpr_types type;
+	struct kparser_hkey condexpr_expr_key;
+};
+
+struct kparser_conf_condexpr_tables {
+	struct kparser_hkey key;
+	int idx;
+	struct kparser_hkey condexpr_expr_table_key;
+};
+
+/* *********************** counter *********************** */
+#define KPARSER_CNTR_NUM_CNTRS		7
+
+struct kparser_cntr_conf {
+	bool valid_entry;
+	__u8 index;
+	__u32 max_value;
+	__u32 array_limit;
+	size_t el_size;
+	bool reset_on_encap;
+	bool overwrite_last;
+	bool error_on_exceeded;
+};
+
+struct kparser_conf_cntr {
+	struct kparser_hkey key;
+	struct kparser_cntr_conf conf;
+};
+
+/* *********************** metadata *********************** */
+enum kparser_metadata_type {
+	KPARSER_METADATA_INVALID,
+	KPARSER_METADATA_HDRDATA,
+	KPARSER_METADATA_HDRDATA_NIBBS_EXTRACT,
+	KPARSER_METADATA_HDRLEN,
+	KPARSER_METADATA_CONSTANT_BYTE,
+	KPARSER_METADATA_CONSTANT_HALFWORD,
+	KPARSER_METADATA_OFFSET,
+	KPARSER_METADATA_BIT_OFFSET,
+	KPARSER_METADATA_NUMENCAPS,
+	KPARSER_METADATA_NUMNODES,
+	KPARSER_METADATA_TIMESTAMP,
+	KPARSER_METADATA_RETURN_CODE,
+	KPARSER_METADATA_COUNTER,
+	KPARSER_METADATA_NOOP,
+	KPARSER_METADATA_MAX
+};
+
+enum kparser_metadata_counter_op_type {
+	KPARSER_METADATA_COUNTEROP_NOOP,
+	KPARSER_METADATA_COUNTEROP_INCR,
+	KPARSER_METADATA_COUNTEROP_RST
+};
+
+#define KPARSER_METADATA_OFFSET_MIN		0
+#define KPARSER_METADATA_OFFSET_MAX		0xffffff
+#define KPARSER_METADATA_OFFSET_INVALID		0xffffffff
+
+/* TODO: align and pack all struct members
+ */
+struct kparser_conf_metadata {
+	struct kparser_hkey key;
+	enum kparser_metadata_type type;
+	enum kparser_metadata_counter_op_type cntr_op; // 3 bit
+	bool frame;
+	bool e_bit;
+	__u16 constant_value;
+	size_t soff;
+	size_t doff;
+	size_t len;
+	size_t add_off;
+	struct kparser_hkey counterkey;
+	struct kparser_hkey counter_data_key;
+};
+
+/* *********************** metadata list/table *********************** */
+struct kparser_conf_metadata_table {
+	struct kparser_hkey key;
+	size_t metadata_keys_count;
+	struct kparser_hkey metadata_keys[0];
+};
+
+/* *********************** parse nodes *********************** */
+/* kParser protocol node types
+ */
+enum kparser_node_type {
+	/* Plain node, no super structure */
+	KPARSER_NODE_TYPE_PLAIN,
+	/* TLVs node with super structure for TLVs */
+	KPARSER_NODE_TYPE_TLVS,
+	/* Flag-fields with super structure for flag-fields */
+	KPARSER_NODE_TYPE_FLAG_FIELDS,
+	/* It represents the limit value */
+	KPARSER_NODE_TYPE_MAX,
+};
+
+/* Types for parameterized functions */
+struct kparser_parameterized_len {
+	__u16 src_off;
+	__u8 size;
+	bool endian;
+	__u32 mask;
+	__u8 right_shift;
+	__u8 multiplier;
+	__u8 add_value;
+};
+
+struct kparser_parameterized_next_proto {
+	__u16 src_off;
+	__u32 mask;
+	__u8 size;
+	__u8 right_shift;
+};
+
+struct kparser_conf_parse_ops {
+	bool len_parameterized;
+	struct kparser_parameterized_len pflen;
+	struct kparser_parameterized_next_proto pfnext_proto;
+	bool cond_exprs_parameterized;
+	struct kparser_hkey cond_exprs_table;
+};
+
+/* base nodes */
+struct kparser_conf_node_proto {
+	bool encap;
+	bool overlay;
+	size_t min_len;
+	struct kparser_conf_parse_ops ops;
+};
+
+struct kparser_conf_node_parse {
+	int unknown_ret;
+	struct kparser_hkey proto_table_key;
+	struct kparser_hkey wildcard_parse_node_key;
+	struct kparser_hkey metadata_table_key;
+	struct kparser_conf_node_proto proto_node;
+};
+
+/* TLVS */
+struct kparser_proto_tlvs_opts {
+	struct kparser_parameterized_len pfstart_offset;
+	bool len_parameterized;
+	struct kparser_parameterized_len pflen;
+	struct kparser_parameterized_next_proto pftype;
+};
+
+struct kparser_conf_proto_tlvs_node {
+	struct kparser_proto_tlvs_opts ops;
+	bool tlvsstdfmt;
+	bool fixed_start_offset;
+	size_t start_offset;
+	__u8 pad1_val;
+	__u8 padn_val;
+	__u8 eol_val;
+	bool pad1_enable;
+	bool padn_enable;
+	bool eol_enable;
+	size_t min_len;
+};
+
+#define KPARSER_DEFAULT_TLV_MAX_LOOP			255
+#define KPARSER_DEFAULT_TLV_MAX_NON_PADDING		255
+#define KPARSER_DEFAULT_TLV_MAX_CONSEC_PAD_BYTES	255
+#define KPARSER_DEFAULT_TLV_MAX_CONSEC_PAD_OPTS		255
+#define KPARSER_DEFAULT_TLV_DISP_LIMIT_EXCEED		0
+#define KPARSER_DEFAULT_TLV_EXCEED_LOOP_CNT_ERR		false
+
+/* Two bit code that describes the action to take when a loop node
+ * exceeds a limit
+ */
+enum {
+	KPARSER_LOOP_DISP_STOP_OKAY = 0,
+	KPARSER_LOOP_DISP_STOP_NODE_OKAY = 1,
+	KPARSER_LOOP_DISP_STOP_SUB_NODE_OKAY = 2,
+	KPARSER_LOOP_DISP_STOP_FAIL = 3,
+};
+
+/* Configuration for a TLV node (generally loop nodes)
+ *
+ * max_loop: Maximum number of TLVs to process
+ * max_non: Maximum number of non-padding TLVs to process
+ * max_plen: Maximum consecutive padding bytes
+ * max_c_pad: Maximum number of consecutive padding options
+ * disp_limit_exceed: Disposition when a TLV parsing limit is exceeded. See
+ * KPARSER_LOOP_DISP_STOP_* in parser.h
+ * exceed_loop_cnt_is_err: True is exceeding maximum number of TLVS is an error
+ */
+struct kparser_loop_node_config {
+	__u16 max_loop;
+	__u16 max_non;
+	__u8 max_plen;
+	__u8 max_c_pad;
+	__u8 disp_limit_exceed;
+	bool exceed_loop_cnt_is_err;
+};
+
+/* TODO:
+ * disp_limit_exceed: 2;
+ * exceed_loop_cnt_is_err: 1;
+ */
+struct kparser_conf_parse_tlvs {
+	struct kparser_conf_proto_tlvs_node proto_node;
+	struct kparser_hkey tlv_proto_table_key;
+	int unknown_tlv_type_ret;
+	struct kparser_hkey tlv_wildcard_node_key;
+	struct kparser_loop_node_config config;
+};
+
+/* flag fields */
+struct kparser_parameterized_get_value {
+	__u16 src_off;
+	__u32 mask;
+	__u8 size;
+};
+
+struct kparser_proto_flag_fields_ops {
+	bool get_flags_parameterized;
+	struct kparser_parameterized_get_value pfget_flags;
+	bool start_fields_offset_parameterized;
+	struct kparser_parameterized_len pfstart_fields_offset;
+	bool flag_fields_len;
+	__u16 hdr_length;
+};
+
+struct kparser_conf_node_proto_flag_fields {
+	struct kparser_proto_flag_fields_ops ops;
+	struct kparser_hkey flag_fields_table_hkey;
+};
+
+struct kparser_conf_parse_flag_fields {
+	struct kparser_conf_node_proto_flag_fields proto_node;
+	struct kparser_hkey flag_fields_proto_table_key;
+};
+
+struct kparser_conf_node {
+	struct kparser_hkey key;
+	enum kparser_node_type type;
+	struct kparser_conf_node_parse plain_parse_node;
+	struct kparser_conf_parse_tlvs tlvs_parse_node;
+	struct kparser_conf_parse_flag_fields flag_fields_parse_node;
+};
+
+/* *********************** tlv parse node *********************** */
+struct kparser_conf_proto_tlv_node_ops {
+	bool overlay_type_parameterized;
+	struct kparser_parameterized_next_proto pfoverlay_type;
+	bool cond_exprs_parameterized;
+	struct kparser_hkey cond_exprs_table;
+};
+
+struct kparser_conf_node_proto_tlv {
+	size_t min_len;
+	size_t max_len;
+	bool is_padding;
+	struct kparser_conf_proto_tlv_node_ops ops;
+};
+
+struct kparser_conf_node_parse_tlv {
+	struct kparser_hkey key;
+	struct kparser_conf_node_proto_tlv node_proto;
+	struct kparser_hkey overlay_proto_tlvs_table_key;
+	struct kparser_hkey overlay_wildcard_parse_node_key;
+	int unknown_ret;
+	struct kparser_hkey metadata_table_key;
+};
+
+/* *********************** flag field *********************** */
+/* One descriptor for a flag
+ *
+ * flag: protocol value
+ * mask: mask to apply to field
+ * size: size for associated field data
+ */
+struct kparser_flag_field {
+	__u32 flag;
+	__u32 networkflag;
+	__u32 mask;
+	size_t size;
+	bool endian;
+};
+
+struct kparser_conf_flag_field {
+	struct kparser_hkey key;
+	struct kparser_flag_field conf;
+};
+
+/* *********************** flag field parse node *********************** */
+struct kparser_parse_flag_field_node_ops_conf {
+	struct kparser_hkey cond_exprs_table_key;
+};
+
+struct kparser_conf_node_parse_flag_field {
+	struct kparser_hkey key;
+	struct kparser_hkey metadata_table_key;
+	struct kparser_parse_flag_field_node_ops_conf ops;
+};
+
+/* *********************** generic tables *********************** */
+struct kparser_conf_table {
+	struct kparser_hkey key;
+	bool add_entry;
+	__u16 elems_cnt;
+	int optional_value1;
+	int optional_value2;
+	struct kparser_hkey elem_key;
+};
+
+/* *********************** parser *********************** */
+/* Flags for parser configuration */
+#define KPARSER_F_DEBUG_DATAPATH		(1 << 0)
+#define KPARSER_F_DEBUG_CLI			(1 << 1)
+
+#define KPARSER_MAX_NODES	10
+#define KPARSER_MAX_ENCAPS	1
+#define KPARSER_MAX_FRAMES	255
+
+/* Configuration for a KPARSER parser
+ *
+ * flags: Flags KPARSER_F_*
+ * max_nodes: Maximum number of nodes to parse
+ * max_encaps: Maximum number of encapsulations to parse
+ * max_frames: Maximum number of metadata frames
+ * metameta_size: Size of metameta data. The metameta data is at the head
+ * of the user defined metadata structure. This also serves as the
+ * offset of the first metadata frame
+ * frame_size: Size of one metadata frame
+ */
+struct kparser_config {
+	__u16 flags;
+	__u16 max_nodes;
+	__u16 max_encaps;
+	__u16 max_frames;
+	size_t metameta_size;
+	size_t frame_size;
+};
+
+struct kparser_conf_parser {
+	struct kparser_hkey key;
+	struct kparser_config config;
+	struct kparser_hkey root_node_key;
+	struct kparser_hkey ok_node_key;
+	struct kparser_hkey fail_node_key;
+	struct kparser_hkey atencap_node_key;
+};
+
+/* *********************** CLI config interface *********************** */
+
+/* NOTE: we can't use BITS_PER_TYPE from kernel header here and had to redefine BITS_IN_U32
+ * since this is shared with user space code.
+ */
+#define KPARSER_CONFIG_MAX_KEYS			128
+#define KPARSER_CONFIG_MAX_KEYS_BV_LEN ((KPARSER_CONFIG_MAX_KEYS /\
+					 (sizeof(__u32) * 8)) + 1)
+struct kparser_config_set_keys_bv {
+	__u32 ns_keys_bvs[KPARSER_CONFIG_MAX_KEYS_BV_LEN];
+};
+
+struct kparser_conf_cmd {
+	enum kparser_global_namespace_ids namespace_id;
+	struct kparser_config_set_keys_bv conf_keys_bv;
+	__u8 recursive_read_delete;
+	union {
+		/* for read/delete commands */
+		/* KPARSER_NS_OP_PARSER_LOCK_UNLOCK */
+		struct kparser_hkey obj_key;
+
+		/* KPARSER_NS_CONDEXPRS */
+		struct kparser_conf_condexpr cond_conf;
+
+		/* KPARSER_NS_COUNTER */
+		struct kparser_conf_cntr cntr_conf;
+
+		/* KPARSER_NS_METADATA */
+		struct kparser_conf_metadata md_conf;
+
+		/* KPARSER_NS_METALIST */
+		struct kparser_conf_metadata_table mdl_conf;
+
+		/* KPARSER_NS_NODE_PARSE */
+		struct kparser_conf_node node_conf;
+
+		/* KPARSER_NS_TLV_NODE_PARSE */
+		struct kparser_conf_node_parse_tlv tlv_node_conf;
+
+		/* KPARSER_NS_FLAG_FIELD */
+		struct kparser_conf_flag_field flag_field_conf;
+
+		/* KPARSER_NS_FLAG_FIELD_NODE_PARSE */
+		struct kparser_conf_node_parse_flag_field flag_field_node_conf;
+
+		/* KPARSER_NS_PROTO_TABLE */
+		/* KPARSER_NS_TLV_PROTO_TABLE */
+		/* KPARSER_NS_FLAG_FIELD_TABLE */
+		/* KPARSER_NS_FLAG_FIELD_PROTO_TABLE */
+		/* KPARSER_NS_CONDEXPRS_TABLE */
+		/* KPARSER_NS_CONDEXPRS_TABLES */
+		/* KPARSER_NS_COUNTER_TABLE */
+		struct kparser_conf_table table_conf;
+
+		/* KPARSER_NS_PARSER */
+		struct kparser_conf_parser parser_conf;
+	};
+};
+
+struct kparser_cmd_rsp_hdr {
+	int op_ret_code;
+	struct kparser_hkey key;
+	struct kparser_conf_cmd object;
+	size_t objects_len;
+	/* array of fixed size kparser_conf_cmd objects */
+	struct kparser_conf_cmd objects[0];
+};
+
+/* ***********************  kParser error code *********************** */
+/*
+ * There are two variants of the KPARSER return codes. The normal variant is
+ * a number between -15 and 0 inclusive where the name for the code is
+ * prefixed by KPARSER_. There is also a special 16-bit encoding which is
+ * 0xfff0 + -val where val is the negative number for the code so that
+ * corresponds to values 0xfff0 to 0xffff. Names for the 16-bit encoding
+ * are prefixed by KPARSER_16BIT_
+ */
+enum {
+	KPARSER_OKAY = 0,		/* Okay and continue */
+	KPARSER_RET_OKAY = -1,		/* Encoding of OKAY in ret code */
+
+	KPARSER_OKAY_USE_WILD = -2,	/* cam instruction */
+	KPARSER_OKAY_USE_ALT_WILD = -3,	/* cam instruction */
+
+	KPARSER_STOP_OKAY = -4,		/* Okay and stop parsing */
+	KPARSER_STOP_NODE_OKAY = -5,	/* Stop parsing current node */
+	KPARSER_STOP_SUB_NODE_OKAY = -6,/* Stop parsing currnet sub-node */
+
+	/* Parser failure */
+	KPARSER_STOP_FAIL = -12,
+	KPARSER_STOP_LENGTH = -13,
+	KPARSER_STOP_UNKNOWN_PROTO = -14,
+	KPARSER_STOP_ENCAP_DEPTH = -15,
+	KPARSER_STOP_UNKNOWN_TLV = -16,
+	KPARSER_STOP_TLV_LENGTH = -17,
+	KPARSER_STOP_BAD_FLAG = -18,
+	KPARSER_STOP_FAIL_CMP = -19,
+	KPARSER_STOP_LOOP_CNT = -20,
+	KPARSER_STOP_TLV_PADDING = -21,
+	KPARSER_STOP_OPTION_LIMIT = -22,
+	KPARSER_STOP_MAX_NODES = -23,
+	KPARSER_STOP_COMPARE = -24,
+	KPARSER_STOP_BAD_EXTRACT = -25,
+	KPARSER_STOP_BAD_CNTR = -26,
+	KPARSER_STOP_CNTR1 = -27,
+	KPARSER_STOP_CNTR2 = -28,
+	KPARSER_STOP_CNTR3 = -29,
+	KPARSER_STOP_CNTR4 = -30,
+	KPARSER_STOP_CNTR5 = -31,
+	KPARSER_STOP_CNTR6 = -32,
+	KPARSER_STOP_CNTR7 = -33,
+};
+
+static inline const char *kparser_code_to_text(int code)
+{
+	switch (code) {
+	case KPARSER_OKAY:
+		return "okay";
+	case KPARSER_RET_OKAY:
+		return "okay-ret";
+	case KPARSER_OKAY_USE_WILD:
+		return "okay-use-wild";
+	case KPARSER_OKAY_USE_ALT_WILD:
+		return "okay-use-alt-wild";
+	case KPARSER_STOP_OKAY:
+		return "stop-okay";
+	case KPARSER_STOP_NODE_OKAY:
+		return "stop-node-okay";
+	case KPARSER_STOP_SUB_NODE_OKAY:
+		return "stop-sub-node-okay";
+	case KPARSER_STOP_FAIL:
+		return "stop-fail";
+	case KPARSER_STOP_LENGTH:
+		return "stop-length";
+	case KPARSER_STOP_UNKNOWN_PROTO:
+		return "stop-unknown-proto";
+	case KPARSER_STOP_ENCAP_DEPTH:
+		return "stop-encap-depth";
+	case KPARSER_STOP_UNKNOWN_TLV:
+		return "stop-unknown-tlv";
+	case KPARSER_STOP_TLV_LENGTH:
+		return "stop-tlv-length";
+	case KPARSER_STOP_BAD_FLAG:
+		return "stop-bad-flag";
+	case KPARSER_STOP_FAIL_CMP:
+		return "stop-fail-cmp";
+	case KPARSER_STOP_LOOP_CNT:
+		return "stop-loop-cnt";
+	case KPARSER_STOP_TLV_PADDING:
+		return "stop-tlv-padding";
+	case KPARSER_STOP_OPTION_LIMIT:
+		return "stop-option-limit";
+	case KPARSER_STOP_MAX_NODES:
+		return "stop-max-nodes";
+	case KPARSER_STOP_COMPARE:
+		return "stop-compare";
+	case KPARSER_STOP_BAD_EXTRACT:
+		return "stop-bad-extract";
+	case KPARSER_STOP_BAD_CNTR:
+		return "stop-bad-counter";
+	default:
+		return "unknown-code";
+	}
+}
+
+/* *********************** HKey utility APIs *********************** */
+static inline bool kparser_hkey_id_empty(const struct kparser_hkey *key)
+{
+	if (!key)
+		return true;
+	return (key->id == KPARSER_INVALID_ID);
+}
+
+static inline bool kparser_hkey_name_empty(const struct kparser_hkey *key)
+{
+	if (!key)
+		return true;
+	return ((key->name[0] == '\0') ||
+			!strcmp(key->name, KPARSER_DEF_NAME_PREFIX));
+}
+
+static inline bool kparser_hkey_empty(const struct kparser_hkey *key)
+{
+	return (kparser_hkey_id_empty(key) && kparser_hkey_name_empty(key));
+}
+
+static inline bool kparser_hkey_user_id_invalid(const struct kparser_hkey *key)
+{
+	if (!key)
+		return true;
+	return ((key->id == KPARSER_INVALID_ID) ||
+			(key->id > KPARSER_USER_ID_MAX));
+}
+
+#endif /* _LINUX_KPARSER_H */
diff --git a/net/Kconfig b/net/Kconfig
index 48c33c222..3bd2a507b 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -471,4 +471,13 @@ config NETDEV_ADDR_LIST_TEST
 	default KUNIT_ALL_TESTS
 	depends on KUNIT
 
+config KPARSER
+	tristate "Parser in Kernel"
+	help
+          kParser stands for "The Kernel Parser". This is a programmable
+          network packet parser which is a ported version of the PANDA
+          parser. This module exposes kParser APIs in Kernel.
+
+	  If unsure, say N.
+
 endif   # if NET
diff --git a/net/Makefile b/net/Makefile
index 0914bea9c..58176c2fd 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -79,3 +79,4 @@ obj-$(CONFIG_NET_NCSI)		+= ncsi/
 obj-$(CONFIG_XDP_SOCKETS)	+= xdp/
 obj-$(CONFIG_MPTCP)		+= mptcp/
 obj-$(CONFIG_MCTP)		+= mctp/
+obj-$(CONFIG_KPARSER)		+= kparser/
diff --git a/net/kparser/Makefile b/net/kparser/Makefile
new file mode 100644
index 000000000..d5a657482
--- /dev/null
+++ b/net/kparser/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for KPARSER module
+#
+GCOV_PROFILE := y
+
+##KBUILD_CFLAGS   := -Wall -Wundef -Wno-trigraphs \
+#                   -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE \
+#                   -Werror=implicit-function-declaration -Werror=implicit-int \
+#                   -Wno-format-security \
+#                   -fanalyzer           \
+#                   -std=gnu89
+ccflags-y := -DDEBUG -DKERNEL_MOD -Wall
+
+obj-$(CONFIG_KPARSER) += kparser.o
+
+kparser-objs := kparser_main.o kparser_cmds.o kparser_cmds_ops.o kparser_cmds_dump_ops.o kparser_datapath.o
diff --git a/net/kparser/kparser.h b/net/kparser/kparser.h
new file mode 100644
index 000000000..836780e6a
--- /dev/null
+++ b/net/kparser/kparser.h
@@ -0,0 +1,418 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser.h - kParser local header file
+ *
+ * Author:      Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#ifndef __KPARSER_H
+#define __KPARSER_H
+
+#include <linux/hash.h>
+#include <linux/kparser.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rhashtable-types.h>
+#include <linux/skbuff.h>
+#include <linux/xxhash.h>
+
+#include "kparser_types.h"
+#include "kparser_condexpr.h"
+#include "kparser_metaextract.h"
+#include "kparser_types.h"
+
+/* These are used to track owner/owned relationship between different objects
+ */
+struct kparser_ref_ctx {
+	int nsid;
+	const void *obj;
+	const void __rcu **link_ptr;
+	struct kref *refcount;
+	struct list_head *list;
+	struct list_head list_node;
+};
+
+#define KPARSER_LINK_OBJ_SIGNATURE		0xffaabbff
+
+/* bookkeeping structure to manage the above struct kparser_ref_ctx and map an owner with owned both
+ * ways
+ */
+struct kparser_obj_link_ctx {
+	int sig;
+	struct kparser_ref_ctx owner_obj;
+	struct kparser_ref_ctx owned_obj;
+};
+
+/* global hash table structures */
+struct kparser_htbl {
+	struct rhashtable tbl;
+	struct rhashtable_params tbl_params;
+};
+
+/* it binds a netlink cli structure to an internal namespace object structure
+ *
+ * key: hash key, must be always the very first entry for hash functions to work correctly.
+ * ht_node_id: ID based hash table's linking object.
+ * ht_node_name: name based hash table's linking object.
+ * refcount: tracks how many other objects are linked using refcount.
+ * config: netlink msg's config structure cached, it is replayed back during read operations.
+ * owner_list: list pointer for kparser_obj_link_ctx.owner_obj.list
+ * owned_list: list pointer for kparser_obj_link_ctx.owned_obj.list
+ */
+struct kparser_glue {
+	struct kparser_hkey key;
+	struct rhash_head ht_node_id;
+	struct rhash_head ht_node_name;
+	struct kref refcount;
+	struct kparser_conf_cmd config;
+	struct list_head owner_list;
+	struct list_head owned_list;
+};
+
+/* internal namespace structures for conditional expressions
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_condexpr_expr {
+	struct kparser_glue glue;
+	struct kparser_condexpr_expr expr;
+};
+
+/* internal namespace structures for conditional expressions table
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_condexpr_table {
+	struct kparser_glue glue;
+	struct kparser_condexpr_table table;
+};
+
+/* internal namespace structures for table of conditional expressions table
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_condexpr_tables {
+	struct kparser_glue glue;
+	struct kparser_condexpr_tables table;
+};
+
+/* internal namespace structures for counters
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_counter {
+	struct kparser_glue glue;
+	struct kparser_cntr_conf counter_cnf;
+};
+
+/* internal namespace structures for counter table
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_counter_table {
+	struct kparser_glue glue;
+	__u8 elems_cnt;
+	struct kparser_glue_counter k_cntrs[KPARSER_CNTR_NUM_CNTRS];
+};
+
+/* internal namespace structures for metadata
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_metadata_extract {
+	struct kparser_glue glue;
+	struct kparser_metadata_extract mde;
+};
+
+/* internal namespace structures for metadata list
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_metadata_table {
+	struct kparser_glue glue;
+	size_t md_configs_len;
+	struct kparser_conf_cmd *md_configs;
+	struct kparser_metadata_table metadata_table;
+};
+
+/* internal namespace structures for node
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_node {
+	struct kparser_glue glue;
+};
+
+struct kparser_glue_glue_parse_node {
+	struct kparser_glue_node glue;
+	union {
+		struct kparser_parse_node node;
+		struct kparser_parse_flag_fields_node flags_parse_node;
+		struct kparser_parse_tlvs_node tlvs_parse_node;
+	} parse_node;
+};
+
+/* internal namespace structures for table
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_protocol_table {
+	struct kparser_glue glue;
+	struct kparser_proto_table proto_table;
+};
+
+/* internal namespace structures for tlv nodes and tables
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_parse_tlv_node {
+	struct kparser_glue_node glue;
+	struct kparser_parse_tlv_node tlv_parse_node;
+};
+
+/* internal namespace structures for tlvs proto table
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_proto_tlvs_table {
+	struct kparser_glue glue;
+	struct kparser_proto_tlvs_table tlvs_proto_table;
+};
+
+/* internal namespace structures for flagfields and tables
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_flag_field {
+	struct kparser_glue glue;
+	struct kparser_flag_field flag_field;
+};
+
+/* internal namespace structures for flag field node
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_flag_fields {
+	struct kparser_glue glue;
+	struct kparser_flag_fields flag_fields;
+};
+
+struct kparser_glue_flag_field_node {
+	struct kparser_glue_node glue;
+	struct kparser_parse_flag_field_node node_flag_field;
+};
+
+/* internal namespace structures for flag field table
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_proto_flag_fields_table {
+	struct kparser_glue glue;
+	struct kparser_proto_flag_fields_table flags_proto_table;
+};
+
+/* internal namespace structures for parser
+ * it binds a netlink cli structure to an internal namespace object structure
+ */
+struct kparser_glue_parser {
+	struct kparser_glue glue;
+	struct list_head list_node;
+	struct kparser_parser parser;
+};
+
+/* name hash table's hash object comparison function callback */
+static inline int kparser_cmp_fn_name(struct rhashtable_compare_arg *arg,
+				      const void *ptr)
+{
+	const char *key2 = arg->key;
+	const struct kparser_hkey *key1 = ptr;
+
+	return strcmp(key1->name, key2);
+}
+
+/* ID hash table's hash object comparison function callback */
+static inline int kparser_cmp_fn_id(struct rhashtable_compare_arg *arg,
+				    const void *ptr)
+{
+	const __u16 *key2 = arg->key;
+	const __u16 *key1 = ptr;
+
+	return (*key1 != *key2);
+}
+
+/* name hash table's hash calculation function callback from hash key */
+static inline __u32 kparser_generic_hash_fn_name(const void *hkey, __u32 key_len, __u32 seed)
+{
+	const char *key = hkey;
+
+	/* TODO: check if seed needs to be used here
+	 * TODO: replace xxh32() with siphash
+	 */
+	return xxh32(hkey, strlen(key), 0);
+}
+
+/* ID hash table's hash calculation function callback from hash key */
+static inline __u32 kparser_generic_hash_fn_id(const void *hkey, __u32 key_len, __u32 seed)
+{
+	const __u16 *key = hkey;
+	/* TODO: check if seed needs to be used here
+	 */
+	return *key;
+}
+
+/* name hash table's hash calculation function callback from object */
+static inline __u32 kparser_generic_obj_hashfn_name(const void *obj, __u32 key_len, __u32 seed)
+{
+	const struct kparser_hkey *key;
+
+	key = obj;
+	/* TODO: check if seed needs to be used here
+	 * TODO: replace xxh32() with siphash
+	 * Note: this only works because key always in the start place
+	 * of all the differnt kparser objects
+	 */
+	return xxh32(key->name, strlen(key->name), 0);
+}
+
+/* ID hash table's hash calculation function callback from object */
+static inline __u32 kparser_generic_obj_hashfn_id(const void *obj, __u32 key_len, __u32 seed)
+{
+	/* TODO: check if seed needs to be used here
+	 * TODO: replace xxh32() with siphash
+	 * Note: this only works because key always is the very first object in all the differnt
+	 * kparser objects
+	 */
+	return ((const struct kparser_hkey *)obj)->id;
+}
+
+/* internal shared functions */
+int kparser_init(void);
+int kparser_deinit(void);
+int kparser_config_handler_add(const void *cmdarg, size_t cmdarglen,
+			       struct kparser_cmd_rsp_hdr **rsp,
+			       size_t *rsp_len,
+			       void *extack, int *err);
+int kparser_config_handler_update(const void *cmdarg, size_t cmdarglen,
+				  struct kparser_cmd_rsp_hdr **rsp,
+				  size_t *rsp_len,
+				  void *extack, int *err);
+int kparser_config_handler_read(const void *cmdarg, size_t cmdarglen,
+				struct kparser_cmd_rsp_hdr **rsp,
+				size_t *rsp_len,
+				void *extack, int *err);
+int kparser_config_handler_delete(const void *cmdarg, size_t cmdarglen,
+				  struct kparser_cmd_rsp_hdr **rsp,
+				  size_t *rsp_len,
+				  void *extack, int *err);
+void *kparser_namespace_lookup(enum kparser_global_namespace_ids ns_id,
+			       const struct kparser_hkey *key);
+void kparser_ref_get(struct kref *refcount);
+void kparser_ref_put(struct kref *refcount);
+int kparser_conf_key_manager(enum kparser_global_namespace_ids ns_id,
+			     const struct kparser_hkey *key,
+			     struct kparser_hkey *new_key,
+			     struct kparser_cmd_rsp_hdr *rsp,
+			     const char *op,
+			     void *extack, int *err);
+void kparser_free(void *ptr);
+int kparser_namespace_remove(enum kparser_global_namespace_ids ns_id,
+			     struct rhash_head *obj_id,
+			     struct rhash_head *obj_name);
+int kparser_namespace_insert(enum kparser_global_namespace_ids ns_id,
+			     struct rhash_head *obj_id,
+			     struct rhash_head *obj_name);
+
+/* Generic kParser KMOD's netlink msg handler's definitions for create */
+typedef int kparser_obj_create_update(const struct kparser_conf_cmd *conf,
+				      size_t conf_len,
+				      struct kparser_cmd_rsp_hdr **rsp,
+				      size_t *rsp_len, const char *op,
+				      void *extack, int *err);
+/* Generic kParser KMOD's netlink msg handler's definitions for read and delete */
+typedef int kparser_obj_read_del(const struct kparser_hkey *key,
+		struct kparser_cmd_rsp_hdr **rsp,
+		size_t *rsp_len, __u8 recursive_read,
+		const char *op, void *extack, int *err);
+/* Generic kParser KMOD's netlink msg handler's free callbacks */
+typedef void kparser_free_obj(void *ptr, void *arg);
+int kparser_link_attach(const void *owner_obj,
+			int owner_nsid,
+			const void **owner_obj_link_ptr,
+			struct kref *owner_obj_refcount,
+			struct list_head *owner_list,
+			const void *owned_obj,
+			int owned_nsid,
+			struct kref *owned_obj_refcount,
+			struct list_head *owned_list,
+			struct kparser_cmd_rsp_hdr *rsp,
+			const char *op,
+			void *extack, int *err);
+int kparser_link_detach(const void *obj,
+			struct list_head *owner_list,
+			struct list_head *owned_list,
+			struct kparser_cmd_rsp_hdr *rsp,
+			void *extack, int *err);
+int alloc_first_rsp(struct kparser_cmd_rsp_hdr **rsp, size_t *rsp_len, int nsid);
+void kparser_start_new_tree_traversal(void);
+void kparser_dump_parser_tree(const struct kparser_parser *obj);
+
+/* kParser KMOD's netlink msg/cmd handler's, these are innermost handlers */
+kparser_obj_create_update
+	kparser_create_cond_exprs,
+	kparser_create_cond_table,
+	kparser_create_cond_tables,
+	kparser_create_counter,
+	kparser_create_counter_table,
+	kparser_create_metadata,
+	kparser_create_metalist,
+	kparser_create_parse_node,
+	kparser_create_proto_table,
+	kparser_create_parse_tlv_node,
+	kparser_create_tlv_proto_table,
+	kparser_create_flag_field,
+	kparser_create_flag_field_table,
+	kparser_create_parse_flag_field_node,
+	kparser_create_flag_field_proto_table,
+	kparser_create_parser,
+	kparser_parser_lock;
+
+kparser_obj_read_del
+	kparser_read_cond_exprs,
+	kparser_read_cond_table,
+	kparser_read_cond_tables,
+	kparser_read_counter,
+	kparser_read_counter_table,
+	kparser_read_metadata,
+	kparser_del_metadata,
+	kparser_read_metalist,
+	kparser_del_metalist,
+	kparser_read_parse_node,
+	kparser_del_parse_node,
+	kparser_read_proto_table,
+	kparser_del_proto_table,
+	kparser_read_parse_tlv_node,
+	kparser_read_tlv_proto_table,
+	kparser_read_flag_field,
+	kparser_read_flag_field_table,
+	kparser_read_parse_flag_field_node,
+	kparser_read_flag_field_proto_table,
+	kparser_read_parser,
+	kparser_del_parser,
+	kparser_parser_unlock;
+
+kparser_free_obj
+	kparser_free_metadata,
+	kparser_free_metalist,
+	kparser_free_node,
+	kparser_free_proto_tbl,
+	kparser_free_parser;
+
+#define KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_START	0
+#define KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_STOP		255
+
+extern void __rcu
+	*kparser_fast_lookup_array[KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_STOP -
+	KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_START + 1];
+
+#define KPARSER_KMOD_DEBUG_PRINT(PARSER_FLAG, FMT, ARGS...)			\
+do {										\
+	unsigned int parser_flag = PARSER_FLAG;					\
+	if ((parser_flag) & KPARSER_F_DEBUG_DATAPATH)				\
+		pr_alert("kParser:DATA:[%s:%d]" FMT, __func__, __LINE__, ## ARGS);\
+	else if ((parser_flag) & KPARSER_F_DEBUG_CLI)				\
+		pr_alert("kParser:CLI:[%s:%d]" FMT, __func__, __LINE__, ## ARGS);\
+	else									\
+		pr_debug("kParser:[%s:%d]" FMT, __func__, __LINE__, ## ARGS);	\
+}										\
+while (0)
+
+#endif /* __KPARSER_H */
diff --git a/net/kparser/kparser_cmds.c b/net/kparser/kparser_cmds.c
new file mode 100644
index 000000000..f1daeedb2
--- /dev/null
+++ b/net/kparser/kparser_cmds.c
@@ -0,0 +1,917 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser_cmds.c - kParser KMOD-CLI management API layer
+ *
+ * Author:      Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#include <linux/bitops.h>
+#include <linux/rhashtable.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/netlink.h>
+
+#include "kparser.h"
+
+#define KREF_INIT_VALUE		1
+
+/* These are used to track node loops in parse tree traversal operations */
+static __u64 curr_traversal_ts_id_ns;
+
+/* This function marks a start of a new parse tree traversal operation */
+void kparser_start_new_tree_traversal(void)
+{
+	curr_traversal_ts_id_ns = ktime_get_ns();
+}
+
+/* A simple wrapper for kfree for additional future internal debug info, particularly to
+ * track memleaks
+ */
+void kparser_free(void *ptr)
+{
+	if (ptr)
+		kfree(ptr);
+}
+
+/* Kernel API kref_put() must have a non-NULL callback, since we don't need to do anything during
+ * refcount release, kparser_release_ref() is just empty.
+ */
+static void kparser_release_ref(struct kref *kref)
+{
+}
+
+/* Consumer of this is datapath */
+void kparser_ref_get(struct kref *refcount)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "refcnt:%u\n", kref_read(refcount));
+
+	kref_get(refcount);
+}
+
+/* Consumer of this is datapath */
+void kparser_ref_put(struct kref *refcount)
+{
+	unsigned int refcnt;
+
+	refcnt = kref_read(refcount);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "refcnt:%u\n", refcnt);
+
+	if (refcnt > KREF_INIT_VALUE)
+		kref_put(refcount, kparser_release_ref);
+	else
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "refcount violation detected, val:%u", refcnt);
+}
+
+/* These are to track/bookkeep owner/owned relationships(both ways) when refcount is involved among
+ * various different types of namespace objects
+ */
+int kparser_link_attach(const void *owner_obj,
+			int owner_nsid,
+			const void **owner_obj_link_ptr,
+			struct kref *owner_obj_refcount,
+			struct list_head *owner_list,
+			const void *owned_obj,
+			int owned_nsid,
+			struct kref *owned_obj_refcount,
+			struct list_head *owned_list,
+			struct kparser_cmd_rsp_hdr *rsp,
+			const char *op,
+			void *extack, int *err)
+{
+	struct kparser_obj_link_ctx *reflist = NULL;
+
+	reflist = kzalloc(sizeof(*reflist), GFP_KERNEL);
+	if (!reflist) {
+		rsp->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc failed, size: %lu",
+				       op, sizeof(*reflist));
+		return -ENOMEM;
+	}
+
+	reflist->sig = KPARSER_LINK_OBJ_SIGNATURE;
+	reflist->owner_obj.nsid = owner_nsid;
+	reflist->owner_obj.obj = owner_obj;
+	reflist->owner_obj.link_ptr = owner_obj_link_ptr;
+	reflist->owner_obj.list = owner_list;
+	reflist->owner_obj.refcount = owner_obj_refcount;
+
+	reflist->owned_obj.nsid = owned_nsid;
+	reflist->owned_obj.obj = owned_obj;
+	reflist->owned_obj.list = owned_list;
+	reflist->owned_obj.refcount = owned_obj_refcount;
+
+	/* reflist is a bookkeeping tracker which maps an owner with owned, both ways.
+	 * hence for both owner and owned map contexts, it is kept in their respective lists.
+	 */
+	list_add_tail(&reflist->owner_obj.list_node, reflist->owner_obj.list);
+	list_add_tail(&reflist->owned_obj.list_node, reflist->owned_obj.list);
+
+	if (reflist->owned_obj.refcount)
+		kref_get(reflist->owned_obj.refcount);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "owner:%p owned:%p ref:%p\n",
+				 owner_obj, owned_obj, reflist);
+
+	synchronize_rcu();
+
+	return 0;
+}
+
+/* It is reverse bookkeeping action of kparser_link_attach(). when an object is detached (be it
+ * owner or owned, the respective map links needs be properly updated to indicate this detachment.
+ * kparser_link_break() is responsible for this removal update.
+ */
+static inline int kparser_link_break(const void *owner, const void *owned,
+				     struct kparser_obj_link_ctx *ref,
+				     struct kparser_cmd_rsp_hdr *rsp,
+				     void *extack, int *err)
+{
+	if (!ref) {
+		if (rsp) {
+			rsp->op_ret_code = EFAULT;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "link is NULL!");
+		}
+		return -EFAULT;
+	}
+
+	if (ref->sig != KPARSER_LINK_OBJ_SIGNATURE) {
+		if (rsp) {
+			rsp->op_ret_code = EFAULT;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "link is corrupt!");
+		}
+		return -EFAULT;
+	}
+
+	if (owner && ref->owner_obj.obj != owner) {
+		if (rsp) {
+			rsp->op_ret_code = EFAULT;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "link owner corrupt!");
+		}
+		return -EFAULT;
+	}
+
+	if (owned && ref->owned_obj.obj != owned) {
+		if (rsp) {
+			rsp->op_ret_code = EFAULT;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "link owned corrupt!");
+		}
+		return -EFAULT;
+	}
+
+	if (ref->owned_obj.refcount)
+		kref_put(ref->owned_obj.refcount, kparser_release_ref);
+
+	if (ref->owner_obj.link_ptr)
+		rcu_assign_pointer(*ref->owner_obj.link_ptr, NULL);
+
+	list_del_init_careful(&ref->owner_obj.list_node);
+	list_del_init_careful(&ref->owned_obj.list_node);
+
+	synchronize_rcu();
+
+	return 0;
+}
+
+/* when a detachment happens, from owner object perspective, it needs to remove the bookkeeping
+ * map contexts with respect to mapped owned objects.
+ */
+static inline int kparser_link_detach_owner(const void *obj,
+					    struct list_head *list,
+					    struct kparser_cmd_rsp_hdr *rsp,
+					    void *extack, int *err)
+{
+	struct kparser_obj_link_ctx *tmp_list_ref = NULL, *curr_ref = NULL;
+
+	list_for_each_entry_safe(curr_ref, tmp_list_ref, list, owner_obj.list_node) {
+		if (kparser_link_break(obj, NULL, curr_ref, rsp, extack, err) != 0)
+			return -EFAULT;
+		kparser_free(curr_ref);
+	}
+
+	return 0;
+}
+
+/* when a detachment happens, from owned object perspective, it needs to remove the bookkeeping
+ * map contexts with respect to mapped owner objects.
+ */
+static inline int kparser_link_detach_owned(const void *obj,
+					    struct list_head *list,
+					    struct kparser_cmd_rsp_hdr *rsp,
+					    void *extack, int *err)
+{
+	struct kparser_obj_link_ctx *tmp_list_ref = NULL, *curr_ref = NULL;
+	const struct kparser_glue_glue_parse_node *kparsenode;
+	const struct kparser_glue_protocol_table *proto_table;
+	int i;
+
+	list_for_each_entry_safe(curr_ref, tmp_list_ref, list, owned_obj.list_node) {
+		/* Special case handling:
+		 * if this is parse node and owned by a prototable, make sure
+		 * to remove that table's entry from array separately
+		 */
+		if (curr_ref->owner_obj.nsid == KPARSER_NS_PROTO_TABLE &&
+		    curr_ref->owned_obj.nsid == KPARSER_NS_NODE_PARSE) {
+			proto_table = curr_ref->owner_obj.obj;
+			kparsenode = curr_ref->owned_obj.obj;
+			for (i = 0; i < proto_table->proto_table.num_ents;
+					i++) {
+				if (proto_table->proto_table.entries[i].node !=
+						&kparsenode->parse_node.node)
+					continue;
+				rcu_assign_pointer(proto_table->proto_table.entries[i].node, NULL);
+				memset(&proto_table->proto_table.entries[i], 0,
+				       sizeof(proto_table->proto_table.entries[i]));
+				synchronize_rcu();
+				break;
+			}
+		}
+
+		if (kparser_link_break(NULL, obj, curr_ref, rsp, extack, err) != 0)
+			return -EFAULT;
+		kparser_free(curr_ref);
+	}
+
+	return 0;
+}
+
+/* bookkeeping function to break a link between an owner and owned object */
+int kparser_link_detach(const void *obj,
+			struct list_head *owner_list,
+			struct list_head *owned_list,
+			struct kparser_cmd_rsp_hdr *rsp,
+			void *extack, int *err)
+{
+	if (kparser_link_detach_owner(obj, owner_list, rsp, extack, err) != 0)
+		return -EFAULT;
+
+	if (kparser_link_detach_owned(obj, owned_list, rsp, extack, err) != 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+/* kParser KMOD's namespace definitions */
+struct kparser_mod_namespaces {
+	enum kparser_global_namespace_ids namespace_id;
+	const char *name;
+	struct kparser_htbl htbl_name;
+	struct kparser_htbl htbl_id;
+	kparser_obj_create_update *create_handler;
+	kparser_obj_create_update *update_handler;
+	kparser_obj_read_del *read_handler;
+	kparser_obj_read_del *del_handler;
+	kparser_free_obj *free_handler;
+	size_t bv_len;
+	unsigned long *bv;
+};
+
+/* Statically define kParser KMOD's namespaces with all the parameters */
+#define KPARSER_DEFINE_MOD_NAMESPACE(g_ns_obj, NSID, OBJ_NAME, FIELD, CREATE,	\
+				     READ, UPDATE, DELETE, FREE)		\
+static struct kparser_mod_namespaces g_ns_obj = {				\
+	.namespace_id = NSID,							\
+	.name = #NSID,								\
+	.htbl_name =	{							\
+		.tbl_params = {							\
+			.head_offset = offsetof(				\
+					struct OBJ_NAME,			\
+					FIELD.ht_node_name),			\
+			.key_offset = offsetof(					\
+					struct OBJ_NAME,			\
+					FIELD.key.name),			\
+			.key_len = sizeof(((struct kparser_hkey *)0)->name),	\
+			.automatic_shrinking = true,				\
+			.hashfn = kparser_generic_hash_fn_name,			\
+			.obj_hashfn = kparser_generic_obj_hashfn_name,		\
+			.obj_cmpfn = kparser_cmp_fn_name,			\
+		}								\
+	},									\
+	.htbl_id =	{							\
+		.tbl_params = {							\
+			.head_offset = offsetof(				\
+					struct OBJ_NAME,			\
+					FIELD.ht_node_id),			\
+			.key_offset = offsetof(					\
+					struct OBJ_NAME,			\
+					FIELD.key.id),				\
+			.key_len = sizeof(((struct kparser_hkey *)0)->id),	\
+			.automatic_shrinking = true,				\
+			.hashfn = kparser_generic_hash_fn_id,			\
+			.obj_hashfn = kparser_generic_obj_hashfn_id,		\
+			.obj_cmpfn = kparser_cmp_fn_id,				\
+		}								\
+	},									\
+										\
+	.create_handler = CREATE,						\
+	.read_handler = READ,							\
+	.update_handler = UPDATE,						\
+	.del_handler = DELETE,							\
+	.free_handler = FREE,							\
+}
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_condexprs,
+			     KPARSER_NS_CONDEXPRS,
+			     kparser_glue_condexpr_expr,
+			     glue,
+			     kparser_create_cond_exprs,
+			     kparser_read_cond_exprs,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_condexprs_table,
+			     KPARSER_NS_CONDEXPRS_TABLE,
+			     kparser_glue_condexpr_table,
+			     glue,
+			     kparser_create_cond_table,
+			     kparser_read_cond_table,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_condexprs_tables,
+			     KPARSER_NS_CONDEXPRS_TABLES,
+			     kparser_glue_condexpr_tables,
+			     glue,
+			     kparser_create_cond_tables,
+			     kparser_read_cond_tables,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_counter,
+			     KPARSER_NS_COUNTER,
+			     kparser_glue_counter,
+			     glue,
+			     kparser_create_counter,
+			     kparser_read_counter,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_counter_table,
+			     KPARSER_NS_COUNTER_TABLE,
+			     kparser_glue_counter_table,
+			     glue,
+			     kparser_create_counter_table,
+			     kparser_read_counter_table,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_metadata,
+			     KPARSER_NS_METADATA,
+			     kparser_glue_metadata_extract,
+			     glue,
+			     kparser_create_metadata,
+			     kparser_read_metadata,
+			     NULL,
+			     kparser_del_metadata,
+			     kparser_free_metadata);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_metalist,
+			     KPARSER_NS_METALIST,
+			     kparser_glue_metadata_table,
+			     glue,
+			     kparser_create_metalist,
+			     kparser_read_metalist,
+			     NULL,
+			     kparser_del_metalist,
+			     kparser_free_metalist);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_node_parse,
+			     KPARSER_NS_NODE_PARSE,
+			     kparser_glue_glue_parse_node,
+			     glue.glue,
+			     kparser_create_parse_node,
+			     kparser_read_parse_node,
+			     NULL,
+			     kparser_del_parse_node,
+			     kparser_free_node);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_proto_table,
+			     KPARSER_NS_PROTO_TABLE,
+			     kparser_glue_protocol_table,
+			     glue,
+			     kparser_create_proto_table,
+			     kparser_read_proto_table,
+			     NULL,
+			     kparser_del_proto_table,
+			     kparser_free_proto_tbl);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_tlv_node_parse,
+			     KPARSER_NS_TLV_NODE_PARSE,
+			     kparser_glue_parse_tlv_node,
+			     glue.glue,
+			     kparser_create_parse_tlv_node,
+			     kparser_read_parse_tlv_node,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_tlv_proto_table,
+			     KPARSER_NS_TLV_PROTO_TABLE,
+			     kparser_glue_proto_tlvs_table,
+			     glue,
+			     kparser_create_tlv_proto_table,
+			     kparser_read_tlv_proto_table,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_flag_field,
+			     KPARSER_NS_FLAG_FIELD,
+			     kparser_glue_flag_field,
+			     glue,
+			     kparser_create_flag_field,
+			     kparser_read_flag_field,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_flag_field_table,
+			     KPARSER_NS_FLAG_FIELD_TABLE,
+			     kparser_glue_flag_fields,
+			     glue,
+			     kparser_create_flag_field_table,
+			     kparser_read_flag_field_table,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_flag_field_parse_node,
+			     KPARSER_NS_FLAG_FIELD_NODE_PARSE,
+			     kparser_glue_flag_field_node,
+			     glue.glue,
+			     kparser_create_parse_flag_field_node,
+			     kparser_read_parse_flag_field_node,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_flag_field_proto_table,
+			     KPARSER_NS_FLAG_FIELD_PROTO_TABLE,
+			     kparser_glue_proto_flag_fields_table,
+			     glue,
+			     kparser_create_flag_field_proto_table,
+			     kparser_read_flag_field_proto_table,
+			     NULL, NULL, NULL);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_parser,
+			     KPARSER_NS_PARSER,
+			     kparser_glue_parser,
+			     glue,
+			     kparser_create_parser,
+			     kparser_read_parser,
+			     NULL,
+			     kparser_del_parser,
+			     kparser_free_parser);
+
+KPARSER_DEFINE_MOD_NAMESPACE(kparser_mod_namespace_parser_lock_unlock,
+			     KPARSER_NS_OP_PARSER_LOCK_UNLOCK,
+			     kparser_glue_parser,
+			     glue,
+			     kparser_parser_lock,
+			     NULL, NULL,
+			     kparser_parser_unlock,
+			     NULL);
+
+static struct kparser_mod_namespaces *g_mod_namespaces[] = {
+	[KPARSER_NS_INVALID] = NULL,
+	[KPARSER_NS_CONDEXPRS] = &kparser_mod_namespace_condexprs,
+	[KPARSER_NS_CONDEXPRS_TABLE] = &kparser_mod_namespace_condexprs_table,
+	[KPARSER_NS_CONDEXPRS_TABLES] =
+		&kparser_mod_namespace_condexprs_tables,
+	[KPARSER_NS_COUNTER] = &kparser_mod_namespace_counter,
+	[KPARSER_NS_COUNTER_TABLE] = &kparser_mod_namespace_counter_table,
+	[KPARSER_NS_METADATA] = &kparser_mod_namespace_metadata,
+	[KPARSER_NS_METALIST] = &kparser_mod_namespace_metalist,
+	[KPARSER_NS_NODE_PARSE] = &kparser_mod_namespace_node_parse,
+	[KPARSER_NS_PROTO_TABLE] = &kparser_mod_namespace_proto_table,
+	[KPARSER_NS_TLV_NODE_PARSE] = &kparser_mod_namespace_tlv_node_parse,
+	[KPARSER_NS_TLV_PROTO_TABLE] = &kparser_mod_namespace_tlv_proto_table,
+	[KPARSER_NS_FLAG_FIELD] = &kparser_mod_namespace_flag_field,
+	[KPARSER_NS_FLAG_FIELD_TABLE] =
+		&kparser_mod_namespace_flag_field_table,
+	[KPARSER_NS_FLAG_FIELD_NODE_PARSE] =
+		&kparser_mod_namespace_flag_field_parse_node,
+	[KPARSER_NS_FLAG_FIELD_PROTO_TABLE] =
+		&kparser_mod_namespace_flag_field_proto_table,
+	[KPARSER_NS_PARSER] = &kparser_mod_namespace_parser,
+	[KPARSER_NS_OP_PARSER_LOCK_UNLOCK] =
+		&kparser_mod_namespace_parser_lock_unlock,
+	[KPARSER_NS_MAX] = NULL,
+};
+
+/* Function to allocate autogen IDs for hash keys if user did not allocate themselves
+ * TODO: free ids
+ */
+static inline __u16 allocate_id(__u16 id, unsigned long *bv, size_t bvsize)
+{
+	int i;
+
+	if (id != KPARSER_INVALID_ID) {
+		/* try to allocate passed id */
+		/* already allocated, conflict */
+		if (!test_bit(id, bv))
+			return KPARSER_INVALID_ID;
+		__clear_bit(id, bv);
+		return id;
+	}
+
+	/* allocate internally, scan bitvector */
+	for (i = 0; i < bvsize; i++) {
+		/* avoid bit vectors which are already full */
+		if (bv[i]) {
+			id = __builtin_ffsl(bv[i]);
+			if (id) {
+				id--;
+				id += (i * BITS_PER_TYPE(unsigned long));
+				__clear_bit(id, bv);
+				return (id + KPARSER_KMOD_ID_MIN);
+			}
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "ID alloc failed: {%d:%d}\n",
+						 id, i);
+			return KPARSER_INVALID_ID;
+		}
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "ID alloc failed: {%d:%d}\n", id, i);
+	return KPARSER_INVALID_ID;
+}
+
+/* allocate hash key's autogen ID */
+static inline int kparser_allocate_key_id(enum kparser_global_namespace_ids ns_id,
+					  const struct kparser_hkey *key,
+					  struct kparser_hkey *new_key)
+{
+	*new_key = *key;
+	new_key->id = allocate_id(KPARSER_INVALID_ID,
+				  g_mod_namespaces[ns_id]->bv,
+				  g_mod_namespaces[ns_id]->bv_len);
+
+	if (new_key->id == KPARSER_INVALID_ID)
+		return -ENOENT;
+
+	return 0;
+}
+
+/* allocate hash key's autogen name */
+static inline bool kparser_allocate_key_name(enum kparser_global_namespace_ids ns_id,
+					     const struct kparser_hkey *key,
+					     struct kparser_hkey *new_key)
+{
+	*new_key = *key;
+	memset(new_key->name, 0, sizeof(new_key->name));
+	snprintf(new_key->name, sizeof(new_key->name),
+		 "%s-%s-%u", KPARSER_DEF_NAME_PREFIX,
+		 g_mod_namespaces[ns_id]->name, key->id);
+	new_key->name[sizeof(new_key->name) - 1] = '\0';
+	return true;
+}
+
+/* check and decide which component of hash key needs to be allocated using autogen code */
+int kparser_conf_key_manager(enum kparser_global_namespace_ids ns_id,
+			     const struct kparser_hkey *key,
+			     struct kparser_hkey *new_key,
+			     struct kparser_cmd_rsp_hdr *rsp,
+			     const char *op,
+			     void *extack, int *err)
+{
+	if (kparser_hkey_empty(key)) {
+		rsp->op_ret_code = -EINVAL;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s:HKey missing", op);
+		return -EINVAL;
+	}
+
+	if (kparser_hkey_id_empty(key) && new_key)
+		return kparser_allocate_key_id(ns_id, key, new_key);
+
+	if (kparser_hkey_user_id_invalid(key)) {
+		rsp->op_ret_code = -EINVAL;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:HKey id invalid:%u",
+				       op, key->id);
+		return -EINVAL;
+	}
+
+	if (kparser_hkey_name_empty(key) && new_key)
+		return kparser_allocate_key_name(ns_id, key, new_key);
+
+	if (new_key)
+		*new_key = *key;
+
+	return 0;
+}
+
+/* remove an object from namespace */
+int kparser_namespace_remove(enum kparser_global_namespace_ids ns_id,
+			     struct rhash_head *obj_id,
+			     struct rhash_head *obj_name)
+{
+	int rc;
+
+	if (ns_id <= KPARSER_NS_INVALID || ns_id >= KPARSER_NS_MAX)
+		return -EINVAL;
+
+	if (!g_mod_namespaces[ns_id])
+		return -ENOENT;
+
+	rc = rhashtable_remove_fast(&g_mod_namespaces[ns_id]->htbl_id.tbl, obj_id,
+				    g_mod_namespaces[ns_id]->htbl_id.tbl_params);
+
+	if (rc)
+		return rc;
+
+	rc = rhashtable_remove_fast(&g_mod_namespaces[ns_id]->htbl_name.tbl, obj_name,
+				    g_mod_namespaces[ns_id]->htbl_name.tbl_params);
+
+	return rc;
+}
+
+/* lookup an object using hash key from namespace */
+void *kparser_namespace_lookup(enum kparser_global_namespace_ids ns_id,
+			       const struct kparser_hkey *key)
+{
+	void *ret;
+
+	if (ns_id <= KPARSER_NS_INVALID || ns_id >= KPARSER_NS_MAX)
+		return NULL;
+
+	if (!g_mod_namespaces[ns_id])
+		return NULL;
+
+	ret = rhashtable_lookup(&g_mod_namespaces[ns_id]->htbl_id.tbl,
+				&key->id,
+				g_mod_namespaces[ns_id]->htbl_id.tbl_params);
+
+	if (ret)
+		return ret;
+
+	ret = rhashtable_lookup(&g_mod_namespaces[ns_id]->htbl_name.tbl,
+				key->name,
+				g_mod_namespaces[ns_id]->htbl_name.tbl_params);
+
+	return ret;
+}
+
+/* insert an object using hash key into namespace */
+int kparser_namespace_insert(enum kparser_global_namespace_ids ns_id,
+			     struct rhash_head *obj_id,
+			     struct rhash_head *obj_name)
+{
+	int rc;
+
+	if (ns_id <= KPARSER_NS_INVALID || ns_id >= KPARSER_NS_MAX)
+		return -EINVAL;
+
+	if (!g_mod_namespaces[ns_id])
+		return -ENOENT;
+
+	rc = rhashtable_insert_fast(&g_mod_namespaces[ns_id]->htbl_id.tbl, obj_id,
+				    g_mod_namespaces[ns_id]->htbl_id.tbl_params);
+	if (rc)
+		return rc;
+
+	rc = rhashtable_insert_fast(&g_mod_namespaces[ns_id]->htbl_name.tbl, obj_name,
+				    g_mod_namespaces[ns_id]->htbl_name.tbl_params);
+
+	return rc;
+}
+
+/* allocate the manadatory very first response header (rsp) for netlink reply msg */
+int alloc_first_rsp(struct kparser_cmd_rsp_hdr **rsp, size_t *rsp_len, int nsid)
+{
+	if (!rsp || *rsp || !rsp_len || (*rsp_len != 0))
+		return -EINVAL;
+
+	*rsp = kzalloc(sizeof(**rsp), GFP_KERNEL);
+	if (!(*rsp)) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, ":kzalloc failed for rsp, size:%lu\n",
+					 sizeof(**rsp));
+		return -ENOMEM;
+	}
+
+	*rsp_len = sizeof(struct kparser_cmd_rsp_hdr);
+	(*rsp)->object.namespace_id = nsid;
+	(*rsp)->objects_len = 0;
+	return 0;
+}
+
+/* initialize kParser's name space manager contexts */
+int kparser_init(void)
+{
+	int err, i, j;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	for (i = 0; i < (sizeof(g_mod_namespaces) /
+				sizeof(g_mod_namespaces[0])); i++) {
+		if (!g_mod_namespaces[i])
+			continue;
+
+		err = rhashtable_init(&g_mod_namespaces[i]->htbl_name.tbl,
+				      &g_mod_namespaces[i]->htbl_name.tbl_params);
+		if (err)
+			goto handle_error;
+
+		err = rhashtable_init(&g_mod_namespaces[i]->htbl_id.tbl,
+				      &g_mod_namespaces[i]->htbl_id.tbl_params);
+		if (err)
+			goto handle_error;
+
+		g_mod_namespaces[i]->bv_len =
+			((KPARSER_KMOD_ID_MAX - KPARSER_KMOD_ID_MIN) /
+			 BITS_PER_TYPE(unsigned long)) + 1;
+
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "bv_len:%lu, total_bytes:%lu, range:[%d:%d]\n",
+					 g_mod_namespaces[i]->bv_len,
+					 sizeof(unsigned long) * g_mod_namespaces[i]->bv_len,
+					 KPARSER_KMOD_ID_MAX, KPARSER_KMOD_ID_MIN);
+
+		g_mod_namespaces[i]->bv = kcalloc(g_mod_namespaces[i]->bv_len,
+						  sizeof(unsigned long),
+						  GFP_KERNEL);
+
+		if (!g_mod_namespaces[i]->bv) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "kzalloc() failed");
+			goto handle_error;
+		}
+
+		memset(g_mod_namespaces[i]->bv, 0xff,
+		       g_mod_namespaces[i]->bv_len * sizeof(unsigned long));
+	}
+
+	memset(kparser_fast_lookup_array, 0, sizeof(kparser_fast_lookup_array));
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+
+	return 0;
+
+handle_error:
+	for (j = 0; j < i; j++) {
+		if (!g_mod_namespaces[j])
+			continue;
+
+		rhashtable_destroy(&g_mod_namespaces[j]->htbl_name.tbl);
+		rhashtable_destroy(&g_mod_namespaces[j]->htbl_id.tbl);
+
+		kparser_free(g_mod_namespaces[j]->bv);
+		g_mod_namespaces[j]->bv_len = 0;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+
+	return err;
+}
+
+/* de-initialize kParser's name space manager contexts and free and remove all entries */
+int kparser_deinit(void)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+	for (i = 0; i < ARRAY_SIZE(g_mod_namespaces); i++) {
+		if (!g_mod_namespaces[i])
+			continue;
+
+		rhashtable_destroy(&g_mod_namespaces[i]->htbl_name.tbl);
+		rhashtable_free_and_destroy(&g_mod_namespaces[i]->htbl_id.tbl,
+					    g_mod_namespaces[i]->free_handler, NULL);
+
+		kparser_free(g_mod_namespaces[i]->bv);
+
+		g_mod_namespaces[i]->bv_len = 0;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return 0;
+}
+
+/* pre-process handler for all the netlink msg processors */
+static inline const struct kparser_conf_cmd
+*kparser_config_handler_preprocess(const void *cmdarg,
+				   size_t cmdarglen, struct kparser_cmd_rsp_hdr **rsp,
+				   size_t *rsp_len)
+{
+	enum kparser_global_namespace_ids ns_id;
+	const struct kparser_conf_cmd *conf;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	conf = cmdarg;
+	if (!conf || cmdarglen < sizeof(*conf) || !rsp || *rsp || !rsp_len ||
+	    (*rsp_len != 0) || conf->namespace_id <= KPARSER_NS_INVALID ||
+	    conf->namespace_id >= KPARSER_NS_MAX) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "[%p %lu %p %p %p %lu %d]\n",
+					 conf, cmdarglen, rsp, *rsp, rsp_len,
+					 *rsp_len, conf->namespace_id);
+		goto err_return;
+	}
+
+	ns_id = conf->namespace_id;
+
+	if (!g_mod_namespaces[ns_id])
+		goto err_return;
+
+	if (!g_mod_namespaces[ns_id]->create_handler)
+		goto err_return;
+
+	rc = alloc_first_rsp(rsp, rsp_len, conf->namespace_id);
+	if (rc) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "alloc_first_rsp() failed, rc:%d\n", rc);
+		goto err_return;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return cmdarg;
+
+err_return:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return NULL;
+}
+
+#define KPARSER_CONFIG_HANDLER_PRE()					\
+do {									\
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");		\
+	conf = kparser_config_handler_preprocess(cmdarg, cmdarglen,	\
+			rsp, rsp_len);					\
+	if (!conf)							\
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");	\
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");		\
+}									\
+while (0)
+
+/* netlink msg processors for create */
+int kparser_config_handler_add(const void *cmdarg, size_t cmdarglen,
+			       struct kparser_cmd_rsp_hdr **rsp,
+			       size_t *rsp_len,
+			       void *extack, int *err)
+{
+	const struct kparser_conf_cmd *conf;
+
+	KPARSER_CONFIG_HANDLER_PRE();
+
+	if (!conf)
+		return KPARSER_ATTR_UNSPEC;
+
+	if (!g_mod_namespaces[conf->namespace_id]->create_handler)
+		return KPARSER_ATTR_UNSPEC;
+
+	return g_mod_namespaces[conf->namespace_id]->create_handler(conf, cmdarglen,
+								    rsp,
+								    rsp_len,
+								    "create",
+								    extack, err);
+}
+
+/* netlink msg processors for update */
+int kparser_config_handler_update(const void *cmdarg, size_t cmdarglen,
+				  struct kparser_cmd_rsp_hdr **rsp,
+				  size_t *rsp_len, void *extack, int *err)
+{
+	const struct kparser_conf_cmd *conf;
+
+	KPARSER_CONFIG_HANDLER_PRE();
+
+	if (!conf)
+		return KPARSER_ATTR_UNSPEC;
+
+	if (!g_mod_namespaces[conf->namespace_id]->update_handler)
+		return KPARSER_ATTR_UNSPEC;
+
+	return g_mod_namespaces[conf->namespace_id]->update_handler(conf, cmdarglen,
+								    rsp,
+								    rsp_len,
+								    "update",
+								    extack, err);
+}
+
+/* netlink msg processors for read */
+int kparser_config_handler_read(const void *cmdarg, size_t cmdarglen,
+				struct kparser_cmd_rsp_hdr **rsp,
+				size_t *rsp_len, void *extack, int *err)
+{
+	const struct kparser_conf_cmd *conf;
+
+	KPARSER_CONFIG_HANDLER_PRE();
+
+	if (!conf)
+		return KPARSER_ATTR_UNSPEC;
+
+	if (!g_mod_namespaces[conf->namespace_id]->read_handler)
+		return KPARSER_ATTR_UNSPEC;
+
+	return g_mod_namespaces[conf->namespace_id]->read_handler(&conf->obj_key, rsp, rsp_len,
+			conf->recursive_read_delete, "read", extack, err);
+}
+
+/* netlink msg processors for delete */
+int kparser_config_handler_delete(const void *cmdarg, size_t cmdarglen,
+				  struct kparser_cmd_rsp_hdr **rsp,
+				  size_t *rsp_len, void *extack, int *err)
+{
+	const struct kparser_conf_cmd *conf;
+
+	KPARSER_CONFIG_HANDLER_PRE();
+
+	if (!conf)
+		return KPARSER_ATTR_UNSPEC;
+
+	if (!g_mod_namespaces[conf->namespace_id]->del_handler)
+		return KPARSER_ATTR_UNSPEC;
+
+	return g_mod_namespaces[conf->namespace_id]->del_handler(&conf->obj_key, rsp, rsp_len,
+			conf->recursive_read_delete, "delete", extack, err);
+}
diff --git a/net/kparser/kparser_cmds_dump_ops.c b/net/kparser/kparser_cmds_dump_ops.c
new file mode 100644
index 000000000..58c867a7e
--- /dev/null
+++ b/net/kparser/kparser_cmds_dump_ops.c
@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser_cmds_dump_ops.c - kParser KMOD-CLI debug dump operations
+ *
+ * Author:      Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#include "kparser.h"
+
+/* forward declarations of dump functions which dump config structures for debug purposes */
+static void kparser_dump_node(const struct kparser_parse_node *obj);
+static void kparser_dump_proto_table(const struct kparser_proto_table *obj);
+static void kparser_dump_tlv_parse_node(const struct kparser_parse_tlv_node *obj);
+static void kparser_dump_metadatatable(const struct kparser_metadata_table *obj);
+static void kparser_dump_cond_tables(const struct kparser_condexpr_tables *obj);
+
+/* debug code: dump kparser_parameterized_len structure */
+static void kparser_dump_param_len(const struct kparser_parameterized_len *pflen)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!pflen) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "pflen.src_off:%u\n", pflen->src_off);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "pflen.size:%u\n", pflen->size);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "pflen.endian:%d\n", pflen->endian);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "pflen.mask:%u\n", pflen->mask);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "pflen.right_shift:%u\n", pflen->right_shift);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "pflen.multiplier:%u\n", pflen->multiplier);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "pflen.add_value:%u\n", pflen->add_value);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_parameterized_next_proto structure */
+static void kparser_dump_param_next_proto(const struct kparser_parameterized_next_proto
+					  *pfnext_proto)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!pfnext_proto) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "pfnext_proto.src_off:%u\n", pfnext_proto->src_off);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "pfnext_proto.mask:%u\n", pfnext_proto->mask);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "pfnext_proto.size:%u\n", pfnext_proto->size);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "pfnext_proto.right_shift:%u\n", pfnext_proto->right_shift);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_condexpr_expr structure */
+static void kparser_dump_cond_expr(const struct kparser_condexpr_expr *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "type:%u, src_off:%u, len:%u, mask:%04x value:%04x\n",
+				 obj->type, obj->src_off,
+				 obj->length, obj->mask, obj->value);
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_condexpr_table structure */
+static void kparser_dump_cond_table(const struct kparser_condexpr_table *obj)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "default_fail:%d, type:%u\n", obj->default_fail, obj->type);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "num_ents:%u, entries:%p\n", obj->num_ents, obj->entries);
+
+	if (!obj->entries)
+		goto done;
+
+	for (i = 0; i < obj->num_ents; i++)
+		kparser_dump_cond_expr(obj->entries[i]);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_condexpr_tables structure */
+static void kparser_dump_cond_tables(const struct kparser_condexpr_tables *obj)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "num_ents:%u, entries:%p\n", obj->num_ents, obj->entries);
+	if (!obj->entries)
+		goto done;
+
+	for (i = 0; i < obj->num_ents; i++)
+		kparser_dump_cond_table(obj->entries[i]);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_proto_node structure */
+static void kparser_dump_proto_node(const struct kparser_proto_node *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "encap:%u\n", obj->encap);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "overlay:%u\n", obj->overlay);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "min_len:%lu\n", obj->min_len);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "ops.flag_fields_length:%d\n", obj->ops.flag_fields_length);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "ops.len_parameterized:%d\n", obj->ops.len_parameterized);
+	kparser_dump_param_len(&obj->ops.pflen);
+
+	kparser_dump_param_next_proto(&obj->ops.pfnext_proto);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "ops.cond_exprs_parameterized:%d\n",
+				 obj->ops.cond_exprs_parameterized);
+	kparser_dump_cond_tables(&obj->ops.cond_exprs);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_proto_tlvs_table structure */
+static void kparser_dump_proto_tlvs_table(const struct kparser_proto_tlvs_table *obj)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "num_ents:%u, entries:%p\n", obj->num_ents, obj->entries);
+	if (!obj->entries)
+		goto done;
+
+	for (i = 0; i < obj->num_ents; i++) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "[%d]: val: %04x\n", i, obj->entries[i].type);
+		kparser_dump_tlv_parse_node(obj->entries[i].node);
+	}
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_parse_tlv_node structure */
+static void kparser_dump_tlv_parse_node(const struct kparser_parse_tlv_node *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "name: %s\n", obj->name);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "unknown_tlv_type_ret:%d\n", obj->unknown_overlay_ret);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "proto_tlv_node.min_len: %lu\n", obj->proto_tlv_node.min_len);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "proto_tlv_node.max_len: %lu\n", obj->proto_tlv_node.max_len);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "proto_tlv_node.is_padding: %u\n", obj->proto_tlv_node.is_padding);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "proto_tlv_node.overlay_type_parameterized: %u\n",
+				 obj->proto_tlv_node.ops.overlay_type_parameterized);
+	kparser_dump_param_next_proto(&obj->proto_tlv_node.ops.pfoverlay_type);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "proto_tlv_node.cond_exprs_parameterized: %u\n",
+		 obj->proto_tlv_node.ops.cond_exprs_parameterized);
+	kparser_dump_cond_tables(&obj->proto_tlv_node.ops.cond_exprs);
+
+	kparser_dump_proto_tlvs_table(obj->overlay_table);
+	kparser_dump_tlv_parse_node(obj->overlay_wildcard_node);
+	kparser_dump_metadatatable(obj->metadata_table);
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_parse_tlvs_node structure */
+static void kparser_dump_tlvs_parse_node(const struct kparser_parse_tlvs_node *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	kparser_dump_proto_tlvs_table(obj->tlv_proto_table);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "unknown_tlv_type_ret:%d\n", obj->unknown_tlv_type_ret);
+
+	kparser_dump_tlv_parse_node(obj->tlv_wildcard_node);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config:max_loop: %u\n", obj->config.max_loop);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config:max_non: %u\n", obj->config.max_non);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config:max_plen: %u\n", obj->config.max_plen);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config:max_c_pad: %u\n", obj->config.max_c_pad);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config:disp_limit_exceed: %u\n", obj->config.disp_limit_exceed);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config:exceed_loop_cnt_is_err: %u\n",
+				 obj->config.exceed_loop_cnt_is_err);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_proto_tlvs_node structure */
+static void kparser_dump_tlvs_proto_node(const struct kparser_proto_tlvs_node *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	kparser_dump_proto_node(&obj->proto_node);
+
+	kparser_dump_param_len(&obj->ops.pfstart_offset);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "ops.len_parameterized:%d\n", obj->ops.len_parameterized);
+	kparser_dump_param_len(&obj->ops.pflen);
+	kparser_dump_param_next_proto(&obj->ops.pftype);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "start_offset:%lu\n", obj->start_offset);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "pad1_val:%u\n", obj->pad1_val);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "padn_val:%u\n", obj->padn_val);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "eol_val:%u\n", obj->eol_val);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "pad1_enable:%u\n", obj->pad1_enable);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "padn_enable:%u\n", obj->padn_enable);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "eol_enable:%u\n", obj->eol_enable);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "fixed_start_offset:%u\n", obj->fixed_start_offset);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "min_len:%lu\n", obj->min_len);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_flag_field structure */
+static void kparser_dump_flag_field(const struct kparser_flag_field *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "flag:%04x, mask:%04x size:%lu\n",
+				 obj->flag, obj->mask, obj->size);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_flag_fields structure */
+static void kparser_dump_flag_fields(const struct kparser_flag_fields *obj)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "num_idx:%lu, fields:%p\n", obj->num_idx, obj->fields);
+
+	if (!obj->fields)
+		goto done;
+
+	for (i = 0; i < obj->num_idx; i++)
+		kparser_dump_flag_field(&obj->fields[i]);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_parse_flag_field_node structure */
+static void kparser_dump_parse_flag_field_node(const struct kparser_parse_flag_field_node *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "name: %s\n", obj->name);
+
+	kparser_dump_metadatatable(obj->metadata_table);
+	kparser_dump_cond_tables(&obj->ops.cond_exprs);
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_proto_flag_fields_table structure */
+static void kparser_dump_proto_flag_fields_table(const struct kparser_proto_flag_fields_table *obj)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "num_ents:%d, entries:%p\n", obj->num_ents, obj->entries);
+
+	if (!obj->entries)
+		goto done;
+
+	for (i = 0; i < obj->num_ents; i++) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "proto_flag_fields_table_entry_flag:%x\n",
+					 obj->entries[i].flag);
+		kparser_dump_parse_flag_field_node(obj->entries[i].node);
+	}
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_parse_flag_fields_node structure */
+static void kparser_dump_flags_parse_node(const struct kparser_parse_flag_fields_node *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	kparser_dump_proto_flag_fields_table(obj->flag_fields_proto_table);
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_proto_flag_fields_node structure */
+static void kparser_dump_flags_proto_node(const struct kparser_proto_flag_fields_node *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	kparser_dump_proto_node(&obj->proto_node);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "ops.get_flags_parameterized:%d\n",
+				 obj->ops.get_flags_parameterized);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "ops.pfget_flags: src_off:%u mask:%04x size:%u\n",
+		 obj->ops.pfget_flags.src_off,
+		 obj->ops.pfget_flags.mask,
+		 obj->ops.pfget_flags.size);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "ops.start_fields_offset_parameterized:%d\n",
+				 obj->ops.start_fields_offset_parameterized);
+	kparser_dump_param_len(&obj->ops.pfstart_fields_offset);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "ops.flag_feilds_len:%u ops.hdr_length:%u\n",
+				 obj->ops.flag_fields_len, obj->ops.hdr_length);
+
+	kparser_dump_flag_fields(obj->flag_fields);
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_metadata_table structure */
+static void kparser_dump_metadatatable(const struct kparser_metadata_table *obj)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "num_ents:%u, entries:%p\n", obj->num_ents, obj->entries);
+	if (!obj->entries)
+		goto done;
+
+	for (i = 0; i < obj->num_ents; i++)
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "mde[%d]:%04x\n", i, obj->entries[i].val);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_proto_table structure */
+static void kparser_dump_proto_table(const struct kparser_proto_table *obj)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "num_ents:%u, entries:%p\n", obj->num_ents, obj->entries);
+	if (!obj->entries)
+		goto done;
+
+	for (i = 0; i < obj->num_ents; i++) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "[%d]: val: %d\n", i, obj->entries[i].value);
+		kparser_dump_node(obj->entries[i].node);
+	}
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump kparser_parse_node structure */
+static void kparser_dump_node(const struct kparser_parse_node *obj)
+{
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "name: %s: type: %d\n", obj->name, obj->node_type);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "unknown_ret:%d\n", obj->unknown_ret);
+
+	switch (obj->node_type) {
+	case KPARSER_NODE_TYPE_PLAIN:
+		kparser_dump_proto_node(&obj->proto_node);
+		break;
+
+	case KPARSER_NODE_TYPE_TLVS:
+		kparser_dump_tlvs_proto_node(&obj->tlvs_proto_node);
+		kparser_dump_tlvs_parse_node((const struct kparser_parse_tlvs_node *)obj);
+		break;
+
+	case KPARSER_NODE_TYPE_FLAG_FIELDS:
+		kparser_dump_flags_proto_node(&obj->flag_fields_proto_node);
+		kparser_dump_flags_parse_node((const struct kparser_parse_flag_fields_node *)obj);
+		break;
+
+	default:
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "unknown node type:%d\n", obj->node_type);
+		break;
+	}
+
+	kparser_dump_proto_table(obj->proto_table);
+
+	kparser_dump_node(obj->wildcard_node);
+
+	kparser_dump_metadatatable(obj->metadata_table);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+/* debug code: dump whole parse tree from kparser_parser structure */
+void kparser_dump_parser_tree(const struct kparser_parser *obj)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	if (!obj) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "obj NULL");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "name: %s\n", obj->name);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "config: flags:%02x\n", obj->config.flags);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config: max_nodes:%u\n", obj->config.max_nodes);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config: max_encaps:%u\n", obj->config.max_encaps);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config: max_frames:%u\n", obj->config.max_frames);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config: metameta_size:%lu\n", obj->config.metameta_size);
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "config: frame_size:%lu\n", obj->config.frame_size);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "cntrs_len: %lu\n", obj->cntrs_len);
+	for (i = 0; i < (sizeof(obj->cntrs_conf.cntrs) /
+				sizeof(obj->cntrs_conf.cntrs[0])); i++) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "cntrs:%d: max_value:%u\n", i,
+					 obj->cntrs_conf.cntrs[i].max_value);
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "cntrs:%d: array_limit:%u\n", i,
+					 obj->cntrs_conf.cntrs[i].array_limit);
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "cntrs:%d: el_size:%lu\n", i,
+					 obj->cntrs_conf.cntrs[i].el_size);
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "cntrs:%d: reset_on_encap:%d\n", i,
+					 obj->cntrs_conf.cntrs[i].reset_on_encap);
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "cntrs:%d: overwrite_last:%d\n", i,
+					 obj->cntrs_conf.cntrs[i].overwrite_last);
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "cntrs:%d: error_on_exceeded:%d\n", i,
+					 obj->cntrs_conf.cntrs[i].error_on_exceeded);
+		if (obj->cntrs)
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "cntr[%d]:%d", i, obj->cntrs->cntr[i]);
+	}
+
+	kparser_dump_node(obj->root_node);
+	kparser_dump_node(obj->okay_node);
+	kparser_dump_node(obj->fail_node);
+	kparser_dump_node(obj->atencap_node);
+
+done:
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
diff --git a/net/kparser/kparser_cmds_ops.c b/net/kparser/kparser_cmds_ops.c
new file mode 100644
index 000000000..b642a8d14
--- /dev/null
+++ b/net/kparser/kparser_cmds_ops.c
@@ -0,0 +1,3778 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser_cmds_ops.c - kParser KMOD-CLI netlink request operations handlers
+ *
+ * Author:      Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <net/kparser.h>
+#include <linux/netlink.h>
+
+#include "kparser.h"
+
+/* global netlink cmd handler mutex, all handlers must run within protection of this mutex
+ * NOTE: never use this mutex on data path operations since they can run under interrupt contexts
+ */
+static DEFINE_MUTEX(kparser_config_lock);
+
+/* global counter config, shared among all the parsers */
+static struct kparser_cntrs_conf cntrs_conf = {};
+static __u8 cntrs_conf_idx;
+
+void *kparser_fast_lookup_array[KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_STOP -
+	KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_START + 1];
+
+/* common pre-process code for create handlers */
+static inline bool
+kparser_cmd_create_pre_process(const char *op,
+			       const struct kparser_conf_cmd *conf,
+			       const struct kparser_hkey *argkey, struct kparser_hkey *newkey,
+			       void **kobj, size_t kobjsize, struct kparser_cmd_rsp_hdr *rsp,
+			       size_t glueoffset,
+			       void *extack, int *err)
+{
+	struct kparser_glue *glue;
+
+	if (kparser_conf_key_manager(conf->namespace_id, argkey, newkey, rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		return false;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OP:%s Key{%s:%d}:{%s:%d}\n",
+				 op, argkey->name, argkey->id,
+				 newkey->name, newkey->id);
+
+	if (kparser_namespace_lookup(conf->namespace_id, newkey)) {
+		rsp->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Duplicate object HKey:{%s:%u}",
+				       op, newkey->name, newkey->id);
+		return false;
+	}
+
+	*kobj = kzalloc(kobjsize, GFP_KERNEL);
+	if (!(*kobj)) {
+		rsp->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Object allocation failed for size:%lu",
+				       op, kobjsize);
+		return false;
+	}
+
+	glue = (*kobj) + glueoffset;
+	glue->key = *newkey;
+
+	rsp->op_ret_code = kparser_namespace_insert(conf->namespace_id,
+						    &glue->ht_node_id, &glue->ht_node_name);
+	if (rsp->op_ret_code) {
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Htbl insert err:%d",
+				       op, rsp->op_ret_code);
+		return false;
+	}
+
+	glue->config = *conf;
+	kref_init(&glue->refcount);
+
+	rsp->key = *newkey;
+	rsp->object.conf_keys_bv = conf->conf_keys_bv;
+	rsp->object = *conf;
+
+	return true;
+}
+
+/* Following functions create kParser object handlers for netlink msgs
+ * create handler for object conditionals
+ * NOTE: All handlers startting from here must hold mutex kparser_config_lock
+ * before any work can be done and must release that mutex before return.
+ */
+int kparser_create_cond_exprs(const struct kparser_conf_cmd *conf,
+			      size_t conf_len,
+			      struct kparser_cmd_rsp_hdr **rsp,
+			      size_t *rsp_len, const char *op,
+			      void *extack, int *err)
+{
+	struct kparser_glue_condexpr_expr *kobj = NULL;
+	const struct kparser_conf_condexpr *arg;
+	struct kparser_hkey key;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->cond_conf;
+
+	if (!kparser_cmd_create_pre_process(op, conf, &arg->key, &key,
+					    (void **)&kobj, sizeof(*kobj), *rsp,
+					    offsetof(struct
+						     kparser_glue_condexpr_expr,
+						     glue), extack, err))
+		goto done;
+
+	kobj->expr = arg->config;
+
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.cond_conf = kobj->glue.config.cond_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		kparser_free(kobj);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_CONDEXPRS);
+}
+
+/* read handler for object conditionals */
+int kparser_read_cond_exprs(const struct kparser_hkey *key,
+			    struct kparser_cmd_rsp_hdr **rsp,
+			    size_t *rsp_len, __u8 recursive_read,
+			    const char *op,
+			    void *extack, int *err)
+{
+	struct kparser_glue_condexpr_expr *kobj;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kobj = kparser_namespace_lookup(KPARSER_NS_CONDEXPRS, key);
+	if (!kobj) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Object key not found:{%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = kobj->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kobj->glue.config.conf_keys_bv;
+	(*rsp)->object.cond_conf = kobj->glue.config.cond_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_CONDEXPRS);
+}
+
+/* create handler for object conditionals table entry */
+static bool kparser_create_cond_table_ent(const struct kparser_conf_table *arg,
+					  struct kparser_glue_condexpr_table **proto_table,
+					  struct kparser_cmd_rsp_hdr *rsp,
+					  const char *op,
+					  void *extack, int *err)
+{
+	const struct kparser_glue_condexpr_expr *kcondent;
+	void *realloced_mem;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	*proto_table = kparser_namespace_lookup(KPARSER_NS_CONDEXPRS_TABLE, &arg->key);
+	if (!(*proto_table)) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Object key not found:{%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		return false;
+	}
+
+	kcondent = kparser_namespace_lookup(KPARSER_NS_CONDEXPRS, &arg->elem_key);
+	if (!kcondent) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Object key not found:{%s:%u}",
+				       op, arg->elem_key.name, arg->elem_key.id);
+		return false;
+	}
+
+	(*proto_table)->table.num_ents++;
+	realloced_mem = krealloc((*proto_table)->table.entries,
+				 (*proto_table)->table.num_ents *
+				 sizeof(struct kparser_condexpr_expr *),
+				 GFP_KERNEL | ___GFP_ZERO);
+	if (!realloced_mem) {
+		rsp->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:krealloc() err, ents:%d, size:%lu",
+				       op, (*proto_table)->table.num_ents,
+				       sizeof(struct kparser_condexpr_expr));
+		return false;
+	}
+	rcu_assign_pointer((*proto_table)->table.entries, realloced_mem);
+
+	(*proto_table)->table.entries[(*proto_table)->table.num_ents - 1] = &kcondent->expr;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return true;
+}
+
+/* create handler for object conditionals table */
+int kparser_create_cond_table(const struct kparser_conf_cmd *conf,
+			      size_t conf_len,
+			      struct kparser_cmd_rsp_hdr **rsp,
+			      size_t *rsp_len, const char *op,
+			      void *extack, int *err)
+{
+	struct kparser_glue_condexpr_table *proto_table = NULL;
+	const struct kparser_conf_table *arg;
+	struct kparser_hkey key;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->table_conf;
+
+	/* create a table entry */
+	if (arg->add_entry) {
+		if (kparser_create_cond_table_ent(arg, &proto_table, *rsp, op,
+						  extack, err) == false)
+			goto done;
+		goto skip_table_create;
+	}
+
+	if (!kparser_cmd_create_pre_process(op, conf, &arg->key, &key,
+					    (void **)&proto_table, sizeof(*proto_table), *rsp,
+					    offsetof(struct
+						     kparser_glue_condexpr_table,
+						     glue), extack, err))
+		goto done;
+
+	proto_table->glue.config.namespace_id = conf->namespace_id;
+	proto_table->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	proto_table->glue.config.table_conf = *arg;
+	proto_table->glue.config.table_conf.key = key;
+	kref_init(&proto_table->glue.refcount);
+	proto_table->table.default_fail = arg->optional_value1;
+	proto_table->table.type = arg->optional_value2;
+
+skip_table_create:
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.table_conf = *arg;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0) {
+		if (proto_table && !arg->add_entry)
+			kparser_free(proto_table);
+	}
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_CONDEXPRS_TABLE);
+}
+
+/* read handler for object conditionals table */
+int kparser_read_cond_table(const struct kparser_hkey *key,
+			    struct kparser_cmd_rsp_hdr **rsp,
+			    size_t *rsp_len, __u8 recursive_read,
+			    const char *op,
+			    void *extack, int *err)
+{
+	const struct kparser_glue_condexpr_table *proto_table;
+	const struct kparser_glue_condexpr_expr *kcondent;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	proto_table = kparser_namespace_lookup(KPARSER_NS_CONDEXPRS_TABLE, key);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Object key not found, key:{%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = proto_table->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n",
+				 (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = proto_table->glue.config.conf_keys_bv;
+	(*rsp)->object.table_conf = proto_table->glue.config.table_conf;
+	(*rsp)->object.table_conf.optional_value1 = proto_table->table.default_fail;
+	(*rsp)->object.table_conf.optional_value2 = proto_table->table.type;
+
+	for (i = 0; i < proto_table->table.num_ents; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = proto_table->glue.config.namespace_id;
+		objects[i].table_conf = proto_table->glue.config.table_conf;
+		if (!proto_table->table.entries)
+			continue;
+		kcondent = container_of(proto_table->table.entries[i],
+					struct kparser_glue_condexpr_expr, expr);
+		objects[i].table_conf.elem_key = kcondent->glue.key;
+	}
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_CONDEXPRS_TABLE);
+}
+
+/* create handler for object conditionals table's list entry */
+static bool kparser_create_cond_tables_ent(const struct kparser_conf_table *arg,
+					   struct kparser_glue_condexpr_tables **proto_table,
+					   struct kparser_cmd_rsp_hdr *rsp,
+					   const char *op,
+					   void *extack, int *err)
+{
+	const struct kparser_glue_condexpr_table *kcondent;
+	void *realloced_mem;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	*proto_table = kparser_namespace_lookup(KPARSER_NS_CONDEXPRS_TABLES, &arg->key);
+	if (!(*proto_table)) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Object key not found, key:{%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		return false;
+	}
+
+	kcondent = kparser_namespace_lookup(KPARSER_NS_CONDEXPRS_TABLE, &arg->elem_key);
+	if (!kcondent) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Object key not found, key:{%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		return false;
+	}
+
+	(*proto_table)->table.num_ents++;
+	realloced_mem = krealloc((*proto_table)->table.entries, (*proto_table)->table.num_ents *
+				 sizeof(struct kparser_condexpr_table *), GFP_KERNEL | ___GFP_ZERO);
+	if (!realloced_mem) {
+		rsp->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: krealloc() err, ents:%d, size:%lu",
+				       op, (*proto_table)->table.num_ents,
+				       sizeof(struct kparser_condexpr_table *));
+		return false;
+	}
+	rcu_assign_pointer((*proto_table)->table.entries, realloced_mem);
+
+	(*proto_table)->table.entries[(*proto_table)->table.num_ents - 1] = &kcondent->table;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return true;
+}
+
+/* create handler for object conditionals table's list */
+int kparser_create_cond_tables(const struct kparser_conf_cmd *conf,
+			       size_t conf_len,
+			       struct kparser_cmd_rsp_hdr **rsp,
+			       size_t *rsp_len, const char *op,
+			       void *extack, int *err)
+{
+	struct kparser_glue_condexpr_tables *proto_table = NULL;
+	const struct kparser_conf_table *arg;
+	struct kparser_hkey key;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->table_conf;
+
+	/* create a table entry */
+	if (arg->add_entry) {
+		if (kparser_create_cond_tables_ent(arg, &proto_table, *rsp, op,
+						   extack, err) == false)
+			goto done;
+		goto skip_table_create;
+	}
+
+	if (!kparser_cmd_create_pre_process(op, conf, &arg->key, &key,
+					    (void **)&proto_table, sizeof(*proto_table), *rsp,
+					    offsetof(struct
+						     kparser_glue_condexpr_tables,
+						     glue), extack, err))
+		goto done;
+
+	proto_table->glue.config.namespace_id = conf->namespace_id;
+	proto_table->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	proto_table->glue.config.table_conf = *arg;
+	proto_table->glue.config.table_conf.key = key;
+	kref_init(&proto_table->glue.refcount);
+
+skip_table_create:
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.table_conf = *arg;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0) {
+		if (proto_table && !arg->add_entry)
+			kparser_free(proto_table);
+	}
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_CONDEXPRS_TABLES);
+}
+
+/* read handler for object conditionals table's list */
+int kparser_read_cond_tables(const struct kparser_hkey *key,
+			     struct kparser_cmd_rsp_hdr **rsp,
+			     size_t *rsp_len, __u8 recursive_read,
+			     const char *op,
+			     void *extack, int *err)
+
+{
+	const struct kparser_glue_condexpr_tables *proto_table;
+	const struct kparser_glue_condexpr_table *kcondent;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	proto_table = kparser_namespace_lookup(KPARSER_NS_CONDEXPRS_TABLES, key);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object key not found, key:{%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = proto_table->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = proto_table->glue.config.conf_keys_bv;
+	(*rsp)->object.table_conf = proto_table->glue.config.table_conf;
+
+	for (i = 0; i < proto_table->table.num_ents; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 ":krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = proto_table->glue.config.namespace_id;
+		objects[i].table_conf = proto_table->glue.config.table_conf;
+		if (!proto_table->table.entries)
+			continue;
+		kcondent = container_of(proto_table->table.entries[i],
+					struct kparser_glue_condexpr_table, table);
+		objects[i].table_conf.elem_key = kcondent->glue.key;
+	}
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_CONDEXPRS_TABLES);
+}
+
+/* create handler for object counter */
+int kparser_create_counter(const struct kparser_conf_cmd *conf,
+			   size_t conf_len,
+			   struct kparser_cmd_rsp_hdr **rsp,
+			   size_t *rsp_len, const char *op,
+			   void *extack, int *err)
+{
+	struct kparser_glue_counter *kcntr = NULL;
+	const struct kparser_conf_cntr *arg;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->cntr_conf;
+
+	if (!arg->conf.valid_entry) {
+		(*rsp)->op_ret_code = EINVAL;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: counter entry is not valid", op);
+		goto done;
+	}
+
+	if (cntrs_conf_idx >= KPARSER_CNTR_NUM_CNTRS) {
+		(*rsp)->op_ret_code = EINVAL;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: counter index %d can not be >= %d",
+				       op, cntrs_conf_idx,
+				       KPARSER_CNTR_NUM_CNTRS);
+		goto done;
+	}
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object key {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	kcntr = kzalloc(sizeof(*kcntr), GFP_KERNEL);
+	if (!kcntr) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu",
+				       op, sizeof(*kcntr));
+		goto done;
+	}
+
+	kcntr->glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &kcntr->glue.ht_node_id, &kcntr->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err:%d",
+				       op, rc);
+		goto done;
+	}
+
+	kcntr->glue.config.namespace_id = conf->namespace_id;
+	kcntr->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	kcntr->glue.config.cntr_conf = *arg;
+	kcntr->glue.config.cntr_conf.key = key;
+	kref_init(&kcntr->glue.refcount);
+
+	kcntr->counter_cnf = arg->conf;
+	kcntr->counter_cnf.index = cntrs_conf_idx;
+
+	cntrs_conf.cntrs[cntrs_conf_idx] = kcntr->counter_cnf;
+
+	cntrs_conf_idx++;
+
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.cntr_conf = kcntr->glue.config.cntr_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		kparser_free(kcntr);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_COUNTER);
+}
+
+/* read handler for object counter */
+int kparser_read_counter(const struct kparser_hkey *key,
+			 struct kparser_cmd_rsp_hdr **rsp,
+			 size_t *rsp_len, __u8 recursive_read,
+			 const char *op,
+			 void *extack, int *err)
+{
+	struct kparser_glue_counter *kcntr;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kcntr = kparser_namespace_lookup(KPARSER_NS_COUNTER, key);
+	if (!kcntr) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Object key not found, key:{%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = kcntr->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kcntr->glue.config.conf_keys_bv;
+	(*rsp)->object.cntr_conf = kcntr->glue.config.cntr_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_COUNTER);
+}
+
+/* create handler for object counter table */
+int kparser_create_counter_table(const struct kparser_conf_cmd *conf,
+				 size_t conf_len,
+				 struct kparser_cmd_rsp_hdr **rsp,
+				 size_t *rsp_len, const char *op,
+				 void *extack, int *err)
+{
+	struct kparser_glue_counter_table *table = NULL;
+	const struct kparser_conf_table *arg;
+	struct kparser_glue_counter *kcntr;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->table_conf;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	/* create a table entry */
+	if (arg->add_entry) {
+		table = kparser_namespace_lookup(conf->namespace_id, &arg->key);
+		if (!table) {
+			(*rsp)->op_ret_code = ENOENT;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s:Object key not found, key:{%s:%u}",
+					       op, arg->key.name, arg->key.id);
+			goto done;
+		}
+		if (table->elems_cnt >= KPARSER_CNTR_NUM_CNTRS) {
+			(*rsp)->op_ret_code = EINVAL;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s:table full, elem cnt:%u",
+					       op, table->elems_cnt);
+			goto done;
+		}
+		kcntr = kparser_namespace_lookup(KPARSER_NS_COUNTER,
+						 &arg->elem_key);
+		if (!kcntr) {
+			(*rsp)->op_ret_code = ENOENT;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s:Object key not found, key:{%s:%u}",
+					       op, arg->elem_key.name,
+					       arg->elem_key.id);
+			goto done;
+		}
+		table->k_cntrs[table->elems_cnt++] = *kcntr;
+		goto skip_table_create;
+	}
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s:Object key duplicate, key:{%s:%u}",
+				       op, key.name, key.id);
+		goto done;
+	}
+
+	/* create counter table */
+	table = kzalloc(sizeof(*table), GFP_KERNEL);
+	if (!table) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu",
+				       op, sizeof(*table));
+		goto done;
+	}
+
+	table->glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &table->glue.ht_node_id, &table->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	table->glue.config.namespace_id = conf->namespace_id;
+	table->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	table->glue.config.table_conf = *arg;
+	table->glue.config.table_conf.key = key;
+	kref_init(&table->glue.refcount);
+
+skip_table_create:
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.table_conf = table->glue.config.table_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		if (table && !arg->add_entry)
+			kparser_free(table);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_COUNTER_TABLE);
+}
+
+/* read handler for object counter table */
+int kparser_read_counter_table(const struct kparser_hkey *key,
+			       struct kparser_cmd_rsp_hdr **rsp,
+			       size_t *rsp_len, __u8 recursive_read,
+			       const char *op,
+			       void *extack, int *err)
+{
+	const struct kparser_glue_counter_table *table;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	table = kparser_namespace_lookup(KPARSER_NS_COUNTER_TABLE, key);
+	if (!table) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object key not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = table->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = table->glue.config.conf_keys_bv;
+	(*rsp)->object.table_conf = table->glue.config.table_conf;
+
+	for (i = 0; i < KPARSER_CNTR_NUM_CNTRS; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = table->k_cntrs[i].glue.config.namespace_id;
+		objects[i].cntr_conf = table->k_cntrs[i].glue.config.cntr_conf;
+		objects[i].cntr_conf.conf = cntrs_conf.cntrs[i];
+	}
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_COUNTER_TABLE);
+}
+
+/* create handler for object metadata */
+int kparser_create_metadata(const struct kparser_conf_cmd *conf,
+			    size_t conf_len,
+			    struct kparser_cmd_rsp_hdr **rsp,
+			    size_t *rsp_len, const char *op,
+			    void *extack, int *err)
+{
+	struct kparser_glue_metadata_extract *kmde = NULL;
+	int rc, cntridx = 0, cntr_arr_idx = 0;
+	const struct kparser_conf_metadata *arg;
+	struct kparser_glue_counter *kcntr;
+	struct kparser_hkey key;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->md_conf;
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object key duplicate, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	kcntr = kparser_namespace_lookup(KPARSER_NS_COUNTER, &arg->counterkey);
+	if (kcntr)
+		cntridx = kcntr->counter_cnf.index + 1;
+
+	if (arg->type == KPARSER_METADATA_COUNTER) {
+		/* In this case, one of the counters must be provided. If not,
+		 * that is an error
+		 */
+		kcntr = kparser_namespace_lookup(KPARSER_NS_COUNTER,
+						 &arg->counter_data_key);
+		if (kcntr)
+			cntr_arr_idx = kcntr->counter_cnf.index + 1;
+
+		if (cntridx == 0 && cntr_arr_idx == 0) {
+			(*rsp)->op_ret_code = -ENOENT;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s: both counteridx and"
+					       " counterdata object keys are not"
+					       " found", op);
+			goto done;
+		} else {
+			if (cntr_arr_idx == 0)
+				cntr_arr_idx = cntridx;
+			else if (cntridx == 0)
+				cntridx = cntr_arr_idx;
+		}
+	}
+
+	kmde = kzalloc(sizeof(*kmde), GFP_KERNEL);
+	if (!kmde) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack, "%s: kzalloc() failed, size:%lu",
+				       op, sizeof(*kmde));
+		goto done;
+	}
+
+	kmde->glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &kmde->glue.ht_node_id, &kmde->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack, "%s: kparser_namespace_insert()"
+				       " err, rc:%d", op, rc);
+		goto done;
+	}
+
+	kmde->glue.config.namespace_id = conf->namespace_id;
+	kmde->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	kmde->glue.config.md_conf = *arg;
+	kmde->glue.config.md_conf.key = key;
+	kref_init(&kmde->glue.refcount);
+	INIT_LIST_HEAD(&kmde->glue.owner_list);
+	INIT_LIST_HEAD(&kmde->glue.owned_list);
+
+	if (!kparser_metadata_convert(arg, &kmde->mde, cntridx, cntr_arr_idx)) {
+		(*rsp)->op_ret_code = EINVAL;
+		NL_SET_ERR_MSG_FMT_MOD(extack, "%s: kparser_metadata_convert()"
+				       " err, rc:%d", op, rc);
+		goto done;
+	}
+
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.md_conf = kmde->glue.config.md_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		kparser_free(kmde);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_METADATA);
+}
+
+/* read handler for object metadata */
+int kparser_read_metadata(const struct kparser_hkey *key,
+			  struct kparser_cmd_rsp_hdr **rsp,
+			  size_t *rsp_len, __u8 recursive_read,
+			  const char *op,
+			  void *extack, int *err)
+{
+	const struct kparser_glue_metadata_extract *kmde;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kmde = kparser_namespace_lookup(KPARSER_NS_METADATA, key);
+	if (!kmde) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack, "%s: Object key not found,"
+				       " key:{%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = kmde->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kmde->glue.config.conf_keys_bv;
+	(*rsp)->object.md_conf = kmde->glue.config.md_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_METADATA);
+}
+
+/* delete handler for object metadata */
+int kparser_del_metadata(const struct kparser_hkey *key,
+			 struct kparser_cmd_rsp_hdr **rsp,
+			 size_t *rsp_len, __u8 recursive_read,
+			 const char *op,
+			 void *extack, int *err)
+{
+	struct kparser_glue_metadata_extract *kmde;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kmde = kparser_namespace_lookup(KPARSER_NS_METADATA, key);
+	if (!kmde) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack, "%s: Object key not found,"
+				       " key:{%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	if (kref_read(&kmde->glue.refcount) != 0) {
+		(*rsp)->op_ret_code = EBUSY;
+		NL_SET_ERR_MSG_FMT_MOD(extack, "%s: Metadata object is"
+				       " associated with a metalist, delete"
+				       " that metalist instead",
+				       op);
+		goto done;
+	}
+
+	rc = kparser_namespace_remove(KPARSER_NS_METADATA,
+				      &kmde->glue.ht_node_id, &kmde->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack, "%s: namespace remove error, rc: %d",
+				       op, rc);
+		goto done;
+	}
+
+	(*rsp)->key = kmde->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kmde->glue.config.conf_keys_bv;
+	(*rsp)->object.md_conf = kmde->glue.config.md_conf;
+
+	kparser_free(kmde);
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_METADATA);
+}
+
+/* free handler for object metadata */
+void kparser_free_metadata(void *ptr, void *arg)
+{
+	/* TODO: */
+}
+
+/* create handler for object metadata list */
+int kparser_create_metalist(const struct kparser_conf_cmd *conf,
+			    size_t conf_len,
+			    struct kparser_cmd_rsp_hdr **rsp,
+			    size_t *rsp_len, const char *op,
+			    void *extack, int *err)
+{
+	struct kparser_glue_metadata_extract *kmde = NULL;
+	struct kparser_glue_metadata_table *kmdl = NULL;
+	const struct kparser_conf_metadata_table *arg;
+	struct kparser_conf_cmd *objects = NULL;
+	struct kparser_hkey key;
+	void *realloced_mem;
+	int rc, i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->mdl_conf;
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object key, {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	kmdl = kzalloc(sizeof(*kmdl), GFP_KERNEL);
+	if (!kmdl) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu",
+				       op, sizeof(*kmdl));
+		goto done;
+	}
+
+	kmdl->glue.key = key;
+	kmdl->glue.config.namespace_id = conf->namespace_id;
+	kmdl->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	kmdl->glue.config.mdl_conf = *arg;
+	kmdl->glue.config.mdl_conf.key = key;
+	kmdl->glue.config.mdl_conf.metadata_keys_count = 0;
+	kref_init(&kmdl->glue.refcount);
+	INIT_LIST_HEAD(&kmdl->glue.owner_list);
+	INIT_LIST_HEAD(&kmdl->glue.owned_list);
+
+	conf_len -= sizeof(*conf);
+
+	for (i = 0; i < arg->metadata_keys_count; i++) {
+		if (conf_len < sizeof(struct kparser_hkey)) {
+			(*rsp)->op_ret_code = EINVAL;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s: conf len/buffer incomplete",
+					       op);
+			goto done;
+		}
+
+		conf_len -= sizeof(struct kparser_hkey);
+
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n",
+					 arg->metadata_keys[i].id, arg->metadata_keys[i].name);
+
+		kmde = kparser_namespace_lookup(KPARSER_NS_METADATA, &arg->metadata_keys[i]);
+		if (!kmde) {
+			(*rsp)->op_ret_code = ENOENT;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s: Object not found, key: {%s:%u}",
+					       op, arg->metadata_keys[i].name,
+					       arg->metadata_keys[i].id);
+			goto done;
+		}
+		kmdl->metadata_table.num_ents++;
+		realloced_mem = krealloc(kmdl->metadata_table.entries,
+					 kmdl->metadata_table.num_ents * sizeof(*kmde),
+					 GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			(*rsp)->op_ret_code = ENOMEM;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s: krealloc() err, ents:%d, size:%lu",
+					       op,
+					       kmdl->metadata_table.num_ents,
+					       sizeof(*kmde));
+			goto done;
+		}
+		rcu_assign_pointer(kmdl->metadata_table.entries, realloced_mem);
+
+		kmdl->metadata_table.entries[i] = kmde->mde;
+		kref_get(&kmde->glue.refcount);
+
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			if (kmdl) {
+				kparser_free(kmdl->metadata_table.entries);
+				kparser_free(kmdl);
+			}
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = kmde->glue.config.namespace_id;
+		objects[i].conf_keys_bv = kmde->glue.config.conf_keys_bv;
+		objects[i].md_conf = kmde->glue.config.md_conf;
+
+		kmdl->md_configs_len++;
+		realloced_mem = krealloc(kmdl->md_configs,
+					 kmdl->md_configs_len *
+					 sizeof(struct kparser_conf_cmd),
+					 GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			(*rsp)->op_ret_code = ENOMEM;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s: krealloc() err, ents:%lu, size:%lu",
+					       op,
+					       kmdl->md_configs_len,
+					       sizeof(struct kparser_conf_cmd));
+			goto done;
+		}
+		kmdl->md_configs = realloced_mem;
+		kmdl->md_configs[i].namespace_id = kmde->glue.config.namespace_id;
+		kmdl->md_configs[i].conf_keys_bv = kmde->glue.config.conf_keys_bv;
+		kmdl->md_configs[i].md_conf = kmde->glue.config.md_conf;
+	}
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &kmdl->glue.ht_node_id, &kmdl->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.mdl_conf = kmdl->glue.config.mdl_conf;
+	(*rsp)->object.mdl_conf.metadata_keys_count = 0;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0 && kmdl) {
+		kparser_free(kmdl->metadata_table.entries);
+		kparser_free(kmdl->md_configs);
+		kparser_free(kmdl);
+	}
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_METALIST);
+}
+
+/* read handler for object metadata list */
+int kparser_read_metalist(const struct kparser_hkey *key,
+			  struct kparser_cmd_rsp_hdr **rsp,
+			  size_t *rsp_len, __u8 recursive_read,
+			  const char *op,
+			  void *extack, int *err)
+{
+	const struct kparser_glue_metadata_table *kmdl;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kmdl = kparser_namespace_lookup(KPARSER_NS_METALIST, key);
+	if (!kmdl) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object key not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = kmdl->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kmdl->glue.config.conf_keys_bv;
+	(*rsp)->object.mdl_conf = kmdl->glue.config.mdl_conf;
+
+	for (i = 0; i < kmdl->md_configs_len; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "%s:krealloc failed for rsp, len:%lu\n",
+						 op, *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = kmdl->md_configs[i].namespace_id;
+		objects[i].conf_keys_bv = kmdl->md_configs[i].conf_keys_bv;
+		objects[i].md_conf = kmdl->md_configs[i].md_conf;
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n",
+					 objects[i].md_conf.key.id, objects[i].md_conf.key.name);
+	}
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_METALIST);
+}
+
+/* delete handler for object metadata list */
+int kparser_del_metalist(const struct kparser_hkey *key,
+			 struct kparser_cmd_rsp_hdr **rsp,
+			 size_t *rsp_len, __u8 recursive_read,
+			 const char *op,
+			 void *extack, int *err)
+{
+	struct kparser_obj_link_ctx *tmp_list_ref = NULL, *curr_ref = NULL;
+	struct kparser_obj_link_ctx *node_tmp_list_ref = NULL;
+	struct kparser_obj_link_ctx *node_curr_ref = NULL;
+	struct kparser_glue_glue_parse_node *kparsenode;
+	struct kparser_glue_metadata_extract *kmde;
+	struct kparser_glue_metadata_table *kmdl;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i, rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kmdl = kparser_namespace_lookup(KPARSER_NS_METALIST, key);
+	if (!kmdl) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object key not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	/* verify if there is any associated immutable parser */
+	list_for_each_entry_safe(curr_ref, tmp_list_ref,
+				 &kmdl->glue.owned_list, owned_obj.list_node) {
+		if (curr_ref->owner_obj.nsid != KPARSER_NS_NODE_PARSE)
+			continue;
+		if (kref_read(curr_ref->owner_obj.refcount) == 0)
+			continue;
+		kparsenode = (struct kparser_glue_glue_parse_node *)curr_ref->owner_obj.obj;
+		list_for_each_entry_safe(node_curr_ref, node_tmp_list_ref,
+					 &kparsenode->glue.glue.owned_list, owned_obj.list_node) {
+			if (node_curr_ref->owner_obj.nsid != KPARSER_NS_PARSER)
+				continue;
+			if (kref_read(node_curr_ref->owner_obj.refcount) != 0) {
+				(*rsp)->op_ret_code = EBUSY;
+				NL_SET_ERR_MSG_FMT_MOD(extack,
+						       "%s: attached parser `%s` is immutable",
+						       op,
+						       ((struct kparser_glue_parser *)
+							node_curr_ref->owner_obj.obj)->glue.key.name);
+				goto done;
+			}
+		}
+	}
+
+	if (kparser_link_detach(kmdl, &kmdl->glue.owner_list,
+				&kmdl->glue.owned_list, *rsp,
+				extack, err) != 0)
+		goto done;
+
+	(*rsp)->key = kmdl->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kmdl->glue.config.conf_keys_bv;
+	(*rsp)->object.mdl_conf = kmdl->glue.config.mdl_conf;
+
+	for (i = 0; i < kmdl->md_configs_len; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = kmdl->md_configs[i].namespace_id;
+		objects[i].conf_keys_bv = kmdl->md_configs[i].conf_keys_bv;
+		objects[i].md_conf = kmdl->md_configs[i].md_conf;
+
+		kmde = kparser_namespace_lookup(KPARSER_NS_METADATA, &objects[i].md_conf.key);
+		if (!kmde) {
+			(*rsp)->op_ret_code = ENOENT;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s: Object not found, key: {%s:%u}",
+					       op, objects[i].md_conf.key.name,
+					       objects[i].md_conf.key.id);
+			goto done;
+		}
+
+		rc = kparser_namespace_remove(KPARSER_NS_METADATA,
+					      &kmde->glue.ht_node_id, &kmde->glue.ht_node_name);
+		if (rc) {
+			(*rsp)->op_ret_code = rc;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s: namespace remove error, rc:%d",
+					       op, rc);
+			goto done;
+		}
+
+		kparser_free(kmde);
+	}
+
+	rc = kparser_namespace_remove(KPARSER_NS_METALIST,
+				      &kmdl->glue.ht_node_id, &kmdl->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: namespace remove error, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	kparser_free(kmdl->metadata_table.entries);
+
+	kmdl->metadata_table.num_ents = 0;
+
+	kparser_free(kmdl->md_configs);
+
+	kparser_free(kmdl);
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_METALIST);
+}
+
+/* free handler for object metadata list */
+void kparser_free_metalist(void *ptr, void *arg)
+{
+	/* TODO:  */
+}
+
+/* handler to convert and map netlink node context to kParser KMOD's node context */
+static inline bool kparser_conf_node_convert(const struct kparser_conf_node *conf,
+					     void *node, size_t node_len)
+{
+	struct kparser_glue_proto_flag_fields_table *kflag_fields_proto_table;
+	struct kparser_parse_flag_fields_node *flag_fields_parse_node;
+	struct kparser_glue_parse_tlv_node *kparsetlvwildcardnode;
+	struct kparser_glue_glue_parse_node *kparsewildcardnode;
+	struct kparser_glue_proto_tlvs_table *kprototlvstbl;
+	struct kparser_glue_condexpr_tables *kcond_tables;
+	struct kparser_parse_tlvs_node *tlvs_parse_node;
+	struct kparser_glue_flag_fields *kflag_fields;
+	struct kparser_glue_protocol_table *kprototbl;
+	struct kparser_parse_node *plain_parse_node;
+	struct kparser_glue_metadata_table *kmdl;
+
+	if (!conf || !node || node_len < sizeof(*plain_parse_node))
+		return false;
+
+	plain_parse_node = node;
+	plain_parse_node->node_type = conf->type;
+	plain_parse_node->unknown_ret = conf->plain_parse_node.unknown_ret;
+	plain_parse_node->proto_node.encap = conf->plain_parse_node.proto_node.encap;
+	plain_parse_node->proto_node.overlay = conf->plain_parse_node.proto_node.overlay;
+	plain_parse_node->proto_node.min_len = conf->plain_parse_node.proto_node.min_len;
+	plain_parse_node->proto_node.ops.len_parameterized =
+		conf->plain_parse_node.proto_node.ops.len_parameterized;
+	plain_parse_node->proto_node.ops.pflen = conf->plain_parse_node.proto_node.ops.pflen;
+	plain_parse_node->proto_node.ops.pfnext_proto =
+		conf->plain_parse_node.proto_node.ops.pfnext_proto;
+
+	kcond_tables =
+		kparser_namespace_lookup(KPARSER_NS_CONDEXPRS_TABLES,
+					 &conf->plain_parse_node.proto_node.ops.cond_exprs_table);
+	if (kcond_tables) {
+		plain_parse_node->proto_node.ops.cond_exprs = kcond_tables->table;
+		plain_parse_node->proto_node.ops.cond_exprs_parameterized = true;
+	}
+
+	strcpy(plain_parse_node->name, conf->key.name);
+
+	kprototbl = kparser_namespace_lookup(KPARSER_NS_PROTO_TABLE,
+					     &conf->plain_parse_node.proto_table_key);
+	if (kprototbl)
+		rcu_assign_pointer(plain_parse_node->proto_table, &kprototbl->proto_table);
+
+	kparsewildcardnode =
+		kparser_namespace_lookup(KPARSER_NS_NODE_PARSE,
+					 &conf->plain_parse_node.wildcard_parse_node_key);
+	if (kparsewildcardnode)
+		rcu_assign_pointer(plain_parse_node->wildcard_node,
+				   &kparsewildcardnode->parse_node);
+
+	kmdl = kparser_namespace_lookup(KPARSER_NS_METALIST,
+					&conf->plain_parse_node.metadata_table_key);
+	if (kmdl)
+		rcu_assign_pointer(plain_parse_node->metadata_table, &kmdl->metadata_table);
+
+	switch (conf->type) {
+	case KPARSER_NODE_TYPE_PLAIN:
+		break;
+
+	case KPARSER_NODE_TYPE_TLVS:
+		if (node_len < sizeof(*tlvs_parse_node))
+			return false;
+
+		tlvs_parse_node = node;
+
+		tlvs_parse_node->parse_node.tlvs_proto_node.ops =
+			conf->tlvs_parse_node.proto_node.ops;
+
+		tlvs_parse_node->parse_node.tlvs_proto_node.start_offset =
+			conf->tlvs_parse_node.proto_node.start_offset;
+		tlvs_parse_node->parse_node.tlvs_proto_node.pad1_val =
+			conf->tlvs_parse_node.proto_node.pad1_val;
+		tlvs_parse_node->parse_node.tlvs_proto_node.padn_val =
+			conf->tlvs_parse_node.proto_node.padn_val;
+		tlvs_parse_node->parse_node.tlvs_proto_node.eol_val =
+			conf->tlvs_parse_node.proto_node.eol_val;
+		tlvs_parse_node->parse_node.tlvs_proto_node.pad1_enable =
+			conf->tlvs_parse_node.proto_node.pad1_enable;
+		tlvs_parse_node->parse_node.tlvs_proto_node.padn_enable =
+			conf->tlvs_parse_node.proto_node.padn_enable;
+		tlvs_parse_node->parse_node.tlvs_proto_node.eol_enable =
+			conf->tlvs_parse_node.proto_node.eol_enable;
+		tlvs_parse_node->parse_node.tlvs_proto_node.fixed_start_offset =
+			conf->tlvs_parse_node.proto_node.fixed_start_offset;
+		tlvs_parse_node->parse_node.tlvs_proto_node.min_len =
+			conf->tlvs_parse_node.proto_node.min_len;
+
+		kprototlvstbl =
+			kparser_namespace_lookup(KPARSER_NS_TLV_PROTO_TABLE,
+						 &conf->tlvs_parse_node.tlv_proto_table_key);
+		if (kprototlvstbl)
+			rcu_assign_pointer(tlvs_parse_node->tlv_proto_table,
+					   &kprototlvstbl->tlvs_proto_table);
+
+		kparsetlvwildcardnode =
+			kparser_namespace_lookup(KPARSER_NS_TLV_NODE_PARSE,
+						 &conf->tlvs_parse_node.tlv_wildcard_node_key);
+		if (kparsetlvwildcardnode)
+			rcu_assign_pointer(tlvs_parse_node->tlv_wildcard_node,
+					   &kparsetlvwildcardnode->tlv_parse_node);
+
+		tlvs_parse_node->unknown_tlv_type_ret =
+			conf->tlvs_parse_node.unknown_tlv_type_ret;
+
+		tlvs_parse_node->config =
+			conf->tlvs_parse_node.config;
+		break;
+
+	case KPARSER_NODE_TYPE_FLAG_FIELDS:
+		if (node_len < sizeof(*flag_fields_parse_node))
+			return false;
+		flag_fields_parse_node = node;
+
+		flag_fields_parse_node->parse_node.flag_fields_proto_node.ops =
+			conf->flag_fields_parse_node.proto_node.ops;
+
+		kflag_fields =
+			kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD_TABLE,
+						 &conf->flag_fields_parse_node.proto_node.
+						 flag_fields_table_hkey);
+		if (kflag_fields)
+			rcu_assign_pointer(flag_fields_parse_node->
+					   parse_node.flag_fields_proto_node.flag_fields,
+					   &kflag_fields->flag_fields);
+
+		kflag_fields_proto_table =
+			kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD_PROTO_TABLE,
+						 &conf->flag_fields_parse_node.
+						 flag_fields_proto_table_key);
+		if (kflag_fields_proto_table)
+			rcu_assign_pointer(flag_fields_parse_node->flag_fields_proto_table,
+					   &kflag_fields_proto_table->flags_proto_table);
+		break;
+
+	default:
+		return false;
+	}
+	return true;
+}
+
+/* create handler for object parse node */
+int kparser_create_parse_node(const struct kparser_conf_cmd *conf,
+			      size_t conf_len,
+			      struct kparser_cmd_rsp_hdr **rsp,
+			      size_t *rsp_len, const char *op,
+			      void *extack, int *err)
+{
+	struct kparser_glue_glue_parse_node *kparsenode = NULL;
+	struct kparser_glue_protocol_table *proto_table;
+	struct kparser_glue_metadata_table *mdl;
+	const struct kparser_conf_node *arg;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->node_conf;
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object, key:{%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	kparsenode = kzalloc(sizeof(*kparsenode), GFP_KERNEL);
+	if (!kparsenode) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size:%lu",
+				       op, sizeof(*kparsenode));
+		goto done;
+	}
+
+	kparsenode->glue.glue.key = key;
+	INIT_LIST_HEAD(&kparsenode->glue.glue.owner_list);
+	INIT_LIST_HEAD(&kparsenode->glue.glue.owned_list);
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &kparsenode->glue.glue.ht_node_id,
+				      &kparsenode->glue.glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc: %d",
+				       op, rc);
+		goto done;
+	}
+
+	kparsenode->glue.glue.config.namespace_id = conf->namespace_id;
+	kparsenode->glue.glue.config.conf_keys_bv = conf->conf_keys_bv;
+	kparsenode->glue.glue.config.node_conf = *arg;
+	kparsenode->glue.glue.config.node_conf.key = key;
+	kref_init(&kparsenode->glue.glue.refcount);
+
+	if (!kparser_conf_node_convert(arg, &kparsenode->parse_node,
+				       sizeof(kparsenode->parse_node))) {
+		(*rsp)->op_ret_code = EINVAL;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_conf_node_convert() err",
+				       op);
+		goto done;
+	}
+
+	if (kparsenode->parse_node.node.proto_table) {
+		proto_table = container_of(kparsenode->parse_node.node.proto_table,
+					   struct kparser_glue_protocol_table,
+					   proto_table);
+		if (kparser_link_attach(kparsenode,
+					KPARSER_NS_NODE_PARSE,
+					(const void **)&kparsenode->parse_node.node.proto_table,
+					&kparsenode->glue.glue.refcount,
+					&kparsenode->glue.glue.owner_list,
+					proto_table,
+					KPARSER_NS_PROTO_TABLE,
+					&proto_table->glue.refcount,
+					&proto_table->glue.owned_list,
+					*rsp, op, extack, err) != 0)
+			goto done;
+	}
+
+	if (kparsenode->parse_node.node.metadata_table) {
+		mdl = container_of(kparsenode->parse_node.node.metadata_table,
+				   struct kparser_glue_metadata_table,
+				   metadata_table);
+		if (kparser_link_attach(kparsenode,
+					KPARSER_NS_NODE_PARSE,
+					(const void **)&kparsenode->parse_node.node.metadata_table,
+					&kparsenode->glue.glue.refcount,
+					&kparsenode->glue.glue.owner_list,
+					mdl,
+					KPARSER_NS_METALIST,
+					&mdl->glue.refcount,
+					&mdl->glue.owned_list,
+					*rsp, op, extack, err) != 0)
+			goto done;
+	}
+
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.node_conf = kparsenode->glue.glue.config.node_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		kparser_free(kparsenode);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_NODE_PARSE);
+}
+
+/* read handler for object parse node */
+int kparser_read_parse_node(const struct kparser_hkey *key,
+			    struct kparser_cmd_rsp_hdr **rsp,
+			    size_t *rsp_len, __u8 recursive_read,
+			    const char *op,
+			    void *extack, int *err)
+{
+	const struct kparser_glue_glue_parse_node *kparsenode;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kparsenode = kparser_namespace_lookup(KPARSER_NS_NODE_PARSE, key);
+	if (!kparsenode) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = kparsenode->glue.glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kparsenode->glue.glue.config.conf_keys_bv;
+	(*rsp)->object.node_conf = kparsenode->glue.glue.config.node_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_NODE_PARSE);
+}
+
+/* delete handler for object parse node */
+int kparser_del_parse_node(const struct kparser_hkey *key,
+			   struct kparser_cmd_rsp_hdr **rsp,
+			   size_t *rsp_len, __u8 recursive_read,
+			   const char *op,
+			   void *extack, int *err)
+{
+	struct kparser_obj_link_ctx *tmp_list_ref = NULL, *curr_ref = NULL;
+	struct kparser_glue_glue_parse_node *kparsenode;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kparsenode = kparser_namespace_lookup(KPARSER_NS_NODE_PARSE, key);
+	if (!kparsenode) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	/* verify if there is any associated immutable parser */
+	list_for_each_entry_safe(curr_ref, tmp_list_ref,
+				 &kparsenode->glue.glue.owned_list,
+				 owned_obj.list_node) {
+		if (curr_ref->owner_obj.nsid != KPARSER_NS_PARSER)
+			continue;
+		if (kref_read(curr_ref->owner_obj.refcount) != 0) {
+			(*rsp)->op_ret_code = EBUSY;
+			NL_SET_ERR_MSG_FMT_MOD(extack,
+					       "%s:attached parser `%s` is immutable",
+					       op,
+					       ((struct kparser_glue_parser *)
+						curr_ref->owner_obj.obj)->glue.key.name);
+			goto done;
+		}
+	}
+
+	if (kparser_link_detach(kparsenode, &kparsenode->glue.glue.owner_list,
+				&kparsenode->glue.glue.owned_list, *rsp, extack,
+				err) != 0)
+		goto done;
+
+	rc = kparser_namespace_remove(KPARSER_NS_NODE_PARSE,
+				      &kparsenode->glue.glue.ht_node_id,
+				      &kparsenode->glue.glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: namespace remove error, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kparsenode->glue.glue.config.conf_keys_bv;
+	(*rsp)->object.node_conf = kparsenode->glue.glue.config.node_conf;
+
+	kparser_free(kparsenode);
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_NODE_PARSE);
+}
+
+/* free handler for object parse node */
+void kparser_free_node(void *ptr, void *arg)
+{
+	/* TODO: */
+}
+
+/* create handler for object protocol table entry */
+static bool kparser_create_proto_table_ent(const struct kparser_conf_table *arg,
+					   struct kparser_glue_protocol_table **proto_table,
+					   struct kparser_cmd_rsp_hdr *rsp,
+					   const char *op,
+					   void *extack, int *err)
+{
+	struct kparser_glue_glue_parse_node *kparsenode;
+	void *realloced_mem;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	*proto_table = kparser_namespace_lookup(KPARSER_NS_PROTO_TABLE, &arg->key);
+	if (!(*proto_table)) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		return false;
+	}
+
+	kparsenode = kparser_namespace_lookup(KPARSER_NS_NODE_PARSE, &arg->elem_key);
+	if (!kparsenode) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: parse node key:{%s:%u} not found",
+				       op, arg->elem_key.name,
+				       arg->elem_key.id);
+		return false;
+	}
+
+	(*proto_table)->proto_table.num_ents++;
+	realloced_mem = krealloc((*proto_table)->proto_table.entries,
+				 (*proto_table)->proto_table.num_ents *
+				 sizeof(struct kparser_proto_table_entry),
+				 GFP_KERNEL | ___GFP_ZERO);
+	if (!realloced_mem) {
+		rsp->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: krealloc() err, ents:%d, size:%lu",
+				       op,
+				       (*proto_table)->proto_table.num_ents,
+				       sizeof(struct kparser_proto_table_entry));
+		return false;
+	}
+	rcu_assign_pointer((*proto_table)->proto_table.entries, realloced_mem);
+
+	if (kparser_link_attach(*proto_table,
+				KPARSER_NS_PROTO_TABLE,
+				NULL, /* due to realloc, can't cache pointer here */
+				&(*proto_table)->glue.refcount,
+				&(*proto_table)->glue.owner_list,
+				kparsenode,
+				KPARSER_NS_NODE_PARSE,
+				&kparsenode->glue.glue.refcount,
+				&kparsenode->glue.glue.owned_list,
+				rsp, op, extack, err) != 0)
+		return false;
+
+	(*proto_table)->proto_table.entries[(*proto_table)->proto_table.num_ents - 1].value =
+			arg->optional_value1;
+	(*proto_table)->proto_table.entries[(*proto_table)->proto_table.num_ents - 1].encap =
+			arg->optional_value2;
+	(*proto_table)->proto_table.entries[(*proto_table)->proto_table.num_ents - 1].node =
+			&kparsenode->parse_node.node;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return true;
+}
+
+/* create handler for object protocol table */
+int kparser_create_proto_table(const struct kparser_conf_cmd *conf,
+			       size_t conf_len,
+			       struct kparser_cmd_rsp_hdr **rsp,
+			       size_t *rsp_len, const char *op,
+			       void *extack, int *err)
+{
+	struct kparser_glue_protocol_table *proto_table = NULL;
+	const struct kparser_conf_table *arg;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->table_conf;
+
+	/* create a table entry */
+	if (arg->add_entry) {
+		if (kparser_create_proto_table_ent(arg, &proto_table, *rsp, op,
+						   extack, err) == false)
+			goto done;
+		goto skip_table_create;
+	}
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	/* create protocol table */
+	proto_table = kzalloc(sizeof(*proto_table), GFP_KERNEL);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu",
+				       op, sizeof(*proto_table));
+		goto done;
+	}
+
+	proto_table->glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &proto_table->glue.ht_node_id,
+				      &proto_table->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	proto_table->glue.config.namespace_id = conf->namespace_id;
+	proto_table->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	proto_table->glue.config.table_conf = *arg;
+	proto_table->glue.config.table_conf.key = key;
+	kref_init(&proto_table->glue.refcount);
+	INIT_LIST_HEAD(&proto_table->glue.owner_list);
+	INIT_LIST_HEAD(&proto_table->glue.owned_list);
+
+skip_table_create:
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.table_conf = *arg;
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		if (proto_table && !arg->add_entry)
+			kparser_free(proto_table);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_PROTO_TABLE);
+}
+
+/* read handler for object protocol table */
+int kparser_read_proto_table(const struct kparser_hkey *key,
+			     struct kparser_cmd_rsp_hdr **rsp,
+			     size_t *rsp_len, __u8 recursive_read,
+			     const char *op,
+			     void *extack, int *err)
+{
+	const struct kparser_glue_protocol_table *proto_table;
+	const struct kparser_glue_glue_parse_node *parse_node;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	proto_table = kparser_namespace_lookup(KPARSER_NS_PROTO_TABLE, key);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = proto_table->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = proto_table->glue.config.conf_keys_bv;
+	(*rsp)->object.table_conf = proto_table->glue.config.table_conf;
+
+	for (i = 0; i < proto_table->proto_table.num_ents; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = proto_table->glue.config.namespace_id;
+		objects[i].table_conf = proto_table->glue.config.table_conf;
+		objects[i].table_conf.optional_value1 = proto_table->proto_table.entries[i].value;
+		if (!proto_table->proto_table.entries[i].node)
+			continue;
+		parse_node = container_of(proto_table->proto_table.entries[i].node,
+					  struct kparser_glue_glue_parse_node,
+					  parse_node.node);
+		objects[i].table_conf.elem_key = parse_node->glue.glue.key;
+	}
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_PROTO_TABLE);
+}
+
+/* delete handler for object protocol table */
+int kparser_del_proto_table(const struct kparser_hkey *key,
+			    struct kparser_cmd_rsp_hdr **rsp,
+			    size_t *rsp_len, __u8 recursive_read,
+			    const char *op,
+			    void *extack, int *err)
+{
+	struct kparser_obj_link_ctx *tmp_list_ref = NULL, *curr_ref = NULL;
+	struct kparser_obj_link_ctx *node_tmp_list_ref = NULL;
+	struct kparser_obj_link_ctx *node_curr_ref = NULL;
+	struct kparser_glue_protocol_table *proto_table;
+	struct kparser_glue_glue_parse_node *kparsenode;
+	struct kparser_glue_glue_parse_node *parse_node;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i, rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	proto_table = kparser_namespace_lookup(KPARSER_NS_PROTO_TABLE, key);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	/* verify if there is any associated immutable parser */
+	list_for_each_entry_safe(curr_ref, tmp_list_ref,
+				 &proto_table->glue.owned_list, owned_obj.list_node) {
+		if (curr_ref->owner_obj.nsid != KPARSER_NS_NODE_PARSE)
+			continue;
+		if (kref_read(curr_ref->owner_obj.refcount) == 0)
+			continue;
+		kparsenode = (struct kparser_glue_glue_parse_node *)
+			curr_ref->owner_obj.obj;
+		list_for_each_entry_safe(node_curr_ref, node_tmp_list_ref,
+					 &kparsenode->glue.glue.owned_list, owned_obj.list_node) {
+			if (node_curr_ref->owner_obj.nsid != KPARSER_NS_PARSER)
+				continue;
+			if (kref_read(node_curr_ref->owner_obj.refcount) != 0) {
+				(*rsp)->op_ret_code = EBUSY;
+				NL_SET_ERR_MSG_FMT_MOD(extack,
+						       "%s:attached parser `%s` is immutable",
+						       op,
+						       ((struct kparser_glue_parser *)
+							node_curr_ref->owner_obj.obj)->glue.key.name);
+				goto done;
+			}
+		}
+	}
+
+	(*rsp)->key = proto_table->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = proto_table->glue.config.conf_keys_bv;
+	(*rsp)->object.table_conf = proto_table->glue.config.table_conf;
+
+	for (i = 0; i < proto_table->proto_table.num_ents; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = proto_table->glue.config.namespace_id;
+		objects[i].table_conf = proto_table->glue.config.table_conf;
+		objects[i].table_conf.optional_value1 = proto_table->proto_table.entries[i].value;
+		if (!proto_table->proto_table.entries[i].node)
+			continue;
+		parse_node = container_of(proto_table->proto_table.entries[i].node,
+					  struct kparser_glue_glue_parse_node,
+					  parse_node.node);
+		objects[i].table_conf.elem_key = parse_node->glue.glue.key;
+	}
+
+	if (kparser_link_detach(proto_table, &proto_table->glue.owner_list,
+				&proto_table->glue.owned_list, *rsp,
+				extack, err) != 0)
+		goto done;
+
+	rc = kparser_namespace_remove(KPARSER_NS_PROTO_TABLE,
+				      &proto_table->glue.ht_node_id,
+				      &proto_table->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: namespace remove error, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	kparser_free(proto_table->proto_table.entries);
+	kparser_free(proto_table);
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_PROTO_TABLE);
+}
+
+/* free handler for object protocol table */
+void kparser_free_proto_tbl(void *ptr, void *arg)
+{
+	/* TODO: */
+}
+
+/* handler to convert and map from netlink tlv node to kParser KMOD's tlv node */
+static inline bool kparser_conf_tlv_node_convert(const struct kparser_conf_node_parse_tlv *conf,
+						 struct kparser_parse_tlv_node *node)
+{
+	struct kparser_glue_parse_tlv_node *kparsewildcardnode;
+	struct kparser_glue_condexpr_tables *kcond_tables;
+	struct kparser_glue_proto_tlvs_table *kprototbl;
+	struct kparser_glue_metadata_table *kmdl;
+
+	if (!conf || !node)
+		return false;
+
+	node->proto_tlv_node.min_len = conf->node_proto.min_len;
+	node->proto_tlv_node.max_len = conf->node_proto.max_len;
+	node->proto_tlv_node.is_padding = conf->node_proto.is_padding;
+
+	node->proto_tlv_node.ops.pfoverlay_type = conf->node_proto.ops.pfoverlay_type;
+	if (node->proto_tlv_node.ops.pfoverlay_type.src_off ||
+	    node->proto_tlv_node.ops.pfoverlay_type.size ||
+	    node->proto_tlv_node.ops.pfoverlay_type.right_shift)
+		node->proto_tlv_node.ops.overlay_type_parameterized = true;
+
+	kcond_tables = kparser_namespace_lookup(KPARSER_NS_CONDEXPRS_TABLES,
+						&conf->node_proto.ops.cond_exprs_table);
+	if (kcond_tables) {
+		node->proto_tlv_node.ops.cond_exprs = kcond_tables->table;
+		node->proto_tlv_node.ops.cond_exprs_parameterized = true;
+	}
+
+	kprototbl = kparser_namespace_lookup(KPARSER_NS_TLV_PROTO_TABLE,
+					     &conf->overlay_proto_tlvs_table_key);
+	if (kprototbl)
+		rcu_assign_pointer(node->overlay_table, &kprototbl->tlvs_proto_table);
+
+	kparsewildcardnode = kparser_namespace_lookup(KPARSER_NS_TLV_NODE_PARSE,
+						      &conf->overlay_wildcard_parse_node_key);
+	if (kparsewildcardnode)
+		rcu_assign_pointer(node->overlay_wildcard_node,
+				   &kparsewildcardnode->tlv_parse_node);
+
+	node->unknown_overlay_ret = conf->unknown_ret;
+	strcpy(node->name, conf->key.name);
+
+	kmdl = kparser_namespace_lookup(KPARSER_NS_METALIST,
+					&conf->metadata_table_key);
+	if (kmdl)
+		rcu_assign_pointer(node->metadata_table, &kmdl->metadata_table);
+
+	return true;
+}
+
+/* create handler for object tlv node */
+int kparser_create_parse_tlv_node(const struct kparser_conf_cmd *conf,
+				  size_t conf_len,
+				  struct kparser_cmd_rsp_hdr **rsp,
+				  size_t *rsp_len, const char *op,
+				  void *extack, int *err)
+{
+	struct kparser_glue_parse_tlv_node *node = NULL;
+	const struct kparser_conf_node_parse_tlv *arg;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->tlv_node_conf;
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object key, {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu",
+				       op, sizeof(*node));
+		goto done;
+	}
+
+	node->glue.glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &node->glue.glue.ht_node_id,
+				      &node->glue.glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	node->glue.glue.config.namespace_id = conf->namespace_id;
+	node->glue.glue.config.conf_keys_bv = conf->conf_keys_bv;
+	node->glue.glue.config.tlv_node_conf = *arg;
+	node->glue.glue.config.tlv_node_conf.key = key;
+	kref_init(&node->glue.glue.refcount);
+
+	if (!kparser_conf_tlv_node_convert(arg, &node->tlv_parse_node)) {
+		(*rsp)->op_ret_code = EINVAL;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_conf_tlv_node_convert() err",
+				       op);
+		goto done;
+	}
+
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.tlv_node_conf = node->glue.glue.config.tlv_node_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		kparser_free(node);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_TLV_NODE_PARSE);
+}
+
+/* read handler for object tlv node */
+int kparser_read_parse_tlv_node(const struct kparser_hkey *key,
+				struct kparser_cmd_rsp_hdr **rsp,
+				size_t *rsp_len, __u8 recursive_read,
+				const char *op,
+				void *extack, int *err)
+{
+	const struct kparser_glue_parse_tlv_node *node;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	node = kparser_namespace_lookup(KPARSER_NS_TLV_NODE_PARSE, key);
+	if (!node) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = node->glue.glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = node->glue.glue.config.conf_keys_bv;
+	(*rsp)->object.tlv_node_conf = node->glue.glue.config.tlv_node_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_TLV_NODE_PARSE);
+}
+
+/* create handler for object tlv proto table's entry */
+static bool kparser_create_tlv_proto_table_ent(const struct kparser_conf_table *arg,
+					       struct kparser_glue_proto_tlvs_table **proto_table,
+					       struct kparser_cmd_rsp_hdr *rsp,
+					       const char *op,
+					       void *extack, int *err)
+{
+	const struct kparser_glue_parse_tlv_node *kparsenode;
+	void *realloced_mem;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	*proto_table = kparser_namespace_lookup(KPARSER_NS_TLV_PROTO_TABLE, &arg->key);
+	if (!(*proto_table)) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		return false;
+	}
+
+	kparsenode = kparser_namespace_lookup(KPARSER_NS_TLV_NODE_PARSE, &arg->elem_key);
+	if (!kparsenode) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, arg->elem_key.name, arg->elem_key.id);
+		return false;
+	}
+
+	(*proto_table)->tlvs_proto_table.num_ents++;
+	realloced_mem = krealloc((*proto_table)->tlvs_proto_table.entries,
+				 (*proto_table)->tlvs_proto_table.num_ents *
+				 sizeof(struct kparser_proto_tlvs_table_entry),
+				 GFP_KERNEL | ___GFP_ZERO);
+	if (!realloced_mem) {
+		rsp->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: krealloc() err, ents:%d, size:%lu",
+				       op,
+				       (*proto_table)->tlvs_proto_table.num_ents,
+				       sizeof(struct kparser_proto_tlvs_table_entry));
+		return false;
+	}
+	rcu_assign_pointer((*proto_table)->tlvs_proto_table.entries, realloced_mem);
+
+	(*proto_table)->tlvs_proto_table.entries[(*proto_table)->tlvs_proto_table.num_ents -
+		1].type = arg->optional_value1;
+	(*proto_table)->tlvs_proto_table.entries[(*proto_table)->tlvs_proto_table.num_ents -
+		1].node = &kparsenode->tlv_parse_node;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return true;
+}
+
+/* create handler for object tlv proto table */
+int kparser_create_tlv_proto_table(const struct kparser_conf_cmd *conf,
+				   size_t conf_len,
+				   struct kparser_cmd_rsp_hdr **rsp,
+				   size_t *rsp_len, const char *op,
+				   void *extack, int *err)
+{
+	struct kparser_glue_proto_tlvs_table *proto_table = NULL;
+	const struct kparser_conf_table *arg;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->table_conf;
+
+	/* create a table entry */
+	if (arg->add_entry) {
+		if (kparser_create_tlv_proto_table_ent(arg, &proto_table, *rsp,
+						       op, extack, err) == false)
+			goto done;
+		goto skip_table_create;
+	}
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	/* create protocol table */
+	proto_table = kzalloc(sizeof(*proto_table), GFP_KERNEL);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu",
+				       op, sizeof(*proto_table));
+		goto done;
+	}
+
+	proto_table->glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &proto_table->glue.ht_node_id,
+				      &proto_table->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc: %d",
+				       op, rc);
+		goto done;
+	}
+
+	proto_table->glue.config.namespace_id = conf->namespace_id;
+	proto_table->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	proto_table->glue.config.table_conf = *arg;
+	proto_table->glue.config.table_conf.key = key;
+	kref_init(&proto_table->glue.refcount);
+
+skip_table_create:
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.table_conf = *arg;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		if (proto_table && !arg->add_entry)
+			kparser_free(proto_table);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_TLV_PROTO_TABLE);
+}
+
+/* read handler for object tlv proto table */
+int kparser_read_tlv_proto_table(const struct kparser_hkey *key,
+				 struct kparser_cmd_rsp_hdr **rsp,
+				 size_t *rsp_len, __u8 recursive_read,
+				 const char *op,
+				 void *extack, int *err)
+{
+	const struct kparser_glue_proto_tlvs_table *proto_table;
+	const struct kparser_glue_parse_tlv_node *parse_node;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	proto_table = kparser_namespace_lookup(KPARSER_NS_TLV_PROTO_TABLE, key);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = proto_table->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = proto_table->glue.config.conf_keys_bv;
+	(*rsp)->object.table_conf = proto_table->glue.config.table_conf;
+
+	for (i = 0; i < proto_table->tlvs_proto_table.num_ents; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = proto_table->glue.config.namespace_id;
+		objects[i].table_conf = proto_table->glue.config.table_conf;
+		objects[i].table_conf.optional_value1 =
+			proto_table->tlvs_proto_table.entries[i].type;
+		if (!proto_table->tlvs_proto_table.entries[i].node)
+			continue;
+		parse_node = container_of(proto_table->tlvs_proto_table.entries[i].node,
+					  struct kparser_glue_parse_tlv_node, tlv_parse_node);
+		objects[i].table_conf.elem_key = parse_node->glue.glue.key;
+	}
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_TLV_PROTO_TABLE);
+}
+
+/* create handler for object flag field */
+int kparser_create_flag_field(const struct kparser_conf_cmd *conf,
+			      size_t conf_len,
+			      struct kparser_cmd_rsp_hdr **rsp,
+			      size_t *rsp_len, const char *op,
+			      void *extack, int *err)
+{
+	struct kparser_glue_flag_field *kobj = NULL;
+	const struct kparser_conf_flag_field *arg;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->flag_field_conf;
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+	if (!kobj) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu",
+				       op, sizeof(*kobj));
+		goto done;
+	}
+
+	kobj->glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &kobj->glue.ht_node_id, &kobj->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	kobj->glue.config.namespace_id = conf->namespace_id;
+	kobj->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	kobj->glue.config.flag_field_conf = *arg;
+	kobj->glue.config.flag_field_conf.key = key;
+	kref_init(&kobj->glue.refcount);
+
+	kobj->flag_field = arg->conf;
+
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.flag_field_conf = kobj->glue.config.flag_field_conf;
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		kparser_free(kobj);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_FLAG_FIELD);
+}
+
+/* read handler for object flag field */
+int kparser_read_flag_field(const struct kparser_hkey *key,
+			    struct kparser_cmd_rsp_hdr **rsp,
+			    size_t *rsp_len, __u8 recursive_read,
+			    const char *op,
+			    void *extack, int *err)
+{
+	struct kparser_glue_flag_field *kobj;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kobj = kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD, key);
+	if (!kobj) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = kobj->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kobj->glue.config.conf_keys_bv;
+	(*rsp)->object.flag_field_conf = kobj->glue.config.flag_field_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_FLAG_FIELD);
+}
+
+/* compare call back to sort flag fields using their flag values in qsort API */
+static int compare(const void *lhs, const void *rhs)
+{
+	const struct kparser_flag_field *lhs_flag = lhs;
+	const struct kparser_flag_field *rhs_flag = rhs;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "lflag:%x rflag:%x\n", lhs_flag->flag, rhs_flag->flag);
+
+	if (lhs_flag->flag < rhs_flag->flag)
+		return -1;
+	if (lhs_flag->flag > rhs_flag->flag)
+		return 1;
+
+	return 0;
+}
+
+/* create handler for object flag field table entry */
+static bool kparser_create_flag_field_table_ent(const struct kparser_conf_table *arg,
+						struct kparser_glue_flag_fields **proto_table,
+						struct kparser_cmd_rsp_hdr *rsp,
+						const char *op,
+						void *extack, int *err)
+{
+	const struct kparser_glue_flag_field *kflagent;
+	void *realloced_mem;
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	*proto_table = kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD_TABLE, &arg->key);
+	if (!(*proto_table)) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		return false;
+	}
+
+	kflagent = kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD, &arg->elem_key);
+	if (!kflagent) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, arg->elem_key.name, arg->elem_key.id);
+		return false;
+	}
+
+	(*proto_table)->flag_fields.num_idx++;
+
+	realloced_mem = krealloc((*proto_table)->flag_fields.fields,
+				 (*proto_table)->flag_fields.num_idx *
+				 sizeof(struct kparser_flag_field),
+				 GFP_KERNEL | ___GFP_ZERO);
+	if (!realloced_mem) {
+		rsp->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: krealloc() err, ents:%lu, size:%lu",
+				       op,
+				       (*proto_table)->flag_fields.num_idx,
+				       sizeof(struct kparser_flag_field));
+		return false;
+	}
+	rcu_assign_pointer((*proto_table)->flag_fields.fields, realloced_mem);
+
+	(*proto_table)->flag_fields.fields[(*proto_table)->flag_fields.num_idx - 1] =
+		kflagent->flag_field;
+
+	sort((*proto_table)->flag_fields.fields,
+	     (*proto_table)->flag_fields.num_idx,
+	     sizeof(struct kparser_flag_field), &compare, NULL);
+
+	for (i = 0; i < (*proto_table)->flag_fields.num_idx; i++)
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "List[%d]:%x\n",
+					 i, (*proto_table)->flag_fields.fields[i].flag);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return true;
+}
+
+/* create handler for object flag field */
+int kparser_create_flag_field_table(const struct kparser_conf_cmd *conf,
+				    size_t conf_len,
+				    struct kparser_cmd_rsp_hdr **rsp,
+				    size_t *rsp_len, const char *op,
+				    void *extack, int *err)
+{
+	struct kparser_glue_flag_fields *proto_table = NULL;
+	const struct kparser_conf_table *arg;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->table_conf;
+
+	if (arg->add_entry) {
+		if (kparser_create_flag_field_table_ent(arg, &proto_table, *rsp,
+							op, extack, err) == false)
+			goto done;
+		goto skip_table_create;
+	}
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	proto_table = kzalloc(sizeof(*proto_table), GFP_KERNEL);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu",
+				       op, sizeof(*proto_table));
+		goto done;
+	}
+
+	proto_table->glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &proto_table->glue.ht_node_id,
+				      &proto_table->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc: %d",
+				       op, rc);
+		goto done;
+	}
+
+	proto_table->glue.config.namespace_id = conf->namespace_id;
+	proto_table->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	proto_table->glue.config.table_conf = *arg;
+	proto_table->glue.config.table_conf.key = key;
+	kref_init(&proto_table->glue.refcount);
+
+skip_table_create:
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.table_conf = *arg;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		if (proto_table && !arg->add_entry)
+			kparser_free(proto_table);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_FLAG_FIELD_TABLE);
+}
+
+/* read handler for object flag field */
+int kparser_read_flag_field_table(const struct kparser_hkey *key,
+				  struct kparser_cmd_rsp_hdr **rsp,
+				  size_t *rsp_len, __u8 recursive_read,
+				  const char *op,
+				  void *extack, int *err)
+{
+	const struct kparser_glue_flag_fields *proto_table;
+	const struct kparser_glue_flag_field *kflagent;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	proto_table = kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD_TABLE, key);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name,  key->id);
+		goto done;
+	}
+
+	(*rsp)->key = proto_table->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n",
+				 (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = proto_table->glue.config.conf_keys_bv;
+	(*rsp)->object.table_conf = proto_table->glue.config.table_conf;
+
+	for (i = 0; i < proto_table->flag_fields.num_idx; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = proto_table->glue.config.namespace_id;
+		objects[i].table_conf = proto_table->glue.config.table_conf;
+		objects[i].table_conf.optional_value1 = i;
+		if (!proto_table->flag_fields.fields)
+			continue;
+		kflagent = container_of(&proto_table->flag_fields.fields[i],
+					struct kparser_glue_flag_field, flag_field);
+		objects[i].table_conf.elem_key = kflagent->glue.key;
+	}
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_FLAG_FIELD_TABLE);
+}
+
+/* handler to convert and map netlink's flag node to kParser KMOD's flag node */
+static inline bool
+kparser_create_parse_flag_field_node_convert(const struct kparser_conf_node_parse_flag_field *conf,
+					     struct kparser_parse_flag_field_node *node)
+{
+	struct kparser_glue_condexpr_tables *kcond_tables;
+	struct kparser_glue_metadata_table *kmdl;
+
+	if (!conf || !node)
+		return false;
+
+	strcpy(node->name, conf->key.name);
+
+	kcond_tables = kparser_namespace_lookup(KPARSER_NS_CONDEXPRS_TABLES,
+						&conf->ops.cond_exprs_table_key);
+	if (kcond_tables)
+		node->ops.cond_exprs = kcond_tables->table;
+
+	kmdl = kparser_namespace_lookup(KPARSER_NS_METALIST, &conf->metadata_table_key);
+	if (kmdl)
+		rcu_assign_pointer(node->metadata_table, &kmdl->metadata_table);
+
+	return true;
+}
+
+/* create handler for object flag field node */
+int kparser_create_parse_flag_field_node(const struct kparser_conf_cmd *conf,
+					 size_t conf_len,
+					 struct kparser_cmd_rsp_hdr **rsp,
+					 size_t *rsp_len, const char *op,
+					 void *extack, int *err)
+{
+	const struct kparser_conf_node_parse_flag_field *arg;
+	struct kparser_glue_flag_field_node *node = NULL;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->flag_field_node_conf;
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu",
+				       op, sizeof(*node));
+		goto done;
+	}
+
+	node->glue.glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &node->glue.glue.ht_node_id, &node->glue.glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	node->glue.glue.config.namespace_id = conf->namespace_id;
+	node->glue.glue.config.conf_keys_bv = conf->conf_keys_bv;
+	node->glue.glue.config.flag_field_node_conf = *arg;
+	node->glue.glue.config.flag_field_node_conf.key = key;
+	kref_init(&node->glue.glue.refcount);
+
+	if (!kparser_create_parse_flag_field_node_convert(arg, &node->node_flag_field)) {
+		(*rsp)->op_ret_code = EINVAL;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_conf_tlv_node_convert() err",
+				       op);
+		goto done;
+	}
+
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.flag_field_node_conf = node->glue.glue.config.flag_field_node_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		kparser_free(node);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_FLAG_FIELD_NODE_PARSE);
+}
+
+/* read handler for object flag field node */
+int kparser_read_parse_flag_field_node(const struct kparser_hkey *key,
+				       struct kparser_cmd_rsp_hdr **rsp,
+				       size_t *rsp_len, __u8 recursive_read,
+				       const char *op,
+				       void *extack, int *err)
+{
+	const struct kparser_glue_flag_field_node *node;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	node = kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD_NODE_PARSE, key);
+	if (!node) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = node->glue.glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = node->glue.glue.config.conf_keys_bv;
+	(*rsp)->object.flag_field_node_conf = node->glue.glue.config.flag_field_node_conf;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_FLAG_FIELD_NODE_PARSE);
+}
+
+/* create handler for object flag field proto table's entry */
+static bool
+kparser_create_flag_field_proto_table_ent(const struct kparser_conf_table *arg,
+					  struct kparser_glue_proto_flag_fields_table **proto_table,
+					  struct kparser_cmd_rsp_hdr *rsp,
+					  const char *op,
+					  void *extack, int *err)
+{
+	const struct kparser_glue_flag_field_node *kparsenode;
+	void *realloced_mem;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	*proto_table = kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD_PROTO_TABLE, &arg->key);
+	if (!(*proto_table)) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		return false;
+	}
+
+	kparsenode = kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD_NODE_PARSE, &arg->elem_key);
+	if (!kparsenode) {
+		rsp->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op,
+				       arg->elem_key.name,
+				       arg->elem_key.id);
+		return false;
+	}
+
+	(*proto_table)->flags_proto_table.num_ents++;
+	realloced_mem = krealloc((*proto_table)->flags_proto_table.entries,
+				 (*proto_table)->flags_proto_table.num_ents *
+				 sizeof(struct kparser_proto_flag_fields_table_entry),
+				 GFP_KERNEL | ___GFP_ZERO);
+	if (!realloced_mem) {
+		rsp->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: krealloc() err, ents:%d, size:%lu",
+				       op,
+				       (*proto_table)->flags_proto_table.num_ents,
+				       sizeof(struct kparser_proto_flag_fields_table_entry));
+		return false;
+	}
+	rcu_assign_pointer((*proto_table)->flags_proto_table.entries, realloced_mem);
+
+	(*proto_table)->flags_proto_table.entries[(*proto_table)->flags_proto_table.num_ents -
+		1].flag = arg->optional_value1;
+	(*proto_table)->flags_proto_table.entries[(*proto_table)->flags_proto_table.num_ents -
+		1].node = &kparsenode->node_flag_field;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return true;
+}
+
+/* create handler for object flag field proto table */
+int kparser_create_flag_field_proto_table(const struct kparser_conf_cmd *conf,
+					  size_t conf_len,
+					  struct kparser_cmd_rsp_hdr **rsp,
+					  size_t *rsp_len, const char *op,
+					  void *extack, int *err)
+{
+	struct kparser_glue_proto_flag_fields_table *proto_table = NULL;
+	const struct kparser_conf_table *arg;
+	struct kparser_hkey key;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->table_conf;
+
+	/* create a table entry */
+	if (arg->add_entry) {
+		if (kparser_create_flag_field_proto_table_ent(arg, &proto_table,
+							      *rsp,
+							      op, extack, err) == false)
+			goto done;
+		goto skip_table_create;
+	}
+
+	if (kparser_conf_key_manager(conf->namespace_id, &arg->key, &key, *rsp,
+				     op, extack, err) != 0) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "error");
+		goto done;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", arg->key.id, arg->key.name);
+
+	if (kparser_namespace_lookup(conf->namespace_id, &key)) {
+		(*rsp)->op_ret_code = EEXIST;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Duplicate object, key {%s:%u}",
+				       op, arg->key.name, arg->key.id);
+		goto done;
+	}
+
+	/* create protocol table */
+	proto_table = kzalloc(sizeof(*proto_table), GFP_KERNEL);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size: %lu", op,
+				       sizeof(*proto_table));
+		goto done;
+	}
+
+	proto_table->glue.key = key;
+
+	rc = kparser_namespace_insert(conf->namespace_id,
+				      &proto_table->glue.ht_node_id,
+				      &proto_table->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kparser_namespace_insert() err, rc: %d",
+				       op, rc);
+		goto done;
+	}
+
+	proto_table->glue.config.namespace_id = conf->namespace_id;
+	proto_table->glue.config.conf_keys_bv = conf->conf_keys_bv;
+	proto_table->glue.config.table_conf = *arg;
+	proto_table->glue.config.table_conf.key = key;
+	kref_init(&proto_table->glue.refcount);
+
+skip_table_create:
+	(*rsp)->key = key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.table_conf = *arg;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0)
+		if (proto_table && !arg->add_entry)
+			kparser_free(proto_table);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_FLAG_FIELD_PROTO_TABLE);
+}
+
+/* read handler for object flag field proto table */
+int kparser_read_flag_field_proto_table(const struct kparser_hkey *key,
+					struct kparser_cmd_rsp_hdr **rsp,
+					size_t *rsp_len, __u8 recursive_read,
+					const char *op,
+					void *extack, int *err)
+{
+	const struct kparser_glue_proto_flag_fields_table *proto_table;
+	const struct kparser_glue_flag_field_node *parse_node;
+	struct kparser_conf_cmd *objects = NULL;
+	void *realloced_mem;
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	proto_table = kparser_namespace_lookup(KPARSER_NS_FLAG_FIELD_PROTO_TABLE, key);
+	if (!proto_table) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = proto_table->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = proto_table->glue.config.conf_keys_bv;
+	(*rsp)->object.table_conf = proto_table->glue.config.table_conf;
+
+	for (i = 0; i < proto_table->flags_proto_table.num_ents; i++) {
+		(*rsp)->objects_len++;
+		*rsp_len = *rsp_len + sizeof(struct kparser_conf_cmd);
+		realloced_mem = krealloc(*rsp, *rsp_len, GFP_KERNEL | ___GFP_ZERO);
+		if (!realloced_mem) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "krealloc failed for rsp, len:%lu\n",
+						 *rsp_len);
+			*rsp_len = 0;
+			mutex_unlock(&kparser_config_lock);
+			return KPARSER_ATTR_UNSPEC;
+		}
+		*rsp = realloced_mem;
+
+		objects = (struct kparser_conf_cmd *)(*rsp)->objects;
+		objects[i].namespace_id = proto_table->glue.config.namespace_id;
+		objects[i].table_conf = proto_table->glue.config.table_conf;
+		if (!proto_table->flags_proto_table.entries[i].node)
+			continue;
+		objects[i].table_conf.optional_value1 =
+			proto_table->flags_proto_table.entries[i].flag;
+		parse_node = container_of(proto_table->flags_proto_table.entries[i].node,
+					  struct kparser_glue_flag_field_node,
+					  node_flag_field);
+		objects[i].table_conf.elem_key = parse_node->glue.glue.key;
+	}
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_FLAG_FIELD_PROTO_TABLE);
+}
+
+/* conevrt and map from netlink's parser to kParser KMOD's parser */
+static inline bool kparser_parser_convert(const struct kparser_conf_parser *conf,
+					  struct kparser_parser *parser)
+{
+	struct kparser_glue_glue_parse_node *node;
+
+	strcpy(parser->name, conf->key.name);
+
+	node = kparser_namespace_lookup(KPARSER_NS_NODE_PARSE, &conf->root_node_key);
+	if (node)
+		rcu_assign_pointer(parser->root_node, &node->parse_node.node);
+	else
+		return false;
+
+	node = kparser_namespace_lookup(KPARSER_NS_NODE_PARSE, &conf->ok_node_key);
+	if (node)
+		rcu_assign_pointer(parser->okay_node, &node->parse_node.node);
+
+	node = kparser_namespace_lookup(KPARSER_NS_NODE_PARSE, &conf->fail_node_key);
+	if (node)
+		rcu_assign_pointer(parser->fail_node, &node->parse_node.node);
+
+	node = kparser_namespace_lookup(KPARSER_NS_NODE_PARSE, &conf->atencap_node_key);
+	if (node)
+		rcu_assign_pointer(parser->atencap_node, &node->parse_node.node);
+
+	parser->cntrs_conf = cntrs_conf;
+
+	parser->config = conf->config;
+	return true;
+}
+
+/* create handler for object parser */
+int kparser_create_parser(const struct kparser_conf_cmd *conf,
+			  size_t conf_len,
+			  struct kparser_cmd_rsp_hdr **rsp,
+			  size_t *rsp_len, const char *op,
+			  void *extack, int *err)
+{
+	struct kparser_glue_glue_parse_node *parse_node;
+	struct kparser_glue_parser *kparser = NULL;
+	struct kparser_counters *cntrs = NULL;
+	const struct kparser_conf_parser *arg;
+	struct kparser_parser parser = {};
+	struct kparser_hkey key;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	arg = &conf->parser_conf;
+
+	cntrs = kzalloc(sizeof(*cntrs), GFP_KERNEL);
+	if (!cntrs) {
+		(*rsp)->op_ret_code = ENOMEM;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: kzalloc() failed, size:%lu",
+				       op, sizeof(*cntrs));
+		goto done;
+	}
+	rcu_assign_pointer(parser.cntrs, cntrs);
+	parser.cntrs_len = sizeof(*cntrs);
+	parser.kparser_start_signature = KPARSERSTARTSIGNATURE;
+	parser.kparser_end_signature = KPARSERENDSIGNATURE;
+	if (!kparser_parser_convert(arg, &parser)) {
+		(*rsp)->op_ret_code = EINVAL;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: parser arg convert error", op);
+		goto done;
+	}
+
+	if (!kparser_cmd_create_pre_process(op, conf, &arg->key, &key,
+					    (void **)&kparser, sizeof(*kparser), *rsp,
+					    offsetof(struct kparser_glue_parser,
+						     glue), extack, err))
+		goto done;
+
+	kparser->parser = parser;
+
+	INIT_LIST_HEAD(&kparser->glue.owner_list);
+	INIT_LIST_HEAD(&kparser->glue.owned_list);
+
+	if (kparser->parser.root_node) {
+		parse_node = container_of(kparser->parser.root_node,
+					  struct kparser_glue_glue_parse_node,
+					  parse_node.node);
+		if (kparser_link_attach(kparser,
+					KPARSER_NS_PARSER,
+					(const void **)&kparser->parser.root_node,
+					&kparser->glue.refcount,
+					&kparser->glue.owner_list,
+					parse_node,
+					KPARSER_NS_NODE_PARSE,
+					&parse_node->glue.glue.refcount,
+					&parse_node->glue.glue.owned_list,
+					*rsp, op, extack, err) != 0)
+			goto done;
+	}
+
+	if (kparser->parser.okay_node) {
+		parse_node = container_of(kparser->parser.okay_node,
+					  struct kparser_glue_glue_parse_node,
+					  parse_node.node);
+		if (kparser_link_attach(kparser,
+					KPARSER_NS_PARSER,
+					(const void **)&kparser->parser.okay_node,
+					&kparser->glue.refcount,
+					&kparser->glue.owner_list,
+					parse_node,
+					KPARSER_NS_NODE_PARSE,
+					&parse_node->glue.glue.refcount,
+					&parse_node->glue.glue.owned_list,
+					*rsp, op, extack, err) != 0)
+			goto done;
+	}
+
+	if (kparser->parser.fail_node) {
+		parse_node = container_of(kparser->parser.fail_node,
+					  struct kparser_glue_glue_parse_node,
+					  parse_node.node);
+		if (kparser_link_attach(kparser,
+					KPARSER_NS_PARSER,
+					(const void **)&kparser->parser.fail_node,
+					&kparser->glue.refcount,
+					&kparser->glue.owner_list,
+					parse_node,
+					KPARSER_NS_NODE_PARSE,
+					&parse_node->glue.glue.refcount,
+					&parse_node->glue.glue.owned_list,
+					*rsp, op, extack, err) != 0)
+			goto done;
+	}
+
+	if (kparser->glue.key.id >= KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_START &&
+	    kparser->glue.key.id <= KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_STOP)
+		rcu_assign_pointer(kparser_fast_lookup_array[kparser->glue.key.id], kparser);
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	if ((*rsp)->op_ret_code != 0) {
+		kparser_free(kparser);
+		kparser_free(cntrs);
+	}
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_PARSER);
+}
+
+static bool kparser_dump_protocol_table(const struct kparser_proto_table *obj,
+					struct kparser_cmd_rsp_hdr **rsp,
+					size_t *rsp_len,
+					void *extack, int *err);
+
+/* dump metadata list to netlink msg rsp */
+static bool kparser_dump_metadata_table(const struct kparser_metadata_table *obj,
+					struct kparser_cmd_rsp_hdr **rsp,
+					size_t *rsp_len,
+					void *extack, int *err)
+{
+	const struct kparser_glue_metadata_table *glue_obj;
+	struct kparser_cmd_rsp_hdr *new_rsp = NULL;
+	size_t new_rsp_len = 0;
+	void *realloced_mem;
+	void *ptr;
+	int rc;
+
+	if (!obj)
+		return true;
+
+	rc = alloc_first_rsp(&new_rsp, &new_rsp_len, KPARSER_NS_METALIST);
+	if (rc) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "alloc_first_rsp() failed, rc:%d\n",
+					 rc);
+		return false;
+	}
+
+	glue_obj = container_of(obj, struct kparser_glue_metadata_table, metadata_table);
+
+	/* NOTE: TODO: kparser_config_lock should not be released and reacquired here. Fix later. */
+	mutex_unlock(&kparser_config_lock);
+	rc = kparser_read_metalist(&glue_obj->glue.key,
+				   &new_rsp, &new_rsp_len, false, "read",
+				   extack, err);
+	mutex_lock(&kparser_config_lock);
+
+	if (rc != KPARSER_ATTR_RSP(KPARSER_NS_METALIST))
+		goto error;
+
+	realloced_mem = krealloc(*rsp, *rsp_len + new_rsp_len, GFP_KERNEL | ___GFP_ZERO);
+	if (!realloced_mem)
+		goto error;
+	*rsp = realloced_mem;
+
+	ptr = (*rsp);
+	ptr += (*rsp_len);
+	(*rsp_len) = (*rsp_len) + new_rsp_len;
+	memcpy(ptr, new_rsp, new_rsp_len);
+	kparser_free(new_rsp);
+	new_rsp = NULL;
+
+	return true;
+error:
+	kparser_free(new_rsp);
+
+	return false;
+}
+
+/* dump parse node to netlink msg rsp */
+static bool kparser_dump_parse_node(const struct kparser_parse_node *obj,
+				    struct kparser_cmd_rsp_hdr **rsp,
+				    size_t *rsp_len,
+				    void *extack, int *err)
+{
+	const struct kparser_glue_glue_parse_node *glue_obj;
+	struct kparser_cmd_rsp_hdr *new_rsp = NULL;
+	size_t new_rsp_len = 0;
+	void *realloced_mem;
+	void *ptr;
+	int rc;
+
+	if (!obj)
+		return true;
+
+	rc = alloc_first_rsp(&new_rsp, &new_rsp_len, KPARSER_NS_NODE_PARSE);
+	if (rc) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "alloc_first_rsp() failed, rc:%d\n", rc);
+		return false;
+	}
+
+	glue_obj = container_of(obj, struct kparser_glue_glue_parse_node, parse_node.node);
+
+	/* NOTE: TODO: kparser_config_lock should not be released and reacquired here. Fix later. */
+	mutex_unlock(&kparser_config_lock);
+	rc = kparser_read_parse_node(&glue_obj->glue.glue.key,
+				     &new_rsp, &new_rsp_len, false, "read",
+				     extack, err);
+	mutex_lock(&kparser_config_lock);
+
+	if (rc != KPARSER_ATTR_RSP(KPARSER_NS_NODE_PARSE))
+		goto error;
+
+	realloced_mem = krealloc(*rsp, *rsp_len + new_rsp_len, GFP_KERNEL | ___GFP_ZERO);
+	if (!realloced_mem)
+		goto error;
+	*rsp = realloced_mem;
+
+	ptr = (*rsp);
+	ptr += (*rsp_len);
+	(*rsp_len) = (*rsp_len) + new_rsp_len;
+	memcpy(ptr, new_rsp, new_rsp_len);
+	kparser_free(new_rsp);
+	new_rsp = NULL;
+
+	if (!kparser_dump_protocol_table(obj->proto_table, rsp, rsp_len, extack,
+					 err))
+		goto error;
+
+	if (!kparser_dump_metadata_table(obj->metadata_table, rsp, rsp_len,
+					 extack, err))
+		goto error;
+
+	return true;
+error:
+	kparser_free(new_rsp);
+
+	return false;
+}
+
+/* dump protocol table to netlink msg rsp */
+static bool kparser_dump_protocol_table(const struct kparser_proto_table *obj,
+					struct kparser_cmd_rsp_hdr **rsp,
+					size_t *rsp_len,
+					void *extack, int *err)
+{
+	const struct kparser_glue_protocol_table *glue_obj;
+	struct kparser_cmd_rsp_hdr *new_rsp = NULL;
+	size_t new_rsp_len = 0;
+	void *realloced_mem;
+	void *ptr;
+	int rc, i;
+
+	if (!obj)
+		return true;
+
+	rc = alloc_first_rsp(&new_rsp, &new_rsp_len, KPARSER_NS_PROTO_TABLE);
+	if (rc) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+					 "alloc_first_rsp() failed, rc:%d\n", rc);
+		return false;
+	}
+
+	glue_obj = container_of(obj, struct kparser_glue_protocol_table,
+				proto_table);
+
+	/* NOTE: TODO: kparser_config_lock should not be released and reacquired here. Fix later. */
+	mutex_unlock(&kparser_config_lock);
+	rc = kparser_read_proto_table(&glue_obj->glue.key,
+				      &new_rsp, &new_rsp_len, false, "read",
+				      extack, err);
+	mutex_lock(&kparser_config_lock);
+
+	if (rc != KPARSER_ATTR_RSP(KPARSER_NS_PROTO_TABLE))
+		goto error;
+
+	realloced_mem = krealloc(*rsp, *rsp_len + new_rsp_len, GFP_KERNEL | ___GFP_ZERO);
+	if (!realloced_mem)
+		goto error;
+	*rsp = realloced_mem;
+
+	ptr = (*rsp);
+	ptr += (*rsp_len);
+	(*rsp_len) = (*rsp_len) + new_rsp_len;
+	memcpy(ptr, new_rsp, new_rsp_len);
+	kparser_free(new_rsp);
+	new_rsp = NULL;
+
+	for (i = 0; i < glue_obj->proto_table.num_ents; i++)
+		if (!kparser_dump_parse_node(glue_obj->proto_table.entries[i].node,
+					     rsp, rsp_len, extack, err))
+			goto error;
+
+	return true;
+error:
+	kparser_free(new_rsp);
+
+	return false;
+}
+
+/* dump parser to netlink msg rsp */
+static bool kparser_dump_parser(const struct kparser_glue_parser *kparser,
+				struct kparser_cmd_rsp_hdr **rsp,
+				size_t *rsp_len,
+				void *extack, int *err)
+{
+	/* DEBUG code, if(0) avoids warning for both compiler and checkpatch */
+	if (0)
+		kparser_dump_parser_tree(&kparser->parser);
+
+	kparser_start_new_tree_traversal();
+
+	if (!kparser_dump_parse_node(kparser->parser.root_node, rsp, rsp_len,
+				     extack, err))
+		goto error;
+
+	return true;
+error:
+	return false;
+}
+
+/* read handler for object parser */
+int kparser_read_parser(const struct kparser_hkey *key,
+			struct kparser_cmd_rsp_hdr **rsp,
+			size_t *rsp_len, __u8 recursive_read,
+			const char *op,
+			void *extack, int *err)
+{
+	const struct kparser_glue_parser *kparser;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kparser = kparser_namespace_lookup(KPARSER_NS_PARSER, key);
+	if (!kparser) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = kparser->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kparser->glue.config.conf_keys_bv;
+	(*rsp)->object.parser_conf = kparser->glue.config.parser_conf;
+
+	if (recursive_read &&
+	    kparser_dump_parser(kparser, rsp, rsp_len, extack, err) == false)
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "kparser_dump_parser failed");
+
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_PARSER);
+}
+
+/* delete handler for object parser */
+int kparser_del_parser(const struct kparser_hkey *key,
+		       struct kparser_cmd_rsp_hdr **rsp,
+		       size_t *rsp_len, __u8 recursive_read,
+		       const char *op,
+		       void *extack, int *err)
+{
+	struct kparser_glue_parser *kparser;
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kparser = kparser_namespace_lookup(KPARSER_NS_PARSER, key);
+	if (!kparser) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	if (kparser_link_detach(kparser, &kparser->glue.owner_list,
+				&kparser->glue.owned_list, *rsp,
+				extack, err) != 0)
+		goto done;
+
+	rc = kparser_namespace_remove(KPARSER_NS_PARSER,
+				      &kparser->glue.ht_node_id, &kparser->glue.ht_node_name);
+	if (rc) {
+		(*rsp)->op_ret_code = rc;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: namespace remove error, rc:%d",
+				       op, rc);
+		goto done;
+	}
+
+	(*rsp)->key = kparser->glue.key;
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+				 "Key: {ID:%u Name:%s}\n", (*rsp)->key.id, (*rsp)->key.name);
+	(*rsp)->object.conf_keys_bv = kparser->glue.config.conf_keys_bv;
+	(*rsp)->object.parser_conf = kparser->glue.config.parser_conf;
+
+	if (kparser->glue.key.id >= KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_START &&
+	    kparser->glue.key.id <= KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_STOP)
+		rcu_assign_pointer(kparser_fast_lookup_array[kparser->glue.key.id], NULL);
+
+	kparser_free(kparser->parser.cntrs);
+	kparser_free(kparser);
+done:
+	mutex_unlock(&kparser_config_lock);
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_PARSER);
+}
+
+/* free handler for object parser */
+void kparser_free_parser(void *ptr, void *arg)
+{
+	/* TODO: */
+}
+
+/* handler for object parser lock */
+int kparser_parser_lock(const struct kparser_conf_cmd *conf,
+			size_t conf_len,
+			struct kparser_cmd_rsp_hdr **rsp,
+			size_t *rsp_len, const char *op,
+			void *extack, int *err)
+{
+	const struct kparser_parser *parser;
+	const struct kparser_hkey *key;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	mutex_lock(&kparser_config_lock);
+
+	key = &conf->obj_key;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	parser = kparser_get_parser(key, false);
+	if (!parser) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	(*rsp)->key = *key;
+	(*rsp)->object.conf_keys_bv = conf->conf_keys_bv;
+	(*rsp)->object.obj_key = *key;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	synchronize_rcu();
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_OP_PARSER_LOCK_UNLOCK);
+}
+
+/* handler for object parser unlock */
+int kparser_parser_unlock(const struct kparser_hkey *key,
+			  struct kparser_cmd_rsp_hdr **rsp,
+			  size_t *rsp_len, __u8 recursive_read,
+			  const char *op,
+			  void *extack, int *err)
+{
+	const struct kparser_glue_parser *kparser;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "Key: {ID:%u Name:%s}\n", key->id, key->name);
+
+	mutex_lock(&kparser_config_lock);
+
+	kparser = kparser_namespace_lookup(KPARSER_NS_PARSER, key);
+	if (!kparser) {
+		(*rsp)->op_ret_code = ENOENT;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: object not found, key: {%s:%u}",
+				       op, key->name, key->id);
+		goto done;
+	}
+
+	if (!kparser_put_parser(&kparser->parser, false)) {
+		(*rsp)->op_ret_code = EINVAL;
+		NL_SET_ERR_MSG_FMT_MOD(extack,
+				       "%s: Parser unlock failed",
+				       op);
+		goto done;
+	}
+
+	(*rsp)->key = *key;
+	(*rsp)->object.obj_key = *key;
+done:
+	mutex_unlock(&kparser_config_lock);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+	return KPARSER_ATTR_RSP(KPARSER_NS_OP_PARSER_LOCK_UNLOCK);
+}
diff --git a/net/kparser/kparser_condexpr.h b/net/kparser/kparser_condexpr.h
new file mode 100644
index 000000000..247e8cb3f
--- /dev/null
+++ b/net/kparser/kparser_condexpr.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser_condexpr.h - kParser conditionals helper and structures header file
+ *
+ * Authors:     Tom Herbert <tom@sipanda.io>
+ *              Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#ifndef __KPARSER_CONDEXPR_H__
+#define __KPARSER_CONDEXPR_H__
+
+/* Definitions for parameterized conditional expressions */
+
+#include "kparser_types.h"
+#include "kparser_metaextract.h"
+
+/* Evaluate one conditional expression */
+static inline bool kparser_expr_evaluate(const struct kparser_condexpr_expr *expr, void *hdr)
+{
+	__u64 val;
+
+	pr_debug("{%s:%d}: soff:%u len:%u mask:%x type:%d\n",
+		 __func__, __LINE__, expr->src_off, expr->length, expr->mask, expr->type);
+
+	__kparser_metadata_bytes_extract(hdr + expr->src_off, (__u8 *)&val, expr->length, false);
+
+	val &= expr->mask;
+
+	pr_debug("{%s:%d}: type:%d val:%llx expr->value:%u\n",
+		 __func__, __LINE__, expr->type, val, expr->value);
+
+	switch (expr->type) {
+	case KPARSER_CONDEXPR_TYPE_EQUAL:
+		return (val == expr->value);
+	case KPARSER_CONDEXPR_TYPE_NOTEQUAL:
+		return (val != expr->value);
+	case KPARSER_CONDEXPR_TYPE_LT:
+		return (val < expr->value);
+	case KPARSER_CONDEXPR_TYPE_LTE:
+		return (val <= expr->value);
+	case KPARSER_CONDEXPR_TYPE_GT:
+		return (val > expr->value);
+	case KPARSER_CONDEXPR_TYPE_GTE:
+		return (val >= expr->value);
+	default:
+		break;
+	}
+
+	return false;
+}
+#endif /* __KPARSER_CONDEXPR_H__ */
diff --git a/net/kparser/kparser_datapath.c b/net/kparser/kparser_datapath.c
new file mode 100644
index 000000000..556d3d055
--- /dev/null
+++ b/net/kparser/kparser_datapath.c
@@ -0,0 +1,1266 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser_datapath.c - kParser main datapath source file for parsing logic - data path
+ *
+ * Authors:     Tom Herbert <tom@sipanda.io>
+ *              Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#include <linux/rhashtable.h>
+#include <linux/skbuff.h>
+#include <net/kparser.h>
+
+#include "kparser.h"
+#include "kparser_condexpr.h"
+#include "kparser_metaextract.h"
+#include "kparser_types.h"
+
+/* Lookup a type in a node table
+ * TODO: as of now, this table is an array, but in future, this needs to be
+ * converted to hash table for performance benefits
+ */
+static const struct kparser_parse_node *lookup_node(__u32 dflags,
+						    int type,
+						    const struct kparser_proto_table *table,
+						    bool *isencap)
+{
+	struct kparser_proto_table_entry __rcu *entries;
+	__u32 tmp;
+	int i;
+
+	if (!table)
+		return NULL;
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags,
+				 "type:0x%04x ents:%d, types:[%x, %x]\n",
+				 type, table->num_ents, ntohs(type), ntohl(type));
+
+	for (i = 0; i < table->num_ents; i++) {
+		entries = rcu_dereference(table->entries);
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "type:0x%x evalue:0x%x\n",
+					 type, entries[i].value);
+		if (type == entries[i].value) {
+			*isencap = entries[i].encap;
+			return entries[i].node;
+		} else if (ntohs(type) == entries[i].value) {
+			// for 2 bytes
+			*isencap = entries[i].encap;
+			return entries[i].node;
+		} else if (ntohl(type) == entries[i].value) {
+			// for 4 bytes
+			*isencap = entries[i].encap;
+			return entries[i].node;
+		}
+		// for 3 bytes
+		tmp = ntohl(type);
+		tmp = tmp >> 8;
+		KPARSER_KMOD_DEBUG_PRINT(dflags, "tmp:%x", tmp);
+		if (tmp == entries[i].value) {
+			*isencap = entries[i].encap;
+			return entries[i].node;
+		}
+	}
+
+	return NULL;
+}
+
+/* Lookup a type in a node TLV table */
+static const struct kparser_parse_tlv_node
+*lookup_tlv_node(__u32 dflags, __u8 type,
+		 const struct kparser_proto_tlvs_table *table)
+{
+	int i;
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags, "type:%d\n", type);
+
+	for (i = 0; i < table->num_ents; i++) {
+		KPARSER_KMOD_DEBUG_PRINT(dflags, "table_type:%d\n",
+					 table->entries[i].type);
+		if (type == table->entries[i].type)
+			return table->entries[i].node;
+	}
+
+	return NULL;
+}
+
+/* Lookup a flag-fields index in a protocol node flag-fields table
+ * TODO: This needs to optimized later to use array for better performance
+ */
+static const struct kparser_parse_flag_field_node
+*lookup_flag_field_node(__u32 dflags, __u32 flag,
+			const struct kparser_proto_flag_fields_table *table)
+{
+	int i;
+
+	for (i = 0; i < table->num_ents; i++) {
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "flag:%x eflag[%d]:%x\n", flag, i,
+					 table->entries[i].flag);
+		if (flag == table->entries[i].flag)
+			return table->entries[i].node;
+	}
+
+	return NULL;
+}
+
+/* Metadata table processing */
+static int extract_metadata_table(__u32 dflags,
+				  const struct kparser_parser *parser,
+				  const struct kparser_metadata_table *metadata_table,
+				  const void *_hdr, size_t hdr_len, size_t hdr_offset,
+				  void *_metadata, void *_frame,
+				  const struct kparser_ctrl_data *ctrl)
+{
+	struct kparser_metadata_extract *entries;
+	int i, ret;
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags, "cnt:%d\n", metadata_table->num_ents);
+
+	for (i = 0; i < metadata_table->num_ents; i++) {
+		entries = rcu_dereference(metadata_table->entries);
+		ret = kparser_metadata_extract(parser, entries[i],
+					       _hdr, hdr_len, hdr_offset,
+					       _metadata, _frame, ctrl);
+		if (ret != KPARSER_OKAY)
+			break;
+	}
+	return ret;
+}
+
+/* evaluate next proto parameterized context */
+static int eval_parameterized_next_proto(__u32 dflags,
+					 const struct kparser_parameterized_next_proto *pf,
+					 void *_hdr)
+{
+	__u32 next_proto;
+	__u32 mask = pf->mask;
+
+	_hdr += pf->src_off;
+
+	switch (pf->size) {
+	case 1:
+		next_proto = *(__u8 *)_hdr;
+		if (pf->mask > 0xff)
+			mask = 0xff;
+		break;
+	case 2:
+		next_proto = *(__u16 *)_hdr;
+		if (pf->mask > 0xffff)
+			mask = 0xffff;
+		break;
+	case 3:
+		memcpy(&next_proto, _hdr, 3);
+		if (pf->mask > 0xffffff)
+			mask = 0xffffff;
+		break;
+	case 4:
+		next_proto = *(__u32 *)_hdr;
+		if (pf->mask > 0xffffffff)
+			mask = 0xffffffff;
+		break;
+
+	default:
+		return KPARSER_STOP_UNKNOWN_PROTO;
+	}
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags,
+				 "next_proto:%x mask:%x rs:%x pf->src_off:%u pf->size:%u",
+				 next_proto, mask,
+				 pf->right_shift, pf->src_off, pf->size);
+
+	return (next_proto & mask) >> pf->right_shift;
+}
+
+/* evaluate len parameterized context */
+static ssize_t eval_parameterized_len(const struct kparser_parameterized_len *pf, void *_hdr)
+{
+	__u32 len;
+
+	_hdr += pf->src_off;
+
+	switch (pf->size) {
+	case 1:
+		len = *(__u8 *)_hdr;
+		break;
+	case 2:
+		len = *(__u16 *)_hdr;
+		break;
+	case 3:
+		len = 0;
+		memcpy(&len, _hdr, 3);
+		break; /* TODO */
+	case 4:
+		len = *(__u32 *)_hdr;
+		break;
+	default:
+		return KPARSER_STOP_LENGTH;
+	}
+
+	len = (len & pf->mask) >> pf->right_shift;
+
+	return (len * pf->multiplier) + pf->add_value;
+}
+
+/* evaluate conditionals */
+static bool eval_cond_exprs_and_table(const struct kparser_condexpr_table *table, void *_hdr)
+{
+	int i;
+
+	for (i = 0; i < table->num_ents; i++)
+		if (!kparser_expr_evaluate(table->entries[i], _hdr))
+			return false;
+
+	return true;
+}
+
+/* evaluate table of conditionals */
+static bool eval_cond_exprs_or_table(const struct kparser_condexpr_table *table, void *_hdr)
+{
+	int i;
+
+	for (i = 0; i < table->num_ents; i++)
+		if (kparser_expr_evaluate(table->entries[i], _hdr))
+			return true;
+
+	return false;
+}
+
+/* evaluate list of table of conditionals */
+static int eval_cond_exprs(__u32 dflags,
+			   const struct kparser_condexpr_tables *tables,
+			   void *_hdr)
+{
+	bool res;
+	int i;
+
+	for (i = 0; i < tables->num_ents; i++) {
+		const struct kparser_condexpr_table *table = tables->entries[i];
+
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "type:%d err:%d\n",
+					 table->type, table->default_fail);
+
+		switch (table->type) {
+		case KPARSER_CONDEXPR_TYPE_OR:
+			res = eval_cond_exprs_or_table(table, _hdr);
+			break;
+		case KPARSER_CONDEXPR_TYPE_AND:
+			res = eval_cond_exprs_and_table(table, _hdr);
+			break;
+		}
+		if (!res) {
+			KPARSER_KMOD_DEBUG_PRINT(dflags,
+						 "i:%d type:%d err:%d\n",
+						 i, table->type,
+						 table->default_fail);
+
+			return table->default_fail;
+		}
+	}
+
+	return KPARSER_OKAY;
+}
+
+/* process one tlv node */
+static int kparser_parse_one_tlv(__u32 dflags,
+				 const struct kparser_parser *parser,
+				 const struct kparser_parse_tlvs_node *parse_tlvs_node,
+				 const struct kparser_parse_tlv_node *parse_tlv_node,
+				 void *_obj_ref, void *_hdr,
+				 size_t tlv_len, size_t tlv_offset, void *_metadata,
+				 void *_frame, struct kparser_ctrl_data *ctrl)
+{
+	const struct kparser_parse_tlv_node *next_parse_tlv_node;
+	const struct kparser_metadata_table *metadata_table;
+	const struct kparser_proto_tlv_node *proto_tlv_node;
+	const struct kparser_proto_tlv_node_ops *proto_ops;
+	struct kparser_proto_tlvs_table *overlay_table;
+	int type, ret;
+
+parse_again:
+
+	proto_tlv_node = &parse_tlv_node->proto_tlv_node;
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags,
+				 "kParser parsing TLV %s\n",
+				 parse_tlv_node->name);
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags,
+				 "tlv_len:%lu min_len:%lu\n",
+				 tlv_len, proto_tlv_node->min_len);
+
+	if (tlv_len < proto_tlv_node->min_len || tlv_len > proto_tlv_node->max_len) {
+		/* Treat check length error as an unrecognized TLV */
+		parse_tlv_node = rcu_dereference(parse_tlvs_node->tlv_wildcard_node);
+		if (parse_tlv_node)
+			goto parse_again;
+		else
+			return parse_tlvs_node->unknown_tlv_type_ret;
+	}
+
+	proto_ops = &proto_tlv_node->ops;
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags, "cond_exprs_parameterized:%d\n",
+				 proto_ops->cond_exprs_parameterized);
+
+	if (proto_ops->cond_exprs_parameterized) {
+		ret = eval_cond_exprs(dflags,
+				      &proto_ops->cond_exprs, _hdr);
+		if (ret != KPARSER_OKAY)
+			return ret;
+	}
+
+	metadata_table = rcu_dereference(parse_tlv_node->metadata_table);
+	if (metadata_table) {
+		ret = extract_metadata_table(dflags,
+					     parser,
+					     metadata_table,
+					     _hdr, tlv_len, tlv_offset,
+					     _metadata,
+					     _frame, ctrl);
+		if (ret != KPARSER_OKAY)
+			return ret;
+	}
+
+	overlay_table = rcu_dereference(parse_tlv_node->overlay_table);
+	if (!overlay_table)
+		return KPARSER_OKAY;
+
+	/* We have an TLV overlay  node */
+	if (proto_ops && proto_ops->overlay_type_parameterized)
+		type = eval_parameterized_next_proto(dflags,
+						     &proto_ops->pfoverlay_type,
+						     _hdr);
+	else
+		type = tlv_len;
+
+	if (type < 0)
+		return type;
+
+	/* Get TLV node */
+	next_parse_tlv_node = lookup_tlv_node(dflags, type, overlay_table);
+	if (next_parse_tlv_node) {
+		parse_tlv_node = next_parse_tlv_node;
+		goto parse_again;
+	}
+
+	/* Unknown TLV overlay node */
+	next_parse_tlv_node = rcu_dereference(parse_tlv_node->overlay_wildcard_node);
+	if (next_parse_tlv_node) {
+		parse_tlv_node = next_parse_tlv_node;
+		goto parse_again;
+	}
+
+	return parse_tlv_node->unknown_overlay_ret;
+}
+
+/* tlv loop limit validator */
+static int loop_limit_exceeded(int ret, unsigned int disp)
+{
+	switch (disp) {
+	case KPARSER_LOOP_DISP_STOP_OKAY:
+		return KPARSER_STOP_OKAY;
+	case KPARSER_LOOP_DISP_STOP_NODE_OKAY:
+		return KPARSER_STOP_NODE_OKAY;
+	case KPARSER_LOOP_DISP_STOP_SUB_NODE_OKAY:
+		return KPARSER_STOP_SUB_NODE_OKAY;
+	case KPARSER_LOOP_DISP_STOP_FAIL:
+	default:
+		return ret;
+	}
+}
+
+/* process packet value using parameters provided */
+static __u64 eval_get_value(const struct kparser_parameterized_get_value *pf, void *_hdr)
+{
+	__u64 ret;
+
+	(void)__kparser_metadata_bytes_extract(_hdr + pf->src_off, (__u8 *)&ret, pf->size, false);
+
+	return ret;
+}
+
+/* process and parse multiple tlvs */
+static int kparser_parse_tlvs(__u32 dflags,
+			      const struct kparser_parser *parser,
+			      const struct kparser_parse_node *parse_node,
+			      void *_obj_ref,
+			      void *_hdr, size_t hdr_len, size_t hdr_offset,
+			      void *_metadata, void *_frame,
+			      const struct kparser_ctrl_data *ctrl)
+{
+	unsigned int loop_cnt = 0, non_pad_cnt = 0, pad_len = 0;
+	const struct kparser_proto_tlvs_table *tlv_proto_table;
+	const struct kparser_parse_tlvs_node *parse_tlvs_node;
+	const struct kparser_proto_tlvs_node *proto_tlvs_node;
+	const struct kparser_parse_tlv_node *parse_tlv_node;
+	struct kparser_ctrl_data tlv_ctrl = {};
+	unsigned int consec_pad = 0;
+	size_t len, tlv_offset;
+	ssize_t off, tlv_len;
+	__u8 *cp = _hdr;
+	int type = -1, ret;
+
+	parse_tlvs_node = (struct kparser_parse_tlvs_node *)parse_node;
+	proto_tlvs_node = (struct kparser_proto_tlvs_node *)&parse_node->tlvs_proto_node;
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags,
+				 "fixed_start_offset:%d start_offset:%lu\n",
+				 proto_tlvs_node->fixed_start_offset,
+				 proto_tlvs_node->start_offset);
+
+	/* Assume hlen marks end of TLVs */
+	if (proto_tlvs_node->fixed_start_offset)
+		off = proto_tlvs_node->start_offset;
+	else
+		off = eval_parameterized_len(&proto_tlvs_node->ops.pfstart_offset, cp);
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags, "off:%ld\n", off);
+
+	if (off < 0)
+		return KPARSER_STOP_LENGTH;
+
+	/* We assume start offset is less than or equal to minimal length */
+	len = hdr_len - off;
+
+	cp += off;
+	tlv_offset = hdr_offset + off;
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags, "len:%ld tlv_offset:%ld\n",
+				 len, tlv_offset);
+
+	/* This is the main TLV processing loop */
+	while (len > 0) {
+		if (++loop_cnt > parse_tlvs_node->config.max_loop)
+			return loop_limit_exceeded(KPARSER_STOP_LOOP_CNT,
+						   parse_tlvs_node->config.disp_limit_exceed);
+
+		if (proto_tlvs_node->pad1_enable &&
+		    *cp == proto_tlvs_node->pad1_val) {
+			/* One byte padding, just advance */
+			cp++;
+			tlv_offset++;
+			len--;
+			if (++pad_len > parse_tlvs_node->config.max_plen ||
+			    ++consec_pad > parse_tlvs_node->config.max_c_pad)
+				return loop_limit_exceeded(KPARSER_STOP_TLV_PADDING,
+							   parse_tlvs_node->
+							   config.disp_limit_exceed);
+			continue;
+		}
+
+		if (proto_tlvs_node->eol_enable &&
+		    *cp == proto_tlvs_node->eol_val) {
+			cp++;
+			tlv_offset++;
+			len--;
+
+			/* Hit EOL, we're done */
+			break;
+		}
+
+		if (len < proto_tlvs_node->min_len) {
+			/* Length error */
+			return loop_limit_exceeded(KPARSER_STOP_TLV_LENGTH,
+						   parse_tlvs_node->config.disp_limit_exceed);
+		}
+
+		/* If the len function is not set this degenerates to an
+		 * array of fixed sized values (which maybe be useful in
+		 * itself now that I think about it)
+		 */
+		do {
+			KPARSER_KMOD_DEBUG_PRINT(dflags,
+						 "len_parameterized:%d min_len:%lu\n",
+						 proto_tlvs_node->ops.len_parameterized,
+						 proto_tlvs_node->min_len);
+			if (proto_tlvs_node->ops.len_parameterized) {
+				tlv_len = eval_parameterized_len(&proto_tlvs_node->ops.pflen, cp);
+			} else {
+				tlv_len = proto_tlvs_node->min_len;
+				break;
+			}
+
+			KPARSER_KMOD_DEBUG_PRINT(dflags,
+						 "tlv_len:%lu\n", tlv_len);
+
+			if (!tlv_len || len < tlv_len)
+				return loop_limit_exceeded(KPARSER_STOP_TLV_LENGTH,
+							   parse_tlvs_node->config.
+							   disp_limit_exceed);
+
+			if (tlv_len < proto_tlvs_node->min_len)
+				return loop_limit_exceeded(KPARSER_STOP_TLV_LENGTH,
+							   parse_tlvs_node->config.
+							   disp_limit_exceed);
+		} while (0);
+
+		type = eval_parameterized_next_proto(dflags,
+						     &proto_tlvs_node->ops.pftype,
+						     cp);
+
+		KPARSER_KMOD_DEBUG_PRINT(dflags, "type:%d\n", type);
+
+		if (proto_tlvs_node->padn_enable &&
+		    type == proto_tlvs_node->padn_val) {
+			/* N byte padding, just advance */
+			pad_len += tlv_len;
+			if (pad_len > parse_tlvs_node->config.max_plen ||
+			    ++consec_pad > parse_tlvs_node->config.max_c_pad)
+				return loop_limit_exceeded(KPARSER_STOP_TLV_PADDING,
+							   parse_tlvs_node->config.
+							   disp_limit_exceed);
+			goto next_tlv;
+		}
+
+		/* Get TLV node */
+		tlv_proto_table = rcu_dereference(parse_tlvs_node->tlv_proto_table);
+		if (tlv_proto_table)
+			parse_tlv_node = lookup_tlv_node(dflags, type, tlv_proto_table);
+parse_one_tlv:
+		if (parse_tlv_node) {
+			const struct kparser_proto_tlv_node *proto_tlv_node =
+				&parse_tlv_node->proto_tlv_node;
+
+			if (proto_tlv_node) {
+				if (proto_tlv_node->is_padding) {
+					pad_len += tlv_len;
+					if (pad_len > parse_tlvs_node->config.max_plen ||
+					    ++consec_pad > parse_tlvs_node->config.max_c_pad)
+						return loop_limit_exceeded(KPARSER_STOP_TLV_PADDING,
+									   parse_tlvs_node->config.
+									   disp_limit_exceed);
+				} else if (++non_pad_cnt > parse_tlvs_node->config.max_non) {
+					return loop_limit_exceeded(KPARSER_STOP_OPTION_LIMIT,
+								   parse_tlvs_node->
+								   config.disp_limit_exceed);
+				}
+			}
+
+			ret = kparser_parse_one_tlv(dflags, parser,
+						    parse_tlvs_node,
+						    parse_tlv_node,
+						    _obj_ref, cp, tlv_len,
+						    tlv_offset, _metadata,
+						    _frame, &tlv_ctrl);
+			if (ret != KPARSER_OKAY)
+				return ret;
+		} else {
+			/* Unknown TLV */
+			parse_tlv_node = rcu_dereference(parse_tlvs_node->tlv_wildcard_node);
+			if (parse_tlv_node) {
+				/* If a wilcard node is present parse that
+				 * node as an overlay to this one. The
+				 * wild card node can perform error processing
+				 */
+				goto parse_one_tlv;
+			}
+			/* Return default error code. Returning
+			 * KPARSER_OKAY means skip
+			 */
+			if (parse_tlvs_node->unknown_tlv_type_ret != KPARSER_OKAY)
+				return parse_tlvs_node->unknown_tlv_type_ret;
+		}
+
+		/* Move over current header */
+next_tlv:
+		cp += tlv_len;
+		tlv_offset += tlv_len;
+		len -= tlv_len;
+	}
+
+	return KPARSER_OKAY;
+}
+
+/* process and parse flag fields */
+static ssize_t kparser_parse_flag_fields(__u32 dflags,
+					 const struct kparser_parser *parser,
+					 const struct kparser_parse_node *parse_node,
+					 void *_obj_ref,
+					 void *_hdr, size_t hdr_len,
+					 size_t hdr_offset, void *_metadata,
+					 void *_frame,
+					 const struct kparser_ctrl_data *ctrl,
+					 size_t parse_len)
+{
+	const struct kparser_parse_flag_fields_node *parse_flag_fields_node;
+	const struct kparser_proto_flag_fields_node *proto_flag_fields_node;
+	const struct kparser_parse_flag_field_node *parse_flag_field_node;
+	const struct kparser_metadata_table *metadata_table;
+	ssize_t off = -1, field_len, field_offset, res = 0;
+	const struct kparser_flag_fields *flag_fields;
+	__u32 flags = 0;
+	int i, ret;
+
+	parse_flag_fields_node = (struct kparser_parse_flag_fields_node *)parse_node;
+	proto_flag_fields_node = (struct kparser_proto_flag_fields_node *)&parse_node->proto_node;
+
+	flag_fields = rcu_dereference(proto_flag_fields_node->flag_fields);
+	if (!flag_fields)
+		return KPARSER_OKAY;
+
+	if (proto_flag_fields_node->ops.get_flags_parameterized)
+		flags = eval_get_value(&proto_flag_fields_node->ops.pfget_flags, _hdr);
+
+	/* Position at start of field data */
+	if (proto_flag_fields_node->ops.flag_fields_len)
+		off = proto_flag_fields_node->ops.hdr_length;
+	else if (proto_flag_fields_node->ops.start_fields_offset_parameterized)
+		off = eval_parameterized_len(&proto_flag_fields_node->ops.pfstart_fields_offset,
+					     _hdr);
+	else
+		return KPARSER_STOP_LENGTH;
+
+	if (off < 0)
+		return off;
+
+	if (hdr_offset + off > parse_len)
+		return KPARSER_STOP_LENGTH;
+	_hdr += off;
+	hdr_offset += off;
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags,
+				 "flag_fields->num_idx:%lu\n",
+				 flag_fields->num_idx);
+
+	for (i = 0; i < flag_fields->num_idx; i++) {
+		off = kparser_flag_fields_offset(i, flags, flag_fields);
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "off:%ld pflag:%x flag:%x\n",
+					 off, flags, flag_fields->fields[i].flag);
+		if (off < 0)
+			continue;
+
+		if (hdr_offset + flag_fields->fields[i].size > parse_len)
+			return KPARSER_STOP_LENGTH;
+
+		res += flag_fields->fields[i].size;
+
+		/* Flag field is present, try to find in the parse node
+		 * table based on index in proto flag-fields
+		 */
+		parse_flag_field_node =
+			lookup_flag_field_node(dflags,
+					       flag_fields->fields[i].flag,
+					       parse_flag_fields_node->flag_fields_proto_table);
+		if (parse_flag_field_node) {
+			const struct kparser_parse_flag_field_node_ops
+				*ops = &parse_flag_field_node->ops;
+			__u8 *cp = _hdr + off;
+
+			field_len = flag_fields->fields[i].size;
+			field_offset = hdr_offset + off;
+
+			if (field_offset > parse_len)
+				return KPARSER_STOP_LENGTH;
+
+			KPARSER_KMOD_DEBUG_PRINT(dflags,
+						 "kParser parsing flag-field %s\n",
+						 parse_flag_field_node->name);
+
+			if (eval_cond_exprs(dflags, &ops->cond_exprs, cp) < 0)
+				return KPARSER_STOP_COMPARE;
+
+			metadata_table = rcu_dereference(parse_flag_field_node->metadata_table);
+			if (metadata_table) {
+				ret = extract_metadata_table(dflags,
+							     parser,
+							     parse_flag_field_node->metadata_table,
+							     cp, field_len, field_offset, _metadata,
+							     _frame, ctrl);
+				if (ret != KPARSER_OKAY)
+					return ret;
+			}
+		}
+	}
+
+	return res;
+}
+
+/* process ok/fail/atencap nodes */
+static int __kparser_run_exit_node(__u32 dflags,
+				   const struct kparser_parser *parser,
+				   const struct kparser_parse_node *parse_node,
+				   void *_obj_ref, void *_hdr,
+				   size_t hdr_offset, ssize_t hdr_len,
+				   void *_metadata, void *_frame,
+				   struct kparser_ctrl_data *ctrl)
+{
+	const struct kparser_metadata_table *metadata_table;
+	int ret;
+
+	KPARSER_KMOD_DEBUG_PRINT(dflags,
+				 "exit node:%s\n", parse_node->name);
+	/* Run an exit parse node. This is an okay_node, fail_node, or
+	 * atencap_node
+	 */
+	metadata_table = rcu_dereference(parse_node->metadata_table);
+	if (metadata_table) {
+		ret = extract_metadata_table(dflags,
+					     parser, metadata_table, _hdr,
+					     hdr_len, hdr_offset, _metadata,
+					     _frame, ctrl);
+		if (ret != KPARSER_OKAY)
+			return ret;
+	}
+
+	return KPARSER_OKAY;
+}
+
+/* __kparser_parse(): Function to parse a void * packet buffer using a parser instance key.
+ *
+ * parser: Non NULL kparser_get_parser() returned and cached opaque pointer
+ * referencing a valid parser instance.
+ * _hdr: input packet buffer
+ * parse_len: length of input packet buffer
+ * _metadata: User provided metadata buffer. It must be same as configured
+ * metadata objects in CLI.
+ * metadata_len: Total length of the user provided metadata buffer.
+ *
+ * return: kParser error code as defined in include/uapi/linux/kparser.h
+ *
+ * rcu lock must be held before calling this function.
+ */
+int ___kparser_parse(const void *obj, void *_hdr, size_t parse_len,
+		     struct sk_buff *skb, void *_metadata, size_t metadata_len)
+{
+	return 0;
+}
+
+int __kparser_parse(const void *obj, void *_hdr, size_t parse_len,
+		    void *_metadata, size_t metadata_len)
+{
+	const struct kparser_parse_node *next_parse_node, *atencap_node;
+	const struct kparser_parse_node *parse_node, *wildcard_node;
+	struct kparser_ctrl_data ctrl = { .ret = KPARSER_OKAY };
+	const struct kparser_metadata_table *metadata_table;
+	const struct kparser_proto_table *proto_table;
+	const struct kparser_proto_node *proto_node;
+	const struct kparser_parser *parser = obj;
+	int type = -1, i, ret, framescnt;
+	struct kparser_counters *cntrs;
+	void *_frame, *_obj_ref = NULL;
+	const void *base_hdr = _hdr;
+	ssize_t hdr_offset = 0;
+	ssize_t hdr_len, res;
+	__u32 frame_num = 0;
+	__u32 dflags = 0;
+	bool currencap;
+
+	if (parser && parser->config.max_encaps > framescnt)
+		framescnt = parser->config.max_encaps;
+
+	if (!parser || !_metadata || metadata_len == 0 || !_hdr || parse_len == 0 ||
+	    (((framescnt * parser->config.frame_size) +
+	       parser->config.metameta_size) > metadata_len)) {
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "one or more empty/invalid param(s)\n");
+		return -EINVAL;
+	}
+
+	if (parser->kparser_start_signature != KPARSERSTARTSIGNATURE ||
+	    parser->kparser_end_signature != KPARSERENDSIGNATURE) {
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "%s:corrupted kparser signature:start:0x%02x, end:0x%02x\n",
+			 __func__, parser->kparser_start_signature, parser->kparser_end_signature);
+		return -EINVAL;
+	}
+
+	if (parse_len < parser->config.metameta_size) {
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "parse buf err, parse_len:%lu, mmd_len:%lu\n",
+					 parse_len, parser->config.metameta_size);
+		return -EINVAL;
+	}
+
+	_frame = _metadata + parser->config.metameta_size;
+	dflags = parser->config.flags;
+
+	if (dflags & KPARSER_F_DEBUG_DATAPATH) {
+		/* This code is required for regression tests also */
+		pr_alert("kParserdump:len:%lu\n", parse_len);
+		print_hex_dump_bytes("kParserdump:rcvd_pkt:",
+				     DUMP_PREFIX_OFFSET, _hdr, parse_len);
+	}
+
+	ctrl.hdr_base = _hdr;
+	ctrl.node_cnt = 0;
+	ctrl.encap_levels = 0;
+
+	cntrs = rcu_dereference(parser->cntrs);
+	if (cntrs) {
+		/* Initialize parser counters */
+		memset(cntrs, 0, sizeof(parser->cntrs_len));
+	}
+
+	parse_node = rcu_dereference(parser->root_node);
+	if (!parse_node) {
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "root node missing,parser:%s\n",
+					 parser->name);
+		return -ENOENT;
+	}
+
+	/* Main parsing loop. The loop normal teminates when we encounter a
+	 * leaf protocol node, an error condition, hitting limit on layers of
+	 * encapsulation, protocol condition to stop (i.e. flags that
+	 * indicate to stop at flow label or hitting fragment), or
+	 * unknown protocol result in table lookup for next node.
+	 */
+	do {
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "Parsing node:%s\n",
+					 parse_node->name);
+		currencap = false;
+		proto_node = &parse_node->proto_node;
+		hdr_len = proto_node->min_len;
+
+		if (++ctrl.node_cnt > parser->config.max_nodes) {
+			ctrl.ret = KPARSER_STOP_MAX_NODES;
+			goto parser_out;
+		}
+		/* Protocol node length checks */
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "kParser parsing %s\n",
+					 parse_node->name);
+		/* when SKB is passed, if parse_len < hdr_len, then
+		 * try to do skb_pullup(hdr_len) here. reset parse_len based on
+		 * new parse_len, reset data ptr. Do this inside this loop.
+		 */
+		if (parse_len < hdr_len) {
+			ctrl.ret = KPARSER_STOP_LENGTH;
+			goto parser_out;
+		}
+
+		do {
+			if (!proto_node->ops.len_parameterized)
+				break;
+
+			hdr_len = eval_parameterized_len(&proto_node->ops.pflen, _hdr);
+
+			KPARSER_KMOD_DEBUG_PRINT(dflags,
+						 "eval_hdr_len:%ld min_len:%lu\n",
+						 hdr_len, proto_node->min_len);
+
+			if (hdr_len < proto_node->min_len) {
+				ctrl.ret = hdr_len < 0 ? hdr_len : KPARSER_STOP_LENGTH;
+				goto parser_out;
+			}
+			if (parse_len < hdr_len) {
+				ctrl.ret = KPARSER_STOP_LENGTH;
+				goto parser_out;
+			}
+		} while (0);
+
+		hdr_offset = _hdr - base_hdr;
+		ctrl.pkt_len = parse_len;
+
+		/* Callback processing order
+		 *    1) Extract Metadata
+		 *    2) Process TLVs
+		 *	2.a) Extract metadata from TLVs
+		 *	2.b) Process TLVs
+		 *    3) Process protocol
+		 */
+
+		metadata_table = rcu_dereference(parse_node->metadata_table);
+		/* Extract metadata, per node processing */
+		if (metadata_table) {
+			ctrl.ret = extract_metadata_table(dflags,
+							  parser,
+							  metadata_table,
+							  _hdr, hdr_len, hdr_offset,
+							  _metadata, _frame, &ctrl);
+			if (ctrl.ret != KPARSER_OKAY)
+				goto parser_out;
+		}
+
+		/* Process node type */
+		switch (parse_node->node_type) {
+		case KPARSER_NODE_TYPE_PLAIN:
+		default:
+			break;
+		case KPARSER_NODE_TYPE_TLVS:
+			/* Process TLV nodes */
+			ctrl.ret = kparser_parse_tlvs(dflags, parser,
+						      parse_node,
+						      _obj_ref, _hdr, hdr_len,
+						      hdr_offset, _metadata,
+						      _frame, &ctrl);
+check_processing_return:
+			switch (ctrl.ret) {
+			case KPARSER_STOP_OKAY:
+				goto parser_out;
+			case KPARSER_OKAY:
+				break; /* Go to the next node */
+			case KPARSER_STOP_NODE_OKAY:
+				/* Note KPARSER_STOP_NODE_OKAY means that
+				 * post loop processing is not
+				 * performed
+				 */
+				ctrl.ret = KPARSER_OKAY;
+				goto after_post_processing;
+			case KPARSER_STOP_SUB_NODE_OKAY:
+				ctrl.ret = KPARSER_OKAY;
+				break; /* Just go to next node */
+			default:
+				goto parser_out;
+			}
+			break;
+		case KPARSER_NODE_TYPE_FLAG_FIELDS:
+			/* Process flag-fields */
+			res = kparser_parse_flag_fields(dflags, parser,
+							parse_node,
+							_obj_ref,
+							_hdr, hdr_len,
+							hdr_offset,
+							_metadata,
+							_frame,
+							&ctrl, parse_len);
+			if (res < 0) {
+				ctrl.ret = res;
+				goto check_processing_return;
+			}
+			hdr_len += res;
+		}
+
+after_post_processing:
+		/* Proceed to next protocol layer */
+
+		proto_table = rcu_dereference(parse_node->proto_table);
+		wildcard_node = rcu_dereference(parse_node->wildcard_node);
+		if (!proto_table && !wildcard_node) {
+			/* Leaf parse node */
+			KPARSER_KMOD_DEBUG_PRINT(dflags, "Leaf node");
+			goto parser_out;
+		}
+
+		if (proto_table) {
+			do {
+				if (proto_node->ops.cond_exprs_parameterized) {
+					ctrl.ret =
+						eval_cond_exprs(dflags,
+								&proto_node->ops.cond_exprs,
+								_hdr);
+					if (ctrl.ret != KPARSER_OKAY)
+						goto parser_out;
+				}
+
+				if (!proto_table)
+					break;
+				type =
+					eval_parameterized_next_proto(dflags,
+								      &proto_node->ops.pfnext_proto,
+								      _hdr);
+				KPARSER_KMOD_DEBUG_PRINT(dflags,
+							 "nxt_proto key:%x\n",
+							 type);
+				if (type < 0) {
+					ctrl.ret = type;
+					goto parser_out;
+				}
+
+				/* Get next node */
+				next_parse_node = lookup_node(dflags,
+							      type,
+							      proto_table,
+							      &currencap);
+
+				if (next_parse_node)
+					goto found_next;
+			} while (0);
+		}
+
+		/* Try wildcard node. Either table lookup failed to find a
+		 * node or there is only a wildcard
+		 */
+		if (wildcard_node) {
+			/* Perform default processing in a wildcard node */
+			next_parse_node = wildcard_node;
+		} else {
+			/* Return default code. Parsing will stop
+			 * with the inidicated code
+			 */
+			ctrl.ret = parse_node->unknown_ret;
+			goto parser_out;
+		}
+
+found_next:
+		/* Found next protocol node, set up to process */
+		if (!proto_node->overlay) {
+			/* Move over current header */
+			_hdr += hdr_len;
+			parse_len -= hdr_len;
+		}
+
+		parse_node = next_parse_node;
+		if (currencap || proto_node->encap) {
+			/* Check is there is an atencap_node configured for
+			 * the parser
+			 */
+			atencap_node = rcu_dereference(parser->atencap_node);
+			if (atencap_node) {
+				ret = __kparser_run_exit_node(dflags,
+							      parser,
+							      atencap_node,
+							      _obj_ref,
+							      _hdr, hdr_offset,
+							      hdr_len,
+							      _metadata, _frame,
+							      &ctrl);
+				if (ret != KPARSER_OKAY)
+					goto parser_out;
+			}
+
+			/* New encapsulation layer. Check against
+			 * number of encap layers allowed and also
+			 * if we need a new metadata frame.
+			 */
+			if (++ctrl.encap_levels > parser->config.max_encaps) {
+				ctrl.ret = KPARSER_STOP_ENCAP_DEPTH;
+				goto parser_out;
+			}
+
+			if (frame_num < parser->config.max_frames) {
+				_frame += parser->config.frame_size;
+				frame_num++;
+			}
+
+			/* Check if parser has counters that need to be reset
+			 * at encap
+			 */
+			if (parser->cntrs)
+				for (i = 0; i < KPARSER_CNTR_NUM_CNTRS; i++)
+					if (parser->cntrs_conf.cntrs[i].reset_on_encap)
+						cntrs->cntr[i] = 0;
+		}
+
+	} while (1);
+
+parser_out:
+	/* Convert PANDA_OKAY to PANDA_STOP_OKAY if parser is exiting normally.
+	 * This means that okay_node will see PANDA_STOP_OKAY in ctrl.ret
+	 */
+	ctrl.ret = ctrl.ret == KPARSER_OKAY ? KPARSER_STOP_OKAY : ctrl.ret;
+
+	parse_node = (ctrl.ret == KPARSER_OKAY || KPARSER_IS_OK_CODE(ctrl.ret)) ?
+		      rcu_dereference(parser->okay_node) : rcu_dereference(parser->fail_node);
+
+	if (!parse_node) {
+		if (dflags & KPARSER_F_DEBUG_DATAPATH) {
+			/* This code is required for regression tests also */
+			pr_alert("kParserdump:metadata_len:%lu\n", metadata_len);
+			print_hex_dump_bytes("kParserdump:md:",
+					     DUMP_PREFIX_OFFSET,
+					     _metadata, metadata_len);
+		}
+		return ctrl.ret;
+	}
+
+	/* Run an exit parse node. This is either the okay node or the fail
+	 * node that is set in parser config
+	 */
+	ret = __kparser_run_exit_node(dflags, parser, parse_node, _obj_ref,
+				      _hdr, hdr_offset, hdr_len,
+				      _metadata, _frame, &ctrl);
+	if (ret != KPARSER_OKAY)
+		ctrl.ret = (ctrl.ret == KPARSER_STOP_OKAY) ? ret : ctrl.ret;
+
+	if (dflags & KPARSER_F_DEBUG_DATAPATH) {
+		/* This code is required for regression tests also */
+		pr_alert("kParserdump:metadata_len:%lu\n", metadata_len);
+		print_hex_dump_bytes("kParserdump:md:", DUMP_PREFIX_OFFSET,
+				     _metadata, metadata_len);
+	}
+
+	return ctrl.ret;
+}
+EXPORT_SYMBOL(__kparser_parse);
+
+static inline void *
+kparser_get_parser_ctx(const struct kparser_hkey *kparser_key)
+{
+	void *ptr, *parser;
+
+	if (!kparser_key)
+		return NULL;
+
+	if (kparser_key->id >= KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_START &&
+	    kparser_key->id <= KPARSER_PARSER_FAST_LOOKUP_RSVD_ID_STOP) {
+		rcu_read_lock();
+		ptr = kparser_fast_lookup_array[kparser_key->id];
+		rcu_read_unlock();
+	} else {
+		ptr = kparser_namespace_lookup(KPARSER_NS_PARSER, kparser_key);
+	}
+
+	parser = rcu_dereference(ptr);
+
+	return parser;
+}
+
+/* kparser_parse(): Function to parse a skb using a parser instance key.
+ *
+ * skb: input packet skb
+ * kparser_key: key of the associated kParser parser object which must be
+ *              already created via CLI.
+ * _metadata: User provided metadata buffer. It must be same as configured
+ *            metadata objects in CLI.
+ * metadata_len: Total length of the user provided metadata buffer.
+ * avoid_ref: Set this flag in case caller wants to avoid holding the reference
+ *            of the active parser object to save performance on the data path.
+ *            But please be advised, caller should hold the reference of the
+ *            parser object while using this data path. In this case, the CLI
+ *            can be used in advance to get the reference, and caller will also
+ *            need to release the reference via CLI once it is done with the
+ *            data path.
+ *
+ * return: kParser error code as defined in include/uapi/linux/kparser.h
+ */
+int kparser_parse(struct sk_buff *skb,
+		  const struct kparser_hkey *kparser_key,
+		  void *_metadata, size_t metadata_len, bool avoid_ref)
+{
+	struct kparser_glue_parser *k_prsr;
+	struct kparser_parser *parser;
+	void *data, *ptr;
+	size_t pktlen;
+	int err;
+	__u32 dflags = 0;
+
+	data = skb_mac_header(skb);
+	pktlen = skb_mac_header_len(skb) + skb->len;
+	if (pktlen > KPARSER_MAX_SKB_PACKET_LEN) {
+		skb_pull(skb, KPARSER_MAX_SKB_PACKET_LEN);
+		data = skb_mac_header(skb);
+		pktlen = skb_mac_header_len(skb) + skb->len;
+	}
+
+	err = skb_linearize(skb);
+	if (err < 0)
+		return err;
+	WARN_ON(skb->data_len);
+
+	/* TODO: do this pullup inside the loop of ___kparser_parse(), when
+	 * parse_len < hdr_len
+	 * if (pktlen > KPARSER_MAX_SKB_PACKET_LEN) {
+	 *	skb_pull(skb, KPARSER_MAX_SKB_PACKET_LEN);
+	 *	data = skb_mac_header(skb);
+	 *	pktlen = skb_mac_header_len(skb) + skb->len;
+	 * }
+	 * err = skb_linearize(skb);
+	 * if (err < 0)
+	 *	return err;
+	 * WARN_ON(skb->data_len);
+	 * ___kparser_parse(parser, skb, _metadata, metadata_len);
+	 */
+	k_prsr = kparser_get_parser_ctx(kparser_key);
+	if (!k_prsr) {
+		if (kparser_key)
+			KPARSER_KMOD_DEBUG_PRINT(dflags, "parser {%s:%u} is not found\n",
+						 kparser_key->name, kparser_key->id);
+		return -EINVAL;
+	}
+
+	rcu_read_lock();
+
+	if (likely(!avoid_ref))
+		kparser_ref_get(&k_prsr->glue.refcount);
+	parser = &k_prsr->parser;
+
+	ptr = kparser_namespace_lookup(KPARSER_NS_PARSER, kparser_key);
+	k_prsr = rcu_dereference(ptr);
+	parser = &k_prsr->parser;
+	if (!parser) {
+		KPARSER_KMOD_DEBUG_PRINT(dflags,
+					 "parser htbl lookup failure for key:{%s:%u}\n",
+					 kparser_key->name, kparser_key->id);
+		rcu_read_unlock();
+		if (likely(!avoid_ref))
+			kparser_ref_put(&k_prsr->glue.refcount);
+		return -ENOENT;
+	}
+
+	err = __kparser_parse(parser, data, pktlen, _metadata, metadata_len);
+
+	rcu_read_unlock();
+
+	if (likely(!avoid_ref))
+		kparser_ref_put(&k_prsr->glue.refcount);
+
+	return err;
+}
+EXPORT_SYMBOL(kparser_parse);
+
+/* kparser_get_parser(): Function to get an opaque reference of a parser instance and mark it
+ * immutable so that while actively using, it can not be deleted. The parser is identified by a key.
+ * It marks the associated parser and whole parse tree immutable so that when it is locked, it can
+ * not be deleted.
+ *
+ * kparser_key: key of the associated kParser parser object which must be
+ * already created via CLI.
+ *
+ * return: NULL if key not found, else an opaque parser instance pointer which
+ * can be used in the following APIs 3 and 4.
+ * avoid_ref: Set this flag in case caller wants to avoid holding the reference
+ *            of the active parser object to save performance on the data path.
+ *            But please be advised, caller should hold the reference of the
+ *            parser object while using this data path. In this case, the CLI
+ *            can be used in advance to get the reference, and caller will also
+ *            need to release the reference via CLI once it is done with the
+ *            data path.
+ *
+ * NOTE: This call makes the whole parser tree immutable. If caller calls this
+ * more than once, later caller will need to release the same parser exactly that
+ * many times using the API kparser_put_parser().
+ */
+const void *kparser_get_parser(const struct kparser_hkey *kparser_key,
+			       bool avoid_ref)
+{
+	struct kparser_glue_parser *k_prsr;
+
+	k_prsr = kparser_get_parser_ctx(kparser_key);
+	if (!k_prsr)
+		return NULL;
+
+	if (likely(!avoid_ref))
+		kparser_ref_get(&k_prsr->glue.refcount);
+
+	return &k_prsr->parser;
+}
+EXPORT_SYMBOL(kparser_get_parser);
+
+/* kparser_put_parser(): Function to return and undo the read only operation done previously by
+ * kparser_get_parser(). The parser instance is identified by using a previously obtained opaque
+ * parser pointer via API kparser_get_parser(). This undo the immutable change so that any component
+ * of the whole parse tree can be deleted again.
+ *
+ * parser: void *, Non NULL opaque pointer which was previously returned by kparser_get_parser().
+ * Caller can use cached opaque pointer as long as system does not restart and kparser.ko is not
+ * reloaded.
+ * avoid_ref: Set this flag only when this was used in the prio call to
+ *            kparser_get_parser(). Incorrect usage of this flag might cause
+ *            error and make the parser state unstable.
+ *
+ * return: boolean, true if put operation is success, else false.
+ *
+ * NOTE: This call makes the whole parser tree deletable for the very last call.
+ */
+bool kparser_put_parser(const void *obj, bool avoid_ref)
+{
+	const struct kparser_parser *parser = obj;
+	struct kparser_glue_parser *k_parser;
+
+	if (!parser)
+		return false;
+
+	if (likely(!avoid_ref)) {
+		k_parser = container_of(parser, struct kparser_glue_parser, parser);
+		kparser_ref_put(&k_parser->glue.refcount);
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(kparser_put_parser);
diff --git a/net/kparser/kparser_main.c b/net/kparser/kparser_main.c
new file mode 100644
index 000000000..8a100e191
--- /dev/null
+++ b/net/kparser/kparser_main.c
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kParser KMOD main module source file with netlink handlers
+ *
+ * Author:      Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#include <linux/errno.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/kparser.h>
+#include <linux/module.h>
+#include <linux/rtnetlink.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <net/act_api.h>
+#include <net/genetlink.h>
+#include <net/kparser.h>
+#include <net/netlink.h>
+#include <net/pkt_cls.h>
+
+#include "kparser.h"
+
+static int kparser_cli_cmd_handler(struct sk_buff *skb, struct genl_info *info);
+
+/* define netlink msg policies */
+#define NS_DEFINE_POLICY_ATTR_ENTRY(ID, STRUC_NAME, RSP_STRUC_NAME)	\
+	[KPARSER_ATTR_CREATE_##ID] = {					\
+		.type = NLA_BINARY,					\
+		.validation_type = NLA_VALIDATE_MIN,			\
+		.min = sizeof(struct STRUC_NAME)			\
+	},								\
+	[KPARSER_ATTR_UPDATE_##ID] = {					\
+		.type = NLA_BINARY,					\
+		.len = sizeof(struct STRUC_NAME),			\
+		.validation_type = NLA_VALIDATE_MIN,			\
+		.min = sizeof(struct STRUC_NAME)			\
+	},								\
+	[KPARSER_ATTR_READ_##ID] = {					\
+		.type = NLA_BINARY,					\
+		.len = sizeof(struct STRUC_NAME),			\
+		.validation_type = NLA_VALIDATE_MIN,			\
+		.min = sizeof(struct STRUC_NAME)			\
+	},								\
+	[KPARSER_ATTR_DELETE_##ID] = {					\
+		.type = NLA_BINARY,					\
+		.len = sizeof(struct STRUC_NAME),			\
+		.validation_type = NLA_VALIDATE_MIN,			\
+		.min = sizeof(struct STRUC_NAME)			\
+	},								\
+	[KPARSER_ATTR_RSP_##ID] = {					\
+		.type = NLA_BINARY,					\
+		.len = sizeof(struct RSP_STRUC_NAME),			\
+		.validation_type = NLA_VALIDATE_MIN,			\
+		.min = sizeof(struct RSP_STRUC_NAME)			\
+	}
+
+static const struct nla_policy kparser_nl_policy[KPARSER_ATTR_MAX] = {
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_CONDEXPRS,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_CONDEXPRS_TABLE,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_CONDEXPRS_TABLES,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_COUNTER,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_COUNTER_TABLE,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_METADATA,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_METALIST,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_NODE_PARSE,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_PROTO_TABLE,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_TLV_NODE_PARSE,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_TLV_PROTO_TABLE,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_FLAG_FIELD,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_FLAG_FIELD_TABLE,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_FLAG_FIELD_NODE_PARSE,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_FLAG_FIELD_PROTO_TABLE,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_PARSER,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+	NS_DEFINE_POLICY_ATTR_ENTRY(KPARSER_NS_OP_PARSER_LOCK_UNLOCK,
+				    kparser_conf_cmd,
+			kparser_cmd_rsp_hdr),
+};
+
+/* define netlink operations and family */
+static const struct genl_ops kparser_nl_ops[] = {
+	{
+	  .cmd = KPARSER_CMD_CONFIGURE,
+	  .doit = kparser_cli_cmd_handler,
+	  .flags = GENL_ADMIN_PERM,
+	},
+};
+
+struct genl_family kparser_nl_family __ro_after_init = {
+	.hdrsize	= 0,
+	.name		= KPARSER_GENL_NAME,
+	.version	= KPARSER_GENL_VERSION,
+	.maxattr	= KPARSER_ATTR_MAX - 1,
+	.policy		= kparser_nl_policy,
+	.netnsok	= true,
+	.parallel_ops	= true,
+	.module		= THIS_MODULE,
+	.ops		= kparser_nl_ops,
+	.n_ops		= ARRAY_SIZE(kparser_nl_ops),
+	.resv_start_op	= KPARSER_CMD_CONFIGURE + 1,
+};
+
+/* send response to netlink msg requests */
+static int kparser_send_cmd_rsp(int cmd, int attrtype,
+				const struct kparser_cmd_rsp_hdr *rsp,
+				size_t rsp_len, struct genl_info *info, int err)
+{
+	struct sk_buff *msg;
+	size_t msgsz = NLMSG_DEFAULT_SIZE;
+	void *hdr;
+	int ret;
+
+	if (rsp_len > msgsz)
+		msgsz = rsp_len;
+
+	msg = nlmsg_new(msgsz, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
+			  &kparser_nl_family, 0, cmd);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
+
+	if (rsp->op_ret_code != 0) {
+		struct nlmsghdr *nlh = hdr - GENL_HDRLEN - NLMSG_HDRLEN;
+		struct nlmsgerr *e;
+
+		nlh->nlmsg_type = NLMSG_ERROR;
+		nlh->nlmsg_len += nlmsg_msg_size(sizeof(*e));
+		nlh->nlmsg_flags |= NLM_F_ACK_TLVS;
+		e = (struct nlmsgerr *)NLMSG_DATA(nlh);
+		memset(&e->msg, 0, sizeof(e->msg));
+		e->error = rsp->op_ret_code;
+		nlmsg_free(msg);
+		return e->error;
+	}
+
+	if (nla_put(msg, attrtype, (int)rsp_len, rsp)) {
+		genlmsg_cancel(msg, hdr);
+		nlmsg_free(msg);
+		return -EMSGSIZE;
+	}
+
+	genlmsg_end(msg, hdr);
+	ret = genlmsg_reply(msg, info);
+
+	/* pr_debug("genlmsg_reply() ret:%d\n", ret); */
+
+	return ret;
+}
+
+typedef int kparser_ops(const void *, size_t, struct kparser_cmd_rsp_hdr **,
+			size_t *, void *extack, int *err);
+
+/* define netlink msg processors */
+#define KPARSER_NS_DEFINE_OP_HANDLERS(NS_ID)				\
+	[KPARSER_ATTR_CREATE_##NS_ID] = kparser_config_handler_add,	\
+	[KPARSER_ATTR_UPDATE_##NS_ID] = kparser_config_handler_update,	\
+	[KPARSER_ATTR_READ_##NS_ID] = kparser_config_handler_read,	\
+	[KPARSER_ATTR_DELETE_##NS_ID] = kparser_config_handler_delete,	\
+	[KPARSER_ATTR_RSP_##NS_ID] = NULL
+
+static kparser_ops *kparser_ns_op_handler[KPARSER_ATTR_MAX] = {
+	NULL,
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_CONDEXPRS),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_CONDEXPRS_TABLE),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_CONDEXPRS_TABLES),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_COUNTER),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_COUNTER_TABLE),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_METADATA),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_METALIST),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_NODE_PARSE),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_PROTO_TABLE),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_TLV_NODE_PARSE),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_TLV_PROTO_TABLE),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_FLAG_FIELD),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_FLAG_FIELD_TABLE),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_FLAG_FIELD_NODE_PARSE),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_FLAG_FIELD_PROTO_TABLE),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_PARSER),
+	KPARSER_NS_DEFINE_OP_HANDLERS(KPARSER_NS_OP_PARSER_LOCK_UNLOCK),
+};
+
+/* netlink msg request handler */
+static int kparser_cli_cmd_handler(struct sk_buff *skb, struct genl_info *info)
+{
+	struct kparser_cmd_rsp_hdr *rsp = NULL;
+	size_t rsp_len = 0;
+	int ret_attr_id;
+	int attr_idx;
+	int rc, err;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	for (attr_idx = KPARSER_ATTR_UNSPEC + 1; attr_idx < KPARSER_ATTR_MAX; attr_idx++) {
+		if (!info->attrs[attr_idx] || !kparser_ns_op_handler[attr_idx])
+			continue;
+
+		ret_attr_id = kparser_ns_op_handler[attr_idx](nla_data(info->attrs[attr_idx]),
+							      nla_len(info->attrs[attr_idx]),
+							      &rsp, &rsp_len,
+							      info->extack, &err);
+
+		if (ret_attr_id <= KPARSER_ATTR_UNSPEC || ret_attr_id >= KPARSER_ATTR_MAX) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "attr %d handler failed", attr_idx);
+			rc = EIO;
+			goto out;
+		}
+
+		rc = kparser_send_cmd_rsp(KPARSER_CMD_CONFIGURE, ret_attr_id,
+					  rsp, rsp_len, info, err);
+		if (rc) {
+			KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI,
+						 "kparser_send_cmd_rsp() failed,attr:%d, rc:%d\n",
+						 attr_idx, rc);
+			// rc = EIO;
+			goto out;
+		}
+
+		kfree(rsp);
+		rsp = NULL;
+		rsp_len = 0;
+	}
+
+out:
+	if (rsp)
+		kfree(rsp);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+
+	return rc;
+}
+
+/* kParser KMOD's init handler */
+static int __init init_kparser(void)
+{
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	rc = genl_register_family(&kparser_nl_family);
+	if (rc) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "genl_register_family failed\n");
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+		return rc;
+	}
+
+	rc = kparser_init();
+	if (rc) {
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "kparser_init() err:%d\n", rc);
+		goto out;
+	}
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+
+	return rc;
+
+out:
+	rc = genl_unregister_family(&kparser_nl_family);
+	if (rc != 0)
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "kparser_deinit() err:%d\n", rc);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "ERR OUT: ");
+
+	return rc;
+}
+
+/* kParser KMOD's exit handler */
+static void __exit exit_kparser(void)
+{
+	int rc;
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "IN: ");
+
+	rc = genl_unregister_family(&kparser_nl_family);
+	if (rc != 0)
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "genl_unregister_family() err:%d\n",
+					 rc);
+
+	rc = kparser_deinit();
+	if (rc != 0)
+		KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "kparser_deinit() err:%d\n", rc);
+
+	KPARSER_KMOD_DEBUG_PRINT(KPARSER_F_DEBUG_CLI, "OUT: ");
+}
+
+module_init(init_kparser);
+module_exit(exit_kparser);
+MODULE_AUTHOR("Pratyush Khan <pratyush@sipanda.io>");
+MODULE_AUTHOR("SiPanda Inc");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Configurable Parameterized Parser in Kernel (KPARSER)");
diff --git a/net/kparser/kparser_metaextract.h b/net/kparser/kparser_metaextract.h
new file mode 100644
index 000000000..68eeb9c91
--- /dev/null
+++ b/net/kparser/kparser_metaextract.h
@@ -0,0 +1,891 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser_metaextract.h - kParser metadata helper and structures header file
+ *
+ * Authors:     Tom Herbert <tom@sipanda.io>
+ *              Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#ifndef __KPARSER_METAEXTRACT_H__
+#define __KPARSER_METAEXTRACT_H__
+
+#include "kparser_types.h"
+
+#include <asm/byteorder.h>
+
+#ifdef __LITTLE_ENDIAN
+#define kparser_htonll(X)						\
+	(((__u64)htonl((X) & 0xffffffff) << 32) | htonl((X) >> 32))
+#define kparser_ntohll(X)						\
+	(((__u64)ntohl((X) & 0xffffffff) << 32) | ntohl((X) >> 32))
+#else
+#error "Cannot determine endianness"
+#define kparser_htonll(X) (X)
+#define kparser_ntohll(X) (X)
+#endif
+
+/* Metadata extraction pseudo instructions
+ *
+ * These instructions extract header data and set control data into metadata.
+ * Common fields are:
+ *    - code: Describes the data being written to the metadata. See descriptions
+ *	      below
+ *    - frame: Boolean value. If true then the data is a written to the current
+ *	      metadata frame (frame + dst_off), else the data is written
+ *	      to the metadata base (metadata + dst_off)
+ *    - cntr: Counter. If nonzero the data is written to an array defined
+ *	      by the specified counter. Note that dst_off in this case could
+ *	      be the base off set of an array plus the offset within an
+ *	      element of the array
+ *    - dst_off: Destination offset into the metadata to write the extracted
+ *	      data. This is a nine bits to allow an offset of 0 to 511
+ *	      bytes. In the case of writing a sixteen bit constant,
+ *	      dst_off is an eight byte field that is multiplied by two
+ *	      to derive the target destination offset
+ *
+ * Metadata extraction codes:
+ *    - KPARSER_METADATA_BYTES_EXTRACT: bytes field
+ *	    Extract some number of bytes of header data. The src_off field
+ *	    indicates the source offset in bytes from the current header being
+ *	    processed, and length indicates the number of bytes to be extracted.
+ *	    One is added to the length to get the target length. For example,
+ *	    to extract the IPv4 source address into metadata, src_off would be
+ *	    set to twelve and length would be set to three (that indicates
+ *	    to extract four bytes). If e_bit is true then the bytes are endian
+ *	    swapped before being stored
+ *    - KPARSER_METADATA_NIBBS_EXTRACT: nibbs field
+ *	    Extract some number of nibbles of header data. The src_off field
+ *	    indicates the source offset in nibbles from the current header being
+ *	    processed, and length indicates the number of nibbles to be
+ *	    extracted. Note that nibbles are counted such that the high order
+ *	    nibble of the first byte is nibble zero, and the low order is
+ *	    nibble one. When nibbles are written to be aligned to the
+ *	    destination bytes (e.g. the high order nibble to the first
+ *	    destination byte contains nibble zero). If an off number of nibbles
+ *	    are written, then the last nibble is written to the high order
+ *	    nibble of the last byte, and the low order nibble of the last
+ *	    byte is zero. If e_bit is true then the resultant bytes are endian
+ *	    swapped before being stored
+ *    - KPARSER_METADATA_CONSTANT_BYTE_SET: constant_byte field
+ *	    Set a byte constant in the metadata. The data field contains the
+ *	    value of the byte to be written
+ *    - KPARSER_METADATA_CONSTANT_HWORD_SET: constant_hword field
+ *	    Set a half word (16 bits) constant in the metadata. The data field
+ *	    contains the value of the halfword to be written. Note that dst_off
+ *	    is multiplied by two to derive the target offset
+ *    - KPARSER_METADATA_OFFSET_SET: offset field
+ *	    Set the current absolute offset of a field in a packet. This
+ *	    is the offset in two bytes of the current header being processed
+ *	    plus the value in add_off which is the offset of the field of
+ *	    interest in the current header. For instance, to get the offset of
+ *	    the source IP address add_off would be set to twelve; and for a
+ *	    plain IPv4 Ethernet packet the value written to metadata would
+ *	    be twenty-six (offset of the IPv4 header is fourteen plus twelve
+ *	    which is value of add_off and the offset of the source address
+ *	    in the IPv4 header). If bit_offset is set then the bit offset of
+ *	    the field is written. This is derived as eight times the current
+ *	    header byte offset plus add_off. For example, to extract the
+ *	    bit offset of the fragment offset of IPv4 header, add_off would
+ *	    have the value fifty-one. For a plain IPv4 Ethernet packet, the
+ *	    extract bit offset would then be 163
+ *    - KPARSER_METADATA_CTRL_HDR_LENGTH: control field
+ *	    Write the length of the current header to metadata. The length is
+ *	    written in two bytes. A counter operation may be specified as
+ *	    described below
+ *    - KPARSER_METADATA_CTRL_NUM_NODES: control field
+ *	    Write the current number of parse nodes that have been visited to
+ *	    metadata. The number of nodes is written in two bytes. A counter
+ *	    operation may be specified as described below
+ *    - KPARSER_METADATA_CTRL_NUM_ENCAPS: control field
+ *	    Write the current number of encapsulation levels to metadata. The
+ *	    number of nodes is written in two bytes. A counter operation may be
+ *	    specified as described below
+ *    - KPARSER_METADATA_CTRL_TIMESTAMP: control field
+ *	    Write the receive timestamp of a packet to metadata. The timestamp
+ *	    number of nodes is written in eight bytes. A counter operation may
+ *	    be specified as described below
+ *    - KPARSER_METADATA_CTRL_COUNTER: control_counter field
+ *	    Write the current value of a counter to metadata. The counter is
+ *	    specified in counter_for_data. The counter is written in two bytes.
+ *	    A counter operation may be specified as described below
+ *    - KPARSER_METADATA_CTRL_NOOP: control_noop field
+ *	    "No operation". This pseudo instruction does not write any data.
+ *	    It's primary purpose is to allow counter operations after performing
+ *	    non-control pseudo instructions (note that the non-control variants
+ *	    don't have a cntr_op field)
+ *
+ * There are two operations that may be performed on a counter and that are
+ * expressed in control type pseudo instructions: increment and reset. A
+ * counter operation is set in the cntr_op field of control pseudo instructions.
+ * The defined counter operations are:
+ *    - KPARSER_METADATA_CNTROP_NULL: No counter operation
+ *    - KPARSER_METADATA_CNTROP_INCREMENT: Increment the counter specified
+ *	    in cntr by one. The configuration for the counter is check and
+ *	    if the limit for the counter is exceeded the appropriate behavior
+ *	    is done
+ *    - KPARSER_METADATA_CNTROP_RESET: Reset the counter specified
+ *          in cntr to zero
+ */
+
+/* Metatdata extract codes */
+#define KPARSER_METADATA_BYTES_EXTRACT		0 /* Var bytes */
+#define KPARSER_METADATA_NIBBS_EXTRACT		1 /* Var bytes */
+#define KPARSER_METADATA_CONSTANT_BYTE_SET	2 /* One byte */
+#define KPARSER_METADATA_CONSTANT_HWORD_SET	3 /* Two bytes */
+#define KPARSER_METADATA_OFFSET_SET		4 /* Two bytes */
+#define KPARSER_METADATA_CTRL_HDR_LENGTH	5 /* Two bytes */
+#define KPARSER_METADATA_CTRL_NUM_NODES		6 /* Two bytes */
+#define KPARSER_METADATA_CTRL_NUM_ENCAPS	7 /* Two bytes */
+#define KPARSER_METADATA_CTRL_TIMESTAMP		8 /* Eight bytes */
+#define KPARSER_METADATA_CTRL_RET_CODE		9 /* Four bytes */
+#define KPARSER_METADATA_CTRL_COUNTER		10 /* Two bytes */
+#define KPARSER_METADATA_CTRL_NOOP		11 /* Zero bytes */
+
+#define KPARSER_METADATA_CNTROP_NULL		0
+#define KPARSER_METADATA_CNTROP_INCREMENT	1
+#define KPARSER_METADATA_CNTROP_RESET		2
+
+/* Metadata extraction pseudo instructions
+ * This emulates the custom SiPANDA riscv instructions for metadata extractions,
+ * hence these are called pseudo instructions
+ */
+struct kparser_metadata_extract {
+	union {
+		struct {
+			__u32 code: 4;	// One of KPARSER_METADATA_* ops
+			__u32 frame: 1;	// Write to frame (true) else to meta
+			__u32 cntr: 3;	// Counter number
+			__u32 dst_off: 9; // Target offset in frame or meta
+			__u32 rsvd: 24;
+		} gen;
+		struct {
+			__u32 code: 4;	// One of KPARSER_METADATA_* ops
+			__u32 frame: 1;	// Write to frame (true) else to meta
+			__u32 cntr: 3;	// Counter number
+			__u32 dst_off: 9; // Target offset in frame or meta
+			__u32 e_bit: 1;	// Swap endianness (true)
+			__u32 src_off: 9; // Src offset in header
+			__u32 length: 5; // Byte length to read/write
+		} bytes;
+		struct {
+			__u32 code: 4;	// One of KPARSER_METADATA_* ops
+			__u32 frame: 1;	// Write to frame (true) else to meta
+			__u32 cntr: 3;	// Counter number
+			__u32 dst_off: 9; // Target offset in frame or meta
+			__u32 e_bit: 1;	// Swap endianness (true)
+			__u32 src_off: 10; // Src offset in header
+			__u32 length: 4; // Nibble length to read/write
+		} nibbs;
+		struct {
+			__u32 code: 4;	// One of KPARSER_METADATA_* ops
+			__u32 frame: 1;	// Write to frame (true) else to meta
+			__u32 cntr: 3;	// Counter number
+			__u32 dst_off: 9; // Target offset / 2 in frame or meta
+			__u32 rsvd: 7;
+			__u32 data: 8;	// Byte constant
+		} constant_byte;
+		struct {
+			__u32 code: 4;	// One of KPARSER_METADATA_* ops
+			__u32 frame: 1;	// Write to frame (true) else to meta
+			__u32 cntr: 3;	// Counter number
+			__u32 dst_off: 8; // Target offset / 2 in frame or meta
+			__u32 data: 16;	// Byte constant
+		} constant_hword;
+		struct {
+			__u32 code: 4;	// One of KPARSER_METADATA_* ops
+			__u32 frame: 1;	// Write to frame (true) else to meta
+			__u32 cntr: 3;	// Counter number
+			__u32 dst_off: 9; // Target offset in frame or meta
+			__u32 bit_offset: 1;
+			__u32 rsvd: 2;
+			__u32 add_off: 12; // 3 bits for bit offset
+		} offset;
+		struct {
+			__u32 code: 4;	// One of KPARSER_METADATA_* ops
+			__u32 frame: 1;	// Write to frame (true) else to meta
+			__u32 cntr: 3;	// Counter number
+			__u32 dst_off: 9; // Target offset in frame or meta
+			__u32 cntr_op: 3; // Counter operation
+			__u32 cntr_for_data: 3;
+			__u32 rsvd: 9;
+		} control;
+		struct {
+			__u32 code: 4;	// One of KPARSER_METADATA_* ops
+			__u32 frame: 1;	// Write to frame (true) else to meta
+			__u32 cntr: 3;	// Counter number
+			__u32 cntr_op: 3; // Counter operation
+			__u32 rsvd: 21;
+		} control_noop;
+		__u32 val;
+	};
+};
+
+/* Helper macros to make various pseudo instructions */
+
+#define __KPARSER_METADATA_MAKE_BYTES_EXTRACT(FRAME, SRC_OFF, DST_OFF, LEN, E_BIT, CNTR)	\
+{												\
+	.bytes.code = KPARSER_METADATA_BYTES_EXTRACT,						\
+	.bytes.frame = FRAME,									\
+	.bytes.src_off = SRC_OFF,								\
+	.bytes.dst_off = DST_OFF,								\
+	.bytes.length = (LEN) - 1, /* Minimum one byte */					\
+	.bytes.e_bit = E_BIT,									\
+	.bytes.cntr = CNTR,									\
+}
+
+static inline struct kparser_metadata_extract
+__kparser_metadata_make_bytes_extract(bool frame, size_t src_off,
+				      size_t dst_off, size_t len,
+				      bool e_bit,
+				      unsigned int cntr)
+{
+	const struct kparser_metadata_extract mde =
+		__KPARSER_METADATA_MAKE_BYTES_EXTRACT(frame, src_off,
+						      dst_off, len,
+						      e_bit, cntr);
+	return mde;
+}
+
+#define __KPARSER_METADATA_MAKE_NIBBS_EXTRACT(FRAME, NIBB_SRC_OFF,				\
+		DST_OFF, NIBB_LEN, E_BIT, CNTR)							\
+{												\
+	.nibbs.code = KPARSER_METADATA_NIBBS_EXTRACT,						\
+	.nibbs.frame = FRAME,									\
+	.nibbs.src_off = NIBB_SRC_OFF,								\
+	.nibbs.dst_off = DST_OFF,								\
+	.nibbs.length = (NIBB_LEN) - 1, /* Minimum one nibble */				\
+	.nibbs.e_bit = E_BIT,									\
+	.nibbs.cntr = CNTR,									\
+}
+
+static inline struct kparser_metadata_extract
+__kparser_make_make_nibbs_extract(bool frame, size_t nibb_src_off,
+				  size_t dst_off, size_t nibb_len,
+				  bool e_bit, unsigned int cntr)
+{
+	const struct kparser_metadata_extract mde =
+		__KPARSER_METADATA_MAKE_NIBBS_EXTRACT(frame, nibb_src_off,
+						      dst_off, nibb_len,
+						      e_bit, cntr);
+
+	return mde;
+}
+
+#define __KPARSER_METADATA_MAKE_SET_CONST_BYTE(FRAME, DST_OFF, DATA, CNTR)			\
+{												\
+	.constant_byte.code = KPARSER_METADATA_CONSTANT_BYTE_SET,				\
+	.constant_byte.frame = FRAME,								\
+	.constant_byte.dst_off = DST_OFF,							\
+	.constant_byte.data = DATA,								\
+	.constant_byte.cntr = CNTR,								\
+}
+
+static inline struct kparser_metadata_extract
+__kparser_metadata_set_const_byte(bool frame, size_t dst_off,
+				  __u8 data, unsigned int cntr)
+{
+	const struct kparser_metadata_extract mde =
+		__KPARSER_METADATA_MAKE_SET_CONST_BYTE(frame, dst_off,
+						       data, cntr);
+
+	return mde;
+}
+
+#define __KPARSER_METADATA_MAKE_SET_CONST_HALFWORD(FRAME, DST_OFF, DATA, CNTR)			\
+{												\
+	.constant_hword.code =									\
+	KPARSER_METADATA_CONSTANT_HWORD_SET,							\
+	.constant_hword.frame = FRAME,								\
+	.constant_hword.dst_off = DST_OFF,							\
+	.constant_hword.data = DATA,								\
+	.constant_hword.cntr = CNTR,								\
+}
+
+static inline struct kparser_metadata_extract
+__kparser_metadata_set_const_halfword(bool frame, size_t dst_off,
+				      __u16 data,
+				      unsigned int cntr)
+{
+	const struct kparser_metadata_extract mde =
+		__KPARSER_METADATA_MAKE_SET_CONST_HALFWORD(frame, dst_off,
+							   data, cntr);
+
+	return mde;
+}
+
+#define __KPARSER_METADATA_MAKE_OFFSET_SET(FRAME, DST_OFF, BIT_OFFSET, ADD_OFF, CNTR)		\
+{												\
+	.offset.code = KPARSER_METADATA_OFFSET_SET,						\
+	.offset.frame = FRAME,									\
+	.offset.dst_off = DST_OFF,								\
+	.offset.bit_offset = BIT_OFFSET,							\
+	.offset.add_off = ADD_OFF,								\
+	.offset.cntr = CNTR,									\
+}
+
+static inline struct kparser_metadata_extract
+__kparser_metadata_offset_set(bool frame, size_t dst_off,
+			      bool bit_offset, size_t add_off, unsigned int cntr)
+{
+	const struct kparser_metadata_extract mde =
+		__KPARSER_METADATA_MAKE_OFFSET_SET(frame, dst_off,
+						   bit_offset, add_off, cntr);
+	return mde;
+}
+
+#define __KPARSER_METADATA_MAKE_SET_CONTROL_COUNTER(FRAME, DST_OFF, CNTR_DATA, CNTR, CNTR_OP)	\
+{												\
+	.control.code = KPARSER_METADATA_CTRL_COUNTER,						\
+	.control.frame = FRAME,									\
+	.control.dst_off = DST_OFF,								\
+	.control.cntr = CNTR,									\
+	.control.cntr_op = CNTR_OP,								\
+	.control.cntr_for_data = CNTR_DATA,							\
+}
+
+static inline struct kparser_metadata_extract
+__kparser_metadata_set_control_counter(bool frame, size_t dst_off,
+				       unsigned int cntr_data,
+		unsigned int cntr,
+		unsigned int cntr_op)
+{
+	const struct kparser_metadata_extract mde =
+		__KPARSER_METADATA_MAKE_SET_CONTROL_COUNTER(frame,
+							    dst_off, cntr_data, cntr,
+							    cntr_op);
+	return mde;
+}
+
+#define __KPARSER_METADATA_MAKE_SET_CONTROL(FRAME, CODE, DST_OFF, CNTR, CNTR_OP)		\
+{												\
+	.control.code = CODE,									\
+	.control.frame = FRAME,									\
+	.control.dst_off = DST_OFF,								\
+	.control.cntr = CNTR,									\
+	.control.cntr_op = CNTR_OP,								\
+}
+
+static inline struct kparser_metadata_extract
+__kparser_metadata_set_control(bool frame, unsigned int code,
+			       size_t dst_off, unsigned int cntr,
+			       unsigned int cntr_op)
+{
+	const struct kparser_metadata_extract mde =
+		__KPARSER_METADATA_MAKE_SET_CONTROL(frame, code, dst_off,
+						    cntr, cntr_op);
+	return mde;
+}
+
+struct kparser_metadata_table {
+	int num_ents;
+	struct kparser_metadata_extract *entries;
+};
+
+/* Extract functions */
+static inline int __kparser_metadata_bytes_extract(const __u8 *sptr,
+						   __u8 *dptr, size_t length, bool e_bit)
+{
+	__u16 v16;
+	__u32 v32;
+	__u64 v64;
+	int i;
+
+	if (!dptr)
+		return KPARSER_OKAY;
+
+	switch (length) {
+	case sizeof(__u8):
+		*dptr = *sptr;
+		break;
+	case sizeof(__u16):
+		v16 = *(__u16 *)sptr;
+		*((__u16 *)dptr) = e_bit ? ntohs(v16) : v16;
+		break;
+	case sizeof(__u32):
+		v32 = *(__u32 *)sptr;
+		*((__u32 *)dptr) = e_bit ? ntohl(v32) : v32;
+		break;
+	case sizeof(__u64):
+		v64 = *(__u64 *)sptr;
+		*((__u64 *)dptr) = e_bit ? kparser_ntohll(v64) : v64;
+		break;
+	default:
+		if (e_bit) {
+			for (i = 0; i < length; i++)
+				dptr[i] = sptr[length - 1 - i];
+		} else {
+			memcpy(dptr, sptr, length);
+		}
+	}
+
+	return KPARSER_OKAY;
+}
+
+static inline void *metadata_get_dst(size_t dst_off, void *mdata)
+{
+	return &((__u8 *)mdata)[dst_off];
+}
+
+static inline bool __metatdata_validate_counter(const struct kparser_parser *parser,
+						unsigned int cntr)
+{
+	if (!parser) {
+		pr_warn("Metadata counter is set for extraction but no parser is set");
+		return false;
+	}
+
+	if (!parser->cntrs) {
+		pr_warn("Metadata counter is set but no counters are configured for parser");
+		return false;
+	}
+
+	if (cntr >= KPARSER_CNTR_NUM_CNTRS) {
+		pr_warn("Metadata counter %u is greater than maximum %u",
+			cntr, KPARSER_CNTR_NUM_CNTRS);
+		return false;
+	}
+
+	return true;
+}
+
+static inline void *metadata_get_dst_cntr(const struct kparser_parser *parser,
+					  size_t dst_off, void *mdata,
+		unsigned int cntr, int code)
+{
+	const struct kparser_cntr_conf *cntr_conf;
+	__u8 *dptr = &((__u8 *)mdata)[dst_off];
+	size_t step;
+
+	if (!cntr)
+		return dptr;
+
+	cntr--; // Make zero based to access array
+
+	if (!__metatdata_validate_counter(parser, cntr))
+		return dptr;
+
+	cntr_conf = &parser->cntrs_conf.cntrs[cntr];
+
+	if (code != KPARSER_METADATA_CTRL_COUNTER) {
+		if (parser->cntrs->cntr[cntr] >= cntr_conf->array_limit) {
+			if (!cntr_conf->array_limit ||
+			    !cntr_conf->overwrite_last)
+				return NULL;
+			step = cntr_conf->array_limit - 1;
+		} else {
+			step = parser->cntrs->cntr[cntr];
+		}
+
+		dptr += cntr_conf->el_size * step;
+	}
+
+	return dptr;
+}
+
+static inline int __metadata_cntr_operation(const struct kparser_parser *parser,
+					    unsigned int operation, unsigned int cntr)
+{
+	/* cntr 0 means no counter attached, the index starts from 1 in this case
+	 */
+	if (!cntr)
+		return KPARSER_OKAY;
+
+	cntr--; /* Make zero based to access array */
+
+	if (!__metatdata_validate_counter(parser, cntr))
+		return KPARSER_STOP_BAD_CNTR;
+
+	switch (operation) {
+	default:
+	case KPARSER_METADATA_CNTROP_NULL:
+		break;
+	case KPARSER_METADATA_CNTROP_INCREMENT:
+		/* Note: parser is const but
+		 * parser->cntrs->cntr is writable
+		 */
+		if (parser->cntrs->cntr[cntr] <
+		    parser->cntrs_conf.cntrs[cntr].max_value)
+			parser->cntrs->cntr[cntr]++;
+		else if (parser->cntrs_conf.cntrs[cntr].error_on_exceeded)
+			return KPARSER_STOP_CNTR1 - cntr;
+		break;
+	case KPARSER_METADATA_CNTROP_RESET:
+		parser->cntrs->cntr[cntr] = 0;
+		break;
+	}
+
+	return KPARSER_OKAY;
+}
+
+static inline int kparser_metadata_bytes_extract(const struct kparser_parser *parser,
+						 struct kparser_metadata_extract mde,
+						 const void *hdr, void *mdata)
+{
+	__u8 *dptr = metadata_get_dst_cntr(parser, mde.bytes.dst_off, mdata,
+					   mde.bytes.cntr, 0);
+	const __u8 *sptr = &((__u8 *)hdr)[mde.bytes.src_off];
+
+	if (!dptr)
+		return KPARSER_OKAY;
+
+	return __kparser_metadata_bytes_extract(sptr, dptr,
+						mde.bytes.length + 1,
+						mde.bytes.e_bit);
+}
+
+static inline int kparser_metadata_nibbs_extract(const struct kparser_parser *parser,
+						 struct kparser_metadata_extract mde,
+						 const void *hdr, void *mdata)
+{
+	__u8 *dptr = metadata_get_dst_cntr(parser, mde.nibbs.dst_off, mdata,
+					   mde.nibbs.cntr, 0);
+	const __u8 *sptr = &((__u8 *)hdr)[mde.nibbs.src_off / 2];
+	size_t nibb_len = mde.nibbs.length + 1;
+	__u8 data;
+	int i;
+
+	if (!dptr)
+		return KPARSER_OKAY;
+
+	if (mde.nibbs.src_off % 2 == 0 && nibb_len % 2 == 0) {
+		/* This is effectively a byte transfer case */
+
+		return __kparser_metadata_bytes_extract(sptr, dptr,
+							mde.nibbs.length / 2,
+							mde.nibbs.e_bit);
+	}
+
+	if (mde.nibbs.e_bit) {
+		/* Endianness bit is set. dlen is the number of bytes
+		 * set for output
+		 */
+		size_t dlen = (nibb_len + 1) / 2;
+
+		if (mde.nibbs.src_off % 2) {
+			/* Starting from the odd nibble */
+			if (nibb_len % 2) {
+				/* Odd length and odd start nibble offset. Set
+				 * the reverse of all the bytes after the first
+				 * nibble, and * construct the last byte from
+				 * the low order nibble of the first input byte
+				 */
+				for (i = 0; i < dlen - 1; i++)
+					dptr[i] = sptr[dlen - 1 - i];
+				dptr[i] = sptr[0] & 0xf;
+			} else {
+				/* Even length and n-bit is set. Logically
+				 * shift all the nibbles in the string left and
+				 * then set the reversed bytes.
+				 */
+
+				/* High order nibble of last byte becomes
+				 * low order nibble of first output byte
+				 */
+				data = sptr[dlen] >> 4;
+
+				for (i = 0; i < dlen - 1; i++) {
+					/* Construct intermediate bytes. data
+					 * contains the input high order nibble
+					 * of the next input byte shifted right.
+					 * That value is or'ed with the shifted
+					 * left low order nibble of the current
+					 * byte. The result is set in the
+					 * reversed position in the output
+					 */
+					dptr[i] = data | sptr[dlen - 1 - i] << 4;
+
+					/* Get the next data value */
+					data = sptr[dlen - 1 - i] >> 4;
+				}
+				/* Set the last byte as the or of the last
+				 * data value and the low order nibble of the
+				 * zeroth byte of the input shifted left
+				 */
+				dptr[i] = data | sptr[0] << 4;
+			}
+		} else {
+			/* Odd length (per check above) and n-bit is not
+			 * set. Logically shift all the nibbles in the
+			 * string right and then set the reversed bytes
+			 */
+
+			/* High order nibble of last byte becomes
+			 * low order nibble of first output byte
+			 */
+			data = sptr[dlen - 1] >> 4;
+
+			for (i = 0; i < dlen - 1; i++) {
+				/* Construct intermediate bytes. data contains
+				 * the input high order nibble of the next
+				 * input byte shifted right. That value is
+				 * or'ed with the shifted left low order nibble
+				 * of the current byte. The result is set in the
+				 * reversed position in the output
+				 */
+				dptr[i] = data | sptr[dlen - 2 - i] << 4;
+
+				/* Get next data value */
+				data = sptr[dlen - 2 - i] >> 4;
+			}
+
+			/* Last output byte is set to high oder nibble of first
+			 * input byte shifted right
+			 */
+			dptr[i] = data;
+		}
+	} else {
+		/* No e-bit (no endiannes) */
+
+		size_t byte_len;
+		int ind = 0;
+
+		if (mde.nibbs.src_off % 2) {
+			/* Starting from the odd nibble. Set first output byte
+			 * to masked low order nibble of first input byte
+			 */
+			dptr[0] = sptr[0] & 0xf;
+			ind = 1;
+			nibb_len--;
+		}
+
+		/* Copy all the whole intermediate bytes */
+		byte_len = nibb_len / 2;
+		memcpy(&dptr[ind], &sptr[ind], byte_len);
+
+		if (nibb_len % 2) {
+			/* Have an odd nibble at the endian. Set the last
+			 * output byte to the mask high order nibble of the
+			 * last input byte
+			 */
+			dptr[ind + byte_len] = sptr[ind + byte_len] & 0xf0;
+		}
+	}
+
+	return KPARSER_OKAY;
+}
+
+static inline int kparser_metadata_const_set_byte(const struct kparser_parser *parser,
+						  struct kparser_metadata_extract mde,
+						  void *mdata)
+{
+	__u8 *dptr = metadata_get_dst_cntr(parser, mde.constant_byte.dst_off,
+					   mdata, mde.constant_byte.cntr, 0);
+
+	if (dptr)
+		*dptr = mde.constant_byte.data;
+
+	return KPARSER_OKAY;
+}
+
+static inline int kparser_metadata_const_set_hword(const struct kparser_parser *parser,
+						   struct kparser_metadata_extract mde,
+						   void *mdata)
+{
+	__u16 *dptr = metadata_get_dst_cntr(parser, mde.constant_hword.dst_off,
+					    mdata, mde.constant_hword.cntr, 0);
+
+	if (dptr)
+		*dptr = mde.constant_hword.data;
+
+	return KPARSER_OKAY;
+}
+
+static inline int kparser_metadata_set_offset(const struct kparser_parser *parser,
+					      struct kparser_metadata_extract mde,
+					      void *mdata, size_t hdr_offset)
+{
+	__u16 *dptr = metadata_get_dst_cntr(parser, mde.offset.dst_off, mdata,
+					    mde.offset.cntr, 0);
+
+	if (dptr) {
+		*dptr = mde.offset.bit_offset ?
+			8 * hdr_offset + mde.offset.add_off :
+			hdr_offset + mde.offset.add_off;
+	}
+
+	return KPARSER_OKAY;
+}
+
+static inline int __kparser_metadata_control_extract(const struct kparser_parser *parser,
+						     const struct kparser_metadata_extract mde,
+						     const void *_hdr, size_t hdr_len,
+						     size_t hdr_offset, void *mdata,
+						     const struct kparser_ctrl_data *ctrl)
+{
+	__u16 *dptr = metadata_get_dst_cntr(parser, mde.control.dst_off, mdata,
+					    mde.control.cntr, mde.control.code);
+
+	switch (mde.control.code) {
+	case KPARSER_METADATA_CTRL_HDR_LENGTH:
+		if (dptr)
+			*((__u16 *)dptr) = hdr_len;
+		break;
+	case KPARSER_METADATA_CTRL_NUM_NODES:
+		if (dptr)
+			*((__u16 *)dptr) = ctrl->node_cnt;
+		break;
+	case KPARSER_METADATA_CTRL_NUM_ENCAPS:
+		if (dptr)
+			*((__u16 *)dptr) = ctrl->encap_levels;
+		break;
+	case KPARSER_METADATA_CTRL_TIMESTAMP:
+		/* TODO */
+		break;
+	case KPARSER_METADATA_CTRL_COUNTER:
+		if (!__metatdata_validate_counter(parser,
+						  mde.control.cntr_for_data))
+			return KPARSER_STOP_BAD_CNTR;
+		if (dptr)
+			*(__u16 *)dptr = parser->cntrs->cntr[mde.control.cntr_for_data - 1];
+		break;
+	case KPARSER_METADATA_CTRL_RET_CODE:
+		if (dptr)
+			*((int *)dptr) = ctrl->ret;
+		break;
+	case KPARSER_METADATA_CTRL_NOOP:
+		break;
+	default:
+		pr_debug("Unknown extract\n");
+		return KPARSER_STOP_BAD_EXTRACT;
+	}
+
+	return __metadata_cntr_operation(parser, mde.control.cntr_op, mde.control.cntr);
+}
+
+/* Front end functions to process one metadata extraction pseudo instruction
+ * in the context of parsing a packet
+ */
+static inline int kparser_metadata_extract(const struct kparser_parser *parser,
+					   const struct kparser_metadata_extract mde,
+					   const void *_hdr, size_t hdr_len,
+					   size_t hdr_offset, void *_metadata,
+					   void *_frame,
+					   const struct kparser_ctrl_data *ctrl)
+{
+	void *mdata = mde.gen.frame ? _frame : _metadata;
+	int ret;
+
+	switch (mde.gen.code) {
+	case KPARSER_METADATA_BYTES_EXTRACT:
+		ret = kparser_metadata_bytes_extract(parser, mde,
+						     _hdr, mdata);
+		break;
+	case KPARSER_METADATA_NIBBS_EXTRACT:
+		ret = kparser_metadata_nibbs_extract(parser, mde,
+						     _hdr, mdata);
+		break;
+	case KPARSER_METADATA_CONSTANT_BYTE_SET:
+		ret = kparser_metadata_const_set_byte(parser, mde,
+						      mdata);
+		break;
+	case KPARSER_METADATA_CONSTANT_HWORD_SET:
+		ret = kparser_metadata_const_set_hword(parser, mde,
+						       mdata);
+		break;
+	case KPARSER_METADATA_OFFSET_SET:
+		ret = kparser_metadata_set_offset(parser, mde, mdata,
+						  hdr_offset);
+		break;
+	default: /* Should be a control metadata extraction */
+		ret = __kparser_metadata_control_extract(parser, mde,
+							 _hdr,
+							 hdr_len,
+							 hdr_offset,
+							 mdata, ctrl);
+	}
+
+	return ret;
+}
+
+static inline bool kparser_metadata_convert(const struct kparser_conf_metadata *conf,
+					    struct kparser_metadata_extract *mde,
+					    int cntridx, int cntr_arr_idx)
+{
+	__u32 encoding_type;
+
+	switch (conf->type) {
+	case KPARSER_METADATA_HDRDATA:
+		*mde = __kparser_metadata_make_bytes_extract(conf->frame,
+							     conf->soff, conf->doff, conf->len,
+							     conf->e_bit, cntridx);
+		return true;
+
+	case KPARSER_METADATA_HDRDATA_NIBBS_EXTRACT:
+		*mde = __kparser_make_make_nibbs_extract(conf->frame,
+							 conf->soff,
+							 conf->doff,
+							 conf->len,
+							 conf->e_bit,
+							 cntridx);
+		return true;
+
+	case KPARSER_METADATA_BIT_OFFSET:
+		*mde =	__kparser_metadata_offset_set(conf->frame,
+						      conf->doff,
+						      true,
+						      conf->add_off,
+						      cntridx);
+		return true;
+
+	case KPARSER_METADATA_OFFSET:
+		*mde =	__kparser_metadata_offset_set(conf->frame,
+						      conf->doff,
+						      false,
+						      conf->add_off,
+						      cntridx);
+		return true;
+
+	case KPARSER_METADATA_CONSTANT_BYTE:
+		*mde =	__kparser_metadata_set_const_byte(conf->frame,
+							  conf->doff, conf->constant_value,
+				cntridx);
+		return true;
+
+	case KPARSER_METADATA_CONSTANT_HALFWORD:
+		*mde =	__kparser_metadata_set_const_halfword(conf->frame,
+							      conf->doff, conf->constant_value,
+				cntridx);
+		return true;
+
+	case KPARSER_METADATA_COUNTER:
+		*mde = __kparser_metadata_set_control_counter(conf->frame, conf->doff,
+							      cntridx, cntr_arr_idx,
+							      conf->cntr_op);
+		return true;
+
+	case KPARSER_METADATA_HDRLEN:
+		encoding_type = KPARSER_METADATA_CTRL_HDR_LENGTH;
+		break;
+
+	case KPARSER_METADATA_NUMENCAPS:
+		encoding_type = KPARSER_METADATA_CTRL_NUM_ENCAPS;
+		break;
+
+	case KPARSER_METADATA_NUMNODES:
+		encoding_type = KPARSER_METADATA_CTRL_NUM_NODES;
+		break;
+
+	case KPARSER_METADATA_TIMESTAMP:
+		encoding_type = KPARSER_METADATA_CTRL_TIMESTAMP;
+		break;
+
+	case KPARSER_METADATA_RETURN_CODE:
+		encoding_type = KPARSER_METADATA_CTRL_RET_CODE;
+		break;
+
+	case KPARSER_METADATA_COUNTEROP_NOOP:
+		encoding_type = KPARSER_METADATA_CTRL_NOOP;
+		break;
+
+	default:
+		return false;
+	}
+
+	*mde = __kparser_metadata_set_control(conf->frame, encoding_type, conf->doff,
+					      cntridx, conf->cntr_op);
+
+	return true;
+}
+
+#endif /* __KPARSER_METAEXTRACT_H__ */
diff --git a/net/kparser/kparser_types.h b/net/kparser/kparser_types.h
new file mode 100644
index 000000000..e957c556e
--- /dev/null
+++ b/net/kparser/kparser_types.h
@@ -0,0 +1,586 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2022, SiPanda Inc.
+ *
+ * kparser_types.h - kParser private data types header file
+ *
+ * Authors:     Tom Herbert <tom@sipanda.io>
+ *              Pratyush Kumar Khan <pratyush@sipanda.io>
+ */
+
+#ifndef __KPARSER_TYPES_H
+#define __KPARSER_TYPES_H
+
+#include <linux/hash.h>
+#include <linux/kparser.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rcupdate.h>
+#include <linux/rhashtable-types.h>
+#include <linux/skbuff.h>
+#include <linux/xxhash.h>
+
+/* Sign extend an returned signed value */
+#define KPARSER_EXTRACT_CODE(X) ((__s64)(short)(X))
+#define KPARSER_IS_RET_CODE(X) (KPARSER_EXTRACT_CODE(X) < 0)
+#define KPARSER_IS_NOT_OK_CODE(X) (KPARSER_EXTRACT_CODE(X) <= KPARSER_STOP_FAIL)
+#define KPARSER_IS_OK_CODE(X)						\
+	(KPARSER_IS_RET_CODE(X) && KPARSER_EXTRACT_CODE(X) > KPARSER_STOP_FAIL)
+
+/* A table of conditional expressions, type indicates that the expressions
+ * are or'ed of and'ed
+ */
+struct kparser_condexpr_table {
+	int default_fail;
+	enum kparser_condexpr_types type;
+	unsigned int num_ents;
+	const struct kparser_condexpr_expr __rcu **entries;
+};
+
+/* A table of tables of conditional expressions. This is used to create more
+ * complex expressions using and's and or's
+ */
+struct kparser_condexpr_tables {
+	unsigned int num_ents;
+	const struct kparser_condexpr_table __rcu **entries;
+};
+
+/* Control data describing various values produced while parsing. This is
+ * used an argument to metadata extraction and handler functions
+ */
+struct kparser_ctrl_data {
+	int ret;
+	size_t pkt_len;
+	void *hdr_base;
+	unsigned int node_cnt;
+	unsigned int encap_levels;
+};
+
+/*****************************************************************************/
+
+/* Protocol parsing operations:
+ *
+ * Operations can be specified either as a function or a parameterization
+ * of a parameterized function
+ *
+ * len: Return length of protocol header. If value is NULL then the length of
+ *	the header is taken from the min_len in the protocol node. If the
+ *	return value < 0 (a KPARSER_STOP_* return code value) this indicates an
+ *	error and parsing is stopped. A the return value greater than or equal
+ *	to zero then gives the protocol length. If the returned length is less
+ *	than the minimum protocol length, indicated in min_len by the protocol
+ *	node, then this considered and error.
+ * next_proto: Return next protocol. If value is NULL then there is no
+ *	next protocol. If return value is greater than or equal to zero
+ *	this indicates a protocol number that is used in a table lookup
+ *	to get the next layer protocol node.
+ * cond_exprs: Parameterization only. This describes a set of conditionals
+ *	check before proceeding. In the case of functions being used, these
+ *	conditionals would be in the next_proto or length function
+ */
+
+struct kparser_parse_ops {
+	bool flag_fields_length;
+	bool len_parameterized;
+	struct kparser_parameterized_len pflen;
+	struct kparser_parameterized_next_proto pfnext_proto;
+	bool cond_exprs_parameterized;
+	struct kparser_condexpr_tables cond_exprs;
+};
+
+/* Protocol node
+ *
+ * This structure contains the definitions to describe parsing of one type
+ * of protocol header. Fields are:
+ *
+ * node_type: The type of the node (plain, TLVs, flag-fields)
+ * encap: Indicates an encapsulation protocol (e.g. IPIP, GRE)
+ * overlay: Indicates an overlay protocol. This is used, for example, to
+ *	switch on version number of a protocol header (e.g. IP version number
+ *	or GRE version number)
+ * name: Text name of protocol node for debugging
+ * min_len: Minimum length of the protocol header
+ * ops: Operations to parse protocol header
+ */
+struct kparser_proto_node {
+	__u8 encap;
+	__u8 overlay;
+	size_t min_len;
+	struct kparser_parse_ops ops;
+};
+
+/* Protocol node and parse node operations ordering. When processing a
+ * layer, operations are called in following order:
+ *
+ * protoop.len
+ * parseop.extract_metadata
+ * parseop.handle_proto
+ * protoop.next_proto
+ */
+/* One entry in a protocol table:
+ *	value: protocol number
+ *	node: associated parse node for the protocol number
+ */
+struct kparser_proto_table_entry {
+	int value;
+	bool encap;
+	const struct kparser_parse_node __rcu *node;
+};
+
+/* Protocol table
+ *
+ * Contains a protocol table that maps a protocol number to a parse
+ * node
+ */
+struct kparser_proto_table {
+	int num_ents;
+	struct kparser_proto_table_entry __rcu *entries;
+};
+
+/*****************************************************************************/
+
+struct kparser_cntrs_conf {
+	struct kparser_cntr_conf cntrs[KPARSER_CNTR_NUM_CNTRS];
+};
+
+struct kparser_counters {
+	__u16 cntr[KPARSER_CNTR_NUM_CNTRS];
+};
+
+/*****************************************************************************/
+
+/* Definitions for parsing TLVs
+ *
+ * Operations can be specified either as a function or a parameterization
+ * of a parameterized function
+ *
+ * TLVs are a common protocol header structure consisting of Type, Length,
+ * Value tuple (e.g. for handling TCP or IPv6 HBH options TLVs)
+ */
+
+/* Descriptor for parsing operations of one type of TLV. Fields are:
+ * For struct kparser_proto_tlvs_opts:
+ * start_offset: Returns the offset of TLVs in a header
+ * len: Return length of a TLV. Must be set. If the return value < 0 (a
+ *	KPARSER_STOP_* return code value) this indicates an error and parsing
+ *	is stopped. A the return value greater than or equal to zero then
+ *	gives the protocol length. If the returned length is less than the
+ *	minimum TLV option length, indicated by min_len by the TLV protocol
+ *	node, then this considered and error.
+ * type: Return the type of the TLV. If the return value is less than zero
+ *	(KPARSER_STOP_* value) then this indicates and error and parsing stops
+ */
+
+/* A protocol node for parsing proto with TLVs
+ *
+ * proto_node: proto node
+ * ops: Operations for parsing TLVs
+ * start_offset: When there TLVs start relative the enapsulating protocol
+ *	(e.g. would be twenty for TCP)
+ * pad1_val: Type value indicating one byte of TLV padding (e.g. would be
+ *	for IPv6 HBH TLVs)
+ * pad1_enable: Pad1 value is used to detect single byte padding
+ * eol_val: Type value that indicates end of TLV list
+ * eol_enable: End of list value in eol_val is used
+ * fixed_start_offset: Take start offset from start_offset
+ * min_len: Minimal length of a TLV option
+ */
+struct kparser_proto_tlvs_node {
+	struct kparser_proto_node proto_node;
+	struct kparser_proto_tlvs_opts ops;
+	size_t start_offset;
+	__u8 pad1_val;
+	__u8 padn_val;
+	__u8 eol_val;
+	bool pad1_enable;
+	bool padn_enable;
+	bool eol_enable;
+	bool fixed_start_offset;
+	size_t min_len;
+};
+
+/*****************************************************************************/
+
+/* Definitions and functions for processing and parsing flag-fields */
+/* Definitions for parsing flag-fields
+ *
+ * Flag-fields is a common networking protocol construct that encodes optional
+ * data in a set of flags and data fields. The flags indicate whether or not a
+ * corresponding data field is present. The data fields are fixed length per
+ * each flag-field definition and ordered by the ordering of the flags
+ * indicating the presence of the fields (e.g. GRE and GUE employ flag-fields)
+ */
+
+/* Flag-fields descriptors and tables
+ *
+ * A set of flag-fields is defined in a table of type struct kparser_flag_fields.
+ * Each entry in the table is a descriptor for one flag-field in a protocol and
+ * includes a flag value, mask (for the case of a multi-bit flag), and size of
+ * the cooresponding field. A flag is matched if "(flags & mask) == flag"
+ */
+
+/* Descriptor for a protocol field with flag fields
+ *
+ * Defines the flags and their data fields for one instance a flag field in
+ * a protocol header (e.g. GRE v0 flags):
+ *
+ * num_idx: Number of flag_field structures
+ * fields: List of defined flag fields
+ */
+struct kparser_flag_fields {
+	size_t num_idx;
+	struct kparser_flag_field __rcu *fields;
+};
+
+/* Structure or parsing operations for flag-fields
+ * For struct kparser_proto_flag_fields_ops
+ * Operations can be specified either as a function or a parameterization
+ * of a parameterized function
+ *
+ * flags_offset: Offset of flags in the protocol header
+ * start_fields_offset: Return the offset in the header of the start of the
+ *	flag fields data
+ */
+
+/* A flag-fields protocol node. Note this is a super structure for aKPARSER
+ * protocol node and type is KPARSER_NODE_TYPE_FLAG_FIELDS
+ */
+struct kparser_proto_flag_fields_node {
+	struct kparser_proto_node proto_node;
+	struct kparser_proto_flag_fields_ops ops;
+	const struct kparser_flag_fields __rcu *flag_fields;
+};
+
+/*****************************************************************************/
+
+/* Parse node definition. Defines parsing and processing for one node in
+ * the parse graph of a parser. Contains:
+ *
+ * node_type: The type of the node (plain, TLVs, flag-fields)
+ * unknown_ret: Code to return for a miss on the protocol table and the
+ *	wildcard node is not set
+ * proto_node: Protocol node
+ * ops: Parse node operations
+ * proto_table: Protocol table for next protocol. This must be non-null if
+ *	next_proto is not NULL
+ * wildcard_node: Node use for a miss on next protocol lookup
+ * metadata_table: Table of parameterized metadata operations
+ * thread_funcs: Thread functions
+ */
+struct kparser_parse_node {
+	enum kparser_node_type node_type;
+	char name[KPARSER_MAX_NAME];
+	int unknown_ret;
+	const struct kparser_proto_table __rcu *proto_table;
+	const struct kparser_parse_node __rcu *wildcard_node;
+	const struct kparser_metadata_table __rcu *metadata_table;
+	union {
+		struct kparser_proto_node proto_node;
+		struct kparser_proto_tlvs_node tlvs_proto_node;
+		struct kparser_proto_flag_fields_node flag_fields_proto_node;
+	};
+};
+
+/*****************************************************************************/
+
+/* TLV parse node operations
+ *
+ * Operations to process a single TLV
+ *
+ * Operations can be specified either as a function or a parameterization
+ * of a parameterized function
+ *
+ * extract_metadata: Extract metadata for the node. Input is the meta
+ *	data frame which points to a parser defined metadata structure.
+ *	If the value is NULL then no metadata is extracted
+ * handle_tlv: Per TLV type handler which allows arbitrary processing
+ *	of a TLV. Input is the TLV data and a parser defined metadata
+ *	structure for the current frame. Return value is a parser
+ *	return code: KPARSER_OKAY indicates no errors, KPARSER_STOP* return
+ *	values indicate to stop parsing
+ * check_tlv: Function to validate a TLV
+ * cond_exprs: Parameterization of a set of conditionals to check before
+ *	proceeding. In the case of functions being used, these
+ *      conditionals would be in the check_tlv function
+ */
+
+/* One entry in a TLV table:
+ *	type: TLV type
+ *	node: associated TLV parse structure for the type
+ */
+struct kparser_proto_tlvs_table_entry {
+	int type;
+	const struct kparser_parse_tlv_node __rcu *node;
+};
+
+/* TLV table
+ *
+ * Contains a table that maps a TLV type to a TLV parse node
+ */
+struct kparser_proto_tlvs_table {
+	int num_ents;
+	struct kparser_proto_tlvs_table_entry __rcu *entries;
+};
+
+/* Parse node for parsing a protocol header that contains TLVs to be
+ * parser:
+ *
+ * parse_node: Node for main protocol header (e.g. IPv6 node in case of HBH
+ *	options) Note that node_type is set in parse_node to
+ *	KPARSER_NODE_TYPE_TLVS and that the parse node can then be cast to a
+ *	parse_tlv_node
+ * tlv_proto_table: Lookup table for TLV type
+ * unknown_tlv_type_ret: Code to return on a TLV type lookup miss and
+ *	tlv_wildcard_node is NULL
+ * tlv_wildcard_node: Node to use on a TLV type lookup miss
+ * config: Loop configuration
+ */
+struct kparser_parse_tlvs_node {
+	struct kparser_parse_node parse_node;
+	const struct kparser_proto_tlvs_table __rcu *tlv_proto_table;
+	int unknown_tlv_type_ret;
+	const struct kparser_parse_tlv_node __rcu *tlv_wildcard_node;
+	struct kparser_loop_node_config config;
+};
+
+struct kparser_proto_tlv_node_ops {
+	bool overlay_type_parameterized;
+	struct kparser_parameterized_next_proto pfoverlay_type;
+	bool cond_exprs_parameterized;
+	struct kparser_condexpr_tables cond_exprs;
+};
+
+/* A protocol node for parsing proto with TLVs
+ *
+ * min_len: Minimal length of TLV
+ * max_len: Maximum size of a TLV option
+ * is_padding: Indicates padding TLV
+ */
+struct kparser_proto_tlv_node {
+	size_t min_len;
+	size_t max_len;
+	bool is_padding;
+	struct kparser_proto_tlv_node_ops ops;
+};
+
+/* Parse node for a single TLV. Use common parse node operations
+ * (extract_metadata and handle_proto)
+ *
+ * proto_tlv_node: TLV protocol node
+ * tlv_ops: Operations on a TLV
+ * overlay_table: Lookup table for an overlay TLV
+ * overlay_wildcard_node: Wildcard node to an overlay lookup miss
+ * unknown_overlay_ret: Code to return on an overlay lookup miss and
+ *	overlay_wildcard_node is NULL
+ * name: Name for debugging
+ * metadata_table: Table of parameterized metadata operations
+ * thread_funcs: Thread functions
+ */
+struct kparser_parse_tlv_node {
+	struct kparser_proto_tlv_node proto_tlv_node;
+	struct kparser_proto_tlvs_table __rcu *overlay_table;
+	const struct kparser_parse_tlv_node __rcu *overlay_wildcard_node;
+	int unknown_overlay_ret;
+	char name[KPARSER_MAX_NAME];
+	struct kparser_metadata_table __rcu *metadata_table;
+};
+
+/*****************************************************************************/
+
+/* Flag-field parse node operations
+ *
+ * Operations to process a single flag-field
+ *
+ * extract_metadata: Extract metadata for the node. Input is the meta
+ *	data frame which points to a parser defined metadata structure.
+ *	If the value is NULL then no metadata is extracted
+ * handle_flag_field: Per flag-field handler which allows arbitrary processing
+ *	of a flag-field. Input is the flag-field data and a parser defined
+ *	metadata structure for the current frame. Return value is a parser
+ *	return code: KPARSER_OKAY indicates no errors, KPARSER_STOP* return
+ *	values indicate to stop parsing
+ * check_flag_field: Function to validate a flag-field
+ * cond_exprs: Parameterization of a set of conditionals to check before
+ *      proceeding. In the case of functions being used, these
+ *      conditionals would be in the check_flag_field function
+ */
+struct kparser_parse_flag_field_node_ops {
+	struct kparser_condexpr_tables cond_exprs;
+};
+
+/* A parse node for a single flag field
+ *
+ * name: Text name for debugging
+ * metadata_table: Table of parameterized metadata operations
+ * ops: Operations
+ * thread_funcs: Thread functions
+ */
+struct kparser_parse_flag_field_node {
+	char name[KPARSER_MAX_NAME];
+	struct kparser_metadata_table __rcu *metadata_table;
+	struct kparser_parse_flag_field_node_ops ops;
+};
+
+/* One entry in a flag-fields protocol table:
+ *	index: flag-field index (index in a flag-fields table)
+ *	node: associated TLV parse structure for the type
+ */
+struct kparser_proto_flag_fields_table_entry {
+	__u32 flag;
+	const struct kparser_parse_flag_field_node __rcu *node;
+};
+
+/* Flag-fields table
+ *
+ * Contains a table that maps a flag-field index to a flag-field parse node.
+ * Note that the index correlates to an entry in a flag-fields table that
+ * describes the flag-fields of a protocol
+ */
+struct kparser_proto_flag_fields_table {
+	int num_ents;
+	struct kparser_proto_flag_fields_table_entry __rcu *entries;
+};
+
+/* A flag-fields parse node. Note this is a super structure for a KPARSER parse
+ * node and type is KPARSER_NODE_TYPE_FLAG_FIELDS
+ */
+struct kparser_parse_flag_fields_node {
+	struct kparser_parse_node parse_node;
+	const struct kparser_proto_flag_fields_table __rcu
+		*flag_fields_proto_table;
+};
+
+static inline ssize_t __kparser_flag_fields_offset(__u32 targ_idx, __u32 flags,
+						   const struct kparser_flag_fields *flag_fields)
+{
+	ssize_t offset = 0;
+	__u32 mask, flag;
+	int i;
+
+	for (i = 0; i < targ_idx; i++) {
+		flag = flag_fields->fields[i].flag;
+		if (flag_fields->fields[i].endian)
+			flag = ntohs(flag);
+		mask = flag_fields->fields[i].mask ? : flag;
+		if ((flags & mask) == flag)
+			offset += flag_fields->fields[i].size;
+	}
+
+	return offset;
+}
+
+/* Determine offset of a field given a set of flags */
+static inline ssize_t kparser_flag_fields_offset(__u32 targ_idx, __u32 flags,
+						 const struct kparser_flag_fields *flag_fields)
+{
+	__u32 mask, flag;
+
+	flag = flag_fields->fields[targ_idx].flag;
+	if (flag_fields->fields[targ_idx].endian)
+		flag = ntohs(flag);
+	mask = flag_fields->fields[targ_idx].mask ? : flag;
+	if ((flags & mask) != flag) {
+		/* Flag not set */
+		return -1;
+	}
+
+	return __kparser_flag_fields_offset(targ_idx, flags, flag_fields);
+}
+
+/* Check flags are legal */
+static inline bool kparser_flag_fields_check_invalid(__u32 flags, __u32 mask)
+{
+	return !!(flags & ~mask);
+}
+
+/* Retrieve a byte value from a flag field */
+static inline __u8 kparser_flag_fields_get8(const __u8 *fields, __u32 targ_idx,
+					    __u32 flags,
+					    const struct kparser_flag_fields
+					    *flag_fields)
+{
+	ssize_t offset = kparser_flag_fields_offset(targ_idx, flags,
+			flag_fields);
+
+	if (offset < 0)
+		return 0;
+
+	return *(__u8 *)&fields[offset];
+}
+
+/* Retrieve a short value from a flag field */
+static inline __u16 kparser_flag_fields_get16(const __u8 *fields,
+					      __u32 targ_idx,
+		__u32 flags,
+		const struct kparser_flag_fields
+		*flag_fields)
+{
+	ssize_t offset = kparser_flag_fields_offset(targ_idx, flags, flag_fields);
+
+	if (offset < 0)
+		return 0;
+
+	return *(__u16 *)&fields[offset];
+}
+
+/* Retrieve a 32 bit value from a flag field */
+static inline __u32 kparser_get_flag_field32(const __u8 *fields, __u32 targ_idx,
+					     __u32 flags,
+		const struct kparser_flag_fields
+		*flag_fields)
+{
+	ssize_t offset = kparser_flag_fields_offset(targ_idx, flags, flag_fields);
+
+	if (offset < 0)
+		return 0;
+
+	return *(__u32 *)&fields[offset];
+}
+
+/* Retrieve a 64 bit value from a flag field */
+static inline __u64 kparser_get_flag_field64(const __u8 *fields, __u32 targ_idx,
+					     __u32 flags,
+		const struct kparser_flag_fields
+		*flag_fields)
+{
+	ssize_t offset = kparser_flag_fields_offset(targ_idx, flags,
+			flag_fields);
+
+	if (offset < 0)
+		return 0;
+
+	return *(__u64 *)&fields[offset];
+}
+
+/*****************************************************************************/
+
+/* Definition of a KPARSER parser. Fields are:
+ *
+ * name: Text name for the parser
+ * root_node: Root parse node of the parser. When the parser is invoked
+ *	parsing commences at this parse node
+ * okay_node: Processed at parser exit if no error
+ * fail_node: Processed at parser exit if there was an error
+ * parser_type: e.g. KPARSER_GENERIC, KPARSER_OPTIMIZED, KPARSER_KMOD, KPARSER_XDP
+ * parser_entry_point: Function entry point for optimized parser
+ * parser_xdp_entry_point: Function entry point for XDP parser
+ * config: Parser conifguration
+ */
+#define KPARSERSTARTSIGNATURE 0xabcd
+#define KPARSERENDSIGNATURE 0xdcba
+struct kparser_parser {
+	__u16 kparser_start_signature;
+	char name[KPARSER_MAX_NAME];
+	const struct kparser_parse_node __rcu *root_node;
+	const struct kparser_parse_node __rcu *okay_node;
+	const struct kparser_parse_node __rcu *fail_node;
+	const struct kparser_parse_node __rcu *atencap_node;
+	size_t cntrs_len;
+	struct kparser_counters __rcu *cntrs;
+	struct kparser_config config;
+	struct kparser_cntrs_conf cntrs_conf;
+	__u16 kparser_end_signature;
+};
+
+#endif /* __KPARSER_TYPES_H */
