Line data Source code
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 12 : DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire");
39 :
40 : DEFINE_QOBJ_TYPE(zebra_pw);
41 :
42 0 : DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw));
43 0 : 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 void zebra_pw_install_retry(struct thread *thread);
51 : static int zebra_pw_check_reachability(const struct zebra_pw *);
52 : static void zebra_pw_update_status(struct zebra_pw *, int);
53 :
54 0 : static inline int zebra_pw_compare(const struct zebra_pw *a,
55 : const struct zebra_pw *b)
56 : {
57 0 : return (strcmp(a->ifname, b->ifname));
58 : }
59 :
60 0 : RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare)
61 0 : RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare)
62 :
63 0 : struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
64 : uint8_t protocol, struct zserv *client)
65 : {
66 0 : struct zebra_pw *pw;
67 :
68 0 : if (IS_ZEBRA_DEBUG_PW)
69 0 : zlog_debug("%u: adding pseudowire %s protocol %s",
70 : zvrf_id(zvrf), ifname, zebra_route_string(protocol));
71 :
72 0 : pw = XCALLOC(MTYPE_PW, sizeof(*pw));
73 0 : strlcpy(pw->ifname, ifname, sizeof(pw->ifname));
74 0 : pw->protocol = protocol;
75 0 : pw->vrf_id = zvrf_id(zvrf);
76 0 : pw->client = client;
77 0 : pw->status = PW_NOT_FORWARDING;
78 0 : pw->local_label = MPLS_NO_LABEL;
79 0 : pw->remote_label = MPLS_NO_LABEL;
80 0 : pw->flags = F_PSEUDOWIRE_CWORD;
81 :
82 0 : RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw);
83 0 : if (pw->protocol == ZEBRA_ROUTE_STATIC) {
84 0 : RB_INSERT(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
85 0 : QOBJ_REG(pw, zebra_pw);
86 : }
87 :
88 0 : return pw;
89 : }
90 :
91 0 : void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw)
92 : {
93 0 : if (IS_ZEBRA_DEBUG_PW)
94 0 : 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 0 : zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
99 :
100 : /* uninstall */
101 0 : if (pw->status == PW_FORWARDING) {
102 0 : hook_call(pw_uninstall, pw);
103 0 : dplane_pw_uninstall(pw);
104 : }
105 :
106 0 : THREAD_OFF(pw->install_retry_timer);
107 :
108 : /* unlink and release memory */
109 0 : RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw);
110 0 : if (pw->protocol == ZEBRA_ROUTE_STATIC)
111 0 : RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
112 :
113 0 : XFREE(MTYPE_PW, pw);
114 0 : }
115 :
116 0 : void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af,
117 : union g_addr *nexthop, uint32_t local_label,
118 : uint32_t remote_label, uint8_t flags,
119 : union pw_protocol_fields *data)
120 : {
121 0 : pw->ifindex = ifindex;
122 0 : pw->type = type;
123 0 : pw->af = af;
124 0 : pw->nexthop = *nexthop;
125 0 : pw->local_label = local_label;
126 0 : pw->remote_label = remote_label;
127 0 : pw->flags = flags;
128 0 : pw->data = *data;
129 :
130 0 : if (zebra_pw_enabled(pw)) {
131 0 : bool nht_exists;
132 0 : zebra_register_rnh_pseudowire(pw->vrf_id, pw, &nht_exists);
133 0 : if (nht_exists)
134 0 : zebra_pw_update(pw);
135 : } else {
136 0 : if (pw->protocol == ZEBRA_ROUTE_STATIC)
137 0 : zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
138 0 : zebra_pw_uninstall(pw);
139 : }
140 0 : }
141 :
142 0 : struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname)
143 : {
144 0 : struct zebra_pw pw;
145 0 : strlcpy(pw.ifname, ifname, sizeof(pw.ifname));
146 0 : return (RB_FIND(zebra_pw_head, &zvrf->pseudowires, &pw));
147 : }
148 :
149 0 : static int zebra_pw_enabled(struct zebra_pw *pw)
150 : {
151 0 : if (pw->protocol == ZEBRA_ROUTE_STATIC) {
152 0 : if (pw->local_label == MPLS_NO_LABEL
153 0 : || pw->remote_label == MPLS_NO_LABEL || pw->af == AF_UNSPEC)
154 : return 0;
155 0 : return 1;
156 : } else
157 0 : return pw->enabled;
158 : }
159 :
160 0 : void zebra_pw_update(struct zebra_pw *pw)
161 : {
162 0 : if (zebra_pw_check_reachability(pw) < 0) {
163 0 : zebra_pw_uninstall(pw);
164 0 : zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
165 : /* wait for NHT and try again later */
166 : } else {
167 : /*
168 : * Install or reinstall the pseudowire (e.g. to update
169 : * parameters like the nexthop or the use of the control word).
170 : */
171 0 : zebra_pw_install(pw);
172 : }
173 0 : }
174 :
175 0 : static void zebra_pw_install(struct zebra_pw *pw)
176 : {
177 0 : if (IS_ZEBRA_DEBUG_PW)
178 0 : zlog_debug("%u: installing pseudowire %s protocol %s",
179 : pw->vrf_id, pw->ifname,
180 : zebra_route_string(pw->protocol));
181 :
182 0 : hook_call(pw_install, pw);
183 0 : if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) {
184 0 : zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
185 0 : return;
186 : }
187 :
188 0 : if (pw->status != PW_FORWARDING)
189 0 : zebra_pw_update_status(pw, PW_FORWARDING);
190 : }
191 :
192 0 : static void zebra_pw_uninstall(struct zebra_pw *pw)
193 : {
194 0 : if (pw->status != PW_FORWARDING)
195 : return;
196 :
197 0 : if (IS_ZEBRA_DEBUG_PW)
198 0 : zlog_debug("%u: uninstalling pseudowire %s protocol %s",
199 : pw->vrf_id, pw->ifname,
200 : zebra_route_string(pw->protocol));
201 :
202 : /* ignore any possible error */
203 0 : hook_call(pw_uninstall, pw);
204 0 : dplane_pw_uninstall(pw);
205 :
206 0 : if (zebra_pw_enabled(pw))
207 0 : zebra_pw_update_status(pw, PW_NOT_FORWARDING);
208 : }
209 :
210 : /*
211 : * Installation of the pseudowire in the kernel or hardware has failed. This
212 : * function will notify the pseudowire client about the failure and schedule
213 : * to retry the installation later. This function can be called by an external
214 : * agent that performs the pseudowire installation in an asynchronous way.
215 : */
216 0 : void zebra_pw_install_failure(struct zebra_pw *pw, int pwstatus)
217 : {
218 0 : if (IS_ZEBRA_DEBUG_PW)
219 0 : zlog_debug(
220 : "%u: failed installing pseudowire %s, scheduling retry in %u seconds",
221 : pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL);
222 :
223 : /* schedule to retry later */
224 0 : THREAD_OFF(pw->install_retry_timer);
225 0 : thread_add_timer(zrouter.master, zebra_pw_install_retry, pw,
226 : PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer);
227 :
228 0 : zebra_pw_update_status(pw, pwstatus);
229 0 : }
230 :
231 0 : static void zebra_pw_install_retry(struct thread *thread)
232 : {
233 0 : struct zebra_pw *pw = THREAD_ARG(thread);
234 :
235 0 : zebra_pw_install(pw);
236 0 : }
237 :
238 0 : static void zebra_pw_update_status(struct zebra_pw *pw, int status)
239 : {
240 0 : pw->status = status;
241 0 : if (pw->client)
242 0 : zsend_pw_update(pw->client, pw);
243 : }
244 :
245 0 : static int zebra_pw_check_reachability_strict(const struct zebra_pw *pw,
246 : struct route_entry *re)
247 : {
248 0 : const struct nexthop *nexthop;
249 0 : const struct nexthop_group *nhg;
250 0 : bool found_p = false;
251 0 : bool fail_p = false;
252 :
253 : /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
254 :
255 : /* All active nexthops must be labelled; look at
256 : * primary and backup fib lists, in case there's been
257 : * a backup nexthop activation.
258 : */
259 0 : nhg = rib_get_fib_nhg(re);
260 0 : if (nhg && nhg->nexthop) {
261 0 : for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
262 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
263 0 : continue;
264 :
265 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
266 0 : if (nexthop->nh_label != NULL)
267 : found_p = true;
268 : else {
269 : fail_p = true;
270 : break;
271 : }
272 : }
273 : }
274 : }
275 :
276 0 : if (fail_p)
277 0 : goto done;
278 :
279 0 : nhg = rib_get_fib_backup_nhg(re);
280 0 : if (nhg && nhg->nexthop) {
281 0 : for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
282 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
283 0 : continue;
284 :
285 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
286 0 : if (nexthop->nh_label != NULL)
287 : found_p = true;
288 : else {
289 : fail_p = true;
290 : break;
291 : }
292 : }
293 : }
294 : }
295 :
296 0 : done:
297 :
298 0 : if (fail_p || !found_p) {
299 0 : if (IS_ZEBRA_DEBUG_PW)
300 0 : zlog_debug("%s: unlabeled route for %s",
301 : __func__, pw->ifname);
302 0 : return -1;
303 : }
304 :
305 : return 0;
306 : }
307 :
308 0 : static int zebra_pw_check_reachability(const struct zebra_pw *pw)
309 : {
310 0 : struct route_entry *re;
311 0 : const struct nexthop *nexthop;
312 0 : const struct nexthop_group *nhg;
313 0 : bool found_p = false;
314 :
315 : /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
316 :
317 : /* Find route to the remote end of the pseudowire */
318 0 : re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
319 : &pw->nexthop, NULL);
320 0 : if (!re) {
321 0 : if (IS_ZEBRA_DEBUG_PW)
322 0 : zlog_debug("%s: no route found for %s", __func__,
323 : pw->ifname);
324 0 : return -1;
325 : }
326 :
327 : /* Stricter checking for some OSes (OBSD, e.g.) */
328 0 : if (mpls_pw_reach_strict)
329 0 : return zebra_pw_check_reachability_strict(pw, re);
330 :
331 : /* There must be at least one installed labelled nexthop;
332 : * look at primary and backup fib lists, in case there's been
333 : * a backup nexthop activation.
334 : */
335 0 : nhg = rib_get_fib_nhg(re);
336 0 : if (nhg && nhg->nexthop) {
337 0 : for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
338 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
339 0 : continue;
340 :
341 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
342 0 : nexthop->nh_label != NULL) {
343 : found_p = true;
344 : break;
345 : }
346 : }
347 : }
348 :
349 0 : if (found_p)
350 : return 0;
351 :
352 0 : nhg = rib_get_fib_backup_nhg(re);
353 0 : if (nhg && nhg->nexthop) {
354 0 : for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
355 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
356 0 : continue;
357 :
358 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
359 0 : nexthop->nh_label != NULL) {
360 : found_p = true;
361 : break;
362 : }
363 : }
364 : }
365 :
366 0 : if (!found_p) {
367 0 : if (IS_ZEBRA_DEBUG_PW)
368 0 : zlog_debug("%s: unlabeled route for %s",
369 : __func__, pw->ifname);
370 0 : return -1;
371 : }
372 :
373 : return 0;
374 : }
375 :
376 12 : static int zebra_pw_client_close(struct zserv *client)
377 : {
378 12 : struct vrf *vrf;
379 12 : struct zebra_vrf *zvrf;
380 12 : struct zebra_pw *pw, *tmp;
381 :
382 36 : RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
383 12 : zvrf = vrf->info;
384 24 : RB_FOREACH_SAFE (pw, zebra_pw_head, &zvrf->pseudowires, tmp) {
385 0 : if (pw->client != client)
386 0 : continue;
387 0 : zebra_pw_del(zvrf, pw);
388 : }
389 : }
390 :
391 12 : return 0;
392 : }
393 :
394 4 : void zebra_pw_init(struct zebra_vrf *zvrf)
395 : {
396 4 : RB_INIT(zebra_pw_head, &zvrf->pseudowires);
397 4 : RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires);
398 :
399 4 : hook_register(zserv_client_close, zebra_pw_client_close);
400 4 : }
401 :
402 4 : void zebra_pw_exit(struct zebra_vrf *zvrf)
403 : {
404 4 : struct zebra_pw *pw;
405 :
406 4 : while (!RB_EMPTY(zebra_pw_head, &zvrf->pseudowires)) {
407 0 : pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires);
408 :
409 0 : zebra_pw_del(zvrf, pw);
410 : }
411 4 : }
412 :
413 0 : DEFUN_NOSH (pseudowire_if,
414 : pseudowire_if_cmd,
415 : "pseudowire IFNAME",
416 : "Static pseudowire configuration\n"
417 : "Pseudowire name\n")
418 : {
419 0 : struct zebra_vrf *zvrf;
420 0 : struct zebra_pw *pw;
421 0 : const char *ifname;
422 0 : int idx = 0;
423 :
424 0 : zvrf = vrf_info_lookup(VRF_DEFAULT);
425 0 : if (!zvrf)
426 : return CMD_WARNING;
427 :
428 0 : argv_find(argv, argc, "IFNAME", &idx);
429 0 : ifname = argv[idx]->arg;
430 :
431 0 : pw = zebra_pw_find(zvrf, ifname);
432 0 : if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
433 0 : vty_out(vty, "%% Pseudowire is not static\n");
434 0 : return CMD_WARNING;
435 : }
436 :
437 0 : if (!pw)
438 0 : pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
439 0 : VTY_PUSH_CONTEXT(PW_NODE, pw);
440 :
441 0 : return CMD_SUCCESS;
442 : }
443 :
444 0 : DEFUN (no_pseudowire_if,
445 : no_pseudowire_if_cmd,
446 : "no pseudowire IFNAME",
447 : NO_STR
448 : "Static pseudowire configuration\n"
449 : "Pseudowire name\n")
450 : {
451 0 : struct zebra_vrf *zvrf;
452 0 : struct zebra_pw *pw;
453 0 : const char *ifname;
454 0 : int idx = 0;
455 :
456 0 : zvrf = vrf_info_lookup(VRF_DEFAULT);
457 0 : if (!zvrf)
458 : return CMD_WARNING;
459 :
460 0 : argv_find(argv, argc, "IFNAME", &idx);
461 0 : ifname = argv[idx]->arg;
462 :
463 0 : pw = zebra_pw_find(zvrf, ifname);
464 0 : if (pw) {
465 0 : if (pw->protocol != ZEBRA_ROUTE_STATIC) {
466 0 : vty_out(vty, "%% Pseudowire is not static\n");
467 0 : return CMD_WARNING;
468 : }
469 0 : zebra_pw_del(zvrf, pw);
470 : }
471 :
472 : return CMD_SUCCESS;
473 : }
474 :
475 0 : DEFUN (pseudowire_labels,
476 : pseudowire_labels_cmd,
477 : "[no] mpls label local (16-1048575) remote (16-1048575)",
478 : NO_STR
479 : "MPLS L2VPN PW command\n"
480 : "MPLS L2VPN static labels\n"
481 : "Local pseudowire label\n"
482 : "Local pseudowire label\n"
483 : "Remote pseudowire label\n"
484 : "Remote pseudowire label\n")
485 : {
486 0 : VTY_DECLVAR_CONTEXT(zebra_pw, pw);
487 0 : int idx = 0;
488 0 : mpls_label_t local_label, remote_label;
489 :
490 0 : if (argv_find(argv, argc, "no", &idx)) {
491 : local_label = MPLS_NO_LABEL;
492 : remote_label = MPLS_NO_LABEL;
493 : } else {
494 0 : argv_find(argv, argc, "local", &idx);
495 0 : local_label = atoi(argv[idx + 1]->arg);
496 0 : argv_find(argv, argc, "remote", &idx);
497 0 : remote_label = atoi(argv[idx + 1]->arg);
498 : }
499 :
500 0 : zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
501 0 : local_label, remote_label, pw->flags, &pw->data);
502 :
503 0 : return CMD_SUCCESS;
504 : }
505 :
506 0 : DEFUN (pseudowire_neighbor,
507 : pseudowire_neighbor_cmd,
508 : "[no] neighbor <A.B.C.D|X:X::X:X>",
509 : NO_STR
510 : "Specify the IPv4 or IPv6 address of the remote endpoint\n"
511 : "IPv4 address\n"
512 : "IPv6 address\n")
513 : {
514 0 : VTY_DECLVAR_CONTEXT(zebra_pw, pw);
515 0 : int idx = 0;
516 0 : const char *address;
517 0 : int af;
518 0 : union g_addr nexthop;
519 :
520 0 : af = AF_UNSPEC;
521 0 : memset(&nexthop, 0, sizeof(nexthop));
522 :
523 0 : if (!argv_find(argv, argc, "no", &idx)) {
524 0 : argv_find(argv, argc, "neighbor", &idx);
525 0 : address = argv[idx + 1]->arg;
526 :
527 0 : if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1)
528 : af = AF_INET;
529 0 : else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1)
530 : af = AF_INET6;
531 : else {
532 0 : vty_out(vty, "%% Malformed address\n");
533 0 : return CMD_WARNING;
534 : }
535 : }
536 :
537 0 : zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop,
538 0 : pw->local_label, pw->remote_label, pw->flags,
539 : &pw->data);
540 :
541 0 : return CMD_SUCCESS;
542 : }
543 :
544 0 : DEFUN (pseudowire_control_word,
545 : pseudowire_control_word_cmd,
546 : "[no] control-word <exclude|include>",
547 : NO_STR
548 : "Control-word options\n"
549 : "Exclude control-word in pseudowire packets\n"
550 : "Include control-word in pseudowire packets\n")
551 : {
552 0 : VTY_DECLVAR_CONTEXT(zebra_pw, pw);
553 0 : int idx = 0;
554 0 : uint8_t flags = 0;
555 :
556 0 : if (argv_find(argv, argc, "no", &idx))
557 : flags = F_PSEUDOWIRE_CWORD;
558 : else {
559 0 : argv_find(argv, argc, "control-word", &idx);
560 0 : if (argv[idx + 1]->text[0] == 'i')
561 0 : flags = F_PSEUDOWIRE_CWORD;
562 : }
563 :
564 0 : zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
565 : pw->local_label, pw->remote_label, flags, &pw->data);
566 :
567 0 : return CMD_SUCCESS;
568 : }
569 :
570 0 : DEFUN (show_pseudowires,
571 : show_pseudowires_cmd,
572 : "show mpls pseudowires",
573 : SHOW_STR
574 : MPLS_STR
575 : "Pseudowires\n")
576 : {
577 0 : struct zebra_vrf *zvrf;
578 0 : struct zebra_pw *pw;
579 :
580 0 : zvrf = vrf_info_lookup(VRF_DEFAULT);
581 0 : if (!zvrf)
582 : return 0;
583 :
584 0 : vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
585 : "Labels", "Protocol", "Status");
586 :
587 0 : RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
588 0 : char buf_nbr[INET6_ADDRSTRLEN];
589 0 : char buf_labels[64];
590 :
591 0 : inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
592 :
593 0 : if (pw->local_label != MPLS_NO_LABEL
594 0 : && pw->remote_label != MPLS_NO_LABEL)
595 0 : snprintf(buf_labels, sizeof(buf_labels), "%u/%u",
596 : pw->local_label, pw->remote_label);
597 : else
598 0 : snprintf(buf_labels, sizeof(buf_labels), "-");
599 :
600 0 : vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname,
601 0 : (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels,
602 0 : zebra_route_string(pw->protocol),
603 0 : (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
604 : ? "UP"
605 : : "DOWN");
606 : }
607 :
608 : return CMD_SUCCESS;
609 : }
610 :
611 0 : static void vty_show_mpls_pseudowire_detail(struct vty *vty)
612 : {
613 0 : struct zebra_vrf *zvrf;
614 0 : struct zebra_pw *pw;
615 0 : struct route_entry *re;
616 0 : struct nexthop *nexthop;
617 0 : struct nexthop_group *nhg;
618 :
619 0 : zvrf = vrf_info_lookup(VRF_DEFAULT);
620 0 : if (!zvrf)
621 : return;
622 :
623 0 : RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
624 0 : char buf_nbr[INET6_ADDRSTRLEN];
625 0 : char buf_nh[100];
626 :
627 0 : vty_out(vty, "Interface: %s\n", pw->ifname);
628 0 : inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
629 0 : vty_out(vty, " Neighbor: %s\n",
630 0 : (pw->af != AF_UNSPEC) ? buf_nbr : "-");
631 0 : if (pw->local_label != MPLS_NO_LABEL)
632 0 : vty_out(vty, " Local Label: %u\n", pw->local_label);
633 : else
634 0 : vty_out(vty, " Local Label: %s\n", "-");
635 0 : if (pw->remote_label != MPLS_NO_LABEL)
636 0 : vty_out(vty, " Remote Label: %u\n", pw->remote_label);
637 : else
638 0 : vty_out(vty, " Remote Label: %s\n", "-");
639 0 : vty_out(vty, " Protocol: %s\n",
640 0 : zebra_route_string(pw->protocol));
641 0 : if (pw->protocol == ZEBRA_ROUTE_LDP)
642 0 : vty_out(vty, " VC-ID: %u\n", pw->data.ldp.pwid);
643 0 : vty_out(vty, " Status: %s \n",
644 0 : (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
645 : ? "Up"
646 : : "Down");
647 0 : re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
648 : &pw->nexthop, NULL);
649 0 : if (re == NULL)
650 0 : continue;
651 :
652 0 : nhg = rib_get_fib_nhg(re);
653 0 : for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
654 0 : snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
655 : nexthop);
656 0 : vty_out(vty, " Next Hop: %s\n", buf_nh);
657 0 : if (nexthop->nh_label)
658 0 : vty_out(vty, " Next Hop label: %u\n",
659 : nexthop->nh_label->label[0]);
660 : else
661 0 : vty_out(vty, " Next Hop label: %s\n",
662 : "-");
663 : }
664 :
665 : /* Include any installed backups */
666 0 : nhg = rib_get_fib_backup_nhg(re);
667 0 : if (nhg == NULL)
668 : continue;
669 :
670 0 : for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
671 0 : snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
672 : nexthop);
673 0 : vty_out(vty, " Next Hop: %s\n", buf_nh);
674 0 : if (nexthop->nh_label)
675 0 : vty_out(vty, " Next Hop label: %u\n",
676 : nexthop->nh_label->label[0]);
677 : else
678 0 : vty_out(vty, " Next Hop label: %s\n",
679 : "-");
680 : }
681 : }
682 : }
683 :
684 0 : static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
685 : {
686 0 : struct route_entry *re;
687 0 : struct nexthop *nexthop;
688 0 : struct nexthop_group *nhg;
689 0 : char buf_nbr[INET6_ADDRSTRLEN];
690 0 : char buf_nh[100];
691 0 : json_object *json_pw = NULL;
692 0 : json_object *json_nexthop = NULL;
693 0 : json_object *json_nexthops = NULL;
694 :
695 0 : json_nexthops = json_object_new_array();
696 0 : json_pw = json_object_new_object();
697 :
698 0 : json_object_string_add(json_pw, "interface", pw->ifname);
699 0 : if (pw->af == AF_UNSPEC)
700 0 : json_object_string_add(json_pw, "neighbor", "-");
701 : else {
702 0 : inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
703 0 : json_object_string_add(json_pw, "neighbor", buf_nbr);
704 : }
705 0 : if (pw->local_label != MPLS_NO_LABEL)
706 0 : json_object_int_add(json_pw, "localLabel", pw->local_label);
707 : else
708 0 : json_object_string_add(json_pw, "localLabel", "-");
709 0 : if (pw->remote_label != MPLS_NO_LABEL)
710 0 : json_object_int_add(json_pw, "remoteLabel", pw->remote_label);
711 : else
712 0 : json_object_string_add(json_pw, "remoteLabel", "-");
713 0 : json_object_string_add(json_pw, "protocol",
714 0 : zebra_route_string(pw->protocol));
715 0 : if (pw->protocol == ZEBRA_ROUTE_LDP)
716 0 : json_object_int_add(json_pw, "vcId", pw->data.ldp.pwid);
717 0 : json_object_string_add(
718 : json_pw, "Status",
719 0 : (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING) ? "Up"
720 : : "Down");
721 0 : re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
722 0 : &pw->nexthop, NULL);
723 0 : if (re == NULL)
724 0 : goto done;
725 :
726 0 : nhg = rib_get_fib_nhg(re);
727 0 : for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
728 0 : json_nexthop = json_object_new_object();
729 0 : snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
730 0 : json_object_string_add(json_nexthop, "nexthop", buf_nh);
731 0 : if (nexthop->nh_label)
732 0 : json_object_int_add(
733 : json_nexthop, "nhLabel",
734 0 : nexthop->nh_label->label[0]);
735 : else
736 0 : json_object_string_add(json_nexthop, "nhLabel",
737 : "-");
738 :
739 0 : json_object_array_add(json_nexthops, json_nexthop);
740 : }
741 :
742 : /* Include installed backup nexthops also */
743 0 : nhg = rib_get_fib_backup_nhg(re);
744 0 : if (nhg == NULL)
745 : goto done;
746 :
747 0 : for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
748 0 : json_nexthop = json_object_new_object();
749 0 : snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
750 0 : json_object_string_add(json_nexthop, "nexthop", buf_nh);
751 0 : if (nexthop->nh_label)
752 0 : json_object_int_add(
753 : json_nexthop, "nhLabel",
754 0 : nexthop->nh_label->label[0]);
755 : else
756 0 : json_object_string_add(json_nexthop, "nhLabel",
757 : "-");
758 :
759 0 : json_object_array_add(json_nexthops, json_nexthop);
760 : }
761 :
762 0 : done:
763 :
764 0 : json_object_object_add(json_pw, "nexthops", json_nexthops);
765 0 : json_object_array_add(json_pws, json_pw);
766 0 : }
767 :
768 0 : static void vty_show_mpls_pseudowire_detail_json(struct vty *vty)
769 : {
770 0 : json_object *json = NULL;
771 0 : json_object *json_pws = NULL;
772 0 : struct zebra_vrf *zvrf;
773 0 : struct zebra_pw *pw;
774 :
775 0 : zvrf = vrf_info_lookup(VRF_DEFAULT);
776 0 : if (!zvrf)
777 : return;
778 :
779 0 : json = json_object_new_object();
780 0 : json_pws = json_object_new_array();
781 0 : RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
782 0 : vty_show_mpls_pseudowire(pw, json_pws);
783 : }
784 0 : json_object_object_add(json, "pw", json_pws);
785 0 : vty_json(vty, json);
786 : }
787 :
788 0 : DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd,
789 : "show mpls pseudowires detail [json]$json",
790 : SHOW_STR MPLS_STR
791 : "Pseudowires\n"
792 : "Detailed output\n" JSON_STR)
793 : {
794 0 : bool uj = use_json(argc, argv);
795 :
796 0 : if (uj)
797 0 : vty_show_mpls_pseudowire_detail_json(vty);
798 : else
799 0 : vty_show_mpls_pseudowire_detail(vty);
800 :
801 0 : return CMD_SUCCESS;
802 : }
803 :
804 : /* Pseudowire configuration write function. */
805 0 : static int zebra_pw_config(struct vty *vty)
806 : {
807 0 : int write = 0;
808 0 : struct zebra_vrf *zvrf;
809 0 : struct zebra_pw *pw;
810 :
811 0 : zvrf = vrf_info_lookup(VRF_DEFAULT);
812 0 : if (!zvrf)
813 : return 0;
814 :
815 0 : RB_FOREACH (pw, zebra_static_pw_head, &zvrf->static_pseudowires) {
816 0 : vty_out(vty, "pseudowire %s\n", pw->ifname);
817 0 : if (pw->local_label != MPLS_NO_LABEL
818 0 : && pw->remote_label != MPLS_NO_LABEL)
819 0 : vty_out(vty, " mpls label local %u remote %u\n",
820 : pw->local_label, pw->remote_label);
821 : else
822 0 : vty_out(vty,
823 : " ! Incomplete config, specify the static MPLS labels\n");
824 :
825 0 : if (pw->af != AF_UNSPEC) {
826 0 : char buf[INET6_ADDRSTRLEN];
827 0 : inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
828 0 : vty_out(vty, " neighbor %s\n", buf);
829 : } else
830 0 : vty_out(vty,
831 : " ! Incomplete config, specify a neighbor address\n");
832 :
833 0 : if (!(pw->flags & F_PSEUDOWIRE_CWORD))
834 0 : vty_out(vty, " control-word exclude\n");
835 :
836 0 : vty_out(vty, "exit\n");
837 0 : vty_out(vty, "!\n");
838 0 : write = 1;
839 : }
840 :
841 : return write;
842 : }
843 :
844 : static int zebra_pw_config(struct vty *vty);
845 : static struct cmd_node pw_node = {
846 : .name = "pw",
847 : .node = PW_NODE,
848 : .parent_node = CONFIG_NODE,
849 : .prompt = "%s(config-pw)# ",
850 : .config_write = zebra_pw_config,
851 : };
852 :
853 4 : void zebra_pw_vty_init(void)
854 : {
855 4 : install_node(&pw_node);
856 4 : install_default(PW_NODE);
857 :
858 4 : install_element(CONFIG_NODE, &pseudowire_if_cmd);
859 4 : install_element(CONFIG_NODE, &no_pseudowire_if_cmd);
860 4 : install_element(PW_NODE, &pseudowire_labels_cmd);
861 4 : install_element(PW_NODE, &pseudowire_neighbor_cmd);
862 4 : install_element(PW_NODE, &pseudowire_control_word_cmd);
863 :
864 4 : install_element(VIEW_NODE, &show_pseudowires_cmd);
865 4 : install_element(VIEW_NODE, &show_pseudowires_detail_cmd);
866 4 : }
|