]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mpls.c
Merge pull request #4267 from qlyoung/fix-misc-compile-warnings
[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 strlcat(buf,
1697 ifindex2ifname(snhlfe->ifindex, VRF_DEFAULT),
1698 size);
1699 break;
1700 default:
1701 break;
1702 }
1703
1704 return buf;
1705 }
1706
1707 /*
1708 * Initialize work queue for processing changed LSPs.
1709 */
1710 static int mpls_processq_init(void)
1711 {
1712 zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
1713 if (!zrouter.lsp_process_q) {
1714 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1715 "%s: could not initialise work queue!", __func__);
1716 return -1;
1717 }
1718
1719 zrouter.lsp_process_q->spec.workfunc = &lsp_process;
1720 zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
1721 zrouter.lsp_process_q->spec.errorfunc = NULL;
1722 zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
1723 zrouter.lsp_process_q->spec.max_retries = 0;
1724 zrouter.lsp_process_q->spec.hold = 10;
1725
1726 return 0;
1727 }
1728
1729
1730 /* Public functions */
1731
1732 /*
1733 * Process LSP update results from zebra dataplane.
1734 */
1735 void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
1736 {
1737 struct zebra_vrf *zvrf;
1738 zebra_ile_t tmp_ile;
1739 struct hash *lsp_table;
1740 zebra_lsp_t *lsp;
1741 zebra_nhlfe_t *nhlfe;
1742 struct nexthop *nexthop;
1743 enum dplane_op_e op;
1744 enum zebra_dplane_result status;
1745
1746 op = dplane_ctx_get_op(ctx);
1747 status = dplane_ctx_get_status(ctx);
1748
1749 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1750 zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
1751 ctx, dplane_op2str(op),
1752 dplane_ctx_get_in_label(ctx),
1753 dplane_res2str(status));
1754
1755 switch (op) {
1756 case DPLANE_OP_LSP_INSTALL:
1757 case DPLANE_OP_LSP_UPDATE:
1758 /* Look for zebra LSP object */
1759 zvrf = vrf_info_lookup(VRF_DEFAULT);
1760 if (zvrf == NULL)
1761 break;
1762
1763 lsp_table = zvrf->lsp_table;
1764
1765 tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
1766 lsp = hash_lookup(lsp_table, &tmp_ile);
1767 if (lsp == NULL) {
1768 if (IS_ZEBRA_DEBUG_DPLANE)
1769 zlog_debug("LSP ctx %p: in-label %u not found",
1770 ctx, dplane_ctx_get_in_label(ctx));
1771 break;
1772 }
1773
1774 /* TODO -- Confirm that this result is still 'current' */
1775
1776 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1777 /* Update zebra object */
1778 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1779 for (nhlfe = lsp->nhlfe_list; nhlfe;
1780 nhlfe = nhlfe->next) {
1781 nexthop = nhlfe->nexthop;
1782 if (!nexthop)
1783 continue;
1784
1785 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1786 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1787 }
1788 } else {
1789 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1790 clear_nhlfe_installed(lsp);
1791 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1792 "LSP Install Failure: in-label %u",
1793 lsp->ile.in_label);
1794 }
1795
1796 break;
1797
1798 case DPLANE_OP_LSP_DELETE:
1799 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
1800 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
1801 "LSP Deletion Failure: in-label %u",
1802 dplane_ctx_get_in_label(ctx));
1803 break;
1804
1805 default:
1806 break;
1807
1808 } /* Switch */
1809
1810 dplane_ctx_fini(&ctx);
1811 }
1812
1813 /*
1814 * Process async dplane notifications.
1815 */
1816 void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
1817 {
1818 struct zebra_vrf *zvrf;
1819 zebra_ile_t tmp_ile;
1820 struct hash *lsp_table;
1821 zebra_lsp_t *lsp;
1822 zebra_nhlfe_t *nhlfe;
1823 const zebra_nhlfe_t *ctx_nhlfe;
1824 struct nexthop *nexthop;
1825 const struct nexthop *ctx_nexthop;
1826 int start_count = 0, end_count = 0; /* Installed counts */
1827 bool changed_p = false;
1828 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1829
1830 if (is_debug)
1831 zlog_debug("LSP dplane notif, in-label %u",
1832 dplane_ctx_get_in_label(ctx));
1833
1834 /* Look for zebra LSP object */
1835 zvrf = vrf_info_lookup(VRF_DEFAULT);
1836 if (zvrf == NULL)
1837 goto done;
1838
1839 lsp_table = zvrf->lsp_table;
1840
1841 tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
1842 lsp = hash_lookup(lsp_table, &tmp_ile);
1843 if (lsp == NULL) {
1844 if (is_debug)
1845 zlog_debug("dplane LSP notif: in-label %u not found",
1846 dplane_ctx_get_in_label(ctx));
1847 goto done;
1848 }
1849
1850 /*
1851 * The dataplane/forwarding plane is notifying zebra about the state
1852 * of the nexthops associated with this LSP. First, we take a
1853 * pre-scan pass to determine whether the LSP has transitioned
1854 * from installed -> uninstalled. In that case, we need to have
1855 * the existing state of the LSP objects available before making
1856 * any changes.
1857 */
1858 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1859 char buf[NEXTHOP_STRLEN];
1860
1861 nexthop = nhlfe->nexthop;
1862 if (!nexthop)
1863 continue;
1864
1865 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
1866 start_count++;
1867
1868 ctx_nexthop = NULL;
1869 for (ctx_nhlfe = dplane_ctx_get_nhlfe(ctx);
1870 ctx_nhlfe; ctx_nhlfe = ctx_nhlfe->next) {
1871
1872 ctx_nexthop = ctx_nhlfe->nexthop;
1873 if (!ctx_nexthop)
1874 continue;
1875
1876 if ((ctx_nexthop->type == nexthop->type) &&
1877 nexthop_same(ctx_nexthop, nexthop)) {
1878 /* Matched */
1879 break;
1880 }
1881 }
1882
1883 if (is_debug)
1884 nexthop2str(nexthop, buf, sizeof(buf));
1885
1886 if (ctx_nhlfe && ctx_nexthop) {
1887 if (is_debug) {
1888 const char *tstr = "";
1889
1890 if (!CHECK_FLAG(ctx_nhlfe->flags,
1891 NHLFE_FLAG_INSTALLED))
1892 tstr = "not ";
1893
1894 zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
1895 buf, tstr);
1896 }
1897
1898 /* Test zebra nhlfe install state */
1899 if (CHECK_FLAG(ctx_nhlfe->flags,
1900 NHLFE_FLAG_INSTALLED)) {
1901
1902 if (!CHECK_FLAG(nhlfe->flags,
1903 NHLFE_FLAG_INSTALLED))
1904 changed_p = true;
1905
1906 /* Update counter */
1907 end_count++;
1908 } else {
1909
1910 if (CHECK_FLAG(nhlfe->flags,
1911 NHLFE_FLAG_INSTALLED))
1912 changed_p = true;
1913 }
1914
1915 } else {
1916 /* Not mentioned in lfib set -> uninstalled */
1917 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ||
1918 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ||
1919 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
1920 changed_p = true;
1921 }
1922
1923 if (is_debug)
1924 zlog_debug("LSP dplane notif: no match, nh %s",
1925 buf);
1926 }
1927 }
1928
1929 if (is_debug)
1930 zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
1931 start_count, end_count,
1932 changed_p ? ", changed" : "");
1933
1934 /*
1935 * Has the LSP become uninstalled?
1936 */
1937 if (start_count > 0 && end_count == 0) {
1938 /* Inform other lfibs */
1939 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
1940 }
1941
1942 /*
1943 * Now we take a second pass and bring the zebra
1944 * nexthop state into sync with the forwarding-plane state.
1945 */
1946 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1947 char buf[NEXTHOP_STRLEN];
1948
1949 nexthop = nhlfe->nexthop;
1950 if (!nexthop)
1951 continue;
1952
1953 ctx_nexthop = NULL;
1954 for (ctx_nhlfe = dplane_ctx_get_nhlfe(ctx);
1955 ctx_nhlfe; ctx_nhlfe = ctx_nhlfe->next) {
1956
1957 ctx_nexthop = ctx_nhlfe->nexthop;
1958 if (!ctx_nexthop)
1959 continue;
1960
1961 if ((ctx_nexthop->type == nexthop->type) &&
1962 nexthop_same(ctx_nexthop, nexthop)) {
1963 /* Matched */
1964 break;
1965 }
1966 }
1967
1968 if (is_debug)
1969 nexthop2str(nexthop, buf, sizeof(buf));
1970
1971 if (ctx_nhlfe && ctx_nexthop) {
1972
1973 /* Bring zebra nhlfe install state into sync */
1974 if (CHECK_FLAG(ctx_nhlfe->flags,
1975 NHLFE_FLAG_INSTALLED)) {
1976
1977 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1978
1979 } else {
1980
1981 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1982 }
1983
1984 if (CHECK_FLAG(ctx_nhlfe->nexthop->flags,
1985 NEXTHOP_FLAG_FIB)) {
1986 SET_FLAG(nhlfe->nexthop->flags,
1987 NEXTHOP_FLAG_ACTIVE);
1988 SET_FLAG(nhlfe->nexthop->flags,
1989 NEXTHOP_FLAG_FIB);
1990 } else {
1991 UNSET_FLAG(nhlfe->nexthop->flags,
1992 NEXTHOP_FLAG_ACTIVE);
1993 UNSET_FLAG(nhlfe->nexthop->flags,
1994 NEXTHOP_FLAG_FIB);
1995 }
1996
1997 } else {
1998 /* Not mentioned in lfib set -> uninstalled */
1999
2000 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2001 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
2002 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2003 }
2004 }
2005
2006 if (end_count > 0) {
2007 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2008
2009 if (changed_p)
2010 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
2011
2012 } else {
2013 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2014 clear_nhlfe_installed(lsp);
2015 }
2016
2017 done:
2018 dplane_ctx_fini(&ctx);
2019 }
2020
2021 /*
2022 * Install dynamic LSP entry.
2023 */
2024 int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
2025 struct route_entry *re)
2026 {
2027 struct route_table *table;
2028 zebra_fec_t *fec;
2029
2030 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2031 if (!table)
2032 return -1;
2033
2034 /* See if there is a configured label binding for this FEC. */
2035 fec = fec_find(table, &rn->p);
2036 if (!fec || fec->label == MPLS_INVALID_LABEL)
2037 return 0;
2038
2039 /* We cannot install a label forwarding entry if local label is the
2040 * implicit-null label.
2041 */
2042 if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
2043 return 0;
2044
2045 if (lsp_install(zvrf, fec->label, rn, re))
2046 return -1;
2047
2048 return 0;
2049 }
2050
2051 /*
2052 * Uninstall dynamic LSP entry, if any.
2053 */
2054 int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
2055 struct route_entry *re)
2056 {
2057 struct route_table *table;
2058 zebra_fec_t *fec;
2059
2060 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2061 if (!table)
2062 return -1;
2063
2064 /* See if there is a configured label binding for this FEC. */
2065 fec = fec_find(table, &rn->p);
2066 if (!fec || fec->label == MPLS_INVALID_LABEL)
2067 return 0;
2068
2069 /* Uninstall always removes all dynamic NHLFEs. */
2070 return lsp_uninstall(zvrf, fec->label);
2071 }
2072
2073 /*
2074 * Add an NHLFE to an LSP, return the newly-added object
2075 */
2076 zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
2077 enum lsp_types_t lsp_type,
2078 enum nexthop_types_t gtype,
2079 union g_addr *gate,
2080 ifindex_t ifindex,
2081 mpls_label_t out_label)
2082 {
2083 /* Just a public pass-through to the internal implementation */
2084 return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, out_label);
2085 }
2086
2087 /*
2088 * Free an allocated NHLFE
2089 */
2090 void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe)
2091 {
2092 /* Just a pass-through to the internal implementation */
2093 nhlfe_del(nhlfe);
2094 }
2095
2096 /*
2097 * Registration from a client for the label binding for a FEC. If a binding
2098 * already exists, it is informed to the client.
2099 * NOTE: If there is a manually configured label binding, that is used.
2100 * Otherwise, if a label index is specified, it means we have to allocate the
2101 * label from a locally configured label block (SRGB), if one exists and index
2102 * is acceptable. If no label index then just register the specified label.
2103 * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
2104 * by the calling function. Register requests with both will be rejected.
2105 */
2106 int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
2107 uint32_t label, uint32_t label_index,
2108 struct zserv *client)
2109 {
2110 struct route_table *table;
2111 zebra_fec_t *fec;
2112 char buf[BUFSIZ];
2113 bool new_client;
2114 bool label_change = false;
2115 uint32_t old_label;
2116 bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
2117 bool is_configured_fec = false; /* indicate statically configured FEC */
2118
2119 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2120 if (!table)
2121 return -1;
2122
2123 if (IS_ZEBRA_DEBUG_MPLS)
2124 prefix2str(p, buf, BUFSIZ);
2125
2126 if (label != MPLS_INVALID_LABEL && have_label_index) {
2127 flog_err(
2128 EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
2129 "Rejecting FEC register for %s with both label %u and Label Index %u specified, client %s",
2130 buf, label, label_index,
2131 zebra_route_string(client->proto));
2132 return -1;
2133 }
2134
2135 /* Locate FEC */
2136 fec = fec_find(table, p);
2137 if (!fec) {
2138 fec = fec_add(table, p, label, 0, label_index);
2139 if (!fec) {
2140 flog_err(
2141 EC_ZEBRA_FEC_ADD_FAILED,
2142 "Failed to add FEC %s upon register, client %s",
2143 buf, zebra_route_string(client->proto));
2144 return -1;
2145 }
2146
2147 old_label = MPLS_INVALID_LABEL;
2148 new_client = true;
2149 } else {
2150 /* Check if the FEC has been statically defined in the config */
2151 is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
2152 /* Client may register same FEC with different label index. */
2153 new_client =
2154 (listnode_lookup(fec->client_list, client) == NULL);
2155 if (!new_client && fec->label_index == label_index
2156 && fec->label == label)
2157 /* Duplicate register */
2158 return 0;
2159
2160 /* Save current label, update the FEC */
2161 old_label = fec->label;
2162 fec->label_index = label_index;
2163 }
2164
2165 if (new_client)
2166 listnode_add(fec->client_list, client);
2167
2168 if (IS_ZEBRA_DEBUG_MPLS)
2169 zlog_debug("FEC %s label%s %u %s by client %s%s", buf,
2170 have_label_index ? " index" : "",
2171 have_label_index ? label_index : label,
2172 new_client ? "registered" : "updated",
2173 zebra_route_string(client->proto),
2174 is_configured_fec
2175 ? ", but using statically configured label"
2176 : "");
2177
2178 /* If not a statically configured FEC, derive the local label
2179 * from label index or use the provided label
2180 */
2181 if (!is_configured_fec) {
2182 if (have_label_index)
2183 fec_derive_label_from_index(zvrf, fec);
2184 else
2185 fec->label = label;
2186
2187 /* If no label change, exit. */
2188 if (fec->label == old_label)
2189 return 0;
2190
2191 label_change = true;
2192 }
2193
2194 /* If new client or label change, update client and install or uninstall
2195 * label forwarding entry as needed.
2196 */
2197 /* Inform client of label, if needed. */
2198 if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
2199 if (IS_ZEBRA_DEBUG_MPLS)
2200 zlog_debug("Update client label %u", fec->label);
2201 fec_send(fec, client);
2202 }
2203
2204 if (new_client || label_change)
2205 return fec_change_update_lsp(zvrf, fec, old_label);
2206
2207 return 0;
2208 }
2209
2210 /*
2211 * Deregistration from a client for the label binding for a FEC. The FEC
2212 * itself is deleted if no other registered clients exist and there is no
2213 * label bound to the FEC.
2214 */
2215 int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
2216 struct zserv *client)
2217 {
2218 struct route_table *table;
2219 zebra_fec_t *fec;
2220 char buf[BUFSIZ];
2221
2222 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2223 if (!table)
2224 return -1;
2225
2226 if (IS_ZEBRA_DEBUG_MPLS)
2227 prefix2str(p, buf, BUFSIZ);
2228
2229 fec = fec_find(table, p);
2230 if (!fec) {
2231 prefix2str(p, buf, BUFSIZ);
2232 flog_err(EC_ZEBRA_FEC_RM_FAILED,
2233 "Failed to find FEC %s upon unregister, client %s",
2234 buf, zebra_route_string(client->proto));
2235 return -1;
2236 }
2237
2238 listnode_delete(fec->client_list, client);
2239
2240 if (IS_ZEBRA_DEBUG_MPLS)
2241 zlog_debug("FEC %s unregistered by client %s", buf,
2242 zebra_route_string(client->proto));
2243
2244 /* If not a configured entry, delete the FEC if no other clients. Before
2245 * deleting, see if any LSP needs to be uninstalled.
2246 */
2247 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2248 && list_isempty(fec->client_list)) {
2249 mpls_label_t old_label = fec->label;
2250 fec->label = MPLS_INVALID_LABEL; /* reset */
2251 fec_change_update_lsp(zvrf, fec, old_label);
2252 fec_del(fec);
2253 }
2254
2255 return 0;
2256 }
2257
2258 /*
2259 * Cleanup any FECs registered by this client.
2260 */
2261 static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
2262 {
2263 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
2264 struct route_node *rn;
2265 zebra_fec_t *fec;
2266 struct listnode *node;
2267 struct zserv *fec_client;
2268 int af;
2269
2270 for (af = AFI_IP; af < AFI_MAX; af++) {
2271 if (zvrf->fec_table[af] == NULL)
2272 continue;
2273
2274 for (rn = route_top(zvrf->fec_table[af]); rn;
2275 rn = route_next(rn)) {
2276 fec = rn->info;
2277 if (!fec || list_isempty(fec->client_list))
2278 continue;
2279
2280 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
2281 fec_client)) {
2282 if (fec_client == client) {
2283 listnode_delete(fec->client_list,
2284 fec_client);
2285 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2286 && list_isempty(fec->client_list))
2287 fec_del(fec);
2288 break;
2289 }
2290 }
2291 }
2292 }
2293
2294 return 0;
2295 }
2296
2297 /*
2298 * Return FEC (if any) to which this label is bound.
2299 * Note: Only works for per-prefix binding and when the label is not
2300 * implicit-null.
2301 * TODO: Currently walks entire table, can optimize later with another
2302 * hash..
2303 */
2304 zebra_fec_t *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
2305 mpls_label_t label)
2306 {
2307 struct route_node *rn;
2308 zebra_fec_t *fec;
2309 int af;
2310
2311 for (af = AFI_IP; af < AFI_MAX; af++) {
2312 if (zvrf->fec_table[af] == NULL)
2313 continue;
2314
2315 for (rn = route_top(zvrf->fec_table[af]); rn;
2316 rn = route_next(rn)) {
2317 if (!rn->info)
2318 continue;
2319 fec = rn->info;
2320 if (fec->label == label)
2321 return fec;
2322 }
2323 }
2324
2325 return NULL;
2326 }
2327
2328 /*
2329 * Inform if specified label is currently bound to a FEC or not.
2330 */
2331 int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
2332 {
2333 return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
2334 }
2335
2336 /*
2337 * Add static FEC to label binding. If there are clients registered for this
2338 * FEC, notify them. If there are labeled routes for this FEC, install the
2339 * label forwarding entry.
2340 */
2341 int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
2342 mpls_label_t in_label)
2343 {
2344 struct route_table *table;
2345 zebra_fec_t *fec;
2346 char buf[BUFSIZ];
2347 mpls_label_t old_label;
2348 int ret = 0;
2349
2350 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2351 if (!table)
2352 return -1;
2353
2354 if (IS_ZEBRA_DEBUG_MPLS)
2355 prefix2str(p, buf, BUFSIZ);
2356
2357 /* Update existing FEC or create a new one. */
2358 fec = fec_find(table, p);
2359 if (!fec) {
2360 fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
2361 MPLS_INVALID_LABEL_INDEX);
2362 if (!fec) {
2363 prefix2str(p, buf, BUFSIZ);
2364 flog_err(EC_ZEBRA_FEC_ADD_FAILED,
2365 "Failed to add FEC %s upon config", buf);
2366 return -1;
2367 }
2368
2369 if (IS_ZEBRA_DEBUG_MPLS)
2370 zlog_debug("Add fec %s label %u", buf, in_label);
2371 } else {
2372 fec->flags |= FEC_FLAG_CONFIGURED;
2373 if (fec->label == in_label)
2374 /* Duplicate config */
2375 return 0;
2376
2377 /* Label change, update clients. */
2378 old_label = fec->label;
2379 if (IS_ZEBRA_DEBUG_MPLS)
2380 zlog_debug("Update fec %s new label %u", buf, in_label);
2381
2382 fec->label = in_label;
2383 fec_update_clients(fec);
2384
2385 /* Update label forwarding entries appropriately */
2386 ret = fec_change_update_lsp(zvrf, fec, old_label);
2387 }
2388
2389 return ret;
2390 }
2391
2392 /*
2393 * Remove static FEC to label binding. If there are no clients registered
2394 * for this FEC, delete the FEC; else notify clients
2395 * Note: Upon delete of static binding, if label index exists for this FEC,
2396 * client may need to be updated with derived label.
2397 */
2398 int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
2399 {
2400 struct route_table *table;
2401 zebra_fec_t *fec;
2402 mpls_label_t old_label;
2403 char buf[BUFSIZ];
2404
2405 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2406 if (!table)
2407 return -1;
2408
2409 fec = fec_find(table, p);
2410 if (!fec) {
2411 prefix2str(p, buf, BUFSIZ);
2412 flog_err(EC_ZEBRA_FEC_RM_FAILED,
2413 "Failed to find FEC %s upon delete", buf);
2414 return -1;
2415 }
2416
2417 if (IS_ZEBRA_DEBUG_MPLS) {
2418 prefix2str(p, buf, BUFSIZ);
2419 zlog_debug("Delete fec %s label %u label index %u", buf,
2420 fec->label, fec->label_index);
2421 }
2422
2423 old_label = fec->label;
2424 fec->flags &= ~FEC_FLAG_CONFIGURED;
2425 fec->label = MPLS_INVALID_LABEL;
2426
2427 /* If no client exists, just delete the FEC. */
2428 if (list_isempty(fec->client_list)) {
2429 fec_del(fec);
2430 return 0;
2431 }
2432
2433 /* Derive the local label (from label index) or reset it. */
2434 fec_derive_label_from_index(zvrf, fec);
2435
2436 /* If there is a label change, update clients. */
2437 if (fec->label == old_label)
2438 return 0;
2439 fec_update_clients(fec);
2440
2441 /* Update label forwarding entries appropriately */
2442 return fec_change_update_lsp(zvrf, fec, old_label);
2443 }
2444
2445 /*
2446 * Display MPLS FEC to label binding configuration (VTY command handler).
2447 */
2448 int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
2449 {
2450 struct route_node *rn;
2451 int af;
2452 zebra_fec_t *fec;
2453 char buf[BUFSIZ];
2454 int write = 0;
2455
2456 for (af = AFI_IP; af < AFI_MAX; af++) {
2457 if (zvrf->fec_table[af] == NULL)
2458 continue;
2459
2460 for (rn = route_top(zvrf->fec_table[af]); rn;
2461 rn = route_next(rn)) {
2462 if (!rn->info)
2463 continue;
2464
2465 char lstr[BUFSIZ];
2466 fec = rn->info;
2467
2468 if (!(fec->flags & FEC_FLAG_CONFIGURED))
2469 continue;
2470
2471 write = 1;
2472 prefix2str(&rn->p, buf, BUFSIZ);
2473 vty_out(vty, "mpls label bind %s %s\n", buf,
2474 label2str(fec->label, lstr, BUFSIZ));
2475 }
2476 }
2477
2478 return write;
2479 }
2480
2481 /*
2482 * Display MPLS FEC to label binding (VTY command handler).
2483 */
2484 void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
2485 {
2486 struct route_node *rn;
2487 int af;
2488
2489 for (af = AFI_IP; af < AFI_MAX; af++) {
2490 if (zvrf->fec_table[af] == NULL)
2491 continue;
2492
2493 for (rn = route_top(zvrf->fec_table[af]); rn;
2494 rn = route_next(rn)) {
2495 if (!rn->info)
2496 continue;
2497 fec_print(rn->info, vty);
2498 }
2499 }
2500 }
2501
2502 /*
2503 * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2504 */
2505 void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
2506 struct prefix *p)
2507 {
2508 struct route_table *table;
2509 struct route_node *rn;
2510
2511 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2512 if (!table)
2513 return;
2514
2515 apply_mask(p);
2516 rn = route_node_lookup(table, p);
2517 if (!rn)
2518 return;
2519
2520 route_unlock_node(rn);
2521 if (!rn->info)
2522 return;
2523
2524 fec_print(rn->info, vty);
2525 }
2526
2527 static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop,
2528 enum lsp_types_t type, mpls_label_t label)
2529 {
2530 if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2531 nexthop_add_labels(nexthop, type, 1, &label);
2532 else if (!add && nexthop->nh_label_type == type)
2533 nexthop_del_labels(nexthop);
2534 else
2535 return false;
2536
2537 return true;
2538 }
2539
2540 /*
2541 * Install/uninstall a FEC-To-NHLFE (FTN) binding.
2542 */
2543 int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
2544 struct prefix *prefix, enum nexthop_types_t gtype,
2545 union g_addr *gate, ifindex_t ifindex, uint8_t distance,
2546 mpls_label_t out_label)
2547 {
2548 struct route_table *table;
2549 struct route_node *rn;
2550 struct route_entry *re;
2551 struct nexthop *nexthop;
2552 bool found;
2553
2554 /* Lookup table. */
2555 table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
2556 zvrf_id(zvrf));
2557 if (!table)
2558 return -1;
2559
2560 /* Lookup existing route */
2561 rn = route_node_get(table, prefix);
2562 RNODE_FOREACH_RE (rn, re) {
2563 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2564 continue;
2565 if (re->distance == distance)
2566 break;
2567 }
2568
2569 if (re == NULL)
2570 return -1;
2571
2572 found = false;
2573 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
2574 switch (nexthop->type) {
2575 case NEXTHOP_TYPE_IPV4:
2576 case NEXTHOP_TYPE_IPV4_IFINDEX:
2577 if (gtype != NEXTHOP_TYPE_IPV4
2578 && gtype != NEXTHOP_TYPE_IPV4_IFINDEX)
2579 continue;
2580 if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4))
2581 continue;
2582 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
2583 && nexthop->ifindex != ifindex)
2584 continue;
2585 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2586 out_label))
2587 return 0;
2588 found = true;
2589 break;
2590 case NEXTHOP_TYPE_IPV6:
2591 case NEXTHOP_TYPE_IPV6_IFINDEX:
2592 if (gtype != NEXTHOP_TYPE_IPV6
2593 && gtype != NEXTHOP_TYPE_IPV6_IFINDEX)
2594 continue;
2595 if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, &gate->ipv6))
2596 continue;
2597 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
2598 && nexthop->ifindex != ifindex)
2599 continue;
2600 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2601 out_label))
2602 return 0;
2603 found = true;
2604 break;
2605 default:
2606 break;
2607 }
2608 }
2609
2610 if (!found)
2611 return -1;
2612
2613 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2614 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
2615 rib_queue_add(rn);
2616
2617 return 0;
2618 }
2619
2620 /*
2621 * Install/update a NHLFE for an LSP in the forwarding table. This may be
2622 * a new LSP entry or a new NHLFE for an existing in-label or an update of
2623 * the out-label for an existing NHLFE (update case).
2624 */
2625 int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
2626 mpls_label_t in_label, mpls_label_t out_label,
2627 enum nexthop_types_t gtype, union g_addr *gate,
2628 ifindex_t ifindex)
2629 {
2630 struct hash *lsp_table;
2631 zebra_ile_t tmp_ile;
2632 zebra_lsp_t *lsp;
2633 zebra_nhlfe_t *nhlfe;
2634 char buf[BUFSIZ];
2635
2636 /* Lookup table. */
2637 lsp_table = zvrf->lsp_table;
2638 if (!lsp_table)
2639 return -1;
2640
2641 /* If entry is present, exit. */
2642 tmp_ile.in_label = in_label;
2643 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2644 if (!lsp)
2645 return -1;
2646 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2647 if (nhlfe) {
2648 struct nexthop *nh = nhlfe->nexthop;
2649
2650 assert(nh);
2651 assert(nh->nh_label);
2652
2653 /* Clear deleted flag (in case it was set) */
2654 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2655 if (nh->nh_label->label[0] == out_label)
2656 /* No change */
2657 return 0;
2658
2659 if (IS_ZEBRA_DEBUG_MPLS) {
2660 nhlfe2str(nhlfe, buf, BUFSIZ);
2661 zlog_debug(
2662 "LSP in-label %u type %d nexthop %s "
2663 "out-label changed to %u (old %u)",
2664 in_label, type, buf, out_label,
2665 nh->nh_label->label[0]);
2666 }
2667
2668 /* Update out label, trigger processing. */
2669 nh->nh_label->label[0] = out_label;
2670 } else {
2671 /* Add LSP entry to this nexthop */
2672 nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, out_label);
2673 if (!nhlfe)
2674 return -1;
2675
2676 if (IS_ZEBRA_DEBUG_MPLS) {
2677 nhlfe2str(nhlfe, buf, BUFSIZ);
2678 zlog_debug(
2679 "Add LSP in-label %u type %d nexthop %s "
2680 "out-label %u",
2681 in_label, type, buf, out_label);
2682 }
2683
2684 lsp->addr_family = NHLFE_FAMILY(nhlfe);
2685 }
2686
2687 /* Mark NHLFE, queue LSP for processing. */
2688 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2689 if (lsp_processq_add(lsp))
2690 return -1;
2691
2692 return 0;
2693 }
2694
2695 /*
2696 * Uninstall a particular NHLFE in the forwarding table. If this is
2697 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
2698 */
2699 int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2700 mpls_label_t in_label, enum nexthop_types_t gtype,
2701 union g_addr *gate, ifindex_t ifindex)
2702 {
2703 struct hash *lsp_table;
2704 zebra_ile_t tmp_ile;
2705 zebra_lsp_t *lsp;
2706 zebra_nhlfe_t *nhlfe;
2707 char buf[BUFSIZ];
2708
2709 /* Lookup table. */
2710 lsp_table = zvrf->lsp_table;
2711 if (!lsp_table)
2712 return -1;
2713
2714 /* If entry is not present, exit. */
2715 tmp_ile.in_label = in_label;
2716 lsp = hash_lookup(lsp_table, &tmp_ile);
2717 if (!lsp)
2718 return 0;
2719 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2720 if (!nhlfe)
2721 return 0;
2722
2723 if (IS_ZEBRA_DEBUG_MPLS) {
2724 nhlfe2str(nhlfe, buf, BUFSIZ);
2725 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
2726 in_label, type, buf, nhlfe->flags);
2727 }
2728
2729 /* Mark NHLFE for delete or directly delete, as appropriate. */
2730 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
2731 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2732 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2733 if (lsp_processq_add(lsp))
2734 return -1;
2735 } else {
2736 nhlfe_del(nhlfe);
2737
2738 /* Free LSP entry if no other NHLFEs and not scheduled. */
2739 if (!lsp->nhlfe_list
2740 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
2741 if (IS_ZEBRA_DEBUG_MPLS)
2742 zlog_debug("Free LSP in-label %u flags 0x%x",
2743 lsp->ile.in_label, lsp->flags);
2744
2745 lsp = hash_release(lsp_table, &lsp->ile);
2746 XFREE(MTYPE_LSP, lsp);
2747 }
2748 }
2749 return 0;
2750 }
2751
2752 /*
2753 * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
2754 * If no other NHLFEs exist, the entry would be deleted.
2755 */
2756 void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt)
2757 {
2758 zebra_lsp_t *lsp;
2759 struct hash *lsp_table;
2760
2761 lsp = (zebra_lsp_t *)bucket->data;
2762 if (!lsp->nhlfe_list)
2763 return;
2764
2765 lsp_table = ctxt;
2766 if (!lsp_table)
2767 return;
2768
2769 mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP);
2770 }
2771
2772 /*
2773 * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
2774 */
2775 void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
2776 {
2777 struct route_table *table;
2778 struct route_node *rn;
2779 struct route_entry *re;
2780 struct nexthop *nexthop;
2781 int update;
2782
2783 /* Process routes of interested address-families. */
2784 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2785 if (!table)
2786 return;
2787
2788 for (rn = route_top(table); rn; rn = route_next(rn)) {
2789 update = 0;
2790 RNODE_FOREACH_RE (rn, re) {
2791 for (nexthop = re->ng.nexthop; nexthop;
2792 nexthop = nexthop->next) {
2793 if (nexthop->nh_label_type != ZEBRA_LSP_LDP)
2794 continue;
2795
2796 nexthop_del_labels(nexthop);
2797 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2798 SET_FLAG(re->status,
2799 ROUTE_ENTRY_LABELS_CHANGED);
2800 update = 1;
2801 }
2802 }
2803
2804 if (update)
2805 rib_queue_add(rn);
2806 }
2807 }
2808
2809 #if defined(HAVE_CUMULUS)
2810 /*
2811 * Check that the label values used in LSP creation are consistent. The
2812 * main criteria is that if there is ECMP, the label operation must still
2813 * be consistent - i.e., all paths either do a swap or do PHP. This is due
2814 * to current HW restrictions.
2815 */
2816 int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
2817 mpls_label_t in_label,
2818 mpls_label_t out_label,
2819 enum nexthop_types_t gtype,
2820 union g_addr *gate, ifindex_t ifindex)
2821 {
2822 struct hash *slsp_table;
2823 zebra_ile_t tmp_ile;
2824 zebra_slsp_t *slsp;
2825 zebra_snhlfe_t *snhlfe;
2826
2827 /* Lookup table. */
2828 slsp_table = zvrf->slsp_table;
2829 if (!slsp_table)
2830 return 0;
2831
2832 /* If entry is not present, exit. */
2833 tmp_ile.in_label = in_label;
2834 slsp = hash_lookup(slsp_table, &tmp_ile);
2835 if (!slsp)
2836 return 1;
2837
2838 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2839 if (snhlfe) {
2840 if (snhlfe->out_label == out_label)
2841 return 1;
2842
2843 /* If not only NHLFE, cannot allow label change. */
2844 if (snhlfe != slsp->snhlfe_list || snhlfe->next)
2845 return 0;
2846 } else {
2847 /* If other NHLFEs exist, label operation must match. */
2848 if (slsp->snhlfe_list) {
2849 int cur_op, new_op;
2850
2851 cur_op = (slsp->snhlfe_list->out_label
2852 == MPLS_LABEL_IMPLICIT_NULL);
2853 new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
2854 if (cur_op != new_op)
2855 return 0;
2856 }
2857 }
2858
2859 /* Label values are good. */
2860 return 1;
2861 }
2862 #endif /* HAVE_CUMULUS */
2863
2864 /*
2865 * Add static LSP entry. This may be the first entry for this incoming label
2866 * or an additional nexthop; an existing entry may also have outgoing label
2867 * changed.
2868 * Note: The label operation (swap or PHP) is common for the LSP entry (all
2869 * NHLFEs).
2870 */
2871 int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
2872 mpls_label_t out_label,
2873 enum nexthop_types_t gtype, union g_addr *gate,
2874 ifindex_t ifindex)
2875 {
2876 struct hash *slsp_table;
2877 zebra_ile_t tmp_ile;
2878 zebra_slsp_t *slsp;
2879 zebra_snhlfe_t *snhlfe;
2880 char buf[BUFSIZ];
2881
2882 /* Lookup table. */
2883 slsp_table = zvrf->slsp_table;
2884 if (!slsp_table)
2885 return -1;
2886
2887 /* If entry is present, exit. */
2888 tmp_ile.in_label = in_label;
2889 slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc);
2890 if (!slsp)
2891 return -1;
2892 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2893 if (snhlfe) {
2894 if (snhlfe->out_label == out_label)
2895 /* No change */
2896 return 0;
2897
2898 if (IS_ZEBRA_DEBUG_MPLS) {
2899 snhlfe2str(snhlfe, buf, BUFSIZ);
2900 zlog_debug(
2901 "Upd static LSP in-label %u nexthop %s "
2902 "out-label %u (old %u)",
2903 in_label, buf, out_label, snhlfe->out_label);
2904 }
2905 snhlfe->out_label = out_label;
2906 } else {
2907 /* Add static LSP entry to this nexthop */
2908 snhlfe = snhlfe_add(slsp, gtype, gate, ifindex, out_label);
2909 if (!snhlfe)
2910 return -1;
2911
2912 if (IS_ZEBRA_DEBUG_MPLS) {
2913 snhlfe2str(snhlfe, buf, BUFSIZ);
2914 zlog_debug(
2915 "Add static LSP in-label %u nexthop %s out-label %u",
2916 in_label, buf, out_label);
2917 }
2918 }
2919
2920 /* (Re)Install LSP in the main table. */
2921 if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
2922 gate, ifindex))
2923 return -1;
2924
2925 return 0;
2926 }
2927
2928 /*
2929 * Delete static LSP entry. This may be the delete of one particular
2930 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
2931 * all NHLFEs).
2932 * NOTE: Delete of the only NHLFE will also end up deleting the entire
2933 * LSP configuration.
2934 */
2935 int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
2936 enum nexthop_types_t gtype, union g_addr *gate,
2937 ifindex_t ifindex)
2938 {
2939 struct hash *slsp_table;
2940 zebra_ile_t tmp_ile;
2941 zebra_slsp_t *slsp;
2942 zebra_snhlfe_t *snhlfe;
2943
2944 /* Lookup table. */
2945 slsp_table = zvrf->slsp_table;
2946 if (!slsp_table)
2947 return -1;
2948
2949 /* If entry is not present, exit. */
2950 tmp_ile.in_label = in_label;
2951 slsp = hash_lookup(slsp_table, &tmp_ile);
2952 if (!slsp)
2953 return 0;
2954
2955 /* Is it delete of entire LSP or a specific NHLFE? */
2956 if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
2957 if (IS_ZEBRA_DEBUG_MPLS)
2958 zlog_debug("Del static LSP in-label %u", in_label);
2959
2960 /* Uninstall entire LSP from the main table. */
2961 mpls_static_lsp_uninstall_all(zvrf, in_label);
2962
2963 /* Delete all static NHLFEs */
2964 snhlfe_del_all(slsp);
2965 } else {
2966 /* Find specific NHLFE, exit if not found. */
2967 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2968 if (!snhlfe)
2969 return 0;
2970
2971 if (IS_ZEBRA_DEBUG_MPLS) {
2972 char buf[BUFSIZ];
2973 snhlfe2str(snhlfe, buf, BUFSIZ);
2974 zlog_debug("Del static LSP in-label %u nexthop %s",
2975 in_label, buf);
2976 }
2977
2978 /* Uninstall LSP from the main table. */
2979 mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
2980 gate, ifindex);
2981
2982 /* Delete static LSP NHLFE */
2983 snhlfe_del(snhlfe);
2984 }
2985
2986 /* Remove entire static LSP entry if no NHLFE - valid in either case
2987 * above. */
2988 if (!slsp->snhlfe_list) {
2989 slsp = hash_release(slsp_table, &tmp_ile);
2990 XFREE(MTYPE_SLSP, slsp);
2991 }
2992
2993 return 0;
2994 }
2995
2996 /*
2997 * Schedule all MPLS label forwarding entries for processing.
2998 * Called upon changes that may affect one or more of them such as
2999 * interface or nexthop state changes.
3000 */
3001 void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
3002 {
3003 if (!zvrf)
3004 return;
3005 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
3006 }
3007
3008 /*
3009 * Display MPLS label forwarding table for a specific LSP
3010 * (VTY command handler).
3011 */
3012 void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
3013 mpls_label_t label, bool use_json)
3014 {
3015 struct hash *lsp_table;
3016 zebra_lsp_t *lsp;
3017 zebra_ile_t tmp_ile;
3018 json_object *json = NULL;
3019
3020 /* Lookup table. */
3021 lsp_table = zvrf->lsp_table;
3022 if (!lsp_table)
3023 return;
3024
3025 /* If entry is not present, exit. */
3026 tmp_ile.in_label = label;
3027 lsp = hash_lookup(lsp_table, &tmp_ile);
3028 if (!lsp)
3029 return;
3030
3031 if (use_json) {
3032 json = lsp_json(lsp);
3033 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3034 json, JSON_C_TO_STRING_PRETTY));
3035 json_object_free(json);
3036 } else
3037 lsp_print(lsp, (void *)vty);
3038 }
3039
3040 /*
3041 * Display MPLS label forwarding table (VTY command handler).
3042 */
3043 void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
3044 bool use_json)
3045 {
3046 char buf[BUFSIZ];
3047 json_object *json = NULL;
3048 zebra_lsp_t *lsp = NULL;
3049 zebra_nhlfe_t *nhlfe = NULL;
3050 struct nexthop *nexthop = NULL;
3051 struct listnode *node = NULL;
3052 struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
3053
3054 if (use_json) {
3055 json = json_object_new_object();
3056
3057 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
3058 json_object_object_add(
3059 json, label2str(lsp->ile.in_label, buf, BUFSIZ),
3060 lsp_json(lsp));
3061
3062 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3063 json, JSON_C_TO_STRING_PRETTY));
3064 json_object_free(json);
3065 } else {
3066 vty_out(vty, " Inbound Outbound\n");
3067 vty_out(vty, " Label Type Nexthop Label\n");
3068 vty_out(vty, "-------- ------- --------------- --------\n");
3069
3070 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
3071 for (nhlfe = lsp->nhlfe_list; nhlfe;
3072 nhlfe = nhlfe->next) {
3073 vty_out(vty, "%8d %7s ", lsp->ile.in_label,
3074 nhlfe_type2str(nhlfe->type));
3075 nexthop = nhlfe->nexthop;
3076
3077 switch (nexthop->type) {
3078 case NEXTHOP_TYPE_IFINDEX: {
3079 struct zebra_ns *zns;
3080 struct interface *ifp;
3081
3082 zns = zebra_ns_lookup(NS_DEFAULT);
3083 ifp = if_lookup_by_index_per_ns(
3084 zns,
3085 nexthop->ifindex);
3086 if (ifp)
3087 vty_out(vty, "%15s", ifp->name);
3088 else
3089 vty_out(vty, "%15s", "Null");
3090
3091 break;
3092 }
3093 case NEXTHOP_TYPE_IPV4:
3094 case NEXTHOP_TYPE_IPV4_IFINDEX:
3095 vty_out(vty, "%15s",
3096 inet_ntoa(nexthop->gate.ipv4));
3097 break;
3098 case NEXTHOP_TYPE_IPV6:
3099 case NEXTHOP_TYPE_IPV6_IFINDEX:
3100 vty_out(vty, "%15s",
3101 inet_ntop(AF_INET6,
3102 &nexthop->gate.ipv6,
3103 buf, BUFSIZ));
3104 break;
3105 default:
3106 break;
3107 }
3108
3109 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
3110 vty_out(vty, " %8s\n",
3111 mpls_label2str(
3112 nexthop->nh_label
3113 ->num_labels,
3114 &nexthop->nh_label
3115 ->label[0],
3116 buf, BUFSIZ, 1));
3117 else
3118 vty_out(vty, "\n");
3119 }
3120 }
3121
3122 vty_out(vty, "\n");
3123 }
3124
3125 list_delete(&lsp_list);
3126 }
3127
3128 /*
3129 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
3130 */
3131 int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
3132 {
3133 zebra_slsp_t *slsp;
3134 zebra_snhlfe_t *snhlfe;
3135 struct listnode *node;
3136 struct list *slsp_list =
3137 hash_get_sorted_list(zvrf->slsp_table, slsp_cmp);
3138
3139 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) {
3140 for (snhlfe = slsp->snhlfe_list; snhlfe;
3141 snhlfe = snhlfe->next) {
3142 char buf[BUFSIZ];
3143 char lstr[30];
3144
3145 snhlfe2str(snhlfe, buf, sizeof(buf));
3146 switch (snhlfe->out_label) {
3147 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
3148 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
3149 strlcpy(lstr, "explicit-null", sizeof(lstr));
3150 break;
3151 case MPLS_LABEL_IMPLICIT_NULL:
3152 strlcpy(lstr, "implicit-null", sizeof(lstr));
3153 break;
3154 default:
3155 sprintf(lstr, "%u", snhlfe->out_label);
3156 break;
3157 }
3158
3159 vty_out(vty, "mpls lsp %u %s %s\n", slsp->ile.in_label,
3160 buf, lstr);
3161 }
3162 }
3163
3164 list_delete(&slsp_list);
3165 return (zvrf->slsp_table->count ? 1 : 0);
3166 }
3167
3168 /*
3169 * Add/update global label block.
3170 */
3171 int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
3172 uint32_t end_label)
3173 {
3174 zvrf->mpls_srgb.start_label = start_label;
3175 zvrf->mpls_srgb.end_label = end_label;
3176
3177 /* Evaluate registered FECs to see if any get a label or not. */
3178 fec_evaluate(zvrf);
3179 return 0;
3180 }
3181
3182 /*
3183 * Delete global label block.
3184 */
3185 int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
3186 {
3187 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3188 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
3189
3190 /* Process registered FECs to clear their local label, if needed. */
3191 fec_evaluate(zvrf);
3192 return 0;
3193 }
3194
3195 /*
3196 * Display MPLS global label block configuration (VTY command handler).
3197 */
3198 int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
3199 {
3200 if (zvrf->mpls_srgb.start_label == 0)
3201 return 0;
3202
3203 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
3204 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
3205 vty_out(vty, "mpls label global-block %u %u\n",
3206 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
3207 }
3208
3209 return 1;
3210 }
3211
3212 /*
3213 * Called when VRF becomes inactive, cleans up information but keeps
3214 * the table itself.
3215 */
3216 void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
3217 {
3218 struct zebra_vrf *def_zvrf;
3219 afi_t afi;
3220
3221 if (zvrf_id(zvrf) == VRF_DEFAULT)
3222 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3223 else {
3224 /*
3225 * For other vrfs, we try to remove associated LSPs; we locate
3226 * the LSPs in the default vrf.
3227 */
3228 def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3229
3230 /* At shutdown, the default may be gone already */
3231 if (def_zvrf == NULL)
3232 return;
3233
3234 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
3235 if (zvrf->label[afi] != MPLS_LABEL_NONE)
3236 lsp_uninstall(def_zvrf, zvrf->label[afi]);
3237 }
3238 }
3239 }
3240
3241 /*
3242 * Called upon process exiting, need to delete LSP forwarding
3243 * entries from the kernel.
3244 * NOTE: Currently supported only for default VRF.
3245 */
3246 void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
3247 {
3248 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3249 hash_clean(zvrf->lsp_table, NULL);
3250 hash_free(zvrf->lsp_table);
3251 hash_clean(zvrf->slsp_table, NULL);
3252 hash_free(zvrf->slsp_table);
3253 route_table_finish(zvrf->fec_table[AFI_IP]);
3254 route_table_finish(zvrf->fec_table[AFI_IP6]);
3255 }
3256
3257 /*
3258 * Allocate MPLS tables for this VRF and do other initialization.
3259 * NOTE: Currently supported only for default VRF.
3260 */
3261 void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
3262 {
3263 if (!zvrf)
3264 return;
3265 zvrf->slsp_table =
3266 hash_create(label_hash, label_cmp, "ZEBRA SLSP table");
3267 zvrf->lsp_table = hash_create(label_hash, label_cmp, "ZEBRA LSP table");
3268 zvrf->fec_table[AFI_IP] = route_table_init();
3269 zvrf->fec_table[AFI_IP6] = route_table_init();
3270 zvrf->mpls_flags = 0;
3271 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3272 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
3273 }
3274
3275 /*
3276 * Global MPLS initialization.
3277 */
3278 void zebra_mpls_init(void)
3279 {
3280 mpls_enabled = 0;
3281
3282 if (mpls_kernel_init() < 0) {
3283 flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
3284 "Disabling MPLS support (no kernel support)");
3285 return;
3286 }
3287
3288 if (!mpls_processq_init())
3289 mpls_enabled = 1;
3290
3291 hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
3292 }