2 * Copyright (C) 2016 Volta Networks, Inc.
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.
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.
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,
28 #include "zebra/debug.h"
29 #include "zebra/rib.h"
30 #include "zebra/zebra_router.h"
31 #include "zebra/zapi_msg.h"
32 #include "zebra/zebra_rnh.h"
33 #include "zebra/zebra_vrf.h"
34 #include "zebra/zebra_pw.h"
36 DEFINE_MTYPE_STATIC(LIB
, PW
, "Pseudowire")
38 DEFINE_QOBJ_TYPE(zebra_pw
)
40 DEFINE_HOOK(pw_install
, (struct zebra_pw
* pw
), (pw
))
41 DEFINE_HOOK(pw_uninstall
, (struct zebra_pw
* pw
), (pw
))
43 #define MPLS_NO_LABEL MPLS_INVALID_LABEL
45 static int zebra_pw_enabled(struct zebra_pw
*);
46 static void zebra_pw_install(struct zebra_pw
*);
47 static void zebra_pw_uninstall(struct zebra_pw
*);
48 static int zebra_pw_install_retry(struct thread
*);
49 static int zebra_pw_check_reachability(struct zebra_pw
*);
50 static void zebra_pw_update_status(struct zebra_pw
*, int);
52 static inline int zebra_pw_compare(const struct zebra_pw
*a
,
53 const struct zebra_pw
*b
)
55 return (strcmp(a
->ifname
, b
->ifname
));
58 RB_GENERATE(zebra_pw_head
, zebra_pw
, pw_entry
, zebra_pw_compare
)
59 RB_GENERATE(zebra_static_pw_head
, zebra_pw
, static_pw_entry
, zebra_pw_compare
)
61 struct zebra_pw
*zebra_pw_add(struct zebra_vrf
*zvrf
, const char *ifname
,
62 uint8_t protocol
, struct zserv
*client
)
66 if (IS_ZEBRA_DEBUG_PW
)
67 zlog_debug("%u: adding pseudowire %s protocol %s",
68 zvrf_id(zvrf
), ifname
, zebra_route_string(protocol
));
70 pw
= XCALLOC(MTYPE_PW
, sizeof(*pw
));
71 strlcpy(pw
->ifname
, ifname
, sizeof(pw
->ifname
));
72 pw
->protocol
= protocol
;
73 pw
->vrf_id
= zvrf_id(zvrf
);
75 pw
->status
= PW_STATUS_DOWN
;
76 pw
->local_label
= MPLS_NO_LABEL
;
77 pw
->remote_label
= MPLS_NO_LABEL
;
78 pw
->flags
= F_PSEUDOWIRE_CWORD
;
80 RB_INSERT(zebra_pw_head
, &zvrf
->pseudowires
, pw
);
81 if (pw
->protocol
== ZEBRA_ROUTE_STATIC
) {
82 RB_INSERT(zebra_static_pw_head
, &zvrf
->static_pseudowires
, pw
);
83 QOBJ_REG(pw
, zebra_pw
);
89 void zebra_pw_del(struct zebra_vrf
*zvrf
, struct zebra_pw
*pw
)
91 if (IS_ZEBRA_DEBUG_PW
)
92 zlog_debug("%u: deleting pseudowire %s protocol %s", pw
->vrf_id
,
93 pw
->ifname
, zebra_route_string(pw
->protocol
));
95 /* remove nexthop tracking */
96 zebra_deregister_rnh_pseudowire(pw
->vrf_id
, pw
);
99 if (pw
->status
== PW_STATUS_UP
) {
100 hook_call(pw_uninstall
, pw
);
101 dplane_pw_uninstall(pw
);
102 } else if (pw
->install_retry_timer
)
103 THREAD_TIMER_OFF(pw
->install_retry_timer
);
105 /* unlink and release memory */
106 RB_REMOVE(zebra_pw_head
, &zvrf
->pseudowires
, pw
);
107 if (pw
->protocol
== ZEBRA_ROUTE_STATIC
)
108 RB_REMOVE(zebra_static_pw_head
, &zvrf
->static_pseudowires
, pw
);
112 void zebra_pw_change(struct zebra_pw
*pw
, ifindex_t ifindex
, int type
, int af
,
113 union g_addr
*nexthop
, uint32_t local_label
,
114 uint32_t remote_label
, uint8_t flags
,
115 union pw_protocol_fields
*data
)
117 zebra_deregister_rnh_pseudowire(pw
->vrf_id
, pw
);
119 pw
->ifindex
= ifindex
;
122 pw
->nexthop
= *nexthop
;
123 pw
->local_label
= local_label
;
124 pw
->remote_label
= remote_label
;
128 if (zebra_pw_enabled(pw
))
129 zebra_register_rnh_pseudowire(pw
->vrf_id
, pw
);
131 zebra_pw_uninstall(pw
);
134 struct zebra_pw
*zebra_pw_find(struct zebra_vrf
*zvrf
, const char *ifname
)
137 strlcpy(pw
.ifname
, ifname
, sizeof(pw
.ifname
));
138 return (RB_FIND(zebra_pw_head
, &zvrf
->pseudowires
, &pw
));
141 static int zebra_pw_enabled(struct zebra_pw
*pw
)
143 if (pw
->protocol
== ZEBRA_ROUTE_STATIC
) {
144 if (pw
->local_label
== MPLS_NO_LABEL
145 || pw
->remote_label
== MPLS_NO_LABEL
|| pw
->af
== AF_UNSPEC
)
152 void zebra_pw_update(struct zebra_pw
*pw
)
154 if (zebra_pw_check_reachability(pw
) < 0) {
155 zebra_pw_uninstall(pw
);
156 zebra_pw_install_failure(pw
);
157 /* wait for NHT and try again later */
160 * Install or reinstall the pseudowire (e.g. to update
161 * parameters like the nexthop or the use of the control word).
163 zebra_pw_install(pw
);
167 static void zebra_pw_install(struct zebra_pw
*pw
)
169 if (IS_ZEBRA_DEBUG_PW
)
170 zlog_debug("%u: installing pseudowire %s protocol %s",
171 pw
->vrf_id
, pw
->ifname
,
172 zebra_route_string(pw
->protocol
));
174 hook_call(pw_install
, pw
);
175 if (dplane_pw_install(pw
) == ZEBRA_DPLANE_REQUEST_FAILURE
) {
176 zebra_pw_install_failure(pw
);
180 if (pw
->status
== PW_STATUS_DOWN
)
181 zebra_pw_update_status(pw
, PW_STATUS_UP
);
184 static void zebra_pw_uninstall(struct zebra_pw
*pw
)
186 if (pw
->status
== PW_STATUS_DOWN
)
189 if (IS_ZEBRA_DEBUG_PW
)
190 zlog_debug("%u: uninstalling pseudowire %s protocol %s",
191 pw
->vrf_id
, pw
->ifname
,
192 zebra_route_string(pw
->protocol
));
194 /* ignore any possible error */
195 hook_call(pw_uninstall
, pw
);
196 dplane_pw_uninstall(pw
);
198 if (zebra_pw_enabled(pw
))
199 zebra_pw_update_status(pw
, PW_STATUS_DOWN
);
203 * Installation of the pseudowire in the kernel or hardware has failed. This
204 * function will notify the pseudowire client about the failure and schedule
205 * to retry the installation later. This function can be called by an external
206 * agent that performs the pseudowire installation in an asynchronous way.
208 void zebra_pw_install_failure(struct zebra_pw
*pw
)
210 if (IS_ZEBRA_DEBUG_PW
)
212 "%u: failed installing pseudowire %s, "
213 "scheduling retry in %u seconds",
214 pw
->vrf_id
, pw
->ifname
, PW_INSTALL_RETRY_INTERVAL
);
216 /* schedule to retry later */
217 THREAD_TIMER_OFF(pw
->install_retry_timer
);
218 thread_add_timer(zrouter
.master
, zebra_pw_install_retry
, pw
,
219 PW_INSTALL_RETRY_INTERVAL
, &pw
->install_retry_timer
);
221 zebra_pw_update_status(pw
, PW_STATUS_DOWN
);
224 static int zebra_pw_install_retry(struct thread
*thread
)
226 struct zebra_pw
*pw
= THREAD_ARG(thread
);
228 pw
->install_retry_timer
= NULL
;
229 zebra_pw_install(pw
);
234 static void zebra_pw_update_status(struct zebra_pw
*pw
, int status
)
238 zsend_pw_update(pw
->client
, pw
);
241 static int zebra_pw_check_reachability(struct zebra_pw
*pw
)
243 struct route_entry
*re
;
244 struct nexthop
*nexthop
;
246 /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
248 /* find route to the remote end of the pseudowire */
249 re
= rib_match(family2afi(pw
->af
), SAFI_UNICAST
, pw
->vrf_id
,
252 if (IS_ZEBRA_DEBUG_PW
)
253 zlog_debug("%s: no route found for %s", __func__
,
259 * Need to ensure that there's a label binding for all nexthops.
260 * Otherwise, ECMP for this route could render the pseudowire unusable.
262 for (ALL_NEXTHOPS_PTR(re
->nhe
->nhg
, nexthop
)) {
263 if (!nexthop
->nh_label
) {
264 if (IS_ZEBRA_DEBUG_PW
)
265 zlog_debug("%s: unlabeled route for %s",
266 __func__
, pw
->ifname
);
274 static int zebra_pw_client_close(struct zserv
*client
)
277 struct zebra_vrf
*zvrf
;
278 struct zebra_pw
*pw
, *tmp
;
280 RB_FOREACH (vrf
, vrf_id_head
, &vrfs_by_id
) {
282 RB_FOREACH_SAFE (pw
, zebra_pw_head
, &zvrf
->pseudowires
, tmp
) {
283 if (pw
->client
!= client
)
285 zebra_pw_del(zvrf
, pw
);
292 void zebra_pw_init(struct zebra_vrf
*zvrf
)
294 RB_INIT(zebra_pw_head
, &zvrf
->pseudowires
);
295 RB_INIT(zebra_static_pw_head
, &zvrf
->static_pseudowires
);
297 hook_register(zserv_client_close
, zebra_pw_client_close
);
300 void zebra_pw_exit(struct zebra_vrf
*zvrf
)
304 while (!RB_EMPTY(zebra_pw_head
, &zvrf
->pseudowires
)) {
305 pw
= RB_ROOT(zebra_pw_head
, &zvrf
->pseudowires
);
307 zebra_pw_del(zvrf
, pw
);
311 DEFUN_NOSH (pseudowire_if
,
314 "Static pseudowire configuration\n"
317 struct zebra_vrf
*zvrf
;
322 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
326 argv_find(argv
, argc
, "IFNAME", &idx
);
327 ifname
= argv
[idx
]->arg
;
329 pw
= zebra_pw_find(zvrf
, ifname
);
330 if (pw
&& pw
->protocol
!= ZEBRA_ROUTE_STATIC
) {
331 vty_out(vty
, "%% Pseudowire is not static\n");
336 pw
= zebra_pw_add(zvrf
, ifname
, ZEBRA_ROUTE_STATIC
, NULL
);
337 VTY_PUSH_CONTEXT(PW_NODE
, pw
);
342 DEFUN (no_pseudowire_if
,
343 no_pseudowire_if_cmd
,
344 "no pseudowire IFNAME",
346 "Static pseudowire configuration\n"
349 struct zebra_vrf
*zvrf
;
354 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
358 argv_find(argv
, argc
, "IFNAME", &idx
);
359 ifname
= argv
[idx
]->arg
;
361 pw
= zebra_pw_find(zvrf
, ifname
);
363 if (pw
->protocol
!= ZEBRA_ROUTE_STATIC
) {
364 vty_out(vty
, "%% Pseudowire is not static\n");
367 zebra_pw_del(zvrf
, pw
);
373 DEFUN (pseudowire_labels
,
374 pseudowire_labels_cmd
,
375 "[no] mpls label local (16-1048575) remote (16-1048575)",
377 "MPLS L2VPN PW command\n"
378 "MPLS L2VPN static labels\n"
379 "Local pseudowire label\n"
380 "Local pseudowire label\n"
381 "Remote pseudowire label\n"
382 "Remote pseudowire label\n")
384 VTY_DECLVAR_CONTEXT(zebra_pw
, pw
);
386 mpls_label_t local_label
, remote_label
;
388 if (argv_find(argv
, argc
, "no", &idx
)) {
389 local_label
= MPLS_NO_LABEL
;
390 remote_label
= MPLS_NO_LABEL
;
392 argv_find(argv
, argc
, "local", &idx
);
393 local_label
= atoi(argv
[idx
+ 1]->arg
);
394 argv_find(argv
, argc
, "remote", &idx
);
395 remote_label
= atoi(argv
[idx
+ 1]->arg
);
398 zebra_pw_change(pw
, pw
->ifindex
, pw
->type
, pw
->af
, &pw
->nexthop
,
399 local_label
, remote_label
, pw
->flags
, &pw
->data
);
404 DEFUN (pseudowire_neighbor
,
405 pseudowire_neighbor_cmd
,
406 "[no] neighbor <A.B.C.D|X:X::X:X>",
408 "Specify the IPv4 or IPv6 address of the remote endpoint\n"
412 VTY_DECLVAR_CONTEXT(zebra_pw
, pw
);
416 union g_addr nexthop
;
419 memset(&nexthop
, 0, sizeof(nexthop
));
421 if (!argv_find(argv
, argc
, "no", &idx
)) {
422 argv_find(argv
, argc
, "neighbor", &idx
);
423 address
= argv
[idx
+ 1]->arg
;
425 if (inet_pton(AF_INET
, address
, &nexthop
.ipv4
) == 1)
427 else if (inet_pton(AF_INET6
, address
, &nexthop
.ipv6
) == 1)
430 vty_out(vty
, "%% Malformed address\n");
435 zebra_pw_change(pw
, pw
->ifindex
, pw
->type
, af
, &nexthop
,
436 pw
->local_label
, pw
->remote_label
, pw
->flags
,
442 DEFUN (pseudowire_control_word
,
443 pseudowire_control_word_cmd
,
444 "[no] control-word <exclude|include>",
446 "Control-word options\n"
447 "Exclude control-word in pseudowire packets\n"
448 "Include control-word in pseudowire packets\n")
450 VTY_DECLVAR_CONTEXT(zebra_pw
, pw
);
454 if (argv_find(argv
, argc
, "no", &idx
))
455 flags
= F_PSEUDOWIRE_CWORD
;
457 argv_find(argv
, argc
, "control-word", &idx
);
458 if (argv
[idx
+ 1]->text
[0] == 'i')
459 flags
= F_PSEUDOWIRE_CWORD
;
462 zebra_pw_change(pw
, pw
->ifindex
, pw
->type
, pw
->af
, &pw
->nexthop
,
463 pw
->local_label
, pw
->remote_label
, flags
, &pw
->data
);
468 DEFUN (show_pseudowires
,
469 show_pseudowires_cmd
,
470 "show mpls pseudowires",
475 struct zebra_vrf
*zvrf
;
478 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
482 vty_out(vty
, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
483 "Labels", "Protocol", "Status");
485 RB_FOREACH (pw
, zebra_pw_head
, &zvrf
->pseudowires
) {
486 char buf_nbr
[INET6_ADDRSTRLEN
];
489 inet_ntop(pw
->af
, &pw
->nexthop
, buf_nbr
, sizeof(buf_nbr
));
491 if (pw
->local_label
!= MPLS_NO_LABEL
492 && pw
->remote_label
!= MPLS_NO_LABEL
)
493 snprintf(buf_labels
, sizeof(buf_labels
), "%u/%u",
494 pw
->local_label
, pw
->remote_label
);
496 snprintf(buf_labels
, sizeof(buf_labels
), "-");
498 vty_out(vty
, "%-16s %-24s %-12s %-8s %-10s\n", pw
->ifname
,
499 (pw
->af
!= AF_UNSPEC
) ? buf_nbr
: "-", buf_labels
,
500 zebra_route_string(pw
->protocol
),
501 (zebra_pw_enabled(pw
) && pw
->status
== PW_STATUS_UP
)
509 /* Pseudowire configuration write function. */
510 static int zebra_pw_config(struct vty
*vty
)
513 struct zebra_vrf
*zvrf
;
516 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
520 RB_FOREACH (pw
, zebra_static_pw_head
, &zvrf
->static_pseudowires
) {
521 vty_out(vty
, "pseudowire %s\n", pw
->ifname
);
522 if (pw
->local_label
!= MPLS_NO_LABEL
523 && pw
->remote_label
!= MPLS_NO_LABEL
)
524 vty_out(vty
, " mpls label local %u remote %u\n",
525 pw
->local_label
, pw
->remote_label
);
528 " ! Incomplete config, specify the static "
531 if (pw
->af
!= AF_UNSPEC
) {
532 char buf
[INET6_ADDRSTRLEN
];
533 inet_ntop(pw
->af
, &pw
->nexthop
, buf
, sizeof(buf
));
534 vty_out(vty
, " neighbor %s\n", buf
);
537 " ! Incomplete config, specify a neighbor "
540 if (!(pw
->flags
& F_PSEUDOWIRE_CWORD
))
541 vty_out(vty
, " control-word exclude\n");
550 static struct cmd_node pw_node
= {
551 PW_NODE
, "%s(config-pw)# ", 1,
554 void zebra_pw_vty_init(void)
556 install_node(&pw_node
, zebra_pw_config
);
557 install_default(PW_NODE
);
559 install_element(CONFIG_NODE
, &pseudowire_if_cmd
);
560 install_element(CONFIG_NODE
, &no_pseudowire_if_cmd
);
561 install_element(PW_NODE
, &pseudowire_labels_cmd
);
562 install_element(PW_NODE
, &pseudowire_neighbor_cmd
);
563 install_element(PW_NODE
, &pseudowire_control_word_cmd
);
565 install_element(VIEW_NODE
, &show_pseudowires_cmd
);