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