2 * Copyright (C)2006 USAGI/WIDE Project
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses>.
18 * split from ip_tunnel.c
22 * Masahide NAKAMURA @USAGI
28 #include <bsd/string.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
35 #include <netinet/in.h>
38 #include <linux/if_tunnel.h>
39 #include <linux/if_arp.h>
43 #include "json_print.h"
45 const char *tnl_strproto(__u8 proto
)
65 int tnl_get_ioctl(const char *basedev
, void *p
)
71 strlcpy(ifr
.ifr_name
, basedev
, IFNAMSIZ
);
72 ifr
.ifr_ifru
.ifru_data
= (void *)p
;
74 fd
= socket(preferred_family
, SOCK_DGRAM
, 0);
76 fprintf(stderr
, "create socket failed: %s\n", strerror(errno
));
80 err
= ioctl(fd
, SIOCGETTUNNEL
, &ifr
);
82 fprintf(stderr
, "get tunnel \"%s\" failed: %s\n", basedev
,
89 int tnl_add_ioctl(int cmd
, const char *basedev
, const char *name
, void *p
)
95 if (cmd
== SIOCCHGTUNNEL
&& name
[0])
96 strlcpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
98 strlcpy(ifr
.ifr_name
, basedev
, IFNAMSIZ
);
99 ifr
.ifr_ifru
.ifru_data
= p
;
101 fd
= socket(preferred_family
, SOCK_DGRAM
, 0);
103 fprintf(stderr
, "create socket failed: %s\n", strerror(errno
));
107 err
= ioctl(fd
, cmd
, &ifr
);
109 fprintf(stderr
, "add tunnel \"%s\" failed: %s\n", ifr
.ifr_name
,
115 int tnl_del_ioctl(const char *basedev
, const char *name
, void *p
)
122 strlcpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
124 strlcpy(ifr
.ifr_name
, basedev
, IFNAMSIZ
);
126 ifr
.ifr_ifru
.ifru_data
= p
;
128 fd
= socket(preferred_family
, SOCK_DGRAM
, 0);
130 fprintf(stderr
, "create socket failed: %s\n", strerror(errno
));
134 err
= ioctl(fd
, SIOCDELTUNNEL
, &ifr
);
136 fprintf(stderr
, "delete tunnel \"%s\" failed: %s\n",
137 ifr
.ifr_name
, strerror(errno
));
142 static int tnl_gen_ioctl(int cmd
, const char *name
,
143 void *p
, int skiperr
)
149 strlcpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
150 ifr
.ifr_ifru
.ifru_data
= p
;
152 fd
= socket(preferred_family
, SOCK_DGRAM
, 0);
154 fprintf(stderr
, "create socket failed: %s\n", strerror(errno
));
158 err
= ioctl(fd
, cmd
, &ifr
);
159 if (err
&& errno
!= skiperr
)
160 fprintf(stderr
, "%s: ioctl %x failed: %s\n", name
,
161 cmd
, strerror(errno
));
166 int tnl_prl_ioctl(int cmd
, const char *name
, void *p
)
168 return tnl_gen_ioctl(cmd
, name
, p
, -1);
171 int tnl_6rd_ioctl(int cmd
, const char *name
, void *p
)
173 return tnl_gen_ioctl(cmd
, name
, p
, -1);
176 int tnl_ioctl_get_6rd(const char *name
, void *p
)
178 return tnl_gen_ioctl(SIOCGET6RD
, name
, p
, EINVAL
);
181 __be32
tnl_parse_key(const char *name
, const char *key
)
185 if (strchr(key
, '.'))
186 return get_addr32(key
);
188 if (get_unsigned(&uval
, key
, 0) < 0) {
190 "invalid value for \"%s\": \"%s\"; it should be an unsigned integer\n",
197 static const char *tnl_encap_str(const char *name
, int enabled
, int port
)
199 static const char ne
[][sizeof("no")] = {
209 } else if (port
< 0) {
212 snprintf(b1
, sizeof(b1
), "%u ", port
- 1);
216 snprintf(buf
, sizeof(buf
), "%sencap-%s %s", ne
[!!enabled
], name
, val
);
220 void tnl_print_encap(struct rtattr
*tb
[],
221 int encap_type
, int encap_flags
,
222 int encap_sport
, int encap_dport
)
224 __u16 type
, flags
, sport
, dport
;
229 type
= rta_getattr_u16(tb
[encap_type
]);
230 if (type
== TUNNEL_ENCAP_NONE
)
233 flags
= rta_getattr_u16(tb
[encap_flags
]);
234 sport
= rta_getattr_u16(tb
[encap_sport
]);
235 dport
= rta_getattr_u16(tb
[encap_dport
]);
237 open_json_object("encap");
238 print_string(PRINT_FP
, NULL
, "encap ", NULL
);
241 case TUNNEL_ENCAP_FOU
:
242 print_string(PRINT_ANY
, "type", "%s ", "fou");
244 case TUNNEL_ENCAP_GUE
:
245 print_string(PRINT_ANY
, "type", "%s ", "gue");
248 print_null(PRINT_ANY
, "type", "%s ", "unknown");
252 if (is_json_context()) {
253 print_uint(PRINT_JSON
, "sport", NULL
, ntohs(sport
));
254 print_uint(PRINT_JSON
, "dport", NULL
, ntohs(dport
));
255 print_bool(PRINT_JSON
, "csum", NULL
,
256 flags
& TUNNEL_ENCAP_FLAG_CSUM
);
257 print_bool(PRINT_JSON
, "csum6", NULL
,
258 flags
& TUNNEL_ENCAP_FLAG_CSUM6
);
259 print_bool(PRINT_JSON
, "remcsum", NULL
,
260 flags
& TUNNEL_ENCAP_FLAG_REMCSUM
);
265 t
= sport
? ntohs(sport
) + 1 : 0;
266 print_string(PRINT_FP
, NULL
, "%s",
267 tnl_encap_str("sport", 1, t
));
269 t
= ntohs(dport
) + 1;
270 print_string(PRINT_FP
, NULL
, "%s",
271 tnl_encap_str("dport", 1, t
));
273 t
= flags
& TUNNEL_ENCAP_FLAG_CSUM
;
274 print_string(PRINT_FP
, NULL
, "%s",
275 tnl_encap_str("csum", t
, -1));
277 t
= flags
& TUNNEL_ENCAP_FLAG_CSUM6
;
278 print_string(PRINT_FP
, NULL
, "%s",
279 tnl_encap_str("csum6", t
, -1));
281 t
= flags
& TUNNEL_ENCAP_FLAG_REMCSUM
;
282 print_string(PRINT_FP
, NULL
, "%s",
283 tnl_encap_str("remcsum", t
, -1));
287 void tnl_print_endpoint(const char *name
, const struct rtattr
*rta
, int family
)
294 } else if (get_addr_rta(&dst
, rta
, family
)) {
296 } else if (dst
.flags
& ADDRTYPE_UNSPEC
) {
299 value
= format_host(family
, dst
.bytelen
, dst
.data
);
304 if (is_json_context()) {
305 print_string(PRINT_JSON
, name
, NULL
, value
);
309 snprintf(b1
, sizeof(b1
), "%s %%s ", name
);
310 print_string(PRINT_FP
, NULL
, b1
, value
);
314 static void tnl_print_stats(const struct rtnl_link_stats64
*s
)
317 printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_
);
318 printf(" %-10lld %-12lld %-6lld %-8lld %-8lld %-8lld%s",
319 s
->rx_packets
, s
->rx_bytes
, s
->rx_errors
, s
->rx_frame_errors
,
320 s
->rx_fifo_errors
, s
->multicast
, _SL_
);
321 printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_
);
322 printf(" %-10lld %-12lld %-6lld %-8lld %-8lld %-6lld",
323 s
->tx_packets
, s
->tx_bytes
, s
->tx_errors
, s
->collisions
,
324 s
->tx_carrier_errors
, s
->tx_dropped
);
327 static int print_nlmsg_tunnel(struct nlmsghdr
*n
, void *arg
)
329 struct tnl_print_nlmsg_info
*info
= arg
;
330 struct ifinfomsg
*ifi
= NLMSG_DATA(n
);
331 struct rtattr
*tb
[IFLA_MAX
+1];
332 const char *name
, *n1
;
334 if (n
->nlmsg_type
!= RTM_NEWLINK
&& n
->nlmsg_type
!= RTM_DELLINK
)
337 if (n
->nlmsg_len
< NLMSG_LENGTH(sizeof(*ifi
)))
340 if (preferred_family
== AF_INET
) {
341 switch (ifi
->ifi_type
) {
350 switch (ifi
->ifi_type
) {
359 parse_rtattr(tb
, IFLA_MAX
, IFLA_RTA(ifi
), IFLA_PAYLOAD(n
));
361 if (!tb
[IFLA_IFNAME
])
364 name
= rta_getattr_str(tb
[IFLA_IFNAME
]);
366 /* Assume p1->name[IFNAMSIZ] is first field of structure */
368 if (n1
[0] && strcmp(n1
, name
))
374 /* TODO: parse netlink attributes */
375 if (tnl_get_ioctl(name
, info
->p2
))
378 if (!info
->match(info
))
381 info
->print(info
->p2
);
383 struct rtnl_link_stats64 s
;
385 if (get_rtnl_link_stats_rta(&s
, tb
) <= 0)
395 int do_tunnels_list(struct tnl_print_nlmsg_info
*info
)
397 if (rtnl_linkdump_req(&rth
, preferred_family
) < 0) {
398 perror("Cannot send dump request\n");
402 if (rtnl_dump_filter(&rth
, print_nlmsg_tunnel
, info
) < 0) {
403 fprintf(stderr
, "Dump terminated\n");