]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_mpls.c
Quagga: Install label forwarding entries for statically configured LSPs
[mirror_frr.git] / zebra / zebra_mpls.c
CommitLineData
7758e3f3 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
40#include "zebra/rib.h"
41#include "zebra/rt.h"
42#include "zebra/zserv.h"
43#include "zebra/redistribute.h"
44#include "zebra/debug.h"
45#include "zebra/zebra_memory.h"
46#include "zebra/zebra_vrf.h"
47#include "zebra/zebra_mpls.h"
48
49DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object")
50DEFINE_MTYPE_STATIC(ZEBRA, SLSP, "MPLS static LSP config")
40c7bdb0 51DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object")
7758e3f3 52DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE, "MPLS static nexthop object")
53DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE_IFNAME, "MPLS static nexthop ifname")
54
55/* Default rtm_table for all clients */
56extern struct zebra_t zebrad;
57
58/* static function declarations */
59static unsigned int
60label_hash (void *p);
61static int
62label_cmp (const void *p1, const void *p2);
40c7bdb0 63static int
64nhlfe_nexthop_active_ipv4 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop);
65static int
66nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop);
67static int
68nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe);
69static void
70lsp_select_best_nhlfe (zebra_lsp_t *lsp);
71static void
72lsp_uninstall_from_kernel (struct hash_backet *backet, void *ctxt);
73static void
74lsp_schedule (struct hash_backet *backet, void *ctxt);
75static wq_item_status
76lsp_process (struct work_queue *wq, void *data);
77static void
78lsp_processq_del (struct work_queue *wq, void *data);
79static void
80lsp_processq_complete (struct work_queue *wq);
81static int
82lsp_processq_add (zebra_lsp_t *lsp);
83static void *
84lsp_alloc (void *p);
85static char *
86nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size);
87static int
88nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
89 union g_addr *gate, char *ifname, ifindex_t ifindex);
90static zebra_nhlfe_t *
91nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
92 enum nexthop_types_t gtype, union g_addr *gate,
93 char *ifname, ifindex_t ifindex);
94static zebra_nhlfe_t *
95nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
96 enum nexthop_types_t gtype, union g_addr *gate,
97 char *ifname, ifindex_t ifindex, mpls_label_t out_label);
98static int
99nhlfe_del (zebra_nhlfe_t *snhlfe);
100static int
101static_lsp_install (struct zebra_vrf *zvrf, mpls_label_t in_label,
102 mpls_label_t out_label, enum nexthop_types_t gtype,
103 union g_addr *gate, char *ifname, ifindex_t ifindex);
104static int
105static_lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t in_label,
106 enum nexthop_types_t gtype, union g_addr *gate,
107 char *ifname, ifindex_t ifindex);
108static int
109static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label);
7758e3f3 110static void
111lsp_config_write (struct hash_backet *backet, void *ctxt);
112static void *
113slsp_alloc (void *p);
114static int
115snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
116 union g_addr *gate, char *ifname, ifindex_t ifindex);
117static zebra_snhlfe_t *
118snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
119 union g_addr *gate, char *ifname, ifindex_t ifindex);
120static zebra_snhlfe_t *
121snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
122 union g_addr *gate, char *ifname, ifindex_t ifindex,
123 mpls_label_t out_label);
124static int
125snhlfe_del (zebra_snhlfe_t *snhlfe);
126static int
127snhlfe_del_all (zebra_slsp_t *slsp);
128static char *
129snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size);
40c7bdb0 130static void
131mpls_processq_init (struct zebra_t *zebra);
7758e3f3 132
133
134
135
136/* Static functions */
137
138/*
139 * Hash function for label.
140 */
141static unsigned int
142label_hash (void *p)
143{
144 const zebra_ile_t *ile = p;
145
146 return (jhash_1word(ile->in_label, 0));
147}
148
149/*
150 * Compare 2 LSP hash entries based on in-label.
151 */
152static int
153label_cmp (const void *p1, const void *p2)
154{
155 const zebra_ile_t *ile1 = p1;
156 const zebra_ile_t *ile2 = p2;
157
158 return (ile1->in_label == ile2->in_label);
159}
160
40c7bdb0 161/*
162 * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
163 * the passed flag.
164 * NOTE: Looking only for connected routes right now.
165 */
166static int
167nhlfe_nexthop_active_ipv4 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop)
168{
169 struct route_table *table;
170 struct prefix_ipv4 p;
171 struct route_node *rn;
172 struct rib *match;
173
174 table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
175 if (!table)
176 return 0;
177
178 /* Lookup nexthop in IPv4 routing table. */
179 memset (&p, 0, sizeof (struct prefix_ipv4));
180 p.family = AF_INET;
181 p.prefixlen = IPV4_MAX_PREFIXLEN;
182 p.prefix = nexthop->gate.ipv4;
183
184 rn = route_node_match (table, (struct prefix *) &p);
185 if (!rn)
186 return 0;
187
188 route_unlock_node (rn);
189
190 /* Locate a valid connected route. */
191 RNODE_FOREACH_RIB (rn, match)
192 {
193 if ((match->type == ZEBRA_ROUTE_CONNECT) &&
194 !CHECK_FLAG (match->status, RIB_ENTRY_REMOVED) &&
195 CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
196 break;
197 }
198
199 if (!match || !match->nexthop)
200 return 0;
201
202 nexthop->ifindex = match->nexthop->ifindex;
203 return 1;
204}
205
206
207/*
208 * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
209 * the passed flag.
210 * NOTE: Looking only for connected routes right now.
211 */
212static int
213nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop)
214{
215 struct route_table *table;
216 struct prefix_ipv6 p;
217 struct route_node *rn;
218 struct rib *match;
219
220 table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT);
221 if (!table)
222 return 0;
223
224 /* Lookup nexthop in IPv6 routing table. */
225 memset (&p, 0, sizeof (struct prefix_ipv6));
226 p.family = AF_INET6;
227 p.prefixlen = IPV6_MAX_PREFIXLEN;
228 p.prefix = nexthop->gate.ipv6;
229
230 rn = route_node_match (table, (struct prefix *) &p);
231 if (!rn)
232 return 0;
233
234 route_unlock_node (rn);
235
236 /* Locate a valid connected route. */
237 RNODE_FOREACH_RIB (rn, match)
238 {
239 if ((match->type == ZEBRA_ROUTE_CONNECT) &&
240 !CHECK_FLAG (match->status, RIB_ENTRY_REMOVED) &&
241 CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
242 break;
243 }
244
245 if (!match || !match->nexthop)
246 return 0;
247
248 nexthop->ifindex = match->nexthop->ifindex;
249 return 1;
250}
251
252
253/*
254 * Check the nexthop reachability for a NHLFE and return if valid (reachable)
255 * or not.
256 * NOTE: Each NHLFE points to only 1 nexthop.
257 */
258static int
259nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe)
260{
261 struct nexthop *nexthop;
262 struct interface *ifp;
263
264 nexthop = nhlfe->nexthop;
265 if (!nexthop) // unexpected
266 return 0;
267
268 /* Check on nexthop based on type. */
269 switch (nexthop->type)
270 {
271 case NEXTHOP_TYPE_IPV4:
272 if (nhlfe_nexthop_active_ipv4 (nhlfe, nexthop))
273 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
274 else
275 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
276 break;
277
278 case NEXTHOP_TYPE_IPV6:
279 if (nhlfe_nexthop_active_ipv6 (nhlfe, nexthop))
280 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
281 else
282 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
283 break;
284
285 case NEXTHOP_TYPE_IPV6_IFINDEX:
286 if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
287 {
288 ifp = if_lookup_by_index (nexthop->ifindex);
289 if (ifp && if_is_operative(ifp))
290 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
291 else
292 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
293 }
294 else
295 {
296 if (nhlfe_nexthop_active_ipv6 (nhlfe, nexthop))
297 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
298 else
299 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
300 }
301 break;
302
303 default:
304 break;
305 }
306
307 return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
308}
309
310/*
311 * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
312 * reachability and select the best. Multipath entries are also
313 * marked. This is invoked when an LSP scheduled for processing (due
314 * to some change) is examined.
315 */
316static void
317lsp_select_best_nhlfe (zebra_lsp_t *lsp)
318{
319 zebra_nhlfe_t *nhlfe;
320 zebra_nhlfe_t *best;
321 struct nexthop *nexthop;
322 int changed = 0;
323
324 if (!lsp)
325 return;
326
327 best = NULL;
328 lsp->num_ecmp = 0;
329 UNSET_FLAG (lsp->flags, LSP_FLAG_CHANGED);
330
331 /*
332 * First compute the best path, after checking nexthop status. We are only
333 * concerned with non-deleted NHLFEs.
334 */
335 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
336 {
337 /* Clear selection flags. */
338 UNSET_FLAG (nhlfe->flags,
339 (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
340
341 if (!CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED) &&
342 nhlfe_nexthop_active (nhlfe))
343 {
344 if (!best || (nhlfe->distance < best->distance))
345 best = nhlfe;
346 }
347 }
348
349 lsp->best_nhlfe = best;
350 if (!lsp->best_nhlfe)
351 return;
352
353 /* Mark best NHLFE as selected. */
354 SET_FLAG (lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
355
356 /*
357 * If best path exists, see if there is ECMP. While doing this, note if a
358 * new (uninstalled) NHLFE has been selected, an installed entry that is
359 * still selected has a change or an installed entry is to be removed.
360 */
361 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
362 {
363 int nh_chg, nh_sel, nh_inst;
364
365 nexthop = nhlfe->nexthop;
366 if (!nexthop) // unexpected
367 continue;
368
369 if (!CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED) &&
370 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
371 (nhlfe->distance == lsp->best_nhlfe->distance))
372 {
373 SET_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED);
374 SET_FLAG (nhlfe->flags, NHLFE_FLAG_MULTIPATH);
375 lsp->num_ecmp++;
376 }
377
378 if (CHECK_FLAG (lsp->flags, LSP_FLAG_INSTALLED) &&
379 !changed)
380 {
381 nh_chg = CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
382 nh_sel = CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED);
383 nh_inst = CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
384
385 if ((nh_sel && !nh_inst) ||
386 (nh_sel && nh_inst && nh_chg) ||
387 (nh_inst && !nh_sel))
388 changed = 1;
389 }
390
391 /* We have finished examining, clear changed flag. */
392 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
393 }
394
395 if (changed)
396 SET_FLAG (lsp->flags, LSP_FLAG_CHANGED);
397}
398
399/*
400 * Delete LSP forwarding entry from kernel, if installed. Called upon
401 * process exit.
402 */
403static void
404lsp_uninstall_from_kernel (struct hash_backet *backet, void *ctxt)
405{
406 zebra_lsp_t *lsp;
407
408 lsp = (zebra_lsp_t *) backet->data;
409 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
410 kernel_del_lsp (lsp);
411}
412
413/*
414 * Schedule LSP forwarding entry for processing. Called upon changes
415 * that may impact LSPs such as nexthop / connected route changes.
416 */
417static void
418lsp_schedule (struct hash_backet *backet, void *ctxt)
419{
420 zebra_lsp_t *lsp;
421
422 lsp = (zebra_lsp_t *) backet->data;
423 lsp_processq_add (lsp);
424}
425
426/*
427 * Process a LSP entry that is in the queue. Recalculate best NHLFE and
428 * any multipaths and update or delete from the kernel, as needed.
429 */
430static wq_item_status
431lsp_process (struct work_queue *wq, void *data)
432{
433 zebra_lsp_t *lsp;
434 zebra_nhlfe_t *oldbest, *newbest;
435 char buf[BUFSIZ], buf2[BUFSIZ];
436
437 lsp = (zebra_lsp_t *)data;
438 if (!lsp) // unexpected
439 return WQ_SUCCESS;
440
441 oldbest = lsp->best_nhlfe;
442
443 /* Select best NHLFE(s) */
444 lsp_select_best_nhlfe (lsp);
445
446 newbest = lsp->best_nhlfe;
447
448 if (IS_ZEBRA_DEBUG_MPLS)
449 {
450 if (oldbest)
451 nhlfe2str (oldbest, buf, BUFSIZ);
452 if (newbest)
453 nhlfe2str (newbest, buf2, BUFSIZ);
454 zlog_debug ("Process LSP in-label %u oldbest %s newbest %s "
455 "flags 0x%x ecmp# %d",
456 lsp->ile.in_label, oldbest ? buf : "NULL",
457 newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
458 }
459
460 if (!CHECK_FLAG (lsp->flags, LSP_FLAG_INSTALLED))
461 {
462 /* Not already installed */
463 if (newbest)
464 kernel_add_lsp (lsp);
465 }
466 else
467 {
468 /* Installed, may need an update and/or delete. */
469 if (!newbest)
470 kernel_del_lsp (lsp);
471 else if (CHECK_FLAG (lsp->flags, LSP_FLAG_CHANGED))
472 kernel_upd_lsp (lsp);
473 }
474
475 return WQ_SUCCESS;
476}
477
478
479/*
480 * Callback upon processing completion of a LSP forwarding entry.
481 */
482static void
483lsp_processq_del (struct work_queue *wq, void *data)
484{
485 struct zebra_vrf *zvrf;
486 zebra_lsp_t *lsp;
487 struct hash *lsp_table;
488 zebra_nhlfe_t *nhlfe, *nhlfe_next;
489
490 zvrf = vrf_info_lookup(VRF_DEFAULT);
491 assert (zvrf);
492
493 lsp_table = zvrf->lsp_table;
494 if (!lsp_table) // unexpected
495 return;
496
497 lsp = (zebra_lsp_t *)data;
498 if (!lsp) // unexpected
499 return;
500
501 /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs exist,
502 * delete LSP entry also.
503 */
504 UNSET_FLAG (lsp->flags, LSP_FLAG_SCHEDULED);
505
506 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next)
507 {
508 nhlfe_next = nhlfe->next;
509 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
510 nhlfe_del (nhlfe);
511 }
512
513 if (!lsp->nhlfe_list)
514 {
515 if (IS_ZEBRA_DEBUG_MPLS)
516 zlog_debug ("Free LSP in-label %u flags 0x%x",
517 lsp->ile.in_label, lsp->flags);
518
519 lsp = hash_release(lsp_table, &lsp->ile);
520 if (lsp)
521 XFREE(MTYPE_LSP, lsp);
522 }
523}
524
525/*
526 * Callback upon finishing the processing of all scheduled
527 * LSP forwarding entries.
528 */
529static void
530lsp_processq_complete (struct work_queue *wq)
531{
532 /* Nothing to do for now. */
533}
534
535/*
536 * Add LSP forwarding entry to queue for subsequent processing.
537 */
538static int
539lsp_processq_add (zebra_lsp_t *lsp)
540{
541 /* If already scheduled, exit. */
542 if (CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
543 return 0;
544
545 work_queue_add (zebrad.lsp_process_q, lsp);
546 SET_FLAG (lsp->flags, LSP_FLAG_SCHEDULED);
547 return 0;
548}
549
550/*
551 * Callback to allocate LSP forwarding table entry.
552 */
553static void *
554lsp_alloc (void *p)
555{
556 const zebra_ile_t *ile = p;
557 zebra_lsp_t *lsp;
558
559 lsp = XCALLOC (MTYPE_LSP, sizeof(zebra_lsp_t));
560 lsp->ile = *ile;
561
562 if (IS_ZEBRA_DEBUG_MPLS)
563 zlog_debug ("Alloc LSP in-label %u", lsp->ile.in_label);
564
565 return ((void *)lsp);
566}
567
568/*
569 * Create printable string for NHLFE entry.
570 */
571static char *
572nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size)
573{
574 struct nexthop *nexthop;
575
576 buf[0] = '\0';
577 nexthop = nhlfe->nexthop;
578 switch (nexthop->type)
579 {
580 case NEXTHOP_TYPE_IPV4:
581 inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, size);
582 break;
583 case NEXTHOP_TYPE_IPV6:
584 inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, size);
585 break;
586 default:
587 break;
588 }
589
590 return buf;
591}
592
593/*
594 * Check if NHLFE matches with search info passed.
595 */
596static int
597nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
598 union g_addr *gate, char *ifname, ifindex_t ifindex)
599{
600 struct nexthop *nhop;
601 u_char cmp = -1;
602
603 nhop = nhlfe->nexthop;
604 if (!nhop)
605 return -1;
606
607 if (nhop->type != gtype)
608 return -1;
609
610 switch (nhop->type)
611 {
612 case NEXTHOP_TYPE_IPV4:
613 cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
614 sizeof(struct in_addr));
615 break;
616 case NEXTHOP_TYPE_IPV6:
617 case NEXTHOP_TYPE_IPV6_IFINDEX:
618 cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
619 sizeof(struct in6_addr));
620 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
621 cmp = !(nhop->ifindex == ifindex);
622 break;
623 default:
624 break;
625 }
626
627 return cmp;
628}
629
630
631/*
632 * Locate NHLFE that matches with passed info.
633 */
634static zebra_nhlfe_t *
635nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
636 enum nexthop_types_t gtype, union g_addr *gate,
637 char *ifname, ifindex_t ifindex)
638{
639 zebra_nhlfe_t *nhlfe;
640
641 if (!lsp)
642 return NULL;
643
644 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
645 {
646 if (nhlfe->type != lsp_type)
647 continue;
648 if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifname, ifindex))
649 break;
650 }
651
652 return nhlfe;
653}
654
655/*
656 * Add NHLFE. Base entry must have been created and duplicate
657 * check done.
658 */
659static zebra_nhlfe_t *
660nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
661 enum nexthop_types_t gtype, union g_addr *gate,
662 char *ifname, ifindex_t ifindex, mpls_label_t out_label)
663{
664 zebra_nhlfe_t *nhlfe;
665 struct nexthop *nexthop;
666
667 if (!lsp)
668 return NULL;
669
670 nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(zebra_nhlfe_t));
671 if (!nhlfe)
672 return NULL;
673
674 nhlfe->lsp = lsp;
675 nhlfe->type = lsp_type;
676 nhlfe->distance = lsp_distance (lsp_type);
677
678 nexthop = nexthop_new();
679 if (!nexthop)
680 {
681 XFREE (MTYPE_NHLFE, nhlfe);
682 return NULL;
683 }
684 nexthop_add_labels (nexthop, 1, &out_label);
685
686 nexthop->type = gtype;
687 switch (nexthop->type)
688 {
689 case NEXTHOP_TYPE_IPV4:
690 nexthop->gate.ipv4 = gate->ipv4;
691 break;
692 case NEXTHOP_TYPE_IPV6:
693 case NEXTHOP_TYPE_IPV6_IFINDEX:
694 nexthop->gate.ipv6 = gate->ipv6;
695 if (ifindex)
696 nexthop->ifindex = ifindex;
697 break;
698 default:
699 nexthop_free(nexthop);
700 XFREE (MTYPE_NHLFE, nhlfe);
701 return NULL;
702 break;
703 }
704
705 nhlfe->nexthop = nexthop;
706 if (lsp->nhlfe_list)
707 lsp->nhlfe_list->prev = nhlfe;
708 nhlfe->next = lsp->nhlfe_list;
709 lsp->nhlfe_list = nhlfe;
710
711 return nhlfe;
712}
713
714/*
715 * Delete NHLFE. Entry must be present on list.
716 */
717static int
718nhlfe_del (zebra_nhlfe_t *nhlfe)
719{
720 zebra_lsp_t *lsp;
721
722 if (!nhlfe)
723 return -1;
724
725 lsp = nhlfe->lsp;
726 if (!lsp)
727 return -1;
728
729 /* Free nexthop. */
730 if (nhlfe->nexthop)
731 nexthop_free(nhlfe->nexthop);
732
733 /* Unlink from LSP */
734 if (nhlfe->next)
735 nhlfe->next->prev = nhlfe->prev;
736 if (nhlfe->prev)
737 nhlfe->prev->next = nhlfe->next;
738 else
739 lsp->nhlfe_list = nhlfe->next;
740
741 XFREE (MTYPE_NHLFE, nhlfe);
742
743 return 0;
744}
745
746
747/*
748 * Install/update a static NHLFE for an LSP in the forwarding table. This may
749 * be a new LSP entry or a new NHLFE for an existing in-label or an update of
750 * the out-label for an existing NHLFE (update case).
751 */
752static int
753static_lsp_install (struct zebra_vrf *zvrf, mpls_label_t in_label,
754 mpls_label_t out_label, enum nexthop_types_t gtype,
755 union g_addr *gate, char *ifname, ifindex_t ifindex)
756{
757 struct hash *lsp_table;
758 zebra_ile_t tmp_ile;
759 zebra_lsp_t *lsp;
760 zebra_nhlfe_t *nhlfe;
761 char buf[BUFSIZ];
762
763 /* Lookup table. */
764 lsp_table = zvrf->lsp_table;
765 if (!lsp_table)
766 return -1;
767
768 /* If entry is present, exit. */
769 tmp_ile.in_label = in_label;
770 lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
771 if (!lsp)
772 return -1;
773 nhlfe = nhlfe_find (lsp, ZEBRA_LSP_STATIC, gtype, gate, ifname, ifindex);
774 if (nhlfe)
775 {
776 struct nexthop *nh = nhlfe->nexthop;
777
778 assert (nh);
779 assert (nh->nh_label);
780
781 /* Clear deleted flag (in case it was set) */
782 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
783 if (nh->nh_label->label[0] == out_label)
784 /* No change */
785 return 0;
786
787 if (IS_ZEBRA_DEBUG_MPLS)
788 {
789 nhlfe2str (nhlfe, buf, BUFSIZ);
790 zlog_debug ("LSP in-label %u type %d nexthop %s "
791 "out-label changed to %u (old %u)",
792 in_label, ZEBRA_LSP_STATIC, buf,
793 out_label, nh->nh_label->label[0]);
794 }
795
796 /* Update out label, trigger processing. */
797 nh->nh_label->label[0] = out_label;
798 }
799 else
800 {
801 /* Add LSP entry to this nexthop */
802 nhlfe = nhlfe_add (lsp, ZEBRA_LSP_STATIC, gtype, gate,
803 ifname, ifindex, out_label);
804 if (!nhlfe)
805 return -1;
806
807 if (IS_ZEBRA_DEBUG_MPLS)
808 {
809 nhlfe2str (nhlfe, buf, BUFSIZ);
810 zlog_debug ("Add LSP in-label %u type %d nexthop %s "
811 "out-label %u",
812 in_label, ZEBRA_LSP_STATIC, buf,
813 out_label);
814 }
815
816 lsp->addr_family = NHLFE_FAMILY (nhlfe);
817 }
818
819 /* Mark NHLFE, queue LSP for processing. */
820 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
821 if (lsp_processq_add (lsp))
822 return -1;
823
824 return 0;
825}
826
827/*
828 * Uninstall a particular static NHLFE in the forwarding table. If this is
829 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
830 */
831static int
832static_lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t in_label,
833 enum nexthop_types_t gtype, union g_addr *gate,
834 char *ifname, ifindex_t ifindex)
835{
836 struct hash *lsp_table;
837 zebra_ile_t tmp_ile;
838 zebra_lsp_t *lsp;
839 zebra_nhlfe_t *nhlfe;
840 char buf[BUFSIZ];
841
842 /* Lookup table. */
843 lsp_table = zvrf->lsp_table;
844 if (!lsp_table)
845 return -1;
846
847 /* If entry is not present, exit. */
848 tmp_ile.in_label = in_label;
849 lsp = hash_lookup (lsp_table, &tmp_ile);
850 if (!lsp)
851 return 0;
852 nhlfe = nhlfe_find (lsp, ZEBRA_LSP_STATIC, gtype, gate, ifname, ifindex);
853 if (!nhlfe)
854 return 0;
855
856 if (IS_ZEBRA_DEBUG_MPLS)
857 {
858 nhlfe2str (nhlfe, buf, BUFSIZ);
859 zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
860 in_label, ZEBRA_LSP_STATIC, buf, nhlfe->flags);
861 }
862
863 /* Mark NHLFE for delete or directly delete, as appropriate. */
864 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
865 {
866 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
867 SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
868 if (lsp_processq_add (lsp))
869 return -1;
870 }
871 else
872 {
873 nhlfe_del (nhlfe);
874
875 /* Free LSP entry if no other NHLFEs and not scheduled. */
876 if (!lsp->nhlfe_list &&
877 !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
878 {
879 if (IS_ZEBRA_DEBUG_MPLS)
880 zlog_debug ("Free LSP in-label %u flags 0x%x",
881 lsp->ile.in_label, lsp->flags);
882
883 lsp = hash_release(lsp_table, &lsp->ile);
884 if (lsp)
885 XFREE(MTYPE_LSP, lsp);
886 }
887 }
888 return 0;
889}
890
891/*
892 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
893 * If no other NHLFEs exist, the entry would be deleted.
894 */
895static int
896static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label)
897{
898 struct hash *lsp_table;
899 zebra_ile_t tmp_ile;
900 zebra_lsp_t *lsp;
901 zebra_nhlfe_t *nhlfe, *nhlfe_next;
902 int schedule_lsp = 0;
903 char buf[BUFSIZ];
904
905 /* Lookup table. */
906 lsp_table = zvrf->lsp_table;
907 if (!lsp_table)
908 return -1;
909
910 /* If entry is not present, exit. */
911 tmp_ile.in_label = in_label;
912 lsp = hash_lookup (lsp_table, &tmp_ile);
913 if (!lsp || !lsp->nhlfe_list)
914 return 0;
915
916 /* Mark NHLFEs for delete or directly delete, as appropriate. */
917 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next)
918 {
919 nhlfe_next = nhlfe->next;
920
921 /* Skip non-static NHLFEs */
922 if (nhlfe->type != ZEBRA_LSP_STATIC)
923 continue;
924
925 if (IS_ZEBRA_DEBUG_MPLS)
926 {
927 nhlfe2str (nhlfe, buf, BUFSIZ);
928 zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
929 in_label, ZEBRA_LSP_STATIC, buf, nhlfe->flags);
930 }
931
932 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
933 {
934 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
935 SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
936 schedule_lsp = 1;
937 }
938 else
939 {
940 nhlfe_del (nhlfe);
941 }
942 }
943
944 /* Queue LSP for processing, if needed, else delete. */
945 if (schedule_lsp)
946 {
947 if (lsp_processq_add (lsp))
948 return -1;
949 }
950 else if (!lsp->nhlfe_list &&
951 !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
952 {
953 if (IS_ZEBRA_DEBUG_MPLS)
954 zlog_debug ("Free LSP in-label %u flags 0x%x",
955 lsp->ile.in_label, lsp->flags);
956
957 lsp = hash_release(lsp_table, &lsp->ile);
958 if (lsp)
959 XFREE(MTYPE_LSP, lsp);
960 }
961
962 return 0;
963}
964
7758e3f3 965/*
966 * Write out static LSP configuration.
967 */
968static void
969lsp_config_write (struct hash_backet *backet, void *ctxt)
970{
971 zebra_slsp_t *slsp;
972 zebra_snhlfe_t *snhlfe;
973 struct vty *vty = (struct vty *) ctxt;
974 char buf[INET6_ADDRSTRLEN];
975
976 slsp = (zebra_slsp_t *) backet->data;
977 if (!slsp)
978 return;
979
980 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
981 {
982 char lstr[30];
983 snhlfe2str (snhlfe, buf, BUFSIZ);
984 vty_out (vty, "mpls lsp %u %s %s%s",
985 slsp->ile.in_label, buf,
986 label2str(snhlfe->out_label, lstr, 30), VTY_NEWLINE);
987 }
988}
989
990/*
991 * Callback to allocate static LSP.
992 */
993static void *
994slsp_alloc (void *p)
995{
996 const zebra_ile_t *ile = p;
997 zebra_slsp_t *slsp;
998
999 slsp = XCALLOC (MTYPE_SLSP, sizeof(zebra_slsp_t));
1000 slsp->ile = *ile;
1001 return ((void *)slsp);
1002}
1003
1004/*
1005 * Check if static NHLFE matches with search info passed.
1006 */
1007static int
1008snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
1009 union g_addr *gate, char *ifname, ifindex_t ifindex)
1010{
1011 u_char cmp = -1;
1012
1013 if (snhlfe->gtype != gtype)
1014 return -1;
1015
1016 switch (snhlfe->gtype)
1017 {
1018 case NEXTHOP_TYPE_IPV4:
1019 cmp = memcmp(&(snhlfe->gate.ipv4), &(gate->ipv4),
1020 sizeof(struct in_addr));
1021 break;
1022 case NEXTHOP_TYPE_IPV6:
1023 case NEXTHOP_TYPE_IPV6_IFINDEX:
1024 cmp = memcmp(&(snhlfe->gate.ipv6), &(gate->ipv6),
1025 sizeof(struct in6_addr));
1026 if (!cmp && snhlfe->gtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1027 cmp = !(snhlfe->ifindex == ifindex);
1028 break;
1029 default:
1030 break;
1031 }
1032
1033 return cmp;
1034}
1035
1036/*
1037 * Locate static NHLFE that matches with passed info.
1038 */
1039static zebra_snhlfe_t *
1040snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
1041 union g_addr *gate, char *ifname, ifindex_t ifindex)
1042{
1043 zebra_snhlfe_t *snhlfe;
1044
1045 if (!slsp)
1046 return NULL;
1047
1048 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
1049 {
1050 if (!snhlfe_match (snhlfe, gtype, gate, ifname, ifindex))
1051 break;
1052 }
1053
1054 return snhlfe;
1055}
1056
1057
1058/*
1059 * Add static NHLFE. Base LSP config entry must have been created
1060 * and duplicate check done.
1061 */
1062static zebra_snhlfe_t *
1063snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
1064 union g_addr *gate, char *ifname, ifindex_t ifindex,
1065 mpls_label_t out_label)
1066{
1067 zebra_snhlfe_t *snhlfe;
1068
1069 if (!slsp)
1070 return NULL;
1071
1072 snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t));
1073 snhlfe->slsp = slsp;
1074 snhlfe->out_label = out_label;
1075 snhlfe->gtype = gtype;
1076 switch (gtype)
1077 {
1078 case NEXTHOP_TYPE_IPV4:
1079 snhlfe->gate.ipv4 = gate->ipv4;
1080 break;
1081 case NEXTHOP_TYPE_IPV6:
1082 case NEXTHOP_TYPE_IPV6_IFINDEX:
1083 snhlfe->gate.ipv6 = gate->ipv6;
1084 if (ifindex)
1085 snhlfe->ifindex = ifindex;
1086 break;
1087 default:
1088 XFREE (MTYPE_SNHLFE, snhlfe);
1089 return NULL;
1090 }
1091
1092 if (slsp->snhlfe_list)
1093 slsp->snhlfe_list->prev = snhlfe;
1094 snhlfe->next = slsp->snhlfe_list;
1095 slsp->snhlfe_list = snhlfe;
1096
1097 return snhlfe;
1098}
1099
1100/*
1101 * Delete static NHLFE. Entry must be present on list.
1102 */
1103static int
1104snhlfe_del (zebra_snhlfe_t *snhlfe)
1105{
1106 zebra_slsp_t *slsp;
1107
1108 if (!snhlfe)
1109 return -1;
1110
1111 slsp = snhlfe->slsp;
1112 if (!slsp)
1113 return -1;
1114
1115 if (snhlfe->next)
1116 snhlfe->next->prev = snhlfe->prev;
1117 if (snhlfe->prev)
1118 snhlfe->prev->next = snhlfe->next;
1119 else
1120 slsp->snhlfe_list = snhlfe->next;
1121
1122 snhlfe->prev = snhlfe->next = NULL;
1123 if (snhlfe->ifname)
1124 XFREE (MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
1125 XFREE (MTYPE_SNHLFE, snhlfe);
1126
1127 return 0;
1128}
1129
1130/*
1131 * Delete all static NHLFE entries for this LSP (in label).
1132 */
1133static int
1134snhlfe_del_all (zebra_slsp_t *slsp)
1135{
1136 zebra_snhlfe_t *snhlfe, *snhlfe_next;
1137
1138 if (!slsp)
1139 return -1;
1140
1141 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next)
1142 {
1143 snhlfe_next = snhlfe->next;
1144 snhlfe_del (snhlfe);
1145 }
1146
1147 return 0;
1148}
1149
1150/*
1151 * Create printable string for NHLFE configuration.
1152 */
1153static char *
1154snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size)
1155{
1156 buf[0] = '\0';
1157 switch (snhlfe->gtype)
1158 {
1159 case NEXTHOP_TYPE_IPV4:
1160 inet_ntop (AF_INET, &snhlfe->gate.ipv4, buf, size);
1161 break;
1162 case NEXTHOP_TYPE_IPV6:
1163 case NEXTHOP_TYPE_IPV6_IFINDEX:
1164 inet_ntop (AF_INET6, &snhlfe->gate.ipv6, buf, size);
1165 if (snhlfe->ifindex)
1166 strcat (buf, ifindex2ifname (snhlfe->ifindex));
1167 break;
1168 default:
1169 break;
1170 }
1171
1172 return buf;
1173}
1174
40c7bdb0 1175/*
1176 * Initialize work queue for processing changed LSPs.
1177 */
1178static void
1179mpls_processq_init (struct zebra_t *zebra)
1180{
1181 zebra->lsp_process_q = work_queue_new (zebra->master, "LSP processing");
1182 if (!zebra->lsp_process_q)
1183 {
1184 zlog_err ("%s: could not initialise work queue!", __func__);
1185 return;
1186 }
1187
1188 zebra->lsp_process_q->spec.workfunc = &lsp_process;
1189 zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del;
1190 zebra->lsp_process_q->spec.errorfunc = NULL;
1191 zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete;
1192 zebra->lsp_process_q->spec.max_retries = 0;
1193 zebra->lsp_process_q->spec.hold = 10;
1194}
1195
7758e3f3 1196
1197
1198/* Public functions */
1199
1200/*
1201 * Check that the label values used in LSP creation are consistent. The
1202 * main criteria is that if there is ECMP, the label operation must still
1203 * be consistent - i.e., all paths either do a swap or do PHP. This is due
1204 * to current HW restrictions.
1205 */
1206int
1207zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
1208 mpls_label_t out_label, enum nexthop_types_t gtype,
1209 union g_addr *gate, char *ifname, ifindex_t ifindex)
1210{
1211 struct hash *slsp_table;
1212 zebra_ile_t tmp_ile;
1213 zebra_slsp_t *slsp;
1214 zebra_snhlfe_t *snhlfe;
1215
1216 /* Lookup table. */
1217 slsp_table = zvrf->slsp_table;
1218 if (!slsp_table)
1219 return 0;
1220
1221 /* If entry is not present, exit. */
1222 tmp_ile.in_label = in_label;
1223 slsp = hash_lookup (slsp_table, &tmp_ile);
1224 if (!slsp)
1225 return 1;
1226
1227 snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
1228 if (snhlfe)
1229 {
1230 if (snhlfe->out_label == out_label)
1231 return 1;
1232
1233 /* If not only NHLFE, cannot allow label change. */
1234 if (snhlfe != slsp->snhlfe_list ||
1235 snhlfe->next)
1236 return 0;
1237 }
1238 else
1239 {
1240 /* If other NHLFEs exist, label operation must match. */
1241 if (slsp->snhlfe_list)
1242 {
1243 int cur_op, new_op;
1244
1245 cur_op = (slsp->snhlfe_list->out_label == MPLS_IMP_NULL_LABEL);
1246 new_op = (out_label == MPLS_IMP_NULL_LABEL);
1247 if (cur_op != new_op)
1248 return 0;
1249 }
1250 }
1251
1252 /* Label values are good. */
1253 return 1;
1254}
1255
1256
1257/*
1258 * Add static LSP entry. This may be the first entry for this incoming label
1259 * or an additional nexthop; an existing entry may also have outgoing label
1260 * changed.
1261 * Note: The label operation (swap or PHP) is common for the LSP entry (all
1262 * NHLFEs).
1263 */
1264int
1265zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
1266 mpls_label_t out_label, enum nexthop_types_t gtype,
1267 union g_addr *gate, char *ifname, ifindex_t ifindex)
1268{
1269 struct hash *slsp_table;
1270 zebra_ile_t tmp_ile;
1271 zebra_slsp_t *slsp;
1272 zebra_snhlfe_t *snhlfe;
1273 char buf[BUFSIZ];
1274
1275 /* Lookup table. */
1276 slsp_table = zvrf->slsp_table;
1277 if (!slsp_table)
1278 return -1;
1279
1280 /* If entry is present, exit. */
1281 tmp_ile.in_label = in_label;
1282 slsp = hash_get (slsp_table, &tmp_ile, slsp_alloc);
1283 if (!slsp)
1284 return -1;
1285 snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
1286 if (snhlfe)
1287 {
1288 if (snhlfe->out_label == out_label)
1289 /* No change */
1290 return 0;
1291
1292 if (IS_ZEBRA_DEBUG_MPLS)
1293 {
1294 snhlfe2str (snhlfe, buf, BUFSIZ);
1295 zlog_debug ("Upd static LSP in-label %u nexthop %s "
1296 "out-label %u (old %u)",
1297 in_label, buf, out_label, snhlfe->out_label);
1298 }
1299 snhlfe->out_label = out_label;
1300 }
1301 else
1302 {
1303 /* Add static LSP entry to this nexthop */
1304 snhlfe = snhlfe_add (slsp, gtype, gate, ifname, ifindex, out_label);
1305 if (!snhlfe)
1306 return -1;
1307
1308 if (IS_ZEBRA_DEBUG_MPLS)
1309 {
1310 snhlfe2str (snhlfe, buf, BUFSIZ);
1311 zlog_debug ("Add static LSP in-label %u nexthop %s out-label %u",
1312 in_label, buf, out_label);
1313 }
1314 }
1315
40c7bdb0 1316 /* (Re)Install LSP in the main table. */
1317 if (static_lsp_install (zvrf, in_label, out_label, gtype,
1318 gate, ifname, ifindex))
1319 return -1;
1320
7758e3f3 1321 return 0;
1322}
1323
1324/*
1325 * Delete static LSP entry. This may be the delete of one particular
1326 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
1327 * all NHLFEs).
1328 * NOTE: Delete of the only NHLFE will also end up deleting the entire
1329 * LSP configuration.
1330 */
1331int
1332zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
1333 enum nexthop_types_t gtype, union g_addr *gate,
1334 char *ifname, ifindex_t ifindex)
1335{
1336 struct hash *slsp_table;
1337 zebra_ile_t tmp_ile;
1338 zebra_slsp_t *slsp;
1339 zebra_snhlfe_t *snhlfe;
1340
1341 /* Lookup table. */
1342 slsp_table = zvrf->slsp_table;
1343 if (!slsp_table)
1344 return -1;
1345
1346 /* If entry is not present, exit. */
1347 tmp_ile.in_label = in_label;
1348 slsp = hash_lookup (slsp_table, &tmp_ile);
1349 if (!slsp)
1350 return 0;
1351
1352 /* Is it delete of entire LSP or a specific NHLFE? */
1353 if (gtype == NEXTHOP_TYPE_BLACKHOLE)
1354 {
1355 if (IS_ZEBRA_DEBUG_MPLS)
1356 zlog_debug ("Del static LSP in-label %u", in_label);
1357
40c7bdb0 1358 /* Uninstall entire LSP from the main table. */
1359 static_lsp_uninstall_all (zvrf, in_label);
1360
7758e3f3 1361 /* Delete all static NHLFEs */
1362 snhlfe_del_all (slsp);
1363 }
1364 else
1365 {
1366 /* Find specific NHLFE, exit if not found. */
1367 snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
1368 if (!snhlfe)
1369 return 0;
1370
1371 if (IS_ZEBRA_DEBUG_MPLS)
1372 {
1373 char buf[BUFSIZ];
1374 snhlfe2str (snhlfe, buf, BUFSIZ);
1375 zlog_debug ("Del static LSP in-label %u nexthop %s",
1376 in_label, buf);
1377 }
1378
40c7bdb0 1379 /* Uninstall LSP from the main table. */
1380 static_lsp_uninstall (zvrf, in_label, gtype,
1381 gate, ifname, ifindex);
1382
7758e3f3 1383 /* Delete static LSP NHLFE */
1384 snhlfe_del (snhlfe);
1385 }
1386
1387 /* Remove entire static LSP entry if no NHLFE - valid in either case above. */
1388 if (!slsp->snhlfe_list)
1389 {
1390 slsp = hash_release(slsp_table, &tmp_ile);
1391 if (slsp)
1392 XFREE(MTYPE_SLSP, slsp);
1393 }
1394
1395 return 0;
1396}
1397
40c7bdb0 1398/*
1399 * Schedule all MPLS label forwarding entries for processing.
1400 * Called upon changes that may affect one or more of them such as
1401 * interface or nexthop state changes.
1402 */
1403void
1404zebra_mpls_lsp_schedule (struct zebra_vrf *zvrf)
1405{
1406 if (!zvrf)
1407 return;
1408 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
1409}
1410
7758e3f3 1411/*
1412 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
1413 */
1414int
1415zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
1416{
1417 hash_iterate(zvrf->slsp_table, lsp_config_write, vty);
1418 return (zvrf->slsp_table->count ? 1 : 0);
1419}
1420
40c7bdb0 1421/*
1422 * Called upon process exiting, need to delete LSP forwarding
1423 * entries from the kernel.
1424 * NOTE: Currently supported only for default VRF.
1425 */
1426void
1427zebra_mpls_close_tables (struct zebra_vrf *zvrf)
1428{
1429 if (!zvrf)
1430 return;
1431 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
1432}
1433
7758e3f3 1434/*
1435 * Allocate MPLS tables for this VRF and do other initialization.
1436 * NOTE: Currently supported only for default VRF.
1437 */
1438void
1439zebra_mpls_init_tables (struct zebra_vrf *zvrf)
1440{
1441 if (!zvrf)
1442 return;
1443 zvrf->slsp_table = hash_create(label_hash, label_cmp);
40c7bdb0 1444 zvrf->lsp_table = hash_create(label_hash, label_cmp);
7758e3f3 1445}
1446
1447/*
1448 * Global MPLS initialization.
1449 */
1450void
1451zebra_mpls_init (void)
1452{
40c7bdb0 1453 mpls_processq_init (&zebrad);
7758e3f3 1454}