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