]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/link_iptnl.c
ip/tunnel: Correct and unify ttl/hoplimit printing
[mirror_iproute2.git] / ip / link_iptnl.c
1 /*
2 * link_iptnl.c ipip and sit driver module
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Nicolas Dichtel <nicolas.dichtel@6wind.com>
10 *
11 */
12
13 #include <string.h>
14 #include <net/if.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <arpa/inet.h>
18
19 #include <linux/in.h>
20 #include <linux/ip.h>
21 #include <linux/if_tunnel.h>
22 #include "rt_names.h"
23 #include "utils.h"
24 #include "ip_common.h"
25 #include "tunnel.h"
26
27 static void print_usage(FILE *f, int sit)
28 {
29 const char *type = sit ? "sit " : "ipip";
30
31 fprintf(f,
32 "Usage: ... %s [ remote ADDR ]\n"
33 " [ local ADDR ]\n"
34 " [ ttl TTL ]\n"
35 " [ tos TOS ]\n"
36 " [ [no]pmtudisc ]\n"
37 " [ dev PHYS_DEV ]\n"
38 " [ 6rd-prefix ADDR ]\n"
39 " [ 6rd-relay_prefix ADDR ]\n"
40 " [ 6rd-reset ]\n"
41 " [ noencap ]\n"
42 " [ encap { fou | gue | none } ]\n"
43 " [ encap-sport PORT ]\n"
44 " [ encap-dport PORT ]\n"
45 " [ [no]encap-csum ]\n"
46 " [ [no]encap-csum6 ]\n"
47 " [ [no]encap-remcsum ]\n",
48 type
49 );
50 if (sit) {
51 fprintf(f, " [ mode { ip6ip | ipip | mplsip | any } ]\n");
52 fprintf(f, " [ isatap ]\n");
53 } else {
54 fprintf(f, " [ mode { ipip | mplsip | any } ]\n");
55 }
56 fprintf(f, " [ external ]\n");
57 fprintf(f, " [ fwmark MARK ]\n");
58 fprintf(f, "\n");
59 fprintf(f, "Where: ADDR := { IP_ADDRESS | any }\n");
60 fprintf(f, " TOS := { NUMBER | inherit }\n");
61 fprintf(f, " TTL := { 1..255 | inherit }\n");
62 fprintf(f, " MARK := { 0x0..0xffffffff }\n");
63 }
64
65 static void usage(int sit) __attribute__((noreturn));
66 static void usage(int sit)
67 {
68 print_usage(stderr, sit);
69 exit(-1);
70 }
71
72 static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
73 struct nlmsghdr *n)
74 {
75 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
76 struct {
77 struct nlmsghdr n;
78 struct ifinfomsg i;
79 } req = {
80 .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
81 .n.nlmsg_flags = NLM_F_REQUEST,
82 .n.nlmsg_type = RTM_GETLINK,
83 .i.ifi_family = preferred_family,
84 .i.ifi_index = ifi->ifi_index,
85 };
86 struct nlmsghdr *answer;
87 struct rtattr *tb[IFLA_MAX + 1];
88 struct rtattr *linkinfo[IFLA_INFO_MAX+1];
89 struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
90 int len;
91 __u32 link = 0;
92 __u32 laddr = 0;
93 __u32 raddr = 0;
94 __u8 ttl = 0;
95 __u8 tos = 0;
96 __u8 pmtudisc = 1;
97 __u16 iflags = 0;
98 __u8 proto = 0;
99 struct in6_addr ip6rdprefix = {};
100 __u16 ip6rdprefixlen = 0;
101 __u32 ip6rdrelayprefix = 0;
102 __u16 ip6rdrelayprefixlen = 0;
103 __u16 encaptype = 0;
104 __u16 encapflags = 0;
105 __u16 encapsport = 0;
106 __u16 encapdport = 0;
107 __u8 metadata = 0;
108 __u32 fwmark = 0;
109
110 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
111 if (rtnl_talk(&rth, &req.n, &answer) < 0) {
112 get_failed:
113 fprintf(stderr,
114 "Failed to get existing tunnel info.\n");
115 return -1;
116 }
117
118 len = answer->nlmsg_len;
119 len -= NLMSG_LENGTH(sizeof(*ifi));
120 if (len < 0)
121 goto get_failed;
122
123 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
124
125 if (!tb[IFLA_LINKINFO])
126 goto get_failed;
127
128 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
129
130 if (!linkinfo[IFLA_INFO_DATA])
131 goto get_failed;
132
133 parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX,
134 linkinfo[IFLA_INFO_DATA]);
135
136 if (iptuninfo[IFLA_IPTUN_LOCAL])
137 laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]);
138
139 if (iptuninfo[IFLA_IPTUN_REMOTE])
140 raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]);
141
142 if (iptuninfo[IFLA_IPTUN_TTL])
143 ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]);
144
145 if (iptuninfo[IFLA_IPTUN_TOS])
146 tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]);
147
148 if (iptuninfo[IFLA_IPTUN_PMTUDISC])
149 pmtudisc =
150 rta_getattr_u8(iptuninfo[IFLA_IPTUN_PMTUDISC]);
151
152 if (iptuninfo[IFLA_IPTUN_FLAGS])
153 iflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_FLAGS]);
154
155 if (iptuninfo[IFLA_IPTUN_LINK])
156 link = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LINK]);
157
158 if (iptuninfo[IFLA_IPTUN_PROTO])
159 proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]);
160
161 if (iptuninfo[IFLA_IPTUN_ENCAP_TYPE])
162 encaptype = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_TYPE]);
163 if (iptuninfo[IFLA_IPTUN_ENCAP_FLAGS])
164 encapflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_FLAGS]);
165 if (iptuninfo[IFLA_IPTUN_ENCAP_SPORT])
166 encapsport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_SPORT]);
167 if (iptuninfo[IFLA_IPTUN_ENCAP_DPORT])
168 encapdport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_DPORT]);
169 if (iptuninfo[IFLA_IPTUN_6RD_PREFIX])
170 memcpy(&ip6rdprefix,
171 RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]),
172 sizeof(laddr));
173
174 if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN])
175 ip6rdprefixlen =
176 rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]);
177
178 if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX])
179 ip6rdrelayprefix =
180 rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]);
181
182 if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN])
183 ip6rdrelayprefixlen =
184 rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
185 if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA])
186 metadata = 1;
187
188 if (iptuninfo[IFLA_IPTUN_FWMARK])
189 fwmark = rta_getattr_u32(iptuninfo[IFLA_IPTUN_FWMARK]);
190
191 free(answer);
192 }
193
194 while (argc > 0) {
195 if (strcmp(*argv, "remote") == 0) {
196 NEXT_ARG();
197 raddr = get_addr32(*argv);
198 } else if (strcmp(*argv, "local") == 0) {
199 NEXT_ARG();
200 laddr = get_addr32(*argv);
201 } else if (matches(*argv, "dev") == 0) {
202 NEXT_ARG();
203 link = if_nametoindex(*argv);
204 if (link == 0)
205 invarg("\"dev\" is invalid", *argv);
206 } else if (strcmp(*argv, "ttl") == 0 ||
207 strcmp(*argv, "hoplimit") == 0) {
208 NEXT_ARG();
209 if (strcmp(*argv, "inherit") != 0) {
210 if (get_u8(&ttl, *argv, 0))
211 invarg("invalid TTL\n", *argv);
212 } else
213 ttl = 0;
214 } else if (strcmp(*argv, "tos") == 0 ||
215 strcmp(*argv, "tclass") == 0 ||
216 matches(*argv, "dsfield") == 0) {
217 __u32 uval;
218
219 NEXT_ARG();
220 if (strcmp(*argv, "inherit") != 0) {
221 if (rtnl_dsfield_a2n(&uval, *argv))
222 invarg("bad TOS value", *argv);
223 tos = uval;
224 } else
225 tos = 1;
226 } else if (strcmp(*argv, "nopmtudisc") == 0) {
227 pmtudisc = 0;
228 } else if (strcmp(*argv, "pmtudisc") == 0) {
229 pmtudisc = 1;
230 } else if (strcmp(lu->id, "sit") == 0 &&
231 strcmp(*argv, "isatap") == 0) {
232 iflags |= SIT_ISATAP;
233 } else if (strcmp(*argv, "mode") == 0) {
234 NEXT_ARG();
235 if (strcmp(lu->id, "sit") == 0 &&
236 (strcmp(*argv, "ipv6/ipv4") == 0 ||
237 strcmp(*argv, "ip6ip") == 0))
238 proto = IPPROTO_IPV6;
239 else if (strcmp(*argv, "ipv4/ipv4") == 0 ||
240 strcmp(*argv, "ipip") == 0 ||
241 strcmp(*argv, "ip4ip4") == 0)
242 proto = IPPROTO_IPIP;
243 else if (strcmp(*argv, "mpls/ipv4") == 0 ||
244 strcmp(*argv, "mplsip") == 0)
245 proto = IPPROTO_MPLS;
246 else if (strcmp(*argv, "any/ipv4") == 0 ||
247 strcmp(*argv, "any") == 0)
248 proto = 0;
249 else
250 invarg("Cannot guess tunnel mode.", *argv);
251 } else if (strcmp(*argv, "noencap") == 0) {
252 encaptype = TUNNEL_ENCAP_NONE;
253 } else if (strcmp(*argv, "encap") == 0) {
254 NEXT_ARG();
255 if (strcmp(*argv, "fou") == 0)
256 encaptype = TUNNEL_ENCAP_FOU;
257 else if (strcmp(*argv, "gue") == 0)
258 encaptype = TUNNEL_ENCAP_GUE;
259 else if (strcmp(*argv, "none") == 0)
260 encaptype = TUNNEL_ENCAP_NONE;
261 else
262 invarg("Invalid encap type.", *argv);
263 } else if (strcmp(*argv, "encap-sport") == 0) {
264 NEXT_ARG();
265 if (strcmp(*argv, "auto") == 0)
266 encapsport = 0;
267 else if (get_u16(&encapsport, *argv, 0))
268 invarg("Invalid source port.", *argv);
269 } else if (strcmp(*argv, "encap-dport") == 0) {
270 NEXT_ARG();
271 if (get_u16(&encapdport, *argv, 0))
272 invarg("Invalid destination port.", *argv);
273 } else if (strcmp(*argv, "encap-csum") == 0) {
274 encapflags |= TUNNEL_ENCAP_FLAG_CSUM;
275 } else if (strcmp(*argv, "noencap-csum") == 0) {
276 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM;
277 } else if (strcmp(*argv, "encap-udp6-csum") == 0) {
278 encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
279 } else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
280 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6;
281 } else if (strcmp(*argv, "encap-remcsum") == 0) {
282 encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
283 } else if (strcmp(*argv, "noencap-remcsum") == 0) {
284 encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM;
285 } else if (strcmp(*argv, "external") == 0) {
286 metadata = 1;
287 } else if (strcmp(*argv, "6rd-prefix") == 0) {
288 inet_prefix prefix;
289
290 NEXT_ARG();
291 if (get_prefix(&prefix, *argv, AF_INET6))
292 invarg("invalid 6rd_prefix\n", *argv);
293 memcpy(&ip6rdprefix, prefix.data, 16);
294 ip6rdprefixlen = prefix.bitlen;
295 } else if (strcmp(*argv, "6rd-relay_prefix") == 0) {
296 inet_prefix prefix;
297
298 NEXT_ARG();
299 if (get_prefix(&prefix, *argv, AF_INET))
300 invarg("invalid 6rd-relay_prefix\n", *argv);
301 memcpy(&ip6rdrelayprefix, prefix.data, 4);
302 ip6rdrelayprefixlen = prefix.bitlen;
303 } else if (strcmp(*argv, "6rd-reset") == 0) {
304 inet_prefix prefix;
305
306 get_prefix(&prefix, "2002::", AF_INET6);
307 memcpy(&ip6rdprefix, prefix.data, 16);
308 ip6rdprefixlen = 16;
309 ip6rdrelayprefix = 0;
310 ip6rdrelayprefixlen = 0;
311 } else if (strcmp(*argv, "fwmark") == 0) {
312 NEXT_ARG();
313 if (get_u32(&fwmark, *argv, 0))
314 invarg("invalid fwmark\n", *argv);
315 } else
316 usage(strcmp(lu->id, "sit") == 0);
317 argc--, argv++;
318 }
319
320 if (ttl && pmtudisc == 0) {
321 fprintf(stderr, "ttl != 0 and nopmtudisc are incompatible\n");
322 exit(-1);
323 }
324
325 addattr8(n, 1024, IFLA_IPTUN_PROTO, proto);
326 if (metadata) {
327 addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0);
328 return 0;
329 }
330
331 addattr32(n, 1024, IFLA_IPTUN_LINK, link);
332 addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr);
333 addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr);
334 addattr8(n, 1024, IFLA_IPTUN_TTL, ttl);
335 addattr8(n, 1024, IFLA_IPTUN_TOS, tos);
336 addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc);
337 addattr32(n, 1024, IFLA_IPTUN_FWMARK, fwmark);
338
339 addattr16(n, 1024, IFLA_IPTUN_ENCAP_TYPE, encaptype);
340 addattr16(n, 1024, IFLA_IPTUN_ENCAP_FLAGS, encapflags);
341 addattr16(n, 1024, IFLA_IPTUN_ENCAP_SPORT, htons(encapsport));
342 addattr16(n, 1024, IFLA_IPTUN_ENCAP_DPORT, htons(encapdport));
343
344 if (strcmp(lu->id, "sit") == 0) {
345 addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags);
346 if (ip6rdprefixlen) {
347 addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX,
348 &ip6rdprefix, sizeof(ip6rdprefix));
349 addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN,
350 ip6rdprefixlen);
351 addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX,
352 ip6rdrelayprefix);
353 addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
354 ip6rdrelayprefixlen);
355 }
356 }
357
358 return 0;
359 }
360
361 static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
362 {
363 char s1[1024];
364 char s2[64];
365 const char *local = "any";
366 const char *remote = "any";
367 __u16 prefixlen, type;
368 __u8 ttl = 0;
369
370 if (!tb)
371 return;
372
373 if (tb[IFLA_IPTUN_COLLECT_METADATA])
374 print_bool(PRINT_ANY, "external", "external ", true);
375
376 if (tb[IFLA_IPTUN_PROTO]) {
377 switch (rta_getattr_u8(tb[IFLA_IPTUN_PROTO])) {
378 case IPPROTO_IPIP:
379 print_string(PRINT_ANY, "proto", "%s ", "ipip");
380 break;
381 case IPPROTO_IPV6:
382 print_string(PRINT_ANY, "proto", "%s ", "ip6ip");
383 break;
384 case IPPROTO_MPLS:
385 print_string(PRINT_ANY, "proto", "%s ", "mplsip");
386 break;
387 case 0:
388 print_string(PRINT_ANY, "proto", "%s ", "any");
389 break;
390 }
391 }
392
393 if (tb[IFLA_IPTUN_REMOTE]) {
394 unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_REMOTE]);
395
396 if (addr)
397 remote = format_host(AF_INET, 4, &addr);
398 }
399
400 print_string(PRINT_ANY, "remote", "remote %s ", remote);
401
402 if (tb[IFLA_IPTUN_LOCAL]) {
403 unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]);
404
405 if (addr)
406 local = format_host(AF_INET, 4, &addr);
407 }
408
409 print_string(PRINT_ANY, "local", "local %s ", local);
410
411 if (tb[IFLA_IPTUN_LINK]) {
412 unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
413
414 if (link) {
415 print_string(PRINT_ANY, "link", "dev %s ",
416 ll_index_to_name(link));
417 }
418 }
419
420 if (tb[IFLA_IPTUN_TTL])
421 ttl = rta_getattr_u8(tb[IFLA_IPTUN_TTL]);
422 if (is_json_context() || ttl)
423 print_uint(PRINT_ANY, "ttl", "ttl %u ", ttl);
424 else
425 print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
426
427 if (tb[IFLA_IPTUN_TOS]) {
428 int tos = rta_getattr_u8(tb[IFLA_IPTUN_TOS]);
429
430 if (tos) {
431 if (is_json_context()) {
432 print_0xhex(PRINT_JSON, "tos", "%#x", tos);
433 } else {
434 fputs("tos ", f);
435 if (tos == 1)
436 fputs("inherit ", f);
437 else
438 fprintf(f, "0x%x ", tos);
439 }
440 }
441 }
442
443 if (tb[IFLA_IPTUN_PMTUDISC] && rta_getattr_u8(tb[IFLA_IPTUN_PMTUDISC]))
444 print_bool(PRINT_ANY, "pmtudisc", "pmtudisc ", true);
445 else
446 print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false);
447
448 if (tb[IFLA_IPTUN_FLAGS]) {
449 __u16 iflags = rta_getattr_u16(tb[IFLA_IPTUN_FLAGS]);
450
451 if (iflags & SIT_ISATAP)
452 print_bool(PRINT_ANY, "isatap", "isatap ", true);
453 }
454
455 if (tb[IFLA_IPTUN_6RD_PREFIXLEN] &&
456 (prefixlen = rta_getattr_u16(tb[IFLA_IPTUN_6RD_PREFIXLEN]))) {
457 __u16 relayprefixlen =
458 rta_getattr_u16(tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
459 __u32 relayprefix =
460 rta_getattr_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]);
461
462 const char *prefix = inet_ntop(AF_INET6,
463 RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]),
464 s1, sizeof(s1));
465
466 if (is_json_context()) {
467 print_string(PRINT_JSON, "prefix", NULL, prefix);
468 print_int(PRINT_JSON, "prefixlen", NULL, prefixlen);
469 if (relayprefix) {
470 print_string(PRINT_JSON,
471 "relay_prefix",
472 NULL,
473 format_host(AF_INET,
474 4,
475 &relayprefix));
476 print_int(PRINT_JSON,
477 "relay_prefixlen",
478 NULL,
479 relayprefixlen);
480 }
481 } else {
482 printf("6rd-prefix %s/%u ", prefix, prefixlen);
483 if (relayprefix) {
484 printf("6rd-relay_prefix %s/%u ",
485 format_host(AF_INET, 4, &relayprefix),
486 relayprefixlen);
487 }
488 }
489 }
490
491 if (tb[IFLA_IPTUN_ENCAP_TYPE] &&
492 (type = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE])) != TUNNEL_ENCAP_NONE) {
493 __u16 flags = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_FLAGS]);
494 __u16 sport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_SPORT]);
495 __u16 dport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_DPORT]);
496
497 open_json_object("encap");
498 print_string(PRINT_FP, NULL, "encap ", NULL);
499 switch (type) {
500 case TUNNEL_ENCAP_FOU:
501 print_string(PRINT_ANY, "type", "%s ", "fou");
502 break;
503 case TUNNEL_ENCAP_GUE:
504 print_string(PRINT_ANY, "type", "%s ", "gue");
505 break;
506 default:
507 print_null(PRINT_ANY, "type", "unknown ", NULL);
508 break;
509 }
510
511 if (is_json_context()) {
512 print_uint(PRINT_JSON,
513 "sport",
514 NULL,
515 sport ? ntohs(sport) : 0);
516 print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
517 print_bool(PRINT_JSON,
518 "csum",
519 NULL,
520 flags & TUNNEL_ENCAP_FLAG_CSUM);
521 print_bool(PRINT_JSON,
522 "csum6",
523 NULL,
524 flags & TUNNEL_ENCAP_FLAG_CSUM6);
525 print_bool(PRINT_JSON,
526 "remcsum",
527 NULL,
528 flags & TUNNEL_ENCAP_FLAG_REMCSUM);
529 close_json_object();
530 } else {
531 if (sport == 0)
532 fputs("encap-sport auto ", f);
533 else
534 fprintf(f, "encap-sport %u", ntohs(sport));
535
536 fprintf(f, "encap-dport %u ", ntohs(dport));
537
538 if (flags & TUNNEL_ENCAP_FLAG_CSUM)
539 fputs("encap-csum ", f);
540 else
541 fputs("noencap-csum ", f);
542
543 if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
544 fputs("encap-csum6 ", f);
545 else
546 fputs("noencap-csum6 ", f);
547
548 if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
549 fputs("encap-remcsum ", f);
550 else
551 fputs("noencap-remcsum ", f);
552 }
553 }
554
555 if (tb[IFLA_IPTUN_FWMARK]) {
556 __u32 fwmark = rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]);
557
558 if (fwmark) {
559 snprintf(s2, sizeof(s2), "0x%x", fwmark);
560
561 print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
562 }
563 }
564 }
565
566 static void iptunnel_print_help(struct link_util *lu, int argc, char **argv,
567 FILE *f)
568 {
569 print_usage(f, strcmp(lu->id, "sit") == 0);
570 }
571
572 struct link_util ipip_link_util = {
573 .id = "ipip",
574 .maxattr = IFLA_IPTUN_MAX,
575 .parse_opt = iptunnel_parse_opt,
576 .print_opt = iptunnel_print_opt,
577 .print_help = iptunnel_print_help,
578 };
579
580 struct link_util sit_link_util = {
581 .id = "sit",
582 .maxattr = IFLA_IPTUN_MAX,
583 .parse_opt = iptunnel_parse_opt,
584 .print_opt = iptunnel_print_opt,
585 .print_help = iptunnel_print_help,
586 };