2 * Copyright (C) 2013 Cumulus Networks, Inc.
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "sockunion.h"
32 #include "workqueue.h"
37 #include "termtable.h"
40 #include "zebra/rib.h"
42 #include "zebra/interface.h"
43 #include "zebra/zserv.h"
44 #include "zebra/zebra_router.h"
45 #include "zebra/redistribute.h"
46 #include "zebra/debug.h"
47 #include "zebra/zebra_memory.h"
48 #include "zebra/zebra_vrf.h"
49 #include "zebra/zebra_mpls.h"
50 #include "zebra/zebra_errors.h"
52 DEFINE_MTYPE_STATIC(ZEBRA
, LSP
, "MPLS LSP object")
53 DEFINE_MTYPE_STATIC(ZEBRA
, FEC
, "MPLS FEC object")
54 DEFINE_MTYPE_STATIC(ZEBRA
, SLSP
, "MPLS static LSP config")
55 DEFINE_MTYPE_STATIC(ZEBRA
, NHLFE
, "MPLS nexthop object")
56 DEFINE_MTYPE_STATIC(ZEBRA
, SNHLFE
, "MPLS static nexthop object")
57 DEFINE_MTYPE_STATIC(ZEBRA
, SNHLFE_IFNAME
, "MPLS static nexthop ifname")
61 /* static function declarations */
63 static void fec_evaluate(struct zebra_vrf
*zvrf
);
64 static uint32_t fec_derive_label_from_index(struct zebra_vrf
*vrf
,
66 static int lsp_install(struct zebra_vrf
*zvrf
, mpls_label_t label
,
67 struct route_node
*rn
, struct route_entry
*re
);
68 static int lsp_uninstall(struct zebra_vrf
*zvrf
, mpls_label_t label
);
69 static int fec_change_update_lsp(struct zebra_vrf
*zvrf
, zebra_fec_t
*fec
,
70 mpls_label_t old_label
);
71 static int fec_send(zebra_fec_t
*fec
, struct zserv
*client
);
72 static void fec_update_clients(zebra_fec_t
*fec
);
73 static void fec_print(zebra_fec_t
*fec
, struct vty
*vty
);
74 static zebra_fec_t
*fec_find(struct route_table
*table
, struct prefix
*p
);
75 static zebra_fec_t
*fec_add(struct route_table
*table
, struct prefix
*p
,
76 mpls_label_t label
, uint32_t flags
,
77 uint32_t label_index
);
78 static int fec_del(zebra_fec_t
*fec
);
80 static unsigned int label_hash(const void *p
);
81 static bool label_cmp(const void *p1
, const void *p2
);
82 static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t
*nhlfe
,
83 struct nexthop
*nexthop
);
84 static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t
*nhlfe
,
85 struct nexthop
*nexthop
);
86 static int nhlfe_nexthop_active(zebra_nhlfe_t
*nhlfe
);
88 static void lsp_select_best_nhlfe(zebra_lsp_t
*lsp
);
89 static void lsp_uninstall_from_kernel(struct hash_bucket
*bucket
, void *ctxt
);
90 static void lsp_schedule(struct hash_bucket
*bucket
, void *ctxt
);
91 static wq_item_status
lsp_process(struct work_queue
*wq
, void *data
);
92 static void lsp_processq_del(struct work_queue
*wq
, void *data
);
93 static void lsp_processq_complete(struct work_queue
*wq
);
94 static int lsp_processq_add(zebra_lsp_t
*lsp
);
95 static void *lsp_alloc(void *p
);
97 static char *nhlfe2str(zebra_nhlfe_t
*nhlfe
, char *buf
, int size
);
98 static int nhlfe_nhop_match(zebra_nhlfe_t
*nhlfe
, enum nexthop_types_t gtype
,
99 union g_addr
*gate
, ifindex_t ifindex
);
100 static zebra_nhlfe_t
*nhlfe_find(zebra_lsp_t
*lsp
, enum lsp_types_t lsp_type
,
101 enum nexthop_types_t gtype
, union g_addr
*gate
,
103 static zebra_nhlfe_t
*nhlfe_add(zebra_lsp_t
*lsp
, enum lsp_types_t lsp_type
,
104 enum nexthop_types_t gtype
, union g_addr
*gate
,
105 ifindex_t ifindex
, uint8_t num_labels
,
106 mpls_label_t
*labels
);
107 static int nhlfe_del(zebra_nhlfe_t
*snhlfe
);
108 static void nhlfe_out_label_update(zebra_nhlfe_t
*nhlfe
,
109 struct mpls_label_stack
*nh_label
);
110 static int mpls_lsp_uninstall_all(struct hash
*lsp_table
, zebra_lsp_t
*lsp
,
111 enum lsp_types_t type
);
112 static int mpls_static_lsp_uninstall_all(struct zebra_vrf
*zvrf
,
113 mpls_label_t in_label
);
114 static void nhlfe_print(zebra_nhlfe_t
*nhlfe
, struct vty
*vty
);
115 static void lsp_print(zebra_lsp_t
*lsp
, void *ctxt
);
116 static void *slsp_alloc(void *p
);
117 static int snhlfe_match(zebra_snhlfe_t
*snhlfe
, enum nexthop_types_t gtype
,
118 union g_addr
*gate
, ifindex_t ifindex
);
119 static zebra_snhlfe_t
*snhlfe_find(zebra_slsp_t
*slsp
,
120 enum nexthop_types_t gtype
,
121 union g_addr
*gate
, ifindex_t ifindex
);
122 static zebra_snhlfe_t
*snhlfe_add(zebra_slsp_t
*slsp
,
123 enum nexthop_types_t gtype
,
124 union g_addr
*gate
, ifindex_t ifindex
,
125 mpls_label_t out_label
);
126 static int snhlfe_del(zebra_snhlfe_t
*snhlfe
);
127 static int snhlfe_del_all(zebra_slsp_t
*slsp
);
128 static char *snhlfe2str(zebra_snhlfe_t
*snhlfe
, char *buf
, int size
);
129 static void mpls_lsp_uninstall_all_type(struct hash_bucket
*bucket
, void *ctxt
);
130 static void mpls_ftn_uninstall_all(struct zebra_vrf
*zvrf
,
131 int afi
, enum lsp_types_t lsp_type
);
134 /* Static functions */
137 * Handle failure in LSP install, clear flags for NHLFE.
139 static void clear_nhlfe_installed(zebra_lsp_t
*lsp
)
141 zebra_nhlfe_t
*nhlfe
;
142 struct nexthop
*nexthop
;
144 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
) {
145 nexthop
= nhlfe
->nexthop
;
149 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
150 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
);
155 * Install label forwarding entry based on labeled-route entry.
157 static int lsp_install(struct zebra_vrf
*zvrf
, mpls_label_t label
,
158 struct route_node
*rn
, struct route_entry
*re
)
160 struct hash
*lsp_table
;
163 zebra_nhlfe_t
*nhlfe
;
164 struct nexthop
*nexthop
;
165 enum lsp_types_t lsp_type
;
170 lsp_table
= zvrf
->lsp_table
;
174 lsp_type
= lsp_type_from_re_type(re
->type
);
177 /* Locate or allocate LSP entry. */
178 tmp_ile
.in_label
= label
;
179 lsp
= hash_get(lsp_table
, &tmp_ile
, lsp_alloc
);
183 /* For each active nexthop, create NHLFE. Note that we deliberately skip
184 * recursive nexthops right now, because intermediate hops won't
186 * the label advertised by the recursive nexthop (plus we don't have the
187 * logic yet to push multiple labels).
189 for (nexthop
= re
->nhe
->nhg
->nexthop
;
190 nexthop
; nexthop
= nexthop
->next
) {
191 /* Skip inactive and recursive entries. */
192 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
194 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
197 nhlfe
= nhlfe_find(lsp
, lsp_type
, nexthop
->type
, &nexthop
->gate
,
200 /* Clear deleted flag (in case it was set) */
201 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
);
202 if (nexthop_labels_match(nhlfe
->nexthop
, nexthop
))
207 if (IS_ZEBRA_DEBUG_MPLS
) {
208 nhlfe2str(nhlfe
, buf
, BUFSIZ
);
210 "LSP in-label %u type %d nexthop %s "
212 lsp
->ile
.in_label
, lsp_type
, buf
);
215 /* Update out label, trigger processing. */
216 nhlfe_out_label_update(nhlfe
, nexthop
->nh_label
);
217 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_CHANGED
);
220 /* Add LSP entry to this nexthop */
221 nhlfe
= nhlfe_add(lsp
, lsp_type
, nexthop
->type
,
222 &nexthop
->gate
, nexthop
->ifindex
,
223 nexthop
->nh_label
->num_labels
,
224 nexthop
->nh_label
->label
);
228 if (IS_ZEBRA_DEBUG_MPLS
) {
229 nhlfe2str(nhlfe
, buf
, BUFSIZ
);
231 "Add LSP in-label %u type %d nexthop %s "
233 lsp
->ile
.in_label
, lsp_type
, buf
,
234 nexthop
->nh_label
->label
[0]);
237 lsp
->addr_family
= NHLFE_FAMILY(nhlfe
);
239 /* Mark NHLFE as changed. */
240 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_CHANGED
);
245 /* Queue LSP for processing if necessary. If no NHLFE got added (special
246 * case), delete the LSP entry; this case results in somewhat ugly
249 if (added
|| changed
) {
250 if (lsp_processq_add(lsp
))
252 } else if (!lsp
->nhlfe_list
253 && !CHECK_FLAG(lsp
->flags
, LSP_FLAG_SCHEDULED
)) {
254 if (IS_ZEBRA_DEBUG_MPLS
)
255 zlog_debug("Free LSP in-label %u flags 0x%x",
256 lsp
->ile
.in_label
, lsp
->flags
);
258 lsp
= hash_release(lsp_table
, &lsp
->ile
);
259 XFREE(MTYPE_LSP
, lsp
);
266 * Uninstall all non-static NHLFEs of a label forwarding entry. If all
267 * NHLFEs are removed, the entire entry is deleted.
269 static int lsp_uninstall(struct zebra_vrf
*zvrf
, mpls_label_t label
)
271 struct hash
*lsp_table
;
274 zebra_nhlfe_t
*nhlfe
, *nhlfe_next
;
278 lsp_table
= zvrf
->lsp_table
;
282 /* If entry is not present, exit. */
283 tmp_ile
.in_label
= label
;
284 lsp
= hash_lookup(lsp_table
, &tmp_ile
);
285 if (!lsp
|| !lsp
->nhlfe_list
)
288 /* Mark NHLFEs for delete or directly delete, as appropriate. */
289 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe_next
) {
290 nhlfe_next
= nhlfe
->next
;
292 /* Skip static NHLFEs */
293 if (nhlfe
->type
== ZEBRA_LSP_STATIC
)
296 if (IS_ZEBRA_DEBUG_MPLS
) {
297 nhlfe2str(nhlfe
, buf
, BUFSIZ
);
299 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
300 label
, nhlfe
->type
, buf
, nhlfe
->flags
);
303 if (CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_SELECTED
)) {
304 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_CHANGED
);
305 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
);
311 /* Queue LSP for processing, if needed, else delete. */
312 if (CHECK_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
)) {
313 if (lsp_processq_add(lsp
))
315 } else if (!lsp
->nhlfe_list
316 && !CHECK_FLAG(lsp
->flags
, LSP_FLAG_SCHEDULED
)) {
317 if (IS_ZEBRA_DEBUG_MPLS
)
318 zlog_debug("Del LSP in-label %u flags 0x%x",
319 lsp
->ile
.in_label
, lsp
->flags
);
321 lsp
= hash_release(lsp_table
, &lsp
->ile
);
322 XFREE(MTYPE_LSP
, lsp
);
329 * This function is invoked upon change to label block configuration; it
330 * will walk all registered FECs with label-index and appropriately update
331 * their local labels and trigger client updates.
333 static void fec_evaluate(struct zebra_vrf
*zvrf
)
335 struct route_node
*rn
;
337 uint32_t old_label
, new_label
;
341 for (af
= AFI_IP
; af
< AFI_MAX
; af
++) {
342 if (zvrf
->fec_table
[af
] == NULL
)
345 for (rn
= route_top(zvrf
->fec_table
[af
]); rn
;
346 rn
= route_next(rn
)) {
347 if ((fec
= rn
->info
) == NULL
)
350 /* Skip configured FECs and those without a label index.
352 if (fec
->flags
& FEC_FLAG_CONFIGURED
353 || fec
->label_index
== MPLS_INVALID_LABEL_INDEX
)
356 if (IS_ZEBRA_DEBUG_MPLS
)
357 prefix2str(&rn
->p
, buf
, BUFSIZ
);
359 /* Save old label, determine new label. */
360 old_label
= fec
->label
;
362 zvrf
->mpls_srgb
.start_label
+ fec
->label_index
;
363 if (new_label
>= zvrf
->mpls_srgb
.end_label
)
364 new_label
= MPLS_INVALID_LABEL
;
366 /* If label has changed, update FEC and clients. */
367 if (new_label
== old_label
)
370 if (IS_ZEBRA_DEBUG_MPLS
)
372 "Update fec %s new label %u upon label block",
375 fec
->label
= new_label
;
376 fec_update_clients(fec
);
378 /* Update label forwarding entries appropriately */
379 fec_change_update_lsp(zvrf
, fec
, old_label
);
385 * Derive (if possible) and update the local label for the FEC based on
386 * its label index. The index is "acceptable" if it falls within the
387 * globally configured label block (SRGB).
389 static uint32_t fec_derive_label_from_index(struct zebra_vrf
*zvrf
,
394 if (fec
->label_index
!= MPLS_INVALID_LABEL_INDEX
395 && zvrf
->mpls_srgb
.start_label
396 && ((label
= zvrf
->mpls_srgb
.start_label
+ fec
->label_index
)
397 < zvrf
->mpls_srgb
.end_label
))
400 fec
->label
= MPLS_INVALID_LABEL
;
406 * There is a change for this FEC. Install or uninstall label forwarding
407 * entries, as appropriate.
409 static int fec_change_update_lsp(struct zebra_vrf
*zvrf
, zebra_fec_t
*fec
,
410 mpls_label_t old_label
)
412 struct route_table
*table
;
413 struct route_node
*rn
;
414 struct route_entry
*re
;
417 /* Uninstall label forwarding entry, if previously installed. */
418 if (old_label
!= MPLS_INVALID_LABEL
419 && old_label
!= MPLS_LABEL_IMPLICIT_NULL
)
420 lsp_uninstall(zvrf
, old_label
);
422 /* Install label forwarding entry corr. to new label, if needed. */
423 if (fec
->label
== MPLS_INVALID_LABEL
424 || fec
->label
== MPLS_LABEL_IMPLICIT_NULL
)
427 afi
= family2afi(PREFIX_FAMILY(&fec
->rn
->p
));
428 table
= zebra_vrf_table(afi
, SAFI_UNICAST
, zvrf_id(zvrf
));
432 /* See if labeled route exists. */
433 rn
= route_node_lookup(table
, &fec
->rn
->p
);
437 RNODE_FOREACH_RE (rn
, re
) {
438 if (CHECK_FLAG(re
->flags
, ZEBRA_FLAG_SELECTED
))
442 if (!re
|| !zebra_rib_labeled_unicast(re
))
445 if (lsp_install(zvrf
, fec
->label
, rn
, re
))
452 * Inform about FEC to a registered client.
454 static int fec_send(zebra_fec_t
*fec
, struct zserv
*client
)
457 struct route_node
*rn
;
461 /* Get output stream. */
462 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
464 zclient_create_header(s
, ZEBRA_FEC_UPDATE
, VRF_DEFAULT
);
466 stream_putw(s
, rn
->p
.family
);
467 stream_put_prefix(s
, &rn
->p
);
468 stream_putl(s
, fec
->label
);
469 stream_putw_at(s
, 0, stream_get_endp(s
));
470 return zserv_send_message(client
, s
);
474 * Update all registered clients about this FEC. Caller should've updated
475 * FEC and ensure no duplicate updates.
477 static void fec_update_clients(zebra_fec_t
*fec
)
479 struct listnode
*node
;
480 struct zserv
*client
;
482 for (ALL_LIST_ELEMENTS_RO(fec
->client_list
, node
, client
)) {
483 if (IS_ZEBRA_DEBUG_MPLS
)
484 zlog_debug("Update client %s",
485 zebra_route_string(client
->proto
));
486 fec_send(fec
, client
);
492 * Print a FEC-label binding entry.
494 static void fec_print(zebra_fec_t
*fec
, struct vty
*vty
)
496 struct route_node
*rn
;
497 struct listnode
*node
;
498 struct zserv
*client
;
502 prefix2str(&rn
->p
, buf
, BUFSIZ
);
503 vty_out(vty
, "%s\n", buf
);
504 vty_out(vty
, " Label: %s", label2str(fec
->label
, buf
, BUFSIZ
));
505 if (fec
->label_index
!= MPLS_INVALID_LABEL_INDEX
)
506 vty_out(vty
, ", Label Index: %u", fec
->label_index
);
508 if (!list_isempty(fec
->client_list
)) {
509 vty_out(vty
, " Client list:");
510 for (ALL_LIST_ELEMENTS_RO(fec
->client_list
, node
, client
))
511 vty_out(vty
, " %s(fd %d)",
512 zebra_route_string(client
->proto
),
519 * Locate FEC-label binding that matches with passed info.
521 static zebra_fec_t
*fec_find(struct route_table
*table
, struct prefix
*p
)
523 struct route_node
*rn
;
526 rn
= route_node_lookup(table
, p
);
530 route_unlock_node(rn
);
535 * Add a FEC. This may be upon a client registering for a binding
536 * or when a binding is configured.
538 static zebra_fec_t
*fec_add(struct route_table
*table
, struct prefix
*p
,
539 mpls_label_t label
, uint32_t flags
,
540 uint32_t label_index
)
542 struct route_node
*rn
;
547 /* Lookup (or add) route node.*/
548 rn
= route_node_get(table
, p
);
555 fec
= XCALLOC(MTYPE_FEC
, sizeof(zebra_fec_t
));
560 fec
->client_list
= list_new();
562 route_unlock_node(rn
); /* for the route_node_get */
564 fec
->label_index
= label_index
;
571 * Delete a FEC. This may be upon the last client deregistering for
572 * a FEC and no binding exists or when the binding is deleted and there
573 * are no registered clients.
575 static int fec_del(zebra_fec_t
*fec
)
577 list_delete(&fec
->client_list
);
578 fec
->rn
->info
= NULL
;
579 route_unlock_node(fec
->rn
);
580 XFREE(MTYPE_FEC
, fec
);
585 * Hash function for label.
587 static unsigned int label_hash(const void *p
)
589 const zebra_ile_t
*ile
= p
;
591 return (jhash_1word(ile
->in_label
, 0));
595 * Compare 2 LSP hash entries based on in-label.
597 static bool label_cmp(const void *p1
, const void *p2
)
599 const zebra_ile_t
*ile1
= p1
;
600 const zebra_ile_t
*ile2
= p2
;
602 return (ile1
->in_label
== ile2
->in_label
);
606 * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
608 * NOTE: Looking only for connected routes right now.
610 static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t
*nhlfe
,
611 struct nexthop
*nexthop
)
613 struct route_table
*table
;
614 struct prefix_ipv4 p
;
615 struct route_node
*rn
;
616 struct route_entry
*match
;
617 struct nexthop
*match_nh
;
619 table
= zebra_vrf_table(AFI_IP
, SAFI_UNICAST
, nexthop
->vrf_id
);
623 /* Lookup nexthop in IPv4 routing table. */
624 memset(&p
, 0, sizeof(struct prefix_ipv4
));
626 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
627 p
.prefix
= nexthop
->gate
.ipv4
;
629 rn
= route_node_match(table
, (struct prefix
*)&p
);
633 route_unlock_node(rn
);
635 /* Locate a valid connected route. */
636 RNODE_FOREACH_RE (rn
, match
) {
637 if (CHECK_FLAG(match
->status
, ROUTE_ENTRY_REMOVED
)
638 || !CHECK_FLAG(match
->flags
, ZEBRA_FLAG_SELECTED
))
641 for (match_nh
= match
->nhe
->nhg
->nexthop
; match_nh
;
642 match_nh
= match_nh
->next
) {
643 if (match
->type
== ZEBRA_ROUTE_CONNECT
644 || nexthop
->ifindex
== match_nh
->ifindex
) {
645 nexthop
->ifindex
= match_nh
->ifindex
;
656 * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
658 * NOTE: Looking only for connected routes right now.
660 static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t
*nhlfe
,
661 struct nexthop
*nexthop
)
663 struct route_table
*table
;
664 struct prefix_ipv6 p
;
665 struct route_node
*rn
;
666 struct route_entry
*match
;
668 table
= zebra_vrf_table(AFI_IP6
, SAFI_UNICAST
, nexthop
->vrf_id
);
672 /* Lookup nexthop in IPv6 routing table. */
673 memset(&p
, 0, sizeof(struct prefix_ipv6
));
675 p
.prefixlen
= IPV6_MAX_PREFIXLEN
;
676 p
.prefix
= nexthop
->gate
.ipv6
;
678 rn
= route_node_match(table
, (struct prefix
*)&p
);
682 route_unlock_node(rn
);
684 /* Locate a valid connected route. */
685 RNODE_FOREACH_RE (rn
, match
) {
686 if ((match
->type
== ZEBRA_ROUTE_CONNECT
)
687 && !CHECK_FLAG(match
->status
, ROUTE_ENTRY_REMOVED
)
688 && CHECK_FLAG(match
->flags
, ZEBRA_FLAG_SELECTED
))
692 if (!match
|| !match
->nhe
->nhg
->nexthop
)
695 nexthop
->ifindex
= match
->nhe
->nhg
->nexthop
->ifindex
;
701 * Check the nexthop reachability for a NHLFE and return if valid (reachable)
703 * NOTE: Each NHLFE points to only 1 nexthop.
705 static int nhlfe_nexthop_active(zebra_nhlfe_t
*nhlfe
)
707 struct nexthop
*nexthop
;
708 struct interface
*ifp
;
709 struct zebra_ns
*zns
;
711 nexthop
= nhlfe
->nexthop
;
712 if (!nexthop
) // unexpected
715 /* Check on nexthop based on type. */
716 switch (nexthop
->type
) {
717 case NEXTHOP_TYPE_IFINDEX
:
719 * Lookup if this type is special. The
720 * NEXTHOP_TYPE_IFINDEX is a pop and
721 * forward into a different table for
722 * processing. As such this ifindex
723 * passed to us may be a VRF device
724 * which will not be in the default
725 * VRF. So let's look in all of them
727 zns
= zebra_ns_lookup(NS_DEFAULT
);
728 ifp
= if_lookup_by_index_per_ns(zns
, nexthop
->ifindex
);
729 if (ifp
&& if_is_operative(ifp
))
730 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
732 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
734 case NEXTHOP_TYPE_IPV4
:
735 case NEXTHOP_TYPE_IPV4_IFINDEX
:
736 if (nhlfe_nexthop_active_ipv4(nhlfe
, nexthop
))
737 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
739 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
742 case NEXTHOP_TYPE_IPV6
:
743 if (nhlfe_nexthop_active_ipv6(nhlfe
, nexthop
))
744 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
746 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
749 case NEXTHOP_TYPE_IPV6_IFINDEX
:
750 if (IN6_IS_ADDR_LINKLOCAL(&nexthop
->gate
.ipv6
)) {
751 ifp
= if_lookup_by_index(nexthop
->ifindex
,
753 if (ifp
&& if_is_operative(ifp
))
754 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
756 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
758 if (nhlfe_nexthop_active_ipv6(nhlfe
, nexthop
))
759 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
761 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
769 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
773 * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
774 * reachability and select the best. Multipath entries are also
775 * marked. This is invoked when an LSP scheduled for processing (due
776 * to some change) is examined.
778 static void lsp_select_best_nhlfe(zebra_lsp_t
*lsp
)
780 zebra_nhlfe_t
*nhlfe
;
782 struct nexthop
*nexthop
;
790 UNSET_FLAG(lsp
->flags
, LSP_FLAG_CHANGED
);
793 * First compute the best path, after checking nexthop status. We are
795 * concerned with non-deleted NHLFEs.
797 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
) {
798 /* Clear selection flags. */
799 UNSET_FLAG(nhlfe
->flags
,
800 (NHLFE_FLAG_SELECTED
| NHLFE_FLAG_MULTIPATH
));
802 if (!CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
)
803 && nhlfe_nexthop_active(nhlfe
)) {
804 if (!best
|| (nhlfe
->distance
< best
->distance
))
809 lsp
->best_nhlfe
= best
;
810 if (!lsp
->best_nhlfe
)
813 /* Mark best NHLFE as selected. */
814 SET_FLAG(lsp
->best_nhlfe
->flags
, NHLFE_FLAG_SELECTED
);
817 * If best path exists, see if there is ECMP. While doing this, note if
819 * new (uninstalled) NHLFE has been selected, an installed entry that is
820 * still selected has a change or an installed entry is to be removed.
822 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
) {
823 int nh_chg
, nh_sel
, nh_inst
;
825 nexthop
= nhlfe
->nexthop
;
826 if (!nexthop
) // unexpected
829 if (!CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
)
830 && CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)
831 && (nhlfe
->distance
== lsp
->best_nhlfe
->distance
)) {
832 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_SELECTED
);
833 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_MULTIPATH
);
837 if (CHECK_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
) && !changed
) {
838 nh_chg
= CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_CHANGED
);
839 nh_sel
= CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_SELECTED
);
841 CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
843 if ((nh_sel
&& !nh_inst
)
844 || (nh_sel
&& nh_inst
&& nh_chg
)
845 || (nh_inst
&& !nh_sel
))
849 /* We have finished examining, clear changed flag. */
850 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_CHANGED
);
854 SET_FLAG(lsp
->flags
, LSP_FLAG_CHANGED
);
858 * Delete LSP forwarding entry from kernel, if installed. Called upon
861 static void lsp_uninstall_from_kernel(struct hash_bucket
*bucket
, void *ctxt
)
865 lsp
= (zebra_lsp_t
*)bucket
->data
;
866 if (CHECK_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
))
867 (void)dplane_lsp_delete(lsp
);
871 * Schedule LSP forwarding entry for processing. Called upon changes
872 * that may impact LSPs such as nexthop / connected route changes.
874 static void lsp_schedule(struct hash_bucket
*bucket
, void *ctxt
)
878 lsp
= (zebra_lsp_t
*)bucket
->data
;
879 (void)lsp_processq_add(lsp
);
883 * Process a LSP entry that is in the queue. Recalculate best NHLFE and
884 * any multipaths and update or delete from the kernel, as needed.
886 static wq_item_status
lsp_process(struct work_queue
*wq
, void *data
)
889 zebra_nhlfe_t
*oldbest
, *newbest
;
890 char buf
[BUFSIZ
], buf2
[BUFSIZ
];
891 struct zebra_vrf
*zvrf
= vrf_info_lookup(VRF_DEFAULT
);
892 enum zebra_dplane_result res
;
894 lsp
= (zebra_lsp_t
*)data
;
895 if (!lsp
) // unexpected
898 oldbest
= lsp
->best_nhlfe
;
900 /* Select best NHLFE(s) */
901 lsp_select_best_nhlfe(lsp
);
903 newbest
= lsp
->best_nhlfe
;
905 if (IS_ZEBRA_DEBUG_MPLS
) {
907 nhlfe2str(oldbest
, buf
, BUFSIZ
);
909 nhlfe2str(newbest
, buf2
, BUFSIZ
);
911 "Process LSP in-label %u oldbest %s newbest %s "
912 "flags 0x%x ecmp# %d",
913 lsp
->ile
.in_label
, oldbest
? buf
: "NULL",
914 newbest
? buf2
: "NULL", lsp
->flags
, lsp
->num_ecmp
);
917 if (!CHECK_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
)) {
918 /* Not already installed */
921 UNSET_FLAG(lsp
->flags
, LSP_FLAG_CHANGED
);
923 switch (dplane_lsp_add(lsp
)) {
924 case ZEBRA_DPLANE_REQUEST_QUEUED
:
925 /* Set 'installed' flag so we will know
926 * that an install is in-flight.
928 SET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
930 zvrf
->lsp_installs_queued
++;
932 case ZEBRA_DPLANE_REQUEST_FAILURE
:
933 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE
,
934 "LSP Install Failure: %u",
937 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
938 zvrf
->lsp_installs
++;
943 /* Installed, may need an update and/or delete. */
945 res
= dplane_lsp_delete(lsp
);
947 /* We do some of the lsp cleanup immediately for
950 UNSET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
951 clear_nhlfe_installed(lsp
);
954 case ZEBRA_DPLANE_REQUEST_QUEUED
:
955 zvrf
->lsp_removals_queued
++;
957 case ZEBRA_DPLANE_REQUEST_FAILURE
:
958 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE
,
959 "LSP Deletion Failure: %u",
962 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
963 zvrf
->lsp_removals
++;
966 } else if (CHECK_FLAG(lsp
->flags
, LSP_FLAG_CHANGED
)) {
967 zebra_nhlfe_t
*nhlfe
;
968 struct nexthop
*nexthop
;
970 UNSET_FLAG(lsp
->flags
, LSP_FLAG_CHANGED
);
972 /* We leave the INSTALLED flag set here
973 * so we know an update in in-flight.
977 * Any NHLFE that was installed but is not
978 * selected now needs to have its flags updated.
980 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
;
981 nhlfe
= nhlfe
->next
) {
982 nexthop
= nhlfe
->nexthop
;
986 if (CHECK_FLAG(nhlfe
->flags
,
987 NHLFE_FLAG_INSTALLED
)
988 && !CHECK_FLAG(nhlfe
->flags
,
989 NHLFE_FLAG_SELECTED
)) {
990 UNSET_FLAG(nhlfe
->flags
,
991 NHLFE_FLAG_INSTALLED
);
992 UNSET_FLAG(nexthop
->flags
,
997 switch (dplane_lsp_update(lsp
)) {
998 case ZEBRA_DPLANE_REQUEST_QUEUED
:
999 zvrf
->lsp_installs_queued
++;
1001 case ZEBRA_DPLANE_REQUEST_FAILURE
:
1002 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE
,
1003 "LSP Update Failure: %u",
1006 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
1007 zvrf
->lsp_installs
++;
1018 * Callback upon processing completion of a LSP forwarding entry.
1020 static void lsp_processq_del(struct work_queue
*wq
, void *data
)
1022 struct zebra_vrf
*zvrf
;
1024 struct hash
*lsp_table
;
1025 zebra_nhlfe_t
*nhlfe
, *nhlfe_next
;
1027 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
1030 lsp_table
= zvrf
->lsp_table
;
1031 if (!lsp_table
) // unexpected
1034 lsp
= (zebra_lsp_t
*)data
;
1035 if (!lsp
) // unexpected
1038 /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
1040 * delete LSP entry also.
1042 UNSET_FLAG(lsp
->flags
, LSP_FLAG_SCHEDULED
);
1044 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe_next
) {
1045 nhlfe_next
= nhlfe
->next
;
1046 if (CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
))
1050 if (!lsp
->nhlfe_list
) {
1051 if (IS_ZEBRA_DEBUG_MPLS
)
1052 zlog_debug("Free LSP in-label %u flags 0x%x",
1053 lsp
->ile
.in_label
, lsp
->flags
);
1055 lsp
= hash_release(lsp_table
, &lsp
->ile
);
1056 XFREE(MTYPE_LSP
, lsp
);
1061 * Callback upon finishing the processing of all scheduled
1062 * LSP forwarding entries.
1064 static void lsp_processq_complete(struct work_queue
*wq
)
1066 /* Nothing to do for now. */
1070 * Add LSP forwarding entry to queue for subsequent processing.
1072 static int lsp_processq_add(zebra_lsp_t
*lsp
)
1074 /* If already scheduled, exit. */
1075 if (CHECK_FLAG(lsp
->flags
, LSP_FLAG_SCHEDULED
))
1078 if (zrouter
.lsp_process_q
== NULL
) {
1079 flog_err(EC_ZEBRA_WQ_NONEXISTENT
,
1080 "%s: work_queue does not exist!", __func__
);
1084 work_queue_add(zrouter
.lsp_process_q
, lsp
);
1085 SET_FLAG(lsp
->flags
, LSP_FLAG_SCHEDULED
);
1090 * Callback to allocate LSP forwarding table entry.
1092 static void *lsp_alloc(void *p
)
1094 const zebra_ile_t
*ile
= p
;
1097 lsp
= XCALLOC(MTYPE_LSP
, sizeof(zebra_lsp_t
));
1100 if (IS_ZEBRA_DEBUG_MPLS
)
1101 zlog_debug("Alloc LSP in-label %u", lsp
->ile
.in_label
);
1103 return ((void *)lsp
);
1107 * Create printable string for NHLFE entry.
1109 static char *nhlfe2str(zebra_nhlfe_t
*nhlfe
, char *buf
, int size
)
1111 struct nexthop
*nexthop
;
1114 nexthop
= nhlfe
->nexthop
;
1115 switch (nexthop
->type
) {
1116 case NEXTHOP_TYPE_IPV4
:
1117 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1118 inet_ntop(AF_INET
, &nexthop
->gate
.ipv4
, buf
, size
);
1120 case NEXTHOP_TYPE_IPV6
:
1121 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1122 inet_ntop(AF_INET6
, &nexthop
->gate
.ipv6
, buf
, size
);
1124 case NEXTHOP_TYPE_IFINDEX
:
1125 snprintf(buf
, size
, "Ifindex: %u", nexthop
->ifindex
);
1134 * Check if NHLFE matches with search info passed.
1136 static int nhlfe_nhop_match(zebra_nhlfe_t
*nhlfe
, enum nexthop_types_t gtype
,
1137 union g_addr
*gate
, ifindex_t ifindex
)
1139 struct nexthop
*nhop
;
1142 nhop
= nhlfe
->nexthop
;
1146 if (nhop
->type
!= gtype
)
1149 switch (nhop
->type
) {
1150 case NEXTHOP_TYPE_IPV4
:
1151 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1152 cmp
= memcmp(&(nhop
->gate
.ipv4
), &(gate
->ipv4
),
1153 sizeof(struct in_addr
));
1154 if (!cmp
&& nhop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
1155 cmp
= !(nhop
->ifindex
== ifindex
);
1157 case NEXTHOP_TYPE_IPV6
:
1158 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1159 cmp
= memcmp(&(nhop
->gate
.ipv6
), &(gate
->ipv6
),
1160 sizeof(struct in6_addr
));
1161 if (!cmp
&& nhop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
1162 cmp
= !(nhop
->ifindex
== ifindex
);
1164 case NEXTHOP_TYPE_IFINDEX
:
1165 cmp
= !(nhop
->ifindex
== ifindex
);
1176 * Locate NHLFE that matches with passed info.
1178 static zebra_nhlfe_t
*nhlfe_find(zebra_lsp_t
*lsp
, enum lsp_types_t lsp_type
,
1179 enum nexthop_types_t gtype
, union g_addr
*gate
,
1182 zebra_nhlfe_t
*nhlfe
;
1187 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
) {
1188 if (nhlfe
->type
!= lsp_type
)
1190 if (!nhlfe_nhop_match(nhlfe
, gtype
, gate
, ifindex
))
1198 * Add NHLFE. Base entry must have been created and duplicate
1201 static zebra_nhlfe_t
*nhlfe_add(zebra_lsp_t
*lsp
, enum lsp_types_t lsp_type
,
1202 enum nexthop_types_t gtype
, union g_addr
*gate
,
1203 ifindex_t ifindex
, uint8_t num_labels
,
1204 mpls_label_t labels
[])
1206 zebra_nhlfe_t
*nhlfe
;
1207 struct nexthop
*nexthop
;
1212 nhlfe
= XCALLOC(MTYPE_NHLFE
, sizeof(zebra_nhlfe_t
));
1215 nhlfe
->type
= lsp_type
;
1216 nhlfe
->distance
= lsp_distance(lsp_type
);
1218 nexthop
= nexthop_new();
1220 XFREE(MTYPE_NHLFE
, nhlfe
);
1223 nexthop_add_labels(nexthop
, lsp_type
, num_labels
, labels
);
1225 nexthop
->vrf_id
= VRF_DEFAULT
;
1226 nexthop
->type
= gtype
;
1227 switch (nexthop
->type
) {
1228 case NEXTHOP_TYPE_IPV4
:
1229 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1230 nexthop
->gate
.ipv4
= gate
->ipv4
;
1232 nexthop
->ifindex
= ifindex
;
1234 case NEXTHOP_TYPE_IPV6
:
1235 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1236 nexthop
->gate
.ipv6
= gate
->ipv6
;
1238 nexthop
->ifindex
= ifindex
;
1240 case NEXTHOP_TYPE_IFINDEX
:
1241 nexthop
->ifindex
= ifindex
;
1244 nexthop_free(nexthop
);
1245 XFREE(MTYPE_NHLFE
, nhlfe
);
1250 nhlfe
->nexthop
= nexthop
;
1251 if (lsp
->nhlfe_list
)
1252 lsp
->nhlfe_list
->prev
= nhlfe
;
1253 nhlfe
->next
= lsp
->nhlfe_list
;
1254 lsp
->nhlfe_list
= nhlfe
;
1260 * Delete NHLFE. Entry must be present on list.
1262 static int nhlfe_del(zebra_nhlfe_t
*nhlfe
)
1275 nexthop_free(nhlfe
->nexthop
);
1277 /* Unlink from LSP */
1279 nhlfe
->next
->prev
= nhlfe
->prev
;
1281 nhlfe
->prev
->next
= nhlfe
->next
;
1283 lsp
->nhlfe_list
= nhlfe
->next
;
1285 if (nhlfe
== lsp
->best_nhlfe
)
1286 lsp
->best_nhlfe
= NULL
;
1288 XFREE(MTYPE_NHLFE
, nhlfe
);
1294 * Update label for NHLFE entry.
1296 static void nhlfe_out_label_update(zebra_nhlfe_t
*nhlfe
,
1297 struct mpls_label_stack
*nh_label
)
1299 nhlfe
->nexthop
->nh_label
->label
[0] = nh_label
->label
[0];
1302 static int mpls_lsp_uninstall_all(struct hash
*lsp_table
, zebra_lsp_t
*lsp
,
1303 enum lsp_types_t type
)
1305 zebra_nhlfe_t
*nhlfe
, *nhlfe_next
;
1306 int schedule_lsp
= 0;
1309 /* Mark NHLFEs for delete or directly delete, as appropriate. */
1310 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe_next
) {
1311 nhlfe_next
= nhlfe
->next
;
1313 /* Skip non-static NHLFEs */
1314 if (nhlfe
->type
!= type
)
1317 if (IS_ZEBRA_DEBUG_MPLS
) {
1318 nhlfe2str(nhlfe
, buf
, BUFSIZ
);
1320 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
1321 lsp
->ile
.in_label
, type
, buf
, nhlfe
->flags
);
1324 if (CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
)) {
1325 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_CHANGED
);
1326 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
);
1333 /* Queue LSP for processing, if needed, else delete. */
1335 if (lsp_processq_add(lsp
))
1337 } else if (!lsp
->nhlfe_list
1338 && !CHECK_FLAG(lsp
->flags
, LSP_FLAG_SCHEDULED
)) {
1339 if (IS_ZEBRA_DEBUG_MPLS
)
1340 zlog_debug("Free LSP in-label %u flags 0x%x",
1341 lsp
->ile
.in_label
, lsp
->flags
);
1343 lsp
= hash_release(lsp_table
, &lsp
->ile
);
1344 XFREE(MTYPE_LSP
, lsp
);
1351 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
1352 * If no other NHLFEs exist, the entry would be deleted.
1354 static int mpls_static_lsp_uninstall_all(struct zebra_vrf
*zvrf
,
1355 mpls_label_t in_label
)
1357 struct hash
*lsp_table
;
1358 zebra_ile_t tmp_ile
;
1362 lsp_table
= zvrf
->lsp_table
;
1366 /* If entry is not present, exit. */
1367 tmp_ile
.in_label
= in_label
;
1368 lsp
= hash_lookup(lsp_table
, &tmp_ile
);
1369 if (!lsp
|| !lsp
->nhlfe_list
)
1372 return mpls_lsp_uninstall_all(lsp_table
, lsp
, ZEBRA_LSP_STATIC
);
1375 static json_object
*nhlfe_json(zebra_nhlfe_t
*nhlfe
)
1378 json_object
*json_nhlfe
= NULL
;
1379 struct nexthop
*nexthop
= nhlfe
->nexthop
;
1381 json_nhlfe
= json_object_new_object();
1382 json_object_string_add(json_nhlfe
, "type", nhlfe_type2str(nhlfe
->type
));
1383 json_object_int_add(json_nhlfe
, "outLabel",
1384 nexthop
->nh_label
->label
[0]);
1385 json_object_int_add(json_nhlfe
, "distance", nhlfe
->distance
);
1387 if (CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
))
1388 json_object_boolean_true_add(json_nhlfe
, "installed");
1390 switch (nexthop
->type
) {
1391 case NEXTHOP_TYPE_IPV4
:
1392 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1393 json_object_string_add(json_nhlfe
, "nexthop",
1394 inet_ntoa(nexthop
->gate
.ipv4
));
1396 case NEXTHOP_TYPE_IPV6
:
1397 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1398 json_object_string_add(
1399 json_nhlfe
, "nexthop",
1400 inet_ntop(AF_INET6
, &nexthop
->gate
.ipv6
, buf
, BUFSIZ
));
1402 if (nexthop
->ifindex
)
1403 json_object_string_add(json_nhlfe
, "interface",
1404 ifindex2ifname(nexthop
->ifindex
,
1414 * Print the NHLFE for a LSP forwarding entry.
1416 static void nhlfe_print(zebra_nhlfe_t
*nhlfe
, struct vty
*vty
)
1418 struct nexthop
*nexthop
;
1421 nexthop
= nhlfe
->nexthop
;
1422 if (!nexthop
|| !nexthop
->nh_label
) // unexpected
1425 vty_out(vty
, " type: %s remote label: %s distance: %d\n",
1426 nhlfe_type2str(nhlfe
->type
),
1427 label2str(nexthop
->nh_label
->label
[0], buf
, BUFSIZ
),
1429 switch (nexthop
->type
) {
1430 case NEXTHOP_TYPE_IPV4
:
1431 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1432 vty_out(vty
, " via %s", inet_ntoa(nexthop
->gate
.ipv4
));
1433 if (nexthop
->ifindex
)
1434 vty_out(vty
, " dev %s",
1435 ifindex2ifname(nexthop
->ifindex
,
1438 case NEXTHOP_TYPE_IPV6
:
1439 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1440 vty_out(vty
, " via %s",
1441 inet_ntop(AF_INET6
, &nexthop
->gate
.ipv6
, buf
, BUFSIZ
));
1442 if (nexthop
->ifindex
)
1443 vty_out(vty
, " dev %s",
1444 ifindex2ifname(nexthop
->ifindex
,
1451 CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
) ? " (installed)"
1457 * Print an LSP forwarding entry.
1459 static void lsp_print(zebra_lsp_t
*lsp
, void *ctxt
)
1461 zebra_nhlfe_t
*nhlfe
;
1464 vty
= (struct vty
*)ctxt
;
1466 vty_out(vty
, "Local label: %u%s\n", lsp
->ile
.in_label
,
1467 CHECK_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
) ? " (installed)"
1470 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
)
1471 nhlfe_print(nhlfe
, vty
);
1475 * JSON objects for an LSP forwarding entry.
1477 static json_object
*lsp_json(zebra_lsp_t
*lsp
)
1479 zebra_nhlfe_t
*nhlfe
= NULL
;
1480 json_object
*json
= json_object_new_object();
1481 json_object
*json_nhlfe_list
= json_object_new_array();
1483 json_object_int_add(json
, "inLabel", lsp
->ile
.in_label
);
1485 if (CHECK_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
))
1486 json_object_boolean_true_add(json
, "installed");
1488 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
)
1489 json_object_array_add(json_nhlfe_list
, nhlfe_json(nhlfe
));
1491 json_object_object_add(json
, "nexthops", json_nhlfe_list
);
1496 /* Return a sorted linked list of the hash contents */
1497 static struct list
*hash_get_sorted_list(struct hash
*hash
, void *cmp
)
1500 struct hash_bucket
*hb
;
1501 struct list
*sorted_list
= list_new();
1503 sorted_list
->cmp
= (int (*)(void *, void *))cmp
;
1505 for (i
= 0; i
< hash
->size
; i
++)
1506 for (hb
= hash
->index
[i
]; hb
; hb
= hb
->next
)
1507 listnode_add_sort(sorted_list
, hb
->data
);
1513 * Compare two LSPs based on their label values.
1515 static int lsp_cmp(zebra_lsp_t
*lsp1
, zebra_lsp_t
*lsp2
)
1517 if (lsp1
->ile
.in_label
< lsp2
->ile
.in_label
)
1520 if (lsp1
->ile
.in_label
> lsp2
->ile
.in_label
)
1527 * Callback to allocate static LSP.
1529 static void *slsp_alloc(void *p
)
1531 const zebra_ile_t
*ile
= p
;
1534 slsp
= XCALLOC(MTYPE_SLSP
, sizeof(zebra_slsp_t
));
1536 return ((void *)slsp
);
1540 * Compare two static LSPs based on their label values.
1542 static int slsp_cmp(zebra_slsp_t
*slsp1
, zebra_slsp_t
*slsp2
)
1544 if (slsp1
->ile
.in_label
< slsp2
->ile
.in_label
)
1547 if (slsp1
->ile
.in_label
> slsp2
->ile
.in_label
)
1554 * Check if static NHLFE matches with search info passed.
1556 static int snhlfe_match(zebra_snhlfe_t
*snhlfe
, enum nexthop_types_t gtype
,
1557 union g_addr
*gate
, ifindex_t ifindex
)
1561 if (snhlfe
->gtype
!= gtype
)
1564 switch (snhlfe
->gtype
) {
1565 case NEXTHOP_TYPE_IPV4
:
1566 cmp
= memcmp(&(snhlfe
->gate
.ipv4
), &(gate
->ipv4
),
1567 sizeof(struct in_addr
));
1569 case NEXTHOP_TYPE_IPV6
:
1570 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1571 cmp
= memcmp(&(snhlfe
->gate
.ipv6
), &(gate
->ipv6
),
1572 sizeof(struct in6_addr
));
1573 if (!cmp
&& snhlfe
->gtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
1574 cmp
= !(snhlfe
->ifindex
== ifindex
);
1584 * Locate static NHLFE that matches with passed info.
1586 static zebra_snhlfe_t
*snhlfe_find(zebra_slsp_t
*slsp
,
1587 enum nexthop_types_t gtype
,
1588 union g_addr
*gate
, ifindex_t ifindex
)
1590 zebra_snhlfe_t
*snhlfe
;
1595 for (snhlfe
= slsp
->snhlfe_list
; snhlfe
; snhlfe
= snhlfe
->next
) {
1596 if (!snhlfe_match(snhlfe
, gtype
, gate
, ifindex
))
1605 * Add static NHLFE. Base LSP config entry must have been created
1606 * and duplicate check done.
1608 static zebra_snhlfe_t
*snhlfe_add(zebra_slsp_t
*slsp
,
1609 enum nexthop_types_t gtype
,
1610 union g_addr
*gate
, ifindex_t ifindex
,
1611 mpls_label_t out_label
)
1613 zebra_snhlfe_t
*snhlfe
;
1618 snhlfe
= XCALLOC(MTYPE_SNHLFE
, sizeof(zebra_snhlfe_t
));
1619 snhlfe
->slsp
= slsp
;
1620 snhlfe
->out_label
= out_label
;
1621 snhlfe
->gtype
= gtype
;
1623 case NEXTHOP_TYPE_IPV4
:
1624 snhlfe
->gate
.ipv4
= gate
->ipv4
;
1626 case NEXTHOP_TYPE_IPV6
:
1627 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1628 snhlfe
->gate
.ipv6
= gate
->ipv6
;
1630 snhlfe
->ifindex
= ifindex
;
1633 XFREE(MTYPE_SNHLFE
, snhlfe
);
1637 if (slsp
->snhlfe_list
)
1638 slsp
->snhlfe_list
->prev
= snhlfe
;
1639 snhlfe
->next
= slsp
->snhlfe_list
;
1640 slsp
->snhlfe_list
= snhlfe
;
1646 * Delete static NHLFE. Entry must be present on list.
1648 static int snhlfe_del(zebra_snhlfe_t
*snhlfe
)
1655 slsp
= snhlfe
->slsp
;
1660 snhlfe
->next
->prev
= snhlfe
->prev
;
1662 snhlfe
->prev
->next
= snhlfe
->next
;
1664 slsp
->snhlfe_list
= snhlfe
->next
;
1666 snhlfe
->prev
= snhlfe
->next
= NULL
;
1667 XFREE(MTYPE_SNHLFE_IFNAME
, snhlfe
->ifname
);
1668 XFREE(MTYPE_SNHLFE
, snhlfe
);
1674 * Delete all static NHLFE entries for this LSP (in label).
1676 static int snhlfe_del_all(zebra_slsp_t
*slsp
)
1678 zebra_snhlfe_t
*snhlfe
, *snhlfe_next
;
1683 for (snhlfe
= slsp
->snhlfe_list
; snhlfe
; snhlfe
= snhlfe_next
) {
1684 snhlfe_next
= snhlfe
->next
;
1692 * Create printable string for NHLFE configuration.
1694 static char *snhlfe2str(zebra_snhlfe_t
*snhlfe
, char *buf
, int size
)
1697 switch (snhlfe
->gtype
) {
1698 case NEXTHOP_TYPE_IPV4
:
1699 inet_ntop(AF_INET
, &snhlfe
->gate
.ipv4
, buf
, size
);
1701 case NEXTHOP_TYPE_IPV6
:
1702 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1703 inet_ntop(AF_INET6
, &snhlfe
->gate
.ipv6
, buf
, size
);
1704 if (snhlfe
->ifindex
)
1706 ifindex2ifname(snhlfe
->ifindex
, VRF_DEFAULT
),
1717 * Initialize work queue for processing changed LSPs.
1719 static int mpls_processq_init(void)
1721 zrouter
.lsp_process_q
= work_queue_new(zrouter
.master
, "LSP processing");
1722 if (!zrouter
.lsp_process_q
) {
1723 flog_err(EC_ZEBRA_WQ_NONEXISTENT
,
1724 "%s: could not initialise work queue!", __func__
);
1728 zrouter
.lsp_process_q
->spec
.workfunc
= &lsp_process
;
1729 zrouter
.lsp_process_q
->spec
.del_item_data
= &lsp_processq_del
;
1730 zrouter
.lsp_process_q
->spec
.errorfunc
= NULL
;
1731 zrouter
.lsp_process_q
->spec
.completion_func
= &lsp_processq_complete
;
1732 zrouter
.lsp_process_q
->spec
.max_retries
= 0;
1733 zrouter
.lsp_process_q
->spec
.hold
= 10;
1739 /* Public functions */
1742 * Process LSP update results from zebra dataplane.
1744 void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx
*ctx
)
1746 struct zebra_vrf
*zvrf
;
1747 zebra_ile_t tmp_ile
;
1748 struct hash
*lsp_table
;
1750 zebra_nhlfe_t
*nhlfe
;
1751 struct nexthop
*nexthop
;
1752 enum dplane_op_e op
;
1753 enum zebra_dplane_result status
;
1755 op
= dplane_ctx_get_op(ctx
);
1756 status
= dplane_ctx_get_status(ctx
);
1758 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL
)
1759 zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
1760 ctx
, dplane_op2str(op
),
1761 dplane_ctx_get_in_label(ctx
),
1762 dplane_res2str(status
));
1765 case DPLANE_OP_LSP_INSTALL
:
1766 case DPLANE_OP_LSP_UPDATE
:
1767 /* Look for zebra LSP object */
1768 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
1772 lsp_table
= zvrf
->lsp_table
;
1774 tmp_ile
.in_label
= dplane_ctx_get_in_label(ctx
);
1775 lsp
= hash_lookup(lsp_table
, &tmp_ile
);
1777 if (IS_ZEBRA_DEBUG_DPLANE
)
1778 zlog_debug("LSP ctx %p: in-label %u not found",
1779 ctx
, dplane_ctx_get_in_label(ctx
));
1783 /* TODO -- Confirm that this result is still 'current' */
1785 if (status
== ZEBRA_DPLANE_REQUEST_SUCCESS
) {
1786 /* Update zebra object */
1787 SET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
1788 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
;
1789 nhlfe
= nhlfe
->next
) {
1790 nexthop
= nhlfe
->nexthop
;
1794 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
1795 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
);
1798 UNSET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
1799 clear_nhlfe_installed(lsp
);
1800 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE
,
1801 "LSP Install Failure: in-label %u",
1807 case DPLANE_OP_LSP_DELETE
:
1808 if (status
!= ZEBRA_DPLANE_REQUEST_SUCCESS
)
1809 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE
,
1810 "LSP Deletion Failure: in-label %u",
1811 dplane_ctx_get_in_label(ctx
));
1819 dplane_ctx_fini(&ctx
);
1823 * Process async dplane notifications.
1825 void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx
*ctx
)
1827 struct zebra_vrf
*zvrf
;
1828 zebra_ile_t tmp_ile
;
1829 struct hash
*lsp_table
;
1831 zebra_nhlfe_t
*nhlfe
;
1832 const zebra_nhlfe_t
*ctx_nhlfe
;
1833 struct nexthop
*nexthop
;
1834 const struct nexthop
*ctx_nexthop
;
1835 int start_count
= 0, end_count
= 0; /* Installed counts */
1836 bool changed_p
= false;
1837 bool is_debug
= (IS_ZEBRA_DEBUG_DPLANE
| IS_ZEBRA_DEBUG_MPLS
);
1840 zlog_debug("LSP dplane notif, in-label %u",
1841 dplane_ctx_get_in_label(ctx
));
1843 /* Look for zebra LSP object */
1844 zvrf
= vrf_info_lookup(VRF_DEFAULT
);
1848 lsp_table
= zvrf
->lsp_table
;
1850 tmp_ile
.in_label
= dplane_ctx_get_in_label(ctx
);
1851 lsp
= hash_lookup(lsp_table
, &tmp_ile
);
1854 zlog_debug("dplane LSP notif: in-label %u not found",
1855 dplane_ctx_get_in_label(ctx
));
1860 * The dataplane/forwarding plane is notifying zebra about the state
1861 * of the nexthops associated with this LSP. First, we take a
1862 * pre-scan pass to determine whether the LSP has transitioned
1863 * from installed -> uninstalled. In that case, we need to have
1864 * the existing state of the LSP objects available before making
1867 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
) {
1868 char buf
[NEXTHOP_STRLEN
];
1870 nexthop
= nhlfe
->nexthop
;
1874 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
))
1878 for (ctx_nhlfe
= dplane_ctx_get_nhlfe(ctx
);
1879 ctx_nhlfe
; ctx_nhlfe
= ctx_nhlfe
->next
) {
1881 ctx_nexthop
= ctx_nhlfe
->nexthop
;
1885 if ((ctx_nexthop
->type
== nexthop
->type
) &&
1886 nexthop_same(ctx_nexthop
, nexthop
)) {
1893 nexthop2str(nexthop
, buf
, sizeof(buf
));
1895 if (ctx_nhlfe
&& ctx_nexthop
) {
1897 const char *tstr
= "";
1899 if (!CHECK_FLAG(ctx_nhlfe
->flags
,
1900 NHLFE_FLAG_INSTALLED
))
1903 zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
1907 /* Test zebra nhlfe install state */
1908 if (CHECK_FLAG(ctx_nhlfe
->flags
,
1909 NHLFE_FLAG_INSTALLED
)) {
1911 if (!CHECK_FLAG(nhlfe
->flags
,
1912 NHLFE_FLAG_INSTALLED
))
1915 /* Update counter */
1919 if (CHECK_FLAG(nhlfe
->flags
,
1920 NHLFE_FLAG_INSTALLED
))
1925 /* Not mentioned in lfib set -> uninstalled */
1926 if (CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
) ||
1927 CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
) ||
1928 CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
)) {
1933 zlog_debug("LSP dplane notif: no match, nh %s",
1939 zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
1940 start_count
, end_count
,
1941 changed_p
? ", changed" : "");
1944 * Has the LSP become uninstalled?
1946 if (start_count
> 0 && end_count
== 0) {
1947 /* Inform other lfibs */
1948 dplane_lsp_notif_update(lsp
, DPLANE_OP_LSP_DELETE
, ctx
);
1952 * Now we take a second pass and bring the zebra
1953 * nexthop state into sync with the forwarding-plane state.
1955 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
) {
1956 char buf
[NEXTHOP_STRLEN
];
1958 nexthop
= nhlfe
->nexthop
;
1963 for (ctx_nhlfe
= dplane_ctx_get_nhlfe(ctx
);
1964 ctx_nhlfe
; ctx_nhlfe
= ctx_nhlfe
->next
) {
1966 ctx_nexthop
= ctx_nhlfe
->nexthop
;
1970 if ((ctx_nexthop
->type
== nexthop
->type
) &&
1971 nexthop_same(ctx_nexthop
, nexthop
)) {
1978 nexthop2str(nexthop
, buf
, sizeof(buf
));
1980 if (ctx_nhlfe
&& ctx_nexthop
) {
1982 /* Bring zebra nhlfe install state into sync */
1983 if (CHECK_FLAG(ctx_nhlfe
->flags
,
1984 NHLFE_FLAG_INSTALLED
)) {
1986 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
1990 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
1993 if (CHECK_FLAG(ctx_nhlfe
->nexthop
->flags
,
1994 NEXTHOP_FLAG_FIB
)) {
1995 SET_FLAG(nhlfe
->nexthop
->flags
,
1996 NEXTHOP_FLAG_ACTIVE
);
1997 SET_FLAG(nhlfe
->nexthop
->flags
,
2000 UNSET_FLAG(nhlfe
->nexthop
->flags
,
2001 NEXTHOP_FLAG_ACTIVE
);
2002 UNSET_FLAG(nhlfe
->nexthop
->flags
,
2007 /* Not mentioned in lfib set -> uninstalled */
2009 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
2010 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
);
2011 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2015 if (end_count
> 0) {
2016 SET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
2019 dplane_lsp_notif_update(lsp
, DPLANE_OP_LSP_UPDATE
, ctx
);
2022 UNSET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
2023 clear_nhlfe_installed(lsp
);
2027 dplane_ctx_fini(&ctx
);
2031 * Install dynamic LSP entry.
2033 int zebra_mpls_lsp_install(struct zebra_vrf
*zvrf
, struct route_node
*rn
,
2034 struct route_entry
*re
)
2036 struct route_table
*table
;
2039 table
= zvrf
->fec_table
[family2afi(PREFIX_FAMILY(&rn
->p
))];
2043 /* See if there is a configured label binding for this FEC. */
2044 fec
= fec_find(table
, &rn
->p
);
2045 if (!fec
|| fec
->label
== MPLS_INVALID_LABEL
)
2048 /* We cannot install a label forwarding entry if local label is the
2049 * implicit-null label.
2051 if (fec
->label
== MPLS_LABEL_IMPLICIT_NULL
)
2054 if (lsp_install(zvrf
, fec
->label
, rn
, re
))
2061 * Uninstall dynamic LSP entry, if any.
2063 int zebra_mpls_lsp_uninstall(struct zebra_vrf
*zvrf
, struct route_node
*rn
,
2064 struct route_entry
*re
)
2066 struct route_table
*table
;
2069 table
= zvrf
->fec_table
[family2afi(PREFIX_FAMILY(&rn
->p
))];
2073 /* See if there is a configured label binding for this FEC. */
2074 fec
= fec_find(table
, &rn
->p
);
2075 if (!fec
|| fec
->label
== MPLS_INVALID_LABEL
)
2078 /* Uninstall always removes all dynamic NHLFEs. */
2079 return lsp_uninstall(zvrf
, fec
->label
);
2083 * Add an NHLFE to an LSP, return the newly-added object
2085 zebra_nhlfe_t
*zebra_mpls_lsp_add_nhlfe(zebra_lsp_t
*lsp
,
2086 enum lsp_types_t lsp_type
,
2087 enum nexthop_types_t gtype
,
2091 mpls_label_t out_labels
[])
2093 /* Just a public pass-through to the internal implementation */
2094 return nhlfe_add(lsp
, lsp_type
, gtype
, gate
, ifindex
, num_labels
,
2099 * Free an allocated NHLFE
2101 void zebra_mpls_nhlfe_del(zebra_nhlfe_t
*nhlfe
)
2103 /* Just a pass-through to the internal implementation */
2108 * Registration from a client for the label binding for a FEC. If a binding
2109 * already exists, it is informed to the client.
2110 * NOTE: If there is a manually configured label binding, that is used.
2111 * Otherwise, if a label index is specified, it means we have to allocate the
2112 * label from a locally configured label block (SRGB), if one exists and index
2113 * is acceptable. If no label index then just register the specified label.
2114 * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
2115 * by the calling function. Register requests with both will be rejected.
2117 int zebra_mpls_fec_register(struct zebra_vrf
*zvrf
, struct prefix
*p
,
2118 uint32_t label
, uint32_t label_index
,
2119 struct zserv
*client
)
2121 struct route_table
*table
;
2125 bool label_change
= false;
2127 bool have_label_index
= (label_index
!= MPLS_INVALID_LABEL_INDEX
);
2128 bool is_configured_fec
= false; /* indicate statically configured FEC */
2130 table
= zvrf
->fec_table
[family2afi(PREFIX_FAMILY(p
))];
2134 if (IS_ZEBRA_DEBUG_MPLS
)
2135 prefix2str(p
, buf
, BUFSIZ
);
2137 if (label
!= MPLS_INVALID_LABEL
&& have_label_index
) {
2139 EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT
,
2140 "Rejecting FEC register for %s with both label %u and Label Index %u specified, client %s",
2141 buf
, label
, label_index
,
2142 zebra_route_string(client
->proto
));
2147 fec
= fec_find(table
, p
);
2149 fec
= fec_add(table
, p
, label
, 0, label_index
);
2152 EC_ZEBRA_FEC_ADD_FAILED
,
2153 "Failed to add FEC %s upon register, client %s",
2154 buf
, zebra_route_string(client
->proto
));
2158 old_label
= MPLS_INVALID_LABEL
;
2161 /* Check if the FEC has been statically defined in the config */
2162 is_configured_fec
= fec
->flags
& FEC_FLAG_CONFIGURED
;
2163 /* Client may register same FEC with different label index. */
2165 (listnode_lookup(fec
->client_list
, client
) == NULL
);
2166 if (!new_client
&& fec
->label_index
== label_index
2167 && fec
->label
== label
)
2168 /* Duplicate register */
2171 /* Save current label, update the FEC */
2172 old_label
= fec
->label
;
2173 fec
->label_index
= label_index
;
2177 listnode_add(fec
->client_list
, client
);
2179 if (IS_ZEBRA_DEBUG_MPLS
)
2180 zlog_debug("FEC %s label%s %u %s by client %s%s", buf
,
2181 have_label_index
? " index" : "",
2182 have_label_index
? label_index
: label
,
2183 new_client
? "registered" : "updated",
2184 zebra_route_string(client
->proto
),
2186 ? ", but using statically configured label"
2189 /* If not a statically configured FEC, derive the local label
2190 * from label index or use the provided label
2192 if (!is_configured_fec
) {
2193 if (have_label_index
)
2194 fec_derive_label_from_index(zvrf
, fec
);
2198 /* If no label change, exit. */
2199 if (fec
->label
== old_label
)
2202 label_change
= true;
2205 /* If new client or label change, update client and install or uninstall
2206 * label forwarding entry as needed.
2208 /* Inform client of label, if needed. */
2209 if ((new_client
&& fec
->label
!= MPLS_INVALID_LABEL
) || label_change
) {
2210 if (IS_ZEBRA_DEBUG_MPLS
)
2211 zlog_debug("Update client label %u", fec
->label
);
2212 fec_send(fec
, client
);
2215 if (new_client
|| label_change
)
2216 return fec_change_update_lsp(zvrf
, fec
, old_label
);
2222 * Deregistration from a client for the label binding for a FEC. The FEC
2223 * itself is deleted if no other registered clients exist and there is no
2224 * label bound to the FEC.
2226 int zebra_mpls_fec_unregister(struct zebra_vrf
*zvrf
, struct prefix
*p
,
2227 struct zserv
*client
)
2229 struct route_table
*table
;
2233 table
= zvrf
->fec_table
[family2afi(PREFIX_FAMILY(p
))];
2237 if (IS_ZEBRA_DEBUG_MPLS
)
2238 prefix2str(p
, buf
, BUFSIZ
);
2240 fec
= fec_find(table
, p
);
2242 prefix2str(p
, buf
, BUFSIZ
);
2243 flog_err(EC_ZEBRA_FEC_RM_FAILED
,
2244 "Failed to find FEC %s upon unregister, client %s",
2245 buf
, zebra_route_string(client
->proto
));
2249 listnode_delete(fec
->client_list
, client
);
2251 if (IS_ZEBRA_DEBUG_MPLS
)
2252 zlog_debug("FEC %s unregistered by client %s", buf
,
2253 zebra_route_string(client
->proto
));
2255 /* If not a configured entry, delete the FEC if no other clients. Before
2256 * deleting, see if any LSP needs to be uninstalled.
2258 if (!(fec
->flags
& FEC_FLAG_CONFIGURED
)
2259 && list_isempty(fec
->client_list
)) {
2260 mpls_label_t old_label
= fec
->label
;
2261 fec
->label
= MPLS_INVALID_LABEL
; /* reset */
2262 fec_change_update_lsp(zvrf
, fec
, old_label
);
2270 * Cleanup any FECs registered by this client.
2272 static int zebra_mpls_cleanup_fecs_for_client(struct zserv
*client
)
2274 struct zebra_vrf
*zvrf
= vrf_info_lookup(VRF_DEFAULT
);
2275 struct route_node
*rn
;
2277 struct listnode
*node
;
2278 struct zserv
*fec_client
;
2281 for (af
= AFI_IP
; af
< AFI_MAX
; af
++) {
2282 if (zvrf
->fec_table
[af
] == NULL
)
2285 for (rn
= route_top(zvrf
->fec_table
[af
]); rn
;
2286 rn
= route_next(rn
)) {
2288 if (!fec
|| list_isempty(fec
->client_list
))
2291 for (ALL_LIST_ELEMENTS_RO(fec
->client_list
, node
,
2293 if (fec_client
== client
) {
2294 listnode_delete(fec
->client_list
,
2296 if (!(fec
->flags
& FEC_FLAG_CONFIGURED
)
2297 && list_isempty(fec
->client_list
))
2308 struct lsp_uninstall_args
{
2309 struct hash
*lsp_table
;
2310 enum lsp_types_t type
;
2314 * Cleanup MPLS labels registered by this client.
2316 static int zebra_mpls_cleanup_zclient_labels(struct zserv
*client
)
2319 struct zebra_vrf
*zvrf
;
2321 RB_FOREACH (vrf
, vrf_id_head
, &vrfs_by_id
) {
2322 struct lsp_uninstall_args args
;
2329 args
.lsp_table
= zvrf
->lsp_table
;
2330 args
.type
= lsp_type_from_re_type(client
->proto
);
2331 hash_iterate(zvrf
->lsp_table
, mpls_lsp_uninstall_all_type
,
2335 mpls_ftn_uninstall_all(zvrf
, AFI_IP
,
2336 lsp_type_from_re_type(client
->proto
));
2337 mpls_ftn_uninstall_all(zvrf
, AFI_IP6
,
2338 lsp_type_from_re_type(client
->proto
));
2345 * Return FEC (if any) to which this label is bound.
2346 * Note: Only works for per-prefix binding and when the label is not
2348 * TODO: Currently walks entire table, can optimize later with another
2351 zebra_fec_t
*zebra_mpls_fec_for_label(struct zebra_vrf
*zvrf
,
2354 struct route_node
*rn
;
2358 for (af
= AFI_IP
; af
< AFI_MAX
; af
++) {
2359 if (zvrf
->fec_table
[af
] == NULL
)
2362 for (rn
= route_top(zvrf
->fec_table
[af
]); rn
;
2363 rn
= route_next(rn
)) {
2367 if (fec
->label
== label
)
2376 * Inform if specified label is currently bound to a FEC or not.
2378 int zebra_mpls_label_already_bound(struct zebra_vrf
*zvrf
, mpls_label_t label
)
2380 return (zebra_mpls_fec_for_label(zvrf
, label
) ? 1 : 0);
2384 * Add static FEC to label binding. If there are clients registered for this
2385 * FEC, notify them. If there are labeled routes for this FEC, install the
2386 * label forwarding entry.
2388 int zebra_mpls_static_fec_add(struct zebra_vrf
*zvrf
, struct prefix
*p
,
2389 mpls_label_t in_label
)
2391 struct route_table
*table
;
2394 mpls_label_t old_label
;
2397 table
= zvrf
->fec_table
[family2afi(PREFIX_FAMILY(p
))];
2401 if (IS_ZEBRA_DEBUG_MPLS
)
2402 prefix2str(p
, buf
, BUFSIZ
);
2404 /* Update existing FEC or create a new one. */
2405 fec
= fec_find(table
, p
);
2407 fec
= fec_add(table
, p
, in_label
, FEC_FLAG_CONFIGURED
,
2408 MPLS_INVALID_LABEL_INDEX
);
2410 prefix2str(p
, buf
, BUFSIZ
);
2411 flog_err(EC_ZEBRA_FEC_ADD_FAILED
,
2412 "Failed to add FEC %s upon config", buf
);
2416 if (IS_ZEBRA_DEBUG_MPLS
)
2417 zlog_debug("Add fec %s label %u", buf
, in_label
);
2419 fec
->flags
|= FEC_FLAG_CONFIGURED
;
2420 if (fec
->label
== in_label
)
2421 /* Duplicate config */
2424 /* Label change, update clients. */
2425 old_label
= fec
->label
;
2426 if (IS_ZEBRA_DEBUG_MPLS
)
2427 zlog_debug("Update fec %s new label %u", buf
, in_label
);
2429 fec
->label
= in_label
;
2430 fec_update_clients(fec
);
2432 /* Update label forwarding entries appropriately */
2433 ret
= fec_change_update_lsp(zvrf
, fec
, old_label
);
2440 * Remove static FEC to label binding. If there are no clients registered
2441 * for this FEC, delete the FEC; else notify clients
2442 * Note: Upon delete of static binding, if label index exists for this FEC,
2443 * client may need to be updated with derived label.
2445 int zebra_mpls_static_fec_del(struct zebra_vrf
*zvrf
, struct prefix
*p
)
2447 struct route_table
*table
;
2449 mpls_label_t old_label
;
2452 table
= zvrf
->fec_table
[family2afi(PREFIX_FAMILY(p
))];
2456 fec
= fec_find(table
, p
);
2458 prefix2str(p
, buf
, BUFSIZ
);
2459 flog_err(EC_ZEBRA_FEC_RM_FAILED
,
2460 "Failed to find FEC %s upon delete", buf
);
2464 if (IS_ZEBRA_DEBUG_MPLS
) {
2465 prefix2str(p
, buf
, BUFSIZ
);
2466 zlog_debug("Delete fec %s label %u label index %u", buf
,
2467 fec
->label
, fec
->label_index
);
2470 old_label
= fec
->label
;
2471 fec
->flags
&= ~FEC_FLAG_CONFIGURED
;
2472 fec
->label
= MPLS_INVALID_LABEL
;
2474 /* If no client exists, just delete the FEC. */
2475 if (list_isempty(fec
->client_list
)) {
2480 /* Derive the local label (from label index) or reset it. */
2481 fec_derive_label_from_index(zvrf
, fec
);
2483 /* If there is a label change, update clients. */
2484 if (fec
->label
== old_label
)
2486 fec_update_clients(fec
);
2488 /* Update label forwarding entries appropriately */
2489 return fec_change_update_lsp(zvrf
, fec
, old_label
);
2493 * Display MPLS FEC to label binding configuration (VTY command handler).
2495 int zebra_mpls_write_fec_config(struct vty
*vty
, struct zebra_vrf
*zvrf
)
2497 struct route_node
*rn
;
2503 for (af
= AFI_IP
; af
< AFI_MAX
; af
++) {
2504 if (zvrf
->fec_table
[af
] == NULL
)
2507 for (rn
= route_top(zvrf
->fec_table
[af
]); rn
;
2508 rn
= route_next(rn
)) {
2515 if (!(fec
->flags
& FEC_FLAG_CONFIGURED
))
2519 prefix2str(&rn
->p
, buf
, BUFSIZ
);
2520 vty_out(vty
, "mpls label bind %s %s\n", buf
,
2521 label2str(fec
->label
, lstr
, BUFSIZ
));
2529 * Display MPLS FEC to label binding (VTY command handler).
2531 void zebra_mpls_print_fec_table(struct vty
*vty
, struct zebra_vrf
*zvrf
)
2533 struct route_node
*rn
;
2536 for (af
= AFI_IP
; af
< AFI_MAX
; af
++) {
2537 if (zvrf
->fec_table
[af
] == NULL
)
2540 for (rn
= route_top(zvrf
->fec_table
[af
]); rn
;
2541 rn
= route_next(rn
)) {
2544 fec_print(rn
->info
, vty
);
2550 * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2552 void zebra_mpls_print_fec(struct vty
*vty
, struct zebra_vrf
*zvrf
,
2555 struct route_table
*table
;
2556 struct route_node
*rn
;
2558 table
= zvrf
->fec_table
[family2afi(PREFIX_FAMILY(p
))];
2563 rn
= route_node_lookup(table
, p
);
2567 route_unlock_node(rn
);
2571 fec_print(rn
->info
, vty
);
2574 static void mpls_zebra_nhg_update(struct route_entry
*re
, afi_t afi
,
2575 struct nexthop_group
*new_grp
)
2577 struct nhg_hash_entry
*nhe
;
2579 nhe
= zebra_nhg_rib_find(0, new_grp
, afi
);
2581 route_entry_update_nhe(re
, nhe
);
2584 static bool mpls_ftn_update_nexthop(int add
, struct nexthop
*nexthop
,
2585 enum lsp_types_t type
, mpls_label_t label
)
2587 if (add
&& nexthop
->nh_label_type
== ZEBRA_LSP_NONE
)
2588 nexthop_add_labels(nexthop
, type
, 1, &label
);
2589 else if (!add
&& nexthop
->nh_label_type
== type
)
2590 nexthop_del_labels(nexthop
);
2598 * Install/uninstall a FEC-To-NHLFE (FTN) binding.
2600 int mpls_ftn_update(int add
, struct zebra_vrf
*zvrf
, enum lsp_types_t type
,
2601 struct prefix
*prefix
, enum nexthop_types_t gtype
,
2602 union g_addr
*gate
, ifindex_t ifindex
, uint8_t route_type
,
2603 unsigned short route_instance
, mpls_label_t out_label
)
2605 struct route_table
*table
;
2606 struct route_node
*rn
;
2607 struct route_entry
*re
;
2608 struct nexthop
*nexthop
;
2609 struct nexthop_group new_grp
= {};
2611 afi_t afi
= family2afi(prefix
->family
);
2614 table
= zebra_vrf_table(afi
, SAFI_UNICAST
, zvrf_id(zvrf
));
2618 /* Lookup existing route */
2619 rn
= route_node_get(table
, prefix
);
2620 RNODE_FOREACH_RE (rn
, re
) {
2621 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_REMOVED
))
2623 if (re
->type
== route_type
&& re
->instance
== route_instance
)
2631 * Copy over current nexthops into a temporary group.
2632 * We can't just change the values here since we are hashing
2633 * on labels. We need to create a whole new group
2635 nexthop_group_copy(&new_grp
, re
->nhe
->nhg
);
2638 for (nexthop
= new_grp
.nexthop
; nexthop
; nexthop
= nexthop
->next
) {
2639 switch (nexthop
->type
) {
2640 case NEXTHOP_TYPE_IPV4
:
2641 case NEXTHOP_TYPE_IPV4_IFINDEX
:
2642 if (gtype
!= NEXTHOP_TYPE_IPV4
2643 && gtype
!= NEXTHOP_TYPE_IPV4_IFINDEX
)
2645 if (!IPV4_ADDR_SAME(&nexthop
->gate
.ipv4
, &gate
->ipv4
))
2647 if (nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
2648 && nexthop
->ifindex
!= ifindex
)
2650 if (!mpls_ftn_update_nexthop(add
, nexthop
, type
,
2655 case NEXTHOP_TYPE_IPV6
:
2656 case NEXTHOP_TYPE_IPV6_IFINDEX
:
2657 if (gtype
!= NEXTHOP_TYPE_IPV6
2658 && gtype
!= NEXTHOP_TYPE_IPV6_IFINDEX
)
2660 if (!IPV6_ADDR_SAME(&nexthop
->gate
.ipv6
, &gate
->ipv6
))
2662 if (nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
2663 && nexthop
->ifindex
!= ifindex
)
2665 if (!mpls_ftn_update_nexthop(add
, nexthop
, type
,
2676 SET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
2677 SET_FLAG(re
->status
, ROUTE_ENTRY_LABELS_CHANGED
);
2679 mpls_zebra_nhg_update(re
, afi
, &new_grp
);
2684 nexthops_free(new_grp
.nexthop
);
2686 return found
? 0 : -1;
2689 int mpls_ftn_uninstall(struct zebra_vrf
*zvrf
, enum lsp_types_t type
,
2690 struct prefix
*prefix
, uint8_t route_type
,
2691 unsigned short route_instance
)
2693 struct route_table
*table
;
2694 struct route_node
*rn
;
2695 struct route_entry
*re
;
2696 struct nexthop
*nexthop
;
2697 struct nexthop_group new_grp
= {};
2698 afi_t afi
= family2afi(prefix
->family
);
2701 table
= zebra_vrf_table(afi
, SAFI_UNICAST
, zvrf_id(zvrf
));
2705 /* Lookup existing route */
2706 rn
= route_node_get(table
, prefix
);
2707 RNODE_FOREACH_RE (rn
, re
) {
2708 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_REMOVED
))
2710 if (re
->type
== route_type
&& re
->instance
== route_instance
)
2716 nexthop_group_copy(&new_grp
, re
->nhe
->nhg
);
2718 for (nexthop
= new_grp
.nexthop
; nexthop
; nexthop
= nexthop
->next
)
2719 nexthop_del_labels(nexthop
);
2721 SET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
2722 SET_FLAG(re
->status
, ROUTE_ENTRY_LABELS_CHANGED
);
2724 mpls_zebra_nhg_update(re
, afi
, &new_grp
);
2726 nexthops_free(new_grp
.nexthop
);
2734 * Install/update a NHLFE for an LSP in the forwarding table. This may be
2735 * a new LSP entry or a new NHLFE for an existing in-label or an update of
2736 * the out-label for an existing NHLFE (update case).
2738 int mpls_lsp_install(struct zebra_vrf
*zvrf
, enum lsp_types_t type
,
2739 mpls_label_t in_label
, uint8_t num_out_labels
,
2740 mpls_label_t out_labels
[], enum nexthop_types_t gtype
,
2741 union g_addr
*gate
, ifindex_t ifindex
)
2743 struct hash
*lsp_table
;
2744 zebra_ile_t tmp_ile
;
2746 zebra_nhlfe_t
*nhlfe
;
2750 lsp_table
= zvrf
->lsp_table
;
2754 /* If entry is present, exit. */
2755 tmp_ile
.in_label
= in_label
;
2756 lsp
= hash_get(lsp_table
, &tmp_ile
, lsp_alloc
);
2759 nhlfe
= nhlfe_find(lsp
, type
, gtype
, gate
, ifindex
);
2761 struct nexthop
*nh
= nhlfe
->nexthop
;
2764 assert(nh
->nh_label
);
2766 /* Clear deleted flag (in case it was set) */
2767 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
);
2768 if (nh
->nh_label
->num_labels
== num_out_labels
2769 && !memcmp(nh
->nh_label
->label
, out_labels
,
2770 sizeof(mpls_label_t
) * num_out_labels
))
2774 if (IS_ZEBRA_DEBUG_MPLS
) {
2778 nhlfe2str(nhlfe
, buf
, BUFSIZ
);
2779 mpls_label2str(num_out_labels
, out_labels
, buf2
,
2781 mpls_label2str(nh
->nh_label
->num_labels
,
2782 nh
->nh_label
->label
, buf3
, sizeof(buf3
),
2786 "LSP in-label %u type %d nexthop %s "
2787 "out-label(s) changed to %s (old %s)",
2788 in_label
, type
, buf
, buf2
, buf3
);
2791 /* Update out label(s), trigger processing. */
2792 if (nh
->nh_label
->num_labels
== num_out_labels
)
2793 memcpy(nh
->nh_label
->label
, out_labels
,
2794 sizeof(mpls_label_t
) * num_out_labels
);
2796 nexthop_del_labels(nh
);
2797 nexthop_add_labels(nh
, type
, num_out_labels
,
2801 /* Add LSP entry to this nexthop */
2802 nhlfe
= nhlfe_add(lsp
, type
, gtype
, gate
, ifindex
,
2803 num_out_labels
, out_labels
);
2807 if (IS_ZEBRA_DEBUG_MPLS
) {
2810 nhlfe2str(nhlfe
, buf
, BUFSIZ
);
2811 mpls_label2str(num_out_labels
, out_labels
, buf2
,
2815 "Add LSP in-label %u type %d nexthop %s "
2817 in_label
, type
, buf
, buf2
);
2820 lsp
->addr_family
= NHLFE_FAMILY(nhlfe
);
2823 /* Mark NHLFE, queue LSP for processing. */
2824 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_CHANGED
);
2825 if (lsp_processq_add(lsp
))
2832 * Uninstall a particular NHLFE in the forwarding table. If this is
2833 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
2835 int mpls_lsp_uninstall(struct zebra_vrf
*zvrf
, enum lsp_types_t type
,
2836 mpls_label_t in_label
, enum nexthop_types_t gtype
,
2837 union g_addr
*gate
, ifindex_t ifindex
)
2839 struct hash
*lsp_table
;
2840 zebra_ile_t tmp_ile
;
2842 zebra_nhlfe_t
*nhlfe
;
2846 lsp_table
= zvrf
->lsp_table
;
2850 /* If entry is not present, exit. */
2851 tmp_ile
.in_label
= in_label
;
2852 lsp
= hash_lookup(lsp_table
, &tmp_ile
);
2855 nhlfe
= nhlfe_find(lsp
, type
, gtype
, gate
, ifindex
);
2859 if (IS_ZEBRA_DEBUG_MPLS
) {
2860 nhlfe2str(nhlfe
, buf
, BUFSIZ
);
2861 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
2862 in_label
, type
, buf
, nhlfe
->flags
);
2865 /* Mark NHLFE for delete or directly delete, as appropriate. */
2866 if (CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
)) {
2867 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_CHANGED
);
2868 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
);
2869 if (lsp_processq_add(lsp
))
2874 /* Free LSP entry if no other NHLFEs and not scheduled. */
2875 if (!lsp
->nhlfe_list
2876 && !CHECK_FLAG(lsp
->flags
, LSP_FLAG_SCHEDULED
)) {
2877 if (IS_ZEBRA_DEBUG_MPLS
)
2878 zlog_debug("Free LSP in-label %u flags 0x%x",
2879 lsp
->ile
.in_label
, lsp
->flags
);
2881 lsp
= hash_release(lsp_table
, &lsp
->ile
);
2882 XFREE(MTYPE_LSP
, lsp
);
2888 int mpls_lsp_uninstall_all_vrf(struct zebra_vrf
*zvrf
, enum lsp_types_t type
,
2889 mpls_label_t in_label
)
2891 struct hash
*lsp_table
;
2892 zebra_ile_t tmp_ile
;
2896 lsp_table
= zvrf
->lsp_table
;
2900 /* If entry is not present, exit. */
2901 tmp_ile
.in_label
= in_label
;
2902 lsp
= hash_lookup(lsp_table
, &tmp_ile
);
2906 return mpls_lsp_uninstall_all(lsp_table
, lsp
, type
);
2910 * Uninstall all NHLFEs for a particular LSP forwarding entry.
2911 * If no other NHLFEs exist, the entry would be deleted.
2913 static void mpls_lsp_uninstall_all_type(struct hash_bucket
*bucket
, void *ctxt
)
2915 struct lsp_uninstall_args
*args
= ctxt
;
2917 struct hash
*lsp_table
;
2919 lsp
= (zebra_lsp_t
*)bucket
->data
;
2920 if (!lsp
->nhlfe_list
)
2923 lsp_table
= args
->lsp_table
;
2927 mpls_lsp_uninstall_all(lsp_table
, lsp
, args
->type
);
2931 * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and
2934 static void mpls_ftn_uninstall_all(struct zebra_vrf
*zvrf
,
2935 int afi
, enum lsp_types_t lsp_type
)
2937 struct route_table
*table
;
2938 struct route_node
*rn
;
2939 struct route_entry
*re
;
2940 struct nexthop
*nexthop
;
2943 /* Process routes of interested address-families. */
2944 table
= zebra_vrf_table(afi
, SAFI_UNICAST
, zvrf_id(zvrf
));
2948 for (rn
= route_top(table
); rn
; rn
= route_next(rn
)) {
2950 RNODE_FOREACH_RE (rn
, re
) {
2951 struct nexthop_group new_grp
= {};
2953 nexthop_group_copy(&new_grp
, re
->nhe
->nhg
);
2955 for (nexthop
= new_grp
.nexthop
; nexthop
;
2956 nexthop
= nexthop
->next
) {
2957 if (nexthop
->nh_label_type
!= lsp_type
)
2960 nexthop_del_labels(nexthop
);
2961 SET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
2962 SET_FLAG(re
->status
,
2963 ROUTE_ENTRY_LABELS_CHANGED
);
2967 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_LABELS_CHANGED
))
2968 mpls_zebra_nhg_update(re
, afi
, &new_grp
);
2970 nexthops_free(new_grp
.nexthop
);
2978 #if defined(HAVE_CUMULUS)
2980 * Check that the label values used in LSP creation are consistent. The
2981 * main criteria is that if there is ECMP, the label operation must still
2982 * be consistent - i.e., all paths either do a swap or do PHP. This is due
2983 * to current HW restrictions.
2985 int zebra_mpls_lsp_label_consistent(struct zebra_vrf
*zvrf
,
2986 mpls_label_t in_label
,
2987 mpls_label_t out_label
,
2988 enum nexthop_types_t gtype
,
2989 union g_addr
*gate
, ifindex_t ifindex
)
2991 struct hash
*slsp_table
;
2992 zebra_ile_t tmp_ile
;
2994 zebra_snhlfe_t
*snhlfe
;
2997 slsp_table
= zvrf
->slsp_table
;
3001 /* If entry is not present, exit. */
3002 tmp_ile
.in_label
= in_label
;
3003 slsp
= hash_lookup(slsp_table
, &tmp_ile
);
3007 snhlfe
= snhlfe_find(slsp
, gtype
, gate
, ifindex
);
3009 if (snhlfe
->out_label
== out_label
)
3012 /* If not only NHLFE, cannot allow label change. */
3013 if (snhlfe
!= slsp
->snhlfe_list
|| snhlfe
->next
)
3016 /* If other NHLFEs exist, label operation must match. */
3017 if (slsp
->snhlfe_list
) {
3020 cur_op
= (slsp
->snhlfe_list
->out_label
3021 == MPLS_LABEL_IMPLICIT_NULL
);
3022 new_op
= (out_label
== MPLS_LABEL_IMPLICIT_NULL
);
3023 if (cur_op
!= new_op
)
3028 /* Label values are good. */
3031 #endif /* HAVE_CUMULUS */
3034 * Add static LSP entry. This may be the first entry for this incoming label
3035 * or an additional nexthop; an existing entry may also have outgoing label
3037 * Note: The label operation (swap or PHP) is common for the LSP entry (all
3040 int zebra_mpls_static_lsp_add(struct zebra_vrf
*zvrf
, mpls_label_t in_label
,
3041 mpls_label_t out_label
,
3042 enum nexthop_types_t gtype
, union g_addr
*gate
,
3045 struct hash
*slsp_table
;
3046 zebra_ile_t tmp_ile
;
3048 zebra_snhlfe_t
*snhlfe
;
3052 slsp_table
= zvrf
->slsp_table
;
3056 /* If entry is present, exit. */
3057 tmp_ile
.in_label
= in_label
;
3058 slsp
= hash_get(slsp_table
, &tmp_ile
, slsp_alloc
);
3061 snhlfe
= snhlfe_find(slsp
, gtype
, gate
, ifindex
);
3063 if (snhlfe
->out_label
== out_label
)
3067 if (IS_ZEBRA_DEBUG_MPLS
) {
3068 snhlfe2str(snhlfe
, buf
, BUFSIZ
);
3070 "Upd static LSP in-label %u nexthop %s "
3071 "out-label %u (old %u)",
3072 in_label
, buf
, out_label
, snhlfe
->out_label
);
3074 snhlfe
->out_label
= out_label
;
3076 /* Add static LSP entry to this nexthop */
3077 snhlfe
= snhlfe_add(slsp
, gtype
, gate
, ifindex
, out_label
);
3081 if (IS_ZEBRA_DEBUG_MPLS
) {
3082 snhlfe2str(snhlfe
, buf
, BUFSIZ
);
3084 "Add static LSP in-label %u nexthop %s out-label %u",
3085 in_label
, buf
, out_label
);
3089 /* (Re)Install LSP in the main table. */
3090 if (mpls_lsp_install(zvrf
, ZEBRA_LSP_STATIC
, in_label
, 1, &out_label
,
3091 gtype
, gate
, ifindex
))
3098 * Delete static LSP entry. This may be the delete of one particular
3099 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
3101 * NOTE: Delete of the only NHLFE will also end up deleting the entire
3102 * LSP configuration.
3104 int zebra_mpls_static_lsp_del(struct zebra_vrf
*zvrf
, mpls_label_t in_label
,
3105 enum nexthop_types_t gtype
, union g_addr
*gate
,
3108 struct hash
*slsp_table
;
3109 zebra_ile_t tmp_ile
;
3111 zebra_snhlfe_t
*snhlfe
;
3114 slsp_table
= zvrf
->slsp_table
;
3118 /* If entry is not present, exit. */
3119 tmp_ile
.in_label
= in_label
;
3120 slsp
= hash_lookup(slsp_table
, &tmp_ile
);
3124 /* Is it delete of entire LSP or a specific NHLFE? */
3125 if (gtype
== NEXTHOP_TYPE_BLACKHOLE
) {
3126 if (IS_ZEBRA_DEBUG_MPLS
)
3127 zlog_debug("Del static LSP in-label %u", in_label
);
3129 /* Uninstall entire LSP from the main table. */
3130 mpls_static_lsp_uninstall_all(zvrf
, in_label
);
3132 /* Delete all static NHLFEs */
3133 snhlfe_del_all(slsp
);
3135 /* Find specific NHLFE, exit if not found. */
3136 snhlfe
= snhlfe_find(slsp
, gtype
, gate
, ifindex
);
3140 if (IS_ZEBRA_DEBUG_MPLS
) {
3142 snhlfe2str(snhlfe
, buf
, BUFSIZ
);
3143 zlog_debug("Del static LSP in-label %u nexthop %s",
3147 /* Uninstall LSP from the main table. */
3148 mpls_lsp_uninstall(zvrf
, ZEBRA_LSP_STATIC
, in_label
, gtype
,
3151 /* Delete static LSP NHLFE */
3155 /* Remove entire static LSP entry if no NHLFE - valid in either case
3157 if (!slsp
->snhlfe_list
) {
3158 slsp
= hash_release(slsp_table
, &tmp_ile
);
3159 XFREE(MTYPE_SLSP
, slsp
);
3166 * Schedule all MPLS label forwarding entries for processing.
3167 * Called upon changes that may affect one or more of them such as
3168 * interface or nexthop state changes.
3170 void zebra_mpls_lsp_schedule(struct zebra_vrf
*zvrf
)
3174 hash_iterate(zvrf
->lsp_table
, lsp_schedule
, NULL
);
3178 * Display MPLS label forwarding table for a specific LSP
3179 * (VTY command handler).
3181 void zebra_mpls_print_lsp(struct vty
*vty
, struct zebra_vrf
*zvrf
,
3182 mpls_label_t label
, bool use_json
)
3184 struct hash
*lsp_table
;
3186 zebra_ile_t tmp_ile
;
3187 json_object
*json
= NULL
;
3190 lsp_table
= zvrf
->lsp_table
;
3194 /* If entry is not present, exit. */
3195 tmp_ile
.in_label
= label
;
3196 lsp
= hash_lookup(lsp_table
, &tmp_ile
);
3201 json
= lsp_json(lsp
);
3202 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3203 json
, JSON_C_TO_STRING_PRETTY
));
3204 json_object_free(json
);
3206 lsp_print(lsp
, (void *)vty
);
3210 * Display MPLS label forwarding table (VTY command handler).
3212 void zebra_mpls_print_lsp_table(struct vty
*vty
, struct zebra_vrf
*zvrf
,
3216 json_object
*json
= NULL
;
3217 zebra_lsp_t
*lsp
= NULL
;
3218 zebra_nhlfe_t
*nhlfe
= NULL
;
3219 struct listnode
*node
= NULL
;
3220 struct list
*lsp_list
= hash_get_sorted_list(zvrf
->lsp_table
, lsp_cmp
);
3223 json
= json_object_new_object();
3225 for (ALL_LIST_ELEMENTS_RO(lsp_list
, node
, lsp
))
3226 json_object_object_add(
3227 json
, label2str(lsp
->ile
.in_label
, buf
, BUFSIZ
),
3230 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3231 json
, JSON_C_TO_STRING_PRETTY
));
3232 json_object_free(json
);
3236 /* Prepare table. */
3237 tt
= ttable_new(&ttable_styles
[TTSTYLE_BLANK
]);
3238 ttable_add_row(tt
, "Inbound Label|Type|Nexthop|Outbound Label");
3239 tt
->style
.cell
.rpad
= 2;
3240 tt
->style
.corner
= '+';
3242 ttable_rowseps(tt
, 0, BOTTOM
, true, '-');
3244 for (ALL_LIST_ELEMENTS_RO(lsp_list
, node
, lsp
)) {
3245 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
;
3246 nhlfe
= nhlfe
->next
) {
3247 struct nexthop
*nexthop
;
3248 const char *out_label_str
;
3249 char nh_buf
[NEXTHOP_STRLEN
];
3251 nexthop
= nhlfe
->nexthop
;
3253 switch (nexthop
->type
) {
3254 case NEXTHOP_TYPE_IFINDEX
: {
3255 struct zebra_ns
*zns
;
3256 struct interface
*ifp
;
3258 zns
= zebra_ns_lookup(NS_DEFAULT
);
3259 ifp
= if_lookup_by_index_per_ns(
3260 zns
, nexthop
->ifindex
);
3261 snprintf(nh_buf
, sizeof(nh_buf
), "%s",
3262 ifp
? ifp
->name
: "Null");
3265 case NEXTHOP_TYPE_IPV4
:
3266 case NEXTHOP_TYPE_IPV4_IFINDEX
:
3267 inet_ntop(AF_INET
, &nexthop
->gate
.ipv4
,
3268 nh_buf
, sizeof(nh_buf
));
3270 case NEXTHOP_TYPE_IPV6
:
3271 case NEXTHOP_TYPE_IPV6_IFINDEX
:
3272 inet_ntop(AF_INET6
, &nexthop
->gate
.ipv6
,
3273 nh_buf
, sizeof(nh_buf
));
3279 if (nexthop
->type
!= NEXTHOP_TYPE_IFINDEX
)
3280 out_label_str
= mpls_label2str(
3281 nexthop
->nh_label
->num_labels
,
3282 &nexthop
->nh_label
->label
[0],
3285 out_label_str
= "-";
3287 ttable_add_row(tt
, "%u|%s|%s|%s",
3289 nhlfe_type2str(nhlfe
->type
),
3290 nh_buf
, out_label_str
);
3294 /* Dump the generated table. */
3295 if (tt
->nrows
> 1) {
3296 char *table
= ttable_dump(tt
, "\n");
3297 vty_out(vty
, "%s\n", table
);
3298 XFREE(MTYPE_TMP
, table
);
3303 list_delete(&lsp_list
);
3307 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
3309 int zebra_mpls_write_lsp_config(struct vty
*vty
, struct zebra_vrf
*zvrf
)
3312 zebra_snhlfe_t
*snhlfe
;
3313 struct listnode
*node
;
3314 struct list
*slsp_list
=
3315 hash_get_sorted_list(zvrf
->slsp_table
, slsp_cmp
);
3317 for (ALL_LIST_ELEMENTS_RO(slsp_list
, node
, slsp
)) {
3318 for (snhlfe
= slsp
->snhlfe_list
; snhlfe
;
3319 snhlfe
= snhlfe
->next
) {
3323 snhlfe2str(snhlfe
, buf
, sizeof(buf
));
3324 switch (snhlfe
->out_label
) {
3325 case MPLS_LABEL_IPV4_EXPLICIT_NULL
:
3326 case MPLS_LABEL_IPV6_EXPLICIT_NULL
:
3327 strlcpy(lstr
, "explicit-null", sizeof(lstr
));
3329 case MPLS_LABEL_IMPLICIT_NULL
:
3330 strlcpy(lstr
, "implicit-null", sizeof(lstr
));
3333 sprintf(lstr
, "%u", snhlfe
->out_label
);
3337 vty_out(vty
, "mpls lsp %u %s %s\n", slsp
->ile
.in_label
,
3342 list_delete(&slsp_list
);
3343 return (zvrf
->slsp_table
->count
? 1 : 0);
3347 * Add/update global label block.
3349 int zebra_mpls_label_block_add(struct zebra_vrf
*zvrf
, uint32_t start_label
,
3352 zvrf
->mpls_srgb
.start_label
= start_label
;
3353 zvrf
->mpls_srgb
.end_label
= end_label
;
3355 /* Evaluate registered FECs to see if any get a label or not. */
3361 * Delete global label block.
3363 int zebra_mpls_label_block_del(struct zebra_vrf
*zvrf
)
3365 zvrf
->mpls_srgb
.start_label
= MPLS_DEFAULT_MIN_SRGB_LABEL
;
3366 zvrf
->mpls_srgb
.end_label
= MPLS_DEFAULT_MAX_SRGB_LABEL
;
3368 /* Process registered FECs to clear their local label, if needed. */
3374 * Display MPLS global label block configuration (VTY command handler).
3376 int zebra_mpls_write_label_block_config(struct vty
*vty
, struct zebra_vrf
*zvrf
)
3378 if (zvrf
->mpls_srgb
.start_label
== 0)
3381 if ((zvrf
->mpls_srgb
.start_label
!= MPLS_DEFAULT_MIN_SRGB_LABEL
)
3382 || (zvrf
->mpls_srgb
.end_label
!= MPLS_DEFAULT_MAX_SRGB_LABEL
)) {
3383 vty_out(vty
, "mpls label global-block %u %u\n",
3384 zvrf
->mpls_srgb
.start_label
, zvrf
->mpls_srgb
.end_label
);
3391 * Called when VRF becomes inactive, cleans up information but keeps
3394 void zebra_mpls_cleanup_tables(struct zebra_vrf
*zvrf
)
3396 struct zebra_vrf
*def_zvrf
;
3399 if (zvrf_id(zvrf
) == VRF_DEFAULT
)
3400 hash_iterate(zvrf
->lsp_table
, lsp_uninstall_from_kernel
, NULL
);
3403 * For other vrfs, we try to remove associated LSPs; we locate
3404 * the LSPs in the default vrf.
3406 def_zvrf
= zebra_vrf_lookup_by_id(VRF_DEFAULT
);
3408 /* At shutdown, the default may be gone already */
3409 if (def_zvrf
== NULL
)
3412 for (afi
= AFI_IP
; afi
< AFI_MAX
; afi
++) {
3413 if (zvrf
->label
[afi
] != MPLS_LABEL_NONE
)
3414 lsp_uninstall(def_zvrf
, zvrf
->label
[afi
]);
3420 * Called upon process exiting, need to delete LSP forwarding
3421 * entries from the kernel.
3422 * NOTE: Currently supported only for default VRF.
3424 void zebra_mpls_close_tables(struct zebra_vrf
*zvrf
)
3426 hash_iterate(zvrf
->lsp_table
, lsp_uninstall_from_kernel
, NULL
);
3427 hash_clean(zvrf
->lsp_table
, NULL
);
3428 hash_free(zvrf
->lsp_table
);
3429 hash_clean(zvrf
->slsp_table
, NULL
);
3430 hash_free(zvrf
->slsp_table
);
3431 route_table_finish(zvrf
->fec_table
[AFI_IP
]);
3432 route_table_finish(zvrf
->fec_table
[AFI_IP6
]);
3436 * Allocate MPLS tables for this VRF and do other initialization.
3437 * NOTE: Currently supported only for default VRF.
3439 void zebra_mpls_init_tables(struct zebra_vrf
*zvrf
)
3444 hash_create(label_hash
, label_cmp
, "ZEBRA SLSP table");
3445 zvrf
->lsp_table
= hash_create(label_hash
, label_cmp
, "ZEBRA LSP table");
3446 zvrf
->fec_table
[AFI_IP
] = route_table_init();
3447 zvrf
->fec_table
[AFI_IP6
] = route_table_init();
3448 zvrf
->mpls_flags
= 0;
3449 zvrf
->mpls_srgb
.start_label
= MPLS_DEFAULT_MIN_SRGB_LABEL
;
3450 zvrf
->mpls_srgb
.end_label
= MPLS_DEFAULT_MAX_SRGB_LABEL
;
3454 * Global MPLS initialization.
3456 void zebra_mpls_init(void)
3460 if (mpls_kernel_init() < 0) {
3461 flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED
,
3462 "Disabling MPLS support (no kernel support)");
3466 if (!mpls_processq_init())
3469 hook_register(zserv_client_close
, zebra_mpls_cleanup_fecs_for_client
);
3470 hook_register(zserv_client_close
, zebra_mpls_cleanup_zclient_labels
);