xref: /openbsd-src/usr.sbin/ldpctl/ldpctl.c (revision fb8aa7497fded39583f40e800732f9c046411717)
1 /*	$OpenBSD: ldpctl.c,v 1.31 2016/05/23 19:06:03 renato Exp $
2  *
3  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
4  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <net/if_media.h>
27 #include <net/if_types.h>
28 #include <netmpls/mpls.h>
29 
30 #include <err.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <limits.h>
37 
38 #include "ldp.h"
39 #include "ldpd.h"
40 #include "ldpe.h"
41 #include "log.h"
42 #include "parser.h"
43 
44 __dead void	 usage(void);
45 const char	*fmt_timeframe_core(time_t);
46 const char	*get_linkstate(uint8_t, int);
47 int		 show_interface_msg(struct imsg *, struct parse_result *);
48 int		 show_discovery_msg(struct imsg *, struct parse_result *);
49 uint64_t	 get_ifms_type(uint8_t);
50 int		 show_lib_msg(struct imsg *, struct parse_result *);
51 int		 show_nbr_msg(struct imsg *, struct parse_result *);
52 void		 show_fib_head(void);
53 int		 show_fib_msg(struct imsg *, struct parse_result *);
54 void		 show_interface_head(void);
55 int		 show_fib_interface_msg(struct imsg *);
56 int		 show_l2vpn_pw_msg(struct imsg *);
57 int		 show_l2vpn_binding_msg(struct imsg *);
58 const char	*get_media_descr(uint64_t);
59 void		 print_baudrate(uint64_t);
60 char		*print_label(char **, uint32_t);
61 const char	*print_pw_type(uint16_t);
62 
63 struct imsgbuf	*ibuf;
64 
65 __dead void
66 usage(void)
67 {
68 	extern char *__progname;
69 
70 	fprintf(stderr, "usage: %s command [argument ...]\n", __progname);
71 	exit(1);
72 }
73 
74 int
75 main(int argc, char *argv[])
76 {
77 	struct sockaddr_un	 sun;
78 	struct parse_result	*res;
79 	struct imsg		 imsg;
80 	unsigned int		 ifidx = 0;
81 	struct kroute		 kr;
82 	int			 ctl_sock;
83 	int			 done = 0, verbose = 0;
84 	int			 n;
85 	struct ctl_nbr		 nbr;
86 
87 	/* parse options */
88 	if ((res = parse(argc - 1, argv + 1)) == NULL)
89 		exit(1);
90 
91 	/* connect to ldpd control socket */
92 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
93 		err(1, "socket");
94 
95 	memset(&sun, 0, sizeof(sun));
96 	sun.sun_family = AF_UNIX;
97 	strlcpy(sun.sun_path, LDPD_SOCKET, sizeof(sun.sun_path));
98 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
99 		err(1, "connect: %s", LDPD_SOCKET);
100 
101 	if (pledge("stdio", NULL) == -1)
102 		err(1, "pledge");
103 
104 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
105 		err(1, NULL);
106 	imsg_init(ibuf, ctl_sock);
107 	done = 0;
108 
109 	/* process user request */
110 	switch (res->action) {
111 	case NONE:
112 		usage();
113 		/* not reached */
114 	case SHOW:
115 	case SHOW_IFACE:
116 		printf("%-4s %-11s %-6s %-10s %-8s %-12s %3s\n",
117 		    "AF", "Interface", "State", "Linkstate", "Uptime",
118 		    "Hello Timers", "ac");
119 		if (*res->ifname) {
120 			ifidx = if_nametoindex(res->ifname);
121 			if (ifidx == 0)
122 				errx(1, "no such interface %s", res->ifname);
123 		}
124 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
125 		    &ifidx, sizeof(ifidx));
126 		break;
127 	case SHOW_DISC:
128 		printf("%-4s %-15s %-8s %-15s %9s\n",
129 		    "AF", "ID", "Type", "Source", "Holdtime");
130 		imsg_compose(ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1,
131 		    NULL, 0);
132 		break;
133 	case SHOW_NBR:
134 		printf("%-4s %-15s %-11s %-15s %8s\n",
135 		    "AF", "ID", "State", "Remote Address", "Uptime");
136 		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
137 		break;
138 	case SHOW_LIB:
139 		printf("%-4s %-20s %-15s %-11s %-13s %6s\n", "AF",
140 		    "Destination", "Nexthop", "Local Label", "Remote Label",
141 		    "In Use");
142 		imsg_compose(ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0);
143 		break;
144 	case SHOW_FIB:
145 		if (!ldp_addrisset(res->family, &res->addr))
146 			imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
147 			    &res->flags, sizeof(res->flags));
148 		else {
149 			memset(&kr, 0, sizeof(kr));
150 			kr.af = res->family;
151 			kr.prefix = res->addr;
152 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
153 			    &kr, sizeof(kr));
154 		}
155 		show_fib_head();
156 		break;
157 	case SHOW_FIB_IFACE:
158 		if (*res->ifname)
159 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1,
160 			    res->ifname, sizeof(res->ifname));
161 		else
162 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0);
163 		show_interface_head();
164 		break;
165 	case SHOW_L2VPN_PW:
166 		printf("%-11s %-15s %-14s %-10s\n",
167 		    "Interface", "Neighbor", "PWID", "Status");
168 		imsg_compose(ibuf, IMSG_CTL_SHOW_L2VPN_PW, 0, 0, -1, NULL, 0);
169 		break;
170 	case SHOW_L2VPN_BINDING:
171 		imsg_compose(ibuf, IMSG_CTL_SHOW_L2VPN_BINDING, 0, 0, -1,
172 		    NULL, 0);
173 		break;
174 	case CLEAR_NBR:
175 		memset(&nbr, 0, sizeof(nbr));
176 		nbr.af = res->family;
177 		memcpy(&nbr.raddr, &res->addr, sizeof(nbr.raddr));
178 		imsg_compose(ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr,
179 		    sizeof(nbr));
180 		done = 1;
181 		break;
182 	case FIB:
183 		errx(1, "fib couple|decouple");
184 		break;
185 	case FIB_COUPLE:
186 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
187 		printf("couple request sent.\n");
188 		done = 1;
189 		break;
190 	case FIB_DECOUPLE:
191 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
192 		printf("decouple request sent.\n");
193 		done = 1;
194 		break;
195 	case LOG_VERBOSE:
196 		verbose = 1;
197 		/* FALLTHROUGH */
198 	case LOG_BRIEF:
199 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
200 		    &verbose, sizeof(verbose));
201 		printf("logging request sent.\n");
202 		done = 1;
203 		break;
204 	case RELOAD:
205 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
206 		printf("reload request sent.\n");
207 		done = 1;
208 		break;
209 	}
210 
211 	while (ibuf->w.queued)
212 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
213 			err(1, "write error");
214 
215 	while (!done) {
216 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
217 			errx(1, "imsg_read error");
218 		if (n == 0)
219 			errx(1, "pipe closed");
220 
221 		while (!done) {
222 			if ((n = imsg_get(ibuf, &imsg)) == -1)
223 				errx(1, "imsg_get error");
224 			if (n == 0)
225 				break;
226 			switch (res->action) {
227 			case SHOW:
228 			case SHOW_IFACE:
229 				done = show_interface_msg(&imsg, res);
230 				break;
231 			case SHOW_DISC:
232 				done = show_discovery_msg(&imsg, res);
233 				break;
234 			case SHOW_NBR:
235 				done = show_nbr_msg(&imsg, res);
236 				break;
237 			case SHOW_LIB:
238 				done = show_lib_msg(&imsg, res);
239 				break;
240 			case SHOW_FIB:
241 				done = show_fib_msg(&imsg, res);
242 				break;
243 			case SHOW_FIB_IFACE:
244 				done = show_fib_interface_msg(&imsg);
245 				break;
246 			case SHOW_L2VPN_PW:
247 				done = show_l2vpn_pw_msg(&imsg);
248 				break;
249 			case SHOW_L2VPN_BINDING:
250 				done = show_l2vpn_binding_msg(&imsg);
251 				break;
252 			case NONE:
253 			case CLEAR_NBR:
254 			case FIB:
255 			case FIB_COUPLE:
256 			case FIB_DECOUPLE:
257 			case LOG_VERBOSE:
258 			case LOG_BRIEF:
259 			case RELOAD:
260 				break;
261 			}
262 			imsg_free(&imsg);
263 		}
264 	}
265 	close(ctl_sock);
266 	free(ibuf);
267 
268 	return (0);
269 }
270 
271 uint64_t
272 get_ifms_type(uint8_t if_type)
273 {
274 	switch (if_type) {
275 	case IFT_ETHER:
276 		return (IFM_ETHER);
277 		break;
278 	case IFT_FDDI:
279 		return (IFM_FDDI);
280 		break;
281 	case IFT_CARP:
282 		return (IFM_CARP);
283 		break;
284 	default:
285 		return (0);
286 		break;
287 	}
288 }
289 
290 #define	TF_BUFS	8
291 #define	TF_LEN	9
292 
293 const char *
294 fmt_timeframe_core(time_t t)
295 {
296 	char		*buf;
297 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
298 	static int	 idx = 0;
299 	unsigned int	 sec, min, hrs, day, week;
300 
301 	if (t == 0)
302 		return ("Stopped");
303 
304 	buf = tfbuf[idx++];
305 	if (idx == TF_BUFS)
306 		idx = 0;
307 
308 	week = t;
309 
310 	sec = week % 60;
311 	week /= 60;
312 	min = week % 60;
313 	week /= 60;
314 	hrs = week % 24;
315 	week /= 24;
316 	day = week % 7;
317 	week /= 7;
318 
319 	if (week > 0)
320 		snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
321 	else if (day > 0)
322 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
323 	else
324 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
325 
326 	return (buf);
327 }
328 
329 int
330 show_interface_msg(struct imsg *imsg, struct parse_result *res)
331 {
332 	struct ctl_iface	*iface;
333 	char			*timers;
334 
335 	switch (imsg->hdr.type) {
336 	case IMSG_CTL_SHOW_INTERFACE:
337 		iface = imsg->data;
338 
339 		if (res->family != AF_UNSPEC && res->family != iface->af)
340 			break;
341 
342 		if (asprintf(&timers, "%u/%u", iface->hello_interval,
343 		    iface->hello_holdtime) == -1)
344 			err(1, NULL);
345 
346 		printf("%-4s %-11s %-6s %-10s %-8s %-12s %3u\n",
347 		    af_name(iface->af), iface->name,
348 		    if_state_name(iface->state), get_linkstate(iface->if_type,
349 		    iface->linkstate), iface->uptime == 0 ? "00:00:00" :
350 		    fmt_timeframe_core(iface->uptime), timers, iface->adj_cnt);
351 		free(timers);
352 		break;
353 	case IMSG_CTL_END:
354 		printf("\n");
355 		return (1);
356 	default:
357 		break;
358 	}
359 
360 	return (0);
361 }
362 
363 int
364 show_discovery_msg(struct imsg *imsg, struct parse_result *res)
365 {
366 	struct ctl_adj	*adj;
367 	const char	*addr;
368 
369 	switch (imsg->hdr.type) {
370 	case IMSG_CTL_SHOW_DISCOVERY:
371 		adj = imsg->data;
372 
373 		if (res->family != AF_UNSPEC && res->family != adj->af)
374 			break;
375 
376 		printf("%-4s %-15s ", af_name(adj->af), inet_ntoa(adj->id));
377 		switch(adj->type) {
378 		case HELLO_LINK:
379 			printf("%-8s %-15s ", "Link", adj->ifname);
380 			break;
381 		case HELLO_TARGETED:
382 			addr = log_addr(adj->af, &adj->src_addr);
383 
384 			printf("%-8s %-15s ", "Targeted", addr);
385 			if (strlen(addr) > 15)
386 				printf("\n%46s", " ");
387 			break;
388 		}
389 		printf("%9u\n", adj->holdtime);
390 		break;
391 	case IMSG_CTL_END:
392 		printf("\n");
393 		return (1);
394 	default:
395 		break;
396 	}
397 
398 	return (0);
399 }
400 
401 int
402 show_lib_msg(struct imsg *imsg, struct parse_result *res)
403 {
404 	struct ctl_rt	*rt;
405 	char		*dstnet, *local = NULL, *remote = NULL;
406 
407 	switch (imsg->hdr.type) {
408 	case IMSG_CTL_SHOW_LIB:
409 		rt = imsg->data;
410 
411 		if (res->family != AF_UNSPEC && res->family != rt->af)
412 			break;
413 
414 		if (asprintf(&dstnet, "%s/%d", log_addr(rt->af, &rt->prefix),
415 		    rt->prefixlen) == -1)
416 			err(1, NULL);
417 
418 		printf("%-4s %-20s", af_name(rt->af), dstnet);
419 		if (strlen(dstnet) > 20)
420 			printf("\n%25s", " ");
421 		printf(" %-15s %-11s %-13s %6s\n", inet_ntoa(rt->nexthop),
422 		    print_label(&local, rt->local_label),
423 		    print_label(&remote, rt->remote_label),
424 		    rt->in_use ? "yes" : "no");
425 
426 		free(remote);
427 		free(local);
428 		free(dstnet);
429 		break;
430 	case IMSG_CTL_END:
431 		printf("\n");
432 		return (1);
433 	default:
434 		break;
435 	}
436 
437 	return (0);
438 }
439 
440 int
441 show_nbr_msg(struct imsg *imsg, struct parse_result *res)
442 {
443 	struct ctl_nbr	*nbr;
444 	const char	*addr;
445 
446 	switch (imsg->hdr.type) {
447 	case IMSG_CTL_SHOW_NBR:
448 		nbr = imsg->data;
449 
450 		if (res->family != AF_UNSPEC && res->family != nbr->af)
451 			break;
452 
453 		addr = log_addr(nbr->af, &nbr->raddr);
454 
455 		printf("%-4s %-15s %-11s %-15s",
456 		    af_name(nbr->af), inet_ntoa(nbr->id),
457 		    nbr_state_name(nbr->nbr_state), addr);
458 		if (strlen(addr) > 15)
459 			printf("\n%48s", " ");
460 		printf(" %8s\n", nbr->uptime == 0 ? "-" :
461 		    fmt_timeframe_core(nbr->uptime));
462 		break;
463 	case IMSG_CTL_END:
464 		printf("\n");
465 		return (1);
466 	default:
467 		break;
468 	}
469 
470 	return (0);
471 }
472 
473 void
474 show_fib_head(void)
475 {
476 	printf("Flags: C = Connected, S = Static\n");
477 	printf(" %-4s %-20s %-17s %-17s %s\n", "Prio", "Destination",
478 	    "Nexthop", "Local Label", "Remote Label");
479 }
480 
481 int
482 show_fib_msg(struct imsg *imsg, struct parse_result *res)
483 {
484 	struct kroute	*k;
485 	char		*p;
486 	char		*local = NULL, *remote = NULL;
487 	const char	*nexthop;
488 
489 	switch (imsg->hdr.type) {
490 	case IMSG_CTL_KROUTE:
491 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
492 			errx(1, "wrong imsg len");
493 		k = imsg->data;
494 
495 		if (res->family != AF_UNSPEC && res->family != k->af)
496 			break;
497 
498 		if (k->flags & F_CONNECTED)
499 			printf("C");
500 		else if (k->flags & F_STATIC)
501 			printf("S");
502 		else
503 			printf(" ");
504 
505 		printf(" %3d ", k->priority);
506 		if (asprintf(&p, "%s/%u", log_addr(k->af, &k->prefix),
507 		    k->prefixlen) == -1)
508 			err(1, NULL);
509 		printf("%-20s ", p);
510 		if (strlen(p) > 20)
511 			printf("\n%27s", " ");
512 		free(p);
513 
514 		if (ldp_addrisset(k->af, &k->nexthop)) {
515 			switch (k->af) {
516 			case AF_INET:
517 				printf("%-18s", inet_ntoa(k->nexthop.v4));
518 				break;
519 			case AF_INET6:
520 				nexthop = log_in6addr_scope(&k->nexthop.v6,
521 				    k->ifindex);
522 				printf("%-18s", nexthop);
523 				if (strlen(nexthop) > 18)
524 					printf("\n%45s", " ");
525 				break;
526 			default:
527 				printf("%-18s", " ");
528 				break;
529 			}
530 		} else if (k->flags & F_CONNECTED)
531 			printf("link#%-13u", k->ifindex);
532 
533 		printf("%-18s", print_label(&local, k->local_label));
534 		printf("%s", print_label(&local, k->remote_label));
535 		printf("\n");
536 
537 		free(remote);
538 		free(local);
539 		break;
540 	case IMSG_CTL_END:
541 		printf("\n");
542 		return (1);
543 	default:
544 		break;
545 	}
546 
547 	return (0);
548 }
549 
550 void
551 show_interface_head(void)
552 {
553 	printf("%-15s%-15s%s\n", "Interface", "Flags",
554 	    "Link state");
555 }
556 
557 int
558 show_fib_interface_msg(struct imsg *imsg)
559 {
560 	struct kif	*k;
561 	uint64_t	 ifms_type;
562 
563 	switch (imsg->hdr.type) {
564 	case IMSG_CTL_IFINFO:
565 		k = imsg->data;
566 		printf("%-15s", k->ifname);
567 		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
568 		ifms_type = get_ifms_type(k->if_type);
569 		if (ifms_type)
570 			printf("%s, ", get_media_descr(ifms_type));
571 
572 		printf("%s", get_linkstate(k->if_type, k->link_state));
573 
574 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
575 			printf(", ");
576 			print_baudrate(k->baudrate);
577 		}
578 		printf("\n");
579 		break;
580 	case IMSG_CTL_END:
581 		printf("\n");
582 		return (1);
583 	default:
584 		break;
585 	}
586 
587 	return (0);
588 }
589 
590 int
591 show_l2vpn_pw_msg(struct imsg *imsg)
592 {
593 	struct ctl_pw	*pw;
594 
595 	switch (imsg->hdr.type) {
596 	case IMSG_CTL_SHOW_L2VPN_PW:
597 		pw = imsg->data;
598 
599 		printf("%-11s %-15s %-14u %-10s\n", pw->ifname,
600 		    inet_ntoa(pw->lsr_id), pw->pwid,
601 		    (pw->status ? "UP" : "DOWN"));
602 		break;
603 	case IMSG_CTL_END:
604 		printf("\n");
605 		return (1);
606 	default:
607 		break;
608 	}
609 
610 	return (0);
611 }
612 
613 int
614 show_l2vpn_binding_msg(struct imsg *imsg)
615 {
616 	struct ctl_pw	*pw;
617 
618 	switch (imsg->hdr.type) {
619 	case IMSG_CTL_SHOW_L2VPN_BINDING:
620 		pw = imsg->data;
621 
622 		printf("Neighbor: %s - PWID: %u (%s)\n",
623 		    inet_ntoa(pw->lsr_id), pw->pwid,
624 		    print_pw_type(pw->type));
625 		printf("%-12s%-15s%-15s%-10s\n", "", "Label", "Group-ID",
626 		    "MTU");
627 		if (pw->local_label != NO_LABEL)
628 			printf("  %-10s%-15u%-15u%u\n", "Local",
629 			    pw->local_label, pw->local_gid, pw->local_ifmtu);
630 		else
631 			printf("  %-10s%-15s%-15s%s\n", "Local", "-",
632 			    "-", "-");
633 		if (pw->remote_label != NO_LABEL)
634 			printf("  %-10s%-15u%-15u%u\n", "Remote",
635 			    pw->remote_label, pw->remote_gid,
636 			    pw->remote_ifmtu);
637 		else
638 			printf("  %-10s%-15s%-15s%s\n", "Remote", "-",
639 			    "-", "-");
640 		break;
641 	case IMSG_CTL_END:
642 		printf("\n");
643 		return (1);
644 	default:
645 		break;
646 	}
647 
648 	return (0);
649 }
650 
651 const struct if_status_description
652 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
653 const struct ifmedia_description
654 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
655 
656 const char *
657 get_media_descr(uint64_t media_type)
658 {
659 	const struct ifmedia_description	*p;
660 
661 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
662 		if (media_type == p->ifmt_word)
663 			return (p->ifmt_string);
664 
665 	return ("unknown");
666 }
667 
668 const char *
669 get_linkstate(uint8_t if_type, int link_state)
670 {
671 	const struct if_status_description *p;
672 	static char buf[8];
673 
674 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
675 		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
676 			return (p->ifs_string);
677 	}
678 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
679 	return (buf);
680 }
681 
682 void
683 print_baudrate(uint64_t baudrate)
684 {
685 	if (baudrate > IF_Gbps(1))
686 		printf("%llu GBit/s", baudrate / IF_Gbps(1));
687 	else if (baudrate > IF_Mbps(1))
688 		printf("%llu MBit/s", baudrate / IF_Mbps(1));
689 	else if (baudrate > IF_Kbps(1))
690 		printf("%llu KBit/s", baudrate / IF_Kbps(1));
691 	else
692 		printf("%llu Bit/s", baudrate);
693 }
694 
695 char *
696 print_label(char **string, uint32_t label)
697 {
698 	if (label == NO_LABEL) {
699 		if (asprintf(string, "-") == -1)
700 			err(1, NULL);
701 	} else if (label == MPLS_LABEL_IMPLNULL) {
702 		if (asprintf(string, "imp-null") == -1)
703 			err(1, NULL);
704 	} else if (label == MPLS_LABEL_IPV4NULL ||
705 	    label == MPLS_LABEL_IPV6NULL) {
706 		if (asprintf(string, "exp-null") == -1)
707 			err(1, NULL);
708 	} else {
709 		if (asprintf(string, "%u", label) == -1)
710 			err(1, NULL);
711 	}
712 
713 	return (*string);
714 }
715 
716 const char *
717 print_pw_type(uint16_t pw_type)
718 {
719 	static char buf[64];
720 
721 	switch (pw_type) {
722 	case PW_TYPE_ETHERNET_TAGGED:
723 		return ("Eth Tagged");
724 	case PW_TYPE_ETHERNET:
725 		return ("Ethernet");
726 	default:
727 		snprintf(buf, sizeof(buf), "[%0x]", pw_type);
728 		return (buf);
729 	}
730 }
731