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