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