]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/ldp_vty_exec.c
ldpd: adapt the code for Quagga
[mirror_frr.git] / ldpd / ldp_vty_exec.c
CommitLineData
eac6e3f0
RW
1/*
2 * Copyright (C) 2016 by Open Source Routing.
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23#include <sys/un.h>
24
25#include "ldpd.h"
26#include "ldpe.h"
27#include "lde.h"
28#include "log.h"
29#include "ldp_vty.h"
30
31#include "command.h"
32#include "vty.h"
33#include "mpls.h"
34
35enum show_command {
36 SHOW_DISC,
37 SHOW_IFACE,
38 SHOW_NBR,
39 SHOW_LIB,
40 SHOW_L2VPN_PW,
41 SHOW_L2VPN_BINDING
42};
43
44struct show_filter {
45 int family;
46 union ldpd_addr addr;
47 uint8_t prefixlen;
48};
49
50#define LDPBUFSIZ 65535
51
52static int show_interface_msg(struct vty *, struct imsg *,
53 struct show_filter *);
54static void show_discovery_adj(struct vty *, char *,
55 struct ctl_adj *);
56static int show_discovery_msg(struct vty *, struct imsg *,
57 struct show_filter *);
58static void show_nbr_adj(struct vty *, char *, struct ctl_adj *);
59static int show_nbr_msg(struct vty *, struct imsg *,
60 struct show_filter *);
61static int show_lib_msg(struct vty *, struct imsg *,
62 struct show_filter *);
63static int show_l2vpn_binding_msg(struct vty *, struct imsg *);
64static int show_l2vpn_pw_msg(struct vty *, struct imsg *);
65static int ldp_vty_connect(struct imsgbuf *);
66static int ldp_vty_dispatch(struct vty *, struct imsgbuf *,
67 enum show_command, struct show_filter *);
68static int ldp_vty_get_af(const char *, int *);
69
70static int
71show_interface_msg(struct vty *vty, struct imsg *imsg,
72 struct show_filter *filter)
73{
74 struct ctl_iface *iface;
75 char timers[BUFSIZ];
76
77 switch (imsg->hdr.type) {
78 case IMSG_CTL_SHOW_INTERFACE:
79 iface = imsg->data;
80
81 if (filter->family != AF_UNSPEC && filter->family != iface->af)
82 break;
83
84 snprintf(timers, sizeof(timers), "%u/%u",
85 iface->hello_interval, iface->hello_holdtime);
86
87 vty_out(vty, "%-4s %-11s %-6s %-8s %-12s %3u%s",
88 af_name(iface->af), iface->name,
89 if_state_name(iface->state), iface->uptime == 0 ?
90 "00:00:00" : log_time(iface->uptime), timers,
91 iface->adj_cnt, VTY_NEWLINE);
92 break;
93 case IMSG_CTL_END:
94 vty_out(vty, "%s", VTY_NEWLINE);
95 return (1);
96 default:
97 break;
98 }
99
100 return (0);
101}
102
103static void
104show_discovery_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
105{
106 size_t buflen = strlen(buffer);
107
108 snprintf(buffer + buflen, LDPBUFSIZ - buflen,
109 " LDP Id: %s:0, Transport address: %s%s",
110 inet_ntoa(adj->id), log_addr(adj->af,
111 &adj->trans_addr), VTY_NEWLINE);
112 buflen = strlen(buffer);
113 snprintf(buffer + buflen, LDPBUFSIZ - buflen,
114 " Hold time: %u sec%s", adj->holdtime, VTY_NEWLINE);
115}
116
117static int
118show_discovery_msg(struct vty *vty, struct imsg *imsg,
119 struct show_filter *filter)
120{
121 struct ctl_adj *adj;
122 struct ctl_disc_if *iface;
123 struct ctl_disc_tnbr *tnbr;
124 struct in_addr rtr_id;
125 union ldpd_addr *trans_addr;
126 size_t buflen;
127 static char ifaces_buffer[LDPBUFSIZ];
128 static char tnbrs_buffer[LDPBUFSIZ];
129
130 switch (imsg->hdr.type) {
131 case IMSG_CTL_SHOW_DISCOVERY:
132 ifaces_buffer[0] = '\0';
133 tnbrs_buffer[0] = '\0';
134 break;
135 case IMSG_CTL_SHOW_DISC_IFACE:
136 iface = imsg->data;
137
138 if (filter->family != AF_UNSPEC &&
139 ((filter->family == AF_INET && !iface->active_v4) ||
140 (filter->family == AF_INET6 && !iface->active_v6)))
141 break;
142
143 buflen = strlen(ifaces_buffer);
144 snprintf(ifaces_buffer + buflen, LDPBUFSIZ - buflen,
145 " %s: %s%s", iface->name, (iface->no_adj) ?
146 "xmit" : "xmit/recv", VTY_NEWLINE);
147 break;
148 case IMSG_CTL_SHOW_DISC_TNBR:
149 tnbr = imsg->data;
150
151 if (filter->family != AF_UNSPEC && filter->family != tnbr->af)
152 break;
153
154 trans_addr = &(ldp_af_conf_get(ldpd_conf,
155 tnbr->af))->trans_addr;
156 buflen = strlen(tnbrs_buffer);
157 snprintf(tnbrs_buffer + buflen, LDPBUFSIZ - buflen,
158 " %s -> %s: %s%s", log_addr(tnbr->af, trans_addr),
159 log_addr(tnbr->af, &tnbr->addr), (tnbr->no_adj) ? "xmit" :
160 "xmit/recv", VTY_NEWLINE);
161 break;
162 case IMSG_CTL_SHOW_DISC_ADJ:
163 adj = imsg->data;
164
165 if (filter->family != AF_UNSPEC && filter->family != adj->af)
166 break;
167
168 switch(adj->type) {
169 case HELLO_LINK:
170 show_discovery_adj(vty, ifaces_buffer, adj);
171 break;
172 case HELLO_TARGETED:
173 show_discovery_adj(vty, tnbrs_buffer, adj);
174 break;
175 }
176 break;
177 case IMSG_CTL_END:
178 rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf);
179 vty_out(vty, "Local LDP Identifier: %s:0%s", inet_ntoa(rtr_id),
180 VTY_NEWLINE);
181 vty_out(vty, "Discovery Sources:%s", VTY_NEWLINE);
182 vty_out(vty, " Interfaces:%s", VTY_NEWLINE);
183 vty_out(vty, "%s", ifaces_buffer);
184 vty_out(vty, " Targeted Hellos:%s", VTY_NEWLINE);
185 vty_out(vty, "%s", tnbrs_buffer);
186 vty_out(vty, "%s", VTY_NEWLINE);
187 return (1);
188 default:
189 break;
190 }
191
192 return (0);
193}
194
195static void
196show_nbr_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
197{
198 size_t buflen = strlen(buffer);
199
200 switch (adj->type) {
201 case HELLO_LINK:
202 snprintf(buffer + buflen, LDPBUFSIZ - buflen,
203 " Interface: %s%s", adj->ifname, VTY_NEWLINE);
204 break;
205 case HELLO_TARGETED:
206 snprintf(buffer + buflen, LDPBUFSIZ - buflen,
207 " Targeted Hello: %s%s", log_addr(adj->af,
208 &adj->src_addr), VTY_NEWLINE);
209 break;
210 }
211}
212
213static int
214show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_filter *filter)
215{
216 struct ctl_adj *adj;
217 struct ctl_nbr *nbr;
218 static char v4adjs_buffer[LDPBUFSIZ];
219 static char v6adjs_buffer[LDPBUFSIZ];
220
221 switch (imsg->hdr.type) {
222 case IMSG_CTL_SHOW_NBR:
223 nbr = imsg->data;
224
225 v4adjs_buffer[0] = '\0';
226 v6adjs_buffer[0] = '\0';
227 vty_out(vty, "Peer LDP Identifier: %s:0%s", inet_ntoa(nbr->id),
228 VTY_NEWLINE);
229 vty_out(vty, " TCP connection: %s:%u - %s:%u%s",
230 log_addr(nbr->af, &nbr->laddr), ntohs(nbr->lport),
231 log_addr(nbr->af, &nbr->raddr), ntohs(nbr->rport),
232 VTY_NEWLINE);
233 vty_out(vty, " Session Holdtime: %u sec%s", nbr->holdtime,
234 VTY_NEWLINE);
235 vty_out(vty, " State: %s; Downstream-Unsolicited%s",
236 nbr_state_name(nbr->nbr_state), VTY_NEWLINE);
237 vty_out(vty, " Up time: %s%s", log_time(nbr->uptime),
238 VTY_NEWLINE);
239 break;
240 case IMSG_CTL_SHOW_NBR_DISC:
241 adj = imsg->data;
242
243 switch (adj->af) {
244 case AF_INET:
245 show_nbr_adj(vty, v4adjs_buffer, adj);
246 break;
247 case AF_INET6:
248 show_nbr_adj(vty, v6adjs_buffer, adj);
249 break;
250 default:
251 fatalx("show_nbr_msg: unknown af");
252 }
253 break;
254 case IMSG_CTL_SHOW_NBR_END:
255 vty_out(vty, " LDP Discovery Sources:%s", VTY_NEWLINE);
256 if (v4adjs_buffer[0] != '\0') {
257 vty_out(vty, " IPv4:%s", VTY_NEWLINE);
258 vty_out(vty, "%s", v4adjs_buffer);
259 }
260 if (v6adjs_buffer[0] != '\0') {
261 vty_out(vty, " IPv6:%s", VTY_NEWLINE);
262 vty_out(vty, "%s", v6adjs_buffer);
263 }
264 vty_out(vty, "%s", VTY_NEWLINE);
265 break;
266 case IMSG_CTL_END:
267 return (1);
268 default:
269 break;
270 }
271
272 return (0);
273}
274
275static int
276show_lib_msg(struct vty *vty, struct imsg *imsg, struct show_filter *filter)
277{
278 struct ctl_rt *rt;
279 char dstnet[BUFSIZ];
280
281 switch (imsg->hdr.type) {
282 case IMSG_CTL_SHOW_LIB:
283 rt = imsg->data;
284
285 if (filter->family != AF_UNSPEC && filter->family != rt->af)
286 break;
287
288 snprintf(dstnet, sizeof(dstnet), "%s/%d",
289 log_addr(rt->af, &rt->prefix), rt->prefixlen);
290
291 if (rt->first) {
292 vty_out(vty, "%s%s", dstnet, VTY_NEWLINE);
293 vty_out(vty, "%-8sLocal binding: label: %s%s", "",
294 log_label(rt->local_label), VTY_NEWLINE);
295
296 if (rt->remote_label != NO_LABEL) {
297 vty_out(vty, "%-8sRemote bindings:%s", "",
298 VTY_NEWLINE);
299 vty_out(vty, "%-12sPeer Label%s",
300 "", VTY_NEWLINE);
301 vty_out(vty, "%-12s----------------- "
302 "---------%s", "", VTY_NEWLINE);
303 } else
304 vty_out(vty, "%-8sNo remote bindings%s", "",
305 VTY_NEWLINE);
306 }
307 if (rt->remote_label != NO_LABEL)
308 vty_out(vty, "%12s%-20s%s%s", "", inet_ntoa(rt->nexthop),
309 log_label(rt->remote_label), VTY_NEWLINE);
310 break;
311 case IMSG_CTL_END:
312 vty_out(vty, "%s", VTY_NEWLINE);
313 return (1);
314 default:
315 break;
316 }
317
318 return (0);
319}
320
321static int
322show_l2vpn_binding_msg(struct vty *vty, struct imsg *imsg)
323{
324 struct ctl_pw *pw;
325
326 switch (imsg->hdr.type) {
327 case IMSG_CTL_SHOW_L2VPN_BINDING:
328 pw = imsg->data;
329
330 vty_out(vty, " Destination Address: %s, VC ID: %u%s",
331 inet_ntoa(pw->lsr_id), pw->pwid, VTY_NEWLINE);
332
333 /* local binding */
334 if (pw->local_label != NO_LABEL) {
335 vty_out(vty, " Local Label: %u%s", pw->local_label,
336 VTY_NEWLINE);
337 vty_out(vty, "%-8sCbit: %u, VC Type: %s, "
338 "GroupID: %u%s", "", pw->local_cword,
339 pw_type_name(pw->type), pw->local_gid,
340 VTY_NEWLINE);
341 vty_out(vty, "%-8sMTU: %u%s", "", pw->local_ifmtu,
342 VTY_NEWLINE);
343 } else
344 vty_out(vty, " Local Label: unassigned%s",
345 VTY_NEWLINE);
346
347 /* remote binding */
348 if (pw->remote_label != NO_LABEL) {
349 vty_out(vty, " Remote Label: %u%s",
350 pw->remote_label, VTY_NEWLINE);
351 vty_out(vty, "%-8sCbit: %u, VC Type: %s, "
352 "GroupID: %u%s", "", pw->remote_cword,
353 pw_type_name(pw->type), pw->remote_gid,
354 VTY_NEWLINE);
355 vty_out(vty, "%-8sMTU: %u%s", "", pw->remote_ifmtu,
356 VTY_NEWLINE);
357 } else
358 vty_out(vty, " Remote Label: unassigned%s",
359 VTY_NEWLINE);
360 break;
361 case IMSG_CTL_END:
362 vty_out(vty, "%s", VTY_NEWLINE);
363 return (1);
364 default:
365 break;
366 }
367
368 return (0);
369}
370
371static int
372show_l2vpn_pw_msg(struct vty *vty, struct imsg *imsg)
373{
374 struct ctl_pw *pw;
375
376 switch (imsg->hdr.type) {
377 case IMSG_CTL_SHOW_L2VPN_PW:
378 pw = imsg->data;
379
380 vty_out(vty, "%-9s %-15s %-10u %-16s %-10s%s", pw->ifname,
381 inet_ntoa(pw->lsr_id), pw->pwid, pw->l2vpn_name,
382 (pw->status ? "UP" : "DOWN"), VTY_NEWLINE);
383 break;
384 case IMSG_CTL_END:
385 vty_out(vty, "%s", VTY_NEWLINE);
386 return (1);
387 default:
388 break;
389 }
390
391 return (0);
392}
393
394static int
395ldp_vty_connect(struct imsgbuf *ibuf)
396{
397 struct sockaddr_un s_un;
398 int ctl_sock;
399
400 /* connect to ldpd control socket */
401 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
402 log_warn("%s: socket", __func__);
403 return (-1);
404 }
405
406 memset(&s_un, 0, sizeof(s_un));
407 s_un.sun_family = AF_UNIX;
408 strlcpy(s_un.sun_path, LDPD_SOCKET, sizeof(s_un.sun_path));
409 if (connect(ctl_sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
410 log_warn("%s: connect: %s", __func__, LDPD_SOCKET);
411 close(ctl_sock);
412 return (-1);
413 }
414
415 imsg_init(ibuf, ctl_sock);
416
417 return (0);
418}
419
420static int
421ldp_vty_dispatch(struct vty *vty, struct imsgbuf *ibuf, enum show_command cmd,
422 struct show_filter *filter)
423{
424 struct imsg imsg;
425 int n, done = 0;
426
427 while (ibuf->w.queued)
428 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) {
429 log_warn("write error");
430 close(ibuf->fd);
431 return (CMD_WARNING);
432 }
433
434 while (!done) {
435 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) {
436 log_warnx("imsg_read error");
437 close(ibuf->fd);
438 return (CMD_WARNING);
439 }
440 if (n == 0) {
441 log_warnx("pipe closed");
442 close(ibuf->fd);
443 return (CMD_WARNING);
444 }
445
446 while (!done) {
447 if ((n = imsg_get(ibuf, &imsg)) == -1) {
448 log_warnx("imsg_get error");
449 close(ibuf->fd);
450 return (CMD_WARNING);
451 }
452 if (n == 0)
453 break;
454 switch (cmd) {
455 case SHOW_IFACE:
456 done = show_interface_msg(vty, &imsg, filter);
457 break;
458 case SHOW_DISC:
459 done = show_discovery_msg(vty, &imsg, filter);
460 break;
461 case SHOW_NBR:
462 done = show_nbr_msg(vty, &imsg, filter);
463 break;
464 case SHOW_LIB:
465 done = show_lib_msg(vty, &imsg, filter);
466 break;
467 case SHOW_L2VPN_PW:
468 done = show_l2vpn_pw_msg(vty, &imsg);
469 break;
470 case SHOW_L2VPN_BINDING:
471 done = show_l2vpn_binding_msg(vty, &imsg);
472 break;
473 default:
474 break;
475 }
476 imsg_free(&imsg);
477 }
478 }
479
480 close(ibuf->fd);
481
482 return (CMD_SUCCESS);
483}
484
485static int
486ldp_vty_get_af(const char *str, int *af)
487{
488 if (str == NULL) {
489 *af = AF_UNSPEC;
490 return (0);
491 } else if (strcmp(str, "ipv4") == 0) {
492 *af = AF_INET;
493 return (0);
494 } else if (strcmp(str, "ipv6") == 0) {
495 *af = AF_INET6;
496 return (0);
497 }
498
499 return (-1);
500}
501
502int
503ldp_vty_show_binding(struct vty *vty, struct vty_arg *args[])
504{
505 struct imsgbuf ibuf;
506 struct show_filter filter;
507 const char *af_str;
508 int af;
509
510 if (ldp_vty_connect(&ibuf) < 0)
511 return (CMD_WARNING);
512
513 imsg_compose(&ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0);
514
515 af_str = vty_get_arg_value(args, "address-family");
516 if (ldp_vty_get_af(af_str, &af) < 0)
517 return (CMD_ERR_NO_MATCH);
518
519 memset(&filter, 0, sizeof(filter));
520 filter.family = af;
521
522 return (ldp_vty_dispatch(vty, &ibuf, SHOW_LIB, &filter));
523}
524
525int
526ldp_vty_show_discovery(struct vty *vty, struct vty_arg *args[])
527{
528 struct imsgbuf ibuf;
529 struct show_filter filter;
530 const char *af_str;
531 int af;
532
533 if (ldp_vty_connect(&ibuf) < 0)
534 return (CMD_WARNING);
535
536 imsg_compose(&ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0);
537
538 af_str = vty_get_arg_value(args, "address-family");
539 if (ldp_vty_get_af(af_str, &af) < 0)
540 return (CMD_ERR_NO_MATCH);
541
542 memset(&filter, 0, sizeof(filter));
543 filter.family = af;
544
545 return (ldp_vty_dispatch(vty, &ibuf, SHOW_DISC, &filter));
546}
547
548int
549ldp_vty_show_interface(struct vty *vty, struct vty_arg *args[])
550{
551 struct imsgbuf ibuf;
552 struct show_filter filter;
553 unsigned int ifidx = 0;
554 const char *af_str;
555 int af;
556
557 if (ldp_vty_connect(&ibuf) < 0)
558 return (CMD_WARNING);
559
560 imsg_compose(&ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, &ifidx,
561 sizeof(ifidx));
562
563 af_str = vty_get_arg_value(args, "address-family");
564 if (ldp_vty_get_af(af_str, &af) < 0)
565 return (CMD_ERR_NO_MATCH);
566
567 memset(&filter, 0, sizeof(filter));
568 filter.family = af;
569
570 /* header */
571 vty_out(vty, "%-4s %-11s %-6s %-8s %-12s %3s%s", "AF",
572 "Interface", "State", "Uptime", "Hello Timers", "ac", VTY_NEWLINE);
573
574 return (ldp_vty_dispatch(vty, &ibuf, SHOW_IFACE, &filter));
575}
576
577int
578ldp_vty_show_neighbor(struct vty *vty, struct vty_arg *args[])
579{
580 struct imsgbuf ibuf;
581 struct show_filter filter;
582
583 if (ldp_vty_connect(&ibuf) < 0)
584 return (CMD_WARNING);
585
586 imsg_compose(&ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
587
588 /* not used */
589 memset(&filter, 0, sizeof(filter));
590
591 return (ldp_vty_dispatch(vty, &ibuf, SHOW_NBR, &filter));
592}
593
594int
595ldp_vty_show_atom_binding(struct vty *vty, struct vty_arg *args[])
596{
597 struct imsgbuf ibuf;
598 struct show_filter filter;
599
600 if (ldp_vty_connect(&ibuf) < 0)
601 return (CMD_WARNING);
602
603 imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_BINDING, 0, 0, -1, NULL, 0);
604
605 /* not used */
606 memset(&filter, 0, sizeof(filter));
607
608 return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_BINDING, &filter));
609}
610
611int
612ldp_vty_show_atom_vc(struct vty *vty, struct vty_arg *args[])
613{
614 struct imsgbuf ibuf;
615 struct show_filter filter;
616
617 if (ldp_vty_connect(&ibuf) < 0)
618 return (CMD_WARNING);
619
620 imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_PW, 0, 0, -1, NULL, 0);
621
622 /* not used */
623 memset(&filter, 0, sizeof(filter));
624
625 /* header */
626 vty_out(vty, "%-9s %-15s %-10s %-16s %-10s%s",
627 "Interface", "Peer ID", "VC ID", "Name", "Status", VTY_NEWLINE);
628 vty_out(vty, "%-9s %-15s %-10s %-16s %-10s%s",
629 "---------", "---------------", "----------",
630 "----------------", "----------", VTY_NEWLINE);
631
632 return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_PW, &filter));
633}
634
635int
636ldp_vty_clear_nbr(struct vty *vty, struct vty_arg *args[])
637{
638 struct imsgbuf ibuf;
639 const char *addr_str;
640 struct ctl_nbr nbr;
641
642 addr_str = vty_get_arg_value(args, "addr");
643
644 memset(&nbr, 0, sizeof(nbr));
645 if (addr_str &&
646 (ldp_get_address(addr_str, &nbr.af, &nbr.raddr) == -1 ||
647 bad_addr(nbr.af, &nbr.raddr))) {
648 vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
649 return (CMD_WARNING);
650 }
651
652 if (ldp_vty_connect(&ibuf) < 0)
653 return (CMD_WARNING);
654
655 imsg_compose(&ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr, sizeof(nbr));
656
657 while (ibuf.w.queued)
658 if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN) {
659 log_warn("write error");
660 close(ibuf.fd);
661 return (CMD_WARNING);
662 }
663
664 close(ibuf.fd);
665
666 return (CMD_SUCCESS);
667}