]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mpls.c
mpls: add support to the OpenBSD kernel
[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
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 #include <zebra.h>
23
24 #include "prefix.h"
25 #include "table.h"
26 #include "memory.h"
27 #include "str.h"
28 #include "command.h"
29 #include "if.h"
30 #include "log.h"
31 #include "sockunion.h"
32 #include "linklist.h"
33 #include "thread.h"
34 #include "workqueue.h"
35 #include "prefix.h"
36 #include "routemap.h"
37 #include "stream.h"
38 #include "nexthop.h"
39 #include "lib/json.h"
40
41 #include "zebra/rib.h"
42 #include "zebra/rt.h"
43 #include "zebra/zserv.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
50 DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object")
51 DEFINE_MTYPE_STATIC(ZEBRA, SLSP, "MPLS static LSP config")
52 DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object")
53 DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE, "MPLS static nexthop object")
54 DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE_IFNAME, "MPLS static nexthop ifname")
55
56 /* Default rtm_table for all clients */
57 extern struct zebra_t zebrad;
58
59 /* static function declarations */
60 static unsigned int
61 label_hash (void *p);
62 static int
63 label_cmp (const void *p1, const void *p2);
64 static int
65 nhlfe_nexthop_active_ipv4 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop);
66 static int
67 nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop);
68 static int
69 nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe);
70 static void
71 lsp_select_best_nhlfe (zebra_lsp_t *lsp);
72 static void
73 lsp_uninstall_from_kernel (struct hash_backet *backet, void *ctxt);
74 static void
75 lsp_schedule (struct hash_backet *backet, void *ctxt);
76 static wq_item_status
77 lsp_process (struct work_queue *wq, void *data);
78 static void
79 lsp_processq_del (struct work_queue *wq, void *data);
80 static void
81 lsp_processq_complete (struct work_queue *wq);
82 static int
83 lsp_processq_add (zebra_lsp_t *lsp);
84 static void *
85 lsp_alloc (void *p);
86 static char *
87 nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size);
88 static int
89 nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
90 union g_addr *gate, char *ifname, ifindex_t ifindex);
91 static zebra_nhlfe_t *
92 nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
93 enum nexthop_types_t gtype, union g_addr *gate,
94 char *ifname, ifindex_t ifindex);
95 static zebra_nhlfe_t *
96 nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
97 enum nexthop_types_t gtype, union g_addr *gate,
98 char *ifname, ifindex_t ifindex, mpls_label_t out_label);
99 static int
100 nhlfe_del (zebra_nhlfe_t *snhlfe);
101 static int
102 mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
103 enum lsp_types_t type);
104 static int
105 mpls_static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label);
106 static void
107 nhlfe_print (zebra_nhlfe_t *nhlfe, struct vty *vty);
108 static void
109 lsp_print (zebra_lsp_t *lsp, void *ctxt);
110 static void *
111 slsp_alloc (void *p);
112 static int
113 snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
114 union g_addr *gate, char *ifname, ifindex_t ifindex);
115 static zebra_snhlfe_t *
116 snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
117 union g_addr *gate, char *ifname, ifindex_t ifindex);
118 static zebra_snhlfe_t *
119 snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
120 union g_addr *gate, char *ifname, ifindex_t ifindex,
121 mpls_label_t out_label);
122 static int
123 snhlfe_del (zebra_snhlfe_t *snhlfe);
124 static int
125 snhlfe_del_all (zebra_slsp_t *slsp);
126 static char *
127 snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size);
128 static void
129 mpls_processq_init (struct zebra_t *zebra);
130
131
132
133
134 /* Static functions */
135
136 /*
137 * Hash function for label.
138 */
139 static unsigned int
140 label_hash (void *p)
141 {
142 const zebra_ile_t *ile = p;
143
144 return (jhash_1word(ile->in_label, 0));
145 }
146
147 /*
148 * Compare 2 LSP hash entries based on in-label.
149 */
150 static int
151 label_cmp (const void *p1, const void *p2)
152 {
153 const zebra_ile_t *ile1 = p1;
154 const zebra_ile_t *ile2 = p2;
155
156 return (ile1->in_label == ile2->in_label);
157 }
158
159 /*
160 * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
161 * the passed flag.
162 * NOTE: Looking only for connected routes right now.
163 */
164 static int
165 nhlfe_nexthop_active_ipv4 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop)
166 {
167 struct route_table *table;
168 struct prefix_ipv4 p;
169 struct route_node *rn;
170 struct rib *match;
171
172 table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
173 if (!table)
174 return 0;
175
176 /* Lookup nexthop in IPv4 routing table. */
177 memset (&p, 0, sizeof (struct prefix_ipv4));
178 p.family = AF_INET;
179 p.prefixlen = IPV4_MAX_PREFIXLEN;
180 p.prefix = nexthop->gate.ipv4;
181
182 rn = route_node_match (table, (struct prefix *) &p);
183 if (!rn)
184 return 0;
185
186 route_unlock_node (rn);
187
188 /* Locate a valid connected route. */
189 RNODE_FOREACH_RIB (rn, match)
190 {
191 if ((match->type == ZEBRA_ROUTE_CONNECT) &&
192 !CHECK_FLAG (match->status, RIB_ENTRY_REMOVED) &&
193 CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
194 break;
195 }
196
197 if (!match || !match->nexthop)
198 return 0;
199
200 nexthop->ifindex = match->nexthop->ifindex;
201 return 1;
202 }
203
204
205 /*
206 * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
207 * the passed flag.
208 * NOTE: Looking only for connected routes right now.
209 */
210 static int
211 nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop)
212 {
213 struct route_table *table;
214 struct prefix_ipv6 p;
215 struct route_node *rn;
216 struct rib *match;
217
218 table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT);
219 if (!table)
220 return 0;
221
222 /* Lookup nexthop in IPv6 routing table. */
223 memset (&p, 0, sizeof (struct prefix_ipv6));
224 p.family = AF_INET6;
225 p.prefixlen = IPV6_MAX_PREFIXLEN;
226 p.prefix = nexthop->gate.ipv6;
227
228 rn = route_node_match (table, (struct prefix *) &p);
229 if (!rn)
230 return 0;
231
232 route_unlock_node (rn);
233
234 /* Locate a valid connected route. */
235 RNODE_FOREACH_RIB (rn, match)
236 {
237 if ((match->type == ZEBRA_ROUTE_CONNECT) &&
238 !CHECK_FLAG (match->status, RIB_ENTRY_REMOVED) &&
239 CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
240 break;
241 }
242
243 if (!match || !match->nexthop)
244 return 0;
245
246 nexthop->ifindex = match->nexthop->ifindex;
247 return 1;
248 }
249
250
251 /*
252 * Check the nexthop reachability for a NHLFE and return if valid (reachable)
253 * or not.
254 * NOTE: Each NHLFE points to only 1 nexthop.
255 */
256 static int
257 nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe)
258 {
259 struct nexthop *nexthop;
260 struct interface *ifp;
261
262 nexthop = nhlfe->nexthop;
263 if (!nexthop) // unexpected
264 return 0;
265
266 /* Check on nexthop based on type. */
267 switch (nexthop->type)
268 {
269 case NEXTHOP_TYPE_IPV4:
270 if (nhlfe_nexthop_active_ipv4 (nhlfe, nexthop))
271 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
272 else
273 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
274 break;
275
276 case NEXTHOP_TYPE_IPV6:
277 if (nhlfe_nexthop_active_ipv6 (nhlfe, nexthop))
278 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
279 else
280 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
281 break;
282
283 case NEXTHOP_TYPE_IPV6_IFINDEX:
284 if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
285 {
286 ifp = if_lookup_by_index (nexthop->ifindex);
287 if (ifp && if_is_operative(ifp))
288 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
289 else
290 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
291 }
292 else
293 {
294 if (nhlfe_nexthop_active_ipv6 (nhlfe, nexthop))
295 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
296 else
297 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
298 }
299 break;
300
301 default:
302 break;
303 }
304
305 return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
306 }
307
308 /*
309 * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
310 * reachability and select the best. Multipath entries are also
311 * marked. This is invoked when an LSP scheduled for processing (due
312 * to some change) is examined.
313 */
314 static void
315 lsp_select_best_nhlfe (zebra_lsp_t *lsp)
316 {
317 zebra_nhlfe_t *nhlfe;
318 zebra_nhlfe_t *best;
319 struct nexthop *nexthop;
320 int changed = 0;
321
322 if (!lsp)
323 return;
324
325 best = NULL;
326 lsp->num_ecmp = 0;
327 UNSET_FLAG (lsp->flags, LSP_FLAG_CHANGED);
328
329 /*
330 * First compute the best path, after checking nexthop status. We are only
331 * concerned with non-deleted NHLFEs.
332 */
333 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
334 {
335 /* Clear selection flags. */
336 UNSET_FLAG (nhlfe->flags,
337 (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
338
339 if (!CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED) &&
340 nhlfe_nexthop_active (nhlfe))
341 {
342 if (!best || (nhlfe->distance < best->distance))
343 best = nhlfe;
344 }
345 }
346
347 lsp->best_nhlfe = best;
348 if (!lsp->best_nhlfe)
349 return;
350
351 /* Mark best NHLFE as selected. */
352 SET_FLAG (lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
353
354 /*
355 * If best path exists, see if there is ECMP. While doing this, note if a
356 * new (uninstalled) NHLFE has been selected, an installed entry that is
357 * still selected has a change or an installed entry is to be removed.
358 */
359 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
360 {
361 int nh_chg, nh_sel, nh_inst;
362
363 nexthop = nhlfe->nexthop;
364 if (!nexthop) // unexpected
365 continue;
366
367 if (!CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED) &&
368 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
369 (nhlfe->distance == lsp->best_nhlfe->distance))
370 {
371 SET_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED);
372 SET_FLAG (nhlfe->flags, NHLFE_FLAG_MULTIPATH);
373 lsp->num_ecmp++;
374 }
375
376 if (CHECK_FLAG (lsp->flags, LSP_FLAG_INSTALLED) &&
377 !changed)
378 {
379 nh_chg = CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
380 nh_sel = CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED);
381 nh_inst = CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
382
383 if ((nh_sel && !nh_inst) ||
384 (nh_sel && nh_inst && nh_chg) ||
385 (nh_inst && !nh_sel))
386 changed = 1;
387 }
388
389 /* We have finished examining, clear changed flag. */
390 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
391 }
392
393 if (changed)
394 SET_FLAG (lsp->flags, LSP_FLAG_CHANGED);
395 }
396
397 /*
398 * Delete LSP forwarding entry from kernel, if installed. Called upon
399 * process exit.
400 */
401 static void
402 lsp_uninstall_from_kernel (struct hash_backet *backet, void *ctxt)
403 {
404 zebra_lsp_t *lsp;
405
406 lsp = (zebra_lsp_t *) backet->data;
407 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
408 kernel_del_lsp (lsp);
409 }
410
411 /*
412 * Schedule LSP forwarding entry for processing. Called upon changes
413 * that may impact LSPs such as nexthop / connected route changes.
414 */
415 static void
416 lsp_schedule (struct hash_backet *backet, void *ctxt)
417 {
418 zebra_lsp_t *lsp;
419
420 lsp = (zebra_lsp_t *) backet->data;
421 lsp_processq_add (lsp);
422 }
423
424 /*
425 * Process a LSP entry that is in the queue. Recalculate best NHLFE and
426 * any multipaths and update or delete from the kernel, as needed.
427 */
428 static wq_item_status
429 lsp_process (struct work_queue *wq, void *data)
430 {
431 zebra_lsp_t *lsp;
432 zebra_nhlfe_t *oldbest, *newbest;
433 char buf[BUFSIZ], buf2[BUFSIZ];
434
435 lsp = (zebra_lsp_t *)data;
436 if (!lsp) // unexpected
437 return WQ_SUCCESS;
438
439 oldbest = lsp->best_nhlfe;
440
441 /* Select best NHLFE(s) */
442 lsp_select_best_nhlfe (lsp);
443
444 newbest = lsp->best_nhlfe;
445
446 if (IS_ZEBRA_DEBUG_MPLS)
447 {
448 if (oldbest)
449 nhlfe2str (oldbest, buf, BUFSIZ);
450 if (newbest)
451 nhlfe2str (newbest, buf2, BUFSIZ);
452 zlog_debug ("Process LSP in-label %u oldbest %s newbest %s "
453 "flags 0x%x ecmp# %d",
454 lsp->ile.in_label, oldbest ? buf : "NULL",
455 newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
456 }
457
458 if (!CHECK_FLAG (lsp->flags, LSP_FLAG_INSTALLED))
459 {
460 /* Not already installed */
461 if (newbest)
462 kernel_add_lsp (lsp);
463 }
464 else
465 {
466 /* Installed, may need an update and/or delete. */
467 if (!newbest)
468 kernel_del_lsp (lsp);
469 else if (CHECK_FLAG (lsp->flags, LSP_FLAG_CHANGED))
470 kernel_upd_lsp (lsp);
471 }
472
473 return WQ_SUCCESS;
474 }
475
476
477 /*
478 * Callback upon processing completion of a LSP forwarding entry.
479 */
480 static void
481 lsp_processq_del (struct work_queue *wq, void *data)
482 {
483 struct zebra_vrf *zvrf;
484 zebra_lsp_t *lsp;
485 struct hash *lsp_table;
486 zebra_nhlfe_t *nhlfe, *nhlfe_next;
487
488 zvrf = vrf_info_lookup(VRF_DEFAULT);
489 assert (zvrf);
490
491 lsp_table = zvrf->lsp_table;
492 if (!lsp_table) // unexpected
493 return;
494
495 lsp = (zebra_lsp_t *)data;
496 if (!lsp) // unexpected
497 return;
498
499 /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs exist,
500 * delete LSP entry also.
501 */
502 UNSET_FLAG (lsp->flags, LSP_FLAG_SCHEDULED);
503
504 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next)
505 {
506 nhlfe_next = nhlfe->next;
507 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
508 nhlfe_del (nhlfe);
509 }
510
511 if (!lsp->nhlfe_list)
512 {
513 if (IS_ZEBRA_DEBUG_MPLS)
514 zlog_debug ("Free LSP in-label %u flags 0x%x",
515 lsp->ile.in_label, lsp->flags);
516
517 lsp = hash_release(lsp_table, &lsp->ile);
518 if (lsp)
519 XFREE(MTYPE_LSP, lsp);
520 }
521 }
522
523 /*
524 * Callback upon finishing the processing of all scheduled
525 * LSP forwarding entries.
526 */
527 static void
528 lsp_processq_complete (struct work_queue *wq)
529 {
530 /* Nothing to do for now. */
531 }
532
533 /*
534 * Add LSP forwarding entry to queue for subsequent processing.
535 */
536 static int
537 lsp_processq_add (zebra_lsp_t *lsp)
538 {
539 /* If already scheduled, exit. */
540 if (CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
541 return 0;
542
543 work_queue_add (zebrad.lsp_process_q, lsp);
544 SET_FLAG (lsp->flags, LSP_FLAG_SCHEDULED);
545 return 0;
546 }
547
548 /*
549 * Callback to allocate LSP forwarding table entry.
550 */
551 static void *
552 lsp_alloc (void *p)
553 {
554 const zebra_ile_t *ile = p;
555 zebra_lsp_t *lsp;
556
557 lsp = XCALLOC (MTYPE_LSP, sizeof(zebra_lsp_t));
558 lsp->ile = *ile;
559
560 if (IS_ZEBRA_DEBUG_MPLS)
561 zlog_debug ("Alloc LSP in-label %u", lsp->ile.in_label);
562
563 return ((void *)lsp);
564 }
565
566 /*
567 * Create printable string for NHLFE entry.
568 */
569 static char *
570 nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size)
571 {
572 struct nexthop *nexthop;
573
574 buf[0] = '\0';
575 nexthop = nhlfe->nexthop;
576 switch (nexthop->type)
577 {
578 case NEXTHOP_TYPE_IPV4:
579 inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, size);
580 break;
581 case NEXTHOP_TYPE_IPV6:
582 inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, size);
583 break;
584 default:
585 break;
586 }
587
588 return buf;
589 }
590
591 /*
592 * Check if NHLFE matches with search info passed.
593 */
594 static int
595 nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
596 union g_addr *gate, char *ifname, ifindex_t ifindex)
597 {
598 struct nexthop *nhop;
599 int cmp = 1;
600
601 nhop = nhlfe->nexthop;
602 if (!nhop)
603 return 1;
604
605 if (nhop->type != gtype)
606 return 1;
607
608 switch (nhop->type)
609 {
610 case NEXTHOP_TYPE_IPV4:
611 cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
612 sizeof(struct in_addr));
613 break;
614 case NEXTHOP_TYPE_IPV6:
615 case NEXTHOP_TYPE_IPV6_IFINDEX:
616 cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
617 sizeof(struct in6_addr));
618 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
619 cmp = !(nhop->ifindex == ifindex);
620 break;
621 default:
622 break;
623 }
624
625 return cmp;
626 }
627
628
629 /*
630 * Locate NHLFE that matches with passed info.
631 */
632 static zebra_nhlfe_t *
633 nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
634 enum nexthop_types_t gtype, union g_addr *gate,
635 char *ifname, ifindex_t ifindex)
636 {
637 zebra_nhlfe_t *nhlfe;
638
639 if (!lsp)
640 return NULL;
641
642 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
643 {
644 if (nhlfe->type != lsp_type)
645 continue;
646 if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifname, ifindex))
647 break;
648 }
649
650 return nhlfe;
651 }
652
653 /*
654 * Add NHLFE. Base entry must have been created and duplicate
655 * check done.
656 */
657 static zebra_nhlfe_t *
658 nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
659 enum nexthop_types_t gtype, union g_addr *gate,
660 char *ifname, ifindex_t ifindex, mpls_label_t out_label)
661 {
662 zebra_nhlfe_t *nhlfe;
663 struct nexthop *nexthop;
664
665 if (!lsp)
666 return NULL;
667
668 nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(zebra_nhlfe_t));
669 if (!nhlfe)
670 return NULL;
671
672 nhlfe->lsp = lsp;
673 nhlfe->type = lsp_type;
674 nhlfe->distance = lsp_distance (lsp_type);
675
676 nexthop = nexthop_new();
677 if (!nexthop)
678 {
679 XFREE (MTYPE_NHLFE, nhlfe);
680 return NULL;
681 }
682 nexthop_add_labels (nexthop, lsp_type, 1, &out_label);
683
684 nexthop->type = gtype;
685 switch (nexthop->type)
686 {
687 case NEXTHOP_TYPE_IPV4:
688 nexthop->gate.ipv4 = gate->ipv4;
689 break;
690 case NEXTHOP_TYPE_IPV6:
691 case NEXTHOP_TYPE_IPV6_IFINDEX:
692 nexthop->gate.ipv6 = gate->ipv6;
693 if (ifindex)
694 nexthop->ifindex = ifindex;
695 break;
696 default:
697 nexthop_free(nexthop);
698 XFREE (MTYPE_NHLFE, nhlfe);
699 return NULL;
700 break;
701 }
702
703 nhlfe->nexthop = nexthop;
704 if (lsp->nhlfe_list)
705 lsp->nhlfe_list->prev = nhlfe;
706 nhlfe->next = lsp->nhlfe_list;
707 lsp->nhlfe_list = nhlfe;
708
709 return nhlfe;
710 }
711
712 /*
713 * Delete NHLFE. Entry must be present on list.
714 */
715 static int
716 nhlfe_del (zebra_nhlfe_t *nhlfe)
717 {
718 zebra_lsp_t *lsp;
719
720 if (!nhlfe)
721 return -1;
722
723 lsp = nhlfe->lsp;
724 if (!lsp)
725 return -1;
726
727 /* Free nexthop. */
728 if (nhlfe->nexthop)
729 nexthop_free(nhlfe->nexthop);
730
731 /* Unlink from LSP */
732 if (nhlfe->next)
733 nhlfe->next->prev = nhlfe->prev;
734 if (nhlfe->prev)
735 nhlfe->prev->next = nhlfe->next;
736 else
737 lsp->nhlfe_list = nhlfe->next;
738
739 XFREE (MTYPE_NHLFE, nhlfe);
740
741 return 0;
742 }
743
744 static int
745 mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
746 enum lsp_types_t type)
747 {
748 zebra_nhlfe_t *nhlfe, *nhlfe_next;
749 int schedule_lsp = 0;
750 char buf[BUFSIZ];
751
752 /* Mark NHLFEs for delete or directly delete, as appropriate. */
753 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next)
754 {
755 nhlfe_next = nhlfe->next;
756
757 /* Skip non-static NHLFEs */
758 if (nhlfe->type != type)
759 continue;
760
761 if (IS_ZEBRA_DEBUG_MPLS)
762 {
763 nhlfe2str (nhlfe, buf, BUFSIZ);
764 zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
765 lsp->ile.in_label, type, buf, nhlfe->flags);
766 }
767
768 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
769 {
770 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
771 SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
772 schedule_lsp = 1;
773 }
774 else
775 {
776 nhlfe_del (nhlfe);
777 }
778 }
779
780 /* Queue LSP for processing, if needed, else delete. */
781 if (schedule_lsp)
782 {
783 if (lsp_processq_add (lsp))
784 return -1;
785 }
786 else if (!lsp->nhlfe_list &&
787 !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
788 {
789 if (IS_ZEBRA_DEBUG_MPLS)
790 zlog_debug ("Free LSP in-label %u flags 0x%x",
791 lsp->ile.in_label, lsp->flags);
792
793 lsp = hash_release(lsp_table, &lsp->ile);
794 if (lsp)
795 XFREE(MTYPE_LSP, lsp);
796 }
797
798 return 0;
799 }
800
801 /*
802 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
803 * If no other NHLFEs exist, the entry would be deleted.
804 */
805 static int
806 mpls_static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label)
807 {
808 struct hash *lsp_table;
809 zebra_ile_t tmp_ile;
810 zebra_lsp_t *lsp;
811
812 /* Lookup table. */
813 lsp_table = zvrf->lsp_table;
814 if (!lsp_table)
815 return -1;
816
817 /* If entry is not present, exit. */
818 tmp_ile.in_label = in_label;
819 lsp = hash_lookup (lsp_table, &tmp_ile);
820 if (!lsp || !lsp->nhlfe_list)
821 return 0;
822
823 return mpls_lsp_uninstall_all (lsp_table, lsp, ZEBRA_LSP_STATIC);
824 }
825
826 static json_object *
827 nhlfe_json (zebra_nhlfe_t *nhlfe)
828 {
829 char buf[BUFSIZ];
830 json_object *json_nhlfe = NULL;
831 struct nexthop *nexthop = nhlfe->nexthop;
832
833 json_nhlfe = json_object_new_object();
834 json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
835 json_object_int_add(json_nhlfe, "outLabel", nexthop->nh_label->label[0]);
836 json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
837
838 if (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED))
839 json_object_boolean_true_add(json_nhlfe, "installed");
840
841 switch (nexthop->type)
842 {
843 case NEXTHOP_TYPE_IPV4:
844 json_object_string_add(json_nhlfe, "nexthop",
845 inet_ntoa (nexthop->gate.ipv4));
846 break;
847 case NEXTHOP_TYPE_IPV6:
848 case NEXTHOP_TYPE_IPV6_IFINDEX:
849 json_object_string_add(json_nhlfe, "nexthop",
850 inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
851
852 if (nexthop->ifindex)
853 json_object_string_add(json_nhlfe, "interface", ifindex2ifname (nexthop->ifindex));
854 break;
855 default:
856 break;
857 }
858 return json_nhlfe;
859 }
860
861 /*
862 * Print the NHLFE for a LSP forwarding entry.
863 */
864 static void
865 nhlfe_print (zebra_nhlfe_t *nhlfe, struct vty *vty)
866 {
867 struct nexthop *nexthop;
868 char buf[BUFSIZ];
869
870 nexthop = nhlfe->nexthop;
871 if (!nexthop || !nexthop->nh_label) // unexpected
872 return;
873
874 vty_out(vty, " type: %s remote label: %s distance: %d%s",
875 nhlfe_type2str(nhlfe->type),
876 label2str(nexthop->nh_label->label[0], buf, BUFSIZ),
877 nhlfe->distance, VTY_NEWLINE);
878 switch (nexthop->type)
879 {
880 case NEXTHOP_TYPE_IPV4:
881 vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
882 break;
883 case NEXTHOP_TYPE_IPV6:
884 case NEXTHOP_TYPE_IPV6_IFINDEX:
885 vty_out (vty, " via %s",
886 inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
887 if (nexthop->ifindex)
888 vty_out (vty, " dev %s", ifindex2ifname (nexthop->ifindex));
889 break;
890 default:
891 break;
892 }
893 vty_out(vty, "%s", CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED) ?
894 " (installed)" : "");
895 vty_out(vty, "%s", VTY_NEWLINE);
896 }
897
898 /*
899 * Print an LSP forwarding entry.
900 */
901 static void
902 lsp_print (zebra_lsp_t *lsp, void *ctxt)
903 {
904 zebra_nhlfe_t *nhlfe;
905 struct vty *vty;
906
907 vty = (struct vty *) ctxt;
908
909 vty_out(vty, "Local label: %u%s%s",
910 lsp->ile.in_label,
911 CHECK_FLAG (lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)" : "",
912 VTY_NEWLINE);
913
914 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
915 nhlfe_print (nhlfe, vty);
916 }
917
918 /*
919 * JSON objects for an LSP forwarding entry.
920 */
921 static json_object *
922 lsp_json (zebra_lsp_t *lsp)
923 {
924 zebra_nhlfe_t *nhlfe = NULL;
925 json_object *json = json_object_new_object();
926 json_object *json_nhlfe_list = json_object_new_array();
927
928 json_object_int_add(json, "inLabel", lsp->ile.in_label);
929
930 if (CHECK_FLAG (lsp->flags, LSP_FLAG_INSTALLED))
931 json_object_boolean_true_add(json, "installed");
932
933 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
934 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
935
936 json_object_object_add(json, "nexthops", json_nhlfe_list);
937 return json;
938 }
939
940
941 /* Return a sorted linked list of the hash contents */
942 static struct list *
943 hash_get_sorted_list (struct hash *hash, void *cmp)
944 {
945 unsigned int i;
946 struct hash_backet *hb;
947 struct list *sorted_list = list_new();
948
949 sorted_list->cmp = (int (*)(void *, void *)) cmp;
950
951 for (i = 0; i < hash->size; i++)
952 for (hb = hash->index[i]; hb; hb = hb->next)
953 listnode_add_sort(sorted_list, hb->data);
954
955 return sorted_list;
956 }
957
958 /*
959 * Compare two LSPs based on their label values.
960 */
961 static int
962 lsp_cmp (zebra_lsp_t *lsp1, zebra_lsp_t *lsp2)
963 {
964 if (lsp1->ile.in_label < lsp2->ile.in_label)
965 return -1;
966
967 if (lsp1->ile.in_label > lsp2->ile.in_label)
968 return 1;
969
970 return 0;
971 }
972
973 /*
974 * Callback to allocate static LSP.
975 */
976 static void *
977 slsp_alloc (void *p)
978 {
979 const zebra_ile_t *ile = p;
980 zebra_slsp_t *slsp;
981
982 slsp = XCALLOC (MTYPE_SLSP, sizeof(zebra_slsp_t));
983 slsp->ile = *ile;
984 return ((void *)slsp);
985 }
986
987 /*
988 * Compare two static LSPs based on their label values.
989 */
990 static int
991 slsp_cmp (zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
992 {
993 if (slsp1->ile.in_label < slsp2->ile.in_label)
994 return -1;
995
996 if (slsp1->ile.in_label > slsp2->ile.in_label)
997 return 1;
998
999 return 0;
1000 }
1001
1002 /*
1003 * Check if static NHLFE matches with search info passed.
1004 */
1005 static int
1006 snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
1007 union g_addr *gate, char *ifname, ifindex_t ifindex)
1008 {
1009 int cmp = 1;
1010
1011 if (snhlfe->gtype != gtype)
1012 return 1;
1013
1014 switch (snhlfe->gtype)
1015 {
1016 case NEXTHOP_TYPE_IPV4:
1017 cmp = memcmp(&(snhlfe->gate.ipv4), &(gate->ipv4),
1018 sizeof(struct in_addr));
1019 break;
1020 case NEXTHOP_TYPE_IPV6:
1021 case NEXTHOP_TYPE_IPV6_IFINDEX:
1022 cmp = memcmp(&(snhlfe->gate.ipv6), &(gate->ipv6),
1023 sizeof(struct in6_addr));
1024 if (!cmp && snhlfe->gtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1025 cmp = !(snhlfe->ifindex == ifindex);
1026 break;
1027 default:
1028 break;
1029 }
1030
1031 return cmp;
1032 }
1033
1034 /*
1035 * Locate static NHLFE that matches with passed info.
1036 */
1037 static zebra_snhlfe_t *
1038 snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
1039 union g_addr *gate, char *ifname, ifindex_t ifindex)
1040 {
1041 zebra_snhlfe_t *snhlfe;
1042
1043 if (!slsp)
1044 return NULL;
1045
1046 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
1047 {
1048 if (!snhlfe_match (snhlfe, gtype, gate, ifname, ifindex))
1049 break;
1050 }
1051
1052 return snhlfe;
1053 }
1054
1055
1056 /*
1057 * Add static NHLFE. Base LSP config entry must have been created
1058 * and duplicate check done.
1059 */
1060 static zebra_snhlfe_t *
1061 snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
1062 union g_addr *gate, char *ifname, ifindex_t ifindex,
1063 mpls_label_t out_label)
1064 {
1065 zebra_snhlfe_t *snhlfe;
1066
1067 if (!slsp)
1068 return NULL;
1069
1070 snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t));
1071 snhlfe->slsp = slsp;
1072 snhlfe->out_label = out_label;
1073 snhlfe->gtype = gtype;
1074 switch (gtype)
1075 {
1076 case NEXTHOP_TYPE_IPV4:
1077 snhlfe->gate.ipv4 = gate->ipv4;
1078 break;
1079 case NEXTHOP_TYPE_IPV6:
1080 case NEXTHOP_TYPE_IPV6_IFINDEX:
1081 snhlfe->gate.ipv6 = gate->ipv6;
1082 if (ifindex)
1083 snhlfe->ifindex = ifindex;
1084 break;
1085 default:
1086 XFREE (MTYPE_SNHLFE, snhlfe);
1087 return NULL;
1088 }
1089
1090 if (slsp->snhlfe_list)
1091 slsp->snhlfe_list->prev = snhlfe;
1092 snhlfe->next = slsp->snhlfe_list;
1093 slsp->snhlfe_list = snhlfe;
1094
1095 return snhlfe;
1096 }
1097
1098 /*
1099 * Delete static NHLFE. Entry must be present on list.
1100 */
1101 static int
1102 snhlfe_del (zebra_snhlfe_t *snhlfe)
1103 {
1104 zebra_slsp_t *slsp;
1105
1106 if (!snhlfe)
1107 return -1;
1108
1109 slsp = snhlfe->slsp;
1110 if (!slsp)
1111 return -1;
1112
1113 if (snhlfe->next)
1114 snhlfe->next->prev = snhlfe->prev;
1115 if (snhlfe->prev)
1116 snhlfe->prev->next = snhlfe->next;
1117 else
1118 slsp->snhlfe_list = snhlfe->next;
1119
1120 snhlfe->prev = snhlfe->next = NULL;
1121 if (snhlfe->ifname)
1122 XFREE (MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
1123 XFREE (MTYPE_SNHLFE, snhlfe);
1124
1125 return 0;
1126 }
1127
1128 /*
1129 * Delete all static NHLFE entries for this LSP (in label).
1130 */
1131 static int
1132 snhlfe_del_all (zebra_slsp_t *slsp)
1133 {
1134 zebra_snhlfe_t *snhlfe, *snhlfe_next;
1135
1136 if (!slsp)
1137 return -1;
1138
1139 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next)
1140 {
1141 snhlfe_next = snhlfe->next;
1142 snhlfe_del (snhlfe);
1143 }
1144
1145 return 0;
1146 }
1147
1148 /*
1149 * Create printable string for NHLFE configuration.
1150 */
1151 static char *
1152 snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size)
1153 {
1154 buf[0] = '\0';
1155 switch (snhlfe->gtype)
1156 {
1157 case NEXTHOP_TYPE_IPV4:
1158 inet_ntop (AF_INET, &snhlfe->gate.ipv4, buf, size);
1159 break;
1160 case NEXTHOP_TYPE_IPV6:
1161 case NEXTHOP_TYPE_IPV6_IFINDEX:
1162 inet_ntop (AF_INET6, &snhlfe->gate.ipv6, buf, size);
1163 if (snhlfe->ifindex)
1164 strcat (buf, ifindex2ifname (snhlfe->ifindex));
1165 break;
1166 default:
1167 break;
1168 }
1169
1170 return buf;
1171 }
1172
1173 /*
1174 * Initialize work queue for processing changed LSPs.
1175 */
1176 static void
1177 mpls_processq_init (struct zebra_t *zebra)
1178 {
1179 zebra->lsp_process_q = work_queue_new (zebra->master, "LSP processing");
1180 if (!zebra->lsp_process_q)
1181 {
1182 zlog_err ("%s: could not initialise work queue!", __func__);
1183 return;
1184 }
1185
1186 zebra->lsp_process_q->spec.workfunc = &lsp_process;
1187 zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del;
1188 zebra->lsp_process_q->spec.errorfunc = NULL;
1189 zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete;
1190 zebra->lsp_process_q->spec.max_retries = 0;
1191 zebra->lsp_process_q->spec.hold = 10;
1192 }
1193
1194
1195
1196 /* Public functions */
1197
1198 /*
1199 * String to label conversion, labels separated by '/'.
1200 */
1201 int
1202 mpls_str2label (const char *label_str, u_int8_t *num_labels,
1203 mpls_label_t *labels)
1204 {
1205 char *endp;
1206 int i;
1207
1208 *num_labels = 0;
1209 for (i = 0; i < MPLS_MAX_LABELS; i++)
1210 {
1211 u_int32_t label;
1212
1213 label = strtoul(label_str, &endp, 0);
1214
1215 /* validity checks */
1216 if (endp == label_str)
1217 return -1;
1218
1219 if (!IS_MPLS_UNRESERVED_LABEL(label))
1220 return -1;
1221
1222 labels[i] = label;
1223 if (*endp == '\0')
1224 {
1225 *num_labels = i + 1;
1226 return 0;
1227 }
1228
1229 /* Check separator. */
1230 if (*endp != '/')
1231 return -1;
1232
1233 label_str = endp + 1;
1234 }
1235
1236 /* Too many labels. */
1237 return -1;
1238 }
1239
1240 /*
1241 * Label to string conversion, labels in string separated by '/'.
1242 */
1243 char *
1244 mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
1245 char *buf, int len)
1246 {
1247 buf[0] = '\0';
1248 if (num_labels == 1)
1249 snprintf (buf, len, "%u", labels[0]);
1250 else if (num_labels == 2)
1251 snprintf (buf, len, "%u/%u", labels[0], labels[1]);
1252 return buf;
1253 }
1254
1255 /*
1256 * Install/uninstall a FEC-To-NHLFE (FTN) binding.
1257 */
1258 int
1259 mpls_ftn_update (int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
1260 struct prefix *prefix, union g_addr *gate, u_int8_t distance,
1261 mpls_label_t out_label)
1262 {
1263 struct route_table *table;
1264 struct route_node *rn;
1265 struct rib *rib;
1266 struct nexthop *nexthop;
1267
1268 /* Lookup table. */
1269 table = zebra_vrf_table (family2afi(prefix->family), SAFI_UNICAST, zvrf->vrf_id);
1270 if (! table)
1271 return -1;
1272
1273 /* Lookup existing route */
1274 rn = route_node_get (table, prefix);
1275 RNODE_FOREACH_RIB (rn, rib)
1276 {
1277 if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
1278 continue;
1279 if (rib->distance == distance)
1280 break;
1281 }
1282
1283 if (rib == NULL)
1284 return -1;
1285
1286 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1287 switch (prefix->family)
1288 {
1289 case AF_INET:
1290 if (nexthop->type != NEXTHOP_TYPE_IPV4 &&
1291 nexthop->type != NEXTHOP_TYPE_IPV4_IFINDEX)
1292 continue;
1293 if (! IPV4_ADDR_SAME (&nexthop->gate.ipv4, &gate->ipv4))
1294 continue;
1295 goto found;
1296 break;
1297 case AF_INET6:
1298 if (nexthop->type != NEXTHOP_TYPE_IPV6 &&
1299 nexthop->type != NEXTHOP_TYPE_IPV6_IFINDEX)
1300 continue;
1301 if (! IPV6_ADDR_SAME (&nexthop->gate.ipv6, &gate->ipv6))
1302 continue;
1303 goto found;
1304 break;
1305 default:
1306 break;
1307 }
1308 /* nexthop not found */
1309 return -1;
1310
1311 found:
1312 if (add)
1313 nexthop_add_labels (nexthop, type, 1, &out_label);
1314 else
1315 nexthop_del_labels (nexthop);
1316
1317 SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
1318 SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
1319 rib_queue_add (rn);
1320
1321 return 0;
1322 }
1323
1324 /*
1325 * Install/update a NHLFE for an LSP in the forwarding table. This may be
1326 * a new LSP entry or a new NHLFE for an existing in-label or an update of
1327 * the out-label for an existing NHLFE (update case).
1328 */
1329 int
1330 mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
1331 mpls_label_t in_label, mpls_label_t out_label,
1332 enum nexthop_types_t gtype, union g_addr *gate,
1333 char *ifname, ifindex_t ifindex)
1334 {
1335 struct hash *lsp_table;
1336 zebra_ile_t tmp_ile;
1337 zebra_lsp_t *lsp;
1338 zebra_nhlfe_t *nhlfe;
1339 char buf[BUFSIZ];
1340
1341 /* Lookup table. */
1342 lsp_table = zvrf->lsp_table;
1343 if (!lsp_table)
1344 return -1;
1345
1346 /* If entry is present, exit. */
1347 tmp_ile.in_label = in_label;
1348 lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
1349 if (!lsp)
1350 return -1;
1351 nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
1352 if (nhlfe)
1353 {
1354 struct nexthop *nh = nhlfe->nexthop;
1355
1356 assert (nh);
1357 assert (nh->nh_label);
1358
1359 /* Clear deleted flag (in case it was set) */
1360 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
1361 if (nh->nh_label->label[0] == out_label)
1362 /* No change */
1363 return 0;
1364
1365 if (IS_ZEBRA_DEBUG_MPLS)
1366 {
1367 nhlfe2str (nhlfe, buf, BUFSIZ);
1368 zlog_debug ("LSP in-label %u type %d nexthop %s "
1369 "out-label changed to %u (old %u)",
1370 in_label, type, buf,
1371 out_label, nh->nh_label->label[0]);
1372 }
1373
1374 /* Update out label, trigger processing. */
1375 nh->nh_label->label[0] = out_label;
1376 }
1377 else
1378 {
1379 /* Add LSP entry to this nexthop */
1380 nhlfe = nhlfe_add (lsp, type, gtype, gate,
1381 ifname, ifindex, out_label);
1382 if (!nhlfe)
1383 return -1;
1384
1385 if (IS_ZEBRA_DEBUG_MPLS)
1386 {
1387 nhlfe2str (nhlfe, buf, BUFSIZ);
1388 zlog_debug ("Add LSP in-label %u type %d nexthop %s "
1389 "out-label %u", in_label, type, buf, out_label);
1390 }
1391
1392 lsp->addr_family = NHLFE_FAMILY (nhlfe);
1393 }
1394
1395 /* Mark NHLFE, queue LSP for processing. */
1396 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1397 if (lsp_processq_add (lsp))
1398 return -1;
1399
1400 return 0;
1401 }
1402
1403 /*
1404 * Uninstall a particular NHLFE in the forwarding table. If this is
1405 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
1406 */
1407 int
1408 mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
1409 mpls_label_t in_label, enum nexthop_types_t gtype,
1410 union g_addr *gate, char *ifname, ifindex_t ifindex)
1411 {
1412 struct hash *lsp_table;
1413 zebra_ile_t tmp_ile;
1414 zebra_lsp_t *lsp;
1415 zebra_nhlfe_t *nhlfe;
1416 char buf[BUFSIZ];
1417
1418 /* Lookup table. */
1419 lsp_table = zvrf->lsp_table;
1420 if (!lsp_table)
1421 return -1;
1422
1423 /* If entry is not present, exit. */
1424 tmp_ile.in_label = in_label;
1425 lsp = hash_lookup (lsp_table, &tmp_ile);
1426 if (!lsp)
1427 return 0;
1428 nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
1429 if (!nhlfe)
1430 return 0;
1431
1432 if (IS_ZEBRA_DEBUG_MPLS)
1433 {
1434 nhlfe2str (nhlfe, buf, BUFSIZ);
1435 zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
1436 in_label, type, buf, nhlfe->flags);
1437 }
1438
1439 /* Mark NHLFE for delete or directly delete, as appropriate. */
1440 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
1441 {
1442 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
1443 SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
1444 if (lsp_processq_add (lsp))
1445 return -1;
1446 }
1447 else
1448 {
1449 nhlfe_del (nhlfe);
1450
1451 /* Free LSP entry if no other NHLFEs and not scheduled. */
1452 if (!lsp->nhlfe_list &&
1453 !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
1454 {
1455 if (IS_ZEBRA_DEBUG_MPLS)
1456 zlog_debug ("Free LSP in-label %u flags 0x%x",
1457 lsp->ile.in_label, lsp->flags);
1458
1459 lsp = hash_release(lsp_table, &lsp->ile);
1460 if (lsp)
1461 XFREE(MTYPE_LSP, lsp);
1462 }
1463 }
1464 return 0;
1465 }
1466
1467 /*
1468 * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
1469 * If no other NHLFEs exist, the entry would be deleted.
1470 */
1471 void
1472 mpls_ldp_lsp_uninstall_all (struct hash_backet *backet, void *ctxt)
1473 {
1474 zebra_lsp_t *lsp;
1475 struct hash *lsp_table;
1476
1477 lsp = (zebra_lsp_t *) backet->data;
1478 if (!lsp || !lsp->nhlfe_list)
1479 return;
1480
1481 lsp_table = ctxt;
1482 if (!lsp_table)
1483 return;
1484
1485 mpls_lsp_uninstall_all (lsp_table, lsp, ZEBRA_LSP_LDP);
1486 }
1487
1488 /*
1489 * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
1490 */
1491 void
1492 mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
1493 {
1494 struct route_table *table;
1495 struct route_node *rn;
1496 struct rib *rib;
1497 struct nexthop *nexthop;
1498 int update;
1499
1500 /* Process routes of interested address-families. */
1501 table = zebra_vrf_table (afi, SAFI_UNICAST, zvrf->vrf_id);
1502 if (!table)
1503 return;
1504
1505 for (rn = route_top (table); rn; rn = route_next (rn))
1506 {
1507 update = 0;
1508 RNODE_FOREACH_RIB (rn, rib)
1509 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1510 if (nexthop->nh_label_type == ZEBRA_LSP_LDP)
1511 {
1512 nexthop_del_labels (nexthop);
1513 SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
1514 SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
1515 update = 1;
1516 }
1517
1518 if (update)
1519 rib_queue_add (rn);
1520 }
1521 }
1522
1523 /*
1524 * Check that the label values used in LSP creation are consistent. The
1525 * main criteria is that if there is ECMP, the label operation must still
1526 * be consistent - i.e., all paths either do a swap or do PHP. This is due
1527 * to current HW restrictions.
1528 */
1529 int
1530 zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
1531 mpls_label_t out_label, enum nexthop_types_t gtype,
1532 union g_addr *gate, char *ifname, ifindex_t ifindex)
1533 {
1534 struct hash *slsp_table;
1535 zebra_ile_t tmp_ile;
1536 zebra_slsp_t *slsp;
1537 zebra_snhlfe_t *snhlfe;
1538
1539 /* Lookup table. */
1540 slsp_table = zvrf->slsp_table;
1541 if (!slsp_table)
1542 return 0;
1543
1544 /* If entry is not present, exit. */
1545 tmp_ile.in_label = in_label;
1546 slsp = hash_lookup (slsp_table, &tmp_ile);
1547 if (!slsp)
1548 return 1;
1549
1550 snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
1551 if (snhlfe)
1552 {
1553 if (snhlfe->out_label == out_label)
1554 return 1;
1555
1556 /* If not only NHLFE, cannot allow label change. */
1557 if (snhlfe != slsp->snhlfe_list ||
1558 snhlfe->next)
1559 return 0;
1560 }
1561 else
1562 {
1563 /* If other NHLFEs exist, label operation must match. */
1564 if (slsp->snhlfe_list)
1565 {
1566 int cur_op, new_op;
1567
1568 cur_op = (slsp->snhlfe_list->out_label == MPLS_IMP_NULL_LABEL);
1569 new_op = (out_label == MPLS_IMP_NULL_LABEL);
1570 if (cur_op != new_op)
1571 return 0;
1572 }
1573 }
1574
1575 /* Label values are good. */
1576 return 1;
1577 }
1578
1579
1580 /*
1581 * Add static LSP entry. This may be the first entry for this incoming label
1582 * or an additional nexthop; an existing entry may also have outgoing label
1583 * changed.
1584 * Note: The label operation (swap or PHP) is common for the LSP entry (all
1585 * NHLFEs).
1586 */
1587 int
1588 zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
1589 mpls_label_t out_label, enum nexthop_types_t gtype,
1590 union g_addr *gate, char *ifname, ifindex_t ifindex)
1591 {
1592 struct hash *slsp_table;
1593 zebra_ile_t tmp_ile;
1594 zebra_slsp_t *slsp;
1595 zebra_snhlfe_t *snhlfe;
1596 char buf[BUFSIZ];
1597
1598 /* Lookup table. */
1599 slsp_table = zvrf->slsp_table;
1600 if (!slsp_table)
1601 return -1;
1602
1603 /* If entry is present, exit. */
1604 tmp_ile.in_label = in_label;
1605 slsp = hash_get (slsp_table, &tmp_ile, slsp_alloc);
1606 if (!slsp)
1607 return -1;
1608 snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
1609 if (snhlfe)
1610 {
1611 if (snhlfe->out_label == out_label)
1612 /* No change */
1613 return 0;
1614
1615 if (IS_ZEBRA_DEBUG_MPLS)
1616 {
1617 snhlfe2str (snhlfe, buf, BUFSIZ);
1618 zlog_debug ("Upd static LSP in-label %u nexthop %s "
1619 "out-label %u (old %u)",
1620 in_label, buf, out_label, snhlfe->out_label);
1621 }
1622 snhlfe->out_label = out_label;
1623 }
1624 else
1625 {
1626 /* Add static LSP entry to this nexthop */
1627 snhlfe = snhlfe_add (slsp, gtype, gate, ifname, ifindex, out_label);
1628 if (!snhlfe)
1629 return -1;
1630
1631 if (IS_ZEBRA_DEBUG_MPLS)
1632 {
1633 snhlfe2str (snhlfe, buf, BUFSIZ);
1634 zlog_debug ("Add static LSP in-label %u nexthop %s out-label %u",
1635 in_label, buf, out_label);
1636 }
1637 }
1638
1639 /* (Re)Install LSP in the main table. */
1640 if (mpls_lsp_install (zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
1641 gate, ifname, ifindex))
1642 return -1;
1643
1644 return 0;
1645 }
1646
1647 /*
1648 * Delete static LSP entry. This may be the delete of one particular
1649 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
1650 * all NHLFEs).
1651 * NOTE: Delete of the only NHLFE will also end up deleting the entire
1652 * LSP configuration.
1653 */
1654 int
1655 zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
1656 enum nexthop_types_t gtype, union g_addr *gate,
1657 char *ifname, ifindex_t ifindex)
1658 {
1659 struct hash *slsp_table;
1660 zebra_ile_t tmp_ile;
1661 zebra_slsp_t *slsp;
1662 zebra_snhlfe_t *snhlfe;
1663
1664 /* Lookup table. */
1665 slsp_table = zvrf->slsp_table;
1666 if (!slsp_table)
1667 return -1;
1668
1669 /* If entry is not present, exit. */
1670 tmp_ile.in_label = in_label;
1671 slsp = hash_lookup (slsp_table, &tmp_ile);
1672 if (!slsp)
1673 return 0;
1674
1675 /* Is it delete of entire LSP or a specific NHLFE? */
1676 if (gtype == NEXTHOP_TYPE_BLACKHOLE)
1677 {
1678 if (IS_ZEBRA_DEBUG_MPLS)
1679 zlog_debug ("Del static LSP in-label %u", in_label);
1680
1681 /* Uninstall entire LSP from the main table. */
1682 mpls_static_lsp_uninstall_all (zvrf, in_label);
1683
1684 /* Delete all static NHLFEs */
1685 snhlfe_del_all (slsp);
1686 }
1687 else
1688 {
1689 /* Find specific NHLFE, exit if not found. */
1690 snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
1691 if (!snhlfe)
1692 return 0;
1693
1694 if (IS_ZEBRA_DEBUG_MPLS)
1695 {
1696 char buf[BUFSIZ];
1697 snhlfe2str (snhlfe, buf, BUFSIZ);
1698 zlog_debug ("Del static LSP in-label %u nexthop %s",
1699 in_label, buf);
1700 }
1701
1702 /* Uninstall LSP from the main table. */
1703 mpls_lsp_uninstall (zvrf, ZEBRA_LSP_STATIC, in_label, gtype, gate,
1704 ifname, ifindex);
1705
1706 /* Delete static LSP NHLFE */
1707 snhlfe_del (snhlfe);
1708 }
1709
1710 /* Remove entire static LSP entry if no NHLFE - valid in either case above. */
1711 if (!slsp->snhlfe_list)
1712 {
1713 slsp = hash_release(slsp_table, &tmp_ile);
1714 if (slsp)
1715 XFREE(MTYPE_SLSP, slsp);
1716 }
1717
1718 return 0;
1719 }
1720
1721 /*
1722 * Schedule all MPLS label forwarding entries for processing.
1723 * Called upon changes that may affect one or more of them such as
1724 * interface or nexthop state changes.
1725 */
1726 void
1727 zebra_mpls_lsp_schedule (struct zebra_vrf *zvrf)
1728 {
1729 if (!zvrf)
1730 return;
1731 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
1732 }
1733
1734 /*
1735 * Display MPLS label forwarding table for a specific LSP
1736 * (VTY command handler).
1737 */
1738 void
1739 zebra_mpls_print_lsp (struct vty *vty, struct zebra_vrf *zvrf, mpls_label_t label,
1740 u_char use_json)
1741 {
1742 struct hash *lsp_table;
1743 zebra_lsp_t *lsp;
1744 zebra_ile_t tmp_ile;
1745 json_object *json = NULL;
1746
1747 /* Lookup table. */
1748 lsp_table = zvrf->lsp_table;
1749 if (!lsp_table)
1750 return;
1751
1752 /* If entry is not present, exit. */
1753 tmp_ile.in_label = label;
1754 lsp = hash_lookup (lsp_table, &tmp_ile);
1755 if (!lsp)
1756 return;
1757
1758 if (use_json)
1759 {
1760 json = lsp_json(lsp);
1761 vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE);
1762 json_object_free(json);
1763 }
1764 else
1765 lsp_print (lsp, (void *)vty);
1766 }
1767
1768 /*
1769 * Display MPLS label forwarding table (VTY command handler).
1770 */
1771 void
1772 zebra_mpls_print_lsp_table (struct vty *vty, struct zebra_vrf *zvrf,
1773 u_char use_json)
1774 {
1775 char buf[BUFSIZ];
1776 json_object *json = NULL;
1777 zebra_lsp_t *lsp = NULL;
1778 zebra_nhlfe_t *nhlfe = NULL;
1779 struct nexthop *nexthop = NULL;
1780 struct listnode *node = NULL;
1781 struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
1782
1783 if (use_json)
1784 {
1785 json = json_object_new_object();
1786
1787 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
1788 json_object_object_add(json, label2str(lsp->ile.in_label, buf, BUFSIZ),
1789 lsp_json(lsp));
1790
1791 vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE);
1792 json_object_free(json);
1793 }
1794 else
1795 {
1796 vty_out (vty, " Inbound Outbound%s", VTY_NEWLINE);
1797 vty_out (vty, " Label Type Nexthop Label%s", VTY_NEWLINE);
1798 vty_out (vty, "-------- ------- --------------- --------%s", VTY_NEWLINE);
1799
1800 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
1801 {
1802 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1803 {
1804 vty_out (vty, "%8d %7s ", lsp->ile.in_label, nhlfe_type2str(nhlfe->type));
1805 nexthop = nhlfe->nexthop;
1806
1807 switch (nexthop->type)
1808 {
1809 case NEXTHOP_TYPE_IPV4:
1810 vty_out (vty, "%15s", inet_ntoa (nexthop->gate.ipv4));
1811 break;
1812 case NEXTHOP_TYPE_IPV6:
1813 case NEXTHOP_TYPE_IPV6_IFINDEX:
1814 vty_out (vty, "%15s", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1815 break;
1816 default:
1817 break;
1818 }
1819
1820 vty_out (vty, " %8d%s", nexthop->nh_label->label[0], VTY_NEWLINE);
1821 }
1822 }
1823
1824 vty_out (vty, "%s", VTY_NEWLINE);
1825 }
1826
1827 list_delete_all_node(lsp_list);
1828 }
1829
1830 /*
1831 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
1832 */
1833 int
1834 zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
1835 {
1836 zebra_slsp_t *slsp;
1837 zebra_snhlfe_t *snhlfe;
1838 struct listnode *node;
1839 char buf[INET6_ADDRSTRLEN];
1840 struct list *slsp_list = hash_get_sorted_list(zvrf->slsp_table, slsp_cmp);
1841
1842 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp))
1843 {
1844 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
1845 {
1846 char lstr[30];
1847 snhlfe2str (snhlfe, buf, BUFSIZ);
1848 vty_out (vty, "mpls lsp %u %s %s%s",
1849 slsp->ile.in_label, buf,
1850 label2str(snhlfe->out_label, lstr, 30), VTY_NEWLINE);
1851 }
1852 }
1853
1854 list_delete_all_node(slsp_list);
1855 return (zvrf->slsp_table->count ? 1 : 0);
1856 }
1857
1858 /*
1859 * Called upon process exiting, need to delete LSP forwarding
1860 * entries from the kernel.
1861 * NOTE: Currently supported only for default VRF.
1862 */
1863 void
1864 zebra_mpls_close_tables (struct zebra_vrf *zvrf)
1865 {
1866 if (!zvrf)
1867 return;
1868 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
1869 }
1870
1871 /*
1872 * Allocate MPLS tables for this VRF and do other initialization.
1873 * NOTE: Currently supported only for default VRF.
1874 */
1875 void
1876 zebra_mpls_init_tables (struct zebra_vrf *zvrf)
1877 {
1878 if (!zvrf)
1879 return;
1880 zvrf->slsp_table = hash_create(label_hash, label_cmp);
1881 zvrf->lsp_table = hash_create(label_hash, label_cmp);
1882 zvrf->mpls_flags = 0;
1883 }
1884
1885 /*
1886 * Global MPLS initialization.
1887 */
1888 void
1889 zebra_mpls_init (void)
1890 {
1891 mpls_kernel_init ();
1892 mpls_processq_init (&zebrad);
1893 }