diff options
author | Michal Swiatkowski <michal.swiatkowski@linux.intel.com> | 2024-04-22 14:05:51 +0200 |
---|---|---|
committer | David Ahern <dsahern@kernel.org> | 2024-04-23 15:34:19 +0000 |
commit | 976dca372e4c3c0685d2d6af5a305493baa4fdad (patch) | |
tree | 8c94876d28e47a2cbc8bb940afc486e52c413948 | |
parent | a25f6771bef3b1c06135ae5e0c2668b29a499472 (diff) | |
download | iproute2-next-976dca372e4c3c0685d2d6af5a305493baa4fdad.tar.gz |
f_flower: implement pfcp opts
Allow adding tc filter for PFCP header.
Add support for parsing TCA_FLOWER_KEY_ENC_OPTS_PFCP.
Options are as follows: TYPE:SEID.
TYPE is a 8-bit value represented in hex and can be 1
for session header and 0 for node header. In PFCP packet
this is S flag in header.
SEID is a 64-bit session id value represented in hex.
This patch enables adding hardware filters using PFCP fields, see [1].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=d823265dd45bbf14bd67aa476057108feb4143ce
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
-rw-r--r-- | include/libnetlink.h | 6 | ||||
-rw-r--r-- | man/man8/tc-flower.8 | 11 | ||||
-rw-r--r-- | tc/f_flower.c | 133 |
3 files changed, 150 insertions, 0 deletions
diff --git a/include/libnetlink.h b/include/libnetlink.h index 35a9bb57d..30f0c2d22 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -274,6 +274,12 @@ static inline __u64 rta_getattr_uint(const struct rtattr *rta) } return -1ULL; } + +static inline __be64 rta_getattr_be64(const struct rtattr *rta) +{ + return htobe64(rta_getattr_u64(rta)); +} + static inline __s32 rta_getattr_s32(const struct rtattr *rta) { return *(__s32 *)RTA_DATA(rta); diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index 832458138..6b5664050 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -97,6 +97,8 @@ flower \- flow based traffic control filter .B erspan_opts | .B gtp_opts +| +.B pfcp_opts } .IR OPTIONS " | " .BR ip_flags @@ -453,6 +455,8 @@ Match the connection zone, and can be masked. .BI erspan_opts " OPTIONS" .TQ .BI gtp_opts " OPTIONS" +.TQ +.BI pfcp_opts " OPTIONS" Match on IP tunnel metadata. Key id .I NUMBER is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel). @@ -494,6 +498,13 @@ doesn't support multiple options, and it consists of a key followed by a slash and corresponding mask. If the mask is missing, \fBtc\fR assumes a full-length match. The option can be described in the form PDU_TYPE:QFI/PDU_TYPE_MASK:QFI_MASK where both PDU_TYPE and QFI are represented as a 8bit hexadecimal values. +pfcp_opts +.I OPTIONS +does not support multiple options. It consists of a key followed by a slash +and corresponding mask. If the mask is missing, \fBtc\fR assumes a full-length +match. The option can be described in the form TYPE:SEID/TYPE_MASK:SEID_MASK +where TYPE is represented as a 8bit number, SEID is represented by 64bit. Both +TYPE and SEID are provided in hex. .TP .BI ip_flags " IP_FLAGS" .I IP_FLAGS diff --git a/tc/f_flower.c b/tc/f_flower.c index cfcd7b2f6..08c1001af 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -91,6 +91,7 @@ static void explain(void) " vxlan_opts MASKED-OPTIONS |\n" " erspan_opts MASKED-OPTIONS |\n" " gtp_opts MASKED-OPTIONS |\n" + " pfcp_opts MASKED-OPTIONS |\n" " ip_flags IP-FLAGS |\n" " l2_miss L2_MISS |\n" " enc_dst_port [ port_number ] |\n" @@ -1152,6 +1153,58 @@ static int flower_parse_gtp_opt(char *str, struct nlmsghdr *n) return 0; } +static int flower_parse_pfcp_opt(char *str, struct nlmsghdr *n) +{ + struct rtattr *nest; + char *token; + int i, err; + + nest = addattr_nest(n, MAX_MSG, + TCA_FLOWER_KEY_ENC_OPTS_PFCP | NLA_F_NESTED); + + i = 1; + token = strsep(&str, ":"); + while (token) { + switch (i) { + case TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE: + { + __u8 opt_type; + + if (!strlen(token)) + break; + err = get_u8(&opt_type, token, 16); + if (err) + return err; + + addattr8(n, MAX_MSG, i, opt_type); + break; + } + case TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID: + { + __be64 opt_seid;; + + if (!strlen(token)) + break; + err = get_be64(&opt_seid, token, 16); + if (err) + return err; + + addattr64(n, MAX_MSG, i, opt_seid); + break; + } + default: + fprintf(stderr, "Unknown \"pfcp_opts\" type\n"); + return -1; + } + + token = strsep(&str, ":"); + i++; + } + addattr_nest_end(n, nest); + + return 0; +} + static int flower_parse_geneve_opts(char *str, struct nlmsghdr *n) { char *token; @@ -1370,6 +1423,44 @@ static int flower_parse_enc_opts_gtp(char *str, struct nlmsghdr *n) return 0; } +static int flower_parse_enc_opts_pfcp(char *str, struct nlmsghdr *n) +{ + char key[XATTR_SIZE_MAX], mask[XATTR_SIZE_MAX]; + struct rtattr *nest; + char *slash; + int err; + + + slash = strchr(str, '/'); + if (slash) { + *slash++ = '\0'; + if (strlen(slash) > XATTR_SIZE_MAX) + return -1; + strcpy(mask, slash); + } else { + strcpy(mask, "ff:ffffffffffffffff"); + } + + if (strlen(str) > XATTR_SIZE_MAX) + return -1; + strcpy(key, str); + + nest = addattr_nest(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPTS | NLA_F_NESTED); + err = flower_parse_pfcp_opt(key, n); + if (err) + return err; + addattr_nest_end(n, nest); + + nest = addattr_nest(n, MAX_MSG, + TCA_FLOWER_KEY_ENC_OPTS_MASK | NLA_F_NESTED); + err = flower_parse_pfcp_opt(mask, n); + if (err) + return err; + addattr_nest_end(n, nest); + + return 0; +} + static int flower_parse_mpls_lse(int *argc_p, char ***argv_p, struct nlmsghdr *nlh) { @@ -2150,6 +2241,13 @@ static int flower_parse_opt(const struct filter_util *qu, char *handle, fprintf(stderr, "Illegal \"gtp_opts\"\n"); return -1; } + } else if (!strcmp(*argv, "pfcp_opts")) { + NEXT_ARG(); + ret = flower_parse_enc_opts_pfcp(*argv, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"pfcp_opts\"\n"); + return -1; + } } else if (matches(*argv, "action") == 0) { NEXT_ARG(); ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n); @@ -2646,6 +2744,29 @@ static void flower_print_gtp_opts(const char *name, struct rtattr *attr, snprintf(strbuf, len, "%02x:%02x", pdu_type, qfi); } +static void flower_print_pfcp_opts(const char *name, struct rtattr *attr, + char *strbuf, int len) +{ + struct rtattr *tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX + 1]; + struct rtattr *i = RTA_DATA(attr); + int rem = RTA_PAYLOAD(attr); + __be64 seid; + __u8 type; + + parse_rtattr(tb, TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX, i, rem); + type = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE]); + seid = rta_getattr_be64(tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID]); + + open_json_array(PRINT_JSON, name); + open_json_object(NULL); + print_uint(PRINT_JSON, "type", NULL, type); + print_uint(PRINT_JSON, "seid", NULL, seid); + close_json_object(); + close_json_array(PRINT_JSON, name); + + snprintf(strbuf, len, "%02x:%llx", type, seid); +} + static void __attribute__((format(printf, 2, 0))) flower_print_enc_parts(const char *name, const char *namefrm, struct rtattr *attr, char *key, char *mask) @@ -2738,6 +2859,18 @@ static void flower_print_enc_opts(const char *name, struct rtattr *attr, flower_print_enc_parts(name, " gtp_opts %s", attr, key, msk); + } else if (key_tb[TCA_FLOWER_KEY_ENC_OPTS_PFCP]) { + flower_print_pfcp_opts("pfcp_opt_key", + key_tb[TCA_FLOWER_KEY_ENC_OPTS_PFCP], + key, len); + + if (msk_tb[TCA_FLOWER_KEY_ENC_OPTS_PFCP]) + flower_print_pfcp_opts("pfcp_opt_mask", + msk_tb[TCA_FLOWER_KEY_ENC_OPTS_PFCP], + msk, len); + + flower_print_enc_parts(name, " pfcp_opts %s", attr, key, + msk); } free(msk); |