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