]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ip: xfrm: support adding xfrm metadata as lwtunnel info in routes
authorEyal Birger <eyal.birger@gmail.com>
Mon, 3 Oct 2022 09:12:12 +0000 (12:12 +0300)
committerDavid Ahern <dsahern@kernel.org>
Mon, 3 Oct 2022 14:49:04 +0000 (08:49 -0600)
Support for xfrm metadata as lwtunnel metadata was added in kernel commit
2c2493b9da91 ("xfrm: lwtunnel: add lwtunnel support for xfrm interfaces in collect_md mode")

This commit adds the respective support in lwt routes.

Example use (consider ipsec1 as an xfrm interface in "external" mode):

ip route add 10.1.0.0/24 dev ipsec1 encap xfrm if_id 1

Or in the context of vrf, one can also specify the "link" property:

ip route add 10.1.0.0/24 dev ipsec1 encap xfrm if_id 1 link_dev eth15

Signed-off-by: Eyal Birger <eyal.birger@gmail.com>
Reviewed-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
ip/iproute.c
ip/iproute_lwtunnel.c
man/man8/ip-route.8.in

index 8b2d1fbe963b46048721a981cd8d13331f2d069e..b4b9d1b203d426e026d54a91182c6c292b51ffd2 100644 (file)
@@ -102,8 +102,8 @@ static void usage(void)
                "TIME := NUMBER[s|ms]\n"
                "BOOL := [1|0]\n"
                "FEATURES := ecn\n"
-               "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl | ioam6 ]\n"
-               "ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL | IOAM6HDR ]\n"
+               "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl | ioam6 | xfrm ]\n"
+               "ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL | IOAM6HDR | XFRMINFO ]\n"
                "SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n"
                "SEGMODE := [ encap | encap.red | inline | l2encap | l2encap.red ]\n"
                "SEG6LOCAL := action ACTION [ OPTIONS ] [ count ]\n"
@@ -116,6 +116,7 @@ static void usage(void)
                "FLAVORS := { FLAVOR[,FLAVOR] }\n"
                "FLAVOR := { psp | usp | usd | next-csid }\n"
                "IOAM6HDR := trace prealloc type IOAM6_TRACE_TYPE ns IOAM6_NAMESPACE size IOAM6_TRACE_SIZE\n"
+               "XFRMINFO := if_id IF_ID [ link_dev LINK ]\n"
                "ROUTE_GET_FLAGS := [ fibmatch ]\n");
        exit(-1);
 }
index 86128c9b6f7c93810a9fcbc8af26536dedb6b62b..bf4468b6db1601c284ddcc7ddd1285182ddc2c74 100644 (file)
@@ -58,6 +58,8 @@ static const char *format_encap_type(int type)
                return "rpl";
        case LWTUNNEL_ENCAP_IOAM6:
                return "ioam6";
+       case LWTUNNEL_ENCAP_XFRM:
+               return "xfrm";
        default:
                return "unknown";
        }
@@ -96,6 +98,8 @@ static int read_encap_type(const char *name)
                return LWTUNNEL_ENCAP_RPL;
        else if (strcmp(name, "ioam6") == 0)
                return LWTUNNEL_ENCAP_IOAM6;
+       else if (strcmp(name, "xfrm") == 0)
+               return LWTUNNEL_ENCAP_XFRM;
        else if (strcmp(name, "help") == 0)
                encap_type_usage();
 
@@ -814,6 +818,24 @@ static void print_encap_bpf(FILE *fp, struct rtattr *encap)
                           " %u ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
 }
 
