From 6bd1f2ad02e8b3e8084b7b71e7ea95d737bba9a3 Mon Sep 17 00:00:00 2001 From: Tomaz Zaman Date: Mon, 10 Aug 2026 13:51:12 +0200 Subject: [PATCH 04/77] libnetfilter-conntrack, libnfnetlink: add ASK fast-path extensions From we-are-mono/ASK patches/ (targeting exactly the 1.1.0 / 1.0.2 versions OpenWrt ships): ctnetlink comcerto_fp attributes, qosconnmark, IPS_PERMANENT, non-blocking heap-buffered event reads. Required by cmm to parse the offload-annotated conntrack events. Co-Authored-By: Claude Fable 5 --- .../900-nxp-ask-comcerto-fp-extensions.patch | 700 ++++++++++++++++++ .../900-nxp-ask-nonblocking-heap-buffer.patch | 190 +++++ 2 files changed, 890 insertions(+) create mode 100644 package/libs/libnetfilter-conntrack/patches/900-nxp-ask-comcerto-fp-extensions.patch create mode 100644 package/libs/libnfnetlink/patches/900-nxp-ask-nonblocking-heap-buffer.patch diff --git a/package/libs/libnetfilter-conntrack/patches/900-nxp-ask-comcerto-fp-extensions.patch b/package/libs/libnetfilter-conntrack/patches/900-nxp-ask-comcerto-fp-extensions.patch new file mode 100644 index 0000000000..c25ab9d153 --- /dev/null +++ b/package/libs/libnetfilter-conntrack/patches/900-nxp-ask-comcerto-fp-extensions.patch @@ -0,0 +1,700 @@ +From: Tomaz Zaman +Date: Sat, 24 Jan 2026 00:17:21 +0100 +Subject: [PATCH] NXP ASK extensions for Comcerto fast path + +Adds support for: +- IPS_PERMANENT and IPS_DPI_ALLOWED connection status bits +- Increased socket buffer size (10MB) for high-volume tracking +- Comcerto fast path info (ifindex, iif, mark, underlying_iif, underlying_vlan_id) +- QoS connection marking (64-bit qosconnmark attribute) +- XFRM/IPSec handle tracking for fast path +- Build ID support for netlink messages + +These extensions enable CMM daemon integration with ASK hardware offloading +on NXP Layerscape processors. + +Note: CTA attribute ordering matches kernel 6.12 nfnetlink_conntrack.h: + CTA_LAYERSCAPE_FP_ORIG, CTA_LAYERSCAPE_FP_REPLY, CTA_QOSCONNMARK, CTA_QOSCONNMARK_PAD + +Upstream-Status: Inappropriate [NXP vendor extension] +Signed-off-by: Tomaz Zaman +--- + include/internal/internal.h | 1 + + include/internal/object.h | 12 ++ + .../libnetfilter_conntrack.h | 17 ++ + .../linux_nf_conntrack_common.h | 10 +- + .../linux_nfnetlink_conntrack.h | 18 +++ + src/conntrack/api.c | 50 ++++++ + src/conntrack/build_mnl.c | 21 +++ + src/conntrack/compare.c | 14 +- + src/conntrack/copy.c | 9 ++ + src/conntrack/getter.c | 80 ++++++++++ + src/conntrack/parse_mnl.c | 151 ++++++++++++++++++ + src/conntrack/setter.c | 9 ++ + src/conntrack/snprintf_default.c | 13 ++ + src/conntrack/snprintf_xml.c | 6 + + src/main.c | 3 + + 15 files changed, 412 insertions(+), 2 deletions(-) + +diff --git a/include/internal/internal.h b/include/internal/internal.h +index 7cd7c44..2b544cd 100644 +--- a/include/internal/internal.h ++++ b/include/internal/internal.h +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/include/internal/object.h b/include/internal/object.h +index 658e4d2..1520b3b 100644 +--- a/include/internal/object.h ++++ b/include/internal/object.h +@@ -149,6 +149,16 @@ struct __nfct_nat { + union __nfct_l4_src l4min, l4max; + }; + ++/* NXP ASK: Comcerto fast path info structure */ ++struct __nfct_comcerto_fp_info { ++ int ifindex; ++ int iif; ++ uint32_t mark; ++ int underlying_iif; ++ uint16_t underlying_vlan_id; ++ uint16_t xfrm_handle[4]; ++}; ++ + struct nfct_tuple_head { + struct __nfct_tuple orig; + +@@ -164,6 +174,8 @@ struct nf_conntrack { + uint32_t timeout; + uint32_t mark; + uint32_t secmark; ++ uint64_t qosconnmark; /* NXP ASK: QoS connection mark */ ++ struct __nfct_comcerto_fp_info fp_info[__DIR_MAX]; /* NXP ASK: fast path info */ + uint32_t status; + uint32_t use; + uint32_t id; +diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h +index 27d972d..919c8b0 100644 +--- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h ++++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h +@@ -144,6 +144,20 @@ enum nf_conntrack_attr { + ATTR_SYNPROXY_ISN = 72, /* u32 bits */ + ATTR_SYNPROXY_ITS, /* u32 bits */ + ATTR_SYNPROXY_TSOFF, /* u32 bits */ ++ /* NXP ASK: Comcerto fast path attributes */ ++ ATTR_ORIG_COMCERTO_FP_IIF, ++ ATTR_ORIG_COMCERTO_FP_IFINDEX, ++ ATTR_ORIG_COMCERTO_FP_MARK, ++ ATTR_REPL_COMCERTO_FP_IIF, ++ ATTR_REPL_COMCERTO_FP_IFINDEX, ++ ATTR_REPL_COMCERTO_FP_MARK, ++ ATTR_ORIG_COMCERTO_FP_UNDERLYING_IIF, ++ ATTR_REPL_COMCERTO_FP_UNDERLYING_IIF, ++ ATTR_ORIG_COMCERTO_FP_XFRM_HANDLE, ++ ATTR_REPL_COMCERTO_FP_XFRM_HANDLE, ++ ATTR_ORIG_COMCERTO_FP_UNDERLYING_VID, ++ ATTR_REPL_COMCERTO_FP_UNDERLYING_VID, ++ ATTR_QOSCONNMARK, /* NXP ASK: u64 bits */ + ATTR_MAX + }; + +@@ -219,6 +233,9 @@ enum nf_conntrack_msg_type { + extern struct nf_conntrack *nfct_new(void); + extern void nfct_destroy(struct nf_conntrack *ct); + ++/* clear/reset conntrack object for reuse */ ++extern void nfct_clear(struct nf_conntrack *ct); ++ + /* clone */ + struct nf_conntrack *nfct_clone(const struct nf_conntrack *ct); + +diff --git a/include/libnetfilter_conntrack/linux_nf_conntrack_common.h b/include/libnetfilter_conntrack/linux_nf_conntrack_common.h +index 131ca25..73953fa 100644 +--- a/include/libnetfilter_conntrack/linux_nf_conntrack_common.h ++++ b/include/libnetfilter_conntrack/linux_nf_conntrack_common.h +@@ -123,6 +123,14 @@ enum ip_conntrack_status { + IPS_HW_OFFLOAD_BIT = 15, + IPS_HW_OFFLOAD = (1 << IPS_HW_OFFLOAD_BIT), + ++ /* NXP ASK: Connection cannot expire */ ++ IPS_PERMANENT_BIT = 16, ++ IPS_PERMANENT = (1 << IPS_PERMANENT_BIT), ++ ++ /* NXP ASK: Connection is assured by DPI application */ ++ IPS_DPI_ALLOWED_BIT = 17, ++ IPS_DPI_ALLOWED = (1 << IPS_DPI_ALLOWED_BIT), ++ + /* Be careful here, modifying these bits can make things messy, + * so don't let users modify them directly. + */ +@@ -131,7 +139,7 @@ enum ip_conntrack_status { + IPS_SEQ_ADJUST | IPS_TEMPLATE | IPS_UNTRACKED | + IPS_OFFLOAD | IPS_HW_OFFLOAD), + +- __IPS_MAX_BIT = 16, ++ __IPS_MAX_BIT = 18, + }; + + /* Connection tracking event types */ +diff --git a/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h b/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h +index b8ffe02..418870a 100644 +--- a/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h ++++ b/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h +@@ -60,6 +60,11 @@ enum ctattr_type { + CTA_SYNPROXY, + CTA_FILTER, + CTA_STATUS_MASK, ++ /* NXP ASK: Layerscape fast path attributes - order must match kernel! */ ++ CTA_LAYERSCAPE_FP_ORIG, ++ CTA_LAYERSCAPE_FP_REPLY, ++ CTA_QOSCONNMARK, ++ CTA_QOSCONNMARK_PAD, + __CTA_MAX + }; + #define CTA_MAX (__CTA_MAX - 1) +@@ -238,6 +243,19 @@ enum ctattr_help { + }; + #define CTA_HELP_MAX (__CTA_HELP_MAX - 1) + ++/* NXP ASK: Comcerto fast path nested attributes - order must match kernel! */ ++enum ctattr_comcerto_fp { ++ CTA_COMCERTO_FP_UNSPEC, ++ CTA_COMCERTO_FP_MARK, ++ CTA_COMCERTO_FP_IFINDEX, ++ CTA_COMCERTO_FP_IIF, ++ CTA_COMCERTO_FP_UNDERLYING_IIF, ++ CTA_COMCERTO_FP_UNDERLYING_VID, ++ CTA_COMCERTO_FP_XFRM_HANDLE, ++ __CTA_COMCERTO_FP_MAX ++}; ++#define CTA_COMCERTO_FP_MAX (__CTA_COMCERTO_FP_MAX - 1) ++ + enum ctattr_secctx { + CTA_SECCTX_UNSPEC, + CTA_SECCTX_NAME, +diff --git a/src/conntrack/api.c b/src/conntrack/api.c +index f0e038b..72adfb6 100644 +--- a/src/conntrack/api.c ++++ b/src/conntrack/api.c +@@ -105,6 +105,56 @@ void nfct_destroy(struct nf_conntrack *ct) + ct = NULL; /* bugtrap */ + } + ++/** ++ * nfct_clear - clear/reset a conntrack object for reuse ++ * \param ct pointer to the conntrack object ++ * ++ * This function clears the conntrack object, releasing any dynamically ++ * allocated fields and resetting all attributes. The object can then ++ * be reused without reallocation. ++ */ ++void nfct_clear(struct nf_conntrack *ct) ++{ ++ assert(ct != NULL); ++ if (ct->secctx) { ++ free(ct->secctx); ++ ct->secctx = NULL; ++ } ++ if (ct->helper_info) { ++ free(ct->helper_info); ++ ct->helper_info = NULL; ++ ct->helper_info_len = 0; ++ } ++ if (ct->connlabels) { ++ nfct_bitmask_destroy(ct->connlabels); ++ ct->connlabels = NULL; ++ } ++ if (ct->connlabels_mask) { ++ nfct_bitmask_destroy(ct->connlabels_mask); ++ ct->connlabels_mask = NULL; ++ } ++ memset(&ct->head, 0, sizeof(ct->head)); ++ memset(&ct->repl, 0, sizeof(ct->repl)); ++ memset(&ct->master, 0, sizeof(ct->master)); ++ ct->timeout = 0; ++ ct->mark = 0; ++ ct->secmark = 0; ++ ct->qosconnmark = 0; ++ memset(&ct->fp_info, 0, sizeof(ct->fp_info)); ++ ct->status = 0; ++ ct->use = 0; ++ ct->id = 0; ++ ct->zone = 0; ++ memset(ct->helper_name, 0, sizeof(ct->helper_name)); ++ memset(&ct->protoinfo, 0, sizeof(ct->protoinfo)); ++ memset(&ct->counters, 0, sizeof(ct->counters)); ++ memset(&ct->snat, 0, sizeof(ct->snat)); ++ memset(&ct->dnat, 0, sizeof(ct->dnat)); ++ memset(&ct->natseq, 0, sizeof(ct->natseq)); ++ memset(&ct->timestamp, 0, sizeof(ct->timestamp)); ++ memset(&ct->synproxy, 0, sizeof(ct->synproxy)); ++} ++ + /** + * nf_sizeof - return the size in bytes of a certain conntrack object + * \param ct pointer to the conntrack object +diff --git a/src/conntrack/build_mnl.c b/src/conntrack/build_mnl.c +index e563c4e..66fd9dc 100644 +--- a/src/conntrack/build_mnl.c ++++ b/src/conntrack/build_mnl.c +@@ -449,6 +449,20 @@ static void nfct_build_synproxy(struct nlmsghdr *nlh, + mnl_attr_nest_end(nlh, nest); + } + ++/* NXP ASK: Build QoS connection mark */ ++static void nfct_build_qosconnmark(struct nlmsghdr *nlh, ++ const struct nf_conntrack *ct) ++{ ++ uint64_t qosconnmark = htobe64(ct->qosconnmark); ++ mnl_attr_put(nlh, CTA_QOSCONNMARK, sizeof(uint64_t), &qosconnmark); ++} ++ ++/* NXP ASK: Build ID */ ++static void nfct_build_id(struct nlmsghdr *nlh, const struct nf_conntrack *ct) ++{ ++ mnl_attr_put_u32(nlh, CTA_ID, htonl(ct->id)); ++} ++ + int + nfct_nlmsg_build(struct nlmsghdr *nlh, const struct nf_conntrack *ct) + { +@@ -592,6 +606,13 @@ nfct_nlmsg_build(struct nlmsghdr *nlh, const struct nf_conntrack *ct) + test_bit(ATTR_SYNPROXY_TSOFF, ct->head.set)) + nfct_build_synproxy(nlh, ct); + ++ /* NXP ASK: QoS connection mark and ID */ ++ if (test_bit(ATTR_QOSCONNMARK, ct->head.set)) ++ nfct_build_qosconnmark(nlh, ct); ++ ++ if (test_bit(ATTR_ID, ct->head.set)) ++ nfct_build_id(nlh, ct); ++ + return 0; + } + +diff --git a/src/conntrack/compare.c b/src/conntrack/compare.c +index 8b2f3cb..86dece3 100644 +--- a/src/conntrack/compare.c ++++ b/src/conntrack/compare.c +@@ -318,7 +318,16 @@ cmp_mark(const struct nf_conntrack *ct1, + nfct_get_attr_u32(ct2, ATTR_MARK); + } + +-static int ++/* NXP ASK: QoS connection mark comparison */ ++static int ++cmp_qosconnmark(const struct nf_conntrack *ct1, ++ const struct nf_conntrack *ct2, ++ unsigned int flags) ++{ ++ return (ct1->qosconnmark == ct2->qosconnmark); ++} ++ ++static int + cmp_timeout(const struct nf_conntrack *ct1, + const struct nf_conntrack *ct2, + unsigned int flags) +@@ -448,6 +457,9 @@ static int cmp_meta(const struct nf_conntrack *ct1, + return 0; + if (!__cmp(ATTR_MARK, ct1, ct2, flags, cmp_mark, false)) + return 0; ++ /* NXP ASK: QoS connection mark */ ++ if (!__cmp(ATTR_QOSCONNMARK, ct1, ct2, flags, cmp_qosconnmark, false)) ++ return 0; + if (!__cmp(ATTR_TIMEOUT, ct1, ct2, flags, cmp_timeout, true)) + return 0; + if (!__cmp(ATTR_STATUS, ct1, ct2, flags, cmp_status, true)) +diff --git a/src/conntrack/copy.c b/src/conntrack/copy.c +index 402f994..c20b400 100644 +--- a/src/conntrack/copy.c ++++ b/src/conntrack/copy.c +@@ -516,6 +516,13 @@ static void copy_attr_synproxy_tsoff(struct nf_conntrack *dest, + dest->synproxy.tsoff = orig->synproxy.tsoff; + } + ++/* NXP ASK: QoS connection mark copy */ ++static void copy_attr_qosconnmark(struct nf_conntrack *dest, ++ const struct nf_conntrack *orig) ++{ ++ dest->qosconnmark = orig->qosconnmark; ++} ++ + const copy_attr copy_attr_array[ATTR_MAX] = { + [ATTR_ORIG_IPV4_SRC] = copy_attr_orig_ipv4_src, + [ATTR_ORIG_IPV4_DST] = copy_attr_orig_ipv4_dst, +@@ -592,6 +599,8 @@ const copy_attr copy_attr_array[ATTR_MAX] = { + [ATTR_SYNPROXY_ITS] = copy_attr_synproxy_its, + [ATTR_SYNPROXY_ISN] = copy_attr_synproxy_isn, + [ATTR_SYNPROXY_TSOFF] = copy_attr_synproxy_tsoff, ++ /* NXP ASK: QoS connection mark */ ++ [ATTR_QOSCONNMARK] = copy_attr_qosconnmark, + }; + + /* this is used by nfct_copy() with the NFCT_CP_OVERRIDE flag set. */ +diff --git a/src/conntrack/getter.c b/src/conntrack/getter.c +index d1f9a5a..ff46725 100644 +--- a/src/conntrack/getter.c ++++ b/src/conntrack/getter.c +@@ -384,6 +384,72 @@ static const void *get_attr_synproxy_tsoff(const struct nf_conntrack *ct) + return &ct->synproxy.tsoff; + } + ++/* NXP ASK: Comcerto fast path getters */ ++static const void *get_attr_orig_comcerto_fp_iif(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_ORIG].iif; ++} ++ ++static const void *get_attr_orig_comcerto_fp_ifindex(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_ORIG].ifindex; ++} ++ ++static const void *get_attr_orig_comcerto_fp_mark(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_ORIG].mark; ++} ++ ++static const void *get_attr_repl_comcerto_fp_iif(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_REPL].iif; ++} ++ ++static const void *get_attr_repl_comcerto_fp_ifindex(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_REPL].ifindex; ++} ++ ++static const void *get_attr_repl_comcerto_fp_mark(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_REPL].mark; ++} ++ ++static const void *get_attr_orig_comcerto_fp_underlying_iif(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_ORIG].underlying_iif; ++} ++ ++static const void *get_attr_repl_comcerto_fp_underlying_iif(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_REPL].underlying_iif; ++} ++ ++static const void *get_attr_orig_comcerto_fp_xfrm_handle(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_ORIG].xfrm_handle; ++} ++ ++static const void *get_attr_repl_comcerto_fp_xfrm_handle(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_REPL].xfrm_handle; ++} ++ ++static const void *get_attr_orig_comcerto_fp_underlying_vid(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_ORIG].underlying_vlan_id; ++} ++ ++static const void *get_attr_repl_comcerto_fp_underlying_vid(const struct nf_conntrack *ct) ++{ ++ return &ct->fp_info[__DIR_REPL].underlying_vlan_id; ++} ++ ++static const void *get_attr_qosconnmark(const struct nf_conntrack *ct) ++{ ++ return &ct->qosconnmark; ++} ++ + const get_attr get_attr_array[ATTR_MAX] = { + [ATTR_ORIG_IPV4_SRC] = get_attr_orig_ipv4_src, + [ATTR_ORIG_IPV4_DST] = get_attr_orig_ipv4_dst, +@@ -460,4 +526,18 @@ const get_attr get_attr_array[ATTR_MAX] = { + [ATTR_SYNPROXY_ISN] = get_attr_synproxy_isn, + [ATTR_SYNPROXY_ITS] = get_attr_synproxy_its, + [ATTR_SYNPROXY_TSOFF] = get_attr_synproxy_tsoff, ++ /* NXP ASK: Comcerto fast path and QoS */ ++ [ATTR_ORIG_COMCERTO_FP_IIF] = get_attr_orig_comcerto_fp_iif, ++ [ATTR_ORIG_COMCERTO_FP_IFINDEX] = get_attr_orig_comcerto_fp_ifindex, ++ [ATTR_ORIG_COMCERTO_FP_MARK] = get_attr_orig_comcerto_fp_mark, ++ [ATTR_REPL_COMCERTO_FP_IIF] = get_attr_repl_comcerto_fp_iif, ++ [ATTR_REPL_COMCERTO_FP_IFINDEX] = get_attr_repl_comcerto_fp_ifindex, ++ [ATTR_REPL_COMCERTO_FP_MARK] = get_attr_repl_comcerto_fp_mark, ++ [ATTR_ORIG_COMCERTO_FP_UNDERLYING_IIF] = get_attr_orig_comcerto_fp_underlying_iif, ++ [ATTR_REPL_COMCERTO_FP_UNDERLYING_IIF] = get_attr_repl_comcerto_fp_underlying_iif, ++ [ATTR_ORIG_COMCERTO_FP_XFRM_HANDLE] = get_attr_orig_comcerto_fp_xfrm_handle, ++ [ATTR_REPL_COMCERTO_FP_XFRM_HANDLE] = get_attr_repl_comcerto_fp_xfrm_handle, ++ [ATTR_ORIG_COMCERTO_FP_UNDERLYING_VID] = get_attr_orig_comcerto_fp_underlying_vid, ++ [ATTR_REPL_COMCERTO_FP_UNDERLYING_VID] = get_attr_repl_comcerto_fp_underlying_vid, ++ [ATTR_QOSCONNMARK] = get_attr_qosconnmark, + }; +diff --git a/src/conntrack/parse_mnl.c b/src/conntrack/parse_mnl.c +index 3cbfc6a..33f7824 100644 +--- a/src/conntrack/parse_mnl.c ++++ b/src/conntrack/parse_mnl.c +@@ -856,6 +856,129 @@ static int nfct_parse_synproxy(const struct nlattr *attr, + return 0; + } + ++/* NXP ASK: Comcerto fast path parsing */ ++static int ++nfct_parse_comcerto_fp_attr_cb(const struct nlattr *attr, void *data) ++{ ++ const struct nlattr **tb = data; ++ int type = mnl_attr_get_type(attr); ++ ++ if (mnl_attr_type_valid(attr, CTA_COMCERTO_FP_MAX) < 0) ++ return MNL_CB_OK; ++ ++ switch(type) { ++ case CTA_COMCERTO_FP_MARK: ++ case CTA_COMCERTO_FP_IFINDEX: ++ case CTA_COMCERTO_FP_IIF: ++ case CTA_COMCERTO_FP_UNDERLYING_IIF: ++ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ abi_breakage(); ++ break; ++ case CTA_COMCERTO_FP_UNDERLYING_VID: ++ if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ abi_breakage(); ++ break; ++ case CTA_COMCERTO_FP_XFRM_HANDLE: ++ /* 4 x u16 = 8 bytes — kernel struct nf_ct_fp_info::xfrm_handle */ ++ if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, 8) < 0) ++ abi_breakage(); ++ break; ++ } ++ tb[type] = attr; ++ return MNL_CB_OK; ++} ++ ++static int ++nfct_parse_comcerto_fp(const struct nlattr *attr, struct nf_conntrack *ct, ++ int dir) ++{ ++ struct nlattr *tb[CTA_COMCERTO_FP_MAX+1] = {}; ++ ++ if (mnl_attr_parse_nested(attr, nfct_parse_comcerto_fp_attr_cb, tb) < 0) ++ return -1; ++ ++ if (tb[CTA_COMCERTO_FP_IIF]) { ++ ct->fp_info[dir].iif = ++ mnl_attr_get_u32(tb[CTA_COMCERTO_FP_IIF]); ++ switch(dir) { ++ case __DIR_ORIG: ++ set_bit(ATTR_ORIG_COMCERTO_FP_IIF, ct->head.set); ++ break; ++ case __DIR_REPL: ++ set_bit(ATTR_REPL_COMCERTO_FP_IIF, ct->head.set); ++ break; ++ } ++ } ++ ++ if (tb[CTA_COMCERTO_FP_IFINDEX]) { ++ ct->fp_info[dir].ifindex = ++ mnl_attr_get_u32(tb[CTA_COMCERTO_FP_IFINDEX]); ++ switch(dir) { ++ case __DIR_ORIG: ++ set_bit(ATTR_ORIG_COMCERTO_FP_IFINDEX, ct->head.set); ++ break; ++ case __DIR_REPL: ++ set_bit(ATTR_REPL_COMCERTO_FP_IFINDEX, ct->head.set); ++ break; ++ } ++ } ++ ++ if (tb[CTA_COMCERTO_FP_MARK]) { ++ ct->fp_info[dir].mark = ++ mnl_attr_get_u32(tb[CTA_COMCERTO_FP_MARK]); ++ switch(dir) { ++ case __DIR_ORIG: ++ set_bit(ATTR_ORIG_COMCERTO_FP_MARK, ct->head.set); ++ break; ++ case __DIR_REPL: ++ set_bit(ATTR_REPL_COMCERTO_FP_MARK, ct->head.set); ++ break; ++ } ++ } ++ ++ if (tb[CTA_COMCERTO_FP_UNDERLYING_IIF]) { ++ ct->fp_info[dir].underlying_iif = ++ mnl_attr_get_u32(tb[CTA_COMCERTO_FP_UNDERLYING_IIF]); ++ switch(dir) { ++ case __DIR_ORIG: ++ set_bit(ATTR_ORIG_COMCERTO_FP_UNDERLYING_IIF, ct->head.set); ++ break; ++ case __DIR_REPL: ++ set_bit(ATTR_REPL_COMCERTO_FP_UNDERLYING_IIF, ct->head.set); ++ break; ++ } ++ } ++ ++ if (tb[CTA_COMCERTO_FP_UNDERLYING_VID]) { ++ ct->fp_info[dir].underlying_vlan_id = ++ mnl_attr_get_u16(tb[CTA_COMCERTO_FP_UNDERLYING_VID]); ++ switch(dir) { ++ case __DIR_ORIG: ++ set_bit(ATTR_ORIG_COMCERTO_FP_UNDERLYING_VID, ct->head.set); ++ break; ++ case __DIR_REPL: ++ set_bit(ATTR_REPL_COMCERTO_FP_UNDERLYING_VID, ct->head.set); ++ break; ++ } ++ } ++ ++ if (tb[CTA_COMCERTO_FP_XFRM_HANDLE]) { ++ memcpy(ct->fp_info[dir].xfrm_handle, ++ mnl_attr_get_payload(tb[CTA_COMCERTO_FP_XFRM_HANDLE]), ++ sizeof(ct->fp_info[dir].xfrm_handle)); ++ switch(dir) { ++ case __DIR_ORIG: ++ set_bit(ATTR_ORIG_COMCERTO_FP_XFRM_HANDLE, ct->head.set); ++ break; ++ case __DIR_REPL: ++ set_bit(ATTR_REPL_COMCERTO_FP_XFRM_HANDLE, ct->head.set); ++ break; ++ } ++ } ++ ++ return 0; ++} ++ + static int + nfct_parse_conntrack_attr_cb(const struct nlattr *attr, void *data) + { +@@ -897,6 +1020,16 @@ nfct_parse_conntrack_attr_cb(const struct nlattr *attr, void *data) + case CTA_NAT_DST: + /* deprecated */ + break; ++ /* NXP ASK: Comcerto fast path and QoS */ ++ case CTA_LAYERSCAPE_FP_ORIG: ++ case CTA_LAYERSCAPE_FP_REPLY: ++ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) ++ abi_breakage(); ++ break; ++ case CTA_QOSCONNMARK: ++ if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) ++ abi_breakage(); ++ break; + } + tb[type] = attr; + return MNL_CB_OK; +@@ -1029,6 +1162,24 @@ nfct_payload_parse(const void *payload, size_t payload_len, + return -1; + } + ++ /* NXP ASK: Comcerto fast path and QoS */ ++ if (tb[CTA_LAYERSCAPE_FP_ORIG]) { ++ if (nfct_parse_comcerto_fp(tb[CTA_LAYERSCAPE_FP_ORIG], ct, ++ __DIR_ORIG) < 0) ++ return -1; ++ } ++ ++ if (tb[CTA_LAYERSCAPE_FP_REPLY]) { ++ if (nfct_parse_comcerto_fp(tb[CTA_LAYERSCAPE_FP_REPLY], ct, ++ __DIR_REPL) < 0) ++ return -1; ++ } ++ ++ if (tb[CTA_QOSCONNMARK]) { ++ ct->qosconnmark = be64toh(mnl_attr_get_u64(tb[CTA_QOSCONNMARK])); ++ set_bit(ATTR_QOSCONNMARK, ct->head.set); ++ } ++ + return 0; + } + +diff --git a/src/conntrack/setter.c b/src/conntrack/setter.c +index cee81f1..2d25380 100644 +--- a/src/conntrack/setter.c ++++ b/src/conntrack/setter.c +@@ -457,6 +457,13 @@ set_attr_synproxy_tsoff(struct nf_conntrack *ct, const void *value, size_t len) + ct->synproxy.tsoff = *((uint32_t *) value); + } + ++/* NXP ASK: QoS connection mark setter */ ++static void ++set_attr_qosconnmark(struct nf_conntrack *ct, const void *value, size_t len) ++{ ++ ct->qosconnmark = *((uint64_t *) value); ++} ++ + static void + set_attr_do_nothing(struct nf_conntrack *ct, const void *value, size_t len) {} + +@@ -536,4 +543,6 @@ const set_attr set_attr_array[ATTR_MAX] = { + [ATTR_SYNPROXY_ISN] = set_attr_synproxy_isn, + [ATTR_SYNPROXY_ITS] = set_attr_synproxy_its, + [ATTR_SYNPROXY_TSOFF] = set_attr_synproxy_tsoff, ++ /* NXP ASK: QoS connection mark */ ++ [ATTR_QOSCONNMARK] = set_attr_qosconnmark, + }; +diff --git a/src/conntrack/snprintf_default.c b/src/conntrack/snprintf_default.c +index 4fe2a2d..8d43808 100644 +--- a/src/conntrack/snprintf_default.c ++++ b/src/conntrack/snprintf_default.c +@@ -244,6 +244,13 @@ __snprintf_mark(char *buf, unsigned int len, const struct nf_conntrack *ct) + return (snprintf(buf, len, "mark=%u ", ct->mark)); + } + ++/* NXP ASK: QoS connection mark output */ ++static int ++__snprintf_qosconnmark(char *buf, unsigned int len, const struct nf_conntrack *ct) ++{ ++ return (snprintf(buf, len, "qosconnmark=0x%" PRIx64 " ", ct->qosconnmark)); ++} ++ + static int + __snprintf_secmark(char *buf, unsigned int len, const struct nf_conntrack *ct) + { +@@ -473,6 +480,12 @@ int __snprintf_conntrack_default(char *buf, + BUFFER_SIZE(ret, size, len, offset); + } + ++ /* NXP ASK: QoS connection mark output */ ++ if (test_bit(ATTR_QOSCONNMARK, ct->head.set)) { ++ ret = __snprintf_qosconnmark(buf+offset, len, ct); ++ BUFFER_SIZE(ret, size, len, offset); ++ } ++ + if (test_bit(ATTR_SECMARK, ct->head.set)) { + ret = __snprintf_secmark(buf+offset, len, ct); + BUFFER_SIZE(ret, size, len, offset); +diff --git a/src/conntrack/snprintf_xml.c b/src/conntrack/snprintf_xml.c +index e557df2..ef917e2 100644 +--- a/src/conntrack/snprintf_xml.c ++++ b/src/conntrack/snprintf_xml.c +@@ -480,6 +480,12 @@ int __snprintf_conntrack_xml(char *buf, + BUFFER_SIZE(ret, size, len, offset); + } + ++ /* NXP ASK: QoS connection mark output */ ++ if (test_bit(ATTR_QOSCONNMARK, ct->head.set)) { ++ ret = snprintf(buf+offset, len, "%" PRIx64 "", ct->qosconnmark); ++ BUFFER_SIZE(ret, size, len, offset); ++ } ++ + if (map && test_bit(ATTR_CONNLABELS, ct->head.set)) { + ret = __snprintf_clabels_xml(buf+offset, len, ct, map); + BUFFER_SIZE(ret, size, len, offset); +diff --git a/src/main.c b/src/main.c +index 4011ad6..c0d5896 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -89,6 +89,9 @@ struct nfct_handle *nfct_open(uint8_t subsys_id, unsigned subscriptions) + if (!nfnlh) + return NULL; + ++ /* Increase socket buffer to 10MB for high-volume connection tracking */ ++ nfnl_rcvbufsiz(nfnlh, 10000000); ++ + nfcth = nfct_open_nfnl(nfnlh, subsys_id, subscriptions); + if (!nfcth) + nfnl_close(nfnlh); +-- +2.47.3 + diff --git a/package/libs/libnfnetlink/patches/900-nxp-ask-nonblocking-heap-buffer.patch b/package/libs/libnfnetlink/patches/900-nxp-ask-nonblocking-heap-buffer.patch new file mode 100644 index 0000000000..f1d609b472 --- /dev/null +++ b/package/libs/libnfnetlink/patches/900-nxp-ask-nonblocking-heap-buffer.patch @@ -0,0 +1,190 @@ +From: Tomaz Zaman +Date: Mon, 12 Jan 2026 12:00:00 +0100 +Subject: [PATCH] libnfnetlink: Add non-blocking mode and heap buffer management + +NXP ASK (Applications Solutions Kit) extensions for libnfnetlink: +- Add nfnl_set_nonblocking_mode() and nfnl_unset_nonblocking_mode() APIs +- Move receive buffer from stack to heap to prevent stack overflow with large buffers +- Required for CMM daemon high-throughput netlink communication + +Upstream-Status: Inappropriate [NXP vendor-specific extension] +Signed-off-by: Tomaz Zaman +--- +diff --git a/include/libnfnetlink/libnfnetlink.h b/include/libnfnetlink/libnfnetlink.h +index 49ce878..03d6c1d 100644 +--- a/include/libnfnetlink/libnfnetlink.h ++++ b/include/libnfnetlink/libnfnetlink.h +@@ -66,6 +66,9 @@ struct nfnl_callback { + struct nfnl_handle; + struct nfnl_subsys_handle; + ++extern NFNL_EXPORT int nfnl_set_nonblocking_mode(struct nfnl_handle *h); ++extern NFNL_EXPORT int nfnl_unset_nonblocking_mode(struct nfnl_handle *h); ++ + extern NFNL_EXPORT int nfnl_fd(struct nfnl_handle *h); + extern NFNL_EXPORT unsigned int nfnl_portid(const struct nfnl_handle *h); + +diff --git a/src/libnfnetlink.c b/src/libnfnetlink.c +index 667e5ef..96ecbbb 100644 +--- a/src/libnfnetlink.c ++++ b/src/libnfnetlink.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -103,6 +104,10 @@ struct nfnl_subsys_handle { + #define NFNL_MAX_SUBSYS 16 /* enough for now */ + + #define NFNL_F_SEQTRACK_ENABLED (1 << 0) ++#define NFNL_F_NONBLOCKING_MODE (1 << 1) ++#define NFNL_F_ALIGN_SIZE 64 ++ ++#define NFNL_F_ALIGN(buf, sz) (uint8_t *)(((unsigned long)buf + sz - 1) & (~(sz - 1))) + + struct nfnl_handle { + int fd; +@@ -112,6 +117,8 @@ struct nfnl_handle { + uint32_t seq; + uint32_t dump; + uint32_t rcv_buffer_size; /* for nfnl_catch */ ++ uint8_t *rcv_buff; ++ uint8_t *rcv_buff_aligned; + uint32_t flags; + struct nlmsghdr *last_nlhdr; + struct nfnl_subsys_handle subsys[NFNL_MAX_SUBSYS+1]; +@@ -222,8 +229,13 @@ struct nfnl_handle *nfnl_open(void) + } + nfnlh->seq = time(NULL); + nfnlh->rcv_buffer_size = NFNL_BUFFSIZE; ++ /* allocate a buffer which can be used to receive data */ ++ nfnlh->rcv_buff = (uint8_t *)calloc(nfnlh->rcv_buffer_size + NFNL_F_ALIGN_SIZE, sizeof(uint8_t)); ++ if (!nfnlh->rcv_buff) ++ goto err_close; ++ nfnlh->rcv_buff_aligned = NFNL_F_ALIGN(nfnlh->rcv_buff, NFNL_F_ALIGN_SIZE); + +- /* don't set pid here, only first socket of process has real pid !!! ++ /* don't set pid here, only first socket of process has real pid !!! + * binding to pid '0' will default */ + + /* let us do the initial bind */ +@@ -279,6 +291,58 @@ void nfnl_unset_sequence_tracking(struct nfnl_handle *h) + void nfnl_set_rcv_buffer_size(struct nfnl_handle *h, unsigned int size) + { + h->rcv_buffer_size = size; ++ /* free existing rcv_buff as there is a change in size */ ++ if (h->rcv_buff) ++ free(h->rcv_buff); ++ /* allocate a buffer which can be used to receive data */ ++ h->rcv_buff = (uint8_t *)calloc(h->rcv_buffer_size + NFNL_F_ALIGN_SIZE, 1); ++ if (!h->rcv_buff) { ++ fprintf(stderr, "%s :: calloc failed\n", __func__); ++ return; ++ } ++ h->rcv_buff_aligned = NFNL_F_ALIGN(h->rcv_buff, NFNL_F_ALIGN_SIZE); ++} ++ ++/** ++ * nfnl_set_nonblocking_mode - set non blocking mode for netlink socket ++ * @h: nfnetlink handler ++ */ ++int nfnl_set_nonblocking_mode(struct nfnl_handle *h) ++{ ++ int ret; ++ ++ ret = fcntl(h->fd, F_GETFL); ++ if (ret < 0) ++ return ret; ++ ++ ret = fcntl(h->fd, F_SETFL, ret | O_NONBLOCK); ++ if (ret < 0) ++ return ret; ++ ++ h->flags |= NFNL_F_NONBLOCKING_MODE; ++ ++ return 0; ++} ++ ++/** ++ * nfnl_unset_nonblocking_mode - unset non blocking mode for netlink socket ++ * @h: nfnetlink handler ++ */ ++int nfnl_unset_nonblocking_mode(struct nfnl_handle *h) ++{ ++ int ret; ++ ++ ret = fcntl(h->fd, F_GETFL); ++ if (ret < 0) ++ return ret; ++ ++ ret = fcntl(h->fd, F_SETFL, ret & ~O_NONBLOCK); ++ if (ret < 0) ++ return ret; ++ ++ h->flags &= ~NFNL_F_NONBLOCKING_MODE; ++ ++ return 0; + } + + /** +@@ -369,6 +433,9 @@ int nfnl_close(struct nfnl_handle *nfnlh) + for (i = 0; i < NFNL_MAX_SUBSYS; i++) + nfnl_subsys_close(&nfnlh->subsys[i]); + ++ if (nfnlh->rcv_buff) ++ free(nfnlh->rcv_buff); ++ + ret = close(nfnlh->fd); + if (ret < 0) + return ret; +@@ -1549,11 +1616,18 @@ int nfnl_catch(struct nfnl_handle *h) + + assert(h); + +- while (1) { +- unsigned char buf[h->rcv_buffer_size] +- __attribute__ ((aligned)); ++ unsigned char *buf = h->rcv_buff_aligned; ++ if (!buf) { ++ h->rcv_buff = (unsigned char *)calloc(1, h->rcv_buffer_size); ++ if (!h->rcv_buff) { ++ return -1; ++ } ++ h->rcv_buff_aligned = NFNL_F_ALIGN(h->rcv_buff, NFNL_F_ALIGN_SIZE); ++ buf = h->rcv_buff_aligned; ++ } ++ do { + +- ret = nfnl_recv(h, buf, sizeof(buf)); ++ ret = nfnl_recv(h, buf, h->rcv_buffer_size); + if (ret == -1) { + /* interrupted syscall must retry */ + if (errno == EINTR) +@@ -1563,8 +1637,9 @@ int nfnl_catch(struct nfnl_handle *h) + + ret = nfnl_process(h, buf, ret); + if (ret <= NFNL_CB_STOP) +- break; +- } ++ break; ++ ++ } while (!(h->flags & NFNL_F_NONBLOCKING_MODE)); + + return ret; + } +diff --git a/src/nfnl.version b/src/nfnl.version +index d123456..e789abc 100644 +--- a/src/nfnl.version ++++ b/src/nfnl.version +@@ -8,6 +8,8 @@ NFNETLINK_1.0.1 { + nfnl_set_sequence_tracking; + nfnl_unset_sequence_tracking; + nfnl_set_rcv_buffer_size; ++ nfnl_set_nonblocking_mode; ++ nfnl_unset_nonblocking_mode; + nfnl_send; + nfnl_sendmsg; + nfnl_sendiov; -- 2.47.3