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