]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mpls.c
Merge pull request #9558 from LabNConsulting/ziemba/doc-cli-new-node
[mirror_frr.git] / zebra / zebra_mpls.c
1 /* Zebra MPLS code
2 * Copyright (C) 2013 Cumulus Networks, Inc.
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "prefix.h"
24 #include "table.h"
25 #include "memory.h"
26 #include "command.h"
27 #include "if.h"
28 #include "log.h"
29 #include "sockunion.h"
30 #include "linklist.h"
31 #include "thread.h"
32 #include "workqueue.h"
33 #include "prefix.h"
34 #include "routemap.h"
35 #include "stream.h"
36 #include "nexthop.h"
37 #include "termtable.h"
38 #include "lib/json.h"
39
40 #include "zebra/rib.h"
41 #include "zebra/rt.h"
42 #include "zebra/interface.h"
43 #include "zebra/zserv.h"
44 #include "zebra/zebra_router.h"
45 #include "zebra/redistribute.h"
46 #include "zebra/debug.h"
47 #include "zebra/zebra_vrf.h"
48 #include "zebra/zebra_mpls.h"
49 #include "zebra/zebra_srte.h"
50 #include "zebra/zebra_errors.h"
51
52 DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object");
53 DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object");
54 DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object");
55
56 int mpls_enabled;
57 bool mpls_pw_reach_strict; /* Strict reachability checking */
58
59 /* static function declarations */
60
61 static void fec_evaluate(struct zebra_vrf *zvrf);
62 static uint32_t fec_derive_label_from_index(struct zebra_vrf *vrf,
63 struct zebra_fec *fec);
64 static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
65 struct route_node *rn, struct route_entry *re);
66 static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label);
67 static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
68 mpls_label_t old_label);
69 static int fec_send(struct zebra_fec *fec, struct zserv *client);
70 static void fec_update_clients(struct zebra_fec *fec);
71 static void fec_print(struct zebra_fec *fec, struct vty *vty);
72 static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p);
73 static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
74 mpls_label_t label, uint32_t flags,
75 uint32_t label_index);
76 static int fec_del(struct zebra_fec *fec);
77
78 static unsigned int label_hash(const void *p);
79 static bool label_cmp(const void *p1, const void *p2);
80 static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
81 struct nexthop *nexthop);
82 static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
83 struct nexthop *nexthop);
84 static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe);
85
86 static void lsp_select_best_nhlfe(struct zebra_lsp *lsp);
87 static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt);
88 static void lsp_schedule(struct hash_bucket *bucket, void *ctxt);
89 static wq_item_status lsp_process(struct work_queue *wq, void *data);
90 static void lsp_processq_del(struct work_queue *wq, void *data);
91 static void lsp_processq_complete(struct work_queue *wq);
92 static int lsp_processq_add(struct zebra_lsp *lsp);
93 static void *lsp_alloc(void *p);
94
95 /* Check whether lsp can be freed - no nhlfes, e.g., and call free api */
96 static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp);
97
98 /* Free lsp; sets caller's pointer to NULL */
99 static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp);
100
101 static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size);
102 static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
103 int size);
104 static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
105 enum nexthop_types_t gtype,
106 const union g_addr *gate, ifindex_t ifindex);
107 static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
108 enum lsp_types_t lsp_type,
109 enum nexthop_types_t gtype,
110 const union g_addr *gate,
111 ifindex_t ifindex);
112 static struct zebra_nhlfe *
113 nhlfe_add(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
114 enum nexthop_types_t gtype, const union g_addr *gate,
115 ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels,
116 bool is_backup);
117 static int nhlfe_del(struct zebra_nhlfe *nhlfe);
118 static void nhlfe_free(struct zebra_nhlfe *nhlfe);
119 static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
120 struct mpls_label_stack *nh_label);
121 static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
122 enum lsp_types_t type);
123 static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
124 mpls_label_t in_label);
125 static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
126 const char *indent);
127 static void lsp_print(struct vty *vty, struct zebra_lsp *lsp);
128 static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt);
129 static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
130 int afi, enum lsp_types_t lsp_type);
131 static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
132 const struct zapi_nexthop *znh);
133 static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
134 const struct zapi_nexthop *znh);
135
136 /* Static functions */
137
138 /*
139 * Handle failure in LSP install, clear flags for NHLFE.
140 */
141 static void clear_nhlfe_installed(struct zebra_lsp *lsp)
142 {
143 struct zebra_nhlfe *nhlfe;
144 struct nexthop *nexthop;
145
146 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
147 nexthop = nhlfe->nexthop;
148 if (!nexthop)
149 continue;
150
151 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
152 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
153 }
154
155 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
156 nexthop = nhlfe->nexthop;
157 if (!nexthop)
158 continue;
159
160 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
161 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
162 }
163 }
164
165 /*
166 * Install label forwarding entry based on labeled-route entry.
167 */
168 static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
169 struct route_node *rn, struct route_entry *re)
170 {
171 struct hash *lsp_table;
172 struct zebra_ile tmp_ile;
173 struct zebra_lsp *lsp;
174 struct zebra_nhlfe *nhlfe;
175 struct nexthop *nexthop;
176 enum lsp_types_t lsp_type;
177 char buf[BUFSIZ];
178 int added, changed;
179
180 /* Lookup table. */
181 lsp_table = zvrf->lsp_table;
182 if (!lsp_table)
183 return -1;
184
185 lsp_type = lsp_type_from_re_type(re->type);
186 added = changed = 0;
187
188 /* Locate or allocate LSP entry. */
189 tmp_ile.in_label = label;
190 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
191 if (!lsp)
192 return -1;
193
194 /* For each active nexthop, create NHLFE. Note that we deliberately skip
195 * recursive nexthops right now, because intermediate hops won't
196 * understand
197 * the label advertised by the recursive nexthop (plus we don't have the
198 * logic yet to push multiple labels).
199 */
200 for (nexthop = re->nhe->nhg.nexthop;
201 nexthop; nexthop = nexthop->next) {
202 /* Skip inactive and recursive entries. */
203 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
204 continue;
205 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
206 continue;
207
208 nhlfe = nhlfe_find(&lsp->nhlfe_list, lsp_type,
209 nexthop->type, &nexthop->gate,
210 nexthop->ifindex);
211 if (nhlfe) {
212 /* Clear deleted flag (in case it was set) */
213 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
214 if (nexthop_labels_match(nhlfe->nexthop, nexthop))
215 /* No change */
216 continue;
217
218
219 if (IS_ZEBRA_DEBUG_MPLS) {
220 nhlfe2str(nhlfe, buf, BUFSIZ);
221 zlog_debug(
222 "LSP in-label %u type %d nexthop %s out-label changed",
223 lsp->ile.in_label, lsp_type, buf);
224 }
225
226 /* Update out label, trigger processing. */
227 nhlfe_out_label_update(nhlfe, nexthop->nh_label);
228 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
229 changed++;
230 } else {
231 /* Add LSP entry to this nexthop */
232 nhlfe = nhlfe_add(lsp, lsp_type, nexthop->type,
233 &nexthop->gate, nexthop->ifindex,
234 nexthop->nh_label->num_labels,
235 nexthop->nh_label->label,
236 false /*backup*/);
237 if (!nhlfe)
238 return -1;
239
240 if (IS_ZEBRA_DEBUG_MPLS) {
241 nhlfe2str(nhlfe, buf, BUFSIZ);
242 zlog_debug(
243 "Add LSP in-label %u type %d nexthop %s out-label %u",
244 lsp->ile.in_label, lsp_type, buf,
245 nexthop->nh_label->label[0]);
246 }
247
248 lsp->addr_family = NHLFE_FAMILY(nhlfe);
249
250 /* Mark NHLFE as changed. */
251 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
252 added++;
253 }
254 }
255
256 /* Queue LSP for processing if necessary. If no NHLFE got added (special
257 * case), delete the LSP entry; this case results in somewhat ugly
258 * logging.
259 */
260 if (added || changed) {
261 if (lsp_processq_add(lsp))
262 return -1;
263 } else {
264 lsp_check_free(lsp_table, &lsp);
265 }
266
267 return 0;
268 }
269
270 /*
271 * Uninstall all non-static NHLFEs of a label forwarding entry. If all
272 * NHLFEs are removed, the entire entry is deleted.
273 */
274 static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label)
275 {
276 struct hash *lsp_table;
277 struct zebra_ile tmp_ile;
278 struct zebra_lsp *lsp;
279 struct zebra_nhlfe *nhlfe;
280 char buf[BUFSIZ];
281
282 /* Lookup table. */
283 lsp_table = zvrf->lsp_table;
284 if (!lsp_table)
285 return -1;
286
287 /* If entry is not present, exit. */
288 tmp_ile.in_label = label;
289 lsp = hash_lookup(lsp_table, &tmp_ile);
290 if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
291 return 0;
292
293 /* Mark NHLFEs for delete or directly delete, as appropriate. */
294 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
295
296 /* Skip static NHLFEs */
297 if (nhlfe->type == ZEBRA_LSP_STATIC)
298 continue;
299
300 if (IS_ZEBRA_DEBUG_MPLS) {
301 nhlfe2str(nhlfe, buf, BUFSIZ);
302 zlog_debug(
303 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
304 label, nhlfe->type, buf, nhlfe->flags);
305 }
306
307 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)) {
308 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
309 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
310 } else {
311 nhlfe_del(nhlfe);
312 }
313 }
314
315 /* Queue LSP for processing, if needed, else delete. */
316 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
317 if (lsp_processq_add(lsp))
318 return -1;
319 } else {
320 lsp_check_free(lsp_table, &lsp);
321 }
322
323 return 0;
324 }
325
326 /*
327 * This function is invoked upon change to label block configuration; it
328 * will walk all registered FECs with label-index and appropriately update
329 * their local labels and trigger client updates.
330 */
331 static void fec_evaluate(struct zebra_vrf *zvrf)
332 {
333 struct route_node *rn;
334 struct zebra_fec *fec;
335 uint32_t old_label, new_label;
336 int af;
337
338 for (af = AFI_IP; af < AFI_MAX; af++) {
339 if (zvrf->fec_table[af] == NULL)
340 continue;
341
342 for (rn = route_top(zvrf->fec_table[af]); rn;
343 rn = route_next(rn)) {
344 if ((fec = rn->info) == NULL)
345 continue;
346
347 /* Skip configured FECs and those without a label index.
348 */
349 if (fec->flags & FEC_FLAG_CONFIGURED
350 || fec->label_index == MPLS_INVALID_LABEL_INDEX)
351 continue;
352
353 /* Save old label, determine new label. */
354 old_label = fec->label;
355 new_label =
356 zvrf->mpls_srgb.start_label + fec->label_index;
357 if (new_label >= zvrf->mpls_srgb.end_label)
358 new_label = MPLS_INVALID_LABEL;
359
360 /* If label has changed, update FEC and clients. */
361 if (new_label == old_label)
362 continue;
363
364 if (IS_ZEBRA_DEBUG_MPLS)
365 zlog_debug(
366 "Update fec %pRN new label %u upon label block",
367 rn, new_label);
368
369 fec->label = new_label;
370 fec_update_clients(fec);
371
372 /* Update label forwarding entries appropriately */
373 fec_change_update_lsp(zvrf, fec, old_label);
374 }
375 }
376 }
377
378 /*
379 * Derive (if possible) and update the local label for the FEC based on
380 * its label index. The index is "acceptable" if it falls within the
381 * globally configured label block (SRGB).
382 */
383 static uint32_t fec_derive_label_from_index(struct zebra_vrf *zvrf,
384 struct zebra_fec *fec)
385 {
386 uint32_t label;
387
388 if (fec->label_index != MPLS_INVALID_LABEL_INDEX
389 && zvrf->mpls_srgb.start_label
390 && ((label = zvrf->mpls_srgb.start_label + fec->label_index)
391 < zvrf->mpls_srgb.end_label))
392 fec->label = label;
393 else
394 fec->label = MPLS_INVALID_LABEL;
395
396 return fec->label;
397 }
398
399 /*
400 * There is a change for this FEC. Install or uninstall label forwarding
401 * entries, as appropriate.
402 */
403 static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
404 mpls_label_t old_label)
405 {
406 struct route_table *table;
407 struct route_node *rn;
408 struct route_entry *re;
409 afi_t afi;
410
411 /* Uninstall label forwarding entry, if previously installed. */
412 if (old_label != MPLS_INVALID_LABEL
413 && old_label != MPLS_LABEL_IMPLICIT_NULL)
414 lsp_uninstall(zvrf, old_label);
415
416 /* Install label forwarding entry corr. to new label, if needed. */
417 if (fec->label == MPLS_INVALID_LABEL
418 || fec->label == MPLS_LABEL_IMPLICIT_NULL)
419 return 0;
420
421 afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
422 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
423 if (!table)
424 return 0;
425
426 /* See if labeled route exists. */
427 rn = route_node_lookup(table, &fec->rn->p);
428 if (!rn)
429 return 0;
430
431 RNODE_FOREACH_RE (rn, re) {
432 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
433 break;
434 }
435
436 if (!re || !zebra_rib_labeled_unicast(re))
437 return 0;
438
439 if (lsp_install(zvrf, fec->label, rn, re))
440 return -1;
441
442 return 0;
443 }
444
445 /*
446 * Inform about FEC to a registered client.
447 */
448 static int fec_send(struct zebra_fec *fec, struct zserv *client)
449 {
450 struct stream *s;
451 struct route_node *rn;
452
453 rn = fec->rn;
454
455 /* Get output stream. */
456 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
457
458 zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
459
460 stream_putw(s, rn->p.family);
461 stream_put_prefix(s, &rn->p);
462 stream_putl(s, fec->label);
463 stream_putw_at(s, 0, stream_get_endp(s));
464 return zserv_send_message(client, s);
465 }
466
467 /*
468 * Update all registered clients about this FEC. Caller should've updated
469 * FEC and ensure no duplicate updates.
470 */
471 static void fec_update_clients(struct zebra_fec *fec)
472 {
473 struct listnode *node;
474 struct zserv *client;
475
476 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) {
477 if (IS_ZEBRA_DEBUG_MPLS)
478 zlog_debug("Update client %s",
479 zebra_route_string(client->proto));
480 fec_send(fec, client);
481 }
482 }
483
484
485 /*
486 * Print a FEC-label binding entry.
487 */
488 static void fec_print(struct zebra_fec *fec, struct vty *vty)
489 {
490 struct route_node *rn;
491 struct listnode *node;
492 struct zserv *client;
493 char buf[BUFSIZ];
494
495 rn = fec->rn;
496 vty_out(vty, "%pRN\n", rn);
497 vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
498 if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
499 vty_out(vty, ", Label Index: %u", fec->label_index);
500 vty_out(vty, "\n");
501 if (!list_isempty(fec->client_list)) {
502 vty_out(vty, " Client list:");
503 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
504 vty_out(vty, " %s(fd %d)",
505 zebra_route_string(client->proto),
506 client->sock);
507 vty_out(vty, "\n");
508 }
509 }
510
511 /*
512 * Locate FEC-label binding that matches with passed info.
513 */
514 static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p)
515 {
516 struct route_node *rn;
517
518 apply_mask(p);
519 rn = route_node_lookup(table, p);
520 if (!rn)
521 return NULL;
522
523 route_unlock_node(rn);
524 return (rn->info);
525 }
526
527 /*
528 * Add a FEC. This may be upon a client registering for a binding
529 * or when a binding is configured.
530 */
531 static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
532 mpls_label_t label, uint32_t flags,
533 uint32_t label_index)
534 {
535 struct route_node *rn;
536 struct zebra_fec *fec;
537
538 apply_mask(p);
539
540 /* Lookup (or add) route node.*/
541 rn = route_node_get(table, p);
542 if (!rn)
543 return NULL;
544
545 fec = rn->info;
546
547 if (!fec) {
548 fec = XCALLOC(MTYPE_FEC, sizeof(struct zebra_fec));
549
550 rn->info = fec;
551 fec->rn = rn;
552 fec->label = label;
553 fec->client_list = list_new();
554 } else
555 route_unlock_node(rn); /* for the route_node_get */
556
557 fec->label_index = label_index;
558 fec->flags = flags;
559
560 return fec;
561 }
562
563 /*
564 * Delete a FEC. This may be upon the last client deregistering for
565 * a FEC and no binding exists or when the binding is deleted and there
566 * are no registered clients.
567 */
568 static int fec_del(struct zebra_fec *fec)
569 {
570 list_delete(&fec->client_list);
571 fec->rn->info = NULL;
572 route_unlock_node(fec->rn);
573 XFREE(MTYPE_FEC, fec);
574 return 0;
575 }
576
577 /*
578 * Hash function for label.
579 */
580 static unsigned int label_hash(const void *p)
581 {
582 const struct zebra_ile *ile = p;
583
584 return (jhash_1word(ile->in_label, 0));
585 }
586
587 /*
588 * Compare 2 LSP hash entries based on in-label.
589 */
590 static bool label_cmp(const void *p1, const void *p2)
591 {
592 const struct zebra_ile *ile1 = p1;
593 const struct zebra_ile *ile2 = p2;
594
595 return (ile1->in_label == ile2->in_label);
596 }
597
598 /*
599 * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
600 * the passed flag.
601 * NOTE: Looking only for connected routes right now.
602 */
603 static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
604 struct nexthop *nexthop)
605 {
606 struct route_table *table;
607 struct prefix_ipv4 p;
608 struct route_node *rn;
609 struct route_entry *match;
610 struct nexthop *match_nh;
611
612 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, nexthop->vrf_id);
613 if (!table)
614 return 0;
615
616 /* Lookup nexthop in IPv4 routing table. */
617 memset(&p, 0, sizeof(struct prefix_ipv4));
618 p.family = AF_INET;
619 p.prefixlen = IPV4_MAX_BITLEN;
620 p.prefix = nexthop->gate.ipv4;
621
622 rn = route_node_match(table, (struct prefix *)&p);
623 if (!rn)
624 return 0;
625
626 route_unlock_node(rn);
627
628 /* Locate a valid connected route. */
629 RNODE_FOREACH_RE (rn, match) {
630 if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
631 || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
632 continue;
633
634 for (match_nh = match->nhe->nhg.nexthop; match_nh;
635 match_nh = match_nh->next) {
636 if (match->type == ZEBRA_ROUTE_CONNECT
637 || nexthop->ifindex == match_nh->ifindex) {
638 nexthop->ifindex = match_nh->ifindex;
639 return 1;
640 }
641 }
642 }
643
644 return 0;
645 }
646
647
648 /*
649 * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
650 * the passed flag.
651 * NOTE: Looking only for connected routes right now.
652 */
653 static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
654 struct nexthop *nexthop)
655 {
656 struct route_table *table;
657 struct prefix_ipv6 p;
658 struct route_node *rn;
659 struct route_entry *match;
660
661 table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
662 if (!table)
663 return 0;
664
665 /* Lookup nexthop in IPv6 routing table. */
666 memset(&p, 0, sizeof(struct prefix_ipv6));
667 p.family = AF_INET6;
668 p.prefixlen = IPV6_MAX_BITLEN;
669 p.prefix = nexthop->gate.ipv6;
670
671 rn = route_node_match(table, (struct prefix *)&p);
672 if (!rn)
673 return 0;
674
675 route_unlock_node(rn);
676
677 /* Locate a valid connected route. */
678 RNODE_FOREACH_RE (rn, match) {
679 if ((match->type == ZEBRA_ROUTE_CONNECT)
680 && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
681 && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
682 break;
683 }
684
685 if (!match || !match->nhe->nhg.nexthop)
686 return 0;
687
688 nexthop->ifindex = match->nhe->nhg.nexthop->ifindex;
689 return 1;
690 }
691
692
693 /*
694 * Check the nexthop reachability for a NHLFE and return if valid (reachable)
695 * or not.
696 * NOTE: Each NHLFE points to only 1 nexthop.
697 */
698 static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe)
699 {
700 struct nexthop *nexthop;
701 struct interface *ifp;
702 struct zebra_ns *zns;
703
704 nexthop = nhlfe->nexthop;
705 if (!nexthop) // unexpected
706 return 0;
707
708 /* Check on nexthop based on type. */
709 switch (nexthop->type) {
710 case NEXTHOP_TYPE_IFINDEX:
711 /*
712 * Lookup if this type is special. The
713 * NEXTHOP_TYPE_IFINDEX is a pop and
714 * forward into a different table for
715 * processing. As such this ifindex
716 * passed to us may be a VRF device
717 * which will not be in the default
718 * VRF. So let's look in all of them
719 */
720 zns = zebra_ns_lookup(NS_DEFAULT);
721 ifp = if_lookup_by_index_per_ns(zns, nexthop->ifindex);
722 if (ifp && if_is_operative(ifp))
723 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
724 else
725 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
726 break;
727 case NEXTHOP_TYPE_IPV4:
728 case NEXTHOP_TYPE_IPV4_IFINDEX:
729 if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop))
730 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
731 else
732 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
733 break;
734
735 case NEXTHOP_TYPE_IPV6:
736 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
737 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
738 else
739 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
740 break;
741
742 case NEXTHOP_TYPE_IPV6_IFINDEX:
743 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
744 ifp = if_lookup_by_index(nexthop->ifindex,
745 nexthop->vrf_id);
746 if (ifp && if_is_operative(ifp))
747 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
748 else
749 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
750 } else {
751 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
752 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
753 else
754 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
755 }
756 break;
757
758 case NEXTHOP_TYPE_BLACKHOLE:
759 break;
760 }
761
762 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
763 }
764
765 /*
766 * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
767 * reachability and select the best. Multipath entries are also
768 * marked. This is invoked when an LSP scheduled for processing (due
769 * to some change) is examined.
770 */
771 static void lsp_select_best_nhlfe(struct zebra_lsp *lsp)
772 {
773 struct zebra_nhlfe *nhlfe;
774 struct zebra_nhlfe *best;
775 struct nexthop *nexthop;
776 int changed = 0;
777
778 if (!lsp)
779 return;
780
781 best = NULL;
782 lsp->num_ecmp = 0;
783 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
784
785 /*
786 * First compute the best path, after checking nexthop status. We are
787 * only concerned with non-deleted NHLFEs.
788 */
789 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
790 /* Clear selection flags. */
791 UNSET_FLAG(nhlfe->flags,
792 (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
793
794 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
795 && nhlfe_nexthop_active(nhlfe)) {
796 if (!best || (nhlfe->distance < best->distance))
797 best = nhlfe;
798 }
799 }
800
801 lsp->best_nhlfe = best;
802 if (!lsp->best_nhlfe)
803 return;
804
805 /*
806 * Check the active status of backup nhlfes also
807 */
808 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
809 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
810 (void)nhlfe_nexthop_active(nhlfe);
811 }
812
813 /* Mark best NHLFE as selected. */
814 SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
815
816 /*
817 * If best path exists, see if there is ECMP. While doing this, note if
818 * a
819 * new (uninstalled) NHLFE has been selected, an installed entry that is
820 * still selected has a change or an installed entry is to be removed.
821 */
822 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
823 int nh_chg, nh_sel, nh_inst;
824
825 nexthop = nhlfe->nexthop;
826 if (!nexthop) // unexpected
827 continue;
828
829 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
830 && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
831 && (nhlfe->distance == lsp->best_nhlfe->distance)) {
832 SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
833 SET_FLAG(nhlfe->flags, NHLFE_FLAG_MULTIPATH);
834 lsp->num_ecmp++;
835 }
836
837 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) && !changed) {
838 nh_chg = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
839 nh_sel = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
840 nh_inst =
841 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
842
843 if ((nh_sel && !nh_inst)
844 || (nh_sel && nh_inst && nh_chg)
845 || (nh_inst && !nh_sel))
846 changed = 1;
847 }
848
849 /* We have finished examining, clear changed flag. */
850 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
851 }
852
853 if (changed)
854 SET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
855 }
856
857 /*
858 * Delete LSP forwarding entry from kernel, if installed. Called upon
859 * process exit.
860 */
861 static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt)
862 {
863 struct zebra_lsp *lsp;
864
865 lsp = (struct zebra_lsp *)bucket->data;
866 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
867 (void)dplane_lsp_delete(lsp);
868 }
869
870 /*
871 * Schedule LSP forwarding entry for processing. Called upon changes
872 * that may impact LSPs such as nexthop / connected route changes.
873 */
874 static void lsp_schedule(struct hash_bucket *bucket, void *ctxt)
875 {
876 struct zebra_lsp *lsp;
877
878 lsp = (struct zebra_lsp *)bucket->data;
879
880 /* In the common flow, this is used when external events occur. For
881 * LSPs with backup nhlfes, we'll assume that the forwarding
882 * plane will use the backups to handle these events, until the
883 * owning protocol can react.
884 */
885 if (ctxt == NULL) {
886 /* Skip LSPs with backups */
887 if (nhlfe_list_first(&lsp->backup_nhlfe_list) != NULL) {
888 if (IS_ZEBRA_DEBUG_MPLS_DETAIL)
889 zlog_debug("%s: skip LSP in-label %u",
890 __func__, lsp->ile.in_label);
891 return;
892 }
893 }
894
895 (void)lsp_processq_add(lsp);
896 }
897
898 /*
899 * Process a LSP entry that is in the queue. Recalculate best NHLFE and
900 * any multipaths and update or delete from the kernel, as needed.
901 */
902 static wq_item_status lsp_process(struct work_queue *wq, void *data)
903 {
904 struct zebra_lsp *lsp;
905 struct zebra_nhlfe *oldbest, *newbest;
906 char buf[BUFSIZ], buf2[BUFSIZ];
907 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
908 enum zebra_dplane_result res;
909
910 lsp = (struct zebra_lsp *)data;
911 if (!lsp) // unexpected
912 return WQ_SUCCESS;
913
914 oldbest = lsp->best_nhlfe;
915
916 /* Select best NHLFE(s) */
917 lsp_select_best_nhlfe(lsp);
918
919 newbest = lsp->best_nhlfe;
920
921 if (IS_ZEBRA_DEBUG_MPLS) {
922 if (oldbest)
923 nhlfe2str(oldbest, buf, sizeof(buf));
924 if (newbest)
925 nhlfe2str(newbest, buf2, sizeof(buf2));
926 zlog_debug(
927 "Process LSP in-label %u oldbest %s newbest %s flags 0x%x ecmp# %d",
928 lsp->ile.in_label, oldbest ? buf : "NULL",
929 newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
930 }
931
932 if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
933 /* Not already installed */
934 if (newbest) {
935
936 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
937
938 switch (dplane_lsp_add(lsp)) {
939 case ZEBRA_DPLANE_REQUEST_QUEUED:
940 /* Set 'installed' flag so we will know
941 * that an install is in-flight.
942 */
943 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
944
945 zvrf->lsp_installs_queued++;
946 break;
947 case ZEBRA_DPLANE_REQUEST_FAILURE:
948 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
949 "LSP Install Failure: %u",
950 lsp->ile.in_label);
951 break;
952 case ZEBRA_DPLANE_REQUEST_SUCCESS:
953 zvrf->lsp_installs++;
954 break;
955 }
956 }
957 } else {
958 /* Installed, may need an update and/or delete. */
959 if (!newbest) {
960 res = dplane_lsp_delete(lsp);
961
962 /* We do some of the lsp cleanup immediately for
963 * deletes.
964 */
965 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
966 clear_nhlfe_installed(lsp);
967
968 switch (res) {
969 case ZEBRA_DPLANE_REQUEST_QUEUED:
970 zvrf->lsp_removals_queued++;
971 break;
972 case ZEBRA_DPLANE_REQUEST_FAILURE:
973 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
974 "LSP Deletion Failure: %u",
975 lsp->ile.in_label);
976 break;
977 case ZEBRA_DPLANE_REQUEST_SUCCESS:
978 zvrf->lsp_removals++;
979 break;
980 }
981 } else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) {
982 struct zebra_nhlfe *nhlfe;
983 struct nexthop *nexthop;
984
985 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
986
987 /* We leave the INSTALLED flag set here
988 * so we know an update is in-flight.
989 */
990
991 /*
992 * Any NHLFE that was installed but is not
993 * selected now needs to have its flags updated.
994 */
995 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
996 nexthop = nhlfe->nexthop;
997 if (!nexthop)
998 continue;
999
1000 if (CHECK_FLAG(nhlfe->flags,
1001 NHLFE_FLAG_INSTALLED)
1002 && !CHECK_FLAG(nhlfe->flags,
1003 NHLFE_FLAG_SELECTED)) {
1004 UNSET_FLAG(nhlfe->flags,
1005 NHLFE_FLAG_INSTALLED);
1006 UNSET_FLAG(nexthop->flags,
1007 NEXTHOP_FLAG_FIB);
1008 }
1009 }
1010
1011 switch (dplane_lsp_update(lsp)) {
1012 case ZEBRA_DPLANE_REQUEST_QUEUED:
1013 zvrf->lsp_installs_queued++;
1014 break;
1015 case ZEBRA_DPLANE_REQUEST_FAILURE:
1016 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1017 "LSP Update Failure: %u",
1018 lsp->ile.in_label);
1019 break;
1020 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1021 zvrf->lsp_installs++;
1022 break;
1023 }
1024 }
1025 }
1026
1027 return WQ_SUCCESS;
1028 }
1029
1030
1031 /*
1032 * Callback upon processing completion of a LSP forwarding entry.
1033 */
1034 static void lsp_processq_del(struct work_queue *wq, void *data)
1035 {
1036 struct zebra_vrf *zvrf;
1037 struct zebra_lsp *lsp;
1038 struct hash *lsp_table;
1039 struct zebra_nhlfe *nhlfe;
1040
1041 zvrf = vrf_info_lookup(VRF_DEFAULT);
1042 assert(zvrf);
1043
1044 lsp_table = zvrf->lsp_table;
1045 if (!lsp_table) // unexpected
1046 return;
1047
1048 lsp = (struct zebra_lsp *)data;
1049 if (!lsp) // unexpected
1050 return;
1051
1052 /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
1053 * exist,
1054 * delete LSP entry also.
1055 */
1056 UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1057
1058 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1059 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1060 nhlfe_del(nhlfe);
1061 }
1062
1063 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1064 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1065 nhlfe_del(nhlfe);
1066 }
1067
1068 lsp_check_free(lsp_table, &lsp);
1069 }
1070
1071 /*
1072 * Callback upon finishing the processing of all scheduled
1073 * LSP forwarding entries.
1074 */
1075 static void lsp_processq_complete(struct work_queue *wq)
1076 {
1077 /* Nothing to do for now. */
1078 }
1079
1080 /*
1081 * Add LSP forwarding entry to queue for subsequent processing.
1082 */
1083 static int lsp_processq_add(struct zebra_lsp *lsp)
1084 {
1085 /* If already scheduled, exit. */
1086 if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1087 return 0;
1088
1089 if (zrouter.lsp_process_q == NULL) {
1090 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1091 "%s: work_queue does not exist!", __func__);
1092 return -1;
1093 }
1094
1095 work_queue_add(zrouter.lsp_process_q, lsp);
1096 SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1097 return 0;
1098 }
1099
1100 /*
1101 * Callback to allocate LSP forwarding table entry.
1102 */
1103 static void *lsp_alloc(void *p)
1104 {
1105 const struct zebra_ile *ile = p;
1106 struct zebra_lsp *lsp;
1107
1108 lsp = XCALLOC(MTYPE_LSP, sizeof(struct zebra_lsp));
1109 lsp->ile = *ile;
1110 nhlfe_list_init(&lsp->nhlfe_list);
1111 nhlfe_list_init(&lsp->backup_nhlfe_list);
1112
1113 if (IS_ZEBRA_DEBUG_MPLS)
1114 zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label);
1115
1116 return ((void *)lsp);
1117 }
1118
1119 /*
1120 * Check whether lsp can be freed - no nhlfes, e.g., and call free api
1121 */
1122 static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp)
1123 {
1124 struct zebra_lsp *lsp;
1125
1126 if (plsp == NULL || *plsp == NULL)
1127 return;
1128
1129 lsp = *plsp;
1130
1131 if ((nhlfe_list_first(&lsp->nhlfe_list) == NULL) &&
1132 (nhlfe_list_first(&lsp->backup_nhlfe_list) == NULL) &&
1133 !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1134 lsp_free(lsp_table, plsp);
1135 }
1136
1137 /*
1138 * Dtor for an LSP: remove from ile hash, release any internal allocations,
1139 * free LSP object.
1140 */
1141 static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp)
1142 {
1143 struct zebra_lsp *lsp;
1144 struct zebra_nhlfe *nhlfe;
1145
1146 if (plsp == NULL || *plsp == NULL)
1147 return;
1148
1149 lsp = *plsp;
1150
1151 if (IS_ZEBRA_DEBUG_MPLS)
1152 zlog_debug("Free LSP in-label %u flags 0x%x",
1153 lsp->ile.in_label, lsp->flags);
1154
1155 /* Free nhlfes, if any. */
1156 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe)
1157 nhlfe_del(nhlfe);
1158
1159 /* Free backup nhlfes, if any. */
1160 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe)
1161 nhlfe_del(nhlfe);
1162
1163 hash_release(lsp_table, &lsp->ile);
1164 XFREE(MTYPE_LSP, lsp);
1165
1166 *plsp = NULL;
1167 }
1168
1169 /*
1170 * Create printable string for NHLFE entry.
1171 */
1172 static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size)
1173 {
1174 const struct nexthop *nexthop;
1175
1176 buf[0] = '\0';
1177 nexthop = nhlfe->nexthop;
1178 switch (nexthop->type) {
1179 case NEXTHOP_TYPE_IPV4:
1180 case NEXTHOP_TYPE_IPV4_IFINDEX:
1181 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
1182 break;
1183 case NEXTHOP_TYPE_IPV6:
1184 case NEXTHOP_TYPE_IPV6_IFINDEX:
1185 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
1186 break;
1187 case NEXTHOP_TYPE_IFINDEX:
1188 snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
1189 case NEXTHOP_TYPE_BLACKHOLE:
1190 break;
1191 }
1192
1193 return buf;
1194 }
1195
1196 /*
1197 * Check if NHLFE matches with search info passed.
1198 */
1199 static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
1200 enum nexthop_types_t gtype,
1201 const union g_addr *gate, ifindex_t ifindex)
1202 {
1203 struct nexthop *nhop;
1204 int cmp = 1;
1205
1206 nhop = nhlfe->nexthop;
1207 if (!nhop)
1208 return 1;
1209
1210 if (nhop->type != gtype)
1211 return 1;
1212
1213 switch (nhop->type) {
1214 case NEXTHOP_TYPE_IPV4:
1215 case NEXTHOP_TYPE_IPV4_IFINDEX:
1216 cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
1217 sizeof(struct in_addr));
1218 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1219 cmp = !(nhop->ifindex == ifindex);
1220 break;
1221 case NEXTHOP_TYPE_IPV6:
1222 case NEXTHOP_TYPE_IPV6_IFINDEX:
1223 cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
1224 sizeof(struct in6_addr));
1225 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1226 cmp = !(nhop->ifindex == ifindex);
1227 break;
1228 case NEXTHOP_TYPE_IFINDEX:
1229 cmp = !(nhop->ifindex == ifindex);
1230 break;
1231 case NEXTHOP_TYPE_BLACKHOLE:
1232 break;
1233 }
1234
1235 return cmp;
1236 }
1237
1238
1239 /*
1240 * Locate NHLFE that matches with passed info.
1241 */
1242 static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
1243 enum lsp_types_t lsp_type,
1244 enum nexthop_types_t gtype,
1245 const union g_addr *gate,
1246 ifindex_t ifindex)
1247 {
1248 struct zebra_nhlfe *nhlfe;
1249
1250 frr_each_safe(nhlfe_list, list, nhlfe) {
1251 if (nhlfe->type != lsp_type)
1252 continue;
1253 if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex))
1254 break;
1255 }
1256
1257 return nhlfe;
1258 }
1259
1260 /*
1261 * Allocate and init new NHLFE.
1262 */
1263 static struct zebra_nhlfe *
1264 nhlfe_alloc(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
1265 enum nexthop_types_t gtype, const union g_addr *gate,
1266 ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels)
1267 {
1268 struct zebra_nhlfe *nhlfe;
1269 struct nexthop *nexthop;
1270
1271 assert(lsp);
1272
1273 nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(struct zebra_nhlfe));
1274
1275 nhlfe->lsp = lsp;
1276 nhlfe->type = lsp_type;
1277 nhlfe->distance = lsp_distance(lsp_type);
1278
1279 nexthop = nexthop_new();
1280
1281 nexthop_add_labels(nexthop, lsp_type, num_labels, labels);
1282
1283 nexthop->vrf_id = VRF_DEFAULT;
1284 nexthop->type = gtype;
1285 switch (nexthop->type) {
1286 case NEXTHOP_TYPE_IPV4:
1287 case NEXTHOP_TYPE_IPV4_IFINDEX:
1288 nexthop->gate.ipv4 = gate->ipv4;
1289 if (ifindex)
1290 nexthop->ifindex = ifindex;
1291 break;
1292 case NEXTHOP_TYPE_IPV6:
1293 case NEXTHOP_TYPE_IPV6_IFINDEX:
1294 nexthop->gate.ipv6 = gate->ipv6;
1295 if (ifindex)
1296 nexthop->ifindex = ifindex;
1297 break;
1298 case NEXTHOP_TYPE_IFINDEX:
1299 nexthop->ifindex = ifindex;
1300 break;
1301 case NEXTHOP_TYPE_BLACKHOLE:
1302 if (IS_ZEBRA_DEBUG_MPLS)
1303 zlog_debug("%s: invalid: blackhole nexthop", __func__);
1304
1305 nexthop_free(nexthop);
1306 XFREE(MTYPE_NHLFE, nhlfe);
1307 return NULL;
1308 }
1309 nhlfe->nexthop = nexthop;
1310
1311 return nhlfe;
1312 }
1313
1314 /*
1315 * Add primary or backup NHLFE. Base entry must have been created and
1316 * duplicate check done.
1317 */
1318 static struct zebra_nhlfe *nhlfe_add(struct zebra_lsp *lsp,
1319 enum lsp_types_t lsp_type,
1320 enum nexthop_types_t gtype,
1321 const union g_addr *gate,
1322 ifindex_t ifindex, uint8_t num_labels,
1323 const mpls_label_t *labels, bool is_backup)
1324 {
1325 struct zebra_nhlfe *nhlfe;
1326
1327 if (!lsp)
1328 return NULL;
1329
1330 /* Must have labels */
1331 if (num_labels == 0 || labels == NULL) {
1332 if (IS_ZEBRA_DEBUG_MPLS)
1333 zlog_debug("%s: invalid nexthop: no labels", __func__);
1334
1335 return NULL;
1336 }
1337
1338 /* Allocate new object */
1339 nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels,
1340 labels);
1341
1342 if (!nhlfe)
1343 return NULL;
1344
1345 /* Enqueue to LSP: primaries at head of list, backups at tail */
1346 if (is_backup) {
1347 SET_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP);
1348 nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe);
1349 } else
1350 nhlfe_list_add_head(&lsp->nhlfe_list, nhlfe);
1351
1352 return nhlfe;
1353 }
1354
1355 /*
1356 * Common delete for NHLFEs.
1357 */
1358 static void nhlfe_free(struct zebra_nhlfe *nhlfe)
1359 {
1360 if (!nhlfe)
1361 return;
1362
1363 /* Free nexthop. */
1364 if (nhlfe->nexthop)
1365 nexthop_free(nhlfe->nexthop);
1366
1367 nhlfe->nexthop = NULL;
1368
1369 XFREE(MTYPE_NHLFE, nhlfe);
1370 }
1371
1372
1373 /*
1374 * Disconnect NHLFE from LSP, and free. Entry must be present on LSP's list.
1375 */
1376 static int nhlfe_del(struct zebra_nhlfe *nhlfe)
1377 {
1378 struct zebra_lsp *lsp;
1379
1380 if (!nhlfe)
1381 return -1;
1382
1383 lsp = nhlfe->lsp;
1384 if (!lsp)
1385 return -1;
1386
1387 if (nhlfe == lsp->best_nhlfe)
1388 lsp->best_nhlfe = NULL;
1389
1390 /* Unlink from LSP */
1391 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP))
1392 nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
1393 else
1394 nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
1395
1396 nhlfe->lsp = NULL;
1397
1398 nhlfe_free(nhlfe);
1399
1400 return 0;
1401 }
1402
1403 /*
1404 * Update label for NHLFE entry.
1405 */
1406 static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
1407 struct mpls_label_stack *nh_label)
1408 {
1409 nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
1410 }
1411
1412 static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
1413 enum lsp_types_t type)
1414 {
1415 struct zebra_nhlfe *nhlfe;
1416 int schedule_lsp = 0;
1417 char buf[BUFSIZ];
1418
1419 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1420 schedule_lsp = 1;
1421
1422 /* Mark NHLFEs for delete or directly delete, as appropriate. */
1423 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1424 /* Skip non-static NHLFEs */
1425 if (nhlfe->type != type)
1426 continue;
1427
1428 if (IS_ZEBRA_DEBUG_MPLS) {
1429 nhlfe2str(nhlfe, buf, sizeof(buf));
1430 zlog_debug(
1431 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
1432 lsp->ile.in_label, type, buf, nhlfe->flags);
1433 }
1434
1435 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1436 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1437 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1438 schedule_lsp = 1;
1439 } else {
1440 nhlfe_del(nhlfe);
1441 }
1442 }
1443
1444 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1445 /* Skip non-static NHLFEs */
1446 if (nhlfe->type != type)
1447 continue;
1448
1449 if (IS_ZEBRA_DEBUG_MPLS) {
1450 nhlfe2str(nhlfe, buf, sizeof(buf));
1451 zlog_debug(
1452 "Del backup LSP in-label %u type %d nexthop %s flags 0x%x",
1453 lsp->ile.in_label, type, buf, nhlfe->flags);
1454 }
1455
1456 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1457 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1458 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1459 schedule_lsp = 1;
1460 } else {
1461 nhlfe_del(nhlfe);
1462 }
1463 }
1464
1465 /* Queue LSP for processing, if needed, else delete. */
1466 if (schedule_lsp) {
1467 if (IS_ZEBRA_DEBUG_MPLS) {
1468 zlog_debug("Schedule LSP in-label %u flags 0x%x",
1469 lsp->ile.in_label, lsp->flags);
1470 }
1471 if (lsp_processq_add(lsp))
1472 return -1;
1473 } else {
1474 lsp_check_free(lsp_table, &lsp);
1475 }
1476
1477 return 0;
1478 }
1479
1480 /*
1481 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
1482 * If no other NHLFEs exist, the entry would be deleted.
1483 */
1484 static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
1485 mpls_label_t in_label)
1486 {
1487 struct hash *lsp_table;
1488 struct zebra_ile tmp_ile;
1489 struct zebra_lsp *lsp;
1490
1491 /* Lookup table. */
1492 lsp_table = zvrf->lsp_table;
1493 if (!lsp_table)
1494 return -1;
1495
1496 /* If entry is not present, exit. */
1497 tmp_ile.in_label = in_label;
1498 lsp = hash_lookup(lsp_table, &tmp_ile);
1499 if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
1500 return 0;
1501
1502 return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC);
1503 }
1504
1505 static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe)
1506 {
1507 char buf[BUFSIZ];
1508 json_object *json_nhlfe = NULL;
1509 json_object *json_backups = NULL;
1510 json_object *json_label_stack;
1511 struct nexthop *nexthop = nhlfe->nexthop;
1512 int i;
1513
1514 json_nhlfe = json_object_new_object();
1515 json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
1516 json_object_int_add(json_nhlfe, "outLabel",
1517 nexthop->nh_label->label[0]);
1518
1519 json_label_stack = json_object_new_array();
1520 json_object_object_add(json_nhlfe, "outLabelStack", json_label_stack);
1521 for (i = 0; i < nexthop->nh_label->num_labels; i++)
1522 json_object_array_add(
1523 json_label_stack,
1524 json_object_new_int(nexthop->nh_label->label[i]));
1525
1526 json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
1527
1528 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
1529 json_object_boolean_true_add(json_nhlfe, "installed");
1530
1531 switch (nexthop->type) {
1532 case NEXTHOP_TYPE_IPV4:
1533 case NEXTHOP_TYPE_IPV4_IFINDEX:
1534 json_object_string_add(json_nhlfe, "nexthop",
1535 inet_ntop(AF_INET, &nexthop->gate.ipv4,
1536 buf, sizeof(buf)));
1537 break;
1538 case NEXTHOP_TYPE_IPV6:
1539 case NEXTHOP_TYPE_IPV6_IFINDEX:
1540 json_object_string_add(
1541 json_nhlfe, "nexthop",
1542 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1543
1544 if (nexthop->ifindex)
1545 json_object_string_add(json_nhlfe, "interface",
1546 ifindex2ifname(nexthop->ifindex,
1547 nexthop->vrf_id));
1548 break;
1549 case NEXTHOP_TYPE_IFINDEX:
1550 if (nexthop->ifindex)
1551 json_object_string_add(json_nhlfe, "interface",
1552 ifindex2ifname(nexthop->ifindex,
1553 nexthop->vrf_id));
1554 break;
1555 case NEXTHOP_TYPE_BLACKHOLE:
1556 break;
1557 }
1558
1559 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
1560 json_backups = json_object_new_array();
1561 for (i = 0; i < nexthop->backup_num; i++) {
1562 json_object_array_add(
1563 json_backups,
1564 json_object_new_int(nexthop->backup_idx[i]));
1565 }
1566
1567 json_object_object_add(json_nhlfe, "backupIndex",
1568 json_backups);
1569 }
1570
1571 return json_nhlfe;
1572 }
1573
1574 /*
1575 * Print the NHLFE for a LSP forwarding entry.
1576 */
1577 static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
1578 const char *indent)
1579 {
1580 struct nexthop *nexthop;
1581 char buf[MPLS_LABEL_STRLEN];
1582
1583 nexthop = nhlfe->nexthop;
1584 if (!nexthop || !nexthop->nh_label) // unexpected
1585 return;
1586
1587 vty_out(vty, " type: %s remote label: %s distance: %d\n",
1588 nhlfe_type2str(nhlfe->type),
1589 mpls_label2str(nexthop->nh_label->num_labels,
1590 nexthop->nh_label->label,
1591 buf, sizeof(buf), 0),
1592 nhlfe->distance);
1593
1594 if (indent)
1595 vty_out(vty, "%s", indent);
1596
1597 switch (nexthop->type) {
1598 case NEXTHOP_TYPE_IPV4:
1599 case NEXTHOP_TYPE_IPV4_IFINDEX:
1600 vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
1601 if (nexthop->ifindex)
1602 vty_out(vty, " dev %s",
1603 ifindex2ifname(nexthop->ifindex,
1604 nexthop->vrf_id));
1605 break;
1606 case NEXTHOP_TYPE_IPV6:
1607 case NEXTHOP_TYPE_IPV6_IFINDEX:
1608 vty_out(vty, " via %s",
1609 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
1610 sizeof(buf)));
1611 if (nexthop->ifindex)
1612 vty_out(vty, " dev %s",
1613 ifindex2ifname(nexthop->ifindex,
1614 nexthop->vrf_id));
1615 break;
1616 case NEXTHOP_TYPE_IFINDEX:
1617 if (nexthop->ifindex)
1618 vty_out(vty, " dev %s",
1619 ifindex2ifname(nexthop->ifindex,
1620 nexthop->vrf_id));
1621 break;
1622 case NEXTHOP_TYPE_BLACKHOLE:
1623 break;
1624 }
1625 vty_out(vty, "%s",
1626 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP) ? " (backup)"
1627 : "");
1628 vty_out(vty, "%s",
1629 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
1630 : "");
1631 vty_out(vty, "\n");
1632 }
1633
1634 /*
1635 * Print an LSP forwarding entry.
1636 */
1637 static void lsp_print(struct vty *vty, struct zebra_lsp *lsp)
1638 {
1639 struct zebra_nhlfe *nhlfe, *backup;
1640 int i, j;
1641
1642 vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label,
1643 CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)"
1644 : "");
1645
1646 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1647 nhlfe_print(nhlfe, vty, NULL);
1648
1649 if (nhlfe->nexthop == NULL ||
1650 !CHECK_FLAG(nhlfe->nexthop->flags,
1651 NEXTHOP_FLAG_HAS_BACKUP))
1652 continue;
1653
1654 /* Backup nhlfes: find backups in backup list */
1655
1656 for (j = 0; j < nhlfe->nexthop->backup_num; j++) {
1657 i = 0;
1658 backup = NULL;
1659 frr_each(nhlfe_list, &lsp->backup_nhlfe_list, backup) {
1660 if (i == nhlfe->nexthop->backup_idx[j])
1661 break;
1662 i++;
1663 }
1664
1665 if (backup) {
1666 vty_out(vty, " [backup %d]", i);
1667 nhlfe_print(backup, vty, " ");
1668 }
1669 }
1670 }
1671 }
1672
1673 /*
1674 * JSON objects for an LSP forwarding entry.
1675 */
1676 static json_object *lsp_json(struct zebra_lsp *lsp)
1677 {
1678 struct zebra_nhlfe *nhlfe = NULL;
1679 json_object *json = json_object_new_object();
1680 json_object *json_nhlfe_list = json_object_new_array();
1681
1682 json_object_int_add(json, "inLabel", lsp->ile.in_label);
1683
1684 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1685 json_object_boolean_true_add(json, "installed");
1686
1687 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe)
1688 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1689
1690 json_object_object_add(json, "nexthops", json_nhlfe_list);
1691 json_nhlfe_list = NULL;
1692
1693
1694 frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1695 if (json_nhlfe_list == NULL)
1696 json_nhlfe_list = json_object_new_array();
1697
1698 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1699 }
1700
1701 if (json_nhlfe_list)
1702 json_object_object_add(json, "backupNexthops", json_nhlfe_list);
1703
1704 return json;
1705 }
1706
1707
1708 /* Return a sorted linked list of the hash contents */
1709 static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
1710 {
1711 unsigned int i;
1712 struct hash_bucket *hb;
1713 struct list *sorted_list = list_new();
1714
1715 sorted_list->cmp = (int (*)(void *, void *))cmp;
1716
1717 for (i = 0; i < hash->size; i++)
1718 for (hb = hash->index[i]; hb; hb = hb->next)
1719 listnode_add_sort(sorted_list, hb->data);
1720
1721 return sorted_list;
1722 }
1723
1724 /*
1725 * Compare two LSPs based on their label values.
1726 */
1727 static int lsp_cmp(const struct zebra_lsp *lsp1, const struct zebra_lsp *lsp2)
1728 {
1729 if (lsp1->ile.in_label < lsp2->ile.in_label)
1730 return -1;
1731
1732 if (lsp1->ile.in_label > lsp2->ile.in_label)
1733 return 1;
1734
1735 return 0;
1736 }
1737
1738 /*
1739 * Initialize work queue for processing changed LSPs.
1740 */
1741 static int mpls_processq_init(void)
1742 {
1743 zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
1744 if (!zrouter.lsp_process_q) {
1745 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1746 "%s: could not initialise work queue!", __func__);
1747 return -1;
1748 }
1749
1750 zrouter.lsp_process_q->spec.workfunc = &lsp_process;
1751 zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
1752 zrouter.lsp_process_q->spec.errorfunc = NULL;
1753 zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
1754 zrouter.lsp_process_q->spec.max_retries = 0;
1755 zrouter.lsp_process_q->spec.hold = 10;
1756
1757 return 0;
1758 }
1759
1760
1761 /*
1762 * Process LSP update results from zebra dataplane.
1763 */
1764 void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
1765 {
1766 struct zebra_vrf *zvrf;
1767 mpls_label_t label;
1768 struct zebra_ile tmp_ile;
1769 struct hash *lsp_table;
1770 struct zebra_lsp *lsp;
1771 struct zebra_nhlfe *nhlfe;
1772 struct nexthop *nexthop;
1773 enum dplane_op_e op;
1774 enum zebra_dplane_result status;
1775 enum zebra_sr_policy_update_label_mode update_mode;
1776
1777 op = dplane_ctx_get_op(ctx);
1778 status = dplane_ctx_get_status(ctx);
1779
1780 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1781 zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
1782 ctx, dplane_op2str(op),
1783 dplane_ctx_get_in_label(ctx),
1784 dplane_res2str(status));
1785
1786 label = dplane_ctx_get_in_label(ctx);
1787
1788 switch (op) {
1789 case DPLANE_OP_LSP_INSTALL:
1790 case DPLANE_OP_LSP_UPDATE:
1791 /* Look for zebra LSP object */
1792 zvrf = vrf_info_lookup(VRF_DEFAULT);
1793 if (zvrf == NULL)
1794 break;
1795
1796 lsp_table = zvrf->lsp_table;
1797
1798 tmp_ile.in_label = label;
1799 lsp = hash_lookup(lsp_table, &tmp_ile);
1800 if (lsp == NULL) {
1801 if (IS_ZEBRA_DEBUG_DPLANE)
1802 zlog_debug("LSP ctx %p: in-label %u not found",
1803 ctx, dplane_ctx_get_in_label(ctx));
1804 break;
1805 }
1806
1807 /* TODO -- Confirm that this result is still 'current' */
1808
1809 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
1810 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1811 clear_nhlfe_installed(lsp);
1812 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1813 "LSP Install Failure: in-label %u",
1814 lsp->ile.in_label);
1815 break;
1816 }
1817
1818 /* Update zebra object */
1819 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1820 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1821 nexthop = nhlfe->nexthop;
1822 if (!nexthop)
1823 continue;
1824
1825 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) &&
1826 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
1827 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1828 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1829 }
1830 }
1831
1832 update_mode = (op == DPLANE_OP_LSP_INSTALL)
1833 ? ZEBRA_SR_POLICY_LABEL_CREATED
1834 : ZEBRA_SR_POLICY_LABEL_UPDATED;
1835 zebra_sr_policy_label_update(label, update_mode);
1836 break;
1837
1838 case DPLANE_OP_LSP_DELETE:
1839 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
1840 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
1841 "LSP Deletion Failure: in-label %u",
1842 dplane_ctx_get_in_label(ctx));
1843 break;
1844 }
1845 zebra_sr_policy_label_update(label,
1846 ZEBRA_SR_POLICY_LABEL_REMOVED);
1847 break;
1848
1849 default:
1850 break;
1851
1852 } /* Switch */
1853
1854 dplane_ctx_fini(&ctx);
1855 }
1856
1857 /*
1858 * Process LSP installation info from two sets of nhlfes: a set from
1859 * a dplane notification, and a set from the zebra LSP object. Update
1860 * counters of installed nexthops, and return whether the LSP has changed.
1861 */
1862 static bool compare_notif_nhlfes(const struct nhlfe_list_head *ctx_head,
1863 struct nhlfe_list_head *nhlfe_head,
1864 int *start_counter, int *end_counter)
1865 {
1866 struct zebra_nhlfe *nhlfe;
1867 const struct zebra_nhlfe *ctx_nhlfe;
1868 struct nexthop *nexthop;
1869 const struct nexthop *ctx_nexthop;
1870 int start_count = 0, end_count = 0;
1871 bool changed_p = false;
1872 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1873
1874 frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
1875 char buf[NEXTHOP_STRLEN];
1876
1877 nexthop = nhlfe->nexthop;
1878 if (!nexthop)
1879 continue;
1880
1881 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
1882 start_count++;
1883
1884 ctx_nhlfe = NULL;
1885 ctx_nexthop = NULL;
1886 frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
1887 ctx_nexthop = ctx_nhlfe->nexthop;
1888 if (!ctx_nexthop)
1889 continue;
1890
1891 if ((ctx_nexthop->type == nexthop->type) &&
1892 nexthop_same(ctx_nexthop, nexthop)) {
1893 /* Matched */
1894 break;
1895 }
1896 }
1897
1898 if (is_debug)
1899 nexthop2str(nexthop, buf, sizeof(buf));
1900
1901 if (ctx_nhlfe && ctx_nexthop) {
1902 if (is_debug) {
1903 const char *tstr = "";
1904
1905 if (!CHECK_FLAG(ctx_nhlfe->flags,
1906 NHLFE_FLAG_INSTALLED))
1907 tstr = "not ";
1908
1909 zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
1910 buf, tstr);
1911 }
1912
1913 /* Test zebra nhlfe install state */
1914 if (CHECK_FLAG(ctx_nhlfe->flags,
1915 NHLFE_FLAG_INSTALLED)) {
1916
1917 if (!CHECK_FLAG(nhlfe->flags,
1918 NHLFE_FLAG_INSTALLED))
1919 changed_p = true;
1920
1921 /* Update counter */
1922 end_count++;
1923 } else {
1924
1925 if (CHECK_FLAG(nhlfe->flags,
1926 NHLFE_FLAG_INSTALLED))
1927 changed_p = true;
1928 }
1929
1930 } else {
1931 /* Not mentioned in lfib set -> uninstalled */
1932 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ||
1933 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ||
1934 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
1935 changed_p = true;
1936 }
1937
1938 if (is_debug)
1939 zlog_debug("LSP dplane notif: no match, nh %s",
1940 buf);
1941 }
1942 }
1943
1944 if (start_counter)
1945 *start_counter += start_count;
1946 if (end_counter)
1947 *end_counter += end_count;
1948
1949 return changed_p;
1950 }
1951
1952 /*
1953 * Update an lsp nhlfe list from a dplane context, typically an async
1954 * notification context. Update the LSP list to match the installed
1955 * status from the context's list.
1956 */
1957 static int update_nhlfes_from_ctx(struct nhlfe_list_head *nhlfe_head,
1958 const struct nhlfe_list_head *ctx_head)
1959 {
1960 int ret = 0;
1961 struct zebra_nhlfe *nhlfe;
1962 const struct zebra_nhlfe *ctx_nhlfe;
1963 struct nexthop *nexthop;
1964 const struct nexthop *ctx_nexthop;
1965 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1966
1967 frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
1968 char buf[NEXTHOP_STRLEN];
1969
1970 nexthop = nhlfe->nexthop;
1971 if (!nexthop)
1972 continue;
1973
1974 ctx_nhlfe = NULL;
1975 ctx_nexthop = NULL;
1976 frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
1977 ctx_nexthop = ctx_nhlfe->nexthop;
1978 if (!ctx_nexthop)
1979 continue;
1980
1981 if ((ctx_nexthop->type == nexthop->type) &&
1982 nexthop_same(ctx_nexthop, nexthop)) {
1983 /* Matched */
1984 break;
1985 }
1986 }
1987
1988 if (is_debug)
1989 nexthop2str(nexthop, buf, sizeof(buf));
1990
1991 if (ctx_nhlfe && ctx_nexthop) {
1992
1993 /* Bring zebra nhlfe install state into sync */
1994 if (CHECK_FLAG(ctx_nhlfe->flags,
1995 NHLFE_FLAG_INSTALLED)) {
1996 if (is_debug)
1997 zlog_debug("%s: matched lsp nhlfe %s (installed)",
1998 __func__, buf);
1999
2000 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2001 SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2002
2003 } else {
2004 if (is_debug)
2005 zlog_debug("%s: matched lsp nhlfe %s (not installed)",
2006 __func__, buf);
2007
2008 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2009 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2010 }
2011
2012 if (CHECK_FLAG(ctx_nhlfe->nexthop->flags,
2013 NEXTHOP_FLAG_FIB)) {
2014 SET_FLAG(nhlfe->nexthop->flags,
2015 NEXTHOP_FLAG_ACTIVE);
2016 SET_FLAG(nhlfe->nexthop->flags,
2017 NEXTHOP_FLAG_FIB);
2018 } else {
2019 UNSET_FLAG(nhlfe->nexthop->flags,
2020 NEXTHOP_FLAG_ACTIVE);
2021 UNSET_FLAG(nhlfe->nexthop->flags,
2022 NEXTHOP_FLAG_FIB);
2023 }
2024
2025 } else {
2026 /* Not mentioned in lfib set -> uninstalled */
2027 if (is_debug)
2028 zlog_debug("%s: no match for lsp nhlfe %s",
2029 __func__, buf);
2030 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2031 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2032 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
2033 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2034 }
2035 }
2036
2037 return ret;
2038 }
2039
2040 /*
2041 * Process async dplane notifications.
2042 */
2043 void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
2044 {
2045 struct zebra_vrf *zvrf;
2046 struct zebra_ile tmp_ile;
2047 struct hash *lsp_table;
2048 struct zebra_lsp *lsp;
2049 const struct nhlfe_list_head *ctx_list;
2050 int start_count = 0, end_count = 0; /* Installed counts */
2051 bool changed_p = false;
2052 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
2053 enum zebra_sr_policy_update_label_mode update_mode;
2054
2055 if (is_debug)
2056 zlog_debug("LSP dplane notif, in-label %u",
2057 dplane_ctx_get_in_label(ctx));
2058
2059 /* Look for zebra LSP object */
2060 zvrf = vrf_info_lookup(VRF_DEFAULT);
2061 if (zvrf == NULL)
2062 goto done;
2063
2064 lsp_table = zvrf->lsp_table;
2065
2066 tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
2067 lsp = hash_lookup(lsp_table, &tmp_ile);
2068 if (lsp == NULL) {
2069 if (is_debug)
2070 zlog_debug("dplane LSP notif: in-label %u not found",
2071 dplane_ctx_get_in_label(ctx));
2072 goto done;
2073 }
2074
2075 /*
2076 * The dataplane/forwarding plane is notifying zebra about the state
2077 * of the nexthops associated with this LSP. First, we take a
2078 * pre-scan pass to determine whether the LSP has transitioned
2079 * from installed -> uninstalled. In that case, we need to have
2080 * the existing state of the LSP objects available before making
2081 * any changes.
2082 */
2083 ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2084
2085 changed_p = compare_notif_nhlfes(ctx_list, &lsp->nhlfe_list,
2086 &start_count, &end_count);
2087
2088 if (is_debug)
2089 zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
2090 start_count, end_count,
2091 changed_p ? ", changed" : "");
2092
2093 ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2094
2095 if (compare_notif_nhlfes(ctx_list, &lsp->backup_nhlfe_list,
2096 &start_count, &end_count))
2097 /* Avoid accidentally setting back to 'false' */
2098 changed_p = true;
2099
2100 if (is_debug)
2101 zlog_debug("LSP dplane notif: lfib backups, start_count %d, end_count %d%s",
2102 start_count, end_count,
2103 changed_p ? ", changed" : "");
2104
2105 /*
2106 * Has the LSP become uninstalled? We need the existing state of the
2107 * nexthops/nhlfes at this point so we know what to delete.
2108 */
2109 if (start_count > 0 && end_count == 0) {
2110 /* Inform other lfibs */
2111 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
2112 }
2113
2114 /*
2115 * Now we take a second pass and bring the zebra
2116 * nexthop state into sync with the forwarding-plane state.
2117 */
2118 ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2119 update_nhlfes_from_ctx(&lsp->nhlfe_list, ctx_list);
2120
2121 ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2122 update_nhlfes_from_ctx(&lsp->backup_nhlfe_list, ctx_list);
2123
2124 if (end_count > 0) {
2125 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2126
2127 /* SR-TE update too */
2128 if (start_count == 0)
2129 update_mode = ZEBRA_SR_POLICY_LABEL_CREATED;
2130 else
2131 update_mode = ZEBRA_SR_POLICY_LABEL_UPDATED;
2132 zebra_sr_policy_label_update(lsp->ile.in_label, update_mode);
2133
2134 if (changed_p)
2135 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
2136
2137 } else {
2138 /* SR-TE update too */
2139 zebra_sr_policy_label_update(lsp->ile.in_label,
2140 ZEBRA_SR_POLICY_LABEL_REMOVED);
2141
2142 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2143 clear_nhlfe_installed(lsp);
2144 }
2145
2146 done:
2147 dplane_ctx_fini(&ctx);
2148 }
2149
2150 /*
2151 * Install dynamic LSP entry.
2152 */
2153 int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
2154 struct route_entry *re)
2155 {
2156 struct route_table *table;
2157 struct zebra_fec *fec;
2158
2159 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2160 if (!table)
2161 return -1;
2162
2163 /* See if there is a configured label binding for this FEC. */
2164 fec = fec_find(table, &rn->p);
2165 if (!fec || fec->label == MPLS_INVALID_LABEL)
2166 return 0;
2167
2168 /* We cannot install a label forwarding entry if local label is the
2169 * implicit-null label.
2170 */
2171 if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
2172 return 0;
2173
2174 if (lsp_install(zvrf, fec->label, rn, re))
2175 return -1;
2176
2177 return 0;
2178 }
2179
2180 /*
2181 * Uninstall dynamic LSP entry, if any.
2182 */
2183 int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
2184 struct route_entry *re)
2185 {
2186 struct route_table *table;
2187 struct zebra_fec *fec;
2188
2189 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2190 if (!table)
2191 return -1;
2192
2193 /* See if there is a configured label binding for this FEC. */
2194 fec = fec_find(table, &rn->p);
2195 if (!fec || fec->label == MPLS_INVALID_LABEL)
2196 return 0;
2197
2198 /* Uninstall always removes all dynamic NHLFEs. */
2199 return lsp_uninstall(zvrf, fec->label);
2200 }
2201
2202 /*
2203 * Add an NHLFE to an LSP, return the newly-added object. This path only changes
2204 * the LSP object - nothing is scheduled for processing, for example.
2205 */
2206 struct zebra_nhlfe *
2207 zebra_mpls_lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
2208 enum nexthop_types_t gtype, const union g_addr *gate,
2209 ifindex_t ifindex, uint8_t num_labels,
2210 const mpls_label_t *out_labels)
2211 {
2212 /* Just a public pass-through to the internal implementation */
2213 return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
2214 out_labels, false /*backup*/);
2215 }
2216
2217 /*
2218 * Add a backup NHLFE to an LSP, return the newly-added object.
2219 * This path only changes the LSP object - nothing is scheduled for
2220 * processing, for example.
2221 */
2222 struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nhlfe(
2223 struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
2224 enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex,
2225 uint8_t num_labels, 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 struct zebra_nhlfe *zebra_mpls_lsp_add_nh(struct zebra_lsp *lsp,
2236 enum lsp_types_t lsp_type,
2237 const struct nexthop *nh)
2238 {
2239 struct zebra_nhlfe *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 struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nh(struct zebra_lsp *lsp,
2256 enum lsp_types_t lsp_type,
2257 const struct nexthop *nh)
2258 {
2259 struct zebra_nhlfe *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(struct zebra_nhlfe *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 struct zebra_fec *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 struct zebra_fec *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 struct zebra_fec *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 struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
2516 mpls_label_t label)
2517 {
2518 struct route_node *rn;
2519 struct zebra_fec *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 struct zebra_fec *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 struct zebra_fec *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 struct zebra_fec *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 struct zebra_lsp *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 struct zebra_nhlfe *
3087 lsp_add_nhlfe(struct zebra_lsp *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 struct zebra_nhlfe *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 struct zebra_lsp *lsp;
3185 struct zebra_nhlfe *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(struct zebra_lsp *lsp, enum lsp_types_t type,
3214 const struct zapi_nexthop *znh)
3215 {
3216 struct zebra_nhlfe *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(struct zebra_lsp *lsp, enum lsp_types_t type,
3252 const struct zapi_nexthop *znh)
3253 {
3254 struct zebra_nhlfe *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 struct zebra_lsp *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 struct zebra_lsp *lsp;
3300 struct zebra_nhlfe *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 struct zebra_lsp *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 struct zebra_lsp *lsp;
3382 struct hash *lsp_table;
3383
3384 lsp = (struct zebra_lsp *)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 struct zebra_lsp *lsp;
3479 struct zebra_nhlfe *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 struct zebra_lsp *lsp;
3547 struct zebra_nhlfe *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 struct zebra_lsp *lsp;
3626 struct zebra_nhlfe *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 struct zebra_lsp *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 struct zebra_lsp *lsp = NULL;
3737 struct zebra_nhlfe *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 struct zebra_nhlfe *nhlfe, char *buf,
3829 int size)
3830 {
3831 const struct nexthop *nh;
3832
3833 nh = nhlfe->nexthop;
3834
3835 buf[0] = '\0';
3836 switch (nh->type) {
3837 case NEXTHOP_TYPE_IPV4:
3838 case NEXTHOP_TYPE_IPV4_IFINDEX:
3839 inet_ntop(AF_INET, &nh->gate.ipv4, buf, size);
3840 if (nh->ifindex)
3841 strlcat(buf, ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3842 size);
3843 break;
3844 case NEXTHOP_TYPE_IPV6:
3845 case NEXTHOP_TYPE_IPV6_IFINDEX:
3846 inet_ntop(AF_INET6, &nh->gate.ipv6, buf, size);
3847 if (nh->ifindex)
3848 strlcat(buf,
3849 ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3850 size);
3851 break;
3852 case NEXTHOP_TYPE_IFINDEX:
3853 if (nh->ifindex)
3854 strlcat(buf,
3855 ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3856 size);
3857 break;
3858 case NEXTHOP_TYPE_BLACKHOLE:
3859 break;
3860 }
3861
3862 return buf;
3863 }
3864
3865 /*
3866 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
3867 */
3868 int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
3869 {
3870 struct zebra_lsp *lsp;
3871 struct zebra_nhlfe *nhlfe;
3872 struct nexthop *nh;
3873 struct listnode *node;
3874 struct list *slsp_list =
3875 hash_get_sorted_list(zvrf->slsp_table, lsp_cmp);
3876
3877 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, lsp)) {
3878 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3879 char buf[BUFSIZ];
3880 char lstr[30];
3881
3882 nh = nhlfe->nexthop;
3883 if (nh == NULL || nh->nh_label == NULL)
3884 continue;
3885
3886 nhlfe_config_str(nhlfe, buf, sizeof(buf));
3887
3888 switch (nh->nh_label->label[0]) {
3889 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
3890 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
3891 strlcpy(lstr, "explicit-null", sizeof(lstr));
3892 break;
3893 case MPLS_LABEL_IMPLICIT_NULL:
3894 strlcpy(lstr, "implicit-null", sizeof(lstr));
3895 break;
3896 default:
3897 snprintf(lstr, sizeof(lstr), "%u",
3898 nh->nh_label->label[0]);
3899 break;
3900 }
3901
3902 vty_out(vty, "mpls lsp %u %s %s\n", lsp->ile.in_label,
3903 buf, lstr);
3904 }
3905 }
3906
3907 list_delete(&slsp_list);
3908 return (zvrf->slsp_table->count ? 1 : 0);
3909 }
3910
3911 /*
3912 * Add/update global label block.
3913 */
3914 int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
3915 uint32_t end_label)
3916 {
3917 zvrf->mpls_srgb.start_label = start_label;
3918 zvrf->mpls_srgb.end_label = end_label;
3919
3920 /* Evaluate registered FECs to see if any get a label or not. */
3921 fec_evaluate(zvrf);
3922 return 0;
3923 }
3924
3925 /*
3926 * Delete global label block.
3927 */
3928 int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
3929 {
3930 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3931 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
3932
3933 /* Process registered FECs to clear their local label, if needed. */
3934 fec_evaluate(zvrf);
3935 return 0;
3936 }
3937
3938 /*
3939 * Display MPLS global label block configuration (VTY command handler).
3940 */
3941 int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
3942 {
3943 if (zvrf->mpls_srgb.start_label == 0)
3944 return 0;
3945
3946 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
3947 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
3948 vty_out(vty, "mpls label global-block %u %u\n",
3949 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
3950 }
3951
3952 return 1;
3953 }
3954
3955 /*
3956 * Called when VRF becomes inactive, cleans up information but keeps
3957 * the table itself.
3958 */
3959 void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
3960 {
3961 struct zebra_vrf *def_zvrf;
3962 afi_t afi;
3963
3964 if (zvrf_id(zvrf) == VRF_DEFAULT)
3965 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3966 else {
3967 /*
3968 * For other vrfs, we try to remove associated LSPs; we locate
3969 * the LSPs in the default vrf.
3970 */
3971 def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3972
3973 /* At shutdown, the default may be gone already */
3974 if (def_zvrf == NULL)
3975 return;
3976
3977 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
3978 if (zvrf->label[afi] != MPLS_LABEL_NONE)
3979 lsp_uninstall(def_zvrf, zvrf->label[afi]);
3980 }
3981 }
3982 }
3983
3984 /*
3985 * When a vrf label is assigned and the client goes away
3986 * we should cleanup the vrf labels associated with
3987 * that zclient.
3988 */
3989 void zebra_mpls_client_cleanup_vrf_label(uint8_t proto)
3990 {
3991 struct vrf *vrf;
3992 struct zebra_vrf *def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3993
3994 if (def_zvrf == NULL)
3995 return;
3996
3997 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
3998 struct zebra_vrf *zvrf = vrf->info;
3999 afi_t afi;
4000
4001 if (!zvrf)
4002 continue;
4003
4004 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4005 if (zvrf->label_proto[afi] == proto
4006 && zvrf->label[afi] != MPLS_LABEL_NONE)
4007 lsp_uninstall(def_zvrf, zvrf->label[afi]);
4008
4009 /*
4010 * Cleanup data structures by fiat
4011 */
4012 zvrf->label_proto[afi] = 0;
4013 zvrf->label[afi] = MPLS_LABEL_NONE;
4014 }
4015 }
4016 }
4017
4018 /*
4019 * Called upon process exiting, need to delete LSP forwarding
4020 * entries from the kernel.
4021 * NOTE: Currently supported only for default VRF.
4022 */
4023 void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
4024 {
4025 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
4026 hash_clean(zvrf->lsp_table, NULL);
4027 hash_free(zvrf->lsp_table);
4028 hash_clean(zvrf->slsp_table, NULL);
4029 hash_free(zvrf->slsp_table);
4030 route_table_finish(zvrf->fec_table[AFI_IP]);
4031 route_table_finish(zvrf->fec_table[AFI_IP6]);
4032 }
4033
4034 /*
4035 * Allocate MPLS tables for this VRF and do other initialization.
4036 * NOTE: Currently supported only for default VRF.
4037 */
4038 void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
4039 {
4040 char buffer[80];
4041
4042 if (!zvrf)
4043 return;
4044
4045 snprintf(buffer, sizeof(buffer), "ZEBRA SLSP table: %s",
4046 zvrf->vrf->name);
4047 zvrf->slsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
4048
4049 snprintf(buffer, sizeof(buffer), "ZEBRA LSP table: %s",
4050 zvrf->vrf->name);
4051 zvrf->lsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
4052 zvrf->fec_table[AFI_IP] = route_table_init();
4053 zvrf->fec_table[AFI_IP6] = route_table_init();
4054 zvrf->mpls_flags = 0;
4055 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
4056 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
4057 }
4058
4059 /*
4060 * Global MPLS initialization.
4061 */
4062 void zebra_mpls_init(void)
4063 {
4064 mpls_enabled = 0;
4065 mpls_pw_reach_strict = false;
4066
4067 if (mpls_kernel_init() < 0) {
4068 flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
4069 "Disabling MPLS support (no kernel support)");
4070 return;
4071 }
4072
4073 if (!mpls_processq_init())
4074 mpls_enabled = 1;
4075
4076 hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
4077 hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
4078 }