+static void print_encap_xfrm(FILE *fp, struct rtattr *encap)
+{
+       struct rtattr *tb[LWT_XFRM_MAX+1];
+
+       parse_rtattr_nested(tb, LWT_XFRM_MAX, encap);
+
+       if (tb[LWT_XFRM_IF_ID])
+               print_uint(PRINT_ANY, "if_id", "if_id %lu ",
+                          rta_getattr_u32(tb[LWT_XFRM_IF_ID]));
+
+       if (tb[LWT_XFRM_LINK]) {
+               int link = rta_getattr_u32(tb[LWT_XFRM_LINK]);
+
+               print_string(PRINT_ANY, "link_dev", "link_dev %s ",
+                            ll_index_to_name(link));
+       }
+}
+
 void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
                          struct rtattr *encap)
 {
@@ -854,6 +876,9 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
        case LWTUNNEL_ENCAP_IOAM6:
                print_encap_ioam6(fp, encap);
                break;
+       case LWTUNNEL_ENCAP_XFRM:
+               print_encap_xfrm(fp, encap);
+               break;
        }
 }
 
@@ -2129,6 +2154,61 @@ static int parse_encap_bpf(struct rtattr *rta, size_t len, int *argcp,
        return 0;
 }
 
+static void lwt_xfrm_usage(void)
+{
+       fprintf(stderr, "Usage: ip route ... encap xfrm if_id IF_ID [ link_dev LINK ]\n");
+       exit(-1);
+}
+
+static int parse_encap_xfrm(struct rtattr *rta, size_t len,
+                           int *argcp, char ***argvp)
+{
+       int if_id_ok = 0, link_ok = 0;
+       char **argv = *argvp;
+       int argc = *argcp;
+       int ret = 0;
+
+       while (argc > 0) {
+               if (!strcmp(*argv, "if_id")) {
+                       __u32 if_id;
+
+                       NEXT_ARG();
+                       if (if_id_ok++)
+                               duparg2("if_id", *argv);
+                       if (get_u32(&if_id, *argv, 0) || if_id == 0)
+                               invarg("\"if_id\" value is invalid\n", *argv);
+                       ret = rta_addattr32(rta, len, LWT_XFRM_IF_ID, if_id);
+               } else if (!strcmp(*argv, "link_dev")) {
+                       int link;
+
+                       NEXT_ARG();
+                       if (link_ok++)
+                               duparg2("link_dev", *argv);
+                       link = ll_name_to_index(*argv);
+                       if (!link)
+                               exit(nodev(*argv));
+                       ret = rta_addattr32(rta, len, LWT_XFRM_LINK, link);
+               } else if (!strcmp(*argv, "help")) {
+                       lwt_xfrm_usage();
+               }
+               if (ret)
+                       break;
+               argc--; argv++;
+       }
+
+       if (!if_id_ok)
+               lwt_xfrm_usage();
+
+       /* argv is currently the first unparsed argument,
+        * but the lwt_parse_encap() caller will move to the next,
+        * so step back
+        */
+       *argcp = argc + 1;
+       *argvp = argv - 1;
+
+       return ret;
+}
+
 int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp,
                    int encap_attr, int encap_type_attr)
 {
@@ -2180,6 +2260,9 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp,
        case LWTUNNEL_ENCAP_IOAM6:
                ret = parse_encap_ioam6(rta, len, &argc, &argv);
                break;
+       case LWTUNNEL_ENCAP_XFRM:
+               ret = parse_encap_xfrm(rta, len, &argc, &argv);
+               break;
        default:
                fprintf(stderr, "Error: unsupported encap type\n");
                break;
index bd38b7d86d4b1efe399011988bdb79eee19368ce..194dc780d890e5b37f406ed7f5be9fa7eb35e7ec 100644 (file)
@@ -738,6 +738,9 @@ is a string specifying the supported encapsulation type. Namely:
 .sp
 .BI ioam6
 - encapsulation type IPv6 IOAM
+.sp
+.BI xfrm
+- encapsulation type XFRM
 
 .in -8
 .I ENCAPHDR
@@ -1024,6 +1027,14 @@ mode.
 .B size
 .I IOAM6_TRACE_SIZE
 - Size, in octets, of the pre-allocated trace data block.
+.in -2
+
+.B xfrm
+.in +2
+.B if_id
+.I IF_ID
+.B  " [ link_dev
+.IR LINK_DEV " ] "
 .in -4
 
 .in -8