This patch adds a new extension to iptables to support IPv6 segment routing 'SEG6' target. The supported actions are: (1) go-next (2) skip-next (3) go-last (4) bind-sid Signed-off-by: Ahmed Abdelsalam <amsalam20@xxxxxxxxx> --- extensions/libip6t_SEG6.c | 154 +++++++++++++++++++++++++++++++ include/linux/netfilter_ipv6/ip6t_SEG6.h | 22 +++++ 2 files changed, 176 insertions(+) create mode 100644 extensions/libip6t_SEG6.c create mode 100644 include/linux/netfilter_ipv6/ip6t_SEG6.h diff --git a/extensions/libip6t_SEG6.c b/extensions/libip6t_SEG6.c new file mode 100644 index 00000000..2f06001e --- /dev/null +++ b/extensions/libip6t_SEG6.c @@ -0,0 +1,154 @@ +/* + * Shared library add-on to ip6tables to add SEG6 target support + * + * Author: + * Ahmed Abdelsalam <amsalam20@xxxxxxxxx> + */ + +#include <stdio.h> +#include <string.h> +#include <xtables.h> +#include <linux/netfilter_ipv6/ip6t_SEG6.h> + +struct seg6_names { + const char *name; + enum ip6t_seg6_action action; + const char *desc; +}; + +/* SEG6 target command-line options */ +enum { + O_SEG6_ACTION, + O_SEG6_BSID, + O_SEG6_TABLE, +}; + +static const struct seg6_names seg6_table[] = { + {"go-next", IP6T_SEG6_GO_NEXT, "SEG6 go next"}, + {"skip-next", IP6T_SEG6_SKIP_NEXT, "SEG6 skip next"}, + {"go-last", IP6T_SEG6_GO_LAST, "SEG6 go last"}, + {"bind-sid", IP6T_SEG6_BSID, "SRv6 bind SID"}, +}; + +static void print_seg6_action(void) +{ + unsigned int i; + + printf("Valid SEG6 action:\n"); + for (i = 0; i < ARRAY_SIZE(seg6_table); ++i) { + printf("\t %s", seg6_table[i].name); + if (seg6_table[i].action == IP6T_SEG6_BSID) + printf(" --bsid <ip6addr> --bsid-tbl <table_number> "); + else + printf(" \t\t\t\t\t"); + printf(" \t%s", seg6_table[i].desc); + printf("\n"); + } + printf("\n"); +} + +static void SEG6_help(void) +{ + printf( +"SEG6 target options:\n" +"--seg6-action action perform SR-specific action on SRv6 packets\n"); + print_seg6_action(); +} + +#define s struct ip6t_seg6_info +static const struct xt_option_entry SEG6_opts[] = { + {.name = "seg6-action", .id = O_SEG6_ACTION, .type = XTTYPE_STRING, + .flags = XTOPT_MAND }, + {.name = "bsid", .id = O_SEG6_BSID, .type = XTTYPE_HOST}, + {.name = "bsid-tbl", .id = O_SEG6_TABLE, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, tbl)}, + {} +}; +#undef s + +static void SEG6_init(struct xt_entry_target *t) +{ + struct ip6t_seg6_info *seg6 = (struct ip6t_seg6_info *)t->data; + + memset(&seg6->bsid, 0, sizeof(struct in6_addr)); + seg6->tbl = 0; +} + +static void SEG6_parse(struct xt_option_call *cb) +{ + struct ip6t_seg6_info *seg6 = cb->data; + unsigned int i; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SEG6_ACTION: + for (i = 0; i < ARRAY_SIZE(seg6_table); ++i) + if (strncasecmp(seg6_table[i].name, cb->arg, strlen(cb->arg)) == 0) { + seg6->action = seg6_table[i].action; + return; + } + xtables_error(PARAMETER_PROBLEM, "unknown SEG6 target action \"%s\"", cb->arg); + case O_SEG6_BSID: + if (seg6->action != IP6T_SEG6_BSID) + xtables_error(PARAMETER_PROBLEM, + "bsid can be used only with \"bind-sid\" action"); + seg6->bsid = cb->val.haddr.in6; + break; + case O_SEG6_TABLE: + if (seg6->action != IP6T_SEG6_BSID) + xtables_error(PARAMETER_PROBLEM, + "bsid-tbl can be only used with \"bind-sid\" action"); + break; + } +} + +static void SEG6_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct ip6t_seg6_info *seg6 = (const struct ip6t_seg6_info *)target->data; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(seg6_table); ++i) + if (seg6_table[i].action == seg6->action) + break; + printf(" seg6-action %s", seg6_table[i].name); + if (seg6->action == IP6T_SEG6_BSID) { + printf(" bsid %s", xtables_ip6addr_to_numeric(&seg6->bsid)); + printf(" bsid-tbl %d", seg6->tbl); + } +} + +static void SEG6_save(const void *ip, const struct xt_entry_target *target) +{ + + const struct ip6t_seg6_info *seg6 = (const struct ip6t_seg6_info *)target->data; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(seg6_table); ++i) + if (seg6_table[i].action == seg6->action) + break; + printf(" --seg6-action %s", seg6_table[i].name); + if (seg6->action == IP6T_SEG6_BSID) { + printf(" --bsid %s", xtables_ip6addr_to_numeric(&seg6->bsid)); + printf(" --bsid-tbl %d", seg6->tbl); + } +} + +static struct xtables_target seg6_tg6_reg = { + .name = "SEG6", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct ip6t_seg6_info)), + .userspacesize = XT_ALIGN(sizeof(struct ip6t_seg6_info)), + .help = SEG6_help, + .init = SEG6_init, + .print = SEG6_print, + .save = SEG6_save, + .x6_parse = SEG6_parse, + .x6_options = SEG6_opts, +}; + +void _init(void) +{ + xtables_register_target(&seg6_tg6_reg); +} diff --git a/include/linux/netfilter_ipv6/ip6t_SEG6.h b/include/linux/netfilter_ipv6/ip6t_SEG6.h new file mode 100644 index 00000000..443805d0 --- /dev/null +++ b/include/linux/netfilter_ipv6/ip6t_SEG6.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#ifndef _IP6T_SEG6_H +#define _IP6T_SEG6_H + +#include <linux/types.h> + +/* SEG6 action options */ +enum ip6t_seg6_action { + IP6T_SEG6_GO_NEXT, + IP6T_SEG6_SKIP_NEXT, + IP6T_SEG6_GO_LAST, + IP6T_SEG6_BSID, +}; + +struct ip6t_seg6_info { + __u32 action; /* SEG6 action */ + struct in6_addr bsid; /* SRv6 Bind SID */ + unsigned int tbl; /* Routing table of bsid */ +}; + +#endif /*_IP6T_SEG6_H*/ -- 2.11.0