]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mpls.c
Merge pull request #4948 from opensourcerouting/show-mpls-table
[mirror_frr.git] / zebra / zebra_mpls.c
1 /* Zebra MPLS code
2 * Copyright (C) 2013 Cumulus Networks, Inc.
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "prefix.h"
24 #include "table.h"
25 #include "memory.h"
26 #include "command.h"
27 #include "if.h"
28 #include "log.h"
29 #include "sockunion.h"
30 #include "linklist.h"
31 #include "thread.h"
32 #include "workqueue.h"
33 #include "prefix.h"
34 #include "routemap.h"
35 #include "stream.h"
36 #include "nexthop.h"
37 #include "termtable.h"
38 #include "lib/json.h"
39
40 #include "zebra/rib.h"
41 #include "zebra/rt.h"
42 #include "zebra/interface.h"
43 #include "zebra/zserv.h"
44 #include "zebra/zebra_router.h"
45 #include "zebra/redistribute.h"
46 #include "zebra/debug.h"
47 #include "zebra/zebra_memory.h"
48 #include "zebra/zebra_vrf.h"
49 #include "zebra/zebra_mpls.h"
50 #include "zebra/zebra_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, SLSP, "MPLS static LSP config")
55 DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object")
56 DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE, "MPLS static nexthop object")
57 DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE_IFNAME, "MPLS static nexthop ifname")
58
59 int mpls_enabled;
60
61 /* static function declarations */
62
63 static void fec_evaluate(struct zebra_vrf *zvrf);
64 static uint32_t fec_derive_label_from_index(struct zebra_vrf *vrf,
65 zebra_fec_t *fec);
66 static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
67 struct route_node *rn, struct route_entry *re);
68 static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label);
69 static int fec_change_update_lsp(struct zebra_vrf *zvrf, zebra_fec_t *fec,
70 mpls_label_t old_label);
71 static int fec_send(zebra_fec_t *fec, struct zserv *client);
72 static void fec_update_clients(zebra_fec_t *fec);
73 static void fec_print(zebra_fec_t *fec, struct vty *vty);
74 static zebra_fec_t *fec_find(struct route_table *table, struct prefix *p);
75 static zebra_fec_t *fec_add(struct route_table *table, struct prefix *p,
76 mpls_label_t label, uint32_t flags,
77 uint32_t label_index);
78 static int fec_del(zebra_fec_t *fec);
79
80 static unsigned int label_hash(const void *p);
81 static bool label_cmp(const void *p1, const void *p2);
82 static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe,
83 struct nexthop *nexthop);
84 static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe,
85 struct nexthop *nexthop);
86 static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe);
87
88 static void lsp_select_best_nhlfe(zebra_lsp_t *lsp);
89 static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt);
90 static void lsp_schedule(struct hash_bucket *bucket, void *ctxt);
91 static wq_item_status lsp_process(struct work_queue *wq, void *data);
92 static void lsp_processq_del(struct work_queue *wq, void *data);
93 static void lsp_processq_complete(struct work_queue *wq);
94 static int lsp_processq_add(zebra_lsp_t *lsp);
95 static void *lsp_alloc(void *p);
96
97 static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size);
98 static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
99 union g_addr *gate, ifindex_t ifindex);
100 static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
101 enum nexthop_types_t gtype, union g_addr *gate,
102 ifindex_t ifindex);
103 static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
104 enum nexthop_types_t gtype, union g_addr *gate,
105 ifindex_t ifindex, mpls_label_t out_label);
106 static int nhlfe_del(zebra_nhlfe_t *snhlfe);
107 static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
108 struct mpls_label_stack *nh_label);
109 static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp,
110 enum lsp_types_t type);
111 static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
112 mpls_label_t in_label);
113 static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty);
114 static void lsp_print(zebra_lsp_t *lsp, void *ctxt);
115 static void *slsp_alloc(void *p);
116 static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
117 union g_addr *gate, ifindex_t ifindex);
118 static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
119 enum nexthop_types_t gtype,
120 union g_addr *gate, ifindex_t ifindex);
121 static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
122 enum nexthop_types_t gtype,
123 union g_addr *gate, ifindex_t ifindex,
124 mpls_label_t out_label);
125 static int snhlfe_del(zebra_snhlfe_t *snhlfe);
126 static int snhlfe_del_all(zebra_slsp_t *slsp);
127 static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size);
128
129
130 /* Static functions */
131
132 /*
133 * Handle failure in LSP install, clear flags for NHLFE.
134 */
135 static void clear_nhlfe_installed(zebra_lsp_t *lsp)
136 {
137 zebra_nhlfe_t *nhlfe;
138 struct nexthop *nexthop;
139
140 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
141 nexthop = nhlfe->nexthop;
142 if (!nexthop)
143 continue;
144
145 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
146 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
147 }
148 }
149
150 /*
151 * Install label forwarding entry based on labeled-route entry.
152 */
153 static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
154 struct route_node *rn, struct route_entry *re)
155 {
156 struct hash *lsp_table;
157 zebra_ile_t tmp_ile;
158 zebra_lsp_t *lsp;
159 zebra_nhlfe_t *nhlfe;
160 struct nexthop *nexthop;
161 enum lsp_types_t lsp_type;
162 char buf[BUFSIZ];
163 int added, changed;
164
165 /* Lookup table. */
166 lsp_table = zvrf->lsp_table;
167 if (!lsp_table)
168 return -1;
169
170 lsp_type = lsp_type_from_re_type(re->type);
171 added = changed = 0;
172
173 /* Locate or allocate LSP entry. */
174 tmp_ile.in_label = label;
175 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
176 if (!lsp)
177 return -1;
178
179 /* For each active nexthop, create NHLFE. Note that we deliberately skip
180 * recursive nexthops right now, because intermediate hops won't
181 * understand
182 * the label advertised by the recursive nexthop (plus we don't have the
183 * logic yet to push multiple labels).
184 */
185 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
186 /* Skip inactive and recursive entries. */
187 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
188 continue;
189 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
190 continue;
191
192 nhlfe = nhlfe_find(lsp, lsp_type, nexthop->type, &nexthop->gate,
193 nexthop->ifindex);
194 if (nhlfe) {
195 /* Clear deleted flag (in case it was set) */
196 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
197 if (nexthop_labels_match(nhlfe->nexthop, nexthop))
198 /* No change */
199 continue;
200
201
202 if (IS_ZEBRA_DEBUG_MPLS) {
203 nhlfe2str(nhlfe, buf, BUFSIZ);
204 zlog_debug(
205 "LSP in-label %u type %d nexthop %s "
206 "out-label changed",
207 lsp->ile.in_label, lsp_type, buf);
208 }
209
210 /* Update out label, trigger processing. */
211 nhlfe_out_label_update(nhlfe, nexthop->nh_label);
212 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
213 changed++;
214 } else {
215 /* Add LSP entry to this nexthop */
216 nhlfe = nhlfe_add(lsp, lsp_type, nexthop->type,
217 &nexthop->gate, nexthop->ifindex,
218 nexthop->nh_label->label[0]);
219 if (!nhlfe)
220 return -1;
221
222 if (IS_ZEBRA_DEBUG_MPLS) {
223 nhlfe2str(nhlfe, buf, BUFSIZ);
224 zlog_debug(
225 "Add LSP in-label %u type %d nexthop %s "
226 "out-label %u",
227 lsp->ile.in_label, lsp_type, buf,
228 nexthop->nh_label->label[0]);
229 }
230
231 lsp->addr_family = NHLFE_FAMILY(nhlfe);
232
233 /* Mark NHLFE as changed. */
234 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
235 added++;
236 }
237 }
238
239 /* Queue LSP for processing if necessary. If no NHLFE got added (special
240 * case), delete the LSP entry; this case results in somewhat ugly
241 * logging.
242 */
243 if (added || changed) {
244 if (lsp_processq_add(lsp))
245 return -1;
246 } else if (!lsp->nhlfe_list
247 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
248 if (IS_ZEBRA_DEBUG_MPLS)
249 zlog_debug("Free LSP in-label %u flags 0x%x",
250 lsp->ile.in_label, lsp->flags);
251
252 lsp = hash_release(lsp_table, &lsp->ile);
253 XFREE(MTYPE_LSP, lsp);
254 }
255
256 return 0;
257 }
258
259 /*
260 * Uninstall all non-static NHLFEs of a label forwarding entry. If all
261 * NHLFEs are removed, the entire entry is deleted.
262 */
263 static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label)
264 {
265 struct hash *lsp_table;
266 zebra_ile_t tmp_ile;
267 zebra_lsp_t *lsp;
268 zebra_nhlfe_t *nhlfe, *nhlfe_next;
269 char buf[BUFSIZ];
270
271 /* Lookup table. */
272 lsp_table = zvrf->lsp_table;
273 if (!lsp_table)
274 return -1;
275
276 /* If entry is not present, exit. */
277 tmp_ile.in_label = label;
278 lsp = hash_lookup(lsp_table, &tmp_ile);
279 if (!lsp || !lsp->nhlfe_list)
280 return 0;
281
282 /* Mark NHLFEs for delete or directly delete, as appropriate. */
283 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) {
284 nhlfe_next = nhlfe->next;
285
286 /* Skip static NHLFEs */
287 if (nhlfe->type == ZEBRA_LSP_STATIC)
288 continue;
289
290 if (IS_ZEBRA_DEBUG_MPLS) {
291 nhlfe2str(nhlfe, buf, BUFSIZ);
292 zlog_debug(
293 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
294 label, nhlfe->type, buf, nhlfe->flags);
295 }
296
297 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)) {
298 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
299 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
300 } else {
301 nhlfe_del(nhlfe);
302 }
303 }
304
305 /* Queue LSP for processing, if needed, else delete. */
306 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
307 if (lsp_processq_add(lsp))
308 return -1;
309 } else if (!lsp->nhlfe_list
310 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
311 if (IS_ZEBRA_DEBUG_MPLS)
312 zlog_debug("Del LSP in-label %u flags 0x%x",
313 lsp->ile.in_label, lsp->flags);
314
315 lsp = hash_release(lsp_table, &lsp->ile);
316 XFREE(MTYPE_LSP, lsp);
317 }
318
319 return 0;
320 }
321
322 /*
323 * This function is invoked upon change to label block configuration; it
324 * will walk all registered FECs with label-index and appropriately update
325 * their local labels and trigger client updates.
326 */
327 static void fec_evaluate(struct zebra_vrf *zvrf)
328 {
329 struct route_node *rn;
330 zebra_fec_t *fec;
331 uint32_t old_label, new_label;
332 int af;
333 char buf[BUFSIZ];
334
335 for (af = AFI_IP; af < AFI_MAX; af++) {
336 if (zvrf->fec_table[af] == NULL)
337 continue;
338
339 for (rn = route_top(zvrf->fec_table[af]); rn;
340 rn = route_next(rn)) {
341 if ((fec = rn->info) == NULL)
342 continue;
343
344 /* Skip configured FECs and those without a label index.
345 */
346 if (fec->flags & FEC_FLAG_CONFIGURED
347 || fec->label_index == MPLS_INVALID_LABEL_INDEX)
348 continue;
349
350 if (IS_ZEBRA_DEBUG_MPLS)
351 prefix2str(&rn->p, buf, BUFSIZ);
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 %s new label %u upon label block",
367 buf, 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 zebra_fec_t *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, zebra_fec_t *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(zebra_fec_t *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(zebra_fec_t *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(zebra_fec_t *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 prefix2str(&rn->p, buf, BUFSIZ);
497 vty_out(vty, "%s\n", buf);
498 vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
499 if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
500 vty_out(vty, ", Label Index: %u", fec->label_index);
501 vty_out(vty, "\n");
502 if (!list_isempty(fec->client_list)) {
503 vty_out(vty, " Client list:");
504 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
505 vty_out(vty, " %s(fd %d)",
506 zebra_route_string(client->proto),
507 client->sock);
508 vty_out(vty, "\n");
509 }
510 }
511
512 /*
513 * Locate FEC-label binding that matches with passed info.
514 */
515 static zebra_fec_t *fec_find(struct route_table *table, struct prefix *p)
516 {
517 struct route_node *rn;
518
519 apply_mask(p);
520 rn = route_node_lookup(table, p);
521 if (!rn)
522 return NULL;
523
524 route_unlock_node(rn);
525 return (rn->info);
526 }
527
528 /*
529 * Add a FEC. This may be upon a client registering for a binding
530 * or when a binding is configured.
531 */
532 static zebra_fec_t *fec_add(struct route_table *table, struct prefix *p,
533 mpls_label_t label, uint32_t flags,
534 uint32_t label_index)
535 {
536 struct route_node *rn;
537 zebra_fec_t *fec;
538
539 apply_mask(p);
540
541 /* Lookup (or add) route node.*/
542 rn = route_node_get(table, p);
543 if (!rn)
544 return NULL;
545
546 fec = rn->info;
547
548 if (!fec) {
549 fec = XCALLOC(MTYPE_FEC, sizeof(zebra_fec_t));
550
551 rn->info = fec;
552 fec->rn = rn;
553 fec->label = label;
554 fec->client_list = list_new();
555 } else
556 route_unlock_node(rn); /* for the route_node_get */
557
558 fec->label_index = label_index;
559 fec->flags = flags;
560
561 return fec;
562 }
563
564 /*
565 * Delete a FEC. This may be upon the last client deregistering for
566 * a FEC and no binding exists or when the binding is deleted and there
567 * are no registered clients.
568 */
569 static int fec_del(zebra_fec_t *fec)
570 {
571 list_delete(&fec->client_list);
572 fec->rn->info = NULL;
573 route_unlock_node(fec->rn);
574 XFREE(MTYPE_FEC, fec);
575 return 0;
576 }
577
578 /*
579 * Hash function for label.
580 */
581 static unsigned int label_hash(const void *p)
582 {
583 const zebra_ile_t *ile = p;
584
585 return (jhash_1word(ile->in_label, 0));
586 }
587
588 /*
589 * Compare 2 LSP hash entries based on in-label.
590 */
591 static bool label_cmp(const void *p1, const void *p2)
592 {
593 const zebra_ile_t *ile1 = p1;
594 const zebra_ile_t *ile2 = p2;
595
596 return (ile1->in_label == ile2->in_label);
597 }
598
599 /*
600 * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
601 * the passed flag.
602 * NOTE: Looking only for connected routes right now.
603 */
604 static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe,
605 struct nexthop *nexthop)
606 {
607 struct route_table *table;
608 struct prefix_ipv4 p;
609 struct route_node *rn;
610 struct route_entry *match;
611 struct nexthop *match_nh;
612
613 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, nexthop->vrf_id);
614 if (!table)
615 return 0;
616
617 /* Lookup nexthop in IPv4 routing table. */
618 memset(&p, 0, sizeof(struct prefix_ipv4));
619 p.family = AF_INET;
620 p.prefixlen = IPV4_MAX_PREFIXLEN;
621 p.prefix = nexthop->gate.ipv4;
622
623 rn = route_node_match(table, (struct prefix *)&p);
624 if (!rn)
625 return 0;
626
627 route_unlock_node(rn);
628
629 /* Locate a valid connected route. */
630 RNODE_FOREACH_RE (rn, match) {
631 if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
632 || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
633 continue;
634
635 for (match_nh = match->ng.nexthop; match_nh;
636 match_nh = match_nh->next) {
637 if (match->type == ZEBRA_ROUTE_CONNECT
638 || nexthop->ifindex == match_nh->ifindex) {
639 nexthop->ifindex = match_nh->ifindex;
640 return 1;
641 }
642 }
643 }
644
645 return 0;
646 }
647
648
649 /*
650 * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
651 * the passed flag.
652 * NOTE: Looking only for connected routes right now.
653 */
654 static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe,
655 struct nexthop *nexthop)
656 {
657 struct route_table *table;
658 struct prefix_ipv6 p;
659 struct route_node *rn;
660 struct route_entry *match;
661
662 table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
663 if (!table)
664 return 0;
665
666 /* Lookup nexthop in IPv6 routing table. */
667 memset(&p, 0, sizeof(struct prefix_ipv6));
668 p.family = AF_INET6;
669 p.prefixlen = IPV6_MAX_PREFIXLEN;
670 p.prefix = nexthop->gate.ipv6;
671
672 rn = route_node_match(table, (struct prefix *)&p);
673 if (!rn)
674 return 0;
675
676 route_unlock_node(rn);
677
678 /* Locate a valid connected route. */
679 RNODE_FOREACH_RE (rn, match) {
680 if ((match->type == ZEBRA_ROUTE_CONNECT)
681 && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
682 && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
683 break;
684 }
685
686 if (!match || !match->ng.nexthop)
687 return 0;
688
689 nexthop->ifindex = match->ng.nexthop->ifindex;
690 return 1;
691 }
692
693
694 /*
695 * Check the nexthop reachability for a NHLFE and return if valid (reachable)
696 * or not.
697 * NOTE: Each NHLFE points to only 1 nexthop.
698 */
699 static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe)
700 {
701 struct nexthop *nexthop;
702 struct interface *ifp;
703 struct zebra_ns *zns;
704
705 nexthop = nhlfe->nexthop;
706 if (!nexthop) // unexpected
707 return 0;
708
709 /* Check on nexthop based on type. */
710 switch (nexthop->type) {
711 case NEXTHOP_TYPE_IFINDEX:
712 /*
713 * Lookup if this type is special. The
714 * NEXTHOP_TYPE_IFINDEX is a pop and
715 * forward into a different table for
716 * processing. As such this ifindex
717 * passed to us may be a VRF device
718 * which will not be in the default
719 * VRF. So let's look in all of them
720 */
721 zns = zebra_ns_lookup(NS_DEFAULT);
722 ifp = if_lookup_by_index_per_ns(zns, nexthop->ifindex);
723 if (ifp && if_is_operative(ifp))
724 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
725 else
726 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
727 break;
728 case NEXTHOP_TYPE_IPV4:
729 case NEXTHOP_TYPE_IPV4_IFINDEX:
730 if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop))
731 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
732 else
733 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
734 break;
735
736 case NEXTHOP_TYPE_IPV6:
737 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
738 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
739 else
740 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
741 break;
742
743 case NEXTHOP_TYPE_IPV6_IFINDEX:
744 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
745 ifp = if_lookup_by_index(nexthop->ifindex,
746 nexthop->vrf_id);
747 if (ifp && if_is_operative(ifp))
748 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
749 else
750 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
751 } else {
752 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
753 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
754 else
755 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
756 }
757 break;
758
759 default:
760 break;
761 }
762
763 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
764 }
765
766 /*
767 * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
768 * reachability and select the best. Multipath entries are also
769 * marked. This is invoked when an LSP scheduled for processing (due
770 * to some change) is examined.
771 */
772 static void lsp_select_best_nhlfe(zebra_lsp_t *lsp)
773 {
774 zebra_nhlfe_t *nhlfe;
775 zebra_nhlfe_t *best;
776 struct nexthop *nexthop;
777 int changed = 0;
778
779 if (!lsp)
780 return;
781
782 best = NULL;
783 lsp->num_ecmp = 0;
784 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
785
786 /*
787 * First compute the best path, after checking nexthop status. We are
788 * only
789 * concerned with non-deleted NHLFEs.
790 */
791 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
792 /* Clear selection flags. */
793 UNSET_FLAG(nhlfe->flags,
794 (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
795
796 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
797 && nhlfe_nexthop_active(nhlfe)) {
798 if (!best || (nhlfe->distance < best->distance))
799 best = nhlfe;
800 }
801 }
802
803 lsp->best_nhlfe = best;
804 if (!lsp->best_nhlfe)
805 return;
806
807 /* Mark best NHLFE as selected. */
808 SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
809
810 /*
811 * If best path exists, see if there is ECMP. While doing this, note if
812 * a
813 * new (uninstalled) NHLFE has been selected, an installed entry that is
814 * still selected has a change or an installed entry is to be removed.
815 */
816 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
817 int nh_chg, nh_sel, nh_inst;
818
819 nexthop = nhlfe->nexthop;
820 if (!nexthop) // unexpected
821 continue;
822
823 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
824 && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
825 && (nhlfe->distance == lsp->best_nhlfe->distance)) {
826 SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
827 SET_FLAG(nhlfe->flags, NHLFE_FLAG_MULTIPATH);
828 lsp->num_ecmp++;
829 }
830
831 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) && !changed) {
832 nh_chg = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
833 nh_sel = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
834 nh_inst =
835 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
836
837 if ((nh_sel && !nh_inst)
838 || (nh_sel && nh_inst && nh_chg)
839 || (nh_inst && !nh_sel))
840 changed = 1;
841 }
842
843 /* We have finished examining, clear changed flag. */
844 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
845 }
846
847 if (changed)
848 SET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
849 }
850
851 /*
852 * Delete LSP forwarding entry from kernel, if installed. Called upon
853 * process exit.
854 */
855 static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt)
856 {
857 zebra_lsp_t *lsp;
858
859 lsp = (zebra_lsp_t *)bucket->data;
860 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
861 (void)dplane_lsp_delete(lsp);
862 }
863
864 /*
865 * Schedule LSP forwarding entry for processing. Called upon changes
866 * that may impact LSPs such as nexthop / connected route changes.
867 */
868 static void lsp_schedule(struct hash_bucket *bucket, void *ctxt)
869 {
870 zebra_lsp_t *lsp;
871
872 lsp = (zebra_lsp_t *)bucket->data;
873 (void)lsp_processq_add(lsp);
874 }
875
876 /*
877 * Process a LSP entry that is in the queue. Recalculate best NHLFE and
878 * any multipaths and update or delete from the kernel, as needed.
879 */
880 static wq_item_status lsp_process(struct work_queue *wq, void *data)
881 {
882 zebra_lsp_t *lsp;
883 zebra_nhlfe_t *oldbest, *newbest;
884 char buf[BUFSIZ], buf2[BUFSIZ];
885 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
886 enum zebra_dplane_result res;
887
888 lsp = (zebra_lsp_t *)data;
889 if (!lsp) // unexpected
890 return WQ_SUCCESS;
891
892 oldbest = lsp->best_nhlfe;
893
894 /* Select best NHLFE(s) */
895 lsp_select_best_nhlfe(lsp);
896
897 newbest = lsp->best_nhlfe;
898
899 if (IS_ZEBRA_DEBUG_MPLS) {
900 if (oldbest)
901 nhlfe2str(oldbest, buf, BUFSIZ);
902 if (newbest)
903 nhlfe2str(newbest, buf2, BUFSIZ);
904 zlog_debug(
905 "Process LSP in-label %u oldbest %s newbest %s "
906 "flags 0x%x ecmp# %d",
907 lsp->ile.in_label, oldbest ? buf : "NULL",
908 newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
909 }
910
911 if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
912 /* Not already installed */
913 if (newbest) {
914
915 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
916
917 switch (dplane_lsp_add(lsp)) {
918 case ZEBRA_DPLANE_REQUEST_QUEUED:
919 /* Set 'installed' flag so we will know
920 * that an install is in-flight.
921 */
922 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
923
924 zvrf->lsp_installs_queued++;
925 break;
926 case ZEBRA_DPLANE_REQUEST_FAILURE:
927 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
928 "LSP Install Failure: %u",
929 lsp->ile.in_label);
930 break;
931 case ZEBRA_DPLANE_REQUEST_SUCCESS:
932 zvrf->lsp_installs++;
933 break;
934 }
935 }
936 } else {
937 /* Installed, may need an update and/or delete. */
938 if (!newbest) {
939 res = dplane_lsp_delete(lsp);
940
941 /* We do some of the lsp cleanup immediately for
942 * deletes.
943 */
944 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
945 clear_nhlfe_installed(lsp);
946
947 switch (res) {
948 case ZEBRA_DPLANE_REQUEST_QUEUED:
949 zvrf->lsp_removals_queued++;
950 break;
951 case ZEBRA_DPLANE_REQUEST_FAILURE:
952 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
953 "LSP Deletion Failure: %u",
954 lsp->ile.in_label);
955 break;
956 case ZEBRA_DPLANE_REQUEST_SUCCESS:
957 zvrf->lsp_removals++;
958 break;
959 }
960 } else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) {
961 zebra_nhlfe_t *nhlfe;
962 struct nexthop *nexthop;
963
964 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
965
966 /* We leave the INSTALLED flag set here
967 * so we know an update in in-flight.
968 */
969
970 /*
971 * Any NHLFE that was installed but is not
972 * selected now needs to have its flags updated.
973 */
974 for (nhlfe = lsp->nhlfe_list; nhlfe;
975 nhlfe = nhlfe->next) {
976 nexthop = nhlfe->nexthop;
977 if (!nexthop)
978 continue;
979
980 if (CHECK_FLAG(nhlfe->flags,
981 NHLFE_FLAG_INSTALLED)
982 && !CHECK_FLAG(nhlfe->flags,
983 NHLFE_FLAG_SELECTED)) {
984 UNSET_FLAG(nhlfe->flags,
985 NHLFE_FLAG_INSTALLED);
986 UNSET_FLAG(nexthop->flags,
987 NEXTHOP_FLAG_FIB);
988 }
989 }
990
991 switch (dplane_lsp_update(lsp)) {
992 case ZEBRA_DPLANE_REQUEST_QUEUED:
993 zvrf->lsp_installs_queued++;
994 break;
995 case ZEBRA_DPLANE_REQUEST_FAILURE:
996 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
997 "LSP Update Failure: %u",
998 lsp->ile.in_label);
999 break;
1000 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1001 zvrf->lsp_installs++;
1002 break;
1003 }
1004 }
1005 }
1006
1007 return WQ_SUCCESS;
1008 }
1009
1010
1011 /*
1012 * Callback upon processing completion of a LSP forwarding entry.
1013 */
1014 static void lsp_processq_del(struct work_queue *wq, void *data)
1015 {
1016 struct zebra_vrf *zvrf;
1017 zebra_lsp_t *lsp;
1018 struct hash *lsp_table;
1019 zebra_nhlfe_t *nhlfe, *nhlfe_next;
1020
1021 zvrf = vrf_info_lookup(VRF_DEFAULT);
1022 assert(zvrf);
1023
1024 lsp_table = zvrf->lsp_table;
1025 if (!lsp_table) // unexpected
1026 return;
1027
1028 lsp = (zebra_lsp_t *)data;
1029 if (!lsp) // unexpected
1030 return;
1031
1032 /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
1033 * exist,
1034 * delete LSP entry also.
1035 */
1036 UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1037
1038 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) {
1039 nhlfe_next = nhlfe->next;
1040 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1041 nhlfe_del(nhlfe);
1042 }
1043
1044 if (!lsp->nhlfe_list) {
1045 if (IS_ZEBRA_DEBUG_MPLS)
1046 zlog_debug("Free LSP in-label %u flags 0x%x",
1047 lsp->ile.in_label, lsp->flags);
1048
1049 lsp = hash_release(lsp_table, &lsp->ile);
1050 XFREE(MTYPE_LSP, lsp);
1051 }
1052 }
1053
1054 /*
1055 * Callback upon finishing the processing of all scheduled
1056 * LSP forwarding entries.
1057 */
1058 static void lsp_processq_complete(struct work_queue *wq)
1059 {
1060 /* Nothing to do for now. */
1061 }
1062
1063 /*
1064 * Add LSP forwarding entry to queue for subsequent processing.
1065 */
1066 static int lsp_processq_add(zebra_lsp_t *lsp)
1067 {
1068 /* If already scheduled, exit. */
1069 if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1070 return 0;
1071
1072 if (zrouter.lsp_process_q == NULL) {
1073 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1074 "%s: work_queue does not exist!", __func__);
1075 return -1;
1076 }
1077
1078 work_queue_add(zrouter.lsp_process_q, lsp);
1079 SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1080 return 0;
1081 }
1082
1083 /*
1084 * Callback to allocate LSP forwarding table entry.
1085 */
1086 static void *lsp_alloc(void *p)
1087 {
1088 const zebra_ile_t *ile = p;
1089 zebra_lsp_t *lsp;
1090
1091 lsp = XCALLOC(MTYPE_LSP, sizeof(zebra_lsp_t));
1092 lsp->ile = *ile;
1093
1094 if (IS_ZEBRA_DEBUG_MPLS)
1095 zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label);
1096
1097 return ((void *)lsp);
1098 }
1099
1100 /*
1101 * Create printable string for NHLFE entry.
1102 */
1103 static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size)
1104 {
1105 struct nexthop *nexthop;
1106
1107 buf[0] = '\0';
1108 nexthop = nhlfe->nexthop;
1109 switch (nexthop->type) {
1110 case NEXTHOP_TYPE_IPV4:
1111 case NEXTHOP_TYPE_IPV4_IFINDEX:
1112 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
1113 break;
1114 case NEXTHOP_TYPE_IPV6:
1115 case NEXTHOP_TYPE_IPV6_IFINDEX:
1116 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
1117 break;
1118 case NEXTHOP_TYPE_IFINDEX:
1119 snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
1120 default:
1121 break;
1122 }
1123
1124 return buf;
1125 }
1126
1127 /*
1128 * Check if NHLFE matches with search info passed.
1129 */
1130 static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
1131 union g_addr *gate, ifindex_t ifindex)
1132 {
1133 struct nexthop *nhop;
1134 int cmp = 1;
1135
1136 nhop = nhlfe->nexthop;
1137 if (!nhop)
1138 return 1;
1139
1140 if (nhop->type != gtype)
1141 return 1;
1142
1143 switch (nhop->type) {
1144 case NEXTHOP_TYPE_IPV4:
1145 case NEXTHOP_TYPE_IPV4_IFINDEX:
1146 cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
1147 sizeof(struct in_addr));
1148 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1149 cmp = !(nhop->ifindex == ifindex);
1150 break;
1151 case NEXTHOP_TYPE_IPV6:
1152 case NEXTHOP_TYPE_IPV6_IFINDEX:
1153 cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
1154 sizeof(struct in6_addr));
1155 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1156 cmp = !(nhop->ifindex == ifindex);
1157 break;
1158 case NEXTHOP_TYPE_IFINDEX:
1159 cmp = !(nhop->ifindex == ifindex);
1160 break;
1161 default:
1162 break;
1163 }
1164
1165 return cmp;
1166 }
1167
1168
1169 /*
1170 * Locate NHLFE that matches with passed info.
1171 */
1172 static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
1173 enum nexthop_types_t gtype, union g_addr *gate,
1174 ifindex_t ifindex)
1175 {
1176 zebra_nhlfe_t *nhlfe;
1177
1178 if (!lsp)
1179 return NULL;
1180
1181 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1182 if (nhlfe->type != lsp_type)
1183 continue;
1184 if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex))
1185 break;
1186 }
1187
1188 return nhlfe;
1189 }
1190
1191 /*
1192 * Add NHLFE. Base entry must have been created and duplicate
1193 * check done.
1194 */
1195 static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
1196 enum nexthop_types_t gtype, union g_addr *gate,
1197 ifindex_t ifindex, mpls_label_t out_label)
1198 {
1199 zebra_nhlfe_t *nhlfe;
1200 struct nexthop *nexthop;
1201
1202 if (!lsp)
1203 return NULL;
1204
1205 nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(zebra_nhlfe_t));
1206
1207 nhlfe->lsp = lsp;
1208 nhlfe->type = lsp_type;
1209 nhlfe->distance = lsp_distance(lsp_type);
1210
1211 nexthop = nexthop_new();
1212 if (!nexthop) {
1213 XFREE(MTYPE_NHLFE, nhlfe);
1214 return NULL;
1215 }
1216 nexthop_add_labels(nexthop, lsp_type, 1, &out_label);
1217
1218 nexthop->vrf_id = VRF_DEFAULT;
1219 nexthop->type = gtype;
1220 switch (nexthop->type) {
1221 case NEXTHOP_TYPE_IPV4:
1222 case NEXTHOP_TYPE_IPV4_IFINDEX:
1223 nexthop->gate.ipv4 = gate->ipv4;
1224 if (ifindex)
1225 nexthop->ifindex = ifindex;
1226 break;
1227 case NEXTHOP_TYPE_IPV6:
1228 case NEXTHOP_TYPE_IPV6_IFINDEX:
1229 nexthop->gate.ipv6 = gate->ipv6;
1230 if (ifindex)
1231 nexthop->ifindex = ifindex;
1232 break;
1233 case NEXTHOP_TYPE_IFINDEX:
1234 nexthop->ifindex = ifindex;
1235 break;
1236 default:
1237 nexthop_free(nexthop);
1238 XFREE(MTYPE_NHLFE, nhlfe);
1239 return NULL;
1240 break;
1241 }
1242
1243 nhlfe->nexthop = nexthop;
1244 if (lsp->nhlfe_list)
1245 lsp->nhlfe_list->prev = nhlfe;
1246 nhlfe->next = lsp->nhlfe_list;
1247 lsp->nhlfe_list = nhlfe;
1248
1249 return nhlfe;
1250 }
1251
1252 /*
1253 * Delete NHLFE. Entry must be present on list.
1254 */
1255 static int nhlfe_del(zebra_nhlfe_t *nhlfe)
1256 {
1257 zebra_lsp_t *lsp;
1258
1259 if (!nhlfe)
1260 return -1;
1261
1262 lsp = nhlfe->lsp;
1263 if (!lsp)
1264 return -1;
1265
1266 /* Free nexthop. */
1267 if (nhlfe->nexthop)
1268 nexthop_free(nhlfe->nexthop);
1269
1270 /* Unlink from LSP */
1271 if (nhlfe->next)
1272 nhlfe->next->prev = nhlfe->prev;
1273 if (nhlfe->prev)
1274 nhlfe->prev->next = nhlfe->next;
1275 else
1276 lsp->nhlfe_list = nhlfe->next;
1277
1278 if (nhlfe == lsp->best_nhlfe)
1279 lsp->best_nhlfe = NULL;
1280
1281 XFREE(MTYPE_NHLFE, nhlfe);
1282
1283 return 0;
1284 }
1285
1286 /*
1287 * Update label for NHLFE entry.
1288 */
1289 static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
1290 struct mpls_label_stack *nh_label)
1291 {
1292 nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
1293 }
1294
1295 static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp,
1296 enum lsp_types_t type)
1297 {
1298 zebra_nhlfe_t *nhlfe, *nhlfe_next;
1299 int schedule_lsp = 0;
1300 char buf[BUFSIZ];
1301
1302 /* Mark NHLFEs for delete or directly delete, as appropriate. */
1303 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) {
1304 nhlfe_next = nhlfe->next;
1305
1306 /* Skip non-static NHLFEs */
1307 if (nhlfe->type != type)
1308 continue;
1309
1310 if (IS_ZEBRA_DEBUG_MPLS) {
1311 nhlfe2str(nhlfe, buf, BUFSIZ);
1312 zlog_debug(
1313 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
1314 lsp->ile.in_label, type, buf, nhlfe->flags);
1315 }
1316
1317 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1318 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1319 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1320 schedule_lsp = 1;
1321 } else {
1322 nhlfe_del(nhlfe);
1323 }
1324 }
1325
1326 /* Queue LSP for processing, if needed, else delete. */
1327 if (schedule_lsp) {
1328 if (lsp_processq_add(lsp))
1329 return -1;
1330 } else if (!lsp->nhlfe_list
1331 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
1332 if (IS_ZEBRA_DEBUG_MPLS)
1333 zlog_debug("Free LSP in-label %u flags 0x%x",
1334 lsp->ile.in_label, lsp->flags);
1335
1336 lsp = hash_release(lsp_table, &lsp->ile);
1337 XFREE(MTYPE_LSP, lsp);
1338 }
1339
1340 return 0;
1341 }
1342
1343 /*
1344 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
1345 * If no other NHLFEs exist, the entry would be deleted.
1346 */
1347 static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
1348 mpls_label_t in_label)
1349 {
1350 struct hash *lsp_table;
1351 zebra_ile_t tmp_ile;
1352 zebra_lsp_t *lsp;
1353
1354 /* Lookup table. */
1355 lsp_table = zvrf->lsp_table;
1356 if (!lsp_table)
1357 return -1;
1358
1359 /* If entry is not present, exit. */
1360 tmp_ile.in_label = in_label;
1361 lsp = hash_lookup(lsp_table, &tmp_ile);
1362 if (!lsp || !lsp->nhlfe_list)
1363 return 0;
1364
1365 return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC);
1366 }
1367
1368 static json_object *nhlfe_json(zebra_nhlfe_t *nhlfe)
1369 {
1370 char buf[BUFSIZ];
1371 json_object *json_nhlfe = NULL;
1372 struct nexthop *nexthop = nhlfe->nexthop;
1373
1374 json_nhlfe = json_object_new_object();
1375 json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
1376 json_object_int_add(json_nhlfe, "outLabel",
1377 nexthop->nh_label->label[0]);
1378 json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
1379
1380 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
1381 json_object_boolean_true_add(json_nhlfe, "installed");
1382
1383 switch (nexthop->type) {
1384 case NEXTHOP_TYPE_IPV4:
1385 case NEXTHOP_TYPE_IPV4_IFINDEX:
1386 json_object_string_add(json_nhlfe, "nexthop",
1387 inet_ntoa(nexthop->gate.ipv4));
1388 break;
1389 case NEXTHOP_TYPE_IPV6:
1390 case NEXTHOP_TYPE_IPV6_IFINDEX:
1391 json_object_string_add(
1392 json_nhlfe, "nexthop",
1393 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1394
1395 if (nexthop->ifindex)
1396 json_object_string_add(json_nhlfe, "interface",
1397 ifindex2ifname(nexthop->ifindex,
1398 nexthop->vrf_id));
1399 break;
1400 default:
1401 break;
1402 }
1403 return json_nhlfe;
1404 }
1405
1406 /*
1407 * Print the NHLFE for a LSP forwarding entry.
1408 */
1409 static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty)
1410 {
1411 struct nexthop *nexthop;
1412 char buf[BUFSIZ];
1413
1414 nexthop = nhlfe->nexthop;
1415 if (!nexthop || !nexthop->nh_label) // unexpected
1416 return;
1417
1418 vty_out(vty, " type: %s remote label: %s distance: %d\n",
1419 nhlfe_type2str(nhlfe->type),
1420 label2str(nexthop->nh_label->label[0], buf, BUFSIZ),
1421 nhlfe->distance);
1422 switch (nexthop->type) {
1423 case NEXTHOP_TYPE_IPV4:
1424 case NEXTHOP_TYPE_IPV4_IFINDEX:
1425 vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
1426 if (nexthop->ifindex)
1427 vty_out(vty, " dev %s",
1428 ifindex2ifname(nexthop->ifindex,
1429 nexthop->vrf_id));
1430 break;
1431 case NEXTHOP_TYPE_IPV6:
1432 case NEXTHOP_TYPE_IPV6_IFINDEX:
1433 vty_out(vty, " via %s",
1434 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1435 if (nexthop->ifindex)
1436 vty_out(vty, " dev %s",
1437 ifindex2ifname(nexthop->ifindex,
1438 nexthop->vrf_id));
1439 break;
1440 default:
1441 break;
1442 }
1443 vty_out(vty, "%s",
1444 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
1445 : "");
1446 vty_out(vty, "\n");
1447 }
1448
1449 /*
1450 * Print an LSP forwarding entry.
1451 */
1452 static void lsp_print(zebra_lsp_t *lsp, void *ctxt)
1453 {
1454 zebra_nhlfe_t *nhlfe;
1455 struct vty *vty;
1456
1457 vty = (struct vty *)ctxt;
1458
1459 vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label,
1460 CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)"
1461 : "");
1462
1463 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1464 nhlfe_print(nhlfe, vty);
1465 }
1466
1467 /*
1468 * JSON objects for an LSP forwarding entry.
1469 */
1470 static json_object *lsp_json(zebra_lsp_t *lsp)
1471 {
1472 zebra_nhlfe_t *nhlfe = NULL;
1473 json_object *json = json_object_new_object();
1474 json_object *json_nhlfe_list = json_object_new_array();
1475
1476 json_object_int_add(json, "inLabel", lsp->ile.in_label);
1477
1478 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1479 json_object_boolean_true_add(json, "installed");
1480
1481 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1482 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1483
1484 json_object_object_add(json, "nexthops", json_nhlfe_list);
1485 return json;
1486 }
1487
1488
1489 /* Return a sorted linked list of the hash contents */
1490 static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
1491 {
1492 unsigned int i;
1493 struct hash_bucket *hb;
1494 struct list *sorted_list = list_new();
1495
1496 sorted_list->cmp = (int (*)(void *, void *))cmp;
1497
1498 for (i = 0; i < hash->size; i++)
1499 for (hb = hash->index[i]; hb; hb = hb->next)
1500 listnode_add_sort(sorted_list, hb->data);
1501
1502 return sorted_list;
1503 }
1504
1505 /*
1506 * Compare two LSPs based on their label values.
1507 */
1508 static int lsp_cmp(zebra_lsp_t *lsp1, zebra_lsp_t *lsp2)
1509 {
1510 if (lsp1->ile.in_label < lsp2->ile.in_label)
1511 return -1;
1512
1513 if (lsp1->ile.in_label > lsp2->ile.in_label)
1514 return 1;
1515
1516 return 0;
1517 }
1518
1519 /*
1520 * Callback to allocate static LSP.
1521 */
1522 static void *slsp_alloc(void *p)
1523 {
1524 const zebra_ile_t *ile = p;
1525 zebra_slsp_t *slsp;
1526
1527 slsp = XCALLOC(MTYPE_SLSP, sizeof(zebra_slsp_t));
1528 slsp->ile = *ile;
1529 return ((void *)slsp);
1530 }
1531
1532 /*
1533 * Compare two static LSPs based on their label values.
1534 */
1535 static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
1536 {
1537 if (slsp1->ile.in_label < slsp2->ile.in_label)
1538 return -1;
1539
1540 if (slsp1->ile.in_label > slsp2->ile.in_label)
1541 return 1;
1542
1543 return 0;
1544 }
1545
1546 /*
1547 * Check if static NHLFE matches with search info passed.
1548 */
1549 static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
1550 union g_addr *gate, ifindex_t ifindex)
1551 {
1552 int cmp = 1;
1553
1554 if (snhlfe->gtype != gtype)
1555 return 1;
1556
1557 switch (snhlfe->gtype) {
1558 case NEXTHOP_TYPE_IPV4:
1559 cmp = memcmp(&(snhlfe->gate.ipv4), &(gate->ipv4),
1560 sizeof(struct in_addr));
1561 break;
1562 case NEXTHOP_TYPE_IPV6:
1563 case NEXTHOP_TYPE_IPV6_IFINDEX:
1564 cmp = memcmp(&(snhlfe->gate.ipv6), &(gate->ipv6),
1565 sizeof(struct in6_addr));
1566 if (!cmp && snhlfe->gtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1567 cmp = !(snhlfe->ifindex == ifindex);
1568 break;
1569 default:
1570 break;
1571 }
1572
1573 return cmp;
1574 }
1575
1576 /*
1577 * Locate static NHLFE that matches with passed info.
1578 */
1579 static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
1580 enum nexthop_types_t gtype,
1581 union g_addr *gate, ifindex_t ifindex)
1582 {
1583 zebra_snhlfe_t *snhlfe;
1584
1585 if (!slsp)
1586 return NULL;
1587
1588 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next) {
1589 if (!snhlfe_match(snhlfe, gtype, gate, ifindex))
1590 break;
1591 }
1592
1593 return snhlfe;
1594 }
1595
1596
1597 /*
1598 * Add static NHLFE. Base LSP config entry must have been created
1599 * and duplicate check done.
1600 */
1601 static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
1602 enum nexthop_types_t gtype,
1603 union g_addr *gate, ifindex_t ifindex,
1604 mpls_label_t out_label)
1605 {
1606 zebra_snhlfe_t *snhlfe;
1607
1608 if (!slsp)
1609 return NULL;
1610
1611 snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t));
1612 snhlfe->slsp = slsp;
1613 snhlfe->out_label = out_label;
1614 snhlfe->gtype = gtype;
1615 switch (gtype) {
1616 case NEXTHOP_TYPE_IPV4:
1617 snhlfe->gate.ipv4 = gate->ipv4;
1618 break;
1619 case NEXTHOP_TYPE_IPV6:
1620 case NEXTHOP_TYPE_IPV6_IFINDEX:
1621 snhlfe->gate.ipv6 = gate->ipv6;
1622 if (ifindex)
1623 snhlfe->ifindex = ifindex;
1624 break;
1625 default:
1626 XFREE(MTYPE_SNHLFE, snhlfe);
1627 return NULL;
1628 }
1629
1630 if (slsp->snhlfe_list)
1631 slsp->snhlfe_list->prev = snhlfe;
1632 snhlfe->next = slsp->snhlfe_list;
1633 slsp->snhlfe_list = snhlfe;
1634
1635 return snhlfe;
1636 }
1637
1638 /*
1639 * Delete static NHLFE. Entry must be present on list.
1640 */
1641 static int snhlfe_del(zebra_snhlfe_t *snhlfe)
1642 {
1643 zebra_slsp_t *slsp;
1644
1645 if (!snhlfe)
1646 return -1;
1647
1648 slsp = snhlfe->slsp;
1649 if (!slsp)
1650 return -1;
1651
1652 if (snhlfe->next)
1653 snhlfe->next->prev = snhlfe->prev;
1654 if (snhlfe->prev)
1655 snhlfe->prev->next = snhlfe->next;
1656 else
1657 slsp->snhlfe_list = snhlfe->next;
1658
1659 snhlfe->prev = snhlfe->next = NULL;
1660 XFREE(MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
1661 XFREE(MTYPE_SNHLFE, snhlfe);
1662
1663 return 0;
1664 }
1665
1666 /*
1667 * Delete all static NHLFE entries for this LSP (in label).
1668 */
1669 static int snhlfe_del_all(zebra_slsp_t *slsp)
1670 {
1671 zebra_snhlfe_t *snhlfe, *snhlfe_next;
1672
1673 if (!slsp)
1674 return -1;
1675
1676 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next) {
1677 snhlfe_next = snhlfe->next;
1678 snhlfe_del(snhlfe);
1679 }
1680
1681 return 0;
1682 }
1683
1684 /*
1685 * Create printable string for NHLFE configuration.
1686 */
1687 static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size)
1688 {
1689 buf[0] = '\0';
1690 switch (snhlfe->gtype) {
1691 case NEXTHOP_TYPE_IPV4:
1692 inet_ntop(AF_INET, &snhlfe->gate.ipv4, buf, size);
1693 break;
1694 case NEXTHOP_TYPE_IPV6:
1695 case NEXTHOP_TYPE_IPV6_IFINDEX:
1696 inet_ntop(AF_INET6, &snhlfe->gate.ipv6, buf, size);
1697 if (snhlfe->ifindex)
1698 strlcat(buf,
1699 ifindex2ifname(snhlfe->ifindex, VRF_DEFAULT),
1700 size);
1701 break;
1702 default:
1703 break;
1704 }
1705
1706 return buf;
1707 }
1708
1709 /*
1710 * Initialize work queue for processing changed LSPs.
1711 */
1712 static int mpls_processq_init(void)
1713 {
1714 zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
1715 if (!zrouter.lsp_process_q) {
1716 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1717 "%s: could not initialise work queue!", __func__);
1718 return -1;
1719 }
1720
1721 zrouter.lsp_process_q->spec.workfunc = &lsp_process;
1722 zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
1723 zrouter.lsp_process_q->spec.errorfunc = NULL;
1724 zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
1725 zrouter.lsp_process_q->spec.max_retries = 0;
1726 zrouter.lsp_process_q->spec.hold = 10;
1727
1728 return 0;
1729 }
1730
1731
1732 /* Public functions */
1733
1734 /*
1735 * Process LSP update results from zebra dataplane.
1736 */
1737 void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
1738 {
1739 struct zebra_vrf *zvrf;
1740 zebra_ile_t tmp_ile;
1741 struct hash *lsp_table;
1742 zebra_lsp_t *lsp;
1743 zebra_nhlfe_t *nhlfe;
1744 struct nexthop *nexthop;
1745 enum dplane_op_e op;
1746 enum zebra_dplane_result status;
1747
1748 op = dplane_ctx_get_op(ctx);
1749 status = dplane_ctx_get_status(ctx);
1750
1751 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1752 zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
1753 ctx, dplane_op2str(op),
1754 dplane_ctx_get_in_label(ctx),
1755 dplane_res2str(status));
1756
1757 switch (op) {
1758 case DPLANE_OP_LSP_INSTALL:
1759 case DPLANE_OP_LSP_UPDATE:
1760 /* Look for zebra LSP object */
1761 zvrf = vrf_info_lookup(VRF_DEFAULT);
1762 if (zvrf == NULL)
1763 break;
1764
1765 lsp_table = zvrf->lsp_table;
1766
1767 tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
1768 lsp = hash_lookup(lsp_table, &tmp_ile);
1769 if (lsp == NULL) {
1770 if (IS_ZEBRA_DEBUG_DPLANE)
1771 zlog_debug("LSP ctx %p: in-label %u not found",
1772 ctx, dplane_ctx_get_in_label(ctx));
1773 break;
1774 }
1775
1776 /* TODO -- Confirm that this result is still 'current' */
1777
1778 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1779 /* Update zebra object */
1780 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1781 for (nhlfe = lsp->nhlfe_list; nhlfe;
1782 nhlfe = nhlfe->next) {
1783 nexthop = nhlfe->nexthop;
1784 if (!nexthop)
1785 continue;
1786
1787 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1788 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1789 }
1790 } else {
1791 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1792 clear_nhlfe_installed(lsp);
1793 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1794 "LSP Install Failure: in-label %u",
1795 lsp->ile.in_label);
1796 }
1797
1798 break;
1799
1800 case DPLANE_OP_LSP_DELETE:
1801 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
1802 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
1803 "LSP Deletion Failure: in-label %u",
1804 dplane_ctx_get_in_label(ctx));
1805 break;
1806
1807 default:
1808 break;
1809
1810 } /* Switch */
1811
1812 dplane_ctx_fini(&ctx);
1813 }
1814
1815 /*
1816 * Process async dplane notifications.
1817 */
1818 void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
1819 {
1820 struct zebra_vrf *zvrf;
1821 zebra_ile_t tmp_ile;
1822 struct hash *lsp_table;
1823 zebra_lsp_t *lsp;
1824 zebra_nhlfe_t *nhlfe;
1825 const zebra_nhlfe_t *ctx_nhlfe;
1826 struct nexthop *nexthop;
1827 const struct nexthop *ctx_nexthop;
1828 int start_count = 0, end_count = 0; /* Installed counts */
1829 bool changed_p = false;
1830 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1831
1832 if (is_debug)
1833 zlog_debug("LSP dplane notif, in-label %u",
1834 dplane_ctx_get_in_label(ctx));
1835
1836 /* Look for zebra LSP object */
1837 zvrf = vrf_info_lookup(VRF_DEFAULT);
1838 if (zvrf == NULL)
1839 goto done;
1840
1841 lsp_table = zvrf->lsp_table;
1842
1843 tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
1844 lsp = hash_lookup(lsp_table, &tmp_ile);
1845 if (lsp == NULL) {
1846 if (is_debug)
1847 zlog_debug("dplane LSP notif: in-label %u not found",
1848 dplane_ctx_get_in_label(ctx));
1849 goto done;
1850 }
1851
1852 /*
1853 * The dataplane/forwarding plane is notifying zebra about the state
1854 * of the nexthops associated with this LSP. First, we take a
1855 * pre-scan pass to determine whether the LSP has transitioned
1856 * from installed -> uninstalled. In that case, we need to have
1857 * the existing state of the LSP objects available before making
1858 * any changes.
1859 */
1860 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1861 char buf[NEXTHOP_STRLEN];
1862
1863 nexthop = nhlfe->nexthop;
1864 if (!nexthop)
1865 continue;
1866
1867 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
1868 start_count++;
1869
1870 ctx_nexthop = NULL;
1871 for (ctx_nhlfe = dplane_ctx_get_nhlfe(ctx);
1872 ctx_nhlfe; ctx_nhlfe = ctx_nhlfe->next) {
1873
1874 ctx_nexthop = ctx_nhlfe->nexthop;
1875 if (!ctx_nexthop)
1876 continue;
1877
1878 if ((ctx_nexthop->type == nexthop->type) &&
1879 nexthop_same(ctx_nexthop, nexthop)) {
1880 /* Matched */
1881 break;
1882 }
1883 }
1884
1885 if (is_debug)
1886 nexthop2str(nexthop, buf, sizeof(buf));
1887
1888 if (ctx_nhlfe && ctx_nexthop) {
1889 if (is_debug) {
1890 const char *tstr = "";
1891
1892 if (!CHECK_FLAG(ctx_nhlfe->flags,
1893 NHLFE_FLAG_INSTALLED))
1894 tstr = "not ";
1895
1896 zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
1897 buf, tstr);
1898 }
1899
1900 /* Test zebra nhlfe install state */
1901 if (CHECK_FLAG(ctx_nhlfe->flags,
1902 NHLFE_FLAG_INSTALLED)) {
1903
1904 if (!CHECK_FLAG(nhlfe->flags,
1905 NHLFE_FLAG_INSTALLED))
1906 changed_p = true;
1907
1908 /* Update counter */
1909 end_count++;
1910 } else {
1911
1912 if (CHECK_FLAG(nhlfe->flags,
1913 NHLFE_FLAG_INSTALLED))
1914 changed_p = true;
1915 }
1916
1917 } else {
1918 /* Not mentioned in lfib set -> uninstalled */
1919 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ||
1920 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ||
1921 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
1922 changed_p = true;
1923 }
1924
1925 if (is_debug)
1926 zlog_debug("LSP dplane notif: no match, nh %s",
1927 buf);
1928 }
1929 }
1930
1931 if (is_debug)
1932 zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
1933 start_count, end_count,
1934 changed_p ? ", changed" : "");
1935
1936 /*
1937 * Has the LSP become uninstalled?
1938 */
1939 if (start_count > 0 && end_count == 0) {
1940 /* Inform other lfibs */
1941 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
1942 }
1943
1944 /*
1945 * Now we take a second pass and bring the zebra
1946 * nexthop state into sync with the forwarding-plane state.
1947 */
1948 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1949 char buf[NEXTHOP_STRLEN];
1950
1951 nexthop = nhlfe->nexthop;
1952 if (!nexthop)
1953 continue;
1954
1955 ctx_nexthop = NULL;
1956 for (ctx_nhlfe = dplane_ctx_get_nhlfe(ctx);
1957 ctx_nhlfe; ctx_nhlfe = ctx_nhlfe->next) {
1958
1959 ctx_nexthop = ctx_nhlfe->nexthop;
1960 if (!ctx_nexthop)
1961 continue;
1962
1963 if ((ctx_nexthop->type == nexthop->type) &&
1964 nexthop_same(ctx_nexthop, nexthop)) {
1965 /* Matched */
1966 break;
1967 }
1968 }
1969
1970 if (is_debug)
1971 nexthop2str(nexthop, buf, sizeof(buf));
1972
1973 if (ctx_nhlfe && ctx_nexthop) {
1974
1975 /* Bring zebra nhlfe install state into sync */
1976 if (CHECK_FLAG(ctx_nhlfe->flags,
1977 NHLFE_FLAG_INSTALLED)) {
1978
1979 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1980
1981 } else {
1982
1983 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1984 }
1985
1986 if (CHECK_FLAG(ctx_nhlfe->nexthop->flags,
1987 NEXTHOP_FLAG_FIB)) {
1988 SET_FLAG(nhlfe->nexthop->flags,
1989 NEXTHOP_FLAG_ACTIVE);
1990 SET_FLAG(nhlfe->nexthop->flags,
1991 NEXTHOP_FLAG_FIB);
1992 } else {
1993 UNSET_FLAG(nhlfe->nexthop->flags,
1994 NEXTHOP_FLAG_ACTIVE);
1995 UNSET_FLAG(nhlfe->nexthop->flags,
1996 NEXTHOP_FLAG_FIB);
1997 }
1998
1999 } else {
2000 /* Not mentioned in lfib set -> uninstalled */
2001
2002 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2003 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
2004 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2005 }
2006 }
2007
2008 if (end_count > 0) {
2009 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2010
2011 if (changed_p)
2012 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
2013
2014 } else {
2015 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2016 clear_nhlfe_installed(lsp);
2017 }
2018
2019 done:
2020 dplane_ctx_fini(&ctx);
2021 }
2022
2023 /*
2024 * Install dynamic LSP entry.
2025 */
2026 int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
2027 struct route_entry *re)
2028 {
2029 struct route_table *table;
2030 zebra_fec_t *fec;
2031
2032 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2033 if (!table)
2034 return -1;
2035
2036 /* See if there is a configured label binding for this FEC. */
2037 fec = fec_find(table, &rn->p);
2038 if (!fec || fec->label == MPLS_INVALID_LABEL)
2039 return 0;
2040
2041 /* We cannot install a label forwarding entry if local label is the
2042 * implicit-null label.
2043 */
2044 if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
2045 return 0;
2046
2047 if (lsp_install(zvrf, fec->label, rn, re))
2048 return -1;
2049
2050 return 0;
2051 }
2052
2053 /*
2054 * Uninstall dynamic LSP entry, if any.
2055 */
2056 int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
2057 struct route_entry *re)
2058 {
2059 struct route_table *table;
2060 zebra_fec_t *fec;
2061
2062 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2063 if (!table)
2064 return -1;
2065
2066 /* See if there is a configured label binding for this FEC. */
2067 fec = fec_find(table, &rn->p);
2068 if (!fec || fec->label == MPLS_INVALID_LABEL)
2069 return 0;
2070
2071 /* Uninstall always removes all dynamic NHLFEs. */
2072 return lsp_uninstall(zvrf, fec->label);
2073 }
2074
2075 /*
2076 * Add an NHLFE to an LSP, return the newly-added object
2077 */
2078 zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
2079 enum lsp_types_t lsp_type,
2080 enum nexthop_types_t gtype,
2081 union g_addr *gate,
2082 ifindex_t ifindex,
2083 mpls_label_t out_label)
2084 {
2085 /* Just a public pass-through to the internal implementation */
2086 return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, out_label);
2087 }
2088
2089 /*
2090 * Free an allocated NHLFE
2091 */
2092 void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe)
2093 {
2094 /* Just a pass-through to the internal implementation */
2095 nhlfe_del(nhlfe);
2096 }
2097
2098 /*
2099 * Registration from a client for the label binding for a FEC. If a binding
2100 * already exists, it is informed to the client.
2101 * NOTE: If there is a manually configured label binding, that is used.
2102 * Otherwise, if a label index is specified, it means we have to allocate the
2103 * label from a locally configured label block (SRGB), if one exists and index
2104 * is acceptable. If no label index then just register the specified label.
2105 * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
2106 * by the calling function. Register requests with both will be rejected.
2107 */
2108 int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
2109 uint32_t label, uint32_t label_index,
2110 struct zserv *client)
2111 {
2112 struct route_table *table;
2113 zebra_fec_t *fec;
2114 char buf[BUFSIZ];
2115 bool new_client;
2116 bool label_change = false;
2117 uint32_t old_label;
2118 bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
2119 bool is_configured_fec = false; /* indicate statically configured FEC */
2120
2121 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2122 if (!table)
2123 return -1;
2124
2125 if (IS_ZEBRA_DEBUG_MPLS)
2126 prefix2str(p, buf, BUFSIZ);
2127
2128 if (label != MPLS_INVALID_LABEL && have_label_index) {
2129 flog_err(
2130 EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
2131 "Rejecting FEC register for %s with both label %u and Label Index %u specified, client %s",
2132 buf, label, label_index,
2133 zebra_route_string(client->proto));
2134 return -1;
2135 }
2136
2137 /* Locate FEC */
2138 fec = fec_find(table, p);
2139 if (!fec) {
2140 fec = fec_add(table, p, label, 0, label_index);
2141 if (!fec) {
2142 flog_err(
2143 EC_ZEBRA_FEC_ADD_FAILED,
2144 "Failed to add FEC %s upon register, client %s",
2145 buf, zebra_route_string(client->proto));
2146 return -1;
2147 }
2148
2149 old_label = MPLS_INVALID_LABEL;
2150 new_client = true;
2151 } else {
2152 /* Check if the FEC has been statically defined in the config */
2153 is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
2154 /* Client may register same FEC with different label index. */
2155 new_client =
2156 (listnode_lookup(fec->client_list, client) == NULL);
2157 if (!new_client && fec->label_index == label_index
2158 && fec->label == label)
2159 /* Duplicate register */
2160 return 0;
2161
2162 /* Save current label, update the FEC */
2163 old_label = fec->label;
2164 fec->label_index = label_index;
2165 }
2166
2167 if (new_client)
2168 listnode_add(fec->client_list, client);
2169
2170 if (IS_ZEBRA_DEBUG_MPLS)
2171 zlog_debug("FEC %s label%s %u %s by client %s%s", buf,
2172 have_label_index ? " index" : "",
2173 have_label_index ? label_index : label,
2174 new_client ? "registered" : "updated",
2175 zebra_route_string(client->proto),
2176 is_configured_fec
2177 ? ", but using statically configured label"
2178 : "");
2179
2180 /* If not a statically configured FEC, derive the local label
2181 * from label index or use the provided label
2182 */
2183 if (!is_configured_fec) {
2184 if (have_label_index)
2185 fec_derive_label_from_index(zvrf, fec);
2186 else
2187 fec->label = label;
2188
2189 /* If no label change, exit. */
2190 if (fec->label == old_label)
2191 return 0;
2192
2193 label_change = true;
2194 }
2195
2196 /* If new client or label change, update client and install or uninstall
2197 * label forwarding entry as needed.
2198 */
2199 /* Inform client of label, if needed. */
2200 if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
2201 if (IS_ZEBRA_DEBUG_MPLS)
2202 zlog_debug("Update client label %u", fec->label);
2203 fec_send(fec, client);
2204 }
2205
2206 if (new_client || label_change)
2207 return fec_change_update_lsp(zvrf, fec, old_label);
2208
2209 return 0;
2210 }
2211
2212 /*
2213 * Deregistration from a client for the label binding for a FEC. The FEC
2214 * itself is deleted if no other registered clients exist and there is no
2215 * label bound to the FEC.
2216 */
2217 int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
2218 struct zserv *client)
2219 {
2220 struct route_table *table;
2221 zebra_fec_t *fec;
2222 char buf[BUFSIZ];
2223
2224 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2225 if (!table)
2226 return -1;
2227
2228 if (IS_ZEBRA_DEBUG_MPLS)
2229 prefix2str(p, buf, BUFSIZ);
2230
2231 fec = fec_find(table, p);
2232 if (!fec) {
2233 prefix2str(p, buf, BUFSIZ);
2234 flog_err(EC_ZEBRA_FEC_RM_FAILED,
2235 "Failed to find FEC %s upon unregister, client %s",
2236 buf, zebra_route_string(client->proto));
2237 return -1;
2238 }
2239
2240 listnode_delete(fec->client_list, client);
2241
2242 if (IS_ZEBRA_DEBUG_MPLS)
2243 zlog_debug("FEC %s unregistered by client %s", buf,
2244 zebra_route_string(client->proto));
2245
2246 /* If not a configured entry, delete the FEC if no other clients. Before
2247 * deleting, see if any LSP needs to be uninstalled.
2248 */
2249 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2250 && list_isempty(fec->client_list)) {
2251 mpls_label_t old_label = fec->label;
2252 fec->label = MPLS_INVALID_LABEL; /* reset */
2253 fec_change_update_lsp(zvrf, fec, old_label);
2254 fec_del(fec);
2255 }
2256
2257 return 0;
2258 }
2259
2260 /*
2261 * Cleanup any FECs registered by this client.
2262 */
2263 static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
2264 {
2265 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
2266 struct route_node *rn;
2267 zebra_fec_t *fec;
2268 struct listnode *node;
2269 struct zserv *fec_client;
2270 int af;
2271
2272 for (af = AFI_IP; af < AFI_MAX; af++) {
2273 if (zvrf->fec_table[af] == NULL)
2274 continue;
2275
2276 for (rn = route_top(zvrf->fec_table[af]); rn;
2277 rn = route_next(rn)) {
2278 fec = rn->info;
2279 if (!fec || list_isempty(fec->client_list))
2280 continue;
2281
2282 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
2283 fec_client)) {
2284 if (fec_client == client) {
2285 listnode_delete(fec->client_list,
2286 fec_client);
2287 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2288 && list_isempty(fec->client_list))
2289 fec_del(fec);
2290 break;
2291 }
2292 }
2293 }
2294 }
2295
2296 return 0;
2297 }
2298
2299 /*
2300 * Return FEC (if any) to which this label is bound.
2301 * Note: Only works for per-prefix binding and when the label is not
2302 * implicit-null.
2303 * TODO: Currently walks entire table, can optimize later with another
2304 * hash..
2305 */
2306 zebra_fec_t *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
2307 mpls_label_t label)
2308 {
2309 struct route_node *rn;
2310 zebra_fec_t *fec;
2311 int af;
2312
2313 for (af = AFI_IP; af < AFI_MAX; af++) {
2314 if (zvrf->fec_table[af] == NULL)
2315 continue;
2316
2317 for (rn = route_top(zvrf->fec_table[af]); rn;
2318 rn = route_next(rn)) {
2319 if (!rn->info)
2320 continue;
2321 fec = rn->info;
2322 if (fec->label == label)
2323 return fec;
2324 }
2325 }
2326
2327 return NULL;
2328 }
2329
2330 /*
2331 * Inform if specified label is currently bound to a FEC or not.
2332 */
2333 int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
2334 {
2335 return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
2336 }
2337
2338 /*
2339 * Add static FEC to label binding. If there are clients registered for this
2340 * FEC, notify them. If there are labeled routes for this FEC, install the
2341 * label forwarding entry.
2342 */
2343 int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
2344 mpls_label_t in_label)
2345 {
2346 struct route_table *table;
2347 zebra_fec_t *fec;
2348 char buf[BUFSIZ];
2349 mpls_label_t old_label;
2350 int ret = 0;
2351
2352 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2353 if (!table)
2354 return -1;
2355
2356 if (IS_ZEBRA_DEBUG_MPLS)
2357 prefix2str(p, buf, BUFSIZ);
2358
2359 /* Update existing FEC or create a new one. */
2360 fec = fec_find(table, p);
2361 if (!fec) {
2362 fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
2363 MPLS_INVALID_LABEL_INDEX);
2364 if (!fec) {
2365 prefix2str(p, buf, BUFSIZ);
2366 flog_err(EC_ZEBRA_FEC_ADD_FAILED,
2367 "Failed to add FEC %s upon config", buf);
2368 return -1;
2369 }
2370
2371 if (IS_ZEBRA_DEBUG_MPLS)
2372 zlog_debug("Add fec %s label %u", buf, in_label);
2373 } else {
2374 fec->flags |= FEC_FLAG_CONFIGURED;
2375 if (fec->label == in_label)
2376 /* Duplicate config */
2377 return 0;
2378
2379 /* Label change, update clients. */
2380 old_label = fec->label;
2381 if (IS_ZEBRA_DEBUG_MPLS)
2382 zlog_debug("Update fec %s new label %u", buf, in_label);
2383
2384 fec->label = in_label;
2385 fec_update_clients(fec);
2386
2387 /* Update label forwarding entries appropriately */
2388 ret = fec_change_update_lsp(zvrf, fec, old_label);
2389 }
2390
2391 return ret;
2392 }
2393
2394 /*
2395 * Remove static FEC to label binding. If there are no clients registered
2396 * for this FEC, delete the FEC; else notify clients
2397 * Note: Upon delete of static binding, if label index exists for this FEC,
2398 * client may need to be updated with derived label.
2399 */
2400 int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
2401 {
2402 struct route_table *table;
2403 zebra_fec_t *fec;
2404 mpls_label_t old_label;
2405 char buf[BUFSIZ];
2406
2407 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2408 if (!table)
2409 return -1;
2410
2411 fec = fec_find(table, p);
2412 if (!fec) {
2413 prefix2str(p, buf, BUFSIZ);
2414 flog_err(EC_ZEBRA_FEC_RM_FAILED,
2415 "Failed to find FEC %s upon delete", buf);
2416 return -1;
2417 }
2418
2419 if (IS_ZEBRA_DEBUG_MPLS) {
2420 prefix2str(p, buf, BUFSIZ);
2421 zlog_debug("Delete fec %s label %u label index %u", buf,
2422 fec->label, fec->label_index);
2423 }
2424
2425 old_label = fec->label;
2426 fec->flags &= ~FEC_FLAG_CONFIGURED;
2427 fec->label = MPLS_INVALID_LABEL;
2428
2429 /* If no client exists, just delete the FEC. */
2430 if (list_isempty(fec->client_list)) {
2431 fec_del(fec);
2432 return 0;
2433 }
2434
2435 /* Derive the local label (from label index) or reset it. */
2436 fec_derive_label_from_index(zvrf, fec);
2437
2438 /* If there is a label change, update clients. */
2439 if (fec->label == old_label)
2440 return 0;
2441 fec_update_clients(fec);
2442
2443 /* Update label forwarding entries appropriately */
2444 return fec_change_update_lsp(zvrf, fec, old_label);
2445 }
2446
2447 /*
2448 * Display MPLS FEC to label binding configuration (VTY command handler).
2449 */
2450 int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
2451 {
2452 struct route_node *rn;
2453 int af;
2454 zebra_fec_t *fec;
2455 char buf[BUFSIZ];
2456 int write = 0;
2457
2458 for (af = AFI_IP; af < AFI_MAX; af++) {
2459 if (zvrf->fec_table[af] == NULL)
2460 continue;
2461
2462 for (rn = route_top(zvrf->fec_table[af]); rn;
2463 rn = route_next(rn)) {
2464 if (!rn->info)
2465 continue;
2466
2467 char lstr[BUFSIZ];
2468 fec = rn->info;
2469
2470 if (!(fec->flags & FEC_FLAG_CONFIGURED))
2471 continue;
2472
2473 write = 1;
2474 prefix2str(&rn->p, buf, BUFSIZ);
2475 vty_out(vty, "mpls label bind %s %s\n", buf,
2476 label2str(fec->label, lstr, BUFSIZ));
2477 }
2478 }
2479
2480 return write;
2481 }
2482
2483 /*
2484 * Display MPLS FEC to label binding (VTY command handler).
2485 */
2486 void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
2487 {
2488 struct route_node *rn;
2489 int af;
2490
2491 for (af = AFI_IP; af < AFI_MAX; af++) {
2492 if (zvrf->fec_table[af] == NULL)
2493 continue;
2494
2495 for (rn = route_top(zvrf->fec_table[af]); rn;
2496 rn = route_next(rn)) {
2497 if (!rn->info)
2498 continue;
2499 fec_print(rn->info, vty);
2500 }
2501 }
2502 }
2503
2504 /*
2505 * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2506 */
2507 void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
2508 struct prefix *p)
2509 {
2510 struct route_table *table;
2511 struct route_node *rn;
2512
2513 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2514 if (!table)
2515 return;
2516
2517 apply_mask(p);
2518 rn = route_node_lookup(table, p);
2519 if (!rn)
2520 return;
2521
2522 route_unlock_node(rn);
2523 if (!rn->info)
2524 return;
2525
2526 fec_print(rn->info, vty);
2527 }
2528
2529 static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop,
2530 enum lsp_types_t type, mpls_label_t label)
2531 {
2532 if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2533 nexthop_add_labels(nexthop, type, 1, &label);
2534 else if (!add && nexthop->nh_label_type == type)
2535 nexthop_del_labels(nexthop);
2536 else
2537 return false;
2538
2539 return true;
2540 }
2541
2542 /*
2543 * Install/uninstall a FEC-To-NHLFE (FTN) binding.
2544 */
2545 int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
2546 struct prefix *prefix, enum nexthop_types_t gtype,
2547 union g_addr *gate, ifindex_t ifindex, uint8_t distance,
2548 mpls_label_t out_label)
2549 {
2550 struct route_table *table;
2551 struct route_node *rn;
2552 struct route_entry *re;
2553 struct nexthop *nexthop;
2554 bool found;
2555
2556 /* Lookup table. */
2557 table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
2558 zvrf_id(zvrf));
2559 if (!table)
2560 return -1;
2561
2562 /* Lookup existing route */
2563 rn = route_node_get(table, prefix);
2564 RNODE_FOREACH_RE (rn, re) {
2565 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2566 continue;
2567 if (re->distance == distance)
2568 break;
2569 }
2570
2571 if (re == NULL)
2572 return -1;
2573
2574 found = false;
2575 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
2576 switch (nexthop->type) {
2577 case NEXTHOP_TYPE_IPV4:
2578 case NEXTHOP_TYPE_IPV4_IFINDEX:
2579 if (gtype != NEXTHOP_TYPE_IPV4
2580 && gtype != NEXTHOP_TYPE_IPV4_IFINDEX)
2581 continue;
2582 if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4))
2583 continue;
2584 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
2585 && nexthop->ifindex != ifindex)
2586 continue;
2587 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2588 out_label))
2589 return 0;
2590 found = true;
2591 break;
2592 case NEXTHOP_TYPE_IPV6:
2593 case NEXTHOP_TYPE_IPV6_IFINDEX:
2594 if (gtype != NEXTHOP_TYPE_IPV6
2595 && gtype != NEXTHOP_TYPE_IPV6_IFINDEX)
2596 continue;
2597 if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, &gate->ipv6))
2598 continue;
2599 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
2600 && nexthop->ifindex != ifindex)
2601 continue;
2602 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2603 out_label))
2604 return 0;
2605 found = true;
2606 break;
2607 default:
2608 break;
2609 }
2610 }
2611
2612 if (!found)
2613 return -1;
2614
2615 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2616 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
2617 rib_queue_add(rn);
2618
2619 return 0;
2620 }
2621
2622 /*
2623 * Install/update a NHLFE for an LSP in the forwarding table. This may be
2624 * a new LSP entry or a new NHLFE for an existing in-label or an update of
2625 * the out-label for an existing NHLFE (update case).
2626 */
2627 int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
2628 mpls_label_t in_label, mpls_label_t out_label,
2629 enum nexthop_types_t gtype, union g_addr *gate,
2630 ifindex_t ifindex)
2631 {
2632 struct hash *lsp_table;
2633 zebra_ile_t tmp_ile;
2634 zebra_lsp_t *lsp;
2635 zebra_nhlfe_t *nhlfe;
2636 char buf[BUFSIZ];
2637
2638 /* Lookup table. */
2639 lsp_table = zvrf->lsp_table;
2640 if (!lsp_table)
2641 return -1;
2642
2643 /* If entry is present, exit. */
2644 tmp_ile.in_label = in_label;
2645 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2646 if (!lsp)
2647 return -1;
2648 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2649 if (nhlfe) {
2650 struct nexthop *nh = nhlfe->nexthop;
2651
2652 assert(nh);
2653 assert(nh->nh_label);
2654
2655 /* Clear deleted flag (in case it was set) */
2656 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2657 if (nh->nh_label->label[0] == out_label)
2658 /* No change */
2659 return 0;
2660
2661 if (IS_ZEBRA_DEBUG_MPLS) {
2662 nhlfe2str(nhlfe, buf, BUFSIZ);
2663 zlog_debug(
2664 "LSP in-label %u type %d nexthop %s "
2665 "out-label changed to %u (old %u)",
2666 in_label, type, buf, out_label,
2667 nh->nh_label->label[0]);
2668 }
2669
2670 /* Update out label, trigger processing. */
2671 nh->nh_label->label[0] = out_label;
2672 } else {
2673 /* Add LSP entry to this nexthop */
2674 nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, out_label);
2675 if (!nhlfe)
2676 return -1;
2677
2678 if (IS_ZEBRA_DEBUG_MPLS) {
2679 nhlfe2str(nhlfe, buf, BUFSIZ);
2680 zlog_debug(
2681 "Add LSP in-label %u type %d nexthop %s "
2682 "out-label %u",
2683 in_label, type, buf, out_label);
2684 }
2685
2686 lsp->addr_family = NHLFE_FAMILY(nhlfe);
2687 }
2688
2689 /* Mark NHLFE, queue LSP for processing. */
2690 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2691 if (lsp_processq_add(lsp))
2692 return -1;
2693
2694 return 0;
2695 }
2696
2697 /*
2698 * Uninstall a particular NHLFE in the forwarding table. If this is
2699 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
2700 */
2701 int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2702 mpls_label_t in_label, enum nexthop_types_t gtype,
2703 union g_addr *gate, ifindex_t ifindex)
2704 {
2705 struct hash *lsp_table;
2706 zebra_ile_t tmp_ile;
2707 zebra_lsp_t *lsp;
2708 zebra_nhlfe_t *nhlfe;
2709 char buf[BUFSIZ];
2710
2711 /* Lookup table. */
2712 lsp_table = zvrf->lsp_table;
2713 if (!lsp_table)
2714 return -1;
2715
2716 /* If entry is not present, exit. */
2717 tmp_ile.in_label = in_label;
2718 lsp = hash_lookup(lsp_table, &tmp_ile);
2719 if (!lsp)
2720 return 0;
2721 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2722 if (!nhlfe)
2723 return 0;
2724
2725 if (IS_ZEBRA_DEBUG_MPLS) {
2726 nhlfe2str(nhlfe, buf, BUFSIZ);
2727 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
2728 in_label, type, buf, nhlfe->flags);
2729 }
2730
2731 /* Mark NHLFE for delete or directly delete, as appropriate. */
2732 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
2733 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2734 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2735 if (lsp_processq_add(lsp))
2736 return -1;
2737 } else {
2738 nhlfe_del(nhlfe);
2739
2740 /* Free LSP entry if no other NHLFEs and not scheduled. */
2741 if (!lsp->nhlfe_list
2742 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
2743 if (IS_ZEBRA_DEBUG_MPLS)
2744 zlog_debug("Free LSP in-label %u flags 0x%x",
2745 lsp->ile.in_label, lsp->flags);
2746
2747 lsp = hash_release(lsp_table, &lsp->ile);
2748 XFREE(MTYPE_LSP, lsp);
2749 }
2750 }
2751 return 0;
2752 }
2753
2754 /*
2755 * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
2756 * If no other NHLFEs exist, the entry would be deleted.
2757 */
2758 void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt)
2759 {
2760 zebra_lsp_t *lsp;
2761 struct hash *lsp_table;
2762
2763 lsp = (zebra_lsp_t *)bucket->data;
2764 if (!lsp->nhlfe_list)
2765 return;
2766
2767 lsp_table = ctxt;
2768 if (!lsp_table)
2769 return;
2770
2771 mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP);
2772 }
2773
2774 /*
2775 * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
2776 */
2777 void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
2778 {
2779 struct route_table *table;
2780 struct route_node *rn;
2781 struct route_entry *re;
2782 struct nexthop *nexthop;
2783 int update;
2784
2785 /* Process routes of interested address-families. */
2786 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2787 if (!table)
2788 return;
2789
2790 for (rn = route_top(table); rn; rn = route_next(rn)) {
2791 update = 0;
2792 RNODE_FOREACH_RE (rn, re) {
2793 for (nexthop = re->ng.nexthop; nexthop;
2794 nexthop = nexthop->next) {
2795 if (nexthop->nh_label_type != ZEBRA_LSP_LDP)
2796 continue;
2797
2798 nexthop_del_labels(nexthop);
2799 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2800 SET_FLAG(re->status,
2801 ROUTE_ENTRY_LABELS_CHANGED);
2802 update = 1;
2803 }
2804 }
2805
2806 if (update)
2807 rib_queue_add(rn);
2808 }
2809 }
2810
2811 #if defined(HAVE_CUMULUS)
2812 /*
2813 * Check that the label values used in LSP creation are consistent. The
2814 * main criteria is that if there is ECMP, the label operation must still
2815 * be consistent - i.e., all paths either do a swap or do PHP. This is due
2816 * to current HW restrictions.
2817 */
2818 int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
2819 mpls_label_t in_label,
2820 mpls_label_t out_label,
2821 enum nexthop_types_t gtype,
2822 union g_addr *gate, ifindex_t ifindex)
2823 {
2824 struct hash *slsp_table;
2825 zebra_ile_t tmp_ile;
2826 zebra_slsp_t *slsp;
2827 zebra_snhlfe_t *snhlfe;
2828
2829 /* Lookup table. */
2830 slsp_table = zvrf->slsp_table;
2831 if (!slsp_table)
2832 return 0;
2833
2834 /* If entry is not present, exit. */
2835 tmp_ile.in_label = in_label;
2836 slsp = hash_lookup(slsp_table, &tmp_ile);
2837 if (!slsp)
2838 return 1;
2839
2840 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2841 if (snhlfe) {
2842 if (snhlfe->out_label == out_label)
2843 return 1;
2844
2845 /* If not only NHLFE, cannot allow label change. */
2846 if (snhlfe != slsp->snhlfe_list || snhlfe->next)
2847 return 0;
2848 } else {
2849 /* If other NHLFEs exist, label operation must match. */
2850 if (slsp->snhlfe_list) {
2851 int cur_op, new_op;
2852
2853 cur_op = (slsp->snhlfe_list->out_label
2854 == MPLS_LABEL_IMPLICIT_NULL);
2855 new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
2856 if (cur_op != new_op)
2857 return 0;
2858 }
2859 }
2860
2861 /* Label values are good. */
2862 return 1;
2863 }
2864 #endif /* HAVE_CUMULUS */
2865
2866 /*
2867 * Add static LSP entry. This may be the first entry for this incoming label
2868 * or an additional nexthop; an existing entry may also have outgoing label
2869 * changed.
2870 * Note: The label operation (swap or PHP) is common for the LSP entry (all
2871 * NHLFEs).
2872 */
2873 int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
2874 mpls_label_t out_label,
2875 enum nexthop_types_t gtype, union g_addr *gate,
2876 ifindex_t ifindex)
2877 {
2878 struct hash *slsp_table;
2879 zebra_ile_t tmp_ile;
2880 zebra_slsp_t *slsp;
2881 zebra_snhlfe_t *snhlfe;
2882 char buf[BUFSIZ];
2883
2884 /* Lookup table. */
2885 slsp_table = zvrf->slsp_table;
2886 if (!slsp_table)
2887 return -1;
2888
2889 /* If entry is present, exit. */
2890 tmp_ile.in_label = in_label;
2891 slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc);
2892 if (!slsp)
2893 return -1;
2894 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2895 if (snhlfe) {
2896 if (snhlfe->out_label == out_label)
2897 /* No change */
2898 return 0;
2899
2900 if (IS_ZEBRA_DEBUG_MPLS) {
2901 snhlfe2str(snhlfe, buf, BUFSIZ);
2902 zlog_debug(
2903 "Upd static LSP in-label %u nexthop %s "
2904 "out-label %u (old %u)",
2905 in_label, buf, out_label, snhlfe->out_label);
2906 }
2907 snhlfe->out_label = out_label;
2908 } else {
2909 /* Add static LSP entry to this nexthop */
2910 snhlfe = snhlfe_add(slsp, gtype, gate, ifindex, out_label);
2911 if (!snhlfe)
2912 return -1;
2913
2914 if (IS_ZEBRA_DEBUG_MPLS) {
2915 snhlfe2str(snhlfe, buf, BUFSIZ);
2916 zlog_debug(
2917 "Add static LSP in-label %u nexthop %s out-label %u",
2918 in_label, buf, out_label);
2919 }
2920 }
2921
2922 /* (Re)Install LSP in the main table. */
2923 if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
2924 gate, ifindex))
2925 return -1;
2926
2927 return 0;
2928 }
2929
2930 /*
2931 * Delete static LSP entry. This may be the delete of one particular
2932 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
2933 * all NHLFEs).
2934 * NOTE: Delete of the only NHLFE will also end up deleting the entire
2935 * LSP configuration.
2936 */
2937 int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
2938 enum nexthop_types_t gtype, union g_addr *gate,
2939 ifindex_t ifindex)
2940 {
2941 struct hash *slsp_table;
2942 zebra_ile_t tmp_ile;
2943 zebra_slsp_t *slsp;
2944 zebra_snhlfe_t *snhlfe;
2945
2946 /* Lookup table. */
2947 slsp_table = zvrf->slsp_table;
2948 if (!slsp_table)
2949 return -1;
2950
2951 /* If entry is not present, exit. */
2952 tmp_ile.in_label = in_label;
2953 slsp = hash_lookup(slsp_table, &tmp_ile);
2954 if (!slsp)
2955 return 0;
2956
2957 /* Is it delete of entire LSP or a specific NHLFE? */
2958 if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
2959 if (IS_ZEBRA_DEBUG_MPLS)
2960 zlog_debug("Del static LSP in-label %u", in_label);
2961
2962 /* Uninstall entire LSP from the main table. */
2963 mpls_static_lsp_uninstall_all(zvrf, in_label);
2964
2965 /* Delete all static NHLFEs */
2966 snhlfe_del_all(slsp);
2967 } else {
2968 /* Find specific NHLFE, exit if not found. */
2969 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2970 if (!snhlfe)
2971 return 0;
2972
2973 if (IS_ZEBRA_DEBUG_MPLS) {
2974 char buf[BUFSIZ];
2975 snhlfe2str(snhlfe, buf, BUFSIZ);
2976 zlog_debug("Del static LSP in-label %u nexthop %s",
2977 in_label, buf);
2978 }
2979
2980 /* Uninstall LSP from the main table. */
2981 mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
2982 gate, ifindex);
2983
2984 /* Delete static LSP NHLFE */
2985 snhlfe_del(snhlfe);
2986 }
2987
2988 /* Remove entire static LSP entry if no NHLFE - valid in either case
2989 * above. */
2990 if (!slsp->snhlfe_list) {
2991 slsp = hash_release(slsp_table, &tmp_ile);
2992 XFREE(MTYPE_SLSP, slsp);
2993 }
2994
2995 return 0;
2996 }
2997
2998 /*
2999 * Schedule all MPLS label forwarding entries for processing.
3000 * Called upon changes that may affect one or more of them such as
3001 * interface or nexthop state changes.
3002 */
3003 void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
3004 {
3005 if (!zvrf)
3006 return;
3007 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
3008 }
3009
3010 /*
3011 * Display MPLS label forwarding table for a specific LSP
3012 * (VTY command handler).
3013 */
3014 void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
3015 mpls_label_t label, bool use_json)
3016 {
3017 struct hash *lsp_table;
3018 zebra_lsp_t *lsp;
3019 zebra_ile_t tmp_ile;
3020 json_object *json = NULL;
3021
3022 /* Lookup table. */
3023 lsp_table = zvrf->lsp_table;
3024 if (!lsp_table)
3025 return;
3026
3027 /* If entry is not present, exit. */
3028 tmp_ile.in_label = label;
3029 lsp = hash_lookup(lsp_table, &tmp_ile);
3030 if (!lsp)
3031 return;
3032
3033 if (use_json) {
3034 json = lsp_json(lsp);
3035 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3036 json, JSON_C_TO_STRING_PRETTY));
3037 json_object_free(json);
3038 } else
3039 lsp_print(lsp, (void *)vty);
3040 }
3041
3042 /*
3043 * Display MPLS label forwarding table (VTY command handler).
3044 */
3045 void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
3046 bool use_json)
3047 {
3048 char buf[BUFSIZ];
3049 json_object *json = NULL;
3050 zebra_lsp_t *lsp = NULL;
3051 zebra_nhlfe_t *nhlfe = NULL;
3052 struct listnode *node = NULL;
3053 struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
3054
3055 if (use_json) {
3056 json = json_object_new_object();
3057
3058 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
3059 json_object_object_add(
3060 json, label2str(lsp->ile.in_label, buf, BUFSIZ),
3061 lsp_json(lsp));
3062
3063 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3064 json, JSON_C_TO_STRING_PRETTY));
3065 json_object_free(json);
3066 } else {
3067 struct ttable *tt;
3068
3069 /* Prepare table. */
3070 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3071 ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label");
3072 tt->style.cell.rpad = 2;
3073 tt->style.corner = '+';
3074 ttable_restyle(tt);
3075 ttable_rowseps(tt, 0, BOTTOM, true, '-');
3076
3077 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
3078 for (nhlfe = lsp->nhlfe_list; nhlfe;
3079 nhlfe = nhlfe->next) {
3080 struct nexthop *nexthop;
3081 const char *out_label_str;
3082 char nh_buf[NEXTHOP_STRLEN];
3083
3084 nexthop = nhlfe->nexthop;
3085
3086 switch (nexthop->type) {
3087 case NEXTHOP_TYPE_IFINDEX: {
3088 struct zebra_ns *zns;
3089 struct interface *ifp;
3090
3091 zns = zebra_ns_lookup(NS_DEFAULT);
3092 ifp = if_lookup_by_index_per_ns(
3093 zns, nexthop->ifindex);
3094 snprintf(nh_buf, sizeof(nh_buf), "%s",
3095 ifp ? ifp->name : "Null");
3096 break;
3097 }
3098 case NEXTHOP_TYPE_IPV4:
3099 case NEXTHOP_TYPE_IPV4_IFINDEX:
3100 inet_ntop(AF_INET, &nexthop->gate.ipv4,
3101 nh_buf, sizeof(nh_buf));
3102 break;
3103 case NEXTHOP_TYPE_IPV6:
3104 case NEXTHOP_TYPE_IPV6_IFINDEX:
3105 inet_ntop(AF_INET6, &nexthop->gate.ipv6,
3106 nh_buf, sizeof(nh_buf));
3107 break;
3108 default:
3109 break;
3110 }
3111
3112 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
3113 out_label_str = mpls_label2str(
3114 nexthop->nh_label->num_labels,
3115 &nexthop->nh_label->label[0],
3116 buf, BUFSIZ, 1);
3117 else
3118 out_label_str = "-";
3119
3120 ttable_add_row(tt, "%u|%s|%s|%s",
3121 lsp->ile.in_label,
3122 nhlfe_type2str(nhlfe->type),
3123 nh_buf, out_label_str);
3124 }
3125 }
3126
3127 /* Dump the generated table. */
3128 if (tt->nrows > 1) {
3129 char *table = ttable_dump(tt, "\n");
3130 vty_out(vty, "%s\n", table);
3131 XFREE(MTYPE_TMP, table);
3132 }
3133 ttable_del(tt);
3134 }
3135
3136 list_delete(&lsp_list);
3137 }
3138
3139 /*
3140 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
3141 */
3142 int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
3143 {
3144 zebra_slsp_t *slsp;
3145 zebra_snhlfe_t *snhlfe;
3146 struct listnode *node;
3147 struct list *slsp_list =
3148 hash_get_sorted_list(zvrf->slsp_table, slsp_cmp);
3149
3150 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) {
3151 for (snhlfe = slsp->snhlfe_list; snhlfe;
3152 snhlfe = snhlfe->next) {
3153 char buf[BUFSIZ];
3154 char lstr[30];
3155
3156 snhlfe2str(snhlfe, buf, sizeof(buf));
3157 switch (snhlfe->out_label) {
3158 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
3159 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
3160 strlcpy(lstr, "explicit-null", sizeof(lstr));
3161 break;
3162 case MPLS_LABEL_IMPLICIT_NULL:
3163 strlcpy(lstr, "implicit-null", sizeof(lstr));
3164 break;
3165 default:
3166 sprintf(lstr, "%u", snhlfe->out_label);
3167 break;
3168 }
3169
3170 vty_out(vty, "mpls lsp %u %s %s\n", slsp->ile.in_label,
3171 buf, lstr);
3172 }
3173 }
3174
3175 list_delete(&slsp_list);
3176 return (zvrf->slsp_table->count ? 1 : 0);
3177 }
3178
3179 /*
3180 * Add/update global label block.
3181 */
3182 int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
3183 uint32_t end_label)
3184 {
3185 zvrf->mpls_srgb.start_label = start_label;
3186 zvrf->mpls_srgb.end_label = end_label;
3187
3188 /* Evaluate registered FECs to see if any get a label or not. */
3189 fec_evaluate(zvrf);
3190 return 0;
3191 }
3192
3193 /*
3194 * Delete global label block.
3195 */
3196 int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
3197 {
3198 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3199 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
3200
3201 /* Process registered FECs to clear their local label, if needed. */
3202 fec_evaluate(zvrf);
3203 return 0;
3204 }
3205
3206 /*
3207 * Display MPLS global label block configuration (VTY command handler).
3208 */
3209 int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
3210 {
3211 if (zvrf->mpls_srgb.start_label == 0)
3212 return 0;
3213
3214 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
3215 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
3216 vty_out(vty, "mpls label global-block %u %u\n",
3217 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
3218 }
3219
3220 return 1;
3221 }
3222
3223 /*
3224 * Called when VRF becomes inactive, cleans up information but keeps
3225 * the table itself.
3226 */
3227 void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
3228 {
3229 struct zebra_vrf *def_zvrf;
3230 afi_t afi;
3231
3232 if (zvrf_id(zvrf) == VRF_DEFAULT)
3233 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3234 else {
3235 /*
3236 * For other vrfs, we try to remove associated LSPs; we locate
3237 * the LSPs in the default vrf.
3238 */
3239 def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3240
3241 /* At shutdown, the default may be gone already */
3242 if (def_zvrf == NULL)
3243 return;
3244
3245 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
3246 if (zvrf->label[afi] != MPLS_LABEL_NONE)
3247 lsp_uninstall(def_zvrf, zvrf->label[afi]);
3248 }
3249 }
3250 }
3251
3252 /*
3253 * Called upon process exiting, need to delete LSP forwarding
3254 * entries from the kernel.
3255 * NOTE: Currently supported only for default VRF.
3256 */
3257 void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
3258 {
3259 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3260 hash_clean(zvrf->lsp_table, NULL);
3261 hash_free(zvrf->lsp_table);
3262 hash_clean(zvrf->slsp_table, NULL);
3263 hash_free(zvrf->slsp_table);
3264 route_table_finish(zvrf->fec_table[AFI_IP]);
3265 route_table_finish(zvrf->fec_table[AFI_IP6]);
3266 }
3267
3268 /*
3269 * Allocate MPLS tables for this VRF and do other initialization.
3270 * NOTE: Currently supported only for default VRF.
3271 */
3272 void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
3273 {
3274 if (!zvrf)
3275 return;
3276 zvrf->slsp_table =
3277 hash_create(label_hash, label_cmp, "ZEBRA SLSP table");
3278 zvrf->lsp_table = hash_create(label_hash, label_cmp, "ZEBRA LSP table");
3279 zvrf->fec_table[AFI_IP] = route_table_init();
3280 zvrf->fec_table[AFI_IP6] = route_table_init();
3281 zvrf->mpls_flags = 0;
3282 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3283 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
3284 }
3285
3286 /*
3287 * Global MPLS initialization.
3288 */
3289 void zebra_mpls_init(void)
3290 {
3291 mpls_enabled = 0;
3292
3293 if (mpls_kernel_init() < 0) {
3294 flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
3295 "Disabling MPLS support (no kernel support)");
3296 return;
3297 }
3298
3299 if (!mpls_processq_init())
3300 mpls_enabled = 1;
3301
3302 hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
3303 }