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