1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2016 Volta Networks, Inc.
16 #include "zebra/debug.h"
17 #include "zebra/rib.h"
18 #include "zebra/zebra_router.h"
19 #include "zebra/zapi_msg.h"
20 #include "zebra/zebra_rnh.h"
21 #include "zebra/zebra_vrf.h"
22 #include "zebra/zebra_pw.h"
24 DEFINE_MTYPE_STATIC(LIB
, PW
, "Pseudowire");
26 DEFINE_QOBJ_TYPE(zebra_pw
);
28 DEFINE_HOOK(pw_install
, (struct zebra_pw
* pw
), (pw
));
29 DEFINE_HOOK(pw_uninstall
, (struct zebra_pw
* pw
), (pw
));
31 #define MPLS_NO_LABEL MPLS_INVALID_LABEL
33 static int zebra_pw_enabled(struct zebra_pw
*);
34 static void zebra_pw_install(struct zebra_pw
*);
35 static void zebra_pw_uninstall(struct zebra_pw
*);
36 static void zebra_pw_install_retry(struct thread
*thread
);
37 static int zebra_pw_check_reachability(const struct zebra_pw
*);
38 static void zebra_pw_update_status(struct zebra_pw
*, int);
40 static inline int zebra_pw_compare(const struct zebra_pw
*a
,
41 const struct zebra_pw
*b
)
43 return (strcmp(a
->ifname
, b
->ifname
));
46 RB_GENERATE(zebra_pw_head
, zebra_pw
, pw_entry
, zebra_pw_compare
)
47 RB_GENERATE(zebra_static_pw_head
, zebra_pw
, static_pw_entry
, zebra_pw_compare
)
49 struct zebra_pw
*zebra_pw_add(struct zebra_vrf
*zvrf
, const char *ifname
,
50 uint8_t protocol
, struct zserv
*client
)
54 if (IS_ZEBRA_DEBUG_PW
)
55 zlog_debug("%u: adding pseudowire %s protocol %s",
56 zvrf_id(zvrf
), ifname
, zebra_route_string(protocol
));
58 pw
= XCALLOC(MTYPE_PW
, sizeof(*pw
));
59 strlcpy(pw
->ifname
, ifname
, sizeof(pw
->ifname
));
60 pw
->protocol
= protocol
;
61 pw
->vrf_id
= zvrf_id(zvrf
);
63 pw
->status
= PW_NOT_FORWARDING
;
64 pw
->local_label
= MPLS_NO_LABEL
;
65 pw
->remote_label
= MPLS_NO_LABEL
;
66 pw
->flags
= F_PSEUDOWIRE_CWORD
;
68 RB_INSERT(zebra_pw_head
, &zvrf
->pseudowires
, pw
);
69 if (pw
->protocol
== ZEBRA_ROUTE_STATIC
) {
70 RB_INSERT(zebra_static_pw_head
, &zvrf
->static_pseudowires
, pw
);
71 QOBJ_REG(pw
, zebra_pw
);
77 void zebra_pw_del(struct zebra_vrf
*zvrf
, struct zebra_pw
*pw
)
79 if (IS_ZEBRA_DEBUG_PW
)
80 zlog_debug("%u: deleting pseudowire %s protocol %s", pw
->vrf_id
,
81 pw
->ifname
, zebra_route_string(pw
->protocol
));
83 /* remove nexthop tracking */
84 zebra_deregister_rnh_pseudowire(pw
->vrf_id
, pw
);
87 if (pw
->status
== PW_FORWARDING
) {
88 hook_call(pw_uninstall
, pw
);
89 dplane_pw_uninstall(pw
);
92 THREAD_OFF(pw
->install_retry_timer
);
94 /* unlink and release memory */
95 RB_REMOVE(zebra_pw_head
, &zvrf
->pseudowires
, pw
);
96 if (pw
->protocol
== ZEBRA_ROUTE_STATIC
)
97 RB_REMOVE(zebra_static_pw_head
, &zvrf
->static_pseudowires
, pw
);
102 void zebra_pw_change(struct zebra_pw
*pw
, ifindex_t ifindex
, int type
, int af
,
103 union g_addr
*nexthop
, uint32_t local_label
,
104 uint32_t remote_label
, uint8_t flags
,
105 union pw_protocol_fields
*data
)
107 pw
->ifindex
= ifindex
;
110 pw
->nexthop
= *nexthop
;
111 pw
->local_label
= local_label
;
112 pw
->remote_label
= remote_label
;
116 if (zebra_pw_enabled(pw
)) {
118 zebra_register_rnh_pseudowire(pw
->vrf_id
, pw
, &nht_exists
);
122 if (pw
->protocol
== ZEBRA_ROUTE_STATIC
)
123 zebra_deregister_rnh_pseudowire(pw
->vrf_id
, pw
);
124 zebra_pw_uninstall(pw
);
128 struct zebra_pw
*zebra_pw_find(struct zebra_vrf
*zvrf
, const char *ifname
)
131 strlcpy(pw
.ifname
, ifname
, sizeof(pw
.ifname
));
132 return (RB_FIND(zebra_pw_head
, &zvrf
->pseudowires
, &pw
));
135 static int zebra_pw_enabled(struct zebra_pw
*pw
)
137 if (pw
->protocol
== ZEBRA_ROUTE_STATIC
) {
138 if (pw
->local_label
== MPLS_NO_LABEL
139 || pw
->remote_label
== MPLS_NO_LABEL
|| pw
->af
== AF_UNSPEC
)
146 void zebra_pw_update(struct zebra_pw
*pw
)
148 if (zebra_pw_check_reachability(pw
) < 0) {
149 zebra_pw_uninstall(pw
);
150 zebra_pw_install_failure(pw
, PW_NOT_FORWARDING
);
151 /* wait for NHT and try again later */
154 * Install or reinstall the pseudowire (e.g. to update
155 * parameters like the nexthop or the use of the control word).
157 zebra_pw_install(pw
);
161 static void zebra_pw_install(struct zebra_pw
*pw
)
163 if (IS_ZEBRA_DEBUG_PW
)
164 zlog_debug("%u: installing pseudowire %s protocol %s",
165 pw
->vrf_id
, pw
->ifname
,
166 zebra_route_string(pw
->protocol
));
168 hook_call(pw_install
, pw
);
169 if (dplane_pw_install(pw
) == ZEBRA_DPLANE_REQUEST_FAILURE
) {
170 zebra_pw_install_failure(pw
, PW_NOT_FORWARDING
);
174 if (pw
->status
!= PW_FORWARDING
)
175 zebra_pw_update_status(pw
, PW_FORWARDING
);
178 static void zebra_pw_uninstall(struct zebra_pw
*pw
)
180 if (pw
->status
!= PW_FORWARDING
)
183 if (IS_ZEBRA_DEBUG_PW
)
184 zlog_debug("%u: uninstalling pseudowire %s protocol %s",
185 pw
->vrf_id
, pw
->ifname
,
186 zebra_route_string(pw
->protocol
));
188 /* ignore any possible error */
189 hook_call(pw_uninstall
, pw
);
190 dplane_pw_uninstall(pw
);
192 if (zebra_pw_enabled(pw
))
193 zebra_pw_update_status(pw
, PW_NOT_FORWARDING
);
197 * Installation of the pseudowire in the kernel or hardware has failed. This
198 * function will notify the pseudowire client about the failure and schedule
199 * to retry the installation later. This function can be called by an external
200 * agent that performs the pseudowire installation in an asynchronous way.
202 void zebra_pw_install_failure(struct zebra_pw
*pw
, int pwstatus
)
204 if (IS_ZEBRA_DEBUG_PW
)
206 "%u: failed installing pseudowire %s, scheduling retry in %u seconds",
207 pw
->vrf_id
, pw
->ifname
, PW_INSTALL_RETRY_INTERVAL
);
209 /* schedule to retry later */
210 THREAD_OFF(pw
->install_retry_timer
);
211 thread_add_timer(zrouter
.master
, zebra_pw_install_retry
, pw
,
212 PW_INSTALL_RETRY_INTERVAL
, &pw
->install_retry_timer
);
214 zebra_pw_update_status(pw
, pwstatus
);
217 static void zebra_pw_install_retry(struct thread
*thread
)
219 struct zebra_pw
*pw
= THREAD_ARG(thread
);
221 zebra_pw_install(pw
);
224 static void zebra_pw_update_status(struct zebra_pw
*pw
, int status
)
228 zsend_pw_update(pw
->client
, pw
);
231 static int zebra_pw_check_reachability_strict(const struct zebra_pw
*pw
,
232 struct route_entry
*re
)
234 const struct nexthop
*nexthop
;
235 const struct nexthop_group
*nhg
;
236 bool found_p
= false;
239 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
241 /* All active nexthops must be labelled; look at
242 * primary and backup fib lists, in case there's been
243 * a backup nexthop activation.
245 nhg
= rib_get_fib_nhg(re
);
246 if (nhg
&& nhg
->nexthop
) {
247 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
248 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
251 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
252 if (nexthop
->nh_label
!= NULL
)
265 nhg
= rib_get_fib_backup_nhg(re
);
266 if (nhg
&& nhg
->nexthop
) {
267 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
268 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
271 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
272 if (nexthop
->nh_label
!= NULL
)
284 if (fail_p
|| !found_p
) {
285 if (IS_ZEBRA_DEBUG_PW
)
286 zlog_debug("%s: unlabeled route for %s",
287 __func__
, pw
->ifname
);
294 static int zebra_pw_check_reachability(const struct zebra_pw
*pw
)
296 struct route_entry
*re
;
297 const struct nexthop
*nexthop
;
298 const struct nexthop_group
*nhg
;
299 bool found_p
= false;
301 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
303 /* Find route to the remote end of the pseudowire */
304 re
= rib_match(family2afi(pw
->af
), SAFI_UNICAST
, pw
->vrf_id
,
307 if (IS_ZEBRA_DEBUG_PW
)
308 zlog_debug("%s: no route found for %s", __func__
,
313 /* Stricter checking for some OSes (OBSD, e.g.) */
314 if (mpls_pw_reach_strict
)
315 return zebra_pw_check_reachability_strict(pw
, re
);
317 /* There must be at least one installed labelled nexthop;
318 * look at primary and backup fib lists, in case there's been
319 * a backup nexthop activation.
321 nhg
= rib_get_fib_nhg(re
);
322 if (nhg
&& nhg
->nexthop
) {
323 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
324 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
327 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
) &&
328 nexthop
->nh_label
!= NULL
) {
338 nhg
= rib_get_fib_backup_nhg(re
);
339 if (nhg
&& nhg
->nexthop
) {
340 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
341 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
344 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
) &&
345 nexthop
->nh_label
!= NULL
) {
353 if (IS_ZEBRA_DEBUG_PW
)
354 zlog_debug("%s: unlabeled route for %s",
355 __func__
, pw
->ifname
);
362 static int zebra_pw_client_close(struct zserv
*client
)
365 struct zebra_vrf
*zvrf
;
366 struct zebra_pw
*pw
, *tmp
;
368 RB_FOREACH (vrf
, vrf_id_head
, &vrfs_by_id
) {
370 RB_FOREACH_SAFE (pw
, zebra_pw_head
, &zvrf
->pseudowires
, tmp
) {
371 if (pw
->client
!= client
)
373 zebra_pw_del(zvrf
, pw
);
380 void zebra_pw_init(struct zebra_vrf
*zvrf
)
382 RB_INIT(zebra_pw_head
, &zvrf
->pseudowires
);
383 RB_INIT(zebra_static_pw_head
, &zvrf
->static_pseudowires
);
385 hook_register(zserv_client_close
, zebra_pw_client_close
);
388 void zebra_pw_exit(struct zebra_vrf
*zvrf
)
392 while (!RB_EMPTY(zebra_pw_head
, &zvrf
->pseudowires
)) {
393 pw
= RB_ROOT(zebra_pw_head
, &zvrf
->pseudowires
);
395 zebra_pw_del(zvrf
, pw
);
399 DEFUN_NOSH (pseudowire_if
,
402 "Static pseudowire configuration\n"
405 struct zebra_vrf
*zvrf
;
410 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
414 argv_find(argv
, argc
, "IFNAME", &idx
);
415 ifname
= argv
[idx
]->arg
;
417 pw
= zebra_pw_find(zvrf
, ifname
);
418 if (pw
&& pw
->protocol
!= ZEBRA_ROUTE_STATIC
) {
419 vty_out(vty
, "%% Pseudowire is not static\n");
424 pw
= zebra_pw_add(zvrf
, ifname
, ZEBRA_ROUTE_STATIC
, NULL
);
425 VTY_PUSH_CONTEXT(PW_NODE
, pw
);
430 DEFUN (no_pseudowire_if
,
431 no_pseudowire_if_cmd
,
432 "no pseudowire IFNAME",
434 "Static pseudowire configuration\n"
437 struct zebra_vrf
*zvrf
;
442 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
446 argv_find(argv
, argc
, "IFNAME", &idx
);
447 ifname
= argv
[idx
]->arg
;
449 pw
= zebra_pw_find(zvrf
, ifname
);
451 if (pw
->protocol
!= ZEBRA_ROUTE_STATIC
) {
452 vty_out(vty
, "%% Pseudowire is not static\n");
455 zebra_pw_del(zvrf
, pw
);
461 DEFUN (pseudowire_labels
,
462 pseudowire_labels_cmd
,
463 "[no] mpls label local (16-1048575) remote (16-1048575)",
465 "MPLS L2VPN PW command\n"
466 "MPLS L2VPN static labels\n"
467 "Local pseudowire label\n"
468 "Local pseudowire label\n"
469 "Remote pseudowire label\n"
470 "Remote pseudowire label\n")
472 VTY_DECLVAR_CONTEXT(zebra_pw
, pw
);
474 mpls_label_t local_label
, remote_label
;
476 if (argv_find(argv
, argc
, "no", &idx
)) {
477 local_label
= MPLS_NO_LABEL
;
478 remote_label
= MPLS_NO_LABEL
;
480 argv_find(argv
, argc
, "local", &idx
);
481 local_label
= atoi(argv
[idx
+ 1]->arg
);
482 argv_find(argv
, argc
, "remote", &idx
);
483 remote_label
= atoi(argv
[idx
+ 1]->arg
);
486 zebra_pw_change(pw
, pw
->ifindex
, pw
->type
, pw
->af
, &pw
->nexthop
,
487 local_label
, remote_label
, pw
->flags
, &pw
->data
);
492 DEFUN (pseudowire_neighbor
,
493 pseudowire_neighbor_cmd
,
494 "[no] neighbor <A.B.C.D|X:X::X:X>",
496 "Specify the IPv4 or IPv6 address of the remote endpoint\n"
500 VTY_DECLVAR_CONTEXT(zebra_pw
, pw
);
504 union g_addr nexthop
;
507 memset(&nexthop
, 0, sizeof(nexthop
));
509 if (!argv_find(argv
, argc
, "no", &idx
)) {
510 argv_find(argv
, argc
, "neighbor", &idx
);
511 address
= argv
[idx
+ 1]->arg
;
513 if (inet_pton(AF_INET
, address
, &nexthop
.ipv4
) == 1)
515 else if (inet_pton(AF_INET6
, address
, &nexthop
.ipv6
) == 1)
518 vty_out(vty
, "%% Malformed address\n");
523 zebra_pw_change(pw
, pw
->ifindex
, pw
->type
, af
, &nexthop
,
524 pw
->local_label
, pw
->remote_label
, pw
->flags
,
530 DEFUN (pseudowire_control_word
,
531 pseudowire_control_word_cmd
,
532 "[no] control-word <exclude|include>",
534 "Control-word options\n"
535 "Exclude control-word in pseudowire packets\n"
536 "Include control-word in pseudowire packets\n")
538 VTY_DECLVAR_CONTEXT(zebra_pw
, pw
);
542 if (argv_find(argv
, argc
, "no", &idx
))
543 flags
= F_PSEUDOWIRE_CWORD
;
545 argv_find(argv
, argc
, "control-word", &idx
);
546 if (argv
[idx
+ 1]->text
[0] == 'i')
547 flags
= F_PSEUDOWIRE_CWORD
;
550 zebra_pw_change(pw
, pw
->ifindex
, pw
->type
, pw
->af
, &pw
->nexthop
,
551 pw
->local_label
, pw
->remote_label
, flags
, &pw
->data
);
556 DEFUN (show_pseudowires
,
557 show_pseudowires_cmd
,
558 "show mpls pseudowires",
563 struct zebra_vrf
*zvrf
;
566 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
570 vty_out(vty
, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
571 "Labels", "Protocol", "Status");
573 RB_FOREACH (pw
, zebra_pw_head
, &zvrf
->pseudowires
) {
574 char buf_nbr
[INET6_ADDRSTRLEN
];
577 inet_ntop(pw
->af
, &pw
->nexthop
, buf_nbr
, sizeof(buf_nbr
));
579 if (pw
->local_label
!= MPLS_NO_LABEL
580 && pw
->remote_label
!= MPLS_NO_LABEL
)
581 snprintf(buf_labels
, sizeof(buf_labels
), "%u/%u",
582 pw
->local_label
, pw
->remote_label
);
584 snprintf(buf_labels
, sizeof(buf_labels
), "-");
586 vty_out(vty
, "%-16s %-24s %-12s %-8s %-10s\n", pw
->ifname
,
587 (pw
->af
!= AF_UNSPEC
) ? buf_nbr
: "-", buf_labels
,
588 zebra_route_string(pw
->protocol
),
589 (zebra_pw_enabled(pw
) && pw
->status
== PW_FORWARDING
)
597 static void vty_show_mpls_pseudowire_detail(struct vty
*vty
)
599 struct zebra_vrf
*zvrf
;
601 struct route_entry
*re
;
602 struct nexthop
*nexthop
;
603 struct nexthop_group
*nhg
;
605 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
609 RB_FOREACH (pw
, zebra_pw_head
, &zvrf
->pseudowires
) {
610 char buf_nbr
[INET6_ADDRSTRLEN
];
613 vty_out(vty
, "Interface: %s\n", pw
->ifname
);
614 inet_ntop(pw
->af
, &pw
->nexthop
, buf_nbr
, sizeof(buf_nbr
));
615 vty_out(vty
, " Neighbor: %s\n",
616 (pw
->af
!= AF_UNSPEC
) ? buf_nbr
: "-");
617 if (pw
->local_label
!= MPLS_NO_LABEL
)
618 vty_out(vty
, " Local Label: %u\n", pw
->local_label
);
620 vty_out(vty
, " Local Label: %s\n", "-");
621 if (pw
->remote_label
!= MPLS_NO_LABEL
)
622 vty_out(vty
, " Remote Label: %u\n", pw
->remote_label
);
624 vty_out(vty
, " Remote Label: %s\n", "-");
625 vty_out(vty
, " Protocol: %s\n",
626 zebra_route_string(pw
->protocol
));
627 if (pw
->protocol
== ZEBRA_ROUTE_LDP
)
628 vty_out(vty
, " VC-ID: %u\n", pw
->data
.ldp
.pwid
);
629 vty_out(vty
, " Status: %s \n",
630 (zebra_pw_enabled(pw
) && pw
->status
== PW_FORWARDING
)
633 re
= rib_match(family2afi(pw
->af
), SAFI_UNICAST
, pw
->vrf_id
,
638 nhg
= rib_get_fib_nhg(re
);
639 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
640 snprintfrr(buf_nh
, sizeof(buf_nh
), "%pNHv",
642 vty_out(vty
, " Next Hop: %s\n", buf_nh
);
643 if (nexthop
->nh_label
)
644 vty_out(vty
, " Next Hop label: %u\n",
645 nexthop
->nh_label
->label
[0]);
647 vty_out(vty
, " Next Hop label: %s\n",
651 /* Include any installed backups */
652 nhg
= rib_get_fib_backup_nhg(re
);
656 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
657 snprintfrr(buf_nh
, sizeof(buf_nh
), "%pNHv",
659 vty_out(vty
, " Next Hop: %s\n", buf_nh
);
660 if (nexthop
->nh_label
)
661 vty_out(vty
, " Next Hop label: %u\n",
662 nexthop
->nh_label
->label
[0]);
664 vty_out(vty
, " Next Hop label: %s\n",
670 static void vty_show_mpls_pseudowire(struct zebra_pw
*pw
, json_object
*json_pws
)
672 struct route_entry
*re
;
673 struct nexthop
*nexthop
;
674 struct nexthop_group
*nhg
;
675 char buf_nbr
[INET6_ADDRSTRLEN
];
677 json_object
*json_pw
= NULL
;
678 json_object
*json_nexthop
= NULL
;
679 json_object
*json_nexthops
= NULL
;
681 json_nexthops
= json_object_new_array();
682 json_pw
= json_object_new_object();
684 json_object_string_add(json_pw
, "interface", pw
->ifname
);
685 if (pw
->af
== AF_UNSPEC
)
686 json_object_string_add(json_pw
, "neighbor", "-");
688 inet_ntop(pw
->af
, &pw
->nexthop
, buf_nbr
, sizeof(buf_nbr
));
689 json_object_string_add(json_pw
, "neighbor", buf_nbr
);
691 if (pw
->local_label
!= MPLS_NO_LABEL
)
692 json_object_int_add(json_pw
, "localLabel", pw
->local_label
);
694 json_object_string_add(json_pw
, "localLabel", "-");
695 if (pw
->remote_label
!= MPLS_NO_LABEL
)
696 json_object_int_add(json_pw
, "remoteLabel", pw
->remote_label
);
698 json_object_string_add(json_pw
, "remoteLabel", "-");
699 json_object_string_add(json_pw
, "protocol",
700 zebra_route_string(pw
->protocol
));
701 if (pw
->protocol
== ZEBRA_ROUTE_LDP
)
702 json_object_int_add(json_pw
, "vcId", pw
->data
.ldp
.pwid
);
703 json_object_string_add(
705 (zebra_pw_enabled(pw
) && pw
->status
== PW_FORWARDING
) ? "Up"
707 re
= rib_match(family2afi(pw
->af
), SAFI_UNICAST
, pw
->vrf_id
,
712 nhg
= rib_get_fib_nhg(re
);
713 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
714 json_nexthop
= json_object_new_object();
715 snprintfrr(buf_nh
, sizeof(buf_nh
), "%pNHv", nexthop
);
716 json_object_string_add(json_nexthop
, "nexthop", buf_nh
);
717 if (nexthop
->nh_label
)
719 json_nexthop
, "nhLabel",
720 nexthop
->nh_label
->label
[0]);
722 json_object_string_add(json_nexthop
, "nhLabel",
725 json_object_array_add(json_nexthops
, json_nexthop
);
728 /* Include installed backup nexthops also */
729 nhg
= rib_get_fib_backup_nhg(re
);
733 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
734 json_nexthop
= json_object_new_object();
735 snprintfrr(buf_nh
, sizeof(buf_nh
), "%pNHv", nexthop
);
736 json_object_string_add(json_nexthop
, "nexthop", buf_nh
);
737 if (nexthop
->nh_label
)
739 json_nexthop
, "nhLabel",
740 nexthop
->nh_label
->label
[0]);
742 json_object_string_add(json_nexthop
, "nhLabel",
745 json_object_array_add(json_nexthops
, json_nexthop
);
750 json_object_object_add(json_pw
, "nexthops", json_nexthops
);
751 json_object_array_add(json_pws
, json_pw
);
754 static void vty_show_mpls_pseudowire_detail_json(struct vty
*vty
)
756 json_object
*json
= NULL
;
757 json_object
*json_pws
= NULL
;
758 struct zebra_vrf
*zvrf
;
761 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
765 json
= json_object_new_object();
766 json_pws
= json_object_new_array();
767 RB_FOREACH (pw
, zebra_pw_head
, &zvrf
->pseudowires
) {
768 vty_show_mpls_pseudowire(pw
, json_pws
);
770 json_object_object_add(json
, "pw", json_pws
);
774 DEFUN(show_pseudowires_detail
, show_pseudowires_detail_cmd
,
775 "show mpls pseudowires detail [json]$json",
778 "Detailed output\n" JSON_STR
)
780 bool uj
= use_json(argc
, argv
);
783 vty_show_mpls_pseudowire_detail_json(vty
);
785 vty_show_mpls_pseudowire_detail(vty
);
790 /* Pseudowire configuration write function. */
791 static int zebra_pw_config(struct vty
*vty
)
794 struct zebra_vrf
*zvrf
;
797 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
801 RB_FOREACH (pw
, zebra_static_pw_head
, &zvrf
->static_pseudowires
) {
802 vty_out(vty
, "pseudowire %s\n", pw
->ifname
);
803 if (pw
->local_label
!= MPLS_NO_LABEL
804 && pw
->remote_label
!= MPLS_NO_LABEL
)
805 vty_out(vty
, " mpls label local %u remote %u\n",
806 pw
->local_label
, pw
->remote_label
);
809 " ! Incomplete config, specify the static MPLS labels\n");
811 if (pw
->af
!= AF_UNSPEC
) {
812 char buf
[INET6_ADDRSTRLEN
];
813 inet_ntop(pw
->af
, &pw
->nexthop
, buf
, sizeof(buf
));
814 vty_out(vty
, " neighbor %s\n", buf
);
817 " ! Incomplete config, specify a neighbor address\n");
819 if (!(pw
->flags
& F_PSEUDOWIRE_CWORD
))
820 vty_out(vty
, " control-word exclude\n");
822 vty_out(vty
, "exit\n");
830 static int zebra_pw_config(struct vty
*vty
);
831 static struct cmd_node pw_node
= {
834 .parent_node
= CONFIG_NODE
,
835 .prompt
= "%s(config-pw)# ",
836 .config_write
= zebra_pw_config
,
839 void zebra_pw_vty_init(void)
841 install_node(&pw_node
);
842 install_default(PW_NODE
);
844 install_element(CONFIG_NODE
, &pseudowire_if_cmd
);
845 install_element(CONFIG_NODE
, &no_pseudowire_if_cmd
);
846 install_element(PW_NODE
, &pseudowire_labels_cmd
);
847 install_element(PW_NODE
, &pseudowire_neighbor_cmd
);
848 install_element(PW_NODE
, &pseudowire_control_word_cmd
);
850 install_element(VIEW_NODE
, &show_pseudowires_cmd
);
851 install_element(VIEW_NODE
, &show_pseudowires_detail_cmd
);