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