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