Merge branch 'ioam-encap-modes' into next

Justin Iurman  says:

====================

Following the series applied to net-next (see [1]), here are the corresponding
changes to iproute2.

In the current implementation, IOAM can only be inserted directly (i.e., only
inside packets generated locally) by default, to be compliant with RFC8200.

This patch adds support for in-transit packets and provides the ip6ip6
encapsulation of IOAM (RFC8200 compliant). Therefore, three ioam6 encap modes
are defined:

 - inline: directly inserts IOAM inside packets (by default).

 - encap:  ip6ip6 encapsulation of IOAM inside packets.

 - auto:   either inline mode for packets generated locally or encap mode for
           in-transit packets.

With current iproute2 implementation, it is configured this way:

$ ip -6 r [...] encap ioam6 trace prealloc [...]

The old syntax does not change (for backwards compatibility) and implicitly uses
the inline mode. With the new syntax, an encap mode can be specified:

(inline mode)
$ ip -6 r [...] encap ioam6 mode inline trace prealloc [...]

(encap mode)
$ ip -6 r [...] encap ioam6 mode encap tundst fc00::2 trace prealloc [...]

(auto mode)
$ ip -6 r [...] encap ioam6 mode auto tundst fc00::2 trace prealloc [...]

A tunnel destination address must be configured when using the encap mode or the
auto mode.

  [1] https://lore.kernel.org/netdev/163335001045.30570.12527451523558030753.git-patchwork-notify@kernel.org/T/#m3b428d4142ee3a414ec803466c211dfdec6e0c09

====================

Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
David Ahern 2021-10-09 17:37:12 -06:00
commit 763fd793fe
2 changed files with 133 additions and 50 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;
}

View File

@ -246,13 +246,17 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
.ti -8
.IR ENCAP_IOAM6 " := "
.B ioam6
.BR trace
.BR prealloc
.BR type
.BR mode " [ "
.BR inline " | " encap " | " auto " ] ["
.B tundst
.IR ADDRESS " ] "
.B trace
.B prealloc
.B type
.IR IOAM6_TRACE_TYPE
.BR ns
.B ns
.IR IOAM6_NAMESPACE
.BR size
.B size
.IR IOAM6_TRACE_SIZE
.ti -8
@ -915,14 +919,35 @@ address is set as described in \fBip-sr\fR(8).
.B ioam6
.in +2
.B mode inline
- Directly insert IOAM after IPv6 header (default mode).
.sp
.B mode encap
- Encapsulate packet in an outer IPv6 header with IOAM.
.sp
.B mode auto
- Automatically use inline mode for local packets and encap mode for in-transit
packets.
.sp
.B tundst
.I ADDRESS
- IPv6 address of the tunnel destination (outer header), not used with inline
mode.
.B type
.I IOAM6_TRACE_TYPE
- List of IOAM data required in the trace, represented by a bitfield (24 bits).
.sp
.B ns
.I IOAM6_NAMESPACE
- Numerical value to represent an IOAM namespace. See \fBip-ioam\fR(8).
.sp
.B size
.I IOAM6_TRACE_SIZE
- Size, in octets, of the pre-allocated trace data block.
.in -4
@ -1249,9 +1274,9 @@ ip -6 route add 2001:db8:1::/64 encap seg6local action End.DT46 vrftable 100 dev
Adds an IPv6 route with SRv6 decapsulation and forward with lookup in VRF table.
.RE
.PP
ip -6 route add 2001:db8:1::/64 encap ioam6 trace prealloc type 0x800000 ns 1 size 12 dev eth0
ip -6 route add 2001:db8:1::/64 encap ioam6 mode encap tundst 2001:db8:42::1 trace prealloc type 0x800000 ns 1 size 12 dev eth0
.RS 4
Adds an IPv6 route with an IOAM Pre-allocated Trace encapsulation that only includes the hop limit and the node id, configured for the IOAM namespace 1 and a pre-allocated data block of 12 octets.
Adds an IPv6 route with an IOAM Pre-allocated Trace encapsulation (ip6ip6) that only includes the hop limit and the node id, configured for the IOAM namespace 1 and a pre-allocated data block of 12 octets.
.RE
.PP
ip route add 10.1.1.0/30 nhid 10