]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_pw.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / zebra / zebra_pw.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
6833ae01 2/* Zebra PW code
3 * Copyright (C) 2016 Volta Networks, Inc.
6833ae01 4 */
5
6#include <zebra.h>
7
8#include "log.h"
9#include "memory.h"
10#include "thread.h"
2dd0d726 11#include "command.h"
6833ae01 12#include "vrf.h"
6bbdd9e9 13#include "lib/json.h"
14#include "printfrr.h"
6833ae01 15
16#include "zebra/debug.h"
17#include "zebra/rib.h"
3801e764 18#include "zebra/zebra_router.h"
bf094f69 19#include "zebra/zapi_msg.h"
731a75fe 20#include "zebra/zebra_rnh.h"
6833ae01 21#include "zebra/zebra_vrf.h"
22#include "zebra/zebra_pw.h"
23
bf8d3d6a 24DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire");
6833ae01 25
96244aca 26DEFINE_QOBJ_TYPE(zebra_pw);
2dd0d726 27
8451921b
DL
28DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw));
29DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw));
6833ae01 30
69965f53
DL
31#define MPLS_NO_LABEL MPLS_INVALID_LABEL
32
2dd0d726 33static int zebra_pw_enabled(struct zebra_pw *);
6833ae01 34static void zebra_pw_install(struct zebra_pw *);
35static void zebra_pw_uninstall(struct zebra_pw *);
cc9f21da 36static void zebra_pw_install_retry(struct thread *thread);
0d145d47 37static int zebra_pw_check_reachability(const struct zebra_pw *);
6833ae01 38static void zebra_pw_update_status(struct zebra_pw *, int);
39
40static inline int zebra_pw_compare(const struct zebra_pw *a,
41 const struct zebra_pw *b)
42{
43 return (strcmp(a->ifname, b->ifname));
44}
45
2dd0d726
RW
46RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare)
47RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare)
6833ae01 48
49struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
50 uint8_t protocol, struct zserv *client)
51{
52 struct zebra_pw *pw;
53
54 if (IS_ZEBRA_DEBUG_PW)
55 zlog_debug("%u: adding pseudowire %s protocol %s",
56 zvrf_id(zvrf), ifname, zebra_route_string(protocol));
57
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);
62 pw->client = client;
fd563cc7 63 pw->status = PW_NOT_FORWARDING;
2dd0d726
RW
64 pw->local_label = MPLS_NO_LABEL;
65 pw->remote_label = MPLS_NO_LABEL;
66 pw->flags = F_PSEUDOWIRE_CWORD;
6833ae01 67
68 RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw);
2dd0d726
RW
69 if (pw->protocol == ZEBRA_ROUTE_STATIC) {
70 RB_INSERT(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
71 QOBJ_REG(pw, zebra_pw);
72 }
6833ae01 73
74 return pw;
75}
76
77void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw)
78{
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));
82
731a75fe
RW
83 /* remove nexthop tracking */
84 zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
85
6833ae01 86 /* uninstall */
fd563cc7 87 if (pw->status == PW_FORWARDING) {
6833ae01 88 hook_call(pw_uninstall, pw);
97d8d05a 89 dplane_pw_uninstall(pw);
86c4fdfa
DS
90 }
91
92 THREAD_OFF(pw->install_retry_timer);
6833ae01 93
94 /* unlink and release memory */
95 RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw);
2dd0d726
RW
96 if (pw->protocol == ZEBRA_ROUTE_STATIC)
97 RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
86c4fdfa 98
6833ae01 99 XFREE(MTYPE_PW, pw);
100}
101
102void 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)
106{
107 pw->ifindex = ifindex;
108 pw->type = type;
109 pw->af = af;
110 pw->nexthop = *nexthop;
111 pw->local_label = local_label;
112 pw->remote_label = remote_label;
113 pw->flags = flags;
114 pw->data = *data;
115
1fddcd0a
KS
116 if (zebra_pw_enabled(pw)) {
117 bool nht_exists;
118 zebra_register_rnh_pseudowire(pw->vrf_id, pw, &nht_exists);
119 if (nht_exists)
120 zebra_pw_update(pw);
121 } else {
13c46fa1
KS
122 if (pw->protocol == ZEBRA_ROUTE_STATIC)
123 zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
6833ae01 124 zebra_pw_uninstall(pw);
13c46fa1 125 }
6833ae01 126}
127
128struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname)
129{
130 struct zebra_pw pw;
131 strlcpy(pw.ifname, ifname, sizeof(pw.ifname));
132 return (RB_FIND(zebra_pw_head, &zvrf->pseudowires, &pw));
133}
134
2dd0d726
RW
135static int zebra_pw_enabled(struct zebra_pw *pw)
136{
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)
140 return 0;
141 return 1;
142 } else
143 return pw->enabled;
144}
145
6833ae01 146void zebra_pw_update(struct zebra_pw *pw)
147{
148 if (zebra_pw_check_reachability(pw) < 0) {
149 zebra_pw_uninstall(pw);
fd563cc7 150 zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
731a75fe 151 /* wait for NHT and try again later */
6833ae01 152 } else {
153 /*
154 * Install or reinstall the pseudowire (e.g. to update
155 * parameters like the nexthop or the use of the control word).
156 */
157 zebra_pw_install(pw);
158 }
159}
160
161static void zebra_pw_install(struct zebra_pw *pw)
162{
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));
167
97d8d05a
MS
168 hook_call(pw_install, pw);
169 if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) {
fd563cc7 170 zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
6833ae01 171 return;
172 }
173
fd563cc7
KS
174 if (pw->status != PW_FORWARDING)
175 zebra_pw_update_status(pw, PW_FORWARDING);
6833ae01 176}
177
178static void zebra_pw_uninstall(struct zebra_pw *pw)
179{
fd563cc7 180 if (pw->status != PW_FORWARDING)
6833ae01 181 return;
182
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));
187
188 /* ignore any possible error */
189 hook_call(pw_uninstall, pw);
97d8d05a 190 dplane_pw_uninstall(pw);
6833ae01 191
2dd0d726 192 if (zebra_pw_enabled(pw))
fd563cc7 193 zebra_pw_update_status(pw, PW_NOT_FORWARDING);
6833ae01 194}
195
196/*
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.
201 */
fd563cc7 202void zebra_pw_install_failure(struct zebra_pw *pw, int pwstatus)
6833ae01 203{
204 if (IS_ZEBRA_DEBUG_PW)
205 zlog_debug(
3efd0893 206 "%u: failed installing pseudowire %s, scheduling retry in %u seconds",
6833ae01 207 pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL);
208
209 /* schedule to retry later */
146bcb9b 210 THREAD_OFF(pw->install_retry_timer);
3801e764 211 thread_add_timer(zrouter.master, zebra_pw_install_retry, pw,
69965f53 212 PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer);
6833ae01 213
fd563cc7 214 zebra_pw_update_status(pw, pwstatus);
6833ae01 215}
216
cc9f21da 217static void zebra_pw_install_retry(struct thread *thread)
6833ae01 218{
219 struct zebra_pw *pw = THREAD_ARG(thread);
220
6833ae01 221 zebra_pw_install(pw);
6833ae01 222}
223
224static void zebra_pw_update_status(struct zebra_pw *pw, int status)
225{
226 pw->status = status;
227 if (pw->client)
228 zsend_pw_update(pw->client, pw);
229}
230
0d145d47
MS
231static int zebra_pw_check_reachability_strict(const struct zebra_pw *pw,
232 struct route_entry *re)
233{
234 const struct nexthop *nexthop;
235 const struct nexthop_group *nhg;
236 bool found_p = false;
237 bool fail_p = false;
238
239 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
240
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.
244 */
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))
249 continue;
250
251 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
252 if (nexthop->nh_label != NULL)
253 found_p = true;
254 else {
255 fail_p = true;
256 break;
257 }
258 }
259 }
260 }
261
262 if (fail_p)
263 goto done;
264
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))
269 continue;
270
271 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
272 if (nexthop->nh_label != NULL)
273 found_p = true;
274 else {
275 fail_p = true;
276 break;
277 }
278 }
279 }
280 }
281
282done:
283
284 if (fail_p || !found_p) {
285 if (IS_ZEBRA_DEBUG_PW)
286 zlog_debug("%s: unlabeled route for %s",
287 __func__, pw->ifname);
288 return -1;
289 }
290
291 return 0;
292}
293
294static int zebra_pw_check_reachability(const struct zebra_pw *pw)
6833ae01 295{
69965f53 296 struct route_entry *re;
0d145d47
MS
297 const struct nexthop *nexthop;
298 const struct nexthop_group *nhg;
299 bool found_p = false;
6833ae01 300
301 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
302
0d145d47 303 /* Find route to the remote end of the pseudowire */
69965f53
DL
304 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
305 &pw->nexthop, NULL);
306 if (!re) {
6833ae01 307 if (IS_ZEBRA_DEBUG_PW)
9df414fe
QY
308 zlog_debug("%s: no route found for %s", __func__,
309 pw->ifname);
6833ae01 310 return -1;
311 }
312
0d145d47
MS
313 /* Stricter checking for some OSes (OBSD, e.g.) */
314 if (mpls_pw_reach_strict)
315 return zebra_pw_check_reachability_strict(pw, re);
316
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.
6833ae01 320 */
0d145d47
MS
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))
325 continue;
326
327 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
328 nexthop->nh_label != NULL) {
329 found_p = true;
330 break;
331 }
332 }
333 }
334
335 if (found_p)
336 return 0;
337
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))
342 continue;
343
344 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
345 nexthop->nh_label != NULL) {
346 found_p = true;
347 break;
348 }
6833ae01 349 }
350 }
351
0d145d47
MS
352 if (!found_p) {
353 if (IS_ZEBRA_DEBUG_PW)
354 zlog_debug("%s: unlabeled route for %s",
355 __func__, pw->ifname);
356 return -1;
357 }
358
6833ae01 359 return 0;
360}
361
453844ab 362static int zebra_pw_client_close(struct zserv *client)
6833ae01 363{
364 struct vrf *vrf;
365 struct zebra_vrf *zvrf;
366 struct zebra_pw *pw, *tmp;
367
a2addae8 368 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
6833ae01 369 zvrf = vrf->info;
a2addae8 370 RB_FOREACH_SAFE (pw, zebra_pw_head, &zvrf->pseudowires, tmp) {
6833ae01 371 if (pw->client != client)
372 continue;
373 zebra_pw_del(zvrf, pw);
374 }
375 }
453844ab
QY
376
377 return 0;
6833ae01 378}
379
380void zebra_pw_init(struct zebra_vrf *zvrf)
381{
69965f53
DL
382 RB_INIT(zebra_pw_head, &zvrf->pseudowires);
383 RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires);
453844ab 384
21ccc0cf 385 hook_register(zserv_client_close, zebra_pw_client_close);
6833ae01 386}
387
388void zebra_pw_exit(struct zebra_vrf *zvrf)
389{
390 struct zebra_pw *pw;
391
55cd0f61
DS
392 while (!RB_EMPTY(zebra_pw_head, &zvrf->pseudowires)) {
393 pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires);
394
6833ae01 395 zebra_pw_del(zvrf, pw);
55cd0f61 396 }
6833ae01 397}
2dd0d726
RW
398
399DEFUN_NOSH (pseudowire_if,
400 pseudowire_if_cmd,
1e9d1183 401 "pseudowire IFNAME",
2dd0d726
RW
402 "Static pseudowire configuration\n"
403 "Pseudowire name\n")
404{
405 struct zebra_vrf *zvrf;
406 struct zebra_pw *pw;
2dd0d726 407 const char *ifname;
1e9d1183 408 int idx = 0;
2dd0d726
RW
409
410 zvrf = vrf_info_lookup(VRF_DEFAULT);
411 if (!zvrf)
412 return CMD_WARNING;
413
414 argv_find(argv, argc, "IFNAME", &idx);
415 ifname = argv[idx]->arg;
1e9d1183 416
2dd0d726
RW
417 pw = zebra_pw_find(zvrf, ifname);
418 if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
69965f53 419 vty_out(vty, "%% Pseudowire is not static\n");
2dd0d726
RW
420 return CMD_WARNING;
421 }
422
2dd0d726
RW
423 if (!pw)
424 pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
425 VTY_PUSH_CONTEXT(PW_NODE, pw);
426
427 return CMD_SUCCESS;
428}
429
1e9d1183
RW
430DEFUN (no_pseudowire_if,
431 no_pseudowire_if_cmd,
432 "no pseudowire IFNAME",
433 NO_STR
434 "Static pseudowire configuration\n"
435 "Pseudowire name\n")
436{
437 struct zebra_vrf *zvrf;
438 struct zebra_pw *pw;
439 const char *ifname;
440 int idx = 0;
441
442 zvrf = vrf_info_lookup(VRF_DEFAULT);
443 if (!zvrf)
444 return CMD_WARNING;
445
446 argv_find(argv, argc, "IFNAME", &idx);
447 ifname = argv[idx]->arg;
448
449 pw = zebra_pw_find(zvrf, ifname);
450 if (pw) {
451 if (pw->protocol != ZEBRA_ROUTE_STATIC) {
452 vty_out(vty, "%% Pseudowire is not static\n");
453 return CMD_WARNING;
454 }
455 zebra_pw_del(zvrf, pw);
456 }
457
458 return CMD_SUCCESS;
459}
460
2dd0d726
RW
461DEFUN (pseudowire_labels,
462 pseudowire_labels_cmd,
463 "[no] mpls label local (16-1048575) remote (16-1048575)",
464 NO_STR
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")
471{
472 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
473 int idx = 0;
474 mpls_label_t local_label, remote_label;
475
476 if (argv_find(argv, argc, "no", &idx)) {
477 local_label = MPLS_NO_LABEL;
478 remote_label = MPLS_NO_LABEL;
479 } else {
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);
484 }
485
486 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
487 local_label, remote_label, pw->flags, &pw->data);
488
489 return CMD_SUCCESS;
490}
491
492DEFUN (pseudowire_neighbor,
493 pseudowire_neighbor_cmd,
494 "[no] neighbor <A.B.C.D|X:X::X:X>",
495 NO_STR
496 "Specify the IPv4 or IPv6 address of the remote endpoint\n"
497 "IPv4 address\n"
498 "IPv6 address\n")
499{
500 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
501 int idx = 0;
502 const char *address;
503 int af;
504 union g_addr nexthop;
505
506 af = AF_UNSPEC;
507 memset(&nexthop, 0, sizeof(nexthop));
508
509 if (!argv_find(argv, argc, "no", &idx)) {
510 argv_find(argv, argc, "neighbor", &idx);
511 address = argv[idx + 1]->arg;
512
513 if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1)
514 af = AF_INET;
515 else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1)
516 af = AF_INET6;
517 else {
69965f53 518 vty_out(vty, "%% Malformed address\n");
2dd0d726
RW
519 return CMD_WARNING;
520 }
521 }
522
523 zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop,
524 pw->local_label, pw->remote_label, pw->flags,
525 &pw->data);
526
527 return CMD_SUCCESS;
528}
529
530DEFUN (pseudowire_control_word,
531 pseudowire_control_word_cmd,
532 "[no] control-word <exclude|include>",
533 NO_STR
534 "Control-word options\n"
535 "Exclude control-word in pseudowire packets\n"
536 "Include control-word in pseudowire packets\n")
537{
538 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
539 int idx = 0;
540 uint8_t flags = 0;
541
542 if (argv_find(argv, argc, "no", &idx))
543 flags = F_PSEUDOWIRE_CWORD;
544 else {
545 argv_find(argv, argc, "control-word", &idx);
546 if (argv[idx + 1]->text[0] == 'i')
547 flags = F_PSEUDOWIRE_CWORD;
548 }
549
550 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
551 pw->local_label, pw->remote_label, flags, &pw->data);
552
553 return CMD_SUCCESS;
554}
555
556DEFUN (show_pseudowires,
557 show_pseudowires_cmd,
d261dd7e 558 "show mpls pseudowires",
2dd0d726 559 SHOW_STR
d261dd7e 560 MPLS_STR
efd7904e 561 "Pseudowires\n")
2dd0d726
RW
562{
563 struct zebra_vrf *zvrf;
564 struct zebra_pw *pw;
565
566 zvrf = vrf_info_lookup(VRF_DEFAULT);
567 if (!zvrf)
568 return 0;
569
69965f53
DL
570 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
571 "Labels", "Protocol", "Status");
2dd0d726 572
a2addae8 573 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
2dd0d726
RW
574 char buf_nbr[INET6_ADDRSTRLEN];
575 char buf_labels[64];
576
577 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
578
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);
583 else
584 snprintf(buf_labels, sizeof(buf_labels), "-");
585
69965f53 586 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname,
2dd0d726
RW
587 (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels,
588 zebra_route_string(pw->protocol),
fd563cc7 589 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
2dd0d726 590 ? "UP"
69965f53 591 : "DOWN");
2dd0d726
RW
592 }
593
594 return CMD_SUCCESS;
595}
596
6bbdd9e9 597static void vty_show_mpls_pseudowire_detail(struct vty *vty)
598{
599 struct zebra_vrf *zvrf;
600 struct zebra_pw *pw;
601 struct route_entry *re;
602 struct nexthop *nexthop;
8b117ff0 603 struct nexthop_group *nhg;
6bbdd9e9 604
605 zvrf = vrf_info_lookup(VRF_DEFAULT);
606 if (!zvrf)
607 return;
608
609 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
610 char buf_nbr[INET6_ADDRSTRLEN];
611 char buf_nh[100];
612
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);
619 else
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);
623 else
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",
fd563cc7 630 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
8b117ff0
MS
631 ? "Up"
632 : "Down");
6bbdd9e9 633 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
634 &pw->nexthop, NULL);
8b117ff0
MS
635 if (re == NULL)
636 continue;
637
638 nhg = rib_get_fib_nhg(re);
639 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
640 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
641 nexthop);
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]);
646 else
647 vty_out(vty, " Next Hop label: %s\n",
648 "-");
649 }
650
651 /* Include any installed backups */
652 nhg = rib_get_fib_backup_nhg(re);
653 if (nhg == NULL)
654 continue;
655
656 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
657 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
658 nexthop);
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]);
663 else
664 vty_out(vty, " Next Hop label: %s\n",
665 "-");
6bbdd9e9 666 }
667 }
668}
669
670static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
671{
672 struct route_entry *re;
673 struct nexthop *nexthop;
8b117ff0 674 struct nexthop_group *nhg;
6bbdd9e9 675 char buf_nbr[INET6_ADDRSTRLEN];
676 char buf_nh[100];
677 json_object *json_pw = NULL;
678 json_object *json_nexthop = NULL;
679 json_object *json_nexthops = NULL;
680
681 json_nexthops = json_object_new_array();
682 json_pw = json_object_new_object();
683
684 json_object_string_add(json_pw, "interface", pw->ifname);
685 if (pw->af == AF_UNSPEC)
686 json_object_string_add(json_pw, "neighbor", "-");
687 else {
688 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
689 json_object_string_add(json_pw, "neighbor", buf_nbr);
690 }
691 if (pw->local_label != MPLS_NO_LABEL)
692 json_object_int_add(json_pw, "localLabel", pw->local_label);
693 else
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);
697 else
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(
704 json_pw, "Status",
fd563cc7
KS
705 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING) ? "Up"
706 : "Down");
6bbdd9e9 707 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
708 &pw->nexthop, NULL);
8b117ff0
MS
709 if (re == NULL)
710 goto done;
711
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)
718 json_object_int_add(
719 json_nexthop, "nhLabel",
720 nexthop->nh_label->label[0]);
721 else
722 json_object_string_add(json_nexthop, "nhLabel",
723 "-");
6bbdd9e9 724
8b117ff0
MS
725 json_object_array_add(json_nexthops, json_nexthop);
726 }
727
728 /* Include installed backup nexthops also */
729 nhg = rib_get_fib_backup_nhg(re);
730 if (nhg == NULL)
731 goto done;
732
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)
738 json_object_int_add(
739 json_nexthop, "nhLabel",
740 nexthop->nh_label->label[0]);
741 else
742 json_object_string_add(json_nexthop, "nhLabel",
743 "-");
744
745 json_object_array_add(json_nexthops, json_nexthop);
6bbdd9e9 746 }
8b117ff0
MS
747
748done:
749
750 json_object_object_add(json_pw, "nexthops", json_nexthops);
6bbdd9e9 751 json_object_array_add(json_pws, json_pw);
752}
753
754static void vty_show_mpls_pseudowire_detail_json(struct vty *vty)
755{
756 json_object *json = NULL;
757 json_object *json_pws = NULL;
758 struct zebra_vrf *zvrf;
759 struct zebra_pw *pw;
760
761 zvrf = vrf_info_lookup(VRF_DEFAULT);
762 if (!zvrf)
763 return;
764
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);
769 }
770 json_object_object_add(json, "pw", json_pws);
962af8a8 771 vty_json(vty, json);
6bbdd9e9 772}
773
774DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd,
775 "show mpls pseudowires detail [json]$json",
776 SHOW_STR MPLS_STR
777 "Pseudowires\n"
778 "Detailed output\n" JSON_STR)
779{
780 bool uj = use_json(argc, argv);
781
782 if (uj)
783 vty_show_mpls_pseudowire_detail_json(vty);
784 else
785 vty_show_mpls_pseudowire_detail(vty);
786
787 return CMD_SUCCESS;
788}
789
2dd0d726
RW
790/* Pseudowire configuration write function. */
791static int zebra_pw_config(struct vty *vty)
792{
793 int write = 0;
794 struct zebra_vrf *zvrf;
795 struct zebra_pw *pw;
796
797 zvrf = vrf_info_lookup(VRF_DEFAULT);
798 if (!zvrf)
799 return 0;
800
a2addae8 801 RB_FOREACH (pw, zebra_static_pw_head, &zvrf->static_pseudowires) {
69965f53 802 vty_out(vty, "pseudowire %s\n", pw->ifname);
2dd0d726
RW
803 if (pw->local_label != MPLS_NO_LABEL
804 && pw->remote_label != MPLS_NO_LABEL)
69965f53
DL
805 vty_out(vty, " mpls label local %u remote %u\n",
806 pw->local_label, pw->remote_label);
2dd0d726
RW
807 else
808 vty_out(vty,
3efd0893 809 " ! Incomplete config, specify the static MPLS labels\n");
2dd0d726
RW
810
811 if (pw->af != AF_UNSPEC) {
812 char buf[INET6_ADDRSTRLEN];
813 inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
69965f53 814 vty_out(vty, " neighbor %s\n", buf);
2dd0d726
RW
815 } else
816 vty_out(vty,
3efd0893 817 " ! Incomplete config, specify a neighbor address\n");
2dd0d726
RW
818
819 if (!(pw->flags & F_PSEUDOWIRE_CWORD))
69965f53 820 vty_out(vty, " control-word exclude\n");
2dd0d726 821
07679ad9 822 vty_out(vty, "exit\n");
69965f53 823 vty_out(vty, "!\n");
2dd0d726
RW
824 write = 1;
825 }
826
827 return write;
828}
829
612c2c15 830static int zebra_pw_config(struct vty *vty);
2dd0d726 831static struct cmd_node pw_node = {
f4b8291f 832 .name = "pw",
62b346ee 833 .node = PW_NODE,
24389580 834 .parent_node = CONFIG_NODE,
62b346ee 835 .prompt = "%s(config-pw)# ",
612c2c15 836 .config_write = zebra_pw_config,
2dd0d726
RW
837};
838
839void zebra_pw_vty_init(void)
840{
612c2c15 841 install_node(&pw_node);
2dd0d726
RW
842 install_default(PW_NODE);
843
844 install_element(CONFIG_NODE, &pseudowire_if_cmd);
1e9d1183 845 install_element(CONFIG_NODE, &no_pseudowire_if_cmd);
2dd0d726
RW
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);
849
850 install_element(VIEW_NODE, &show_pseudowires_cmd);
6bbdd9e9 851 install_element(VIEW_NODE, &show_pseudowires_detail_cmd);
2dd0d726 852}