]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_pw.c
tests: clean up all_proto_startup a bit
[mirror_frr.git] / zebra / zebra_pw.c
CommitLineData
6833ae01 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"
2dd0d726 25#include "command.h"
6833ae01 26#include "vrf.h"
6bbdd9e9 27#include "lib/json.h"
28#include "printfrr.h"
6833ae01 29
30#include "zebra/debug.h"
31#include "zebra/rib.h"
3801e764 32#include "zebra/zebra_router.h"
bf094f69 33#include "zebra/zapi_msg.h"
731a75fe 34#include "zebra/zebra_rnh.h"
6833ae01 35#include "zebra/zebra_vrf.h"
36#include "zebra/zebra_pw.h"
37
bf8d3d6a 38DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire");
6833ae01 39
96244aca 40DEFINE_QOBJ_TYPE(zebra_pw);
2dd0d726 41
8451921b
DL
42DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw));
43DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw));
6833ae01 44
69965f53
DL
45#define MPLS_NO_LABEL MPLS_INVALID_LABEL
46
2dd0d726 47static int zebra_pw_enabled(struct zebra_pw *);
6833ae01 48static void zebra_pw_install(struct zebra_pw *);
49static void zebra_pw_uninstall(struct zebra_pw *);
50static int zebra_pw_install_retry(struct thread *);
0d145d47 51static int zebra_pw_check_reachability(const struct zebra_pw *);
6833ae01 52static void zebra_pw_update_status(struct zebra_pw *, int);
53
54static 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
2dd0d726
RW
60RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare)
61RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare)
6833ae01 62
63struct 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;
fd563cc7 77 pw->status = PW_NOT_FORWARDING;
2dd0d726
RW
78 pw->local_label = MPLS_NO_LABEL;
79 pw->remote_label = MPLS_NO_LABEL;
80 pw->flags = F_PSEUDOWIRE_CWORD;
6833ae01 81
82 RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw);
2dd0d726
RW
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 }
6833ae01 87
88 return pw;
89}
90
91void 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
731a75fe
RW
97 /* remove nexthop tracking */
98 zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
99
6833ae01 100 /* uninstall */
fd563cc7 101 if (pw->status == PW_FORWARDING) {
6833ae01 102 hook_call(pw_uninstall, pw);
97d8d05a
MS
103 dplane_pw_uninstall(pw);
104 } else if (pw->install_retry_timer)
50478845 105 thread_cancel(&pw->install_retry_timer);
6833ae01 106
107 /* unlink and release memory */
108 RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw);
2dd0d726
RW
109 if (pw->protocol == ZEBRA_ROUTE_STATIC)
110 RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
6833ae01 111 XFREE(MTYPE_PW, pw);
112}
113
114void 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
1fddcd0a
KS
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 {
13c46fa1
KS
134 if (pw->protocol == ZEBRA_ROUTE_STATIC)
135 zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
6833ae01 136 zebra_pw_uninstall(pw);
13c46fa1 137 }
6833ae01 138}
139
140struct 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
2dd0d726
RW
147static 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
6833ae01 158void zebra_pw_update(struct zebra_pw *pw)
159{
160 if (zebra_pw_check_reachability(pw) < 0) {
161 zebra_pw_uninstall(pw);
fd563cc7 162 zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
731a75fe 163 /* wait for NHT and try again later */
6833ae01 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
173static 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
97d8d05a
MS
180 hook_call(pw_install, pw);
181 if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) {
fd563cc7 182 zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
6833ae01 183 return;
184 }
185
fd563cc7
KS
186 if (pw->status != PW_FORWARDING)
187 zebra_pw_update_status(pw, PW_FORWARDING);
6833ae01 188}
189
190static void zebra_pw_uninstall(struct zebra_pw *pw)
191{
fd563cc7 192 if (pw->status != PW_FORWARDING)
6833ae01 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);
97d8d05a 202 dplane_pw_uninstall(pw);
6833ae01 203
2dd0d726 204 if (zebra_pw_enabled(pw))
fd563cc7 205 zebra_pw_update_status(pw, PW_NOT_FORWARDING);
6833ae01 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 */
fd563cc7 214void zebra_pw_install_failure(struct zebra_pw *pw, int pwstatus)
6833ae01 215{
216 if (IS_ZEBRA_DEBUG_PW)
217 zlog_debug(
3efd0893 218 "%u: failed installing pseudowire %s, scheduling retry in %u seconds",
6833ae01 219 pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL);
220
221 /* schedule to retry later */
50478845 222 thread_cancel(&pw->install_retry_timer);
3801e764 223 thread_add_timer(zrouter.master, zebra_pw_install_retry, pw,
69965f53 224 PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer);
6833ae01 225
fd563cc7 226 zebra_pw_update_status(pw, pwstatus);
6833ae01 227}
228
229static 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
239static 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
0d145d47
MS
246static int zebra_pw_check_reachability_strict(const struct zebra_pw *pw,
247 struct route_entry *re)
248{
249 const struct nexthop *nexthop;
250 const struct nexthop_group *nhg;
251 bool found_p = false;
252 bool fail_p = false;
253
254 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
255
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.
259 */
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))
264 continue;
265
266 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
267 if (nexthop->nh_label != NULL)
268 found_p = true;
269 else {
270 fail_p = true;
271 break;
272 }
273 }
274 }
275 }
276
277 if (fail_p)
278 goto done;
279
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))
284 continue;
285
286 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
287 if (nexthop->nh_label != NULL)
288 found_p = true;
289 else {
290 fail_p = true;
291 break;
292 }
293 }
294 }
295 }
296
297done:
298
299 if (fail_p || !found_p) {
300 if (IS_ZEBRA_DEBUG_PW)
301 zlog_debug("%s: unlabeled route for %s",
302 __func__, pw->ifname);
303 return -1;
304 }
305
306 return 0;
307}
308
309static int zebra_pw_check_reachability(const struct zebra_pw *pw)
6833ae01 310{
69965f53 311 struct route_entry *re;
0d145d47
MS
312 const struct nexthop *nexthop;
313 const struct nexthop_group *nhg;
314 bool found_p = false;
6833ae01 315
316 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
317
0d145d47 318 /* Find route to the remote end of the pseudowire */
69965f53
DL
319 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
320 &pw->nexthop, NULL);
321 if (!re) {
6833ae01 322 if (IS_ZEBRA_DEBUG_PW)
9df414fe
QY
323 zlog_debug("%s: no route found for %s", __func__,
324 pw->ifname);
6833ae01 325 return -1;
326 }
327
0d145d47
MS
328 /* Stricter checking for some OSes (OBSD, e.g.) */
329 if (mpls_pw_reach_strict)
330 return zebra_pw_check_reachability_strict(pw, re);
331
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.
6833ae01 335 */
0d145d47
MS
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))
340 continue;
341
342 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
343 nexthop->nh_label != NULL) {
344 found_p = true;
345 break;
346 }
347 }
348 }
349
350 if (found_p)
351 return 0;
352
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))
357 continue;
358
359 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
360 nexthop->nh_label != NULL) {
361 found_p = true;
362 break;
363 }
6833ae01 364 }
365 }
366
0d145d47
MS
367 if (!found_p) {
368 if (IS_ZEBRA_DEBUG_PW)
369 zlog_debug("%s: unlabeled route for %s",
370 __func__, pw->ifname);
371 return -1;
372 }
373
6833ae01 374 return 0;
375}
376
453844ab 377static int zebra_pw_client_close(struct zserv *client)
6833ae01 378{
379 struct vrf *vrf;
380 struct zebra_vrf *zvrf;
381 struct zebra_pw *pw, *tmp;
382
a2addae8 383 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
6833ae01 384 zvrf = vrf->info;
a2addae8 385 RB_FOREACH_SAFE (pw, zebra_pw_head, &zvrf->pseudowires, tmp) {
6833ae01 386 if (pw->client != client)
387 continue;
388 zebra_pw_del(zvrf, pw);
389 }
390 }
453844ab
QY
391
392 return 0;
6833ae01 393}
394
395void zebra_pw_init(struct zebra_vrf *zvrf)
396{
69965f53
DL
397 RB_INIT(zebra_pw_head, &zvrf->pseudowires);
398 RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires);
453844ab 399
21ccc0cf 400 hook_register(zserv_client_close, zebra_pw_client_close);
6833ae01 401}
402
403void zebra_pw_exit(struct zebra_vrf *zvrf)
404{
405 struct zebra_pw *pw;
406
55cd0f61
DS
407 while (!RB_EMPTY(zebra_pw_head, &zvrf->pseudowires)) {
408 pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires);
409
6833ae01 410 zebra_pw_del(zvrf, pw);
55cd0f61 411 }
6833ae01 412}
2dd0d726
RW
413
414DEFUN_NOSH (pseudowire_if,
415 pseudowire_if_cmd,
1e9d1183 416 "pseudowire IFNAME",
2dd0d726
RW
417 "Static pseudowire configuration\n"
418 "Pseudowire name\n")
419{
420 struct zebra_vrf *zvrf;
421 struct zebra_pw *pw;
2dd0d726 422 const char *ifname;
1e9d1183 423 int idx = 0;
2dd0d726
RW
424
425 zvrf = vrf_info_lookup(VRF_DEFAULT);
426 if (!zvrf)
427 return CMD_WARNING;
428
429 argv_find(argv, argc, "IFNAME", &idx);
430 ifname = argv[idx]->arg;
1e9d1183 431
2dd0d726
RW
432 pw = zebra_pw_find(zvrf, ifname);
433 if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
69965f53 434 vty_out(vty, "%% Pseudowire is not static\n");
2dd0d726
RW
435 return CMD_WARNING;
436 }
437
2dd0d726
RW
438 if (!pw)
439 pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
440 VTY_PUSH_CONTEXT(PW_NODE, pw);
441
442 return CMD_SUCCESS;
443}
444
1e9d1183
RW
445DEFUN (no_pseudowire_if,
446 no_pseudowire_if_cmd,
447 "no pseudowire IFNAME",
448 NO_STR
449 "Static pseudowire configuration\n"
450 "Pseudowire name\n")
451{
452 struct zebra_vrf *zvrf;
453 struct zebra_pw *pw;
454 const char *ifname;
455 int idx = 0;
456
457 zvrf = vrf_info_lookup(VRF_DEFAULT);
458 if (!zvrf)
459 return CMD_WARNING;
460
461 argv_find(argv, argc, "IFNAME", &idx);
462 ifname = argv[idx]->arg;
463
464 pw = zebra_pw_find(zvrf, ifname);
465 if (pw) {
466 if (pw->protocol != ZEBRA_ROUTE_STATIC) {
467 vty_out(vty, "%% Pseudowire is not static\n");
468 return CMD_WARNING;
469 }
470 zebra_pw_del(zvrf, pw);
471 }
472
473 return CMD_SUCCESS;
474}
475
2dd0d726
RW
476DEFUN (pseudowire_labels,
477 pseudowire_labels_cmd,
478 "[no] mpls label local (16-1048575) remote (16-1048575)",
479 NO_STR
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")
486{
487 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
488 int idx = 0;
489 mpls_label_t local_label, remote_label;
490
491 if (argv_find(argv, argc, "no", &idx)) {
492 local_label = MPLS_NO_LABEL;
493 remote_label = MPLS_NO_LABEL;
494 } else {
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);
499 }
500
501 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
502 local_label, remote_label, pw->flags, &pw->data);
503
504 return CMD_SUCCESS;
505}
506
507DEFUN (pseudowire_neighbor,
508 pseudowire_neighbor_cmd,
509 "[no] neighbor <A.B.C.D|X:X::X:X>",
510 NO_STR
511 "Specify the IPv4 or IPv6 address of the remote endpoint\n"
512 "IPv4 address\n"
513 "IPv6 address\n")
514{
515 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
516 int idx = 0;
517 const char *address;
518 int af;
519 union g_addr nexthop;
520
521 af = AF_UNSPEC;
522 memset(&nexthop, 0, sizeof(nexthop));
523
524 if (!argv_find(argv, argc, "no", &idx)) {
525 argv_find(argv, argc, "neighbor", &idx);
526 address = argv[idx + 1]->arg;
527
528 if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1)
529 af = AF_INET;
530 else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1)
531 af = AF_INET6;
532 else {
69965f53 533 vty_out(vty, "%% Malformed address\n");
2dd0d726
RW
534 return CMD_WARNING;
535 }
536 }
537
538 zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop,
539 pw->local_label, pw->remote_label, pw->flags,
540 &pw->data);
541
542 return CMD_SUCCESS;
543}
544
545DEFUN (pseudowire_control_word,
546 pseudowire_control_word_cmd,
547 "[no] control-word <exclude|include>",
548 NO_STR
549 "Control-word options\n"
550 "Exclude control-word in pseudowire packets\n"
551 "Include control-word in pseudowire packets\n")
552{
553 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
554 int idx = 0;
555 uint8_t flags = 0;
556
557 if (argv_find(argv, argc, "no", &idx))
558 flags = F_PSEUDOWIRE_CWORD;
559 else {
560 argv_find(argv, argc, "control-word", &idx);
561 if (argv[idx + 1]->text[0] == 'i')
562 flags = F_PSEUDOWIRE_CWORD;
563 }
564
565 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
566 pw->local_label, pw->remote_label, flags, &pw->data);
567
568 return CMD_SUCCESS;
569}
570
571DEFUN (show_pseudowires,
572 show_pseudowires_cmd,
d261dd7e 573 "show mpls pseudowires",
2dd0d726 574 SHOW_STR
d261dd7e 575 MPLS_STR
efd7904e 576 "Pseudowires\n")
2dd0d726
RW
577{
578 struct zebra_vrf *zvrf;
579 struct zebra_pw *pw;
580
581 zvrf = vrf_info_lookup(VRF_DEFAULT);
582 if (!zvrf)
583 return 0;
584
69965f53
DL
585 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
586 "Labels", "Protocol", "Status");
2dd0d726 587
a2addae8 588 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
2dd0d726
RW
589 char buf_nbr[INET6_ADDRSTRLEN];
590 char buf_labels[64];
591
592 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
593
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);
598 else
599 snprintf(buf_labels, sizeof(buf_labels), "-");
600
69965f53 601 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname,
2dd0d726
RW
602 (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels,
603 zebra_route_string(pw->protocol),
fd563cc7 604 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
2dd0d726 605 ? "UP"
69965f53 606 : "DOWN");
2dd0d726
RW
607 }
608
609 return CMD_SUCCESS;
610}
611
6bbdd9e9 612static void vty_show_mpls_pseudowire_detail(struct vty *vty)
613{
614 struct zebra_vrf *zvrf;
615 struct zebra_pw *pw;
616 struct route_entry *re;
617 struct nexthop *nexthop;
8b117ff0 618 struct nexthop_group *nhg;
6bbdd9e9 619
620 zvrf = vrf_info_lookup(VRF_DEFAULT);
621 if (!zvrf)
622 return;
623
624 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
625 char buf_nbr[INET6_ADDRSTRLEN];
626 char buf_nh[100];
627
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);
634 else
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);
638 else
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",
fd563cc7 645 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
8b117ff0
MS
646 ? "Up"
647 : "Down");
6bbdd9e9 648 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
649 &pw->nexthop, NULL);
8b117ff0
MS
650 if (re == NULL)
651 continue;
652
653 nhg = rib_get_fib_nhg(re);
654 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
655 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
656 nexthop);
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]);
661 else
662 vty_out(vty, " Next Hop label: %s\n",
663 "-");
664 }
665
666 /* Include any installed backups */
667 nhg = rib_get_fib_backup_nhg(re);
668 if (nhg == NULL)
669 continue;
670
671 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
672 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
673 nexthop);
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]);
678 else
679 vty_out(vty, " Next Hop label: %s\n",
680 "-");
6bbdd9e9 681 }
682 }
683}
684
685static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
686{
687 struct route_entry *re;
688 struct nexthop *nexthop;
8b117ff0 689 struct nexthop_group *nhg;
6bbdd9e9 690 char buf_nbr[INET6_ADDRSTRLEN];
691 char buf_nh[100];
692 json_object *json_pw = NULL;
693 json_object *json_nexthop = NULL;
694 json_object *json_nexthops = NULL;
695
696 json_nexthops = json_object_new_array();
697 json_pw = json_object_new_object();
698
699 json_object_string_add(json_pw, "interface", pw->ifname);
700 if (pw->af == AF_UNSPEC)
701 json_object_string_add(json_pw, "neighbor", "-");
702 else {
703 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
704 json_object_string_add(json_pw, "neighbor", buf_nbr);
705 }
706 if (pw->local_label != MPLS_NO_LABEL)
707 json_object_int_add(json_pw, "localLabel", pw->local_label);
708 else
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);
712 else
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(
719 json_pw, "Status",
fd563cc7
KS
720 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING) ? "Up"
721 : "Down");
6bbdd9e9 722 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
723 &pw->nexthop, NULL);
8b117ff0
MS
724 if (re == NULL)
725 goto done;
726
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)
733 json_object_int_add(
734 json_nexthop, "nhLabel",
735 nexthop->nh_label->label[0]);
736 else
737 json_object_string_add(json_nexthop, "nhLabel",
738 "-");
6bbdd9e9 739
8b117ff0
MS
740 json_object_array_add(json_nexthops, json_nexthop);
741 }
742
743 /* Include installed backup nexthops also */
744 nhg = rib_get_fib_backup_nhg(re);
745 if (nhg == NULL)
746 goto done;
747
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)
753 json_object_int_add(
754 json_nexthop, "nhLabel",
755 nexthop->nh_label->label[0]);
756 else
757 json_object_string_add(json_nexthop, "nhLabel",
758 "-");
759
760 json_object_array_add(json_nexthops, json_nexthop);
6bbdd9e9 761 }
8b117ff0
MS
762
763done:
764
765 json_object_object_add(json_pw, "nexthops", json_nexthops);
6bbdd9e9 766 json_object_array_add(json_pws, json_pw);
767}
768
769static void vty_show_mpls_pseudowire_detail_json(struct vty *vty)
770{
771 json_object *json = NULL;
772 json_object *json_pws = NULL;
773 struct zebra_vrf *zvrf;
774 struct zebra_pw *pw;
775
776 zvrf = vrf_info_lookup(VRF_DEFAULT);
777 if (!zvrf)
778 return;
779
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);
784 }
785 json_object_object_add(json, "pw", json_pws);
786 vty_out(vty, "%s\n",
787 json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
788 json_object_free(json);
789}
790
791DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd,
792 "show mpls pseudowires detail [json]$json",
793 SHOW_STR MPLS_STR
794 "Pseudowires\n"
795 "Detailed output\n" JSON_STR)
796{
797 bool uj = use_json(argc, argv);
798
799 if (uj)
800 vty_show_mpls_pseudowire_detail_json(vty);
801 else
802 vty_show_mpls_pseudowire_detail(vty);
803
804 return CMD_SUCCESS;
805}
806
2dd0d726
RW
807/* Pseudowire configuration write function. */
808static int zebra_pw_config(struct vty *vty)
809{
810 int write = 0;
811 struct zebra_vrf *zvrf;
812 struct zebra_pw *pw;
813
814 zvrf = vrf_info_lookup(VRF_DEFAULT);
815 if (!zvrf)
816 return 0;
817
a2addae8 818 RB_FOREACH (pw, zebra_static_pw_head, &zvrf->static_pseudowires) {
69965f53 819 vty_out(vty, "pseudowire %s\n", pw->ifname);
2dd0d726
RW
820 if (pw->local_label != MPLS_NO_LABEL
821 && pw->remote_label != MPLS_NO_LABEL)
69965f53
DL
822 vty_out(vty, " mpls label local %u remote %u\n",
823 pw->local_label, pw->remote_label);
2dd0d726
RW
824 else
825 vty_out(vty,
3efd0893 826 " ! Incomplete config, specify the static MPLS labels\n");
2dd0d726
RW
827
828 if (pw->af != AF_UNSPEC) {
829 char buf[INET6_ADDRSTRLEN];
830 inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
69965f53 831 vty_out(vty, " neighbor %s\n", buf);
2dd0d726
RW
832 } else
833 vty_out(vty,
3efd0893 834 " ! Incomplete config, specify a neighbor address\n");
2dd0d726
RW
835
836 if (!(pw->flags & F_PSEUDOWIRE_CWORD))
69965f53 837 vty_out(vty, " control-word exclude\n");
2dd0d726 838
07679ad9 839 vty_out(vty, "exit\n");
69965f53 840 vty_out(vty, "!\n");
2dd0d726
RW
841 write = 1;
842 }
843
844 return write;
845}
846
612c2c15 847static int zebra_pw_config(struct vty *vty);
2dd0d726 848static struct cmd_node pw_node = {
f4b8291f 849 .name = "pw",
62b346ee 850 .node = PW_NODE,
24389580 851 .parent_node = CONFIG_NODE,
62b346ee 852 .prompt = "%s(config-pw)# ",
612c2c15 853 .config_write = zebra_pw_config,
2dd0d726
RW
854};
855
856void zebra_pw_vty_init(void)
857{
612c2c15 858 install_node(&pw_node);
2dd0d726
RW
859 install_default(PW_NODE);
860
861 install_element(CONFIG_NODE, &pseudowire_if_cmd);
1e9d1183 862 install_element(CONFIG_NODE, &no_pseudowire_if_cmd);
2dd0d726
RW
863 install_element(PW_NODE, &pseudowire_labels_cmd);
864 install_element(PW_NODE, &pseudowire_neighbor_cmd);
865 install_element(PW_NODE, &pseudowire_control_word_cmd);
866
867 install_element(VIEW_NODE, &show_pseudowires_cmd);
6bbdd9e9 868 install_element(VIEW_NODE, &show_pseudowires_detail_cmd);
2dd0d726 869}