]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_pw.c
Merge pull request #8888 from dlqs/lua-call
[mirror_frr.git] / zebra / zebra_pw.c
1 /* Zebra PW code
2 * Copyright (C) 2016 Volta Networks, Inc.
3 *
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.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21
22 #include "log.h"
23 #include "memory.h"
24 #include "thread.h"
25 #include "command.h"
26 #include "vrf.h"
27 #include "lib/json.h"
28 #include "printfrr.h"
29
30 #include "zebra/debug.h"
31 #include "zebra/rib.h"
32 #include "zebra/zebra_router.h"
33 #include "zebra/zapi_msg.h"
34 #include "zebra/zebra_rnh.h"
35 #include "zebra/zebra_vrf.h"
36 #include "zebra/zebra_pw.h"
37
38 DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire");
39
40 DEFINE_QOBJ_TYPE(zebra_pw);
41
42 DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw));
43 DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw));
44
45 #define MPLS_NO_LABEL MPLS_INVALID_LABEL
46
47 static int zebra_pw_enabled(struct zebra_pw *);
48 static void zebra_pw_install(struct zebra_pw *);
49 static void zebra_pw_uninstall(struct zebra_pw *);
50 static int zebra_pw_install_retry(struct thread *);
51 static int zebra_pw_check_reachability(const struct zebra_pw *);
52 static void zebra_pw_update_status(struct zebra_pw *, int);
53
54 static inline int zebra_pw_compare(const struct zebra_pw *a,
55 const struct zebra_pw *b)
56 {
57 return (strcmp(a->ifname, b->ifname));
58 }
59
60 RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare)
61 RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare)
62
63 struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
64 uint8_t protocol, struct zserv *client)
65 {
66 struct zebra_pw *pw;
67
68 if (IS_ZEBRA_DEBUG_PW)
69 zlog_debug("%u: adding pseudowire %s protocol %s",
70 zvrf_id(zvrf), ifname, zebra_route_string(protocol));
71
72 pw = XCALLOC(MTYPE_PW, sizeof(*pw));
73 strlcpy(pw->ifname, ifname, sizeof(pw->ifname));
74 pw->protocol = protocol;
75 pw->vrf_id = zvrf_id(zvrf);
76 pw->client = client;
77 pw->status = PW_NOT_FORWARDING;
78 pw->local_label = MPLS_NO_LABEL;
79 pw->remote_label = MPLS_NO_LABEL;
80 pw->flags = F_PSEUDOWIRE_CWORD;
81
82 RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw);
83 if (pw->protocol == ZEBRA_ROUTE_STATIC) {
84 RB_INSERT(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
85 QOBJ_REG(pw, zebra_pw);
86 }
87
88 return pw;
89 }
90
91 void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw)
92 {
93 if (IS_ZEBRA_DEBUG_PW)
94 zlog_debug("%u: deleting pseudowire %s protocol %s", pw->vrf_id,
95 pw->ifname, zebra_route_string(pw->protocol));
96
97 /* remove nexthop tracking */
98 zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
99
100 /* uninstall */
101 if (pw->status == PW_FORWARDING) {
102 hook_call(pw_uninstall, pw);
103 dplane_pw_uninstall(pw);
104 } else if (pw->install_retry_timer)
105 thread_cancel(&pw->install_retry_timer);
106
107 /* unlink and release memory */
108 RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw);
109 if (pw->protocol == ZEBRA_ROUTE_STATIC)
110 RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
111 XFREE(MTYPE_PW, pw);
112 }
113
114 void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af,
115 union g_addr *nexthop, uint32_t local_label,
116 uint32_t remote_label, uint8_t flags,
117 union pw_protocol_fields *data)
118 {
119 pw->ifindex = ifindex;
120 pw->type = type;
121 pw->af = af;
122 pw->nexthop = *nexthop;
123 pw->local_label = local_label;
124 pw->remote_label = remote_label;
125 pw->flags = flags;
126 pw->data = *data;
127
128 if (zebra_pw_enabled(pw)) {
129 bool nht_exists;
130 zebra_register_rnh_pseudowire(pw->vrf_id, pw, &nht_exists);
131 if (nht_exists)
132 zebra_pw_update(pw);
133 } else {
134 if (pw->protocol == ZEBRA_ROUTE_STATIC)
135 zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
136 zebra_pw_uninstall(pw);
137 }
138 }
139
140 struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname)
141 {
142 struct zebra_pw pw;
143 strlcpy(pw.ifname, ifname, sizeof(pw.ifname));
144 return (RB_FIND(zebra_pw_head, &zvrf->pseudowires, &pw));
145 }
146
147 static int zebra_pw_enabled(struct zebra_pw *pw)
148 {
149 if (pw->protocol == ZEBRA_ROUTE_STATIC) {
150 if (pw->local_label == MPLS_NO_LABEL
151 || pw->remote_label == MPLS_NO_LABEL || pw->af == AF_UNSPEC)
152 return 0;
153 return 1;
154 } else
155 return pw->enabled;
156 }
157
158 void zebra_pw_update(struct zebra_pw *pw)
159 {
160 if (zebra_pw_check_reachability(pw) < 0) {
161 zebra_pw_uninstall(pw);
162 zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
163 /* wait for NHT and try again later */
164 } else {
165 /*
166 * Install or reinstall the pseudowire (e.g. to update
167 * parameters like the nexthop or the use of the control word).
168 */
169 zebra_pw_install(pw);
170 }
171 }
172
173 static void zebra_pw_install(struct zebra_pw *pw)
174 {
175 if (IS_ZEBRA_DEBUG_PW)
176 zlog_debug("%u: installing pseudowire %s protocol %s",
177 pw->vrf_id, pw->ifname,
178 zebra_route_string(pw->protocol));
179
180 hook_call(pw_install, pw);
181 if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) {
182 zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
183 return;
184 }
185
186 if (pw->status != PW_FORWARDING)
187 zebra_pw_update_status(pw, PW_FORWARDING);
188 }
189
190 static void zebra_pw_uninstall(struct zebra_pw *pw)
191 {
192 if (pw->status != PW_FORWARDING)
193 return;
194
195 if (IS_ZEBRA_DEBUG_PW)
196 zlog_debug("%u: uninstalling pseudowire %s protocol %s",
197 pw->vrf_id, pw->ifname,
198 zebra_route_string(pw->protocol));
199
200 /* ignore any possible error */
201 hook_call(pw_uninstall, pw);
202 dplane_pw_uninstall(pw);
203
204 if (zebra_pw_enabled(pw))
205 zebra_pw_update_status(pw, PW_NOT_FORWARDING);
206 }
207
208 /*
209 * Installation of the pseudowire in the kernel or hardware has failed. This
210 * function will notify the pseudowire client about the failure and schedule
211 * to retry the installation later. This function can be called by an external
212 * agent that performs the pseudowire installation in an asynchronous way.
213 */
214 void zebra_pw_install_failure(struct zebra_pw *pw, int pwstatus)
215 {
216 if (IS_ZEBRA_DEBUG_PW)
217 zlog_debug(
218 "%u: failed installing pseudowire %s, scheduling retry in %u seconds",
219 pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL);
220
221 /* schedule to retry later */
222 thread_cancel(&pw->install_retry_timer);
223 thread_add_timer(zrouter.master, zebra_pw_install_retry, pw,
224 PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer);
225
226 zebra_pw_update_status(pw, pwstatus);
227 }
228
229 static int zebra_pw_install_retry(struct thread *thread)
230 {
231 struct zebra_pw *pw = THREAD_ARG(thread);
232
233 pw->install_retry_timer = NULL;
234 zebra_pw_install(pw);
235
236 return 0;
237 }
238
239 static void zebra_pw_update_status(struct zebra_pw *pw, int status)
240 {
241 pw->status = status;
242 if (pw->client)
243 zsend_pw_update(pw->client, pw);
244 }
245
246 static int zebra_pw_check_reachability_strict(const struct zebra_pw *pw,
247 struct route_entry *re)
248 {
249 const struct nexthop *nexthop;
250 const struct nexthop_group *nhg;
251 bool found_p = false;
252 bool fail_p = false;
253
254 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
255
256 /* All active nexthops must be labelled; look at
257 * primary and backup fib lists, in case there's been
258 * a backup nexthop activation.
259 */
260 nhg = rib_get_fib_nhg(re);
261 if (nhg && nhg->nexthop) {
262 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
263 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
264 continue;
265
266 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
267 if (nexthop->nh_label != NULL)
268 found_p = true;
269 else {
270 fail_p = true;
271 break;
272 }
273 }
274 }
275 }
276
277 if (fail_p)
278 goto done;
279
280 nhg = rib_get_fib_backup_nhg(re);
281 if (nhg && nhg->nexthop) {
282 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
283 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
284 continue;
285
286 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
287 if (nexthop->nh_label != NULL)
288 found_p = true;
289 else {
290 fail_p = true;
291 break;
292 }
293 }
294 }
295 }
296
297 done:
298
299 if (fail_p || !found_p) {
300 if (IS_ZEBRA_DEBUG_PW)
301 zlog_debug("%s: unlabeled route for %s",
302 __func__, pw->ifname);
303 return -1;
304 }
305
306 return 0;
307 }
308
309 static int zebra_pw_check_reachability(const struct zebra_pw *pw)
310 {
311 struct route_entry *re;
312 const struct nexthop *nexthop;
313 const struct nexthop_group *nhg;
314 bool found_p = false;
315
316 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
317
318 /* Find route to the remote end of the pseudowire */
319 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
320 &pw->nexthop, NULL);
321 if (!re) {
322 if (IS_ZEBRA_DEBUG_PW)
323 zlog_debug("%s: no route found for %s", __func__,
324 pw->ifname);
325 return -1;
326 }
327
328 /* Stricter checking for some OSes (OBSD, e.g.) */
329 if (mpls_pw_reach_strict)
330 return zebra_pw_check_reachability_strict(pw, re);
331
332 /* There must be at least one installed labelled nexthop;
333 * look at primary and backup fib lists, in case there's been
334 * a backup nexthop activation.
335 */
336 nhg = rib_get_fib_nhg(re);
337 if (nhg && nhg->nexthop) {
338 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
339 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
340 continue;
341
342 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
343 nexthop->nh_label != NULL) {
344 found_p = true;
345 break;
346 }
347 }
348 }
349
350 if (found_p)
351 return 0;
352
353 nhg = rib_get_fib_backup_nhg(re);
354 if (nhg && nhg->nexthop) {
355 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
356 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
357 continue;
358
359 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
360 nexthop->nh_label != NULL) {
361 found_p = true;
362 break;
363 }
364 }
365 }
366
367 if (!found_p) {
368 if (IS_ZEBRA_DEBUG_PW)
369 zlog_debug("%s: unlabeled route for %s",
370 __func__, pw->ifname);
371 return -1;
372 }
373
374 return 0;
375 }
376
377 static int zebra_pw_client_close(struct zserv *client)
378 {
379 struct vrf *vrf;
380 struct zebra_vrf *zvrf;
381 struct zebra_pw *pw, *tmp;
382
383 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
384 zvrf = vrf->info;
385 RB_FOREACH_SAFE (pw, zebra_pw_head, &zvrf->pseudowires, tmp) {
386 if (pw->client != client)
387 continue;
388 zebra_pw_del(zvrf, pw);
389 }
390 }
391
392 return 0;
393 }
394
395 void zebra_pw_init(struct zebra_vrf *zvrf)
396 {
397 RB_INIT(zebra_pw_head, &zvrf->pseudowires);
398 RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires);
399
400 hook_register(zserv_client_close, zebra_pw_client_close);
401 }
402
403 void zebra_pw_exit(struct zebra_vrf *zvrf)
404 {
405 struct zebra_pw *pw;
406
407 while (!RB_EMPTY(zebra_pw_head, &zvrf->pseudowires)) {
408 pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires);
409
410 zebra_pw_del(zvrf, pw);
411 }
412 }
413
414 DEFUN_NOSH (pseudowire_if,
415 pseudowire_if_cmd,
416 "pseudowire IFNAME",
417 "Static pseudowire configuration\n"
418 "Pseudowire name\n")
419 {
420 struct zebra_vrf *zvrf;
421 struct zebra_pw *pw;
422 const char *ifname;
423 int idx = 0;
424
425 zvrf = vrf_info_lookup(VRF_DEFAULT);
426 if (!zvrf)
427 return CMD_WARNING;
428
429 argv_find(argv, argc, "IFNAME", &idx);
430 ifname = argv[idx]->arg;
431
432 pw = zebra_pw_find(zvrf, ifname);
433 if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
434 vty_out(vty, "%% Pseudowire is not static\n");
435 return CMD_WARNING;
436 }
437
438 if (!pw)
439 pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
440 VTY_PUSH_CONTEXT(PW_NODE, pw);
441
442 return CMD_SUCCESS;
443 }
444
445 DEFUN (no_pseudowire_if,
446 no_pseudowire_if_cmd,
447 "no pseudowire IFNAME",
448 NO_STR
449 "Static pseudowire configuration\n"
450 "Pseudowire name\n")
451 {
452 struct zebra_vrf *zvrf;
453 struct zebra_pw *pw;
454 const char *ifname;
455 int idx = 0;
456
457 zvrf = vrf_info_lookup(VRF_DEFAULT);
458 if (!zvrf)
459 return CMD_WARNING;
460
461 argv_find(argv, argc, "IFNAME", &idx);
462 ifname = argv[idx]->arg;
463
464 pw = zebra_pw_find(zvrf, ifname);
465 if (pw) {
466 if (pw->protocol != ZEBRA_ROUTE_STATIC) {
467 vty_out(vty, "%% Pseudowire is not static\n");
468 return CMD_WARNING;
469 }
470 zebra_pw_del(zvrf, pw);
471 }
472
473 return CMD_SUCCESS;
474 }
475
476 DEFUN (pseudowire_labels,
477 pseudowire_labels_cmd,
478 "[no] mpls label local (16-1048575) remote (16-1048575)",
479 NO_STR
480 "MPLS L2VPN PW command\n"
481 "MPLS L2VPN static labels\n"
482 "Local pseudowire label\n"
483 "Local pseudowire label\n"
484 "Remote pseudowire label\n"
485 "Remote pseudowire label\n")
486 {
487 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
488 int idx = 0;
489 mpls_label_t local_label, remote_label;
490
491 if (argv_find(argv, argc, "no", &idx)) {
492 local_label = MPLS_NO_LABEL;
493 remote_label = MPLS_NO_LABEL;
494 } else {
495 argv_find(argv, argc, "local", &idx);
496 local_label = atoi(argv[idx + 1]->arg);
497 argv_find(argv, argc, "remote", &idx);
498 remote_label = atoi(argv[idx + 1]->arg);
499 }
500
501 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
502 local_label, remote_label, pw->flags, &pw->data);
503
504 return CMD_SUCCESS;
505 }
506
507 DEFUN (pseudowire_neighbor,
508 pseudowire_neighbor_cmd,
509 "[no] neighbor <A.B.C.D|X:X::X:X>",
510 NO_STR
511 "Specify the IPv4 or IPv6 address of the remote endpoint\n"
512 "IPv4 address\n"
513 "IPv6 address\n")
514 {
515 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
516 int idx = 0;
517 const char *address;
518 int af;
519 union g_addr nexthop;
520
521 af = AF_UNSPEC;
522 memset(&nexthop, 0, sizeof(nexthop));
523
524 if (!argv_find(argv, argc, "no", &idx)) {
525 argv_find(argv, argc, "neighbor", &idx);
526 address = argv[idx + 1]->arg;
527
528 if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1)
529 af = AF_INET;
530 else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1)
531 af = AF_INET6;
532 else {
533 vty_out(vty, "%% Malformed address\n");
534 return CMD_WARNING;
535 }
536 }
537
538 zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop,
539 pw->local_label, pw->remote_label, pw->flags,
540 &pw->data);
541
542 return CMD_SUCCESS;
543 }
544
545 DEFUN (pseudowire_control_word,
546 pseudowire_control_word_cmd,
547 "[no] control-word <exclude|include>",
548 NO_STR
549 "Control-word options\n"
550 "Exclude control-word in pseudowire packets\n"
551 "Include control-word in pseudowire packets\n")
552 {
553 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
554 int idx = 0;
555 uint8_t flags = 0;
556
557 if (argv_find(argv, argc, "no", &idx))
558 flags = F_PSEUDOWIRE_CWORD;
559 else {
560 argv_find(argv, argc, "control-word", &idx);
561 if (argv[idx + 1]->text[0] == 'i')
562 flags = F_PSEUDOWIRE_CWORD;
563 }
564
565 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
566 pw->local_label, pw->remote_label, flags, &pw->data);
567
568 return CMD_SUCCESS;
569 }
570
571 DEFUN (show_pseudowires,
572 show_pseudowires_cmd,
573 "show mpls pseudowires",
574 SHOW_STR
575 MPLS_STR
576 "Pseudowires\n")
577 {
578 struct zebra_vrf *zvrf;
579 struct zebra_pw *pw;
580
581 zvrf = vrf_info_lookup(VRF_DEFAULT);
582 if (!zvrf)
583 return 0;
584
585 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
586 "Labels", "Protocol", "Status");
587
588 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
589 char buf_nbr[INET6_ADDRSTRLEN];
590 char buf_labels[64];
591
592 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
593
594 if (pw->local_label != MPLS_NO_LABEL
595 && pw->remote_label != MPLS_NO_LABEL)
596 snprintf(buf_labels, sizeof(buf_labels), "%u/%u",
597 pw->local_label, pw->remote_label);
598 else
599 snprintf(buf_labels, sizeof(buf_labels), "-");
600
601 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname,
602 (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels,
603 zebra_route_string(pw->protocol),
604 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
605 ? "UP"
606 : "DOWN");
607 }
608
609 return CMD_SUCCESS;
610 }
611
612 static void vty_show_mpls_pseudowire_detail(struct vty *vty)
613 {
614 struct zebra_vrf *zvrf;
615 struct zebra_pw *pw;
616 struct route_entry *re;
617 struct nexthop *nexthop;
618 struct nexthop_group *nhg;
619
620 zvrf = vrf_info_lookup(VRF_DEFAULT);
621 if (!zvrf)
622 return;
623
624 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
625 char buf_nbr[INET6_ADDRSTRLEN];
626 char buf_nh[100];
627
628 vty_out(vty, "Interface: %s\n", pw->ifname);
629 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
630 vty_out(vty, " Neighbor: %s\n",
631 (pw->af != AF_UNSPEC) ? buf_nbr : "-");
632 if (pw->local_label != MPLS_NO_LABEL)
633 vty_out(vty, " Local Label: %u\n", pw->local_label);
634 else
635 vty_out(vty, " Local Label: %s\n", "-");
636 if (pw->remote_label != MPLS_NO_LABEL)
637 vty_out(vty, " Remote Label: %u\n", pw->remote_label);
638 else
639 vty_out(vty, " Remote Label: %s\n", "-");
640 vty_out(vty, " Protocol: %s\n",
641 zebra_route_string(pw->protocol));
642 if (pw->protocol == ZEBRA_ROUTE_LDP)
643 vty_out(vty, " VC-ID: %u\n", pw->data.ldp.pwid);
644 vty_out(vty, " Status: %s \n",
645 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
646 ? "Up"
647 : "Down");
648 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
649 &pw->nexthop, NULL);
650 if (re == NULL)
651 continue;
652
653 nhg = rib_get_fib_nhg(re);
654 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
655 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
656 nexthop);
657 vty_out(vty, " Next Hop: %s\n", buf_nh);
658 if (nexthop->nh_label)
659 vty_out(vty, " Next Hop label: %u\n",
660 nexthop->nh_label->label[0]);
661 else
662 vty_out(vty, " Next Hop label: %s\n",
663 "-");
664 }
665
666 /* Include any installed backups */
667 nhg = rib_get_fib_backup_nhg(re);
668 if (nhg == NULL)
669 continue;
670
671 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
672 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
673 nexthop);
674 vty_out(vty, " Next Hop: %s\n", buf_nh);
675 if (nexthop->nh_label)
676 vty_out(vty, " Next Hop label: %u\n",
677 nexthop->nh_label->label[0]);
678 else
679 vty_out(vty, " Next Hop label: %s\n",
680 "-");
681 }
682 }
683 }
684
685 static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
686 {
687 struct route_entry *re;
688 struct nexthop *nexthop;
689 struct nexthop_group *nhg;
690 char buf_nbr[INET6_ADDRSTRLEN];
691 char buf_nh[100];
692 json_object *json_pw = NULL;
693 json_object *json_nexthop = NULL;
694 json_object *json_nexthops = NULL;
695
696 json_nexthops = json_object_new_array();
697 json_pw = json_object_new_object();
698
699 json_object_string_add(json_pw, "interface", pw->ifname);
700 if (pw->af == AF_UNSPEC)
701 json_object_string_add(json_pw, "neighbor", "-");
702 else {
703 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
704 json_object_string_add(json_pw, "neighbor", buf_nbr);
705 }
706 if (pw->local_label != MPLS_NO_LABEL)
707 json_object_int_add(json_pw, "localLabel", pw->local_label);
708 else
709 json_object_string_add(json_pw, "localLabel", "-");
710 if (pw->remote_label != MPLS_NO_LABEL)
711 json_object_int_add(json_pw, "remoteLabel", pw->remote_label);
712 else
713 json_object_string_add(json_pw, "remoteLabel", "-");
714 json_object_string_add(json_pw, "protocol",
715 zebra_route_string(pw->protocol));
716 if (pw->protocol == ZEBRA_ROUTE_LDP)
717 json_object_int_add(json_pw, "vcId", pw->data.ldp.pwid);
718 json_object_string_add(
719 json_pw, "Status",
720 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING) ? "Up"
721 : "Down");
722 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
723 &pw->nexthop, NULL);
724 if (re == NULL)
725 goto done;
726
727 nhg = rib_get_fib_nhg(re);
728 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
729 json_nexthop = json_object_new_object();
730 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
731 json_object_string_add(json_nexthop, "nexthop", buf_nh);
732 if (nexthop->nh_label)
733 json_object_int_add(
734 json_nexthop, "nhLabel",
735 nexthop->nh_label->label[0]);
736 else
737 json_object_string_add(json_nexthop, "nhLabel",
738 "-");
739
740 json_object_array_add(json_nexthops, json_nexthop);
741 }
742
743 /* Include installed backup nexthops also */
744 nhg = rib_get_fib_backup_nhg(re);
745 if (nhg == NULL)
746 goto done;
747
748 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
749 json_nexthop = json_object_new_object();
750 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
751 json_object_string_add(json_nexthop, "nexthop", buf_nh);
752 if (nexthop->nh_label)
753 json_object_int_add(
754 json_nexthop, "nhLabel",
755 nexthop->nh_label->label[0]);
756 else
757 json_object_string_add(json_nexthop, "nhLabel",
758 "-");
759
760 json_object_array_add(json_nexthops, json_nexthop);
761 }
762
763 done:
764
765 json_object_object_add(json_pw, "nexthops", json_nexthops);
766 json_object_array_add(json_pws, json_pw);
767 }
768
769 static void vty_show_mpls_pseudowire_detail_json(struct vty *vty)
770 {
771 json_object *json = NULL;
772 json_object *json_pws = NULL;
773 struct zebra_vrf *zvrf;
774 struct zebra_pw *pw;
775
776 zvrf = vrf_info_lookup(VRF_DEFAULT);
777 if (!zvrf)
778 return;
779
780 json = json_object_new_object();
781 json_pws = json_object_new_array();
782 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
783 vty_show_mpls_pseudowire(pw, json_pws);
784 }
785 json_object_object_add(json, "pw", json_pws);
786 vty_out(vty, "%s\n",
787 json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
788 json_object_free(json);
789 }
790
791 DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd,
792 "show mpls pseudowires detail [json]$json",
793 SHOW_STR MPLS_STR
794 "Pseudowires\n"
795 "Detailed output\n" JSON_STR)
796 {
797 bool uj = use_json(argc, argv);
798
799 if (uj)
800 vty_show_mpls_pseudowire_detail_json(vty);
801 else
802 vty_show_mpls_pseudowire_detail(vty);
803
804 return CMD_SUCCESS;
805 }
806
807 /* Pseudowire configuration write function. */
808 static int zebra_pw_config(struct vty *vty)
809 {
810 int write = 0;
811 struct zebra_vrf *zvrf;
812 struct zebra_pw *pw;
813
814 zvrf = vrf_info_lookup(VRF_DEFAULT);
815 if (!zvrf)
816 return 0;
817
818 RB_FOREACH (pw, zebra_static_pw_head, &zvrf->static_pseudowires) {
819 vty_out(vty, "pseudowire %s\n", pw->ifname);
820 if (pw->local_label != MPLS_NO_LABEL
821 && pw->remote_label != MPLS_NO_LABEL)
822 vty_out(vty, " mpls label local %u remote %u\n",
823 pw->local_label, pw->remote_label);
824 else
825 vty_out(vty,
826 " ! Incomplete config, specify the static MPLS labels\n");
827
828 if (pw->af != AF_UNSPEC) {
829 char buf[INET6_ADDRSTRLEN];
830 inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
831 vty_out(vty, " neighbor %s\n", buf);
832 } else
833 vty_out(vty,
834 " ! Incomplete config, specify a neighbor address\n");
835
836 if (!(pw->flags & F_PSEUDOWIRE_CWORD))
837 vty_out(vty, " control-word exclude\n");
838
839 vty_out(vty, "!\n");
840 write = 1;
841 }
842
843 return write;
844 }
845
846 static int zebra_pw_config(struct vty *vty);
847 static struct cmd_node pw_node = {
848 .name = "pw",
849 .node = PW_NODE,
850 .parent_node = CONFIG_NODE,
851 .prompt = "%s(config-pw)# ",
852 .config_write = zebra_pw_config,
853 };
854
855 void zebra_pw_vty_init(void)
856 {
857 install_node(&pw_node);
858 install_default(PW_NODE);
859
860 install_element(CONFIG_NODE, &pseudowire_if_cmd);
861 install_element(CONFIG_NODE, &no_pseudowire_if_cmd);
862 install_element(PW_NODE, &pseudowire_labels_cmd);
863 install_element(PW_NODE, &pseudowire_neighbor_cmd);
864 install_element(PW_NODE, &pseudowire_control_word_cmd);
865
866 install_element(VIEW_NODE, &show_pseudowires_cmd);
867 install_element(VIEW_NODE, &show_pseudowires_detail_cmd);
868 }