xref: /aosp_15_r20/external/iproute2/ip/link_vti6.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * link_vti6.c	VTI driver module
3*de1e4e89SAndroid Build Coastguard Worker  *
4*de1e4e89SAndroid Build Coastguard Worker  *		This program is free software; you can redistribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker  *		modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker  *		as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker  *		2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker  *
9*de1e4e89SAndroid Build Coastguard Worker  * Authors:	Herbert Xu <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker  *		Saurabh Mohan <[email protected]> Modified link_gre.c for VTI
11*de1e4e89SAndroid Build Coastguard Worker  *		Steffen Klassert <[email protected]> Modified link_vti.c for IPv6
12*de1e4e89SAndroid Build Coastguard Worker  */
13*de1e4e89SAndroid Build Coastguard Worker 
14*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <net/if.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <sys/types.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
19*de1e4e89SAndroid Build Coastguard Worker 
20*de1e4e89SAndroid Build Coastguard Worker #include <linux/ip.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_tunnel.h>
22*de1e4e89SAndroid Build Coastguard Worker #include "rt_names.h"
23*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
24*de1e4e89SAndroid Build Coastguard Worker #include "ip_common.h"
25*de1e4e89SAndroid Build Coastguard Worker #include "tunnel.h"
26*de1e4e89SAndroid Build Coastguard Worker 
27*de1e4e89SAndroid Build Coastguard Worker 
28*de1e4e89SAndroid Build Coastguard Worker static void usage(void) __attribute__((noreturn));
usage(void)29*de1e4e89SAndroid Build Coastguard Worker static void usage(void)
30*de1e4e89SAndroid Build Coastguard Worker {
31*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
32*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "          type { vti6 } [ remote ADDR ] [ local ADDR ]\n");
33*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "          [ [i|o]key KEY ]\n");
34*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "          [ dev PHYS_DEV ]\n");
35*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "          [ fwmark MARK ]\n");
36*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "\n");
37*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "Where: NAME := STRING\n");
38*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       ADDR := { IPV6_ADDRESS }\n");
39*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
40*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       MARK := { 0x0..0xffffffff }\n");
41*de1e4e89SAndroid Build Coastguard Worker 	exit(-1);
42*de1e4e89SAndroid Build Coastguard Worker }
43*de1e4e89SAndroid Build Coastguard Worker 
vti6_parse_opt(struct link_util * lu,int argc,char ** argv,struct nlmsghdr * n)44*de1e4e89SAndroid Build Coastguard Worker static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
45*de1e4e89SAndroid Build Coastguard Worker 			  struct nlmsghdr *n)
46*de1e4e89SAndroid Build Coastguard Worker {
47*de1e4e89SAndroid Build Coastguard Worker 	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
48*de1e4e89SAndroid Build Coastguard Worker 	struct {
49*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr n;
50*de1e4e89SAndroid Build Coastguard Worker 		struct ifinfomsg i;
51*de1e4e89SAndroid Build Coastguard Worker 		char buf[1024];
52*de1e4e89SAndroid Build Coastguard Worker 	} req = {
53*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
54*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_flags = NLM_F_REQUEST,
55*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_type = RTM_GETLINK,
56*de1e4e89SAndroid Build Coastguard Worker 		.i.ifi_family = preferred_family,
57*de1e4e89SAndroid Build Coastguard Worker 		.i.ifi_index = ifi->ifi_index,
58*de1e4e89SAndroid Build Coastguard Worker 	};
59*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[IFLA_MAX + 1];
60*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
61*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
62*de1e4e89SAndroid Build Coastguard Worker 	struct in6_addr saddr = IN6ADDR_ANY_INIT;
63*de1e4e89SAndroid Build Coastguard Worker 	struct in6_addr daddr = IN6ADDR_ANY_INIT;
64*de1e4e89SAndroid Build Coastguard Worker 	unsigned int ikey = 0;
65*de1e4e89SAndroid Build Coastguard Worker 	unsigned int okey = 0;
66*de1e4e89SAndroid Build Coastguard Worker 	unsigned int link = 0;
67*de1e4e89SAndroid Build Coastguard Worker 	__u32 fwmark = 0;
68*de1e4e89SAndroid Build Coastguard Worker 	int len;
69*de1e4e89SAndroid Build Coastguard Worker 
70*de1e4e89SAndroid Build Coastguard Worker 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
71*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
72*de1e4e89SAndroid Build Coastguard Worker get_failed:
73*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr,
74*de1e4e89SAndroid Build Coastguard Worker 				"Failed to get existing tunnel info.\n");
75*de1e4e89SAndroid Build Coastguard Worker 			return -1;
76*de1e4e89SAndroid Build Coastguard Worker 		}
77*de1e4e89SAndroid Build Coastguard Worker 
78*de1e4e89SAndroid Build Coastguard Worker 		len = req.n.nlmsg_len;
79*de1e4e89SAndroid Build Coastguard Worker 		len -= NLMSG_LENGTH(sizeof(*ifi));
80*de1e4e89SAndroid Build Coastguard Worker 		if (len < 0)
81*de1e4e89SAndroid Build Coastguard Worker 			goto get_failed;
82*de1e4e89SAndroid Build Coastguard Worker 
83*de1e4e89SAndroid Build Coastguard Worker 		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
84*de1e4e89SAndroid Build Coastguard Worker 
85*de1e4e89SAndroid Build Coastguard Worker 		if (!tb[IFLA_LINKINFO])
86*de1e4e89SAndroid Build Coastguard Worker 			goto get_failed;
87*de1e4e89SAndroid Build Coastguard Worker 
88*de1e4e89SAndroid Build Coastguard Worker 		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
89*de1e4e89SAndroid Build Coastguard Worker 
90*de1e4e89SAndroid Build Coastguard Worker 		if (!linkinfo[IFLA_INFO_DATA])
91*de1e4e89SAndroid Build Coastguard Worker 			goto get_failed;
92*de1e4e89SAndroid Build Coastguard Worker 
93*de1e4e89SAndroid Build Coastguard Worker 		parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
94*de1e4e89SAndroid Build Coastguard Worker 				    linkinfo[IFLA_INFO_DATA]);
95*de1e4e89SAndroid Build Coastguard Worker 
96*de1e4e89SAndroid Build Coastguard Worker 		if (vtiinfo[IFLA_VTI_IKEY])
97*de1e4e89SAndroid Build Coastguard Worker 			ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
98*de1e4e89SAndroid Build Coastguard Worker 
99*de1e4e89SAndroid Build Coastguard Worker 		if (vtiinfo[IFLA_VTI_OKEY])
100*de1e4e89SAndroid Build Coastguard Worker 			okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
101*de1e4e89SAndroid Build Coastguard Worker 
102*de1e4e89SAndroid Build Coastguard Worker 		if (vtiinfo[IFLA_VTI_LOCAL])
103*de1e4e89SAndroid Build Coastguard Worker 			memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr));
104*de1e4e89SAndroid Build Coastguard Worker 
105*de1e4e89SAndroid Build Coastguard Worker 		if (vtiinfo[IFLA_VTI_REMOTE])
106*de1e4e89SAndroid Build Coastguard Worker 			memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr));
107*de1e4e89SAndroid Build Coastguard Worker 
108*de1e4e89SAndroid Build Coastguard Worker 		if (vtiinfo[IFLA_VTI_LINK])
109*de1e4e89SAndroid Build Coastguard Worker 			link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
110*de1e4e89SAndroid Build Coastguard Worker 
111*de1e4e89SAndroid Build Coastguard Worker 		if (vtiinfo[IFLA_VTI_FWMARK])
112*de1e4e89SAndroid Build Coastguard Worker 			fwmark = rta_getattr_u32(vtiinfo[IFLA_VTI_FWMARK]);
113*de1e4e89SAndroid Build Coastguard Worker 	}
114*de1e4e89SAndroid Build Coastguard Worker 
115*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
116*de1e4e89SAndroid Build Coastguard Worker 		if (!matches(*argv, "key")) {
117*de1e4e89SAndroid Build Coastguard Worker 			unsigned int uval;
118*de1e4e89SAndroid Build Coastguard Worker 
119*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
120*de1e4e89SAndroid Build Coastguard Worker 			if (strchr(*argv, '.'))
121*de1e4e89SAndroid Build Coastguard Worker 				uval = get_addr32(*argv);
122*de1e4e89SAndroid Build Coastguard Worker 			else {
123*de1e4e89SAndroid Build Coastguard Worker 				if (get_unsigned(&uval, *argv, 0) < 0) {
124*de1e4e89SAndroid Build Coastguard Worker 					fprintf(stderr,
125*de1e4e89SAndroid Build Coastguard Worker 						"Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv);
126*de1e4e89SAndroid Build Coastguard Worker 					exit(-1);
127*de1e4e89SAndroid Build Coastguard Worker 				}
128*de1e4e89SAndroid Build Coastguard Worker 				uval = htonl(uval);
129*de1e4e89SAndroid Build Coastguard Worker 			}
130*de1e4e89SAndroid Build Coastguard Worker 
131*de1e4e89SAndroid Build Coastguard Worker 			ikey = okey = uval;
132*de1e4e89SAndroid Build Coastguard Worker 		} else if (!matches(*argv, "ikey")) {
133*de1e4e89SAndroid Build Coastguard Worker 			unsigned int uval;
134*de1e4e89SAndroid Build Coastguard Worker 
135*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
136*de1e4e89SAndroid Build Coastguard Worker 			if (strchr(*argv, '.'))
137*de1e4e89SAndroid Build Coastguard Worker 				uval = get_addr32(*argv);
138*de1e4e89SAndroid Build Coastguard Worker 			else {
139*de1e4e89SAndroid Build Coastguard Worker 				if (get_unsigned(&uval, *argv, 0) < 0) {
140*de1e4e89SAndroid Build Coastguard Worker 					fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv);
141*de1e4e89SAndroid Build Coastguard Worker 					exit(-1);
142*de1e4e89SAndroid Build Coastguard Worker 				}
143*de1e4e89SAndroid Build Coastguard Worker 				uval = htonl(uval);
144*de1e4e89SAndroid Build Coastguard Worker 			}
145*de1e4e89SAndroid Build Coastguard Worker 			ikey = uval;
146*de1e4e89SAndroid Build Coastguard Worker 		} else if (!matches(*argv, "okey")) {
147*de1e4e89SAndroid Build Coastguard Worker 			unsigned int uval;
148*de1e4e89SAndroid Build Coastguard Worker 
149*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
150*de1e4e89SAndroid Build Coastguard Worker 			if (strchr(*argv, '.'))
151*de1e4e89SAndroid Build Coastguard Worker 				uval = get_addr32(*argv);
152*de1e4e89SAndroid Build Coastguard Worker 			else {
153*de1e4e89SAndroid Build Coastguard Worker 				if (get_unsigned(&uval, *argv, 0) < 0) {
154*de1e4e89SAndroid Build Coastguard Worker 					fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv);
155*de1e4e89SAndroid Build Coastguard Worker 					exit(-1);
156*de1e4e89SAndroid Build Coastguard Worker 				}
157*de1e4e89SAndroid Build Coastguard Worker 				uval = htonl(uval);
158*de1e4e89SAndroid Build Coastguard Worker 			}
159*de1e4e89SAndroid Build Coastguard Worker 			okey = uval;
160*de1e4e89SAndroid Build Coastguard Worker 		} else if (!matches(*argv, "remote")) {
161*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
162*de1e4e89SAndroid Build Coastguard Worker 			if (!strcmp(*argv, "any")) {
163*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "invalid value for \"remote\": \"%s\"\n", *argv);
164*de1e4e89SAndroid Build Coastguard Worker 				exit(-1);
165*de1e4e89SAndroid Build Coastguard Worker 			} else {
166*de1e4e89SAndroid Build Coastguard Worker 				inet_prefix addr;
167*de1e4e89SAndroid Build Coastguard Worker 
168*de1e4e89SAndroid Build Coastguard Worker 				get_prefix(&addr, *argv, AF_INET6);
169*de1e4e89SAndroid Build Coastguard Worker 				memcpy(&daddr, addr.data, addr.bytelen);
170*de1e4e89SAndroid Build Coastguard Worker 			}
171*de1e4e89SAndroid Build Coastguard Worker 		} else if (!matches(*argv, "local")) {
172*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
173*de1e4e89SAndroid Build Coastguard Worker 			if (!strcmp(*argv, "any")) {
174*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv);
175*de1e4e89SAndroid Build Coastguard Worker 				exit(-1);
176*de1e4e89SAndroid Build Coastguard Worker 			} else {
177*de1e4e89SAndroid Build Coastguard Worker 				inet_prefix addr;
178*de1e4e89SAndroid Build Coastguard Worker 
179*de1e4e89SAndroid Build Coastguard Worker 				get_prefix(&addr, *argv, AF_INET6);
180*de1e4e89SAndroid Build Coastguard Worker 				memcpy(&saddr, addr.data, addr.bytelen);
181*de1e4e89SAndroid Build Coastguard Worker 			}
182*de1e4e89SAndroid Build Coastguard Worker 		} else if (!matches(*argv, "dev")) {
183*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
184*de1e4e89SAndroid Build Coastguard Worker 			link = if_nametoindex(*argv);
185*de1e4e89SAndroid Build Coastguard Worker 			if (link == 0)
186*de1e4e89SAndroid Build Coastguard Worker 				exit(-1);
187*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "fwmark") == 0) {
188*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
189*de1e4e89SAndroid Build Coastguard Worker 			if (get_u32(&fwmark, *argv, 0))
190*de1e4e89SAndroid Build Coastguard Worker 				invarg("invalid fwmark\n", *argv);
191*de1e4e89SAndroid Build Coastguard Worker 		} else
192*de1e4e89SAndroid Build Coastguard Worker 			usage();
193*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
194*de1e4e89SAndroid Build Coastguard Worker 	}
195*de1e4e89SAndroid Build Coastguard Worker 
196*de1e4e89SAndroid Build Coastguard Worker 	addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
197*de1e4e89SAndroid Build Coastguard Worker 	addattr32(n, 1024, IFLA_VTI_OKEY, okey);
198*de1e4e89SAndroid Build Coastguard Worker 
199*de1e4e89SAndroid Build Coastguard Worker 	if (memcmp(&saddr, &in6addr_any, sizeof(in6addr_any)))
200*de1e4e89SAndroid Build Coastguard Worker 	    addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr));
201*de1e4e89SAndroid Build Coastguard Worker 	if (memcmp(&daddr, &in6addr_any, sizeof(in6addr_any)))
202*de1e4e89SAndroid Build Coastguard Worker 	    addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr));
203*de1e4e89SAndroid Build Coastguard Worker 	addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark);
204*de1e4e89SAndroid Build Coastguard Worker 	if (link)
205*de1e4e89SAndroid Build Coastguard Worker 		addattr32(n, 1024, IFLA_VTI_LINK, link);
206*de1e4e89SAndroid Build Coastguard Worker 
207*de1e4e89SAndroid Build Coastguard Worker 	return 0;
208*de1e4e89SAndroid Build Coastguard Worker }
209*de1e4e89SAndroid Build Coastguard Worker 
vti6_print_opt(struct link_util * lu,FILE * f,struct rtattr * tb[])210*de1e4e89SAndroid Build Coastguard Worker static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
211*de1e4e89SAndroid Build Coastguard Worker {
212*de1e4e89SAndroid Build Coastguard Worker 	const char *local = "any";
213*de1e4e89SAndroid Build Coastguard Worker 	const char *remote = "any";
214*de1e4e89SAndroid Build Coastguard Worker 	struct in6_addr saddr;
215*de1e4e89SAndroid Build Coastguard Worker 	struct in6_addr daddr;
216*de1e4e89SAndroid Build Coastguard Worker 	unsigned int link;
217*de1e4e89SAndroid Build Coastguard Worker 	char s2[64];
218*de1e4e89SAndroid Build Coastguard Worker 
219*de1e4e89SAndroid Build Coastguard Worker 	if (!tb)
220*de1e4e89SAndroid Build Coastguard Worker 		return;
221*de1e4e89SAndroid Build Coastguard Worker 
222*de1e4e89SAndroid Build Coastguard Worker 	if (tb[IFLA_VTI_REMOTE]) {
223*de1e4e89SAndroid Build Coastguard Worker 		memcpy(&daddr, RTA_DATA(tb[IFLA_VTI_REMOTE]), sizeof(daddr));
224*de1e4e89SAndroid Build Coastguard Worker 
225*de1e4e89SAndroid Build Coastguard Worker 		remote = format_host(AF_INET6, 16, &daddr);
226*de1e4e89SAndroid Build Coastguard Worker 	}
227*de1e4e89SAndroid Build Coastguard Worker 
228*de1e4e89SAndroid Build Coastguard Worker 	print_string(PRINT_ANY, "remote", "remote %s ", remote);
229*de1e4e89SAndroid Build Coastguard Worker 
230*de1e4e89SAndroid Build Coastguard Worker 	if (tb[IFLA_VTI_LOCAL]) {
231*de1e4e89SAndroid Build Coastguard Worker 		memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr));
232*de1e4e89SAndroid Build Coastguard Worker 
233*de1e4e89SAndroid Build Coastguard Worker 		local = format_host(AF_INET6, 16, &saddr);
234*de1e4e89SAndroid Build Coastguard Worker 	}
235*de1e4e89SAndroid Build Coastguard Worker 
236*de1e4e89SAndroid Build Coastguard Worker 	print_string(PRINT_ANY, "local", "local %s ", local);
237*de1e4e89SAndroid Build Coastguard Worker 
238*de1e4e89SAndroid Build Coastguard Worker 	if (tb[IFLA_VTI_LINK] && (link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) {
239*de1e4e89SAndroid Build Coastguard Worker 		const char *n = if_indextoname(link, s2);
240*de1e4e89SAndroid Build Coastguard Worker 
241*de1e4e89SAndroid Build Coastguard Worker 		if (n)
242*de1e4e89SAndroid Build Coastguard Worker 			print_string(PRINT_ANY, "link", "dev %s ", n);
243*de1e4e89SAndroid Build Coastguard Worker 		else
244*de1e4e89SAndroid Build Coastguard Worker 			print_uint(PRINT_ANY, "link_index", "dev %u ", link);
245*de1e4e89SAndroid Build Coastguard Worker 	}
246*de1e4e89SAndroid Build Coastguard Worker 
247*de1e4e89SAndroid Build Coastguard Worker 	if (tb[IFLA_VTI_IKEY]) {
248*de1e4e89SAndroid Build Coastguard Worker 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2));
249*de1e4e89SAndroid Build Coastguard Worker 		print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
250*de1e4e89SAndroid Build Coastguard Worker 	}
251*de1e4e89SAndroid Build Coastguard Worker 
252*de1e4e89SAndroid Build Coastguard Worker 	if (tb[IFLA_VTI_OKEY]) {
253*de1e4e89SAndroid Build Coastguard Worker 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2));
254*de1e4e89SAndroid Build Coastguard Worker 		print_string(PRINT_ANY, "okey", "okey %s ", s2);
255*de1e4e89SAndroid Build Coastguard Worker 	}
256*de1e4e89SAndroid Build Coastguard Worker 
257*de1e4e89SAndroid Build Coastguard Worker 	if (tb[IFLA_VTI_FWMARK]) {
258*de1e4e89SAndroid Build Coastguard Worker 		__u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
259*de1e4e89SAndroid Build Coastguard Worker 
260*de1e4e89SAndroid Build Coastguard Worker 		if (fwmark) {
261*de1e4e89SAndroid Build Coastguard Worker 			snprintf(s2, sizeof(s2), "0x%x", fwmark);
262*de1e4e89SAndroid Build Coastguard Worker 
263*de1e4e89SAndroid Build Coastguard Worker 			print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
264*de1e4e89SAndroid Build Coastguard Worker 		}
265*de1e4e89SAndroid Build Coastguard Worker 	}
266*de1e4e89SAndroid Build Coastguard Worker }
267*de1e4e89SAndroid Build Coastguard Worker 
268*de1e4e89SAndroid Build Coastguard Worker struct link_util vti6_link_util = {
269*de1e4e89SAndroid Build Coastguard Worker 	.id = "vti6",
270*de1e4e89SAndroid Build Coastguard Worker 	.maxattr = IFLA_VTI_MAX,
271*de1e4e89SAndroid Build Coastguard Worker 	.parse_opt = vti6_parse_opt,
272*de1e4e89SAndroid Build Coastguard Worker 	.print_opt = vti6_print_opt,
273*de1e4e89SAndroid Build Coastguard Worker };
274