]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_pw.c
zebra: let /32 host route with same IP cross VRF
[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 *);
cc9f21da 50static void zebra_pw_install_retry(struct thread *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
cc9f21da 229static void zebra_pw_install_retry(struct thread *thread)
6833ae01 230{
231 struct zebra_pw *pw = THREAD_ARG(thread);
232
233 pw->install_retry_timer = NULL;
234 zebra_pw_install(pw);
6833ae01 235}
236
237static void zebra_pw_update_status(struct zebra_pw *pw, int status)
238{
239 pw->status = status;
240 if (pw->client)
241 zsend_pw_update(pw->client, pw);
242}
243
0d145d47
MS
244static int zebra_pw_check_reachability_strict(const struct zebra_pw *pw,
245 struct route_entry *re)
246{
247 const struct nexthop *nexthop;
248 const struct nexthop_group *nhg;
249 bool found_p = false;
250 bool fail_p = false;
251
252 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
253
254 /* All active nexthops must be labelled; look at
255 * primary and backup fib lists, in case there's been
256 * a backup nexthop activation.
257 */
258 nhg = rib_get_fib_nhg(re);
259 if (nhg && nhg->nexthop) {
260 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
261 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
262 continue;
263
264 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
265 if (nexthop->nh_label != NULL)
266 found_p = true;
267 else {
268 fail_p = true;
269 break;
270 }
271 }
272 }
273 }
274
275 if (fail_p)
276 goto done;
277
278 nhg = rib_get_fib_backup_nhg(re);
279 if (nhg && nhg->nexthop) {
280 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
281 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
282 continue;
283
284 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
285 if (nexthop->nh_label != NULL)
286 found_p = true;
287 else {
288 fail_p = true;
289 break;
290 }
291 }
292 }
293 }
294
295done:
296
297 if (fail_p || !found_p) {
298 if (IS_ZEBRA_DEBUG_PW)
299 zlog_debug("%s: unlabeled route for %s",
300 __func__, pw->ifname);
301 return -1;
302 }
303
304 return 0;
305}
306
307static int zebra_pw_check_reachability(const struct zebra_pw *pw)
6833ae01 308{
69965f53 309 struct route_entry *re;
0d145d47
MS
310 const struct nexthop *nexthop;
311 const struct nexthop_group *nhg;
312 bool found_p = false;
6833ae01 313
314 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
315
0d145d47 316 /* Find route to the remote end of the pseudowire */
69965f53
DL
317 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
318 &pw->nexthop, NULL);
319 if (!re) {
6833ae01 320 if (IS_ZEBRA_DEBUG_PW)
9df414fe
QY
321 zlog_debug("%s: no route found for %s", __func__,
322 pw->ifname);
6833ae01 323 return -1;
324 }
325
0d145d47
MS
326 /* Stricter checking for some OSes (OBSD, e.g.) */
327 if (mpls_pw_reach_strict)
328 return zebra_pw_check_reachability_strict(pw, re);
329
330 /* There must be at least one installed labelled nexthop;
331 * look at primary and backup fib lists, in case there's been
332 * a backup nexthop activation.
6833ae01 333 */
0d145d47
MS
334 nhg = rib_get_fib_nhg(re);
335 if (nhg && nhg->nexthop) {
336 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
337 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
338 continue;
339
340 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
341 nexthop->nh_label != NULL) {
342 found_p = true;
343 break;
344 }
345 }
346 }
347
348 if (found_p)
349 return 0;
350
351 nhg = rib_get_fib_backup_nhg(re);
352 if (nhg && nhg->nexthop) {
353 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
354 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
355 continue;
356
357 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
358 nexthop->nh_label != NULL) {
359 found_p = true;
360 break;
361 }
6833ae01 362 }
363 }
364
0d145d47
MS
365 if (!found_p) {
366 if (IS_ZEBRA_DEBUG_PW)
367 zlog_debug("%s: unlabeled route for %s",
368 __func__, pw->ifname);
369 return -1;
370 }
371
6833ae01 372 return 0;
373}
374
453844ab 375static int zebra_pw_client_close(struct zserv *client)
6833ae01 376{
377 struct vrf *vrf;
378 struct zebra_vrf *zvrf;
379 struct zebra_pw *pw, *tmp;
380
a2addae8 381 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
6833ae01 382 zvrf = vrf->info;
a2addae8 383 RB_FOREACH_SAFE (pw, zebra_pw_head, &zvrf->pseudowires, tmp) {
6833ae01 384 if (pw->client != client)
385 continue;
386 zebra_pw_del(zvrf, pw);
387 }
388 }
453844ab
QY
389
390 return 0;
6833ae01 391}
392
393void zebra_pw_init(struct zebra_vrf *zvrf)
394{
69965f53
DL
395 RB_INIT(zebra_pw_head, &zvrf->pseudowires);
396 RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires);
453844ab 397
21ccc0cf 398 hook_register(zserv_client_close, zebra_pw_client_close);
6833ae01 399}
400
401void zebra_pw_exit(struct zebra_vrf *zvrf)
402{
403 struct zebra_pw *pw;
404
55cd0f61
DS
405 while (!RB_EMPTY(zebra_pw_head, &zvrf->pseudowires)) {
406 pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires);
407
6833ae01 408 zebra_pw_del(zvrf, pw);
55cd0f61 409 }
6833ae01 410}
2dd0d726
RW
411
412DEFUN_NOSH (pseudowire_if,
413 pseudowire_if_cmd,
1e9d1183 414 "pseudowire IFNAME",
2dd0d726
RW
415 "Static pseudowire configuration\n"
416 "Pseudowire name\n")
417{
418 struct zebra_vrf *zvrf;
419 struct zebra_pw *pw;
2dd0d726 420 const char *ifname;
1e9d1183 421 int idx = 0;
2dd0d726
RW
422
423 zvrf = vrf_info_lookup(VRF_DEFAULT);
424 if (!zvrf)
425 return CMD_WARNING;
426
427 argv_find(argv, argc, "IFNAME", &idx);
428 ifname = argv[idx]->arg;
1e9d1183 429
2dd0d726
RW
430 pw = zebra_pw_find(zvrf, ifname);
431 if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
69965f53 432 vty_out(vty, "%% Pseudowire is not static\n");
2dd0d726
RW
433 return CMD_WARNING;
434 }
435
2dd0d726
RW
436 if (!pw)
437 pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
438 VTY_PUSH_CONTEXT(PW_NODE, pw);
439
440 return CMD_SUCCESS;
441}
442
1e9d1183
RW
443DEFUN (no_pseudowire_if,
444 no_pseudowire_if_cmd,
445 "no pseudowire IFNAME",
446 NO_STR
447 "Static pseudowire configuration\n"
448 "Pseudowire name\n")
449{
450 struct zebra_vrf *zvrf;
451 struct zebra_pw *pw;
452 const char *ifname;
453 int idx = 0;
454
455 zvrf = vrf_info_lookup(VRF_DEFAULT);
456 if (!zvrf)
457 return CMD_WARNING;
458
459 argv_find(argv, argc, "IFNAME", &idx);
460 ifname = argv[idx]->arg;
461
462 pw = zebra_pw_find(zvrf, ifname);
463 if (pw) {
464 if (pw->protocol != ZEBRA_ROUTE_STATIC) {
465 vty_out(vty, "%% Pseudowire is not static\n");
466 return CMD_WARNING;
467 }
468 zebra_pw_del(zvrf, pw);
469 }
470
471 return CMD_SUCCESS;
472}
473
2dd0d726
RW
474DEFUN (pseudowire_labels,
475 pseudowire_labels_cmd,
476 "[no] mpls label local (16-1048575) remote (16-1048575)",
477 NO_STR
478 "MPLS L2VPN PW command\n"
479 "MPLS L2VPN static labels\n"
480 "Local pseudowire label\n"
481 "Local pseudowire label\n"
482 "Remote pseudowire label\n"
483 "Remote pseudowire label\n")
484{
485 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
486 int idx = 0;
487 mpls_label_t local_label, remote_label;
488
489 if (argv_find(argv, argc, "no", &idx)) {
490 local_label = MPLS_NO_LABEL;
491 remote_label = MPLS_NO_LABEL;
492 } else {
493 argv_find(argv, argc, "local", &idx);
494 local_label = atoi(argv[idx + 1]->arg);
495 argv_find(argv, argc, "remote", &idx);
496 remote_label = atoi(argv[idx + 1]->arg);
497 }
498
499 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
500 local_label, remote_label, pw->flags, &pw->data);
501
502 return CMD_SUCCESS;
503}
504
505DEFUN (pseudowire_neighbor,
506 pseudowire_neighbor_cmd,
507 "[no] neighbor <A.B.C.D|X:X::X:X>",
508 NO_STR
509 "Specify the IPv4 or IPv6 address of the remote endpoint\n"
510 "IPv4 address\n"
511 "IPv6 address\n")
512{
513 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
514 int idx = 0;
515 const char *address;
516 int af;
517 union g_addr nexthop;
518
519 af = AF_UNSPEC;
520 memset(&nexthop, 0, sizeof(nexthop));
521
522 if (!argv_find(argv, argc, "no", &idx)) {
523 argv_find(argv, argc, "neighbor", &idx);
524 address = argv[idx + 1]->arg;
525
526 if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1)
527 af = AF_INET;
528 else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1)
529 af = AF_INET6;
530 else {
69965f53 531 vty_out(vty, "%% Malformed address\n");
2dd0d726
RW
532 return CMD_WARNING;
533 }
534 }
535
536 zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop,
537 pw->local_label, pw->remote_label, pw->flags,
538 &pw->data);
539
540 return CMD_SUCCESS;
541}
542
543DEFUN (pseudowire_control_word,
544 pseudowire_control_word_cmd,
545 "[no] control-word <exclude|include>",
546 NO_STR
547 "Control-word options\n"
548 "Exclude control-word in pseudowire packets\n"
549 "Include control-word in pseudowire packets\n")
550{
551 VTY_DECLVAR_CONTEXT(zebra_pw, pw);
552 int idx = 0;
553 uint8_t flags = 0;
554
555 if (argv_find(argv, argc, "no", &idx))
556 flags = F_PSEUDOWIRE_CWORD;
557 else {
558 argv_find(argv, argc, "control-word", &idx);
559 if (argv[idx + 1]->text[0] == 'i')
560 flags = F_PSEUDOWIRE_CWORD;
561 }
562
563 zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
564 pw->local_label, pw->remote_label, flags, &pw->data);
565
566 return CMD_SUCCESS;
567}
568
569DEFUN (show_pseudowires,
570 show_pseudowires_cmd,
d261dd7e 571 "show mpls pseudowires",
2dd0d726 572 SHOW_STR
d261dd7e 573 MPLS_STR
efd7904e 574 "Pseudowires\n")
2dd0d726
RW
575{
576 struct zebra_vrf *zvrf;
577 struct zebra_pw *pw;
578
579 zvrf = vrf_info_lookup(VRF_DEFAULT);
580 if (!zvrf)
581 return 0;
582
69965f53
DL
583 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
584 "Labels", "Protocol", "Status");
2dd0d726 585
a2addae8 586 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
2dd0d726
RW
587 char buf_nbr[INET6_ADDRSTRLEN];
588 char buf_labels[64];
589
590 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
591
592 if (pw->local_label != MPLS_NO_LABEL
593 && pw->remote_label != MPLS_NO_LABEL)
594 snprintf(buf_labels, sizeof(buf_labels), "%u/%u",
595 pw->local_label, pw->remote_label);
596 else
597 snprintf(buf_labels, sizeof(buf_labels), "-");
598
69965f53 599 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname,
2dd0d726
RW
600 (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels,
601 zebra_route_string(pw->protocol),
fd563cc7 602 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
2dd0d726 603 ? "UP"
69965f53 604 : "DOWN");
2dd0d726
RW
605 }
606
607 return CMD_SUCCESS;
608}
609
6bbdd9e9 610static void vty_show_mpls_pseudowire_detail(struct vty *vty)
611{
612 struct zebra_vrf *zvrf;
613 struct zebra_pw *pw;
614 struct route_entry *re;
615 struct nexthop *nexthop;
8b117ff0 616 struct nexthop_group *nhg;
6bbdd9e9 617
618 zvrf = vrf_info_lookup(VRF_DEFAULT);
619 if (!zvrf)
620 return;
621
622 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
623 char buf_nbr[INET6_ADDRSTRLEN];
624 char buf_nh[100];
625
626 vty_out(vty, "Interface: %s\n", pw->ifname);
627 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
628 vty_out(vty, " Neighbor: %s\n",
629 (pw->af != AF_UNSPEC) ? buf_nbr : "-");
630 if (pw->local_label != MPLS_NO_LABEL)
631 vty_out(vty, " Local Label: %u\n", pw->local_label);
632 else
633 vty_out(vty, " Local Label: %s\n", "-");
634 if (pw->remote_label != MPLS_NO_LABEL)
635 vty_out(vty, " Remote Label: %u\n", pw->remote_label);
636 else
637 vty_out(vty, " Remote Label: %s\n", "-");
638 vty_out(vty, " Protocol: %s\n",
639 zebra_route_string(pw->protocol));
640 if (pw->protocol == ZEBRA_ROUTE_LDP)
641 vty_out(vty, " VC-ID: %u\n", pw->data.ldp.pwid);
642 vty_out(vty, " Status: %s \n",
fd563cc7 643 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
8b117ff0
MS
644 ? "Up"
645 : "Down");
6bbdd9e9 646 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
647 &pw->nexthop, NULL);
8b117ff0
MS
648 if (re == NULL)
649 continue;
650
651 nhg = rib_get_fib_nhg(re);
652 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
653 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
654 nexthop);
655 vty_out(vty, " Next Hop: %s\n", buf_nh);
656 if (nexthop->nh_label)
657 vty_out(vty, " Next Hop label: %u\n",
658 nexthop->nh_label->label[0]);
659 else
660 vty_out(vty, " Next Hop label: %s\n",
661 "-");
662 }
663
664 /* Include any installed backups */
665 nhg = rib_get_fib_backup_nhg(re);
666 if (nhg == NULL)
667 continue;
668
669 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
670 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
671 nexthop);
672 vty_out(vty, " Next Hop: %s\n", buf_nh);
673 if (nexthop->nh_label)
674 vty_out(vty, " Next Hop label: %u\n",
675 nexthop->nh_label->label[0]);
676 else
677 vty_out(vty, " Next Hop label: %s\n",
678 "-");
6bbdd9e9 679 }
680 }
681}
682
683static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
684{
685 struct route_entry *re;
686 struct nexthop *nexthop;
8b117ff0 687 struct nexthop_group *nhg;
6bbdd9e9 688 char buf_nbr[INET6_ADDRSTRLEN];
689 char buf_nh[100];
690 json_object *json_pw = NULL;
691 json_object *json_nexthop = NULL;
692 json_object *json_nexthops = NULL;
693
694 json_nexthops = json_object_new_array();
695 json_pw = json_object_new_object();
696
697 json_object_string_add(json_pw, "interface", pw->ifname);
698 if (pw->af == AF_UNSPEC)
699 json_object_string_add(json_pw, "neighbor", "-");
700 else {
701 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
702 json_object_string_add(json_pw, "neighbor", buf_nbr);
703 }
704 if (pw->local_label != MPLS_NO_LABEL)
705 json_object_int_add(json_pw, "localLabel", pw->local_label);
706 else
707 json_object_string_add(json_pw, "localLabel", "-");
708 if (pw->remote_label != MPLS_NO_LABEL)
709 json_object_int_add(json_pw, "remoteLabel", pw->remote_label);
710 else
711 json_object_string_add(json_pw, "remoteLabel", "-");
712 json_object_string_add(json_pw, "protocol",
713 zebra_route_string(pw->protocol));
714 if (pw->protocol == ZEBRA_ROUTE_LDP)
715 json_object_int_add(json_pw, "vcId", pw->data.ldp.pwid);
716 json_object_string_add(
717 json_pw, "Status",
fd563cc7
KS
718 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING) ? "Up"
719 : "Down");
6bbdd9e9 720 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
721 &pw->nexthop, NULL);
8b117ff0
MS
722 if (re == NULL)
723 goto done;
724
725 nhg = rib_get_fib_nhg(re);
726 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
727 json_nexthop = json_object_new_object();
728 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
729 json_object_string_add(json_nexthop, "nexthop", buf_nh);
730 if (nexthop->nh_label)
731 json_object_int_add(
732 json_nexthop, "nhLabel",
733 nexthop->nh_label->label[0]);
734 else
735 json_object_string_add(json_nexthop, "nhLabel",
736 "-");
6bbdd9e9 737
8b117ff0
MS
738 json_object_array_add(json_nexthops, json_nexthop);
739 }
740
741 /* Include installed backup nexthops also */
742 nhg = rib_get_fib_backup_nhg(re);
743 if (nhg == NULL)
744 goto done;
745
746 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
747 json_nexthop = json_object_new_object();
748 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
749 json_object_string_add(json_nexthop, "nexthop", buf_nh);
750 if (nexthop->nh_label)
751 json_object_int_add(
752 json_nexthop, "nhLabel",
753 nexthop->nh_label->label[0]);
754 else
755 json_object_string_add(json_nexthop, "nhLabel",
756 "-");
757
758 json_object_array_add(json_nexthops, json_nexthop);
6bbdd9e9 759 }
8b117ff0
MS
760
761done:
762
763 json_object_object_add(json_pw, "nexthops", json_nexthops);
6bbdd9e9 764 json_object_array_add(json_pws, json_pw);
765}
766
767static void vty_show_mpls_pseudowire_detail_json(struct vty *vty)
768{
769 json_object *json = NULL;
770 json_object *json_pws = NULL;
771 struct zebra_vrf *zvrf;
772 struct zebra_pw *pw;
773
774 zvrf = vrf_info_lookup(VRF_DEFAULT);
775 if (!zvrf)
776 return;
777
778 json = json_object_new_object();
779 json_pws = json_object_new_array();
780 RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
781 vty_show_mpls_pseudowire(pw, json_pws);
782 }
783 json_object_object_add(json, "pw", json_pws);
962af8a8 784 vty_json(vty, json);
6bbdd9e9 785}
786
787DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd,
788 "show mpls pseudowires detail [json]$json",
789 SHOW_STR MPLS_STR
790 "Pseudowires\n"
791 "Detailed output\n" JSON_STR)
792{
793 bool uj = use_json(argc, argv);
794
795 if (uj)
796 vty_show_mpls_pseudowire_detail_json(vty);
797 else
798 vty_show_mpls_pseudowire_detail(vty);
799
800 return CMD_SUCCESS;
801}
802
2dd0d726
RW
803/* Pseudowire configuration write function. */
804static int zebra_pw_config(struct vty *vty)
805{
806 int write = 0;
807 struct zebra_vrf *zvrf;
808 struct zebra_pw *pw;
809
810 zvrf = vrf_info_lookup(VRF_DEFAULT);
811 if (!zvrf)
812 return 0;
813
a2addae8 814 RB_FOREACH (pw, zebra_static_pw_head, &zvrf->static_pseudowires) {
69965f53 815 vty_out(vty, "pseudowire %s\n", pw->ifname);
2dd0d726
RW
816 if (pw->local_label != MPLS_NO_LABEL
817 && pw->remote_label != MPLS_NO_LABEL)
69965f53
DL
818 vty_out(vty, " mpls label local %u remote %u\n",
819 pw->local_label, pw->remote_label);
2dd0d726
RW
820 else
821 vty_out(vty,
3efd0893 822 " ! Incomplete config, specify the static MPLS labels\n");
2dd0d726
RW
823
824 if (pw->af != AF_UNSPEC) {
825 char buf[INET6_ADDRSTRLEN];
826 inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
69965f53 827 vty_out(vty, " neighbor %s\n", buf);
2dd0d726
RW
828 } else
829 vty_out(vty,
3efd0893 830 " ! Incomplete config, specify a neighbor address\n");
2dd0d726
RW
831
832 if (!(pw->flags & F_PSEUDOWIRE_CWORD))
69965f53 833 vty_out(vty, " control-word exclude\n");
2dd0d726 834
07679ad9 835 vty_out(vty, "exit\n");
69965f53 836 vty_out(vty, "!\n");
2dd0d726
RW
837 write = 1;
838 }
839
840 return write;
841}
842
612c2c15 843static int zebra_pw_config(struct vty *vty);
2dd0d726 844static struct cmd_node pw_node = {
f4b8291f 845 .name = "pw",
62b346ee 846 .node = PW_NODE,
24389580 847 .parent_node = CONFIG_NODE,
62b346ee 848 .prompt = "%s(config-pw)# ",
612c2c15 849 .config_write = zebra_pw_config,
2dd0d726
RW
850};
851
852void zebra_pw_vty_init(void)
853{
612c2c15 854 install_node(&pw_node);
2dd0d726
RW
855 install_default(PW_NODE);
856
857 install_element(CONFIG_NODE, &pseudowire_if_cmd);
1e9d1183 858 install_element(CONFIG_NODE, &no_pseudowire_if_cmd);
2dd0d726
RW
859 install_element(PW_NODE, &pseudowire_labels_cmd);
860 install_element(PW_NODE, &pseudowire_neighbor_cmd);
861 install_element(PW_NODE, &pseudowire_control_word_cmd);
862
863 install_element(VIEW_NODE, &show_pseudowires_cmd);
6bbdd9e9 864 install_element(VIEW_NODE, &show_pseudowires_detail_cmd);
2dd0d726 865}