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