]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mpls.c
Merge pull request #9517 from anlancs/reload-add-str
[mirror_frr.git] / zebra / zebra_mpls.c
1 /* Zebra MPLS code
2 * Copyright (C) 2013 Cumulus Networks, Inc.
3 *
4 * This file is part of GNU Zebra.
5 *
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
9 * later version.
10 *
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.
15 *
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
19 */
20
21 #include <zebra.h>
22
23 #include "prefix.h"
24 #include "table.h"
25 #include "memory.h"
26 #include "command.h"
27 #include "if.h"
28 #include "log.h"
29 #include "sockunion.h"
30 #include "linklist.h"
31 #include "thread.h"
32 #include "workqueue.h"
33 #include "prefix.h"
34 #include "routemap.h"
35 #include "stream.h"
36 #include "nexthop.h"
37 #include "termtable.h"
38 #include "lib/json.h"
39
40 #include "zebra/rib.h"
41 #include "zebra/rt.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_vrf.h"
48 #include "zebra/zebra_mpls.h"
49 #include "zebra/zebra_srte.h"
50 #include "zebra/zebra_errors.h"
51
52 DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object");
53 DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object");
54 DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object");
55
56 int mpls_enabled;
57 bool mpls_pw_reach_strict; /* Strict reachability checking */
58
59 /* static function declarations */
60
61 static void fec_evaluate(struct zebra_vrf *zvrf);
62 static uint32_t fec_derive_label_from_index(struct zebra_vrf *vrf,
63 struct zebra_fec *fec);
64 static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
65 struct route_node *rn, struct route_entry *re);
66 static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label);
67 static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
68 mpls_label_t old_label);
69 static int fec_send(struct zebra_fec *fec, struct zserv *client);
70 static void fec_update_clients(struct zebra_fec *fec);
71 static void fec_print(struct zebra_fec *fec, struct vty *vty);
72 static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p);
73 static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
74 mpls_label_t label, uint32_t flags,
75 uint32_t label_index);
76 static int fec_del(struct zebra_fec *fec);
77
78 static unsigned int label_hash(const void *p);
79 static bool label_cmp(const void *p1, const void *p2);
80 static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
81 struct nexthop *nexthop);
82 static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
83 struct nexthop *nexthop);
84 static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe);
85
86 static void lsp_select_best_nhlfe(struct zebra_lsp *lsp);
87 static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt);
88 static void lsp_schedule(struct hash_bucket *bucket, void *ctxt);
89 static wq_item_status lsp_process(struct work_queue *wq, void *data);
90 static void lsp_processq_del(struct work_queue *wq, void *data);
91 static void lsp_processq_complete(struct work_queue *wq);
92 static int lsp_processq_add(struct zebra_lsp *lsp);
93 static void *lsp_alloc(void *p);
94
95 /* Check whether lsp can be freed - no nhlfes, e.g., and call free api */
96 static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp);
97
98 /* Free lsp; sets caller's pointer to NULL */
99 static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp);
100
101 static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size);
102 static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
103 int size);
104 static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
105 enum nexthop_types_t gtype,
106 const union g_addr *gate, ifindex_t ifindex);
107 static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
108 enum lsp_types_t lsp_type,
109 enum nexthop_types_t gtype,
110 const union g_addr *gate,
111 ifindex_t ifindex);
112 static struct zebra_nhlfe *
113 nhlfe_add(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
114 enum nexthop_types_t gtype, const union g_addr *gate,
115 ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels,
116 bool is_backup);
117 static int nhlfe_del(struct zebra_nhlfe *nhlfe);
118 static void nhlfe_free(struct zebra_nhlfe *nhlfe);
119 static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
120 struct mpls_label_stack *nh_label);
121 static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
122 enum lsp_types_t type);
123 static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
124 mpls_label_t in_label);
125 static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
126 const char *indent);
127 static void lsp_print(struct vty *vty, struct zebra_lsp *lsp);
128 static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt);
129 static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
130 int afi, enum lsp_types_t lsp_type);
131 static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
132 const struct zapi_nexthop *znh);
133 static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
134 const struct zapi_nexthop *znh);
135
136 /* Static functions */
137
138 /*
139 * Handle failure in LSP install, clear flags for NHLFE.
140 */
141 static void clear_nhlfe_installed(struct zebra_lsp *lsp)
142 {
143 struct zebra_nhlfe *nhlfe;
144 struct nexthop *nexthop;
145
146 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
147 nexthop = nhlfe->nexthop;
148 if (!nexthop)
149 continue;
150
151 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
152 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
153 }
154
155 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
156 nexthop = nhlfe->nexthop;
157 if (!nexthop)
158 continue;
159
160 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
161 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
162 }
163 }
164
165 /*
166 * Install label forwarding entry based on labeled-route entry.
167 */
168 static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
169 struct route_node *rn, struct route_entry *re)
170 {
171 struct hash *lsp_table;
172 struct zebra_ile tmp_ile;
173 struct zebra_lsp *lsp;
174 struct zebra_nhlfe *nhlfe;
175 struct nexthop *nexthop;
176 enum lsp_types_t lsp_type;
177 char buf[BUFSIZ];
178 int added, changed;
179
180 /* Lookup table. */
181 lsp_table = zvrf->lsp_table;
182 if (!lsp_table)
183 return -1;
184
185 lsp_type = lsp_type_from_re_type(re->type);
186 added = changed = 0;
187
188 /* Locate or allocate LSP entry. */
189 tmp_ile.in_label = label;
190 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
191 if (!lsp)
192 return -1;
193
194 /* For each active nexthop, create NHLFE. Note that we deliberately skip
195 * recursive nexthops right now, because intermediate hops won't
196 * understand
197 * the label advertised by the recursive nexthop (plus we don't have the
198 * logic yet to push multiple labels).
199 */
200 for (nexthop = re->nhe->nhg.nexthop;
201 nexthop; nexthop = nexthop->next) {
202 /* Skip inactive and recursive entries. */
203 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
204 continue;
205 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
206 continue;
207
208 nhlfe = nhlfe_find(&lsp->nhlfe_list, lsp_type,
209 nexthop->type, &nexthop->gate,
210 nexthop->ifindex);
211 if (nhlfe) {
212 /* Clear deleted flag (in case it was set) */
213 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
214 if (nexthop_labels_match(nhlfe->nexthop, nexthop))
215 /* No change */
216 continue;
217
218
219 if (IS_ZEBRA_DEBUG_MPLS) {
220 nhlfe2str(nhlfe, buf, BUFSIZ);
221 zlog_debug(
222 "LSP in-label %u type %d nexthop %s out-label changed",
223 lsp->ile.in_label, lsp_type, buf);
224 }
225
226 /* Update out label, trigger processing. */
227 nhlfe_out_label_update(nhlfe, nexthop->nh_label);
228 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
229 changed++;
230 } else {
231 /* Add LSP entry to this nexthop */
232 nhlfe = nhlfe_add(lsp, lsp_type, nexthop->type,
233 &nexthop->gate, nexthop->ifindex,
234 nexthop->nh_label->num_labels,
235 nexthop->nh_label->label,
236 false /*backup*/);
237 if (!nhlfe)
238 return -1;
239
240 if (IS_ZEBRA_DEBUG_MPLS) {
241 nhlfe2str(nhlfe, buf, BUFSIZ);
242 zlog_debug(
243 "Add LSP in-label %u type %d nexthop %s out-label %u",
244 lsp->ile.in_label, lsp_type, buf,
245 nexthop->nh_label->label[0]);
246 }
247
248 lsp->addr_family = NHLFE_FAMILY(nhlfe);
249
250 /* Mark NHLFE as changed. */
251 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
252 added++;
253 }
254 }
255
256 /* Queue LSP for processing if necessary. If no NHLFE got added (special
257 * case), delete the LSP entry; this case results in somewhat ugly
258 * logging.
259 */
260 if (added || changed) {
261 if (lsp_processq_add(lsp))
262 return -1;
263 } else {
264 lsp_check_free(lsp_table, &lsp);
265 }
266
267 return 0;
268 }
269
270 /*
271 * Uninstall all non-static NHLFEs of a label forwarding entry. If all
272 * NHLFEs are removed, the entire entry is deleted.
273 */
274 static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label)
275 {
276 struct hash *lsp_table;
277 struct zebra_ile tmp_ile;
278 struct zebra_lsp *lsp;
279 struct zebra_nhlfe *nhlfe;
280 char buf[BUFSIZ];
281
282 /* Lookup table. */
283 lsp_table = zvrf->lsp_table;
284 if (!lsp_table)
285 return -1;
286
287 /* If entry is not present, exit. */
288 tmp_ile.in_label = label;
289 lsp = hash_lookup(lsp_table, &tmp_ile);
290 if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
291 return 0;
292
293 /* Mark NHLFEs for delete or directly delete, as appropriate. */
294 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
295
296 /* Skip static NHLFEs */
297 if (nhlfe->type == ZEBRA_LSP_STATIC)
298 continue;
299
300 if (IS_ZEBRA_DEBUG_MPLS) {
301 nhlfe2str(nhlfe, buf, BUFSIZ);
302 zlog_debug(
303 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
304 label, nhlfe->type, buf, nhlfe->flags);
305 }
306
307 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)) {
308 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
309 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
310 } else {
311 nhlfe_del(nhlfe);
312 }
313 }
314
315 /* Queue LSP for processing, if needed, else delete. */
316 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
317 if (lsp_processq_add(lsp))
318 return -1;
319 } else {
320 lsp_check_free(lsp_table, &lsp);
321 }
322
323 return 0;
324 }
325
326 /*
327 * This function is invoked upon change to label block configuration; it
328 * will walk all registered FECs with label-index and appropriately update
329 * their local labels and trigger client updates.
330 */
331 static void fec_evaluate(struct zebra_vrf *zvrf)
332 {
333 struct route_node *rn;
334 struct zebra_fec *fec;
335 uint32_t old_label, new_label;
336 int af;
337
338 for (af = AFI_IP; af < AFI_MAX; af++) {
339 if (zvrf->fec_table[af] == NULL)
340 continue;
341
342 for (rn = route_top(zvrf->fec_table[af]); rn;
343 rn = route_next(rn)) {
344 if ((fec = rn->info) == NULL)
345 continue;
346
347 /* Skip configured FECs and those without a label index.
348 */
349 if (fec->flags & FEC_FLAG_CONFIGURED
350 || fec->label_index == MPLS_INVALID_LABEL_INDEX)
351 continue;
352
353 /* Save old label, determine new label. */
354 old_label = fec->label;
355 new_label =
356 zvrf->mpls_srgb.start_label + fec->label_index;
357 if (new_label >= zvrf->mpls_srgb.end_label)
358 new_label = MPLS_INVALID_LABEL;
359
360 /* If label has changed, update FEC and clients. */
361 if (new_label == old_label)
362 continue;
363
364 if (IS_ZEBRA_DEBUG_MPLS)
365 zlog_debug(
366 "Update fec %pRN new label %u upon label block",
367 rn, new_label);
368
369 fec->label = new_label;
370 fec_update_clients(fec);
371
372 /* Update label forwarding entries appropriately */
373 fec_change_update_lsp(zvrf, fec, old_label);
374 }
375 }
376 }
377
378 /*
379 * Derive (if possible) and update the local label for the FEC based on
380 * its label index. The index is "acceptable" if it falls within the
381 * globally configured label block (SRGB).
382 */
383 static uint32_t fec_derive_label_from_index(struct zebra_vrf *zvrf,
384 struct zebra_fec *fec)
385 {
386 uint32_t label;
387
388 if (fec->label_index != MPLS_INVALID_LABEL_INDEX
389 && zvrf->mpls_srgb.start_label
390 && ((label = zvrf->mpls_srgb.start_label + fec->label_index)
391 < zvrf->mpls_srgb.end_label))
392 fec->label = label;
393 else
394 fec->label = MPLS_INVALID_LABEL;
395
396 return fec->label;
397 }
398
399 /*
400 * There is a change for this FEC. Install or uninstall label forwarding
401 * entries, as appropriate.
402 */
403 static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
404 mpls_label_t old_label)
405 {
406 struct route_table *table;
407 struct route_node *rn;
408 struct route_entry *re;
409 afi_t afi;
410
411 /* Uninstall label forwarding entry, if previously installed. */
412 if (old_label != MPLS_INVALID_LABEL
413 && old_label != MPLS_LABEL_IMPLICIT_NULL)
414 lsp_uninstall(zvrf, old_label);
415
416 /* Install label forwarding entry corr. to new label, if needed. */
417 if (fec->label == MPLS_INVALID_LABEL
418 || fec->label == MPLS_LABEL_IMPLICIT_NULL)
419 return 0;
420
421 afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
422 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
423 if (!table)
424 return 0;
425
426 /* See if labeled route exists. */
427 rn = route_node_lookup(table, &fec->rn->p);
428 if (!rn)
429 return 0;
430
431 RNODE_FOREACH_RE (rn, re) {
432 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
433 break;
434 }
435
436 if (!re || !zebra_rib_labeled_unicast(re))
437 return 0;
438
439 if (lsp_install(zvrf, fec->label, rn, re))
440 return -1;
441
442 return 0;
443 }
444
445 /*
446 * Inform about FEC to a registered client.
447 */
448 static int fec_send(struct zebra_fec *fec, struct zserv *client)
449 {
450 struct stream *s;
451 struct route_node *rn;
452
453 rn = fec->rn;
454
455 /* Get output stream. */
456 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
457
458 zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
459
460 stream_putw(s, rn->p.family);
461 stream_put_prefix(s, &rn->p);
462 stream_putl(s, fec->label);
463 stream_putw_at(s, 0, stream_get_endp(s));
464 return zserv_send_message(client, s);
465 }
466
467 /*
468 * Update all registered clients about this FEC. Caller should've updated
469 * FEC and ensure no duplicate updates.
470 */
471 static void fec_update_clients(struct zebra_fec *fec)
472 {
473 struct listnode *node;
474 struct zserv *client;
475
476 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) {
477 if (IS_ZEBRA_DEBUG_MPLS)
478 zlog_debug("Update client %s",
479 zebra_route_string(client->proto));
480 fec_send(fec, client);
481 }
482 }
483
484
485 /*
486 * Print a FEC-label binding entry.
487 */
488 static void fec_print(struct zebra_fec *fec, struct vty *vty)
489 {
490 struct route_node *rn;
491 struct listnode *node;
492 struct zserv *client;
493 char buf[BUFSIZ];
494
495 rn = fec->rn;
496 vty_out(vty, "%pRN\n", rn);
497 vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
498 if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
499 vty_out(vty, ", Label Index: %u", fec->label_index);
500 vty_out(vty, "\n");
501 if (!list_isempty(fec->client_list)) {
502 vty_out(vty, " Client list:");
503 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
504 vty_out(vty, " %s(fd %d)",
505 zebra_route_string(client->proto),
506 client->sock);
507 vty_out(vty, "\n");
508 }
509 }
510
511 /*
512 * Locate FEC-label binding that matches with passed info.
513 */
514 static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p)
515 {
516 struct route_node *rn;
517
518 apply_mask(p);
519 rn = route_node_lookup(table, p);
520 if (!rn)
521 return NULL;
522
523 route_unlock_node(rn);
524 return (rn->info);
525 }
526
527 /*
528 * Add a FEC. This may be upon a client registering for a binding
529 * or when a binding is configured.
530 */
531 static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
532 mpls_label_t label, uint32_t flags,
533 uint32_t label_index)
534 {
535 struct route_node *rn;
536 struct zebra_fec *fec;
537
538 apply_mask(p);
539
540 /* Lookup (or add) route node.*/
541 rn = route_node_get(table, p);
542 if (!rn)
543 return NULL;
544
545 fec = rn->info;
546
547 if (!fec) {
548 fec = XCALLOC(MTYPE_FEC, sizeof(struct zebra_fec));
549
550 rn->info = fec;
551 fec->rn = rn;
552 fec->label = label;
553 fec->client_list = list_new();
554 } else
555 route_unlock_node(rn); /* for the route_node_get */
556
557 fec->label_index = label_index;
558 fec->flags = flags;
559
560 return fec;
561 }
562
563 /*
564 * Delete a FEC. This may be upon the last client deregistering for
565 * a FEC and no binding exists or when the binding is deleted and there
566 * are no registered clients.
567 */
568 static int fec_del(struct zebra_fec *fec)
569 {
570 list_delete(&fec->client_list);
571 fec->rn->info = NULL;
572 route_unlock_node(fec->rn);
573 XFREE(MTYPE_FEC, fec);
574 return 0;
575 }
576
577 /*
578 * Hash function for label.
579 */
580 static unsigned int label_hash(const void *p)
581 {
582 const struct zebra_ile *ile = p;
583
584 return (jhash_1word(ile->in_label, 0));
585 }
586
587 /*
588 * Compare 2 LSP hash entries based on in-label.
589 */
590 static bool label_cmp(const void *p1, const void *p2)
591 {
592 const struct zebra_ile *ile1 = p1;
593 const struct zebra_ile *ile2 = p2;
594
595 return (ile1->in_label == ile2->in_label);
596 }
597
598 /*
599 * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
600 * the passed flag.
601 * NOTE: Looking only for connected routes right now.
602 */
603 static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
604 struct nexthop *nexthop)
605 {
606 struct route_table *table;
607 struct prefix_ipv4 p;
608 struct route_node *rn;
609 struct route_entry *match;
610 struct nexthop *match_nh;
611
612 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, nexthop->vrf_id);
613 if (!table)
614 return 0;
615
616 /* Lookup nexthop in IPv4 routing table. */
617 memset(&p, 0, sizeof(struct prefix_ipv4));
618 p.family = AF_INET;
619 p.prefixlen = IPV4_MAX_BITLEN;
620 p.prefix = nexthop->gate.ipv4;
621
622 rn = route_node_match(table, (struct prefix *)&p);
623 if (!rn)
624 return 0;
625
626 route_unlock_node(rn);
627
628 /* Locate a valid connected route. */
629 RNODE_FOREACH_RE (rn, match) {
630 if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
631 || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
632 continue;
633
634 for (match_nh = match->nhe->nhg.nexthop; match_nh;
635 match_nh = match_nh->next) {
636 if (match->type == ZEBRA_ROUTE_CONNECT
637 || nexthop->ifindex == match_nh->ifindex) {
638 nexthop->ifindex = match_nh->ifindex;
639 return 1;
640 }
641 }
642 }
643
644 return 0;
645 }
646
647
648 /*
649 * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
650 * the passed flag.
651 * NOTE: Looking only for connected routes right now.
652 */
653 static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
654 struct nexthop *nexthop)
655 {
656 struct route_table *table;
657 struct prefix_ipv6 p;
658 struct route_node *rn;
659 struct route_entry *match;
660
661 table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
662 if (!table)
663 return 0;
664
665 /* Lookup nexthop in IPv6 routing table. */
666 memset(&p, 0, sizeof(struct prefix_ipv6));
667 p.family = AF_INET6;
668 p.prefixlen = IPV6_MAX_BITLEN;
669 p.prefix = nexthop->gate.ipv6;
670
671 rn = route_node_match(table, (struct prefix *)&p);
672 if (!rn)
673 return 0;
674
675 route_unlock_node(rn);
676
677 /* Locate a valid connected route. */
678 RNODE_FOREACH_RE (rn, match) {
679 if ((match->type == ZEBRA_ROUTE_CONNECT)
680 && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
681 && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
682 break;
683 }
684
685 if (!match || !match->nhe->nhg.nexthop)
686 return 0;
687
688 nexthop->ifindex = match->nhe->nhg.nexthop->ifindex;
689 return 1;
690 }
691
692
693 /*
694 * Check the nexthop reachability for a NHLFE and return if valid (reachable)
695 * or not.
696 * NOTE: Each NHLFE points to only 1 nexthop.
697 */
698 static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe)
699 {
700 struct nexthop *nexthop;
701 struct interface *ifp;
702 struct zebra_ns *zns;
703
704 nexthop = nhlfe->nexthop;
705 if (!nexthop) // unexpected
706 return 0;
707
708 /* Check on nexthop based on type. */
709 switch (nexthop->type) {
710 case NEXTHOP_TYPE_IFINDEX:
711 /*
712 * Lookup if this type is special. The
713 * NEXTHOP_TYPE_IFINDEX is a pop and
714 * forward into a different table for
715 * processing. As such this ifindex
716 * passed to us may be a VRF device
717 * which will not be in the default
718 * VRF. So let's look in all of them
719 */
720 zns = zebra_ns_lookup(NS_DEFAULT);
721 ifp = if_lookup_by_index_per_ns(zns, nexthop->ifindex);
722 if (ifp && if_is_operative(ifp))
723 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
724 else
725 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
726 break;
727 case NEXTHOP_TYPE_IPV4:
728 case NEXTHOP_TYPE_IPV4_IFINDEX:
729 if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop))
730 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
731 else
732 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
733 break;
734
735 case NEXTHOP_TYPE_IPV6:
736 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
737 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
738 else
739 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
740 break;
741
742 case NEXTHOP_TYPE_IPV6_IFINDEX:
743 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
744 ifp = if_lookup_by_index(nexthop->ifindex,
745 nexthop->vrf_id);
746 if (ifp && if_is_operative(ifp))
747 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
748 else
749 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
750 } else {
751 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
752 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
753 else
754 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
755 }
756 break;
757
758 case NEXTHOP_TYPE_BLACKHOLE:
759 break;
760 }
761
762 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
763 }
764
765 /*
766 * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
767 * reachability and select the best. Multipath entries are also
768 * marked. This is invoked when an LSP scheduled for processing (due
769 * to some change) is examined.
770 */
771 static void lsp_select_best_nhlfe(struct zebra_lsp *lsp)
772 {
773 struct zebra_nhlfe *nhlfe;
774 struct zebra_nhlfe *best;
775 struct nexthop *nexthop;
776 int changed = 0;
777
778 if (!lsp)
779 return;
780
781 best = NULL;
782 lsp->num_ecmp = 0;
783 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
784
785 /*
786 * First compute the best path, after checking nexthop status. We are
787 * only concerned with non-deleted NHLFEs.
788 */
789 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
790 /* Clear selection flags. */
791 UNSET_FLAG(nhlfe->flags,
792 (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
793
794 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
795 && nhlfe_nexthop_active(nhlfe)) {
796 if (!best || (nhlfe->distance < best->distance))
797 best = nhlfe;
798 }
799 }
800
801 lsp->best_nhlfe = best;
802 if (!lsp->best_nhlfe)
803 return;
804
805 /*
806 * Check the active status of backup nhlfes also
807 */
808 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
809 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
810 (void)nhlfe_nexthop_active(nhlfe);
811 }
812
813 /* Mark best NHLFE as selected. */
814 SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
815
816 /*
817 * If best path exists, see if there is ECMP. While doing this, note if
818 * a
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.
821 */
822 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
823 int nh_chg, nh_sel, nh_inst;
824
825 nexthop = nhlfe->nexthop;
826 if (!nexthop) // unexpected
827 continue;
828
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);
834 lsp->num_ecmp++;
835 }
836
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);
840 nh_inst =
841 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
842
843 if ((nh_sel && !nh_inst)
844 || (nh_sel && nh_inst && nh_chg)
845 || (nh_inst && !nh_sel))
846 changed = 1;
847 }
848
849 /* We have finished examining, clear changed flag. */
850 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
851 }
852
853 if (changed)
854 SET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
855 }
856
857 /*
858 * Delete LSP forwarding entry from kernel, if installed. Called upon
859 * process exit.
860 */
861 static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt)
862 {
863 struct zebra_lsp *lsp;
864
865 lsp = (struct zebra_lsp *)bucket->data;
866 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
867 (void)dplane_lsp_delete(lsp);
868 }
869
870 /*
871 * Schedule LSP forwarding entry for processing. Called upon changes
872 * that may impact LSPs such as nexthop / connected route changes.
873 */
874 static void lsp_schedule(struct hash_bucket *bucket, void *ctxt)
875 {
876 struct zebra_lsp *lsp;
877
878 lsp = (struct zebra_lsp *)bucket->data;
879
880 /* In the common flow, this is used when external events occur. For
881 * LSPs with backup nhlfes, we'll assume that the forwarding
882 * plane will use the backups to handle these events, until the
883 * owning protocol can react.
884 */
885 if (ctxt == NULL) {
886 /* Skip LSPs with backups */
887 if (nhlfe_list_first(&lsp->backup_nhlfe_list) != NULL) {
888 if (IS_ZEBRA_DEBUG_MPLS_DETAIL)
889 zlog_debug("%s: skip LSP in-label %u",
890 __func__, lsp->ile.in_label);
891 return;
892 }
893 }
894
895 (void)lsp_processq_add(lsp);
896 }
897
898 /*
899 * Process a LSP entry that is in the queue. Recalculate best NHLFE and
900 * any multipaths and update or delete from the kernel, as needed.
901 */
902 static wq_item_status lsp_process(struct work_queue *wq, void *data)
903 {
904 struct zebra_lsp *lsp;
905 struct zebra_nhlfe *oldbest, *newbest;
906 char buf[BUFSIZ], buf2[BUFSIZ];
907 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
908 enum zebra_dplane_result res;
909
910 lsp = (struct zebra_lsp *)data;
911 if (!lsp) // unexpected
912 return WQ_SUCCESS;
913
914 oldbest = lsp->best_nhlfe;
915
916 /* Select best NHLFE(s) */
917 lsp_select_best_nhlfe(lsp);
918
919 newbest = lsp->best_nhlfe;
920
921 if (IS_ZEBRA_DEBUG_MPLS) {
922 if (oldbest)
923 nhlfe2str(oldbest, buf, sizeof(buf));
924 if (newbest)
925 nhlfe2str(newbest, buf2, sizeof(buf2));
926 zlog_debug(
927 "Process LSP in-label %u oldbest %s newbest %s flags 0x%x ecmp# %d",
928 lsp->ile.in_label, oldbest ? buf : "NULL",
929 newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
930 }
931
932 if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
933 /* Not already installed */
934 if (newbest) {
935
936 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
937
938 switch (dplane_lsp_add(lsp)) {
939 case ZEBRA_DPLANE_REQUEST_QUEUED:
940 /* Set 'installed' flag so we will know
941 * that an install is in-flight.
942 */
943 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
944
945 zvrf->lsp_installs_queued++;
946 break;
947 case ZEBRA_DPLANE_REQUEST_FAILURE:
948 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
949 "LSP Install Failure: %u",
950 lsp->ile.in_label);
951 break;
952 case ZEBRA_DPLANE_REQUEST_SUCCESS:
953 zvrf->lsp_installs++;
954 break;
955 }
956 }
957 } else {
958 /* Installed, may need an update and/or delete. */
959 if (!newbest) {
960 res = dplane_lsp_delete(lsp);
961
962 /* We do some of the lsp cleanup immediately for
963 * deletes.
964 */
965 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
966 clear_nhlfe_installed(lsp);
967
968 switch (res) {
969 case ZEBRA_DPLANE_REQUEST_QUEUED:
970 zvrf->lsp_removals_queued++;
971 break;
972 case ZEBRA_DPLANE_REQUEST_FAILURE:
973 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
974 "LSP Deletion Failure: %u",
975 lsp->ile.in_label);
976 break;
977 case ZEBRA_DPLANE_REQUEST_SUCCESS:
978 zvrf->lsp_removals++;
979 break;
980 }
981 } else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) {
982 struct zebra_nhlfe *nhlfe;
983 struct nexthop *nexthop;
984
985 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
986
987 /* We leave the INSTALLED flag set here
988 * so we know an update is in-flight.
989 */
990
991 /*
992 * Any NHLFE that was installed but is not
993 * selected now needs to have its flags updated.
994 */
995 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
996 nexthop = nhlfe->nexthop;
997 if (!nexthop)
998 continue;
999
1000 if (CHECK_FLAG(nhlfe->flags,
1001 NHLFE_FLAG_INSTALLED)
1002 && !CHECK_FLAG(nhlfe->flags,
1003 NHLFE_FLAG_SELECTED)) {
1004 UNSET_FLAG(nhlfe->flags,
1005 NHLFE_FLAG_INSTALLED);
1006 UNSET_FLAG(nexthop->flags,
1007 NEXTHOP_FLAG_FIB);
1008 }
1009 }
1010
1011 switch (dplane_lsp_update(lsp)) {
1012 case ZEBRA_DPLANE_REQUEST_QUEUED:
1013 zvrf->lsp_installs_queued++;
1014 break;
1015 case ZEBRA_DPLANE_REQUEST_FAILURE:
1016 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1017 "LSP Update Failure: %u",
1018 lsp->ile.in_label);
1019 break;
1020 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1021 zvrf->lsp_installs++;
1022 break;
1023 }
1024 }
1025 }
1026
1027 return WQ_SUCCESS;
1028 }
1029
1030
1031 /*
1032 * Callback upon processing completion of a LSP forwarding entry.
1033 */
1034 static void lsp_processq_del(struct work_queue *wq, void *data)
1035 {
1036 struct zebra_vrf *zvrf;
1037 struct zebra_lsp *lsp;
1038 struct hash *lsp_table;
1039 struct zebra_nhlfe *nhlfe;
1040 bool in_shutdown = false;
1041
1042 /* If zebra is shutting down, don't delete any structs,
1043 * just ignore this callback. The LSPs will be cleaned up
1044 * during the shutdown processing.
1045 */
1046 in_shutdown = atomic_load_explicit(&zrouter.in_shutdown,
1047 memory_order_relaxed);
1048 if (in_shutdown)
1049 return;
1050
1051 zvrf = vrf_info_lookup(VRF_DEFAULT);
1052 assert(zvrf);
1053
1054 lsp_table = zvrf->lsp_table;
1055 if (!lsp_table) // unexpected
1056 return;
1057
1058 lsp = (struct zebra_lsp *)data;
1059 if (!lsp) // unexpected
1060 return;
1061
1062 /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
1063 * exist,
1064 * delete LSP entry also.
1065 */
1066 UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1067
1068 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1069 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1070 nhlfe_del(nhlfe);
1071 }
1072
1073 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1074 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1075 nhlfe_del(nhlfe);
1076 }
1077
1078 lsp_check_free(lsp_table, &lsp);
1079 }
1080
1081 /*
1082 * Callback upon finishing the processing of all scheduled
1083 * LSP forwarding entries.
1084 */
1085 static void lsp_processq_complete(struct work_queue *wq)
1086 {
1087 /* Nothing to do for now. */
1088 }
1089
1090 /*
1091 * Add LSP forwarding entry to queue for subsequent processing.
1092 */
1093 static int lsp_processq_add(struct zebra_lsp *lsp)
1094 {
1095 /* If already scheduled, exit. */
1096 if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1097 return 0;
1098
1099 if (zrouter.lsp_process_q == NULL) {
1100 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1101 "%s: work_queue does not exist!", __func__);
1102 return -1;
1103 }
1104
1105 work_queue_add(zrouter.lsp_process_q, lsp);
1106 SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1107 return 0;
1108 }
1109
1110 /*
1111 * Callback to allocate LSP forwarding table entry.
1112 */
1113 static void *lsp_alloc(void *p)
1114 {
1115 const struct zebra_ile *ile = p;
1116 struct zebra_lsp *lsp;
1117
1118 lsp = XCALLOC(MTYPE_LSP, sizeof(struct zebra_lsp));
1119 lsp->ile = *ile;
1120 nhlfe_list_init(&lsp->nhlfe_list);
1121 nhlfe_list_init(&lsp->backup_nhlfe_list);
1122
1123 if (IS_ZEBRA_DEBUG_MPLS)
1124 zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label);
1125
1126 return ((void *)lsp);
1127 }
1128
1129 /*
1130 * Check whether lsp can be freed - no nhlfes, e.g., and call free api
1131 */
1132 static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp)
1133 {
1134 struct zebra_lsp *lsp;
1135
1136 if (plsp == NULL || *plsp == NULL)
1137 return;
1138
1139 lsp = *plsp;
1140
1141 if ((nhlfe_list_first(&lsp->nhlfe_list) == NULL) &&
1142 (nhlfe_list_first(&lsp->backup_nhlfe_list) == NULL) &&
1143 !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1144 lsp_free(lsp_table, plsp);
1145 }
1146
1147 /*
1148 * Dtor for an LSP: remove from ile hash, release any internal allocations,
1149 * free LSP object.
1150 */
1151 static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp)
1152 {
1153 struct zebra_lsp *lsp;
1154 struct zebra_nhlfe *nhlfe;
1155
1156 if (plsp == NULL || *plsp == NULL)
1157 return;
1158
1159 lsp = *plsp;
1160
1161 if (IS_ZEBRA_DEBUG_MPLS)
1162 zlog_debug("Free LSP in-label %u flags 0x%x",
1163 lsp->ile.in_label, lsp->flags);
1164
1165 /* Free nhlfes, if any. */
1166 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe)
1167 nhlfe_del(nhlfe);
1168
1169 /* Free backup nhlfes, if any. */
1170 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe)
1171 nhlfe_del(nhlfe);
1172
1173 hash_release(lsp_table, &lsp->ile);
1174 XFREE(MTYPE_LSP, lsp);
1175
1176 *plsp = NULL;
1177 }
1178
1179 /*
1180 * Create printable string for NHLFE entry.
1181 */
1182 static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size)
1183 {
1184 const struct nexthop *nexthop;
1185
1186 buf[0] = '\0';
1187 nexthop = nhlfe->nexthop;
1188 switch (nexthop->type) {
1189 case NEXTHOP_TYPE_IPV4:
1190 case NEXTHOP_TYPE_IPV4_IFINDEX:
1191 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
1192 break;
1193 case NEXTHOP_TYPE_IPV6:
1194 case NEXTHOP_TYPE_IPV6_IFINDEX:
1195 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
1196 break;
1197 case NEXTHOP_TYPE_IFINDEX:
1198 snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
1199 case NEXTHOP_TYPE_BLACKHOLE:
1200 break;
1201 }
1202
1203 return buf;
1204 }
1205
1206 /*
1207 * Check if NHLFE matches with search info passed.
1208 */
1209 static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
1210 enum nexthop_types_t gtype,
1211 const union g_addr *gate, ifindex_t ifindex)
1212 {
1213 struct nexthop *nhop;
1214 int cmp = 1;
1215
1216 nhop = nhlfe->nexthop;
1217 if (!nhop)
1218 return 1;
1219
1220 if (nhop->type != gtype)
1221 return 1;
1222
1223 switch (nhop->type) {
1224 case NEXTHOP_TYPE_IPV4:
1225 case NEXTHOP_TYPE_IPV4_IFINDEX:
1226 cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
1227 sizeof(struct in_addr));
1228 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1229 cmp = !(nhop->ifindex == ifindex);
1230 break;
1231 case NEXTHOP_TYPE_IPV6:
1232 case NEXTHOP_TYPE_IPV6_IFINDEX:
1233 cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
1234 sizeof(struct in6_addr));
1235 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1236 cmp = !(nhop->ifindex == ifindex);
1237 break;
1238 case NEXTHOP_TYPE_IFINDEX:
1239 cmp = !(nhop->ifindex == ifindex);
1240 break;
1241 case NEXTHOP_TYPE_BLACKHOLE:
1242 break;
1243 }
1244
1245 return cmp;
1246 }
1247
1248
1249 /*
1250 * Locate NHLFE that matches with passed info.
1251 */
1252 static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
1253 enum lsp_types_t lsp_type,
1254 enum nexthop_types_t gtype,
1255 const union g_addr *gate,
1256 ifindex_t ifindex)
1257 {
1258 struct zebra_nhlfe *nhlfe;
1259
1260 frr_each_safe(nhlfe_list, list, nhlfe) {
1261 if (nhlfe->type != lsp_type)
1262 continue;
1263 if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex))
1264 break;
1265 }
1266
1267 return nhlfe;
1268 }
1269
1270 /*
1271 * Allocate and init new NHLFE.
1272 */
1273 static struct zebra_nhlfe *
1274 nhlfe_alloc(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
1275 enum nexthop_types_t gtype, const union g_addr *gate,
1276 ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels)
1277 {
1278 struct zebra_nhlfe *nhlfe;
1279 struct nexthop *nexthop;
1280
1281 assert(lsp);
1282
1283 nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(struct zebra_nhlfe));
1284
1285 nhlfe->lsp = lsp;
1286 nhlfe->type = lsp_type;
1287 nhlfe->distance = lsp_distance(lsp_type);
1288
1289 nexthop = nexthop_new();
1290
1291 nexthop_add_labels(nexthop, lsp_type, num_labels, labels);
1292
1293 nexthop->vrf_id = VRF_DEFAULT;
1294 nexthop->type = gtype;
1295 switch (nexthop->type) {
1296 case NEXTHOP_TYPE_IPV4:
1297 case NEXTHOP_TYPE_IPV4_IFINDEX:
1298 nexthop->gate.ipv4 = gate->ipv4;
1299 if (ifindex)
1300 nexthop->ifindex = ifindex;
1301 break;
1302 case NEXTHOP_TYPE_IPV6:
1303 case NEXTHOP_TYPE_IPV6_IFINDEX:
1304 nexthop->gate.ipv6 = gate->ipv6;
1305 if (ifindex)
1306 nexthop->ifindex = ifindex;
1307 break;
1308 case NEXTHOP_TYPE_IFINDEX:
1309 nexthop->ifindex = ifindex;
1310 break;
1311 case NEXTHOP_TYPE_BLACKHOLE:
1312 if (IS_ZEBRA_DEBUG_MPLS)
1313 zlog_debug("%s: invalid: blackhole nexthop", __func__);
1314
1315 nexthop_free(nexthop);
1316 XFREE(MTYPE_NHLFE, nhlfe);
1317 return NULL;
1318 }
1319 nhlfe->nexthop = nexthop;
1320
1321 return nhlfe;
1322 }
1323
1324 /*
1325 * Add primary or backup NHLFE. Base entry must have been created and
1326 * duplicate check done.
1327 */
1328 static struct zebra_nhlfe *nhlfe_add(struct zebra_lsp *lsp,
1329 enum lsp_types_t lsp_type,
1330 enum nexthop_types_t gtype,
1331 const union g_addr *gate,
1332 ifindex_t ifindex, uint8_t num_labels,
1333 const mpls_label_t *labels, bool is_backup)
1334 {
1335 struct zebra_nhlfe *nhlfe;
1336
1337 if (!lsp)
1338 return NULL;
1339
1340 /* Must have labels */
1341 if (num_labels == 0 || labels == NULL) {
1342 if (IS_ZEBRA_DEBUG_MPLS)
1343 zlog_debug("%s: invalid nexthop: no labels", __func__);
1344
1345 return NULL;
1346 }
1347
1348 /* Allocate new object */
1349 nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels,
1350 labels);
1351
1352 if (!nhlfe)
1353 return NULL;
1354
1355 /* Enqueue to LSP: primaries at head of list, backups at tail */
1356 if (is_backup) {
1357 SET_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP);
1358 nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe);
1359 } else
1360 nhlfe_list_add_head(&lsp->nhlfe_list, nhlfe);
1361
1362 return nhlfe;
1363 }
1364
1365 /*
1366 * Common delete for NHLFEs.
1367 */
1368 static void nhlfe_free(struct zebra_nhlfe *nhlfe)
1369 {
1370 if (!nhlfe)
1371 return;
1372
1373 /* Free nexthop. */
1374 if (nhlfe->nexthop)
1375 nexthop_free(nhlfe->nexthop);
1376
1377 nhlfe->nexthop = NULL;
1378
1379 XFREE(MTYPE_NHLFE, nhlfe);
1380 }
1381
1382
1383 /*
1384 * Disconnect NHLFE from LSP, and free. Entry must be present on LSP's list.
1385 */
1386 static int nhlfe_del(struct zebra_nhlfe *nhlfe)
1387 {
1388 struct zebra_lsp *lsp;
1389
1390 if (!nhlfe)
1391 return -1;
1392
1393 lsp = nhlfe->lsp;
1394 if (!lsp)
1395 return -1;
1396
1397 if (nhlfe == lsp->best_nhlfe)
1398 lsp->best_nhlfe = NULL;
1399
1400 /* Unlink from LSP */
1401 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP))
1402 nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
1403 else
1404 nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
1405
1406 nhlfe->lsp = NULL;
1407
1408 nhlfe_free(nhlfe);
1409
1410 return 0;
1411 }
1412
1413 /*
1414 * Update label for NHLFE entry.
1415 */
1416 static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
1417 struct mpls_label_stack *nh_label)
1418 {
1419 nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
1420 }
1421
1422 static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
1423 enum lsp_types_t type)
1424 {
1425 struct zebra_nhlfe *nhlfe;
1426 int schedule_lsp = 0;
1427 char buf[BUFSIZ];
1428
1429 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1430 schedule_lsp = 1;
1431
1432 /* Mark NHLFEs for delete or directly delete, as appropriate. */
1433 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1434 /* Skip non-static NHLFEs */
1435 if (nhlfe->type != type)
1436 continue;
1437
1438 if (IS_ZEBRA_DEBUG_MPLS) {
1439 nhlfe2str(nhlfe, buf, sizeof(buf));
1440 zlog_debug(
1441 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
1442 lsp->ile.in_label, type, buf, nhlfe->flags);
1443 }
1444
1445 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1446 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1447 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1448 schedule_lsp = 1;
1449 } else {
1450 nhlfe_del(nhlfe);
1451 }
1452 }
1453
1454 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1455 /* Skip non-static NHLFEs */
1456 if (nhlfe->type != type)
1457 continue;
1458
1459 if (IS_ZEBRA_DEBUG_MPLS) {
1460 nhlfe2str(nhlfe, buf, sizeof(buf));
1461 zlog_debug(
1462 "Del backup LSP in-label %u type %d nexthop %s flags 0x%x",
1463 lsp->ile.in_label, type, buf, nhlfe->flags);
1464 }
1465
1466 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1467 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1468 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1469 schedule_lsp = 1;
1470 } else {
1471 nhlfe_del(nhlfe);
1472 }
1473 }
1474
1475 /* Queue LSP for processing, if needed, else delete. */
1476 if (schedule_lsp) {
1477 if (IS_ZEBRA_DEBUG_MPLS) {
1478 zlog_debug("Schedule LSP in-label %u flags 0x%x",
1479 lsp->ile.in_label, lsp->flags);
1480 }
1481 if (lsp_processq_add(lsp))
1482 return -1;
1483 } else {
1484 lsp_check_free(lsp_table, &lsp);
1485 }
1486
1487 return 0;
1488 }
1489
1490 /*
1491 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
1492 * If no other NHLFEs exist, the entry would be deleted.
1493 */
1494 static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
1495 mpls_label_t in_label)
1496 {
1497 struct hash *lsp_table;
1498 struct zebra_ile tmp_ile;
1499 struct zebra_lsp *lsp;
1500
1501 /* Lookup table. */
1502 lsp_table = zvrf->lsp_table;
1503 if (!lsp_table)
1504 return -1;
1505
1506 /* If entry is not present, exit. */
1507 tmp_ile.in_label = in_label;
1508 lsp = hash_lookup(lsp_table, &tmp_ile);
1509 if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
1510 return 0;
1511
1512 return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC);
1513 }
1514
1515 static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe)
1516 {
1517 json_object *json_nhlfe = NULL;
1518 json_object *json_backups = NULL;
1519 json_object *json_label_stack;
1520 struct nexthop *nexthop = nhlfe->nexthop;
1521 int i;
1522
1523 json_nhlfe = json_object_new_object();
1524 json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
1525 json_object_int_add(json_nhlfe, "outLabel",
1526 nexthop->nh_label->label[0]);
1527
1528 json_label_stack = json_object_new_array();
1529 json_object_object_add(json_nhlfe, "outLabelStack", json_label_stack);
1530 for (i = 0; i < nexthop->nh_label->num_labels; i++)
1531 json_object_array_add(
1532 json_label_stack,
1533 json_object_new_int(nexthop->nh_label->label[i]));
1534
1535 json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
1536
1537 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
1538 json_object_boolean_true_add(json_nhlfe, "installed");
1539
1540 switch (nexthop->type) {
1541 case NEXTHOP_TYPE_IPV4:
1542 case NEXTHOP_TYPE_IPV4_IFINDEX:
1543 json_object_string_addf(json_nhlfe, "nexthop", "%pI4",
1544 &nexthop->gate.ipv4);
1545 break;
1546 case NEXTHOP_TYPE_IPV6:
1547 case NEXTHOP_TYPE_IPV6_IFINDEX:
1548 json_object_string_addf(json_nhlfe, "nexthop", "%pI6",
1549 &nexthop->gate.ipv6);
1550
1551 if (nexthop->ifindex)
1552 json_object_string_add(json_nhlfe, "interface",
1553 ifindex2ifname(nexthop->ifindex,
1554 nexthop->vrf_id));
1555 break;
1556 case NEXTHOP_TYPE_IFINDEX:
1557 if (nexthop->ifindex)
1558 json_object_string_add(json_nhlfe, "interface",
1559 ifindex2ifname(nexthop->ifindex,
1560 nexthop->vrf_id));
1561 break;
1562 case NEXTHOP_TYPE_BLACKHOLE:
1563 break;
1564 }
1565
1566 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
1567 json_backups = json_object_new_array();
1568 for (i = 0; i < nexthop->backup_num; i++) {
1569 json_object_array_add(
1570 json_backups,
1571 json_object_new_int(nexthop->backup_idx[i]));
1572 }
1573
1574 json_object_object_add(json_nhlfe, "backupIndex",
1575 json_backups);
1576 }
1577
1578 return json_nhlfe;
1579 }
1580
1581 /*
1582 * Print the NHLFE for a LSP forwarding entry.
1583 */
1584 static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
1585 const char *indent)
1586 {
1587 struct nexthop *nexthop;
1588 char buf[MPLS_LABEL_STRLEN];
1589
1590 nexthop = nhlfe->nexthop;
1591 if (!nexthop || !nexthop->nh_label) // unexpected
1592 return;
1593
1594 vty_out(vty, " type: %s remote label: %s distance: %d\n",
1595 nhlfe_type2str(nhlfe->type),
1596 mpls_label2str(nexthop->nh_label->num_labels,
1597 nexthop->nh_label->label,
1598 buf, sizeof(buf), 0),
1599 nhlfe->distance);
1600
1601 if (indent)
1602 vty_out(vty, "%s", indent);
1603
1604 switch (nexthop->type) {
1605 case NEXTHOP_TYPE_IPV4:
1606 case NEXTHOP_TYPE_IPV4_IFINDEX:
1607 vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
1608 if (nexthop->ifindex)
1609 vty_out(vty, " dev %s",
1610 ifindex2ifname(nexthop->ifindex,
1611 nexthop->vrf_id));
1612 break;
1613 case NEXTHOP_TYPE_IPV6:
1614 case NEXTHOP_TYPE_IPV6_IFINDEX:
1615 vty_out(vty, " via %s",
1616 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
1617 sizeof(buf)));
1618 if (nexthop->ifindex)
1619 vty_out(vty, " dev %s",
1620 ifindex2ifname(nexthop->ifindex,
1621 nexthop->vrf_id));
1622 break;
1623 case NEXTHOP_TYPE_IFINDEX:
1624 if (nexthop->ifindex)
1625 vty_out(vty, " dev %s",
1626 ifindex2ifname(nexthop->ifindex,
1627 nexthop->vrf_id));
1628 break;
1629 case NEXTHOP_TYPE_BLACKHOLE:
1630 break;
1631 }
1632 vty_out(vty, "%s",
1633 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP) ? " (backup)"
1634 : "");
1635 vty_out(vty, "%s",
1636 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
1637 : "");
1638 vty_out(vty, "\n");
1639 }
1640
1641 /*
1642 * Print an LSP forwarding entry.
1643 */
1644 static void lsp_print(struct vty *vty, struct zebra_lsp *lsp)
1645 {
1646 struct zebra_nhlfe *nhlfe, *backup;
1647 int i, j;
1648
1649 vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label,
1650 CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)"
1651 : "");
1652
1653 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1654 nhlfe_print(nhlfe, vty, NULL);
1655
1656 if (nhlfe->nexthop == NULL ||
1657 !CHECK_FLAG(nhlfe->nexthop->flags,
1658 NEXTHOP_FLAG_HAS_BACKUP))
1659 continue;
1660
1661 /* Backup nhlfes: find backups in backup list */
1662
1663 for (j = 0; j < nhlfe->nexthop->backup_num; j++) {
1664 i = 0;
1665 backup = NULL;
1666 frr_each(nhlfe_list, &lsp->backup_nhlfe_list, backup) {
1667 if (i == nhlfe->nexthop->backup_idx[j])
1668 break;
1669 i++;
1670 }
1671
1672 if (backup) {
1673 vty_out(vty, " [backup %d]", i);
1674 nhlfe_print(backup, vty, " ");
1675 }
1676 }
1677 }
1678 }
1679
1680 /*
1681 * JSON objects for an LSP forwarding entry.
1682 */
1683 static json_object *lsp_json(struct zebra_lsp *lsp)
1684 {
1685 struct zebra_nhlfe *nhlfe = NULL;
1686 json_object *json = json_object_new_object();
1687 json_object *json_nhlfe_list = json_object_new_array();
1688
1689 json_object_int_add(json, "inLabel", lsp->ile.in_label);
1690
1691 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1692 json_object_boolean_true_add(json, "installed");
1693
1694 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe)
1695 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1696
1697 json_object_object_add(json, "nexthops", json_nhlfe_list);
1698 json_nhlfe_list = NULL;
1699
1700
1701 frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1702 if (json_nhlfe_list == NULL)
1703 json_nhlfe_list = json_object_new_array();
1704
1705 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1706 }
1707
1708 if (json_nhlfe_list)
1709 json_object_object_add(json, "backupNexthops", json_nhlfe_list);
1710
1711 return json;
1712 }
1713
1714
1715 /* Return a sorted linked list of the hash contents */
1716 static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
1717 {
1718 unsigned int i;
1719 struct hash_bucket *hb;
1720 struct list *sorted_list = list_new();
1721
1722 sorted_list->cmp = (int (*)(void *, void *))cmp;
1723
1724 for (i = 0; i < hash->size; i++)
1725 for (hb = hash->index[i]; hb; hb = hb->next)
1726 listnode_add_sort(sorted_list, hb->data);
1727
1728 return sorted_list;
1729 }
1730
1731 /*
1732 * Compare two LSPs based on their label values.
1733 */
1734 static int lsp_cmp(const struct zebra_lsp *lsp1, const struct zebra_lsp *lsp2)
1735 {
1736 if (lsp1->ile.in_label < lsp2->ile.in_label)
1737 return -1;
1738
1739 if (lsp1->ile.in_label > lsp2->ile.in_label)
1740 return 1;
1741
1742 return 0;
1743 }
1744
1745 /*
1746 * Initialize work queue for processing changed LSPs.
1747 */
1748 static int mpls_processq_init(void)
1749 {
1750 zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
1751 if (!zrouter.lsp_process_q) {
1752 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1753 "%s: could not initialise work queue!", __func__);
1754 return -1;
1755 }
1756
1757 zrouter.lsp_process_q->spec.workfunc = &lsp_process;
1758 zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
1759 zrouter.lsp_process_q->spec.errorfunc = NULL;
1760 zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
1761 zrouter.lsp_process_q->spec.max_retries = 0;
1762 zrouter.lsp_process_q->spec.hold = 10;
1763
1764 return 0;
1765 }
1766
1767
1768 /*
1769 * Process LSP update results from zebra dataplane.
1770 */
1771 void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
1772 {
1773 struct zebra_vrf *zvrf;
1774 mpls_label_t label;
1775 struct zebra_ile tmp_ile;
1776 struct hash *lsp_table;
1777 struct zebra_lsp *lsp;
1778 struct zebra_nhlfe *nhlfe;
1779 struct nexthop *nexthop;
1780 enum dplane_op_e op;
1781 enum zebra_dplane_result status;
1782 enum zebra_sr_policy_update_label_mode update_mode;
1783
1784 op = dplane_ctx_get_op(ctx);
1785 status = dplane_ctx_get_status(ctx);
1786
1787 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1788 zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
1789 ctx, dplane_op2str(op),
1790 dplane_ctx_get_in_label(ctx),
1791 dplane_res2str(status));
1792
1793 label = dplane_ctx_get_in_label(ctx);
1794
1795 switch (op) {
1796 case DPLANE_OP_LSP_INSTALL:
1797 case DPLANE_OP_LSP_UPDATE:
1798 /* Look for zebra LSP object */
1799 zvrf = vrf_info_lookup(VRF_DEFAULT);
1800 if (zvrf == NULL)
1801 break;
1802
1803 lsp_table = zvrf->lsp_table;
1804
1805 tmp_ile.in_label = label;
1806 lsp = hash_lookup(lsp_table, &tmp_ile);
1807 if (lsp == NULL) {
1808 if (IS_ZEBRA_DEBUG_DPLANE)
1809 zlog_debug("LSP ctx %p: in-label %u not found",
1810 ctx, dplane_ctx_get_in_label(ctx));
1811 break;
1812 }
1813
1814 /* TODO -- Confirm that this result is still 'current' */
1815
1816 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
1817 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1818 clear_nhlfe_installed(lsp);
1819 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1820 "LSP Install Failure: in-label %u",
1821 lsp->ile.in_label);
1822 break;
1823 }
1824
1825 /* Update zebra object */
1826 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1827 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1828 nexthop = nhlfe->nexthop;
1829 if (!nexthop)
1830 continue;
1831
1832 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) &&
1833 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
1834 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1835 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1836 }
1837 }
1838
1839 update_mode = (op == DPLANE_OP_LSP_INSTALL)
1840 ? ZEBRA_SR_POLICY_LABEL_CREATED
1841 : ZEBRA_SR_POLICY_LABEL_UPDATED;
1842 zebra_sr_policy_label_update(label, update_mode);
1843 break;
1844
1845 case DPLANE_OP_LSP_DELETE:
1846 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
1847 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
1848 "LSP Deletion Failure: in-label %u",
1849 dplane_ctx_get_in_label(ctx));
1850 break;
1851 }
1852 zebra_sr_policy_label_update(label,
1853 ZEBRA_SR_POLICY_LABEL_REMOVED);
1854 break;
1855
1856 default:
1857 break;
1858
1859 } /* Switch */
1860
1861 dplane_ctx_fini(&ctx);
1862 }
1863
1864 /*
1865 * Process LSP installation info from two sets of nhlfes: a set from
1866 * a dplane notification, and a set from the zebra LSP object. Update
1867 * counters of installed nexthops, and return whether the LSP has changed.
1868 */
1869 static bool compare_notif_nhlfes(const struct nhlfe_list_head *ctx_head,
1870 struct nhlfe_list_head *nhlfe_head,
1871 int *start_counter, int *end_counter)
1872 {
1873 struct zebra_nhlfe *nhlfe;
1874 const struct zebra_nhlfe *ctx_nhlfe;
1875 struct nexthop *nexthop;
1876 const struct nexthop *ctx_nexthop;
1877 int start_count = 0, end_count = 0;
1878 bool changed_p = false;
1879 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1880
1881 frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
1882 char buf[NEXTHOP_STRLEN];
1883
1884 nexthop = nhlfe->nexthop;
1885 if (!nexthop)
1886 continue;
1887
1888 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
1889 start_count++;
1890
1891 ctx_nhlfe = NULL;
1892 ctx_nexthop = NULL;
1893 frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
1894 ctx_nexthop = ctx_nhlfe->nexthop;
1895 if (!ctx_nexthop)
1896 continue;
1897
1898 if ((ctx_nexthop->type == nexthop->type) &&
1899 nexthop_same(ctx_nexthop, nexthop)) {
1900 /* Matched */
1901 break;
1902 }
1903 }
1904
1905 if (is_debug)
1906 nexthop2str(nexthop, buf, sizeof(buf));
1907
1908 if (ctx_nhlfe && ctx_nexthop) {
1909 if (is_debug) {
1910 const char *tstr = "";
1911
1912 if (!CHECK_FLAG(ctx_nhlfe->flags,
1913 NHLFE_FLAG_INSTALLED))
1914 tstr = "not ";
1915
1916 zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
1917 buf, tstr);
1918 }
1919
1920 /* Test zebra nhlfe install state */
1921 if (CHECK_FLAG(ctx_nhlfe->flags,
1922 NHLFE_FLAG_INSTALLED)) {
1923
1924 if (!CHECK_FLAG(nhlfe->flags,
1925 NHLFE_FLAG_INSTALLED))
1926 changed_p = true;
1927
1928 /* Update counter */
1929 end_count++;
1930 } else {
1931
1932 if (CHECK_FLAG(nhlfe->flags,
1933 NHLFE_FLAG_INSTALLED))
1934 changed_p = true;
1935 }
1936
1937 } else {
1938 /* Not mentioned in lfib set -> uninstalled */
1939 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ||
1940 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ||
1941 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
1942 changed_p = true;
1943 }
1944
1945 if (is_debug)
1946 zlog_debug("LSP dplane notif: no match, nh %s",
1947 buf);
1948 }
1949 }
1950
1951 if (start_counter)
1952 *start_counter += start_count;
1953 if (end_counter)
1954 *end_counter += end_count;
1955
1956 return changed_p;
1957 }
1958
1959 /*
1960 * Update an lsp nhlfe list from a dplane context, typically an async
1961 * notification context. Update the LSP list to match the installed
1962 * status from the context's list.
1963 */
1964 static int update_nhlfes_from_ctx(struct nhlfe_list_head *nhlfe_head,
1965 const struct nhlfe_list_head *ctx_head)
1966 {
1967 int ret = 0;
1968 struct zebra_nhlfe *nhlfe;
1969 const struct zebra_nhlfe *ctx_nhlfe;
1970 struct nexthop *nexthop;
1971 const struct nexthop *ctx_nexthop;
1972 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1973
1974 frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
1975 char buf[NEXTHOP_STRLEN];
1976
1977 nexthop = nhlfe->nexthop;
1978 if (!nexthop)
1979 continue;
1980
1981 ctx_nhlfe = NULL;
1982 ctx_nexthop = NULL;
1983 frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
1984 ctx_nexthop = ctx_nhlfe->nexthop;
1985 if (!ctx_nexthop)
1986 continue;
1987
1988 if ((ctx_nexthop->type == nexthop->type) &&
1989 nexthop_same(ctx_nexthop, nexthop)) {
1990 /* Matched */
1991 break;
1992 }
1993 }
1994
1995 if (is_debug)
1996 nexthop2str(nexthop, buf, sizeof(buf));
1997
1998 if (ctx_nhlfe && ctx_nexthop) {
1999
2000 /* Bring zebra nhlfe install state into sync */
2001 if (CHECK_FLAG(ctx_nhlfe->flags,
2002 NHLFE_FLAG_INSTALLED)) {
2003 if (is_debug)
2004 zlog_debug("%s: matched lsp nhlfe %s (installed)",
2005 __func__, buf);
2006
2007 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2008 SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2009
2010 } else {
2011 if (is_debug)
2012 zlog_debug("%s: matched lsp nhlfe %s (not installed)",
2013 __func__, buf);
2014
2015 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2016 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2017 }
2018
2019 if (CHECK_FLAG(ctx_nhlfe->nexthop->flags,
2020 NEXTHOP_FLAG_FIB)) {
2021 SET_FLAG(nhlfe->nexthop->flags,
2022 NEXTHOP_FLAG_ACTIVE);
2023 SET_FLAG(nhlfe->nexthop->flags,
2024 NEXTHOP_FLAG_FIB);
2025 } else {
2026 UNSET_FLAG(nhlfe->nexthop->flags,
2027 NEXTHOP_FLAG_ACTIVE);
2028 UNSET_FLAG(nhlfe->nexthop->flags,
2029 NEXTHOP_FLAG_FIB);
2030 }
2031
2032 } else {
2033 /* Not mentioned in lfib set -> uninstalled */
2034 if (is_debug)
2035 zlog_debug("%s: no match for lsp nhlfe %s",
2036 __func__, buf);
2037 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2038 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2039 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
2040 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2041 }
2042 }
2043
2044 return ret;
2045 }
2046
2047 /*
2048 * Process async dplane notifications.
2049 */
2050 void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
2051 {
2052 struct zebra_vrf *zvrf;
2053 struct zebra_ile tmp_ile;
2054 struct hash *lsp_table;
2055 struct zebra_lsp *lsp;
2056 const struct nhlfe_list_head *ctx_list;
2057 int start_count = 0, end_count = 0; /* Installed counts */
2058 bool changed_p = false;
2059 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
2060 enum zebra_sr_policy_update_label_mode update_mode;
2061
2062 if (is_debug)
2063 zlog_debug("LSP dplane notif, in-label %u",
2064 dplane_ctx_get_in_label(ctx));
2065
2066 /* Look for zebra LSP object */
2067 zvrf = vrf_info_lookup(VRF_DEFAULT);
2068 if (zvrf == NULL)
2069 goto done;
2070
2071 lsp_table = zvrf->lsp_table;
2072
2073 tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
2074 lsp = hash_lookup(lsp_table, &tmp_ile);
2075 if (lsp == NULL) {
2076 if (is_debug)
2077 zlog_debug("dplane LSP notif: in-label %u not found",
2078 dplane_ctx_get_in_label(ctx));
2079 goto done;
2080 }
2081
2082 /*
2083 * The dataplane/forwarding plane is notifying zebra about the state
2084 * of the nexthops associated with this LSP. First, we take a
2085 * pre-scan pass to determine whether the LSP has transitioned
2086 * from installed -> uninstalled. In that case, we need to have
2087 * the existing state of the LSP objects available before making
2088 * any changes.
2089 */
2090 ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2091
2092 changed_p = compare_notif_nhlfes(ctx_list, &lsp->nhlfe_list,
2093 &start_count, &end_count);
2094
2095 if (is_debug)
2096 zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
2097 start_count, end_count,
2098 changed_p ? ", changed" : "");
2099
2100 ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2101
2102 if (compare_notif_nhlfes(ctx_list, &lsp->backup_nhlfe_list,
2103 &start_count, &end_count))
2104 /* Avoid accidentally setting back to 'false' */
2105 changed_p = true;
2106
2107 if (is_debug)
2108 zlog_debug("LSP dplane notif: lfib backups, start_count %d, end_count %d%s",
2109 start_count, end_count,
2110 changed_p ? ", changed" : "");
2111
2112 /*
2113 * Has the LSP become uninstalled? We need the existing state of the
2114 * nexthops/nhlfes at this point so we know what to delete.
2115 */
2116 if (start_count > 0 && end_count == 0) {
2117 /* Inform other lfibs */
2118 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
2119 }
2120
2121 /*
2122 * Now we take a second pass and bring the zebra
2123 * nexthop state into sync with the forwarding-plane state.
2124 */
2125 ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2126 update_nhlfes_from_ctx(&lsp->nhlfe_list, ctx_list);
2127
2128 ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2129 update_nhlfes_from_ctx(&lsp->backup_nhlfe_list, ctx_list);
2130
2131 if (end_count > 0) {
2132 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2133
2134 /* SR-TE update too */
2135 if (start_count == 0)
2136 update_mode = ZEBRA_SR_POLICY_LABEL_CREATED;
2137 else
2138 update_mode = ZEBRA_SR_POLICY_LABEL_UPDATED;
2139 zebra_sr_policy_label_update(lsp->ile.in_label, update_mode);
2140
2141 if (changed_p)
2142 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
2143
2144 } else {
2145 /* SR-TE update too */
2146 zebra_sr_policy_label_update(lsp->ile.in_label,
2147 ZEBRA_SR_POLICY_LABEL_REMOVED);
2148
2149 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2150 clear_nhlfe_installed(lsp);
2151 }
2152
2153 done:
2154 dplane_ctx_fini(&ctx);
2155 }
2156
2157 /*
2158 * Install dynamic LSP entry.
2159 */
2160 int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
2161 struct route_entry *re)
2162 {
2163 struct route_table *table;
2164 struct zebra_fec *fec;
2165
2166 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2167 if (!table)
2168 return -1;
2169
2170 /* See if there is a configured label binding for this FEC. */
2171 fec = fec_find(table, &rn->p);
2172 if (!fec || fec->label == MPLS_INVALID_LABEL)
2173 return 0;
2174
2175 /* We cannot install a label forwarding entry if local label is the
2176 * implicit-null label.
2177 */
2178 if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
2179 return 0;
2180
2181 if (lsp_install(zvrf, fec->label, rn, re))
2182 return -1;
2183
2184 return 0;
2185 }
2186
2187 /*
2188 * Uninstall dynamic LSP entry, if any.
2189 */
2190 int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
2191 struct route_entry *re)
2192 {
2193 struct route_table *table;
2194 struct zebra_fec *fec;
2195
2196 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2197 if (!table)
2198 return -1;
2199
2200 /* See if there is a configured label binding for this FEC. */
2201 fec = fec_find(table, &rn->p);
2202 if (!fec || fec->label == MPLS_INVALID_LABEL)
2203 return 0;
2204
2205 /* Uninstall always removes all dynamic NHLFEs. */
2206 return lsp_uninstall(zvrf, fec->label);
2207 }
2208
2209 /*
2210 * Add an NHLFE to an LSP, return the newly-added object. This path only changes
2211 * the LSP object - nothing is scheduled for processing, for example.
2212 */
2213 struct zebra_nhlfe *
2214 zebra_mpls_lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
2215 enum nexthop_types_t gtype, const union g_addr *gate,
2216 ifindex_t ifindex, uint8_t num_labels,
2217 const mpls_label_t *out_labels)
2218 {
2219 /* Just a public pass-through to the internal implementation */
2220 return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
2221 out_labels, false /*backup*/);
2222 }
2223
2224 /*
2225 * Add a backup NHLFE to an LSP, return the newly-added object.
2226 * This path only changes the LSP object - nothing is scheduled for
2227 * processing, for example.
2228 */
2229 struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nhlfe(
2230 struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
2231 enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex,
2232 uint8_t num_labels, const mpls_label_t *out_labels)
2233 {
2234 /* Just a public pass-through to the internal implementation */
2235 return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
2236 out_labels, true);
2237 }
2238
2239 /*
2240 * Add an NHLFE to an LSP based on a nexthop; return the newly-added object
2241 */
2242 struct zebra_nhlfe *zebra_mpls_lsp_add_nh(struct zebra_lsp *lsp,
2243 enum lsp_types_t lsp_type,
2244 const struct nexthop *nh)
2245 {
2246 struct zebra_nhlfe *nhlfe;
2247
2248 if (nh->nh_label == NULL || nh->nh_label->num_labels == 0)
2249 return NULL;
2250
2251 nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, nh->ifindex,
2252 nh->nh_label->num_labels, nh->nh_label->label,
2253 false /*backup*/);
2254
2255 return nhlfe;
2256 }
2257
2258 /*
2259 * Add a backup NHLFE to an LSP based on a nexthop;
2260 * return the newly-added object.
2261 */
2262 struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nh(struct zebra_lsp *lsp,
2263 enum lsp_types_t lsp_type,
2264 const struct nexthop *nh)
2265 {
2266 struct zebra_nhlfe *nhlfe;
2267
2268 if (nh->nh_label == NULL || nh->nh_label->num_labels == 0)
2269 return NULL;
2270
2271 nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate,
2272 nh->ifindex, nh->nh_label->num_labels,
2273 nh->nh_label->label, true);
2274
2275 return nhlfe;
2276 }
2277
2278 /*
2279 * Free an allocated NHLFE
2280 */
2281 void zebra_mpls_nhlfe_free(struct zebra_nhlfe *nhlfe)
2282 {
2283 /* Just a pass-through to the internal implementation */
2284 nhlfe_free(nhlfe);
2285 }
2286
2287 /*
2288 * Registration from a client for the label binding for a FEC. If a binding
2289 * already exists, it is informed to the client.
2290 * NOTE: If there is a manually configured label binding, that is used.
2291 * Otherwise, if a label index is specified, it means we have to allocate the
2292 * label from a locally configured label block (SRGB), if one exists and index
2293 * is acceptable. If no label index then just register the specified label.
2294 * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
2295 * by the calling function. Register requests with both will be rejected.
2296 */
2297 int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
2298 uint32_t label, uint32_t label_index,
2299 struct zserv *client)
2300 {
2301 struct route_table *table;
2302 struct zebra_fec *fec;
2303 bool new_client;
2304 bool label_change = false;
2305 uint32_t old_label;
2306 bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
2307 bool is_configured_fec = false; /* indicate statically configured FEC */
2308
2309 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2310 if (!table)
2311 return -1;
2312
2313 if (label != MPLS_INVALID_LABEL && have_label_index) {
2314 flog_err(
2315 EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
2316 "Rejecting FEC register for %pFX with both label %u and Label Index %u specified, client %s",
2317 p, label, label_index,
2318 zebra_route_string(client->proto));
2319 return -1;
2320 }
2321
2322 /* Locate FEC */
2323 fec = fec_find(table, p);
2324 if (!fec) {
2325 fec = fec_add(table, p, label, 0, label_index);
2326 if (!fec) {
2327 flog_err(
2328 EC_ZEBRA_FEC_ADD_FAILED,
2329 "Failed to add FEC %pFX upon register, client %s",
2330 p, zebra_route_string(client->proto));
2331 return -1;
2332 }
2333
2334 old_label = MPLS_INVALID_LABEL;
2335 new_client = true;
2336 } else {
2337 /* Check if the FEC has been statically defined in the config */
2338 is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
2339 /* Client may register same FEC with different label index. */
2340 new_client =
2341 (listnode_lookup(fec->client_list, client) == NULL);
2342 if (!new_client && fec->label_index == label_index
2343 && fec->label == label)
2344 /* Duplicate register */
2345 return 0;
2346
2347 /* Save current label, update the FEC */
2348 old_label = fec->label;
2349 fec->label_index = label_index;
2350 }
2351
2352 if (new_client)
2353 listnode_add(fec->client_list, client);
2354
2355 if (IS_ZEBRA_DEBUG_MPLS)
2356 zlog_debug("FEC %pFX label%s %u %s by client %s%s", p,
2357 have_label_index ? " index" : "",
2358 have_label_index ? label_index : label,
2359 new_client ? "registered" : "updated",
2360 zebra_route_string(client->proto),
2361 is_configured_fec
2362 ? ", but using statically configured label"
2363 : "");
2364
2365 /* If not a statically configured FEC, derive the local label
2366 * from label index or use the provided label
2367 */
2368 if (!is_configured_fec) {
2369 if (have_label_index)
2370 fec_derive_label_from_index(zvrf, fec);
2371 else
2372 fec->label = label;
2373
2374 /* If no label change, exit. */
2375 if (fec->label == old_label)
2376 return 0;
2377
2378 label_change = true;
2379 }
2380
2381 /* If new client or label change, update client and install or uninstall
2382 * label forwarding entry as needed.
2383 */
2384 /* Inform client of label, if needed. */
2385 if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
2386 if (IS_ZEBRA_DEBUG_MPLS)
2387 zlog_debug("Update client label %u", fec->label);
2388 fec_send(fec, client);
2389 }
2390
2391 if (new_client || label_change)
2392 return fec_change_update_lsp(zvrf, fec, old_label);
2393
2394 return 0;
2395 }
2396
2397 /*
2398 * Deregistration from a client for the label binding for a FEC. The FEC
2399 * itself is deleted if no other registered clients exist and there is no
2400 * label bound to the FEC.
2401 */
2402 int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
2403 struct zserv *client)
2404 {
2405 struct route_table *table;
2406 struct zebra_fec *fec;
2407
2408 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2409 if (!table)
2410 return -1;
2411
2412 fec = fec_find(table, p);
2413 if (!fec) {
2414 flog_err(EC_ZEBRA_FEC_RM_FAILED,
2415 "Failed to find FEC %pFX upon unregister, client %s",
2416 p, zebra_route_string(client->proto));
2417 return -1;
2418 }
2419
2420 listnode_delete(fec->client_list, client);
2421
2422 if (IS_ZEBRA_DEBUG_MPLS)
2423 zlog_debug("FEC %pFX unregistered by client %s", p,
2424 zebra_route_string(client->proto));
2425
2426 /* If not a configured entry, delete the FEC if no other clients. Before
2427 * deleting, see if any LSP needs to be uninstalled.
2428 */
2429 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2430 && list_isempty(fec->client_list)) {
2431 mpls_label_t old_label = fec->label;
2432 fec->label = MPLS_INVALID_LABEL; /* reset */
2433 fec_change_update_lsp(zvrf, fec, old_label);
2434 fec_del(fec);
2435 }
2436
2437 return 0;
2438 }
2439
2440 /*
2441 * Cleanup any FECs registered by this client.
2442 */
2443 static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
2444 {
2445 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
2446 struct route_node *rn;
2447 struct zebra_fec *fec;
2448 struct listnode *node;
2449 struct zserv *fec_client;
2450 int af;
2451
2452 for (af = AFI_IP; af < AFI_MAX; af++) {
2453 if (zvrf->fec_table[af] == NULL)
2454 continue;
2455
2456 for (rn = route_top(zvrf->fec_table[af]); rn;
2457 rn = route_next(rn)) {
2458 fec = rn->info;
2459 if (!fec || list_isempty(fec->client_list))
2460 continue;
2461
2462 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
2463 fec_client)) {
2464 if (fec_client == client) {
2465 listnode_delete(fec->client_list,
2466 fec_client);
2467 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2468 && list_isempty(fec->client_list))
2469 fec_del(fec);
2470 break;
2471 }
2472 }
2473 }
2474 }
2475
2476 return 0;
2477 }
2478
2479 struct lsp_uninstall_args {
2480 struct hash *lsp_table;
2481 enum lsp_types_t type;
2482 };
2483
2484 /*
2485 * Cleanup MPLS labels registered by this client.
2486 */
2487 static int zebra_mpls_cleanup_zclient_labels(struct zserv *client)
2488 {
2489 struct vrf *vrf;
2490 struct zebra_vrf *zvrf;
2491
2492 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
2493 struct lsp_uninstall_args args;
2494
2495 zvrf = vrf->info;
2496 if (!zvrf)
2497 continue;
2498
2499 /* Cleanup LSPs. */
2500 args.lsp_table = zvrf->lsp_table;
2501 args.type = lsp_type_from_re_type(client->proto);
2502 hash_iterate(zvrf->lsp_table, mpls_lsp_uninstall_all_type,
2503 &args);
2504
2505 /* Cleanup FTNs. */
2506 mpls_ftn_uninstall_all(zvrf, AFI_IP,
2507 lsp_type_from_re_type(client->proto));
2508 mpls_ftn_uninstall_all(zvrf, AFI_IP6,
2509 lsp_type_from_re_type(client->proto));
2510 }
2511
2512 return 0;
2513 }
2514
2515 /*
2516 * Return FEC (if any) to which this label is bound.
2517 * Note: Only works for per-prefix binding and when the label is not
2518 * implicit-null.
2519 * TODO: Currently walks entire table, can optimize later with another
2520 * hash..
2521 */
2522 struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
2523 mpls_label_t label)
2524 {
2525 struct route_node *rn;
2526 struct zebra_fec *fec;
2527 int af;
2528
2529 for (af = AFI_IP; af < AFI_MAX; af++) {
2530 if (zvrf->fec_table[af] == NULL)
2531 continue;
2532
2533 for (rn = route_top(zvrf->fec_table[af]); rn;
2534 rn = route_next(rn)) {
2535 if (!rn->info)
2536 continue;
2537 fec = rn->info;
2538 if (fec->label == label)
2539 return fec;
2540 }
2541 }
2542
2543 return NULL;
2544 }
2545
2546 /*
2547 * Inform if specified label is currently bound to a FEC or not.
2548 */
2549 int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
2550 {
2551 return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
2552 }
2553
2554 /*
2555 * Add static FEC to label binding. If there are clients registered for this
2556 * FEC, notify them. If there are labeled routes for this FEC, install the
2557 * label forwarding entry.
2558 */
2559 int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
2560 mpls_label_t in_label)
2561 {
2562 struct route_table *table;
2563 struct zebra_fec *fec;
2564 mpls_label_t old_label;
2565 int ret = 0;
2566
2567 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2568 if (!table)
2569 return -1;
2570
2571 /* Update existing FEC or create a new one. */
2572 fec = fec_find(table, p);
2573 if (!fec) {
2574 fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
2575 MPLS_INVALID_LABEL_INDEX);
2576 if (!fec) {
2577 flog_err(EC_ZEBRA_FEC_ADD_FAILED,
2578 "Failed to add FEC %pFX upon config", p);
2579 return -1;
2580 }
2581
2582 if (IS_ZEBRA_DEBUG_MPLS)
2583 zlog_debug("Add fec %pFX label %u", p, in_label);
2584 } else {
2585 fec->flags |= FEC_FLAG_CONFIGURED;
2586 if (fec->label == in_label)
2587 /* Duplicate config */
2588 return 0;
2589
2590 /* Label change, update clients. */
2591 old_label = fec->label;
2592 if (IS_ZEBRA_DEBUG_MPLS)
2593 zlog_debug("Update fec %pFX new label %u", p, in_label);
2594
2595 fec->label = in_label;
2596 fec_update_clients(fec);
2597
2598 /* Update label forwarding entries appropriately */
2599 ret = fec_change_update_lsp(zvrf, fec, old_label);
2600 }
2601
2602 return ret;
2603 }
2604
2605 /*
2606 * Remove static FEC to label binding. If there are no clients registered
2607 * for this FEC, delete the FEC; else notify clients
2608 * Note: Upon delete of static binding, if label index exists for this FEC,
2609 * client may need to be updated with derived label.
2610 */
2611 int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
2612 {
2613 struct route_table *table;
2614 struct zebra_fec *fec;
2615 mpls_label_t old_label;
2616
2617 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2618 if (!table)
2619 return -1;
2620
2621 fec = fec_find(table, p);
2622 if (!fec) {
2623 flog_err(EC_ZEBRA_FEC_RM_FAILED,
2624 "Failed to find FEC %pFX upon delete", p);
2625 return -1;
2626 }
2627
2628 if (IS_ZEBRA_DEBUG_MPLS) {
2629 zlog_debug("Delete fec %pFX label %u label index %u", p,
2630 fec->label, fec->label_index);
2631 }
2632
2633 old_label = fec->label;
2634 fec->flags &= ~FEC_FLAG_CONFIGURED;
2635 fec->label = MPLS_INVALID_LABEL;
2636
2637 /* If no client exists, just delete the FEC. */
2638 if (list_isempty(fec->client_list)) {
2639 fec_del(fec);
2640 return 0;
2641 }
2642
2643 /* Derive the local label (from label index) or reset it. */
2644 fec_derive_label_from_index(zvrf, fec);
2645
2646 /* If there is a label change, update clients. */
2647 if (fec->label == old_label)
2648 return 0;
2649 fec_update_clients(fec);
2650
2651 /* Update label forwarding entries appropriately */
2652 return fec_change_update_lsp(zvrf, fec, old_label);
2653 }
2654
2655 /*
2656 * Display MPLS FEC to label binding configuration (VTY command handler).
2657 */
2658 int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
2659 {
2660 struct route_node *rn;
2661 int af;
2662 struct zebra_fec *fec;
2663 int write = 0;
2664
2665 for (af = AFI_IP; af < AFI_MAX; af++) {
2666 if (zvrf->fec_table[af] == NULL)
2667 continue;
2668
2669 for (rn = route_top(zvrf->fec_table[af]); rn;
2670 rn = route_next(rn)) {
2671 if (!rn->info)
2672 continue;
2673
2674 char lstr[BUFSIZ];
2675 fec = rn->info;
2676
2677 if (!(fec->flags & FEC_FLAG_CONFIGURED))
2678 continue;
2679
2680 write = 1;
2681 vty_out(vty, "mpls label bind %pFX %s\n", &rn->p,
2682 label2str(fec->label, lstr, BUFSIZ));
2683 }
2684 }
2685
2686 return write;
2687 }
2688
2689 /*
2690 * Display MPLS FEC to label binding (VTY command handler).
2691 */
2692 void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
2693 {
2694 struct route_node *rn;
2695 int af;
2696
2697 for (af = AFI_IP; af < AFI_MAX; af++) {
2698 if (zvrf->fec_table[af] == NULL)
2699 continue;
2700
2701 for (rn = route_top(zvrf->fec_table[af]); rn;
2702 rn = route_next(rn)) {
2703 if (!rn->info)
2704 continue;
2705 fec_print(rn->info, vty);
2706 }
2707 }
2708 }
2709
2710 /*
2711 * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2712 */
2713 void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
2714 struct prefix *p)
2715 {
2716 struct route_table *table;
2717 struct route_node *rn;
2718
2719 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2720 if (!table)
2721 return;
2722
2723 apply_mask(p);
2724 rn = route_node_lookup(table, p);
2725 if (!rn)
2726 return;
2727
2728 route_unlock_node(rn);
2729 if (!rn->info)
2730 return;
2731
2732 fec_print(rn->info, vty);
2733 }
2734
2735 static void mpls_zebra_nhe_update(struct route_entry *re, afi_t afi,
2736 struct nhg_hash_entry *new_nhe)
2737 {
2738 struct nhg_hash_entry *nhe;
2739
2740 nhe = zebra_nhg_rib_find_nhe(new_nhe, afi);
2741
2742 route_entry_update_nhe(re, nhe);
2743 }
2744
2745 static bool ftn_update_nexthop(bool add_p, struct nexthop *nexthop,
2746 enum lsp_types_t type,
2747 const struct zapi_nexthop *znh)
2748 {
2749 if (add_p && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2750 nexthop_add_labels(nexthop, type, znh->label_num, znh->labels);
2751 else if (!add_p && nexthop->nh_label_type == type)
2752 nexthop_del_labels(nexthop);
2753 else
2754 return false;
2755
2756 return true;
2757 }
2758
2759 int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2760 struct prefix *prefix, uint8_t route_type,
2761 unsigned short route_instance)
2762 {
2763 struct route_table *table;
2764 struct route_node *rn;
2765 struct route_entry *re;
2766 struct nexthop *nexthop;
2767 struct nhg_hash_entry *new_nhe;
2768 afi_t afi = family2afi(prefix->family);
2769
2770 /* Lookup table. */
2771 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2772 if (!table)
2773 return -1;
2774
2775 /* Lookup existing route */
2776 rn = route_node_get(table, prefix);
2777 RNODE_FOREACH_RE (rn, re) {
2778 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2779 continue;
2780 if (re->type == route_type && re->instance == route_instance)
2781 break;
2782 }
2783 if (re == NULL)
2784 return -1;
2785
2786 /*
2787 * Nexthops are now shared by multiple routes, so we have to make
2788 * a local copy, modify the copy, then update the route.
2789 */
2790 new_nhe = zebra_nhe_copy(re->nhe, 0);
2791
2792 for (nexthop = new_nhe->nhg.nexthop; nexthop; nexthop = nexthop->next)
2793 nexthop_del_labels(nexthop);
2794
2795 /* Update backup routes/nexthops also, if present. */
2796 if (zebra_nhg_get_backup_nhg(new_nhe) != NULL) {
2797 for (nexthop = new_nhe->backup_info->nhe->nhg.nexthop; nexthop;
2798 nexthop = nexthop->next)
2799 nexthop_del_labels(nexthop);
2800 }
2801
2802 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2803 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
2804
2805 /* This will create (or ref) a new nhe, so we will discard the local
2806 * temporary nhe
2807 */
2808 mpls_zebra_nhe_update(re, afi, new_nhe);
2809
2810 zebra_nhg_free(new_nhe);
2811
2812 rib_queue_add(rn);
2813
2814 return 0;
2815 }
2816
2817 /*
2818 * Iterate through a list of nexthops, for a match for 'znh'. If found,
2819 * update its labels according to 'add_p', and return 'true' if successful.
2820 */
2821 static bool ftn_update_znh(bool add_p, enum lsp_types_t type,
2822 struct nexthop *head, const struct zapi_nexthop *znh)
2823 {
2824 bool found = false, success = false;
2825 struct nexthop *nexthop;
2826
2827 for (nexthop = head; nexthop; nexthop = nexthop->next) {
2828 switch (nexthop->type) {
2829 case NEXTHOP_TYPE_IPV4:
2830 case NEXTHOP_TYPE_IPV4_IFINDEX:
2831 if (znh->type != NEXTHOP_TYPE_IPV4
2832 && znh->type != NEXTHOP_TYPE_IPV4_IFINDEX)
2833 continue;
2834 if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4,
2835 &znh->gate.ipv4))
2836 continue;
2837 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
2838 && nexthop->ifindex != znh->ifindex)
2839 continue;
2840
2841 found = true;
2842
2843 if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2844 break;
2845
2846 success = true;
2847 break;
2848 case NEXTHOP_TYPE_IPV6:
2849 case NEXTHOP_TYPE_IPV6_IFINDEX:
2850 if (znh->type != NEXTHOP_TYPE_IPV6
2851 && znh->type != NEXTHOP_TYPE_IPV6_IFINDEX)
2852 continue;
2853 if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6,
2854 &znh->gate.ipv6))
2855 continue;
2856 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
2857 && nexthop->ifindex != znh->ifindex)
2858 continue;
2859
2860 found = true;
2861
2862 if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2863 break;
2864 success = true;
2865 break;
2866 case NEXTHOP_TYPE_IFINDEX:
2867 if (znh->type != NEXTHOP_TYPE_IFINDEX)
2868 continue;
2869 if (nexthop->ifindex != znh->ifindex)
2870 continue;
2871
2872 found = true;
2873
2874 if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2875 break;
2876 success = true;
2877 break;
2878 case NEXTHOP_TYPE_BLACKHOLE:
2879 /* Not valid */
2880 continue;
2881 }
2882
2883 if (found)
2884 break;
2885 }
2886
2887 return success;
2888 }
2889
2890 /*
2891 * Install/uninstall LSP and (optionally) FEC-To-NHLFE (FTN) bindings,
2892 * using zapi message info.
2893 * There are several changes that need to be made, in several zebra
2894 * data structures, so we want to do all the work required at once.
2895 */
2896 int mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
2897 const struct zapi_labels *zl)
2898 {
2899 int i, counter, ret = 0;
2900 char buf[NEXTHOP_STRLEN];
2901 const struct zapi_nexthop *znh;
2902 struct route_table *table;
2903 struct route_node *rn = NULL;
2904 struct route_entry *re = NULL;
2905 struct nhg_hash_entry *new_nhe = NULL;
2906 bool found;
2907 afi_t afi = AFI_IP;
2908 const struct prefix *prefix = NULL;
2909 struct hash *lsp_table;
2910 struct zebra_ile tmp_ile;
2911 struct zebra_lsp *lsp = NULL;
2912
2913 /* Prep LSP for add case */
2914 if (add_p) {
2915 /* Lookup table. */
2916 lsp_table = zvrf->lsp_table;
2917 if (!lsp_table)
2918 return -1;
2919
2920 /* Find or create LSP object */
2921 tmp_ile.in_label = zl->local_label;
2922 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2923 if (!lsp)
2924 return -1;
2925 }
2926
2927 /* Prep for route/FEC update if requested */
2928 if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
2929 prefix = &zl->route.prefix;
2930
2931 afi = family2afi(prefix->family);
2932
2933 /* Lookup table. */
2934 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2935 if (table) {
2936 /* Lookup existing route */
2937 rn = route_node_get(table, prefix);
2938 RNODE_FOREACH_RE(rn, re) {
2939 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2940 continue;
2941 if (re->type == zl->route.type &&
2942 re->instance == zl->route.instance)
2943 break;
2944 }
2945 }
2946
2947 if (re) {
2948 /*
2949 * Copy over current nexthops into a temporary group.
2950 * We can't just change the values here since the nhgs
2951 * are shared and if the labels change, we'll need
2952 * to find or create a new nhg. We need to create
2953 * a whole temporary group, make changes to it,
2954 * then attach that to the route.
2955 */
2956 new_nhe = zebra_nhe_copy(re->nhe, 0);
2957
2958 } else {
2959 /*
2960 * The old version of the zapi code
2961 * attempted to manage LSPs before trying to
2962 * find a route/FEC, so we'll continue that way.
2963 */
2964 if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS)
2965 zlog_debug(
2966 "%s: FTN update requested: no route for prefix %pFX",
2967 __func__, prefix);
2968 }
2969 }
2970
2971 /*
2972 * Use info from the zapi nexthops to add/replace/remove LSP/FECs
2973 */
2974
2975 counter = 0;
2976 for (i = 0; i < zl->nexthop_num; i++) {
2977
2978 znh = &zl->nexthops[i];
2979
2980 /* Attempt LSP update */
2981 if (add_p)
2982 ret = lsp_znh_install(lsp, zl->type, znh);
2983 else
2984 ret = mpls_lsp_uninstall(zvrf, zl->type,
2985 zl->local_label, znh->type,
2986 &znh->gate, znh->ifindex,
2987 false);
2988 if (ret < 0) {
2989 if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS) {
2990 zapi_nexthop2str(znh, buf, sizeof(buf));
2991 zlog_debug("%s: Unable to %sinstall LSP: label %u, znh %s",
2992 __func__, (add_p ? "" : "un"),
2993 zl->local_label, buf);
2994 }
2995 continue;
2996 }
2997
2998 /* Attempt route/FEC update if requested */
2999 if (re == NULL)
3000 continue;
3001
3002 /* Search the route's nexthops for a match, and update it. */
3003 found = ftn_update_znh(add_p, zl->type, new_nhe->nhg.nexthop,
3004 znh);
3005 if (found) {
3006 counter++;
3007 } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
3008 zapi_nexthop2str(znh, buf, sizeof(buf));
3009 zlog_debug(
3010 "%s: Unable to update FEC: prefix %pFX, label %u, znh %s",
3011 __func__, prefix, zl->local_label, buf);
3012 }
3013 }
3014
3015 /*
3016 * Process backup LSPs/nexthop entries also. We associate backup
3017 * LSP info with backup nexthops.
3018 */
3019 if (!CHECK_FLAG(zl->message, ZAPI_LABELS_HAS_BACKUPS))
3020 goto znh_done;
3021
3022 for (i = 0; i < zl->backup_nexthop_num; i++) {
3023
3024 znh = &zl->backup_nexthops[i];
3025
3026 if (add_p)
3027 ret = lsp_backup_znh_install(lsp, zl->type, znh);
3028 else
3029 ret = mpls_lsp_uninstall(zvrf, zl->type,
3030 zl->local_label,
3031 znh->type, &znh->gate,
3032 znh->ifindex, true);
3033
3034 if (ret < 0) {
3035 if (IS_ZEBRA_DEBUG_RECV ||
3036 IS_ZEBRA_DEBUG_MPLS) {
3037 zapi_nexthop2str(znh, buf, sizeof(buf));
3038 zlog_debug("%s: Unable to %sinstall backup LSP: label %u, znh %s",
3039 __func__, (add_p ? "" : "un"),
3040 zl->local_label, buf);
3041 }
3042 continue;
3043 }
3044
3045 /* Attempt backup nexthop/FEC update if requested */
3046 if (re == NULL || zebra_nhg_get_backup_nhg(new_nhe) == NULL)
3047 continue;
3048
3049 /* Search the route's backup nexthops for a match
3050 * and update it.
3051 */
3052 found = ftn_update_znh(add_p, zl->type,
3053 new_nhe->backup_info->nhe->nhg.nexthop,
3054 znh);
3055 if (found) {
3056 counter++;
3057 } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
3058 zapi_nexthop2str(znh, buf, sizeof(buf));
3059 zlog_debug(
3060 "%s: Unable to update backup FEC: prefix %pFX, label %u, znh %s",
3061 __func__, prefix, zl->local_label, buf);
3062 }
3063 }
3064
3065 znh_done:
3066
3067 /*
3068 * If we made changes, update the route, and schedule it
3069 * for rib processing
3070 */
3071 if (re != NULL && counter > 0) {
3072 assert(rn != NULL);
3073
3074 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
3075 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
3076
3077 mpls_zebra_nhe_update(re, afi, new_nhe);
3078
3079 rib_queue_add(rn);
3080 }
3081
3082 if (new_nhe)
3083 zebra_nhg_free(new_nhe);
3084
3085 return ret;
3086 }
3087
3088 /*
3089 * Install/update a NHLFE for an LSP in the forwarding table. This may be
3090 * a new LSP entry or a new NHLFE for an existing in-label or an update of
3091 * the out-label for an existing NHLFE (update case).
3092 */
3093 static struct zebra_nhlfe *
3094 lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type,
3095 uint8_t num_out_labels, const mpls_label_t *out_labels,
3096 enum nexthop_types_t gtype, const union g_addr *gate,
3097 ifindex_t ifindex, bool is_backup)
3098 {
3099 struct zebra_nhlfe *nhlfe;
3100 char buf[MPLS_LABEL_STRLEN];
3101 const char *backup_str;
3102
3103 if (is_backup) {
3104 nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
3105 gate, ifindex);
3106 backup_str = "backup ";
3107 } else {
3108 nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
3109 ifindex);
3110 backup_str = "";
3111 }
3112
3113 if (nhlfe) {
3114 struct nexthop *nh = nhlfe->nexthop;
3115
3116 assert(nh);
3117 assert(nh->nh_label);
3118
3119 /* Clear deleted flag (in case it was set) */
3120 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
3121 if (nh->nh_label->num_labels == num_out_labels
3122 && !memcmp(nh->nh_label->label, out_labels,
3123 sizeof(mpls_label_t) * num_out_labels))
3124 /* No change */
3125 return nhlfe;
3126
3127 if (IS_ZEBRA_DEBUG_MPLS) {
3128 char buf2[MPLS_LABEL_STRLEN];
3129 char buf3[MPLS_LABEL_STRLEN];
3130
3131 nhlfe2str(nhlfe, buf, sizeof(buf));
3132 mpls_label2str(num_out_labels, out_labels, buf2,
3133 sizeof(buf2), 0);
3134 mpls_label2str(nh->nh_label->num_labels,
3135 nh->nh_label->label, buf3, sizeof(buf3),
3136 0);
3137
3138 zlog_debug("LSP in-label %u type %d %snexthop %s out-label(s) changed to %s (old %s)",
3139 lsp->ile.in_label, type, backup_str, buf,
3140 buf2, buf3);
3141 }
3142
3143 /* Update out label(s), trigger processing. */
3144 if (nh->nh_label->num_labels == num_out_labels)
3145 memcpy(nh->nh_label->label, out_labels,
3146 sizeof(mpls_label_t) * num_out_labels);
3147 else {
3148 nexthop_del_labels(nh);
3149 nexthop_add_labels(nh, type, num_out_labels,
3150 out_labels);
3151 }
3152 } else {
3153 /* Add LSP entry to this nexthop */
3154 nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex,
3155 num_out_labels, out_labels, is_backup);
3156 if (!nhlfe)
3157 return NULL;
3158
3159 if (IS_ZEBRA_DEBUG_MPLS) {
3160 char buf2[MPLS_LABEL_STRLEN];
3161
3162 nhlfe2str(nhlfe, buf, sizeof(buf));
3163 mpls_label2str(num_out_labels, out_labels, buf2,
3164 sizeof(buf2), 0);
3165
3166 zlog_debug("Add LSP in-label %u type %d %snexthop %s out-label(s) %s",
3167 lsp->ile.in_label, type, backup_str, buf,
3168 buf2);
3169 }
3170
3171 lsp->addr_family = NHLFE_FAMILY(nhlfe);
3172 }
3173
3174 /* Mark NHLFE, queue LSP for processing. */
3175 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
3176
3177 return nhlfe;
3178 }
3179
3180 /*
3181 * Install an LSP and forwarding entry; used primarily
3182 * from vrf zapi message processing.
3183 */
3184 int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
3185 mpls_label_t in_label, uint8_t num_out_labels,
3186 const mpls_label_t *out_labels, enum nexthop_types_t gtype,
3187 const union g_addr *gate, ifindex_t ifindex)
3188 {
3189 struct hash *lsp_table;
3190 struct zebra_ile tmp_ile;
3191 struct zebra_lsp *lsp;
3192 struct zebra_nhlfe *nhlfe;
3193
3194 /* Lookup table. */
3195 lsp_table = zvrf->lsp_table;
3196 if (!lsp_table)
3197 return -1;
3198
3199 /* Find or create LSP object */
3200 tmp_ile.in_label = in_label;
3201 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
3202 if (!lsp)
3203 return -1;
3204
3205 nhlfe = lsp_add_nhlfe(lsp, type, num_out_labels, out_labels, gtype,
3206 gate, ifindex, false /*backup*/);
3207 if (nhlfe == NULL)
3208 return -1;
3209
3210 /* Queue LSP for processing. */
3211 if (lsp_processq_add(lsp))
3212 return -1;
3213
3214 return 0;
3215 }
3216
3217 /*
3218 * Install or replace NHLFE, using info from zapi nexthop
3219 */
3220 static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
3221 const struct zapi_nexthop *znh)
3222 {
3223 struct zebra_nhlfe *nhlfe;
3224
3225 nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels,
3226 znh->type, &znh->gate, znh->ifindex,
3227 false /*backup*/);
3228 if (nhlfe == NULL)
3229 return -1;
3230
3231 /* Update backup info if present */
3232 if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
3233 if (znh->backup_num > NEXTHOP_MAX_BACKUPS) {
3234 nhlfe_del(nhlfe);
3235 return -1;
3236 }
3237
3238 nhlfe->nexthop->backup_num = znh->backup_num;
3239 memcpy(nhlfe->nexthop->backup_idx, znh->backup_idx,
3240 znh->backup_num);
3241 SET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
3242 } else {
3243 /* Ensure there's no stale backup info */
3244 UNSET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
3245 nhlfe->nexthop->backup_num = 0;
3246 }
3247
3248 /* Queue LSP for processing. */
3249 if (lsp_processq_add(lsp))
3250 return -1;
3251
3252 return 0;
3253 }
3254
3255 /*
3256 * Install/update backup NHLFE for an LSP, using info from a zapi message.
3257 */
3258 static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
3259 const struct zapi_nexthop *znh)
3260 {
3261 struct zebra_nhlfe *nhlfe;
3262
3263 nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num,
3264 znh->labels, znh->type, &znh->gate,
3265 znh->ifindex, true /*backup*/);
3266 if (nhlfe == NULL) {
3267 if (IS_ZEBRA_DEBUG_MPLS)
3268 zlog_debug("%s: unable to add backup nhlfe, label: %u",
3269 __func__, lsp->ile.in_label);
3270 return -1;
3271 }
3272
3273 /* Queue LSP for processing. */
3274 if (lsp_processq_add(lsp))
3275 return -1;
3276
3277 return 0;
3278 }
3279
3280 struct zebra_lsp *mpls_lsp_find(struct zebra_vrf *zvrf, mpls_label_t in_label)
3281 {
3282 struct hash *lsp_table;
3283 struct zebra_ile tmp_ile;
3284
3285 /* Lookup table. */
3286 lsp_table = zvrf->lsp_table;
3287 if (!lsp_table)
3288 return NULL;
3289
3290 /* If entry is not present, exit. */
3291 tmp_ile.in_label = in_label;
3292 return hash_lookup(lsp_table, &tmp_ile);
3293 }
3294
3295 /*
3296 * Uninstall a particular NHLFE in the forwarding table. If this is
3297 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
3298 */
3299 int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
3300 mpls_label_t in_label, enum nexthop_types_t gtype,
3301 const union g_addr *gate, ifindex_t ifindex,
3302 bool backup_p)
3303 {
3304 struct hash *lsp_table;
3305 struct zebra_ile tmp_ile;
3306 struct zebra_lsp *lsp;
3307 struct zebra_nhlfe *nhlfe;
3308 char buf[NEXTHOP_STRLEN];
3309 bool schedule_lsp = false;
3310
3311 /* Lookup table. */
3312 lsp_table = zvrf->lsp_table;
3313 if (!lsp_table)
3314 return -1;
3315
3316 /* If entry is not present, exit. */
3317 tmp_ile.in_label = in_label;
3318 lsp = hash_lookup(lsp_table, &tmp_ile);
3319 if (!lsp)
3320 return 0;
3321
3322 if (backup_p)
3323 nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
3324 gate, ifindex);
3325 else
3326 nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
3327 ifindex);
3328 if (!nhlfe)
3329 return 0;
3330
3331 if (IS_ZEBRA_DEBUG_MPLS) {
3332 nhlfe2str(nhlfe, buf, sizeof(buf));
3333 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
3334 in_label, type, buf, nhlfe->flags);
3335 }
3336
3337 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ||
3338 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
3339 schedule_lsp = true;
3340
3341 /* Mark NHLFE for delete or directly delete, as appropriate. */
3342 if (schedule_lsp) {
3343 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
3344 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
3345
3346 if (IS_ZEBRA_DEBUG_MPLS)
3347 zlog_debug("Schedule LSP in-label %u flags 0x%x",
3348 lsp->ile.in_label, lsp->flags);
3349 if (lsp_processq_add(lsp))
3350 return -1;
3351 } else {
3352 nhlfe_del(nhlfe);
3353
3354 /* Free LSP entry if no other NHLFEs and not scheduled. */
3355 lsp_check_free(lsp_table, &lsp);
3356 }
3357 return 0;
3358 }
3359
3360 int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
3361 mpls_label_t in_label)
3362 {
3363 struct hash *lsp_table;
3364 struct zebra_ile tmp_ile;
3365 struct zebra_lsp *lsp;
3366
3367 /* Lookup table. */
3368 lsp_table = zvrf->lsp_table;
3369 if (!lsp_table)
3370 return -1;
3371
3372 /* If entry is not present, exit. */
3373 tmp_ile.in_label = in_label;
3374 lsp = hash_lookup(lsp_table, &tmp_ile);
3375 if (!lsp)
3376 return 0;
3377
3378 return mpls_lsp_uninstall_all(lsp_table, lsp, type);
3379 }
3380
3381 /*
3382 * Uninstall all NHLFEs for a particular LSP forwarding entry.
3383 * If no other NHLFEs exist, the entry would be deleted.
3384 */
3385 static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt)
3386 {
3387 struct lsp_uninstall_args *args = ctxt;
3388 struct zebra_lsp *lsp;
3389 struct hash *lsp_table;
3390
3391 lsp = (struct zebra_lsp *)bucket->data;
3392 if (nhlfe_list_first(&lsp->nhlfe_list) == NULL)
3393 return;
3394
3395 lsp_table = args->lsp_table;
3396 if (!lsp_table)
3397 return;
3398
3399 mpls_lsp_uninstall_all(lsp_table, lsp, args->type);
3400 }
3401
3402 /*
3403 * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and
3404 * LSP type.
3405 */
3406 static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
3407 int afi, enum lsp_types_t lsp_type)
3408 {
3409 struct route_table *table;
3410 struct route_node *rn;
3411 struct route_entry *re;
3412 struct nexthop *nexthop;
3413 struct nexthop_group *nhg;
3414 bool update;
3415
3416 /* Process routes of interested address-families. */
3417 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
3418 if (!table)
3419 return;
3420
3421 for (rn = route_top(table); rn; rn = route_next(rn)) {
3422 update = false;
3423
3424 RNODE_FOREACH_RE (rn, re) {
3425 struct nhg_hash_entry *new_nhe;
3426
3427 new_nhe = zebra_nhe_copy(re->nhe, 0);
3428
3429 nhg = &new_nhe->nhg;
3430 for (nexthop = nhg->nexthop; nexthop;
3431 nexthop = nexthop->next) {
3432 if (nexthop->nh_label_type != lsp_type)
3433 continue;
3434
3435 nexthop_del_labels(nexthop);
3436 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
3437 SET_FLAG(re->status,
3438 ROUTE_ENTRY_LABELS_CHANGED);
3439 update = true;
3440 }
3441
3442 /* Check for backup info and update that also */
3443 nhg = zebra_nhg_get_backup_nhg(new_nhe);
3444 if (nhg != NULL) {
3445 for (nexthop = nhg->nexthop; nexthop;
3446 nexthop = nexthop->next) {
3447 if (nexthop->nh_label_type != lsp_type)
3448 continue;
3449
3450 nexthop_del_labels(nexthop);
3451 SET_FLAG(re->status,
3452 ROUTE_ENTRY_CHANGED);
3453 SET_FLAG(re->status,
3454 ROUTE_ENTRY_LABELS_CHANGED);
3455 update = true;
3456 }
3457 }
3458
3459 if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
3460 mpls_zebra_nhe_update(re, afi, new_nhe);
3461
3462 zebra_nhg_free(new_nhe);
3463 }
3464
3465 if (update)
3466 rib_queue_add(rn);
3467 }
3468 }
3469
3470 #if defined(HAVE_CUMULUS)
3471 /*
3472 * Check that the label values used in LSP creation are consistent. The
3473 * main criteria is that if there is ECMP, the label operation must still
3474 * be consistent - i.e., all paths either do a swap or do PHP. This is due
3475 * to current HW restrictions.
3476 */
3477 int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
3478 mpls_label_t in_label,
3479 mpls_label_t out_label,
3480 enum nexthop_types_t gtype,
3481 union g_addr *gate, ifindex_t ifindex)
3482 {
3483 struct hash *slsp_table;
3484 struct zebra_ile tmp_ile;
3485 struct zebra_lsp *lsp;
3486 struct zebra_nhlfe *nhlfe;
3487 const struct nexthop *nh;
3488
3489 /* Lookup table. */
3490 slsp_table = zvrf->slsp_table;
3491 if (!slsp_table)
3492 return 0;
3493
3494 /* If entry is not present, exit. */
3495 tmp_ile.in_label = in_label;
3496 lsp = hash_lookup(slsp_table, &tmp_ile);
3497 if (!lsp)
3498 return 1;
3499
3500 nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
3501 gtype, gate, ifindex);
3502 if (nhlfe) {
3503 nh = nhlfe->nexthop;
3504
3505 if (nh == NULL || nh->nh_label == NULL)
3506 return 0;
3507
3508 if (nh->nh_label->label[0] == out_label)
3509 return 1;
3510
3511 /* If not only NHLFE, cannot allow label change. */
3512 if (nhlfe != nhlfe_list_first(&lsp->nhlfe_list) ||
3513 nhlfe_list_next(&lsp->nhlfe_list, nhlfe) != NULL)
3514 return 0;
3515 } else {
3516 /* If other NHLFEs exist, label operation must match. */
3517 nhlfe = nhlfe_list_first(&lsp->nhlfe_list);
3518 if (nhlfe != NULL) {
3519 int cur_op, new_op;
3520
3521 nh = nhlfe->nexthop;
3522
3523 if (nh == NULL || nh->nh_label == NULL)
3524 return 0;
3525
3526 cur_op = (nh->nh_label->label[0] ==
3527 MPLS_LABEL_IMPLICIT_NULL);
3528 new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
3529 if (cur_op != new_op)
3530 return 0;
3531 }
3532 }
3533
3534 /* Label values are good. */
3535 return 1;
3536 }
3537 #endif /* HAVE_CUMULUS */
3538
3539 /*
3540 * Add static LSP entry. This may be the first entry for this incoming label
3541 * or an additional nexthop; an existing entry may also have outgoing label
3542 * changed.
3543 * Note: The label operation (swap or PHP) is common for the LSP entry (all
3544 * NHLFEs).
3545 */
3546 int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
3547 mpls_label_t out_label,
3548 enum nexthop_types_t gtype, union g_addr *gate,
3549 ifindex_t ifindex)
3550 {
3551 struct hash *slsp_table;
3552 struct zebra_ile tmp_ile;
3553 struct zebra_lsp *lsp;
3554 struct zebra_nhlfe *nhlfe;
3555 char buf[BUFSIZ];
3556
3557 /* Lookup table. */
3558 slsp_table = zvrf->slsp_table;
3559 if (!slsp_table)
3560 return -1;
3561
3562 /* Find or create LSP. */
3563 tmp_ile.in_label = in_label;
3564 lsp = hash_get(slsp_table, &tmp_ile, lsp_alloc);
3565 if (!lsp)
3566 return -1;
3567
3568 nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC, gtype, gate,
3569 ifindex);
3570 if (nhlfe) {
3571 struct nexthop *nh = nhlfe->nexthop;
3572
3573 assert(nh);
3574 assert(nh->nh_label);
3575
3576 /* Compare existing nexthop */
3577 if (nh->nh_label->num_labels == 1 &&
3578 nh->nh_label->label[0] == out_label)
3579 /* No change */
3580 return 0;
3581
3582 if (IS_ZEBRA_DEBUG_MPLS) {
3583 nhlfe2str(nhlfe, buf, sizeof(buf));
3584 zlog_debug(
3585 "Upd static LSP in-label %u nexthop %s out-label %u (old %u)",
3586 in_label, buf, out_label,
3587 nh->nh_label->label[0]);
3588 }
3589 if (nh->nh_label->num_labels == 1)
3590 nh->nh_label->label[0] = out_label;
3591 else {
3592 nexthop_del_labels(nh);
3593 nexthop_add_labels(nh, ZEBRA_LSP_STATIC, 1, &out_label);
3594 }
3595
3596 } else {
3597 /* Add static LSP entry to this nexthop */
3598 nhlfe = nhlfe_add(lsp, ZEBRA_LSP_STATIC, gtype, gate,
3599 ifindex, 1, &out_label, false /*backup*/);
3600 if (!nhlfe)
3601 return -1;
3602
3603 if (IS_ZEBRA_DEBUG_MPLS) {
3604 nhlfe2str(nhlfe, buf, sizeof(buf));
3605 zlog_debug(
3606 "Add static LSP in-label %u nexthop %s out-label %u",
3607 in_label, buf, out_label);
3608 }
3609 }
3610
3611 /* (Re)Install LSP in the main table. */
3612 if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, 1, &out_label,
3613 gtype, gate, ifindex))
3614 return -1;
3615
3616 return 0;
3617 }
3618
3619 /*
3620 * Delete static LSP entry. This may be the delete of one particular
3621 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
3622 * all NHLFEs).
3623 * NOTE: Delete of the only NHLFE will also end up deleting the entire
3624 * LSP configuration.
3625 */
3626 int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
3627 enum nexthop_types_t gtype, union g_addr *gate,
3628 ifindex_t ifindex)
3629 {
3630 struct hash *slsp_table;
3631 struct zebra_ile tmp_ile;
3632 struct zebra_lsp *lsp;
3633 struct zebra_nhlfe *nhlfe;
3634
3635 /* Lookup table. */
3636 slsp_table = zvrf->slsp_table;
3637 if (!slsp_table)
3638 return -1;
3639
3640 /* If entry is not present, exit. */
3641 tmp_ile.in_label = in_label;
3642 lsp = hash_lookup(slsp_table, &tmp_ile);
3643 if (!lsp)
3644 return 0;
3645
3646 /* Is it delete of entire LSP or a specific NHLFE? */
3647 if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
3648 if (IS_ZEBRA_DEBUG_MPLS)
3649 zlog_debug("Del static LSP in-label %u", in_label);
3650
3651 /* Uninstall entire LSP from the main table. */
3652 mpls_static_lsp_uninstall_all(zvrf, in_label);
3653
3654 /* Delete all static NHLFEs */
3655 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3656 nhlfe_del(nhlfe);
3657 }
3658 } else {
3659 /* Find specific NHLFE, exit if not found. */
3660 nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
3661 gtype, gate, ifindex);
3662 if (!nhlfe)
3663 return 0;
3664
3665 if (IS_ZEBRA_DEBUG_MPLS) {
3666 char buf[BUFSIZ];
3667 nhlfe2str(nhlfe, buf, sizeof(buf));
3668 zlog_debug("Del static LSP in-label %u nexthop %s",
3669 in_label, buf);
3670 }
3671
3672 /* Uninstall LSP from the main table. */
3673 mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
3674 gate, ifindex, false);
3675
3676 /* Delete static LSP NHLFE */
3677 nhlfe_del(nhlfe);
3678 }
3679
3680 /* Remove entire static LSP entry if no NHLFE - valid in either case
3681 * above.
3682 */
3683 if (nhlfe_list_first(&lsp->nhlfe_list) == NULL) {
3684 lsp = hash_release(slsp_table, &tmp_ile);
3685 XFREE(MTYPE_LSP, lsp);
3686 }
3687
3688 return 0;
3689 }
3690
3691 /*
3692 * Schedule all MPLS label forwarding entries for processing.
3693 * Called upon changes that may affect one or more of them such as
3694 * interface or nexthop state changes.
3695 */
3696 void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
3697 {
3698 if (!zvrf)
3699 return;
3700 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
3701 }
3702
3703 /*
3704 * Display MPLS label forwarding table for a specific LSP
3705 * (VTY command handler).
3706 */
3707 void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
3708 mpls_label_t label, bool use_json)
3709 {
3710 struct hash *lsp_table;
3711 struct zebra_lsp *lsp;
3712 struct zebra_ile tmp_ile;
3713 json_object *json = NULL;
3714
3715 /* Lookup table. */
3716 lsp_table = zvrf->lsp_table;
3717 if (!lsp_table)
3718 return;
3719
3720 /* If entry is not present, exit. */
3721 tmp_ile.in_label = label;
3722 lsp = hash_lookup(lsp_table, &tmp_ile);
3723 if (!lsp)
3724 return;
3725
3726 if (use_json) {
3727 json = lsp_json(lsp);
3728 vty_json(vty, json);
3729 } else
3730 lsp_print(vty, lsp);
3731 }
3732
3733 /*
3734 * Display MPLS label forwarding table (VTY command handler).
3735 */
3736 void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
3737 bool use_json)
3738 {
3739 char buf[BUFSIZ];
3740 json_object *json = NULL;
3741 struct zebra_lsp *lsp = NULL;
3742 struct zebra_nhlfe *nhlfe = NULL;
3743 struct listnode *node = NULL;
3744 struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
3745
3746 if (use_json) {
3747 json = json_object_new_object();
3748
3749 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
3750 json_object_object_add(
3751 json, label2str(lsp->ile.in_label, buf,
3752 sizeof(buf)),
3753 lsp_json(lsp));
3754
3755 vty_json(vty, json);
3756 } else {
3757 struct ttable *tt;
3758
3759 /* Prepare table. */
3760 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3761 ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label");
3762 tt->style.cell.rpad = 2;
3763 tt->style.corner = '+';
3764 ttable_restyle(tt);
3765 ttable_rowseps(tt, 0, BOTTOM, true, '-');
3766
3767 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
3768 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3769 struct nexthop *nexthop;
3770 const char *out_label_str;
3771 char nh_buf[NEXTHOP_STRLEN];
3772
3773 nexthop = nhlfe->nexthop;
3774
3775 switch (nexthop->type) {
3776 case NEXTHOP_TYPE_IFINDEX: {
3777 struct zebra_ns *zns;
3778 struct interface *ifp;
3779
3780 zns = zebra_ns_lookup(NS_DEFAULT);
3781 ifp = if_lookup_by_index_per_ns(
3782 zns, nexthop->ifindex);
3783 snprintf(nh_buf, sizeof(nh_buf), "%s",
3784 ifp ? ifp->name : "Null");
3785 break;
3786 }
3787 case NEXTHOP_TYPE_IPV4:
3788 case NEXTHOP_TYPE_IPV4_IFINDEX:
3789 inet_ntop(AF_INET, &nexthop->gate.ipv4,
3790 nh_buf, sizeof(nh_buf));
3791 break;
3792 case NEXTHOP_TYPE_IPV6:
3793 case NEXTHOP_TYPE_IPV6_IFINDEX:
3794 inet_ntop(AF_INET6, &nexthop->gate.ipv6,
3795 nh_buf, sizeof(nh_buf));
3796 break;
3797 case NEXTHOP_TYPE_BLACKHOLE:
3798 break;
3799 }
3800
3801 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
3802 out_label_str = mpls_label2str(
3803 nexthop->nh_label->num_labels,
3804 &nexthop->nh_label->label[0],
3805 buf, sizeof(buf), 1);
3806 else
3807 out_label_str = "-";
3808
3809 ttable_add_row(tt, "%u|%s|%s|%s",
3810 lsp->ile.in_label,
3811 nhlfe_type2str(nhlfe->type),
3812 nh_buf, out_label_str);
3813 }
3814 }
3815
3816 /* Dump the generated table. */
3817 if (tt->nrows > 1) {
3818 char *table = ttable_dump(tt, "\n");
3819 vty_out(vty, "%s\n", table);
3820 XFREE(MTYPE_TMP, table);
3821 }
3822 ttable_del(tt);
3823 }
3824
3825 list_delete(&lsp_list);
3826 }
3827
3828 /*
3829 * Create printable string for static LSP configuration.
3830 */
3831 static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
3832 int size)
3833 {
3834 const struct nexthop *nh;
3835
3836 nh = nhlfe->nexthop;
3837
3838 buf[0] = '\0';
3839 switch (nh->type) {
3840 case NEXTHOP_TYPE_IPV4:
3841 case NEXTHOP_TYPE_IPV4_IFINDEX:
3842 inet_ntop(AF_INET, &nh->gate.ipv4, buf, size);
3843 if (nh->ifindex)
3844 strlcat(buf, ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3845 size);
3846 break;
3847 case NEXTHOP_TYPE_IPV6:
3848 case NEXTHOP_TYPE_IPV6_IFINDEX:
3849 inet_ntop(AF_INET6, &nh->gate.ipv6, buf, size);
3850 if (nh->ifindex)
3851 strlcat(buf,
3852 ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3853 size);
3854 break;
3855 case NEXTHOP_TYPE_IFINDEX:
3856 if (nh->ifindex)
3857 strlcat(buf,
3858 ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3859 size);
3860 break;
3861 case NEXTHOP_TYPE_BLACKHOLE:
3862 break;
3863 }
3864
3865 return buf;
3866 }
3867
3868 /*
3869 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
3870 */
3871 int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
3872 {
3873 struct zebra_lsp *lsp;
3874 struct zebra_nhlfe *nhlfe;
3875 struct nexthop *nh;
3876 struct listnode *node;
3877 struct list *slsp_list =
3878 hash_get_sorted_list(zvrf->slsp_table, lsp_cmp);
3879
3880 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, lsp)) {
3881 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3882 char buf[BUFSIZ];
3883 char lstr[30];
3884
3885 nh = nhlfe->nexthop;
3886 if (nh == NULL || nh->nh_label == NULL)
3887 continue;
3888
3889 nhlfe_config_str(nhlfe, buf, sizeof(buf));
3890
3891 switch (nh->nh_label->label[0]) {
3892 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
3893 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
3894 strlcpy(lstr, "explicit-null", sizeof(lstr));
3895 break;
3896 case MPLS_LABEL_IMPLICIT_NULL:
3897 strlcpy(lstr, "implicit-null", sizeof(lstr));
3898 break;
3899 default:
3900 snprintf(lstr, sizeof(lstr), "%u",
3901 nh->nh_label->label[0]);
3902 break;
3903 }
3904
3905 vty_out(vty, "mpls lsp %u %s %s\n", lsp->ile.in_label,
3906 buf, lstr);
3907 }
3908 }
3909
3910 list_delete(&slsp_list);
3911 return (zvrf->slsp_table->count ? 1 : 0);
3912 }
3913
3914 /*
3915 * Add/update global label block.
3916 */
3917 int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
3918 uint32_t end_label)
3919 {
3920 zvrf->mpls_srgb.start_label = start_label;
3921 zvrf->mpls_srgb.end_label = end_label;
3922
3923 /* Evaluate registered FECs to see if any get a label or not. */
3924 fec_evaluate(zvrf);
3925 return 0;
3926 }
3927
3928 /*
3929 * Delete global label block.
3930 */
3931 int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
3932 {
3933 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3934 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
3935
3936 /* Process registered FECs to clear their local label, if needed. */
3937 fec_evaluate(zvrf);
3938 return 0;
3939 }
3940
3941 /*
3942 * Display MPLS global label block configuration (VTY command handler).
3943 */
3944 int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
3945 {
3946 if (zvrf->mpls_srgb.start_label == 0)
3947 return 0;
3948
3949 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
3950 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
3951 vty_out(vty, "mpls label global-block %u %u\n",
3952 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
3953 }
3954
3955 return 1;
3956 }
3957
3958 /*
3959 * Called when VRF becomes inactive, cleans up information but keeps
3960 * the table itself.
3961 */
3962 void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
3963 {
3964 struct zebra_vrf *def_zvrf;
3965 afi_t afi;
3966
3967 if (zvrf_id(zvrf) == VRF_DEFAULT)
3968 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3969 else {
3970 /*
3971 * For other vrfs, we try to remove associated LSPs; we locate
3972 * the LSPs in the default vrf.
3973 */
3974 def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3975
3976 /* At shutdown, the default may be gone already */
3977 if (def_zvrf == NULL)
3978 return;
3979
3980 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
3981 if (zvrf->label[afi] != MPLS_LABEL_NONE)
3982 lsp_uninstall(def_zvrf, zvrf->label[afi]);
3983 }
3984 }
3985 }
3986
3987 /*
3988 * When a vrf label is assigned and the client goes away
3989 * we should cleanup the vrf labels associated with
3990 * that zclient.
3991 */
3992 void zebra_mpls_client_cleanup_vrf_label(uint8_t proto)
3993 {
3994 struct vrf *vrf;
3995 struct zebra_vrf *def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3996
3997 if (def_zvrf == NULL)
3998 return;
3999
4000 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
4001 struct zebra_vrf *zvrf = vrf->info;
4002 afi_t afi;
4003
4004 if (!zvrf)
4005 continue;
4006
4007 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4008 if (zvrf->label_proto[afi] == proto
4009 && zvrf->label[afi] != MPLS_LABEL_NONE)
4010 lsp_uninstall(def_zvrf, zvrf->label[afi]);
4011
4012 /*
4013 * Cleanup data structures by fiat
4014 */
4015 zvrf->label_proto[afi] = 0;
4016 zvrf->label[afi] = MPLS_LABEL_NONE;
4017 }
4018 }
4019 }
4020
4021 /*
4022 * Called upon process exiting, need to delete LSP forwarding
4023 * entries from the kernel.
4024 * NOTE: Currently supported only for default VRF.
4025 */
4026 void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
4027 {
4028 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
4029 hash_clean(zvrf->lsp_table, NULL);
4030 hash_free(zvrf->lsp_table);
4031 hash_clean(zvrf->slsp_table, NULL);
4032 hash_free(zvrf->slsp_table);
4033 route_table_finish(zvrf->fec_table[AFI_IP]);
4034 route_table_finish(zvrf->fec_table[AFI_IP6]);
4035 }
4036
4037 /*
4038 * Allocate MPLS tables for this VRF and do other initialization.
4039 * NOTE: Currently supported only for default VRF.
4040 */
4041 void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
4042 {
4043 char buffer[80];
4044
4045 if (!zvrf)
4046 return;
4047
4048 snprintf(buffer, sizeof(buffer), "ZEBRA SLSP table: %s",
4049 zvrf->vrf->name);
4050 zvrf->slsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
4051
4052 snprintf(buffer, sizeof(buffer), "ZEBRA LSP table: %s",
4053 zvrf->vrf->name);
4054 zvrf->lsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
4055 zvrf->fec_table[AFI_IP] = route_table_init();
4056 zvrf->fec_table[AFI_IP6] = route_table_init();
4057 zvrf->mpls_flags = 0;
4058 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
4059 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
4060 }
4061
4062 /*
4063 * Global MPLS initialization.
4064 */
4065 void zebra_mpls_init(void)
4066 {
4067 mpls_enabled = 0;
4068 mpls_pw_reach_strict = false;
4069
4070 if (mpls_kernel_init() < 0) {
4071 flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
4072 "Disabling MPLS support (no kernel support)");
4073 return;
4074 }
4075
4076 if (!mpls_processq_init())
4077 mpls_enabled = 1;
4078
4079 hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
4080 hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
4081 }