Add support for IOAM encap modes

This patch adds support for the three IOAM encap modes that were introduced:
inline, encap and auto.

Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
Justin Iurman 2021-10-05 17:10:19 +02:00 committed by David Ahern
parent b840c620fe
commit 8fb522cde3
1 changed files with 101 additions and 43 deletions

View File

@ -210,16 +210,54 @@ static void print_encap_rpl(FILE *fp, struct rtattr *encap)
print_rpl_srh(fp, srh);
}
static const char *ioam6_mode_types[IOAM6_IPTUNNEL_MODE_MAX + 1] = {
[IOAM6_IPTUNNEL_MODE_INLINE] = "inline",
[IOAM6_IPTUNNEL_MODE_ENCAP] = "encap",
[IOAM6_IPTUNNEL_MODE_AUTO] = "auto",
};
static const char *format_ioam6mode_type(int mode)
{
if (mode < IOAM6_IPTUNNEL_MODE_MIN ||
mode > IOAM6_IPTUNNEL_MODE_MAX ||
!ioam6_mode_types[mode])
return "<unknown>";
return ioam6_mode_types[mode];
}
static __u8 read_ioam6mode_type(const char *mode)
{
__u8 i;
for (i = IOAM6_IPTUNNEL_MODE_MIN; i <= IOAM6_IPTUNNEL_MODE_MAX; i++) {
if (ioam6_mode_types[i] && !strcmp(mode, ioam6_mode_types[i]))
return i;
}
return 0;
}
static void print_encap_ioam6(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[IOAM6_IPTUNNEL_MAX + 1];
struct ioam6_trace_hdr *trace;
__u8 mode;
parse_rtattr_nested(tb, IOAM6_IPTUNNEL_MAX, encap);
if (!tb[IOAM6_IPTUNNEL_TRACE])
if (!tb[IOAM6_IPTUNNEL_MODE] || !tb[IOAM6_IPTUNNEL_TRACE])
return;
mode = rta_getattr_u8(tb[IOAM6_IPTUNNEL_MODE]);
if (!tb[IOAM6_IPTUNNEL_DST] && mode != IOAM6_IPTUNNEL_MODE_INLINE)
return;
print_string(PRINT_ANY, "mode", "mode %s ", format_ioam6mode_type(mode));
if (mode != IOAM6_IPTUNNEL_MODE_INLINE)
print_string(PRINT_ANY, "tundst", "tundst %s ",
rt_addr_n2a_rta(AF_INET6, tb[IOAM6_IPTUNNEL_DST]));
trace = RTA_DATA(tb[IOAM6_IPTUNNEL_TRACE]);
print_null(PRINT_ANY, "trace", "trace ", NULL);
@ -884,23 +922,48 @@ out:
static int parse_encap_ioam6(struct rtattr *rta, size_t len, int *argcp,
char ***argvp)
{
int ns_found = 0, argc = *argcp;
__u16 trace_ns, trace_size = 0;
struct ioam6_trace_hdr *trace;
char **argv = *argvp;
int argc = *argcp;
int ns_found = 0;
__u16 size = 0;
__u32 type = 0;
__u16 ns;
__u32 trace_type = 0;
inet_prefix addr;
__u8 mode;
trace = calloc(1, sizeof(*trace));
if (!trace)
return -1;
if (strcmp(*argv, "mode") != 0) {
mode = IOAM6_IPTUNNEL_MODE_INLINE;
} else {
NEXT_ARG();
if (strcmp(*argv, "trace"))
mode = read_ioam6mode_type(*argv);
if (!mode)
invarg("Invalid mode", *argv);
NEXT_ARG();
}
if (strcmp(*argv, "tundst") != 0) {
if (mode != IOAM6_IPTUNNEL_MODE_INLINE)
missarg("tundst");
} else {
if (mode == IOAM6_IPTUNNEL_MODE_INLINE)
invarg("Inline mode does not need tundst", *argv);
NEXT_ARG();
get_addr(&addr, *argv, AF_INET6);
if (addr.family != AF_INET6 || addr.bytelen != 16)
invarg("Invalid IPv6 address for tundst", *argv);
NEXT_ARG();
}
if (strcmp(*argv, "trace") != 0)
missarg("trace");
NEXT_ARG();
if (strcmp(*argv, "prealloc"))
if (strcmp(*argv, "prealloc") != 0)
missarg("prealloc");
while (NEXT_ARG_OK()) {
@ -909,63 +972,58 @@ static int parse_encap_ioam6(struct rtattr *rta, size_t len, int *argcp,
if (strcmp(*argv, "type") == 0) {
NEXT_ARG();
if (type)
if (trace_type)
duparg2("type", *argv);
if (get_u32(&type, *argv, 0) || !type)
invarg("Invalid type", *argv);
trace->type_be32 = htonl(type << 8);
if (get_u32(&trace_type, *argv, 0) || !trace_type)
invarg("Invalid trace type", *argv);
} else if (strcmp(*argv, "ns") == 0) {
NEXT_ARG();
if (ns_found++)
duparg2("ns", *argv);
if (!type)
missarg("type");
if (get_u16(&ns, *argv, 0))
if (get_u16(&trace_ns, *argv, 0))
invarg("Invalid namespace ID", *argv);
trace->namespace_id = htons(ns);
} else if (strcmp(*argv, "size") == 0) {
NEXT_ARG();
if (size)
if (trace_size)
duparg2("size", *argv);
if (!type)
missarg("type");
if (!ns_found)
missarg("ns");
if (get_u16(&trace_size, *argv, 0) || !trace_size)
invarg("Invalid trace size", *argv);
if (get_u16(&size, *argv, 0) || !size)
invarg("Invalid size", *argv);
if (size % 4)
invarg("Size must be a 4-octet multiple", *argv);
if (size > IOAM6_TRACE_DATA_SIZE_MAX)
invarg("Size too big", *argv);
trace->remlen = (__u8)(size / 4);
if (trace_size % 4)
invarg("Trace size must be a 4-octet multiple",
*argv);
if (trace_size > IOAM6_TRACE_DATA_SIZE_MAX)
invarg("Trace size is too big", *argv);
} else {
break;
}
}
if (!type)
if (!trace_type)
missarg("type");
if (!ns_found)
missarg("ns");
if (!size)
if (!trace_size)
missarg("size");
if (rta_addattr_l(rta, len, IOAM6_IPTUNNEL_TRACE, trace,
sizeof(*trace))) {
trace = calloc(1, sizeof(*trace));
if (!trace)
return -1;
trace->type_be32 = htonl(trace_type << 8);
trace->namespace_id = htons(trace_ns);
trace->remlen = (__u8)(trace_size / 4);
if (rta_addattr8(rta, len, IOAM6_IPTUNNEL_MODE, mode) ||
(mode != IOAM6_IPTUNNEL_MODE_INLINE &&
rta_addattr_l(rta, len, IOAM6_IPTUNNEL_DST, &addr.data, addr.bytelen)) ||
rta_addattr_l(rta, len, IOAM6_IPTUNNEL_TRACE, trace, sizeof(*trace))) {
free(trace);
return -1;
}