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