2 * Copyright (C) 2016 Volta Networks, Inc.
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, 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.
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,
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"
38 DEFINE_MTYPE_STATIC(LIB
, PW
, "Pseudowire");
40 DEFINE_QOBJ_TYPE(zebra_pw
);
42 DEFINE_HOOK(pw_install
, (struct zebra_pw
* pw
), (pw
));
43 DEFINE_HOOK(pw_uninstall
, (struct zebra_pw
* pw
), (pw
));
45 #define MPLS_NO_LABEL MPLS_INVALID_LABEL
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);
54 static inline int zebra_pw_compare(const struct zebra_pw
*a
,
55 const struct zebra_pw
*b
)
57 return (strcmp(a
->ifname
, b
->ifname
));
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
)
63 struct zebra_pw
*zebra_pw_add(struct zebra_vrf
*zvrf
, const char *ifname
,
64 uint8_t protocol
, struct zserv
*client
)
68 if (IS_ZEBRA_DEBUG_PW
)
69 zlog_debug("%u: adding pseudowire %s protocol %s",
70 zvrf_id(zvrf
), ifname
, zebra_route_string(protocol
));
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
);
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
;
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
);
91 void zebra_pw_del(struct zebra_vrf
*zvrf
, struct zebra_pw
*pw
)
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
));
97 /* remove nexthop tracking */
98 zebra_deregister_rnh_pseudowire(pw
->vrf_id
, pw
);
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
);
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
);
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
)
119 pw
->ifindex
= ifindex
;
122 pw
->nexthop
= *nexthop
;
123 pw
->local_label
= local_label
;
124 pw
->remote_label
= remote_label
;
128 if (zebra_pw_enabled(pw
)) {
130 zebra_register_rnh_pseudowire(pw
->vrf_id
, pw
, &nht_exists
);
134 if (pw
->protocol
== ZEBRA_ROUTE_STATIC
)
135 zebra_deregister_rnh_pseudowire(pw
->vrf_id
, pw
);
136 zebra_pw_uninstall(pw
);
140 struct zebra_pw
*zebra_pw_find(struct zebra_vrf
*zvrf
, const char *ifname
)
143 strlcpy(pw
.ifname
, ifname
, sizeof(pw
.ifname
));
144 return (RB_FIND(zebra_pw_head
, &zvrf
->pseudowires
, &pw
));
147 static int zebra_pw_enabled(struct zebra_pw
*pw
)
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
)
158 void zebra_pw_update(struct zebra_pw
*pw
)
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 */
166 * Install or reinstall the pseudowire (e.g. to update
167 * parameters like the nexthop or the use of the control word).
169 zebra_pw_install(pw
);
173 static void zebra_pw_install(struct zebra_pw
*pw
)
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
));
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
);
186 if (pw
->status
!= PW_FORWARDING
)
187 zebra_pw_update_status(pw
, PW_FORWARDING
);
190 static void zebra_pw_uninstall(struct zebra_pw
*pw
)
192 if (pw
->status
!= PW_FORWARDING
)
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
));
200 /* ignore any possible error */
201 hook_call(pw_uninstall
, pw
);
202 dplane_pw_uninstall(pw
);
204 if (zebra_pw_enabled(pw
))
205 zebra_pw_update_status(pw
, PW_NOT_FORWARDING
);
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.
214 void zebra_pw_install_failure(struct zebra_pw
*pw
, int pwstatus
)
216 if (IS_ZEBRA_DEBUG_PW
)
218 "%u: failed installing pseudowire %s, scheduling retry in %u seconds",
219 pw
->vrf_id
, pw
->ifname
, PW_INSTALL_RETRY_INTERVAL
);
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
);
226 zebra_pw_update_status(pw
, pwstatus
);
229 static int zebra_pw_install_retry(struct thread
*thread
)
231 struct zebra_pw
*pw
= THREAD_ARG(thread
);
233 pw
->install_retry_timer
= NULL
;
234 zebra_pw_install(pw
);
239 static void zebra_pw_update_status(struct zebra_pw
*pw
, int status
)
243 zsend_pw_update(pw
->client
, pw
);
246 static int zebra_pw_check_reachability_strict(const struct zebra_pw
*pw
,
247 struct route_entry
*re
)
249 const struct nexthop
*nexthop
;
250 const struct nexthop_group
*nhg
;
251 bool found_p
= false;
254 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
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.
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
))
266 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
267 if (nexthop
->nh_label
!= NULL
)
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
))
286 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
287 if (nexthop
->nh_label
!= NULL
)
299 if (fail_p
|| !found_p
) {
300 if (IS_ZEBRA_DEBUG_PW
)
301 zlog_debug("%s: unlabeled route for %s",
302 __func__
, pw
->ifname
);
309 static int zebra_pw_check_reachability(const struct zebra_pw
*pw
)
311 struct route_entry
*re
;
312 const struct nexthop
*nexthop
;
313 const struct nexthop_group
*nhg
;
314 bool found_p
= false;
316 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
318 /* Find route to the remote end of the pseudowire */
319 re
= rib_match(family2afi(pw
->af
), SAFI_UNICAST
, pw
->vrf_id
,
322 if (IS_ZEBRA_DEBUG_PW
)
323 zlog_debug("%s: no route found for %s", __func__
,
328 /* Stricter checking for some OSes (OBSD, e.g.) */
329 if (mpls_pw_reach_strict
)
330 return zebra_pw_check_reachability_strict(pw
, re
);
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.
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
))
342 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
) &&
343 nexthop
->nh_label
!= NULL
) {
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
))
359 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
) &&
360 nexthop
->nh_label
!= NULL
) {
368 if (IS_ZEBRA_DEBUG_PW
)
369 zlog_debug("%s: unlabeled route for %s",
370 __func__
, pw
->ifname
);
377 static int zebra_pw_client_close(struct zserv
*client
)
380 struct zebra_vrf
*zvrf
;
381 struct zebra_pw
*pw
, *tmp
;
383 RB_FOREACH (vrf
, vrf_id_head
, &vrfs_by_id
) {
385 RB_FOREACH_SAFE (pw
, zebra_pw_head
, &zvrf
->pseudowires
, tmp
) {
386 if (pw
->client
!= client
)
388 zebra_pw_del(zvrf
, pw
);
395 void zebra_pw_init(struct zebra_vrf
*zvrf
)
397 RB_INIT(zebra_pw_head
, &zvrf
->pseudowires
);
398 RB_INIT(zebra_static_pw_head
, &zvrf
->static_pseudowires
);
400 hook_register(zserv_client_close
, zebra_pw_client_close
);
403 void zebra_pw_exit(struct zebra_vrf
*zvrf
)
407 while (!RB_EMPTY(zebra_pw_head
, &zvrf
->pseudowires
)) {
408 pw
= RB_ROOT(zebra_pw_head
, &zvrf
->pseudowires
);
410 zebra_pw_del(zvrf
, pw
);
414 DEFUN_NOSH (pseudowire_if
,
417 "Static pseudowire configuration\n"
420 struct zebra_vrf
*zvrf
;
425 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
429 argv_find(argv
, argc
, "IFNAME", &idx
);
430 ifname
= argv
[idx
]->arg
;
432 pw
= zebra_pw_find(zvrf
, ifname
);
433 if (pw
&& pw
->protocol
!= ZEBRA_ROUTE_STATIC
) {
434 vty_out(vty
, "%% Pseudowire is not static\n");
439 pw
= zebra_pw_add(zvrf
, ifname
, ZEBRA_ROUTE_STATIC
, NULL
);
440 VTY_PUSH_CONTEXT(PW_NODE
, pw
);
445 DEFUN (no_pseudowire_if
,
446 no_pseudowire_if_cmd
,
447 "no pseudowire IFNAME",
449 "Static pseudowire configuration\n"
452 struct zebra_vrf
*zvrf
;
457 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
461 argv_find(argv
, argc
, "IFNAME", &idx
);
462 ifname
= argv
[idx
]->arg
;
464 pw
= zebra_pw_find(zvrf
, ifname
);
466 if (pw
->protocol
!= ZEBRA_ROUTE_STATIC
) {
467 vty_out(vty
, "%% Pseudowire is not static\n");
470 zebra_pw_del(zvrf
, pw
);
476 DEFUN (pseudowire_labels
,
477 pseudowire_labels_cmd
,
478 "[no] mpls label local (16-1048575) remote (16-1048575)",
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")
487 VTY_DECLVAR_CONTEXT(zebra_pw
, pw
);
489 mpls_label_t local_label
, remote_label
;
491 if (argv_find(argv
, argc
, "no", &idx
)) {
492 local_label
= MPLS_NO_LABEL
;
493 remote_label
= MPLS_NO_LABEL
;
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
);
501 zebra_pw_change(pw
, pw
->ifindex
, pw
->type
, pw
->af
, &pw
->nexthop
,
502 local_label
, remote_label
, pw
->flags
, &pw
->data
);
507 DEFUN (pseudowire_neighbor
,
508 pseudowire_neighbor_cmd
,
509 "[no] neighbor <A.B.C.D|X:X::X:X>",
511 "Specify the IPv4 or IPv6 address of the remote endpoint\n"
515 VTY_DECLVAR_CONTEXT(zebra_pw
, pw
);
519 union g_addr nexthop
;
522 memset(&nexthop
, 0, sizeof(nexthop
));
524 if (!argv_find(argv
, argc
, "no", &idx
)) {
525 argv_find(argv
, argc
, "neighbor", &idx
);
526 address
= argv
[idx
+ 1]->arg
;
528 if (inet_pton(AF_INET
, address
, &nexthop
.ipv4
) == 1)
530 else if (inet_pton(AF_INET6
, address
, &nexthop
.ipv6
) == 1)
533 vty_out(vty
, "%% Malformed address\n");
538 zebra_pw_change(pw
, pw
->ifindex
, pw
->type
, af
, &nexthop
,
539 pw
->local_label
, pw
->remote_label
, pw
->flags
,
545 DEFUN (pseudowire_control_word
,
546 pseudowire_control_word_cmd
,
547 "[no] control-word <exclude|include>",
549 "Control-word options\n"
550 "Exclude control-word in pseudowire packets\n"
551 "Include control-word in pseudowire packets\n")
553 VTY_DECLVAR_CONTEXT(zebra_pw
, pw
);
557 if (argv_find(argv
, argc
, "no", &idx
))
558 flags
= F_PSEUDOWIRE_CWORD
;
560 argv_find(argv
, argc
, "control-word", &idx
);
561 if (argv
[idx
+ 1]->text
[0] == 'i')
562 flags
= F_PSEUDOWIRE_CWORD
;
565 zebra_pw_change(pw
, pw
->ifindex
, pw
->type
, pw
->af
, &pw
->nexthop
,
566 pw
->local_label
, pw
->remote_label
, flags
, &pw
->data
);
571 DEFUN (show_pseudowires
,
572 show_pseudowires_cmd
,
573 "show mpls pseudowires",
578 struct zebra_vrf
*zvrf
;
581 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
585 vty_out(vty
, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
586 "Labels", "Protocol", "Status");
588 RB_FOREACH (pw
, zebra_pw_head
, &zvrf
->pseudowires
) {
589 char buf_nbr
[INET6_ADDRSTRLEN
];
592 inet_ntop(pw
->af
, &pw
->nexthop
, buf_nbr
, sizeof(buf_nbr
));
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
);
599 snprintf(buf_labels
, sizeof(buf_labels
), "-");
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
)
612 static void vty_show_mpls_pseudowire_detail(struct vty
*vty
)
614 struct zebra_vrf
*zvrf
;
616 struct route_entry
*re
;
617 struct nexthop
*nexthop
;
618 struct nexthop_group
*nhg
;
620 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
624 RB_FOREACH (pw
, zebra_pw_head
, &zvrf
->pseudowires
) {
625 char buf_nbr
[INET6_ADDRSTRLEN
];
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
);
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
);
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
)
648 re
= rib_match(family2afi(pw
->af
), SAFI_UNICAST
, pw
->vrf_id
,
653 nhg
= rib_get_fib_nhg(re
);
654 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
655 snprintfrr(buf_nh
, sizeof(buf_nh
), "%pNHv",
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]);
662 vty_out(vty
, " Next Hop label: %s\n",
666 /* Include any installed backups */
667 nhg
= rib_get_fib_backup_nhg(re
);
671 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
672 snprintfrr(buf_nh
, sizeof(buf_nh
), "%pNHv",
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]);
679 vty_out(vty
, " Next Hop label: %s\n",
685 static void vty_show_mpls_pseudowire(struct zebra_pw
*pw
, json_object
*json_pws
)
687 struct route_entry
*re
;
688 struct nexthop
*nexthop
;
689 struct nexthop_group
*nhg
;
690 char buf_nbr
[INET6_ADDRSTRLEN
];
692 json_object
*json_pw
= NULL
;
693 json_object
*json_nexthop
= NULL
;
694 json_object
*json_nexthops
= NULL
;
696 json_nexthops
= json_object_new_array();
697 json_pw
= json_object_new_object();
699 json_object_string_add(json_pw
, "interface", pw
->ifname
);
700 if (pw
->af
== AF_UNSPEC
)
701 json_object_string_add(json_pw
, "neighbor", "-");
703 inet_ntop(pw
->af
, &pw
->nexthop
, buf_nbr
, sizeof(buf_nbr
));
704 json_object_string_add(json_pw
, "neighbor", buf_nbr
);
706 if (pw
->local_label
!= MPLS_NO_LABEL
)
707 json_object_int_add(json_pw
, "localLabel", pw
->local_label
);
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
);
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(
720 (zebra_pw_enabled(pw
) && pw
->status
== PW_FORWARDING
) ? "Up"
722 re
= rib_match(family2afi(pw
->af
), SAFI_UNICAST
, pw
->vrf_id
,
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
)
734 json_nexthop
, "nhLabel",
735 nexthop
->nh_label
->label
[0]);
737 json_object_string_add(json_nexthop
, "nhLabel",
740 json_object_array_add(json_nexthops
, json_nexthop
);
743 /* Include installed backup nexthops also */
744 nhg
= rib_get_fib_backup_nhg(re
);
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
)
754 json_nexthop
, "nhLabel",
755 nexthop
->nh_label
->label
[0]);
757 json_object_string_add(json_nexthop
, "nhLabel",
760 json_object_array_add(json_nexthops
, json_nexthop
);
765 json_object_object_add(json_pw
, "nexthops", json_nexthops
);
766 json_object_array_add(json_pws
, json_pw
);
769 static void vty_show_mpls_pseudowire_detail_json(struct vty
*vty
)
771 json_object
*json
= NULL
;
772 json_object
*json_pws
= NULL
;
773 struct zebra_vrf
*zvrf
;
776 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
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
);
785 json_object_object_add(json
, "pw", json_pws
);
787 json_object_to_json_string_ext(json
, JSON_C_TO_STRING_PRETTY
));
788 json_object_free(json
);
791 DEFUN(show_pseudowires_detail
, show_pseudowires_detail_cmd
,
792 "show mpls pseudowires detail [json]$json",
795 "Detailed output\n" JSON_STR
)
797 bool uj
= use_json(argc
, argv
);
800 vty_show_mpls_pseudowire_detail_json(vty
);
802 vty_show_mpls_pseudowire_detail(vty
);
807 /* Pseudowire configuration write function. */
808 static int zebra_pw_config(struct vty
*vty
)
811 struct zebra_vrf
*zvrf
;
814 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
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
);
826 " ! Incomplete config, specify the static MPLS labels\n");
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
);
834 " ! Incomplete config, specify a neighbor address\n");
836 if (!(pw
->flags
& F_PSEUDOWIRE_CWORD
))
837 vty_out(vty
, " control-word exclude\n");
846 static int zebra_pw_config(struct vty
*vty
);
847 static struct cmd_node pw_node
= {
850 .parent_node
= CONFIG_NODE
,
851 .prompt
= "%s(config-pw)# ",
852 .config_write
= zebra_pw_config
,
855 void zebra_pw_vty_init(void)
857 install_node(&pw_node
);
858 install_default(PW_NODE
);
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
);
866 install_element(VIEW_NODE
, &show_pseudowires_cmd
);
867 install_element(VIEW_NODE
, &show_pseudowires_detail_cmd
);