]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_pw.c
Merge pull request #11408 from donaldsharp/common_config
[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 void zebra_pw_install_retry(struct thread *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 void 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
237 static void zebra_pw_update_status(struct zebra_pw *pw, int status)
238 {
239 pw->status = status;
240 if (pw->client)
241 zsend_pw_update(pw->client, pw);
242 }
243
244 static int zebra_pw_check_reachability_strict(const struct zebra_pw *pw,
245 struct route_entry *re)
246 {
247 const struct nexthop *nexthop;
248 const struct nexthop_group *nhg;
249 bool found_p = false;
250 bool fail_p = false;
251
252 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
253
254 /* All active nexthops must be labelled; look at
255 * primary and backup fib lists, in case there's been
256 * a backup nexthop activation.
257 */
258 nhg = rib_get_fib_nhg(re);
259 if (nhg && nhg->nexthop) {
260 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
261 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
262 continue;
263
264 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
265 if (nexthop->nh_label != NULL)
266 found_p = true;
267 else {
268 fail_p = true;
269 break;
270 }
271 }
272 }
273 }
274
275 if (fail_p)
276 goto done;
277
278 nhg = rib_get_fib_backup_nhg(re);
279 if (nhg && nhg->nexthop) {
280 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
281 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
282 continue;
283
284 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
285 if (nexthop->nh_label != NULL)
286 found_p = true;
287 else {
288 fail_p = true;
289 break;
290 }
291 }
292 }
293 }
294
295 done:
296
297 if (fail_p || !found_p) {
298 if (IS_ZEBRA_DEBUG_PW)
299 zlog_debug("%s: unlabeled route for %s",
300 __func__, pw->ifname);
301 return -1;
302 }
303
304 return 0;
305 }
306
307 static int zebra_pw_check_reachability(const struct zebra_pw *pw)
308 {
309 struct route_entry *re;
310 const struct nexthop *nexthop;
311 const struct nexthop_group *nhg;
312 bool found_p = false;
313
314 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
315
316 /* Find route to the remote end of the pseudowire */
317 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
318 &pw->nexthop, NULL);
319 if (!re) {
320 if (IS_ZEBRA_DEBUG_PW)
321 zlog_debug("%s: no route found for %s", __func__,
322 pw->ifname);
323 return -1;
324 }
325
326 /* Stricter checking for some OSes (OBSD, e.g.) */
327 if (mpls_pw_reach_strict)
328 return zebra_pw_check_reachability_strict(pw, re);
329
330 /* There must be at least one installed labelled nexthop;
331 * look at primary and backup fib lists, in case there's been
332 * a backup nexthop activation.
333 */
334 nhg = rib_get_fib_nhg(re);
335 if (nhg && nhg->nexthop) {
336 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
337 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
338 continue;
339
340 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
341 nexthop->nh_label != NULL) {
342 found_p = true;
343 break;
344 }
345 }
346 }
347
348 if (found_p)
349 return 0;
350
351 nhg = rib_get_fib_backup_nhg(re);
352 if (nhg && nhg->nexthop) {
353 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
354 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
355 continue;
356
357 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
358 nexthop->nh_label != NULL) {
359 found_p = true;
360 break;
361 }
362 }
363 }
364
365 if (!found_p) {
366 if (IS_ZEBRA_DEBUG_PW)
367 zlog_debug("%s: unlabeled route for %s",
368 __func__, pw->ifname);
369 return -1;
370 }
371
372 return 0;
373 }
374
375 static int zebra_pw_client_close(struct zserv *client)
376 {
377 struct vrf *vrf;
378 struct zebra_vrf *zvrf;
379 struct zebra_pw *pw, *tmp;
380
381 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
382 zvrf = vrf->info;
383 RB_FOREACH_SAFE (pw, zebra_pw_head, &zvrf->pseudowires, tmp) {
384 if (pw->client != client)
385 continue;
386 zebra_pw_del(zvrf, pw);
387 }
388 }
389
390 return 0;
391 }
392
393 void zebra_pw_init(struct zebra_vrf *zvrf)
394 {
395 RB_INIT(zebra_pw_head, &zvrf->pseudowires);
396 RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires);
397
398 hook_register(zserv_client_close, zebra_pw_client_close);
399 }
400
401 void zebra_pw_exit(struct zebra_vrf *zvrf)
402 {
403 struct zebra_pw *pw;
404
405 while (!RB_EMPTY(zebra_pw_head, &zvrf->pseudowires)) {
406 pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires);
407
408 zebra_pw_del(zvrf, pw);
409 }
410 }
411
412 DEFUN_NOSH (pseudowire_if,
413 pseudowire_if_cmd,
414 "pseudowire IFNAME",
415 "Static pseudowire configuration\n"
416 "Pseudowire name\n")
417 {
418 struct zebra_vrf *zvrf;
419 struct zebra_pw *pw;
420 const char *ifname;
421 int idx = 0;
422
423 zvrf = vrf_info_lookup(VRF_DEFAULT);
424 if (!zvrf)
425 return CMD_WARNING;
426
427 argv_find(argv, argc, "IFNAME", &idx);
428 ifname = argv[idx]->arg;
429
430 pw = zebra_pw_find(zvrf, ifname);
431 if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
432 vty_out(vty, "%% Pseudowire is not static\n");
433 return CMD_WARNING;
434 }
435
436 if (!pw)
437 pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
438 VTY_PUSH_CONTEXT(PW_NODE, pw);
439
440 return CMD_SUCCESS;
441 }
442
443 DEFUN (no_pseudowire_if,
444 no_pseudowire_if_cmd,
445 "no pseudowire IFNAME",
446 NO_STR
447 "Static pseudowire configuration\n"
448 "Pseudowire name\n")
449 {
450 struct zebra_vrf *zvrf;
451 struct zebra_pw *pw;
452 const char *ifname;
453 int idx = 0;
454
455 zvrf = vrf_info_lookup(VRF_DEFAULT);
456 if (!zvrf)
457 return CMD_WARNING;
458
459 argv_find(argv, argc, "IFNAME", &idx);
460 ifname = argv[idx]->arg;
461
462 pw = zebra_pw_find(zvrf, ifname);
463 if (pw) {
464 if (pw->protocol != ZEBRA_ROUTE_STATIC) {
465 vty_out(vty, "%% Pseudowire is not static\n");
466 return CMD_WARNING;
467 }
468 zebra_pw_del(zvrf, pw);
469 }
470
471 return CMD_SUCCESS;
472 }
473
474 DEFUN (pseudowire_labels,
475 pseudowire_labels_cmd,
476 "[no] mpls label local (16-1048575) remote (16-1048575)",
477 NO_STR
478 "MPLS L2VPN PW command\n"
479 "MPLS L2VPN static labels\n"
480 "Local pseudowire label\n"
481 "Local pseudowire label\n"
482 "Remote pseudowire label\n"
483 "Remote pseudowire label\n")
484 {
485 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
486 int idx = 0;
487 mpls_label_t local_label, remote_label;
488
489 if (argv_find(argv, argc, "no", &idx)) {
490 local_label = MPLS_NO_LABEL;
491 remote_label = MPLS_NO_LABEL;
492 } else {
493 argv_find(argv, argc, "local", &idx);
494 local_label = atoi(argv[idx + 1]->arg);
495 argv_find(argv, argc, "remote", &idx);
496 remote_label = atoi(argv[idx + 1]->arg);
497 }
498
499 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
500 local_label, remote_label, pw->flags, &pw->data);
501
502 return CMD_SUCCESS;
503 }
504
505 DEFUN (pseudowire_neighbor,
506 pseudowire_neighbor_cmd,
507 "[no] neighbor <A.B.C.D|X:X::X:X>",
508 NO_STR
509 "Specify the IPv4 or IPv6 address of the remote endpoint\n"
510 "IPv4 address\n"
511 "IPv6 address\n")
512 {
513 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
514 int idx = 0;
515 const char *address;
516 int af;
517 union g_addr nexthop;
518
519 af = AF_UNSPEC;
520 memset(&nexthop, 0, sizeof(nexthop));
521
522 if (!argv_find(argv, argc, "no", &idx)) {
523 argv_find(argv, argc, "neighbor", &idx);
524 address = argv[idx + 1]->arg;
525
526 if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1)
527 af = AF_INET;
528 else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1)
529 af = AF_INET6;
530 else {
531 vty_out(vty, "%% Malformed address\n");
532 return CMD_WARNING;
533 }
534 }
535
536 zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop,
537 pw->local_label, pw->remote_label, pw->flags,
538 &pw->data);
539
540 return CMD_SUCCESS;
541 }
542
543 DEFUN (pseudowire_control_word,
544 pseudowire_control_word_cmd,
545 "[no] control-word <exclude|include>",
546 NO_STR
547 "Control-word options\n"
548 "Exclude control-word in pseudowire packets\n"
549 "Include control-word in pseudowire packets\n")
550 {
551 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
552 int idx = 0;
553 uint8_t flags = 0;
554
555 if (argv_find(argv, argc, "no", &idx))
556 flags = F_PSEUDOWIRE_CWORD;
557 else {
558 argv_find(argv, argc, "control-word", &idx);
559 if (argv[idx + 1]->text[0] == 'i')
560 flags = F_PSEUDOWIRE_CWORD;
561 }
562
563 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
564 pw->local_label, pw->remote_label, flags, &pw->data);
565
566 return CMD_SUCCESS;
567 }
568
569 DEFUN (show_pseudowires,
570 show_pseudowires_cmd,
571 "show mpls pseudowires",
572 SHOW_STR
573 MPLS_STR
574 "Pseudowires\n")
575 {
576 struct zebra_vrf *zvrf;
577 struct zebra_pw *pw;
578
579 zvrf = vrf_info_lookup(VRF_DEFAULT);
580 if (!zvrf)
581 return 0;
582
583 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
584 "Labels", "Protocol", "Status");
585
586 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
587 char buf_nbr[INET6_ADDRSTRLEN];
588 char buf_labels[64];
589
590 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
591
592 if (pw->local_label != MPLS_NO_LABEL
593 && pw->remote_label != MPLS_NO_LABEL)
594 snprintf(buf_labels, sizeof(buf_labels), "%u/%u",
595 pw->local_label, pw->remote_label);
596 else
597 snprintf(buf_labels, sizeof(buf_labels), "-");
598
599 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname,
600 (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels,
601 zebra_route_string(pw->protocol),
602 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
603 ? "UP"
604 : "DOWN");
605 }
606
607 return CMD_SUCCESS;
608 }
609
610 static void vty_show_mpls_pseudowire_detail(struct vty *vty)
611 {
612 struct zebra_vrf *zvrf;
613 struct zebra_pw *pw;
614 struct route_entry *re;
615 struct nexthop *nexthop;
616 struct nexthop_group *nhg;
617
618 zvrf = vrf_info_lookup(VRF_DEFAULT);
619 if (!zvrf)
620 return;
621
622 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
623 char buf_nbr[INET6_ADDRSTRLEN];
624 char buf_nh[100];
625
626 vty_out(vty, "Interface: %s\n", pw->ifname);
627 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
628 vty_out(vty, " Neighbor: %s\n",
629 (pw->af != AF_UNSPEC) ? buf_nbr : "-");
630 if (pw->local_label != MPLS_NO_LABEL)
631 vty_out(vty, " Local Label: %u\n", pw->local_label);
632 else
633 vty_out(vty, " Local Label: %s\n", "-");
634 if (pw->remote_label != MPLS_NO_LABEL)
635 vty_out(vty, " Remote Label: %u\n", pw->remote_label);
636 else
637 vty_out(vty, " Remote Label: %s\n", "-");
638 vty_out(vty, " Protocol: %s\n",
639 zebra_route_string(pw->protocol));
640 if (pw->protocol == ZEBRA_ROUTE_LDP)
641 vty_out(vty, " VC-ID: %u\n", pw->data.ldp.pwid);
642 vty_out(vty, " Status: %s \n",
643 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
644 ? "Up"
645 : "Down");
646 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
647 &pw->nexthop, NULL);
648 if (re == NULL)
649 continue;
650
651 nhg = rib_get_fib_nhg(re);
652 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
653 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
654 nexthop);
655 vty_out(vty, " Next Hop: %s\n", buf_nh);
656 if (nexthop->nh_label)
657 vty_out(vty, " Next Hop label: %u\n",
658 nexthop->nh_label->label[0]);
659 else
660 vty_out(vty, " Next Hop label: %s\n",
661 "-");
662 }
663
664 /* Include any installed backups */
665 nhg = rib_get_fib_backup_nhg(re);
666 if (nhg == NULL)
667 continue;
668
669 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
670 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
671 nexthop);
672 vty_out(vty, " Next Hop: %s\n", buf_nh);
673 if (nexthop->nh_label)
674 vty_out(vty, " Next Hop label: %u\n",
675 nexthop->nh_label->label[0]);
676 else
677 vty_out(vty, " Next Hop label: %s\n",
678 "-");
679 }
680 }
681 }
682
683 static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
684 {
685 struct route_entry *re;
686 struct nexthop *nexthop;
687 struct nexthop_group *nhg;
688 char buf_nbr[INET6_ADDRSTRLEN];
689 char buf_nh[100];
690 json_object *json_pw = NULL;
691 json_object *json_nexthop = NULL;
692 json_object *json_nexthops = NULL;
693
694 json_nexthops = json_object_new_array();
695 json_pw = json_object_new_object();
696
697 json_object_string_add(json_pw, "interface", pw->ifname);
698 if (pw->af == AF_UNSPEC)
699 json_object_string_add(json_pw, "neighbor", "-");
700 else {
701 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
702 json_object_string_add(json_pw, "neighbor", buf_nbr);
703 }
704 if (pw->local_label != MPLS_NO_LABEL)
705 json_object_int_add(json_pw, "localLabel", pw->local_label);
706 else
707 json_object_string_add(json_pw, "localLabel", "-");
708 if (pw->remote_label != MPLS_NO_LABEL)
709 json_object_int_add(json_pw, "remoteLabel", pw->remote_label);
710 else
711 json_object_string_add(json_pw, "remoteLabel", "-");
712 json_object_string_add(json_pw, "protocol",
713 zebra_route_string(pw->protocol));
714 if (pw->protocol == ZEBRA_ROUTE_LDP)
715 json_object_int_add(json_pw, "vcId", pw->data.ldp.pwid);
716 json_object_string_add(
717 json_pw, "Status",
718 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING) ? "Up"
719 : "Down");
720 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
721 &pw->nexthop, NULL);
722 if (re == NULL)
723 goto done;
724
725 nhg = rib_get_fib_nhg(re);
726 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
727 json_nexthop = json_object_new_object();
728 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
729 json_object_string_add(json_nexthop, "nexthop", buf_nh);
730 if (nexthop->nh_label)
731 json_object_int_add(
732 json_nexthop, "nhLabel",
733 nexthop->nh_label->label[0]);
734 else
735 json_object_string_add(json_nexthop, "nhLabel",
736 "-");
737
738 json_object_array_add(json_nexthops, json_nexthop);
739 }
740
741 /* Include installed backup nexthops also */
742 nhg = rib_get_fib_backup_nhg(re);
743 if (nhg == NULL)
744 goto done;
745
746 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
747 json_nexthop = json_object_new_object();
748 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
749 json_object_string_add(json_nexthop, "nexthop", buf_nh);
750 if (nexthop->nh_label)
751 json_object_int_add(
752 json_nexthop, "nhLabel",
753 nexthop->nh_label->label[0]);
754 else
755 json_object_string_add(json_nexthop, "nhLabel",
756 "-");
757
758 json_object_array_add(json_nexthops, json_nexthop);
759 }
760
761 done:
762
763 json_object_object_add(json_pw, "nexthops", json_nexthops);
764 json_object_array_add(json_pws, json_pw);
765 }
766
767 static void vty_show_mpls_pseudowire_detail_json(struct vty *vty)
768 {
769 json_object *json = NULL;
770 json_object *json_pws = NULL;
771 struct zebra_vrf *zvrf;
772 struct zebra_pw *pw;
773
774 zvrf = vrf_info_lookup(VRF_DEFAULT);
775 if (!zvrf)
776 return;
777
778 json = json_object_new_object();
779 json_pws = json_object_new_array();
780 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
781 vty_show_mpls_pseudowire(pw, json_pws);
782 }
783 json_object_object_add(json, "pw", json_pws);
784 vty_json(vty, json);
785 }
786
787 DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd,
788 "show mpls pseudowires detail [json]$json",
789 SHOW_STR MPLS_STR
790 "Pseudowires\n"
791 "Detailed output\n" JSON_STR)
792 {
793 bool uj = use_json(argc, argv);
794
795 if (uj)
796 vty_show_mpls_pseudowire_detail_json(vty);
797 else
798 vty_show_mpls_pseudowire_detail(vty);
799
800 return CMD_SUCCESS;
801 }
802
803 /* Pseudowire configuration write function. */
804 static int zebra_pw_config(struct vty *vty)
805 {
806 int write = 0;
807 struct zebra_vrf *zvrf;
808 struct zebra_pw *pw;
809
810 zvrf = vrf_info_lookup(VRF_DEFAULT);
811 if (!zvrf)
812 return 0;
813
814 RB_FOREACH (pw, zebra_static_pw_head, &zvrf->static_pseudowires) {
815 vty_out(vty, "pseudowire %s\n", pw->ifname);
816 if (pw->local_label != MPLS_NO_LABEL
817 && pw->remote_label != MPLS_NO_LABEL)
818 vty_out(vty, " mpls label local %u remote %u\n",
819 pw->local_label, pw->remote_label);
820 else
821 vty_out(vty,
822 " ! Incomplete config, specify the static MPLS labels\n");
823
824 if (pw->af != AF_UNSPEC) {
825 char buf[INET6_ADDRSTRLEN];
826 inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
827 vty_out(vty, " neighbor %s\n", buf);
828 } else
829 vty_out(vty,
830 " ! Incomplete config, specify a neighbor address\n");
831
832 if (!(pw->flags & F_PSEUDOWIRE_CWORD))
833 vty_out(vty, " control-word exclude\n");
834
835 vty_out(vty, "exit\n");
836 vty_out(vty, "!\n");
837 write = 1;
838 }
839
840 return write;
841 }
842
843 static int zebra_pw_config(struct vty *vty);
844 static struct cmd_node pw_node = {
845 .name = "pw",
846 .node = PW_NODE,
847 .parent_node = CONFIG_NODE,
848 .prompt = "%s(config-pw)# ",
849 .config_write = zebra_pw_config,
850 };
851
852 void zebra_pw_vty_init(void)
853 {
854 install_node(&pw_node);
855 install_default(PW_NODE);
856
857 install_element(CONFIG_NODE, &pseudowire_if_cmd);
858 install_element(CONFIG_NODE, &no_pseudowire_if_cmd);
859 install_element(PW_NODE, &pseudowire_labels_cmd);
860 install_element(PW_NODE, &pseudowire_neighbor_cmd);
861 install_element(PW_NODE, &pseudowire_control_word_cmd);
862
863 install_element(VIEW_NODE, &show_pseudowires_cmd);
864 install_element(VIEW_NODE, &show_pseudowires_detail_cmd);
865 }