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