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