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
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/ioctl.h>
32 #include <netinet/in.h>
35 #include <linux/if_tunnel.h>
36 #include <linux/if_arp.h>
40 #include "json_print.h"
42 const char *tnl_strproto(__u8 proto
)
62 int tnl_get_ioctl(const char *basedev
, void *p
)
68 strlcpy(ifr
.ifr_name
, basedev
, IFNAMSIZ
);
69 ifr
.ifr_ifru
.ifru_data
= (void *)p
;
71 fd
= socket(preferred_family
, SOCK_DGRAM
, 0);
73 fprintf(stderr
, "create socket failed: %s\n", strerror(errno
));
77 err
= ioctl(fd
, SIOCGETTUNNEL
, &ifr
);
79 fprintf(stderr
, "get tunnel \"%s\" failed: %s\n", basedev
,
86 int tnl_add_ioctl(int cmd
, const char *basedev
, const char *name
, void *p
)
92 if (cmd
== SIOCCHGTUNNEL
&& name
[0])
93 strlcpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
95 strlcpy(ifr
.ifr_name
, basedev
, IFNAMSIZ
);
96 ifr
.ifr_ifru
.ifru_data
= p
;
98 fd
= socket(preferred_family
, SOCK_DGRAM
, 0);
100 fprintf(stderr
, "create socket failed: %s\n", strerror(errno
));
104 err
= ioctl(fd
, cmd
, &ifr
);
106 fprintf(stderr
, "add tunnel \"%s\" failed: %s\n", ifr
.ifr_name
,
112 int tnl_del_ioctl(const char *basedev
, const char *name
, void *p
)
119 strlcpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
121 strlcpy(ifr
.ifr_name
, basedev
, IFNAMSIZ
);
123 ifr
.ifr_ifru
.ifru_data
= p
;
125 fd
= socket(preferred_family
, SOCK_DGRAM
, 0);
127 fprintf(stderr
, "create socket failed: %s\n", strerror(errno
));
131 err
= ioctl(fd
, SIOCDELTUNNEL
, &ifr
);
133 fprintf(stderr
, "delete tunnel \"%s\" failed: %s\n",
134 ifr
.ifr_name
, strerror(errno
));
139 static int tnl_gen_ioctl(int cmd
, const char *name
,
140 void *p
, int skiperr
)
146 strlcpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
147 ifr
.ifr_ifru
.ifru_data
= p
;
149 fd
= socket(preferred_family
, SOCK_DGRAM
, 0);
151 fprintf(stderr
, "create socket failed: %s\n", strerror(errno
));
155 err
= ioctl(fd
, cmd
, &ifr
);
156 if (err
&& errno
!= skiperr
)
157 fprintf(stderr
, "%s: ioctl %x failed: %s\n", name
,
158 cmd
, strerror(errno
));
163 int tnl_prl_ioctl(int cmd
, const char *name
, void *p
)
165 return tnl_gen_ioctl(cmd
, name
, p
, -1);
168 int tnl_6rd_ioctl(int cmd
, const char *name
, void *p
)
170 return tnl_gen_ioctl(cmd
, name
, p
, -1);
173 int tnl_ioctl_get_6rd(const char *name
, void *p
)
175 return tnl_gen_ioctl(SIOCGET6RD
, name
, p
, EINVAL
);
178 __be32
tnl_parse_key(const char *name
, const char *key
)
182 if (strchr(key
, '.'))
183 return get_addr32(key
);
185 if (get_unsigned(&uval
, key
, 0) < 0) {
187 "invalid value for \"%s\": \"%s\"; it should be an unsigned integer\n",
194 static const char *tnl_encap_str(const char *name
, int enabled
, int port
)
196 static const char ne
[][sizeof("no")] = {
206 } else if (port
< 0) {
209 snprintf(b1
, sizeof(b1
), "%u ", port
- 1);
213 snprintf(buf
, sizeof(buf
), "%sencap-%s %s", ne
[!!enabled
], name
, val
);
217 void tnl_print_encap(struct rtattr
*tb
[],
218 int encap_type
, int encap_flags
,
219 int encap_sport
, int encap_dport
)
221 __u16 type
, flags
, sport
, dport
;
226 type
= rta_getattr_u16(tb
[encap_type
]);
227 if (type
== TUNNEL_ENCAP_NONE
)
230 flags
= rta_getattr_u16(tb
[encap_flags
]);
231 sport
= rta_getattr_u16(tb
[encap_sport
]);
232 dport
= rta_getattr_u16(tb
[encap_dport
]);
234 open_json_object("encap");
235 print_string(PRINT_FP
, NULL
, "encap ", NULL
);
238 case TUNNEL_ENCAP_FOU
:
239 print_string(PRINT_ANY
, "type", "%s ", "fou");
241 case TUNNEL_ENCAP_GUE
:
242 print_string(PRINT_ANY
, "type", "%s ", "gue");
245 print_null(PRINT_ANY
, "type", "%s ", "unknown");
249 if (is_json_context()) {
250 print_uint(PRINT_JSON
, "sport", NULL
, ntohs(sport
));
251 print_uint(PRINT_JSON
, "dport", NULL
, ntohs(dport
));
252 print_bool(PRINT_JSON
, "csum", NULL
,
253 flags
& TUNNEL_ENCAP_FLAG_CSUM
);
254 print_bool(PRINT_JSON
, "csum6", NULL
,
255 flags
& TUNNEL_ENCAP_FLAG_CSUM6
);
256 print_bool(PRINT_JSON
, "remcsum", NULL
,
257 flags
& TUNNEL_ENCAP_FLAG_REMCSUM
);
262 t
= sport
? ntohs(sport
) + 1 : 0;
263 print_string(PRINT_FP
, NULL
, "%s",
264 tnl_encap_str("sport", 1, t
));
266 t
= ntohs(dport
) + 1;
267 print_string(PRINT_FP
, NULL
, "%s",
268 tnl_encap_str("dport", 1, t
));
270 t
= flags
& TUNNEL_ENCAP_FLAG_CSUM
;
271 print_string(PRINT_FP
, NULL
, "%s",
272 tnl_encap_str("csum", t
, -1));
274 t
= flags
& TUNNEL_ENCAP_FLAG_CSUM6
;
275 print_string(PRINT_FP
, NULL
, "%s",
276 tnl_encap_str("csum6", t
, -1));
278 t
= flags
& TUNNEL_ENCAP_FLAG_REMCSUM
;
279 print_string(PRINT_FP
, NULL
, "%s",
280 tnl_encap_str("remcsum", t
, -1));
284 void tnl_print_endpoint(const char *name
, const struct rtattr
*rta
, int family
)
291 } else if (get_addr_rta(&dst
, rta
, family
)) {
293 } else if (dst
.flags
& ADDRTYPE_UNSPEC
) {
296 value
= format_host(family
, dst
.bytelen
, dst
.data
);
301 if (is_json_context()) {
302 print_string(PRINT_JSON
, name
, NULL
, value
);
306 snprintf(b1
, sizeof(b1
), "%s %%s ", name
);
307 print_string(PRINT_FP
, NULL
, b1
, value
);
311 static void tnl_print_stats(const struct rtnl_link_stats64
*s
)
314 printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_
);
315 printf(" %-10lld %-12lld %-6lld %-8lld %-8lld %-8lld%s",
316 s
->rx_packets
, s
->rx_bytes
, s
->rx_errors
, s
->rx_frame_errors
,
317 s
->rx_fifo_errors
, s
->multicast
, _SL_
);
318 printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_
);
319 printf(" %-10lld %-12lld %-6lld %-8lld %-8lld %-6lld",
320 s
->tx_packets
, s
->tx_bytes
, s
->tx_errors
, s
->collisions
,
321 s
->tx_carrier_errors
, s
->tx_dropped
);
324 static int print_nlmsg_tunnel(const struct sockaddr_nl
*who
,
325 struct nlmsghdr
*n
, void *arg
)
327 struct tnl_print_nlmsg_info
*info
= arg
;
328 struct ifinfomsg
*ifi
= NLMSG_DATA(n
);
329 struct rtattr
*tb
[IFLA_MAX
+1];
330 const char *name
, *n1
;
332 if (n
->nlmsg_type
!= RTM_NEWLINK
&& n
->nlmsg_type
!= RTM_DELLINK
)
335 if (n
->nlmsg_len
< NLMSG_LENGTH(sizeof(*ifi
)))
338 if (preferred_family
== AF_INET
) {
339 switch (ifi
->ifi_type
) {
348 switch (ifi
->ifi_type
) {
357 parse_rtattr(tb
, IFLA_MAX
, IFLA_RTA(ifi
), IFLA_PAYLOAD(n
));
359 if (!tb
[IFLA_IFNAME
])
362 name
= rta_getattr_str(tb
[IFLA_IFNAME
]);
364 /* Assume p1->name[IFNAMSIZ] is first field of structure */
366 if (n1
[0] && strcmp(n1
, name
))
372 /* TODO: parse netlink attributes */
373 if (tnl_get_ioctl(name
, info
->p2
))
376 if (!info
->match(info
))
379 info
->print(info
->p2
);
381 struct rtnl_link_stats64 s
;
383 if (get_rtnl_link_stats_rta(&s
, tb
) <= 0)
393 int do_tunnels_list(struct tnl_print_nlmsg_info
*info
)
395 if (rtnl_wilddump_request(&rth
, preferred_family
, RTM_GETLINK
) < 0) {
396 perror("Cannot send dump request\n");
400 if (rtnl_dump_filter(&rth
, print_nlmsg_tunnel
, info
) < 0) {
401 fprintf(stderr
, "Dump terminated\n");