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