diff options
author | Wojciech Drewek <wojciech.drewek@intel.com> | 2022-03-17 17:27:55 +0100 |
---|---|---|
committer | David Ahern <dsahern@kernel.org> | 2022-03-20 17:40:29 -0600 |
commit | 28add13738253cf07cc7aa4bb73148ea718d8d77 (patch) | |
tree | 1cbd37cfd204b1be77850b7b60b57dd0d8181db7 | |
parent | b25599c57ef283b4d94ea4881d423d761a9ca3dc (diff) | |
download | iproute2-28add13738253cf07cc7aa4bb73148ea718d8d77.tar.gz |
f_flower: Implement gtp options support
Add support for parsing TCA_FLOWER_KEY_ENC_OPTS_GTP.
Options are as follows: PDU_TYPE:QFI where each
option is represented as 8-bit hexadecimal value.
e.g.
# ip link add gtp_dev type gtp role sgsn
# tc qdisc add dev gtp_dev ingress
# tc filter add dev gtp_dev protocol ip parent ffff: \
flower \
enc_key_id 11 \
gtp_opts 1:8/ff:ff \
action mirred egress redirect dev eth0
Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
-rw-r--r-- | man/man8/tc-flower.8 | 10 | ||||
-rw-r--r-- | tc/f_flower.c | 123 |
2 files changed, 131 insertions, 2 deletions
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index 4541d9372..f918a06d2 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -89,6 +89,8 @@ flower \- flow based traffic control filter .B vxlan_opts | .B erspan_opts +| +.B gtp_opts } .IR OPTIONS " | " .BR ip_flags @@ -411,6 +413,8 @@ Match the connection zone, and can be masked. .BI vxlan_opts " OPTIONS" .TQ .BI erspan_opts " OPTIONS" +.TQ +.BI gtp_opts " OPTIONS" Match on IP tunnel metadata. Key id .I NUMBER is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel). @@ -446,6 +450,12 @@ VERSION:INDEX:DIR:HWID/VERSION:INDEX_MASK:DIR_MASK:HWID_MASK, where VERSION is represented as a 8bit number, INDEX as an 32bit number, DIR and HWID as a 8bit number. Multiple options is not supported. Note INDEX/INDEX_MASK is used when VERSION is 1, and DIR/DIR_MASK and HWID/HWID_MASK are used when VERSION is 2. +gtp_opts +.I OPTIONS +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. .TP .BI ip_flags " IP_FLAGS" .I IP_FLAGS diff --git a/tc/f_flower.c b/tc/f_flower.c index ad159719c..686cf1214 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -84,6 +84,7 @@ static void explain(void) " geneve_opts MASKED-OPTIONS |\n" " vxlan_opts MASKED-OPTIONS |\n" " erspan_opts MASKED-OPTIONS |\n" + " gtp_opts MASKED-OPTIONS |\n" " ip_flags IP-FLAGS |\n" " enc_dst_port [ port_number ] |\n" " ct_state MASKED_CT_STATE |\n" @@ -1034,6 +1035,52 @@ static int flower_parse_erspan_opt(char *str, struct nlmsghdr *n) return 0; } +static int flower_parse_gtp_opt(char *str, struct nlmsghdr *n) +{ + struct rtattr *nest; + char *token; + int arg, err; + + nest = addattr_nest(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPTS_GTP | NLA_F_NESTED); + + token = strsep(&str, ":"); + for (arg = 1; arg <= TCA_FLOWER_KEY_ENC_OPT_GTP_MAX; arg++) { + switch (arg) { + case TCA_FLOWER_KEY_ENC_OPT_GTP_PDU_TYPE: + { + __u8 pdu_type; + + if (!strlen(token)) + break; + err = get_u8(&pdu_type, token, 16); + if (err) + return err; + addattr8(n, MAX_MSG, arg, pdu_type); + break; + } + case TCA_FLOWER_KEY_ENC_OPT_GTP_QFI: + { + __u8 qfi; + + if (!strlen(token)) + break; + err = get_u8(&qfi, token, 16); + if (err) + return err; + addattr8(n, MAX_MSG, arg, qfi); + break; + } + default: + fprintf(stderr, "Unknown \"gtp_opts\" type\n"); + return -1; + } + token = strsep(&str, ":"); + } + addattr_nest_end(n, nest); + + return 0; +} + static int flower_parse_geneve_opts(char *str, struct nlmsghdr *n) { char *token; @@ -1217,6 +1264,41 @@ static int flower_parse_enc_opts_erspan(char *str, struct nlmsghdr *n) return 0; } +static int flower_parse_enc_opts_gtp(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:ff"); + + 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_gtp_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_gtp_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) { @@ -1869,6 +1951,13 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, fprintf(stderr, "Illegal \"erspan_opts\"\n"); return -1; } + } else if (!strcmp(*argv, "gtp_opts")) { + NEXT_ARG(); + ret = flower_parse_enc_opts_gtp(*argv, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"gtp_opts\"\n"); + return -1; + } } else if (matches(*argv, "action") == 0) { NEXT_ARG(); ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n); @@ -2338,6 +2427,21 @@ static void flower_print_erspan_opts(const char *name, struct rtattr *attr, sprintf(strbuf, "%u:%u:%u:%u", ver, idx, dir, hwid); } +static void flower_print_gtp_opts(const char *name, struct rtattr *attr, + char *strbuf, int len) +{ + struct rtattr *tb[TCA_FLOWER_KEY_ENC_OPT_GTP_MAX + 1]; + __u8 pdu_type, qfi; + + parse_rtattr(tb, TCA_FLOWER_KEY_ENC_OPT_GTP_MAX, RTA_DATA(attr), + RTA_PAYLOAD(attr)); + + pdu_type = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_GTP_PDU_TYPE]); + qfi = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_GTP_QFI]); + + snprintf(strbuf, len, "%02x:%02x", pdu_type, qfi); +} + static void __attribute__((format(printf, 2, 0))) flower_print_enc_parts(const char *name, const char *namefrm, struct rtattr *attr, char *key, char *mask) @@ -2370,15 +2474,18 @@ static void flower_print_enc_opts(const char *name, struct rtattr *attr, struct rtattr *key_tb[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1]; struct rtattr *msk_tb[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1]; char *key, *msk; + int len; if (!attr) return; - key = malloc(RTA_PAYLOAD(attr) * 2 + 1); + len = RTA_PAYLOAD(attr) * 2 + 1; + + key = malloc(len); if (!key) return; - msk = malloc(RTA_PAYLOAD(attr) * 2 + 1); + msk = malloc(len); if (!msk) goto err_key_free; @@ -2415,6 +2522,18 @@ static void flower_print_enc_opts(const char *name, struct rtattr *attr, flower_print_enc_parts(name, " erspan_opts %s", attr, key, msk); + } else if (key_tb[TCA_FLOWER_KEY_ENC_OPTS_GTP]) { + flower_print_gtp_opts("gtp_opt_key", + key_tb[TCA_FLOWER_KEY_ENC_OPTS_GTP], + key, len); + + if (msk_tb[TCA_FLOWER_KEY_ENC_OPTS_GTP]) + flower_print_gtp_opts("gtp_opt_mask", + msk_tb[TCA_FLOWER_KEY_ENC_OPTS_GTP], + msk, len); + + flower_print_enc_parts(name, " gtp_opts %s", attr, key, + msk); } free(msk); |