]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_mpls.c
lib, zebra: Allow zapi to send down the tableid
[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. */
996c9314
LB
414 if (old_label != MPLS_INVALID_LABEL
415 && old_label != MPLS_LABEL_IMPLICIT_NULL)
d62a17ae 416 lsp_uninstall(zvrf, old_label);
a64448ba 417
d62a17ae 418 /* Install label forwarding entry corr. to new label, if needed. */
419 if (fec->label == MPLS_INVALID_LABEL
70e98a7f 420 || fec->label == MPLS_LABEL_IMPLICIT_NULL)
d62a17ae 421 return 0;
a64448ba 422
d62a17ae 423 afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
424 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
425 if (!table)
426 return 0;
a64448ba 427
d62a17ae 428 /* See if labeled route exists. */
429 rn = route_node_lookup(table, &fec->rn->p);
430 if (!rn)
431 return 0;
a64448ba 432
a2addae8 433 RNODE_FOREACH_RE (rn, re) {
d62a17ae 434 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
435 break;
436 }
a64448ba 437
d62a17ae 438 if (!re || !zebra_rib_labeled_unicast(re))
439 return 0;
a64448ba 440
d62a17ae 441 if (lsp_install(zvrf, fec->label, rn, re))
442 return -1;
a64448ba 443
d62a17ae 444 return 0;
a64448ba
DS
445}
446
5aba114a
DS
447/*
448 * Inform about FEC to a registered client.
449 */
d62a17ae 450static int fec_send(zebra_fec_t *fec, struct zserv *client)
5aba114a 451{
d62a17ae 452 struct stream *s;
453 struct route_node *rn;
5aba114a 454
d62a17ae 455 rn = fec->rn;
5aba114a 456
d62a17ae 457 /* Get output stream. */
458 s = client->obuf;
459 stream_reset(s);
5aba114a 460
7cf15b25 461 zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
5aba114a 462
d62a17ae 463 stream_putw(s, rn->p.family);
464 stream_put_prefix(s, &rn->p);
465 stream_putl(s, fec->label);
466 stream_putw_at(s, 0, stream_get_endp(s));
467 return zebra_server_send_message(client);
5aba114a
DS
468}
469
470/*
471 * Update all registered clients about this FEC. Caller should've updated
472 * FEC and ensure no duplicate updates.
473 */
d62a17ae 474static void fec_update_clients(zebra_fec_t *fec)
5aba114a 475{
d62a17ae 476 struct listnode *node;
477 struct zserv *client;
5aba114a 478
d62a17ae 479 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) {
480 if (IS_ZEBRA_DEBUG_MPLS)
481 zlog_debug("Update client %s",
482 zebra_route_string(client->proto));
483 fec_send(fec, client);
484 }
5aba114a
DS
485}
486
487
f31e084c
DS
488/*
489 * Print a FEC-label binding entry.
490 */
d62a17ae 491static void fec_print(zebra_fec_t *fec, struct vty *vty)
492{
493 struct route_node *rn;
494 struct listnode *node;
495 struct zserv *client;
496 char buf[BUFSIZ];
497
498 rn = fec->rn;
499 prefix2str(&rn->p, buf, BUFSIZ);
500 vty_out(vty, "%s\n", buf);
501 vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
502 if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
503 vty_out(vty, ", Label Index: %u", fec->label_index);
504 vty_out(vty, "\n");
505 if (!list_isempty(fec->client_list)) {
506 vty_out(vty, " Client list:");
507 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
508 vty_out(vty, " %s(fd %d)",
509 zebra_route_string(client->proto),
510 client->sock);
511 vty_out(vty, "\n");
512 }
f31e084c
DS
513}
514
515/*
516 * Locate FEC-label binding that matches with passed info.
517 */
d62a17ae 518static zebra_fec_t *fec_find(struct route_table *table, struct prefix *p)
f31e084c 519{
d62a17ae 520 struct route_node *rn;
f31e084c 521
d62a17ae 522 apply_mask(p);
523 rn = route_node_lookup(table, p);
524 if (!rn)
525 return NULL;
f31e084c 526
d62a17ae 527 route_unlock_node(rn);
528 return (rn->info);
f31e084c
DS
529}
530
531/*
5aba114a
DS
532 * Add a FEC. This may be upon a client registering for a binding
533 * or when a binding is configured.
f31e084c 534 */
d62a17ae 535static zebra_fec_t *fec_add(struct route_table *table, struct prefix *p,
536 mpls_label_t label, u_int32_t flags,
537 u_int32_t label_index)
f31e084c 538{
d62a17ae 539 struct route_node *rn;
540 zebra_fec_t *fec;
f31e084c 541
d62a17ae 542 apply_mask(p);
f31e084c 543
d62a17ae 544 /* Lookup (or add) route node.*/
545 rn = route_node_get(table, p);
546 if (!rn)
547 return NULL;
f31e084c 548
d62a17ae 549 fec = rn->info;
f31e084c 550
d62a17ae 551 if (!fec) {
552 fec = XCALLOC(MTYPE_FEC, sizeof(zebra_fec_t));
553 if (!fec)
554 return NULL;
f31e084c 555
d62a17ae 556 rn->info = fec;
557 fec->rn = rn;
558 fec->label = label;
559 fec->client_list = list_new();
560 } else
561 route_unlock_node(rn); /* for the route_node_get */
f31e084c 562
d62a17ae 563 fec->label_index = label_index;
564 fec->flags = flags;
f31e084c 565
d62a17ae 566 return fec;
f31e084c
DS
567}
568
569/*
5aba114a
DS
570 * Delete a FEC. This may be upon the last client deregistering for
571 * a FEC and no binding exists or when the binding is deleted and there
572 * are no registered clients.
f31e084c 573 */
d62a17ae 574static int fec_del(zebra_fec_t *fec)
f31e084c 575{
acdf5e25 576 list_delete_and_null(&fec->client_list);
d62a17ae 577 fec->rn->info = NULL;
578 route_unlock_node(fec->rn);
579 XFREE(MTYPE_FEC, fec);
580 return 0;
f31e084c
DS
581}
582
7758e3f3 583/*
584 * Hash function for label.
585 */
d62a17ae 586static unsigned int label_hash(void *p)
7758e3f3 587{
d62a17ae 588 const zebra_ile_t *ile = p;
7758e3f3 589
d62a17ae 590 return (jhash_1word(ile->in_label, 0));
7758e3f3 591}
592
593/*
594 * Compare 2 LSP hash entries based on in-label.
595 */
d62a17ae 596static int label_cmp(const void *p1, const void *p2)
7758e3f3 597{
d62a17ae 598 const zebra_ile_t *ile1 = p1;
599 const zebra_ile_t *ile2 = p2;
7758e3f3 600
d62a17ae 601 return (ile1->in_label == ile2->in_label);
7758e3f3 602}
603
40c7bdb0 604/*
605 * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
606 * the passed flag.
607 * NOTE: Looking only for connected routes right now.
608 */
d62a17ae 609static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe,
610 struct nexthop *nexthop)
40c7bdb0 611{
d62a17ae 612 struct route_table *table;
613 struct prefix_ipv4 p;
614 struct route_node *rn;
615 struct route_entry *match;
616 struct nexthop *match_nh;
40c7bdb0 617
4a7371e9 618 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, nexthop->vrf_id);
d62a17ae 619 if (!table)
620 return 0;
40c7bdb0 621
d62a17ae 622 /* Lookup nexthop in IPv4 routing table. */
623 memset(&p, 0, sizeof(struct prefix_ipv4));
624 p.family = AF_INET;
625 p.prefixlen = IPV4_MAX_PREFIXLEN;
626 p.prefix = nexthop->gate.ipv4;
40c7bdb0 627
d62a17ae 628 rn = route_node_match(table, (struct prefix *)&p);
629 if (!rn)
630 return 0;
40c7bdb0 631
d62a17ae 632 route_unlock_node(rn);
88d88a9c 633
d62a17ae 634 /* Locate a valid connected route. */
a2addae8 635 RNODE_FOREACH_RE (rn, match) {
d62a17ae 636 if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
637 || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
638 continue;
639
640 for (match_nh = match->nexthop; match_nh;
641 match_nh = match_nh->next) {
642 if (match->type == ZEBRA_ROUTE_CONNECT
643 || nexthop->ifindex == match_nh->ifindex) {
644 nexthop->ifindex = match_nh->ifindex;
645 return 1;
646 }
647 }
88d88a9c 648 }
40c7bdb0 649
d62a17ae 650 return 0;
40c7bdb0 651}
652
653
654/*
655 * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
656 * the passed flag.
657 * NOTE: Looking only for connected routes right now.
658 */
d62a17ae 659static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe,
660 struct nexthop *nexthop)
40c7bdb0 661{
d62a17ae 662 struct route_table *table;
663 struct prefix_ipv6 p;
664 struct route_node *rn;
665 struct route_entry *match;
40c7bdb0 666
4a7371e9 667 table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
d62a17ae 668 if (!table)
669 return 0;
40c7bdb0 670
d62a17ae 671 /* Lookup nexthop in IPv6 routing table. */
672 memset(&p, 0, sizeof(struct prefix_ipv6));
673 p.family = AF_INET6;
674 p.prefixlen = IPV6_MAX_PREFIXLEN;
675 p.prefix = nexthop->gate.ipv6;
40c7bdb0 676
d62a17ae 677 rn = route_node_match(table, (struct prefix *)&p);
678 if (!rn)
679 return 0;
40c7bdb0 680
d62a17ae 681 route_unlock_node(rn);
40c7bdb0 682
d62a17ae 683 /* Locate a valid connected route. */
a2addae8 684 RNODE_FOREACH_RE (rn, match) {
d62a17ae 685 if ((match->type == ZEBRA_ROUTE_CONNECT)
686 && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
687 && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
688 break;
689 }
40c7bdb0 690
d62a17ae 691 if (!match || !match->nexthop)
692 return 0;
40c7bdb0 693
d62a17ae 694 nexthop->ifindex = match->nexthop->ifindex;
695 return 1;
40c7bdb0 696}
697
698
699/*
700 * Check the nexthop reachability for a NHLFE and return if valid (reachable)
701 * or not.
702 * NOTE: Each NHLFE points to only 1 nexthop.
703 */
d62a17ae 704static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe)
705{
706 struct nexthop *nexthop;
707 struct interface *ifp;
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 */
725 ifp = if_lookup_by_index(nexthop->ifindex, VRF_UNKNOWN);
726 if (ifp && if_is_operative(ifp))
727 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
728 else
729 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
730 break;
d62a17ae 731 case NEXTHOP_TYPE_IPV4:
732 case NEXTHOP_TYPE_IPV4_IFINDEX:
733 if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop))
734 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
735 else
736 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
737 break;
738
739 case NEXTHOP_TYPE_IPV6:
740 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
741 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
742 else
743 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
744 break;
745
746 case NEXTHOP_TYPE_IPV6_IFINDEX:
747 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
4a7371e9
DS
748 ifp = if_lookup_by_index(nexthop->ifindex,
749 nexthop->vrf_id);
d62a17ae 750 if (ifp && if_is_operative(ifp))
751 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
752 else
753 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
754 } else {
755 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
756 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
757 else
758 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
759 }
760 break;
761
762 default:
763 break;
764 }
765
766 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
40c7bdb0 767}
768
769/*
770 * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
771 * reachability and select the best. Multipath entries are also
772 * marked. This is invoked when an LSP scheduled for processing (due
773 * to some change) is examined.
774 */
d62a17ae 775static void lsp_select_best_nhlfe(zebra_lsp_t *lsp)
776{
777 zebra_nhlfe_t *nhlfe;
778 zebra_nhlfe_t *best;
779 struct nexthop *nexthop;
780 int changed = 0;
781
782 if (!lsp)
783 return;
784
785 best = NULL;
786 lsp->num_ecmp = 0;
787 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
788
789 /*
790 * First compute the best path, after checking nexthop status. We are
791 * only
792 * concerned with non-deleted NHLFEs.
793 */
794 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
795 /* Clear selection flags. */
796 UNSET_FLAG(nhlfe->flags,
797 (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
798
799 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
800 && nhlfe_nexthop_active(nhlfe)) {
801 if (!best || (nhlfe->distance < best->distance))
802 best = nhlfe;
803 }
804 }
805
806 lsp->best_nhlfe = best;
807 if (!lsp->best_nhlfe)
808 return;
809
810 /* Mark best NHLFE as selected. */
811 SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
812
813 /*
814 * If best path exists, see if there is ECMP. While doing this, note if
815 * a
816 * new (uninstalled) NHLFE has been selected, an installed entry that is
817 * still selected has a change or an installed entry is to be removed.
818 */
819 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
820 int nh_chg, nh_sel, nh_inst;
821
822 nexthop = nhlfe->nexthop;
823 if (!nexthop) // unexpected
824 continue;
825
826 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
827 && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
828 && (nhlfe->distance == lsp->best_nhlfe->distance)) {
829 SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
830 SET_FLAG(nhlfe->flags, NHLFE_FLAG_MULTIPATH);
831 lsp->num_ecmp++;
832 }
833
834 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) && !changed) {
835 nh_chg = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
836 nh_sel = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
837 nh_inst =
838 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
839
840 if ((nh_sel && !nh_inst)
841 || (nh_sel && nh_inst && nh_chg)
842 || (nh_inst && !nh_sel))
843 changed = 1;
844 }
845
846 /* We have finished examining, clear changed flag. */
847 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
848 }
849
850 if (changed)
851 SET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
40c7bdb0 852}
853
854/*
855 * Delete LSP forwarding entry from kernel, if installed. Called upon
856 * process exit.
857 */
d62a17ae 858static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt)
40c7bdb0 859{
d62a17ae 860 zebra_lsp_t *lsp;
40c7bdb0 861
d62a17ae 862 lsp = (zebra_lsp_t *)backet->data;
4a83e7a0
DS
863 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
864 kernel_del_lsp(lsp);
40c7bdb0 865}
866
867/*
868 * Schedule LSP forwarding entry for processing. Called upon changes
869 * that may impact LSPs such as nexthop / connected route changes.
870 */
d62a17ae 871static void lsp_schedule(struct hash_backet *backet, void *ctxt)
40c7bdb0 872{
d62a17ae 873 zebra_lsp_t *lsp;
40c7bdb0 874
d62a17ae 875 lsp = (zebra_lsp_t *)backet->data;
0af35d90 876 (void)lsp_processq_add(lsp);
40c7bdb0 877}
878
879/*
880 * Process a LSP entry that is in the queue. Recalculate best NHLFE and
881 * any multipaths and update or delete from the kernel, as needed.
882 */
d62a17ae 883static wq_item_status lsp_process(struct work_queue *wq, void *data)
884{
885 zebra_lsp_t *lsp;
886 zebra_nhlfe_t *oldbest, *newbest;
887 char buf[BUFSIZ], buf2[BUFSIZ];
888 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
889
890 lsp = (zebra_lsp_t *)data;
891 if (!lsp) // unexpected
892 return WQ_SUCCESS;
893
894 oldbest = lsp->best_nhlfe;
895
896 /* Select best NHLFE(s) */
897 lsp_select_best_nhlfe(lsp);
898
899 newbest = lsp->best_nhlfe;
900
901 if (IS_ZEBRA_DEBUG_MPLS) {
902 if (oldbest)
903 nhlfe2str(oldbest, buf, BUFSIZ);
904 if (newbest)
905 nhlfe2str(newbest, buf2, BUFSIZ);
906 zlog_debug(
907 "Process LSP in-label %u oldbest %s newbest %s "
908 "flags 0x%x ecmp# %d",
909 lsp->ile.in_label, oldbest ? buf : "NULL",
910 newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
911 }
912
913 if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
914 /* Not already installed */
915 if (newbest) {
2b63430c
DS
916
917 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
4a83e7a0 918 kernel_add_lsp(lsp);
2b63430c 919
d62a17ae 920 zvrf->lsp_installs++;
921 }
922 } else {
923 /* Installed, may need an update and/or delete. */
924 if (!newbest) {
e6d44ec7 925
4a83e7a0 926 kernel_del_lsp(lsp);
e6d44ec7 927
d62a17ae 928 zvrf->lsp_removals++;
929 } else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) {
9fa38ec6
DS
930 zebra_nhlfe_t *nhlfe;
931 struct nexthop *nexthop;
2b63430c
DS
932
933 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
934 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
e6d44ec7 935
9fa38ec6
DS
936 /*
937 * Any NHLFE that was installed but is not
938 * selected now needs to have its flags updated.
939 */
996c9314
LB
940 for (nhlfe = lsp->nhlfe_list; nhlfe;
941 nhlfe = nhlfe->next) {
9fa38ec6
DS
942 nexthop = nhlfe->nexthop;
943 if (!nexthop)
944 continue;
945
946 if (CHECK_FLAG(nhlfe->flags,
996c9314
LB
947 NHLFE_FLAG_INSTALLED)
948 && !CHECK_FLAG(nhlfe->flags,
949 NHLFE_FLAG_SELECTED)) {
9fa38ec6
DS
950 UNSET_FLAG(nhlfe->flags,
951 NHLFE_FLAG_INSTALLED);
952 UNSET_FLAG(nexthop->flags,
953 NEXTHOP_FLAG_FIB);
954 }
955 }
956
4a83e7a0 957 kernel_upd_lsp(lsp);
2b63430c 958
d62a17ae 959 zvrf->lsp_installs++;
960 }
961 }
962
963 return WQ_SUCCESS;
40c7bdb0 964}
965
966
967/*
968 * Callback upon processing completion of a LSP forwarding entry.
969 */
d62a17ae 970static void lsp_processq_del(struct work_queue *wq, void *data)
40c7bdb0 971{
d62a17ae 972 struct zebra_vrf *zvrf;
973 zebra_lsp_t *lsp;
974 struct hash *lsp_table;
975 zebra_nhlfe_t *nhlfe, *nhlfe_next;
40c7bdb0 976
d62a17ae 977 zvrf = vrf_info_lookup(VRF_DEFAULT);
978 assert(zvrf);
40c7bdb0 979
d62a17ae 980 lsp_table = zvrf->lsp_table;
981 if (!lsp_table) // unexpected
982 return;
40c7bdb0 983
d62a17ae 984 lsp = (zebra_lsp_t *)data;
985 if (!lsp) // unexpected
986 return;
40c7bdb0 987
d62a17ae 988 /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
989 * exist,
990 * delete LSP entry also.
991 */
992 UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
40c7bdb0 993
d62a17ae 994 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) {
995 nhlfe_next = nhlfe->next;
996 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
997 nhlfe_del(nhlfe);
998 }
40c7bdb0 999
d62a17ae 1000 if (!lsp->nhlfe_list) {
1001 if (IS_ZEBRA_DEBUG_MPLS)
1002 zlog_debug("Free LSP in-label %u flags 0x%x",
1003 lsp->ile.in_label, lsp->flags);
40c7bdb0 1004
d62a17ae 1005 lsp = hash_release(lsp_table, &lsp->ile);
1006 if (lsp)
1007 XFREE(MTYPE_LSP, lsp);
1008 }
40c7bdb0 1009}
1010
1011/*
1012 * Callback upon finishing the processing of all scheduled
1013 * LSP forwarding entries.
1014 */
d62a17ae 1015static void lsp_processq_complete(struct work_queue *wq)
40c7bdb0 1016{
d62a17ae 1017 /* Nothing to do for now. */
40c7bdb0 1018}
1019
1020/*
1021 * Add LSP forwarding entry to queue for subsequent processing.
1022 */
d62a17ae 1023static int lsp_processq_add(zebra_lsp_t *lsp)
40c7bdb0 1024{
d62a17ae 1025 /* If already scheduled, exit. */
1026 if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1027 return 0;
40c7bdb0 1028
d62a17ae 1029 if (zebrad.lsp_process_q == NULL) {
1030 zlog_err("%s: work_queue does not exist!", __func__);
1031 return -1;
1032 }
33c32282 1033
d62a17ae 1034 work_queue_add(zebrad.lsp_process_q, lsp);
1035 SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1036 return 0;
40c7bdb0 1037}
1038
1039/*
1040 * Callback to allocate LSP forwarding table entry.
1041 */
d62a17ae 1042static void *lsp_alloc(void *p)
40c7bdb0 1043{
d62a17ae 1044 const zebra_ile_t *ile = p;
1045 zebra_lsp_t *lsp;
40c7bdb0 1046
d62a17ae 1047 lsp = XCALLOC(MTYPE_LSP, sizeof(zebra_lsp_t));
1048 lsp->ile = *ile;
40c7bdb0 1049
d62a17ae 1050 if (IS_ZEBRA_DEBUG_MPLS)
1051 zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label);
40c7bdb0 1052
d62a17ae 1053 return ((void *)lsp);
40c7bdb0 1054}
1055
1056/*
1057 * Create printable string for NHLFE entry.
1058 */
d62a17ae 1059static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size)
40c7bdb0 1060{
d62a17ae 1061 struct nexthop *nexthop;
40c7bdb0 1062
d62a17ae 1063 buf[0] = '\0';
1064 nexthop = nhlfe->nexthop;
1065 switch (nexthop->type) {
1066 case NEXTHOP_TYPE_IPV4:
1067 case NEXTHOP_TYPE_IPV4_IFINDEX:
1068 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
1069 break;
1070 case NEXTHOP_TYPE_IPV6:
1071 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
1072 break;
b9abd9ad
DS
1073 case NEXTHOP_TYPE_IFINDEX:
1074 snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
d62a17ae 1075 default:
1076 break;
1077 }
40c7bdb0 1078
d62a17ae 1079 return buf;
40c7bdb0 1080}
1081
1082/*
1083 * Check if NHLFE matches with search info passed.
1084 */
d62a17ae 1085static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
1086 union g_addr *gate, ifindex_t ifindex)
40c7bdb0 1087{
d62a17ae 1088 struct nexthop *nhop;
1089 int cmp = 1;
40c7bdb0 1090
d62a17ae 1091 nhop = nhlfe->nexthop;
1092 if (!nhop)
1093 return 1;
40c7bdb0 1094
d62a17ae 1095 if (nhop->type != gtype)
1096 return 1;
40c7bdb0 1097
d62a17ae 1098 switch (nhop->type) {
1099 case NEXTHOP_TYPE_IPV4:
1100 case NEXTHOP_TYPE_IPV4_IFINDEX:
1101 cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
1102 sizeof(struct in_addr));
1103 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1104 cmp = !(nhop->ifindex == ifindex);
1105 break;
1106 case NEXTHOP_TYPE_IPV6:
1107 case NEXTHOP_TYPE_IPV6_IFINDEX:
1108 cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
1109 sizeof(struct in6_addr));
1110 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1111 cmp = !(nhop->ifindex == ifindex);
1112 break;
b9abd9ad
DS
1113 case NEXTHOP_TYPE_IFINDEX:
1114 cmp = !(nhop->ifindex == ifindex);
1115 break;
d62a17ae 1116 default:
1117 break;
1118 }
40c7bdb0 1119
d62a17ae 1120 return cmp;
40c7bdb0 1121}
1122
1123
1124/*
1125 * Locate NHLFE that matches with passed info.
1126 */
d62a17ae 1127static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
1128 enum nexthop_types_t gtype, union g_addr *gate,
1129 ifindex_t ifindex)
40c7bdb0 1130{
d62a17ae 1131 zebra_nhlfe_t *nhlfe;
40c7bdb0 1132
d62a17ae 1133 if (!lsp)
1134 return NULL;
40c7bdb0 1135
d62a17ae 1136 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1137 if (nhlfe->type != lsp_type)
1138 continue;
1139 if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex))
1140 break;
1141 }
40c7bdb0 1142
d62a17ae 1143 return nhlfe;
40c7bdb0 1144}
1145
1146/*
1147 * Add NHLFE. Base entry must have been created and duplicate
1148 * check done.
1149 */
d62a17ae 1150static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
1151 enum nexthop_types_t gtype, union g_addr *gate,
1152 ifindex_t ifindex, mpls_label_t out_label)
1153{
1154 zebra_nhlfe_t *nhlfe;
1155 struct nexthop *nexthop;
1156
1157 if (!lsp)
1158 return NULL;
1159
1160 nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(zebra_nhlfe_t));
1161 if (!nhlfe)
1162 return NULL;
1163
1164 nhlfe->lsp = lsp;
1165 nhlfe->type = lsp_type;
1166 nhlfe->distance = lsp_distance(lsp_type);
1167
1168 nexthop = nexthop_new();
1169 if (!nexthop) {
1170 XFREE(MTYPE_NHLFE, nhlfe);
1171 return NULL;
1172 }
1173 nexthop_add_labels(nexthop, lsp_type, 1, &out_label);
1174
4a7371e9 1175 nexthop->vrf_id = VRF_DEFAULT;
d62a17ae 1176 nexthop->type = gtype;
1177 switch (nexthop->type) {
1178 case NEXTHOP_TYPE_IPV4:
1179 case NEXTHOP_TYPE_IPV4_IFINDEX:
1180 nexthop->gate.ipv4 = gate->ipv4;
1181 if (ifindex)
1182 nexthop->ifindex = ifindex;
1183 break;
1184 case NEXTHOP_TYPE_IPV6:
1185 case NEXTHOP_TYPE_IPV6_IFINDEX:
1186 nexthop->gate.ipv6 = gate->ipv6;
1187 if (ifindex)
1188 nexthop->ifindex = ifindex;
1189 break;
b9abd9ad
DS
1190 case NEXTHOP_TYPE_IFINDEX:
1191 nexthop->ifindex = ifindex;
1192 break;
d62a17ae 1193 default:
1194 nexthop_free(nexthop);
1195 XFREE(MTYPE_NHLFE, nhlfe);
1196 return NULL;
1197 break;
1198 }
1199
1200 nhlfe->nexthop = nexthop;
1201 if (lsp->nhlfe_list)
1202 lsp->nhlfe_list->prev = nhlfe;
1203 nhlfe->next = lsp->nhlfe_list;
1204 lsp->nhlfe_list = nhlfe;
1205
1206 return nhlfe;
40c7bdb0 1207}
1208
1209/*
1210 * Delete NHLFE. Entry must be present on list.
1211 */
d62a17ae 1212static int nhlfe_del(zebra_nhlfe_t *nhlfe)
40c7bdb0 1213{
d62a17ae 1214 zebra_lsp_t *lsp;
40c7bdb0 1215
d62a17ae 1216 if (!nhlfe)
1217 return -1;
40c7bdb0 1218
d62a17ae 1219 lsp = nhlfe->lsp;
1220 if (!lsp)
1221 return -1;
40c7bdb0 1222
d62a17ae 1223 /* Free nexthop. */
1224 if (nhlfe->nexthop)
1225 nexthop_free(nhlfe->nexthop);
40c7bdb0 1226
d62a17ae 1227 /* Unlink from LSP */
1228 if (nhlfe->next)
1229 nhlfe->next->prev = nhlfe->prev;
1230 if (nhlfe->prev)
1231 nhlfe->prev->next = nhlfe->next;
1232 else
1233 lsp->nhlfe_list = nhlfe->next;
40c7bdb0 1234
d62a17ae 1235 if (nhlfe == lsp->best_nhlfe)
1236 lsp->best_nhlfe = NULL;
bb49a121 1237
d62a17ae 1238 XFREE(MTYPE_NHLFE, nhlfe);
40c7bdb0 1239
d62a17ae 1240 return 0;
40c7bdb0 1241}
1242
a64448ba
DS
1243/*
1244 * Update label for NHLFE entry.
1245 */
d62a17ae 1246static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
8ecdb26e 1247 struct mpls_label_stack *nh_label)
d62a17ae 1248{
1249 nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
1250}
1251
1252static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp,
1253 enum lsp_types_t type)
1254{
1255 zebra_nhlfe_t *nhlfe, *nhlfe_next;
1256 int schedule_lsp = 0;
1257 char buf[BUFSIZ];
1258
1259 /* Mark NHLFEs for delete or directly delete, as appropriate. */
1260 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) {
1261 nhlfe_next = nhlfe->next;
1262
1263 /* Skip non-static NHLFEs */
1264 if (nhlfe->type != type)
1265 continue;
1266
1267 if (IS_ZEBRA_DEBUG_MPLS) {
1268 nhlfe2str(nhlfe, buf, BUFSIZ);
1269 zlog_debug(
1270 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
1271 lsp->ile.in_label, type, buf, nhlfe->flags);
1272 }
1273
1274 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1275 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1276 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1277 schedule_lsp = 1;
1278 } else {
1279 nhlfe_del(nhlfe);
1280 }
1281 }
1282
1283 /* Queue LSP for processing, if needed, else delete. */
1284 if (schedule_lsp) {
1285 if (lsp_processq_add(lsp))
1286 return -1;
1287 } else if (!lsp->nhlfe_list
1288 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
1289 if (IS_ZEBRA_DEBUG_MPLS)
1290 zlog_debug("Free LSP in-label %u flags 0x%x",
1291 lsp->ile.in_label, lsp->flags);
1292
1293 lsp = hash_release(lsp_table, &lsp->ile);
1294 if (lsp)
1295 XFREE(MTYPE_LSP, lsp);
1296 }
1297
1298 return 0;
40c7bdb0 1299}
1300
ce549947
RW
1301/*
1302 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
1303 * If no other NHLFEs exist, the entry would be deleted.
1304 */
d62a17ae 1305static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
1306 mpls_label_t in_label)
ce549947 1307{
d62a17ae 1308 struct hash *lsp_table;
1309 zebra_ile_t tmp_ile;
1310 zebra_lsp_t *lsp;
ce549947 1311
d62a17ae 1312 /* Lookup table. */
1313 lsp_table = zvrf->lsp_table;
1314 if (!lsp_table)
1315 return -1;
ce549947 1316
d62a17ae 1317 /* If entry is not present, exit. */
1318 tmp_ile.in_label = in_label;
1319 lsp = hash_lookup(lsp_table, &tmp_ile);
1320 if (!lsp || !lsp->nhlfe_list)
1321 return 0;
ce549947 1322
d62a17ae 1323 return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC);
ce549947
RW
1324}
1325
d62a17ae 1326static json_object *nhlfe_json(zebra_nhlfe_t *nhlfe)
b78b820d 1327{
d62a17ae 1328 char buf[BUFSIZ];
1329 json_object *json_nhlfe = NULL;
1330 struct nexthop *nexthop = nhlfe->nexthop;
b78b820d 1331
d62a17ae 1332 json_nhlfe = json_object_new_object();
1333 json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
1334 json_object_int_add(json_nhlfe, "outLabel",
1335 nexthop->nh_label->label[0]);
1336 json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
b78b820d 1337
d62a17ae 1338 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
1339 json_object_boolean_true_add(json_nhlfe, "installed");
b78b820d 1340
d62a17ae 1341 switch (nexthop->type) {
1342 case NEXTHOP_TYPE_IPV4:
1343 case NEXTHOP_TYPE_IPV4_IFINDEX:
1344 json_object_string_add(json_nhlfe, "nexthop",
1345 inet_ntoa(nexthop->gate.ipv4));
1346 break;
1347 case NEXTHOP_TYPE_IPV6:
1348 case NEXTHOP_TYPE_IPV6_IFINDEX:
1349 json_object_string_add(
1350 json_nhlfe, "nexthop",
1351 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1352
1353 if (nexthop->ifindex)
4a7371e9
DS
1354 json_object_string_add(json_nhlfe, "interface",
1355 ifindex2ifname(nexthop->ifindex,
1356 nexthop->vrf_id));
d62a17ae 1357 break;
1358 default:
1359 break;
1360 }
1361 return json_nhlfe;
b78b820d 1362}
1363
3ab18ff2 1364/*
1365 * Print the NHLFE for a LSP forwarding entry.
1366 */
d62a17ae 1367static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty)
1368{
1369 struct nexthop *nexthop;
1370 char buf[BUFSIZ];
1371
1372 nexthop = nhlfe->nexthop;
1373 if (!nexthop || !nexthop->nh_label) // unexpected
1374 return;
1375
1376 vty_out(vty, " type: %s remote label: %s distance: %d\n",
1377 nhlfe_type2str(nhlfe->type),
1378 label2str(nexthop->nh_label->label[0], buf, BUFSIZ),
1379 nhlfe->distance);
1380 switch (nexthop->type) {
1381 case NEXTHOP_TYPE_IPV4:
1382 case NEXTHOP_TYPE_IPV4_IFINDEX:
1383 vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
1384 if (nexthop->ifindex)
1385 vty_out(vty, " dev %s",
4a7371e9
DS
1386 ifindex2ifname(nexthop->ifindex,
1387 nexthop->vrf_id));
d62a17ae 1388 break;
1389 case NEXTHOP_TYPE_IPV6:
1390 case NEXTHOP_TYPE_IPV6_IFINDEX:
1391 vty_out(vty, " via %s",
1392 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1393 if (nexthop->ifindex)
1394 vty_out(vty, " dev %s",
4a7371e9
DS
1395 ifindex2ifname(nexthop->ifindex,
1396 nexthop->vrf_id));
d62a17ae 1397 break;
1398 default:
1399 break;
1400 }
996c9314
LB
1401 vty_out(vty, "%s",
1402 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
1403 : "");
d62a17ae 1404 vty_out(vty, "\n");
3ab18ff2 1405}
1406
1407/*
1408 * Print an LSP forwarding entry.
1409 */
d62a17ae 1410static void lsp_print(zebra_lsp_t *lsp, void *ctxt)
3ab18ff2 1411{
d62a17ae 1412 zebra_nhlfe_t *nhlfe;
1413 struct vty *vty;
3ab18ff2 1414
d62a17ae 1415 vty = (struct vty *)ctxt;
3ab18ff2 1416
d62a17ae 1417 vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label,
1418 CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)"
1419 : "");
3ab18ff2 1420
d62a17ae 1421 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1422 nhlfe_print(nhlfe, vty);
3ab18ff2 1423}
1424
1425/*
b78b820d 1426 * JSON objects for an LSP forwarding entry.
3ab18ff2 1427 */
d62a17ae 1428static json_object *lsp_json(zebra_lsp_t *lsp)
3ab18ff2 1429{
d62a17ae 1430 zebra_nhlfe_t *nhlfe = NULL;
1431 json_object *json = json_object_new_object();
1432 json_object *json_nhlfe_list = json_object_new_array();
3ab18ff2 1433
d62a17ae 1434 json_object_int_add(json, "inLabel", lsp->ile.in_label);
b78b820d 1435
d62a17ae 1436 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1437 json_object_boolean_true_add(json, "installed");
3ab18ff2 1438
d62a17ae 1439 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1440 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
b78b820d 1441
d62a17ae 1442 json_object_object_add(json, "nexthops", json_nhlfe_list);
1443 return json;
b78b820d 1444}
1445
1446
1447/* Return a sorted linked list of the hash contents */
d62a17ae 1448static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
b78b820d 1449{
d62a17ae 1450 unsigned int i;
1451 struct hash_backet *hb;
1452 struct list *sorted_list = list_new();
b78b820d 1453
d62a17ae 1454 sorted_list->cmp = (int (*)(void *, void *))cmp;
b78b820d 1455
d62a17ae 1456 for (i = 0; i < hash->size; i++)
1457 for (hb = hash->index[i]; hb; hb = hb->next)
1458 listnode_add_sort(sorted_list, hb->data);
b78b820d 1459
d62a17ae 1460 return sorted_list;
3ab18ff2 1461}
1462
7758e3f3 1463/*
b78b820d 1464 * Compare two LSPs based on their label values.
7758e3f3 1465 */
d62a17ae 1466static int lsp_cmp(zebra_lsp_t *lsp1, zebra_lsp_t *lsp2)
7758e3f3 1467{
d62a17ae 1468 if (lsp1->ile.in_label < lsp2->ile.in_label)
1469 return -1;
7758e3f3 1470
d62a17ae 1471 if (lsp1->ile.in_label > lsp2->ile.in_label)
1472 return 1;
7758e3f3 1473
d62a17ae 1474 return 0;
7758e3f3 1475}
1476
1477/*
1478 * Callback to allocate static LSP.
1479 */
d62a17ae 1480static void *slsp_alloc(void *p)
7758e3f3 1481{
d62a17ae 1482 const zebra_ile_t *ile = p;
1483 zebra_slsp_t *slsp;
7758e3f3 1484
d62a17ae 1485 slsp = XCALLOC(MTYPE_SLSP, sizeof(zebra_slsp_t));
1486 slsp->ile = *ile;
1487 return ((void *)slsp);
7758e3f3 1488}
1489
b78b820d 1490/*
1491 * Compare two static LSPs based on their label values.
1492 */
d62a17ae 1493static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
b78b820d 1494{
d62a17ae 1495 if (slsp1->ile.in_label < slsp2->ile.in_label)
1496 return -1;
b78b820d 1497
d62a17ae 1498 if (slsp1->ile.in_label > slsp2->ile.in_label)
1499 return 1;
b78b820d 1500
d62a17ae 1501 return 0;
b78b820d 1502}
1503
7758e3f3 1504/*
1505 * Check if static NHLFE matches with search info passed.
1506 */
d62a17ae 1507static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
1508 union g_addr *gate, ifindex_t ifindex)
7758e3f3 1509{
d62a17ae 1510 int cmp = 1;
7758e3f3 1511
d62a17ae 1512 if (snhlfe->gtype != gtype)
1513 return 1;
7758e3f3 1514
d62a17ae 1515 switch (snhlfe->gtype) {
1516 case NEXTHOP_TYPE_IPV4:
1517 cmp = memcmp(&(snhlfe->gate.ipv4), &(gate->ipv4),
1518 sizeof(struct in_addr));
1519 break;
1520 case NEXTHOP_TYPE_IPV6:
1521 case NEXTHOP_TYPE_IPV6_IFINDEX:
1522 cmp = memcmp(&(snhlfe->gate.ipv6), &(gate->ipv6),
1523 sizeof(struct in6_addr));
1524 if (!cmp && snhlfe->gtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1525 cmp = !(snhlfe->ifindex == ifindex);
1526 break;
1527 default:
1528 break;
1529 }
7758e3f3 1530
d62a17ae 1531 return cmp;
7758e3f3 1532}
1533
1534/*
1535 * Locate static NHLFE that matches with passed info.
1536 */
d62a17ae 1537static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
1538 enum nexthop_types_t gtype,
1539 union g_addr *gate, ifindex_t ifindex)
7758e3f3 1540{
d62a17ae 1541 zebra_snhlfe_t *snhlfe;
7758e3f3 1542
d62a17ae 1543 if (!slsp)
1544 return NULL;
7758e3f3 1545
d62a17ae 1546 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next) {
1547 if (!snhlfe_match(snhlfe, gtype, gate, ifindex))
1548 break;
1549 }
7758e3f3 1550
d62a17ae 1551 return snhlfe;
7758e3f3 1552}
1553
1554
1555/*
1556 * Add static NHLFE. Base LSP config entry must have been created
1557 * and duplicate check done.
1558 */
d62a17ae 1559static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
1560 enum nexthop_types_t gtype,
1561 union g_addr *gate, ifindex_t ifindex,
1562 mpls_label_t out_label)
1563{
1564 zebra_snhlfe_t *snhlfe;
1565
1566 if (!slsp)
1567 return NULL;
1568
1569 snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t));
1570 snhlfe->slsp = slsp;
1571 snhlfe->out_label = out_label;
1572 snhlfe->gtype = gtype;
1573 switch (gtype) {
1574 case NEXTHOP_TYPE_IPV4:
1575 snhlfe->gate.ipv4 = gate->ipv4;
1576 break;
1577 case NEXTHOP_TYPE_IPV6:
1578 case NEXTHOP_TYPE_IPV6_IFINDEX:
1579 snhlfe->gate.ipv6 = gate->ipv6;
1580 if (ifindex)
1581 snhlfe->ifindex = ifindex;
1582 break;
1583 default:
1584 XFREE(MTYPE_SNHLFE, snhlfe);
1585 return NULL;
1586 }
1587
1588 if (slsp->snhlfe_list)
1589 slsp->snhlfe_list->prev = snhlfe;
1590 snhlfe->next = slsp->snhlfe_list;
1591 slsp->snhlfe_list = snhlfe;
1592
1593 return snhlfe;
7758e3f3 1594}
1595
1596/*
1597 * Delete static NHLFE. Entry must be present on list.
1598 */
d62a17ae 1599static int snhlfe_del(zebra_snhlfe_t *snhlfe)
7758e3f3 1600{
d62a17ae 1601 zebra_slsp_t *slsp;
7758e3f3 1602
d62a17ae 1603 if (!snhlfe)
1604 return -1;
7758e3f3 1605
d62a17ae 1606 slsp = snhlfe->slsp;
1607 if (!slsp)
1608 return -1;
7758e3f3 1609
d62a17ae 1610 if (snhlfe->next)
1611 snhlfe->next->prev = snhlfe->prev;
1612 if (snhlfe->prev)
1613 snhlfe->prev->next = snhlfe->next;
1614 else
1615 slsp->snhlfe_list = snhlfe->next;
7758e3f3 1616
d62a17ae 1617 snhlfe->prev = snhlfe->next = NULL;
1618 if (snhlfe->ifname)
1619 XFREE(MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
1620 XFREE(MTYPE_SNHLFE, snhlfe);
7758e3f3 1621
d62a17ae 1622 return 0;
7758e3f3 1623}
1624
1625/*
1626 * Delete all static NHLFE entries for this LSP (in label).
1627 */
d62a17ae 1628static int snhlfe_del_all(zebra_slsp_t *slsp)
7758e3f3 1629{
d62a17ae 1630 zebra_snhlfe_t *snhlfe, *snhlfe_next;
7758e3f3 1631
d62a17ae 1632 if (!slsp)
1633 return -1;
7758e3f3 1634
d62a17ae 1635 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next) {
1636 snhlfe_next = snhlfe->next;
1637 snhlfe_del(snhlfe);
1638 }
7758e3f3 1639
d62a17ae 1640 return 0;
7758e3f3 1641}
1642
1643/*
1644 * Create printable string for NHLFE configuration.
1645 */
d62a17ae 1646static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size)
7758e3f3 1647{
d62a17ae 1648 buf[0] = '\0';
1649 switch (snhlfe->gtype) {
1650 case NEXTHOP_TYPE_IPV4:
1651 inet_ntop(AF_INET, &snhlfe->gate.ipv4, buf, size);
1652 break;
1653 case NEXTHOP_TYPE_IPV6:
1654 case NEXTHOP_TYPE_IPV6_IFINDEX:
1655 inet_ntop(AF_INET6, &snhlfe->gate.ipv6, buf, size);
1656 if (snhlfe->ifindex)
1657 strcat(buf,
1658 ifindex2ifname(snhlfe->ifindex, VRF_DEFAULT));
1659 break;
1660 default:
1661 break;
1662 }
7758e3f3 1663
d62a17ae 1664 return buf;
7758e3f3 1665}
1666
40c7bdb0 1667/*
1668 * Initialize work queue for processing changed LSPs.
1669 */
d62a17ae 1670static int mpls_processq_init(struct zebra_t *zebra)
40c7bdb0 1671{
d62a17ae 1672 zebra->lsp_process_q = work_queue_new(zebra->master, "LSP processing");
1673 if (!zebra->lsp_process_q) {
1674 zlog_err("%s: could not initialise work queue!", __func__);
1675 return -1;
1676 }
40c7bdb0 1677
d62a17ae 1678 zebra->lsp_process_q->spec.workfunc = &lsp_process;
1679 zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del;
1680 zebra->lsp_process_q->spec.errorfunc = NULL;
1681 zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete;
1682 zebra->lsp_process_q->spec.max_retries = 0;
1683 zebra->lsp_process_q->spec.hold = 10;
33c32282 1684
d62a17ae 1685 return 0;
40c7bdb0 1686}
1687
7758e3f3 1688
7758e3f3 1689/* Public functions */
1690
996c9314 1691void kernel_lsp_pass_fail(zebra_lsp_t *lsp, enum southbound_results res)
4a83e7a0
DS
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 */
70e98a7f 1824 if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
d62a17ae 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
70e98a7f
DS
2568 == MPLS_LABEL_IMPLICIT_NULL);
2569 new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
d62a17ae 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) {
996c9314 2795 case NEXTHOP_TYPE_IFINDEX: {
b9abd9ad
DS
2796 struct interface *ifp;
2797
2798 ifp = if_lookup_by_index(
2799 nexthop->ifindex, VRF_UNKNOWN);
2800 vty_out(vty, "%15s", ifp->name);
2801 break;
2802 }
d62a17ae 2803 case NEXTHOP_TYPE_IPV4:
2804 case NEXTHOP_TYPE_IPV4_IFINDEX:
2805 vty_out(vty, "%15s",
2806 inet_ntoa(nexthop->gate.ipv4));
2807 break;
2808 case NEXTHOP_TYPE_IPV6:
2809 case NEXTHOP_TYPE_IPV6_IFINDEX:
2810 vty_out(vty, "%15s",
2811 inet_ntop(AF_INET6,
2812 &nexthop->gate.ipv6,
2813 buf, BUFSIZ));
2814 break;
2815 default:
2816 break;
2817 }
2818
b9abd9ad 2819 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
fc5cca9f
DS
2820 vty_out(vty, " %8s\n",
2821 mpls_label2str(
2822 nexthop->nh_label
2823 ->num_labels,
2824 &nexthop->nh_label
2825 ->label[0],
2826 buf, BUFSIZ, 1));
b9abd9ad
DS
2827 else
2828 vty_out(vty, "\n");
d62a17ae 2829 }
2830 }
2831
2832 vty_out(vty, "\n");
2833 }
2834
affe9e99 2835 list_delete_and_null(&lsp_list);
3ab18ff2 2836}
2837
7758e3f3 2838/*
2839 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
2840 */
d62a17ae 2841int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
2842{
2843 zebra_slsp_t *slsp;
2844 zebra_snhlfe_t *snhlfe;
2845 struct listnode *node;
2846 struct list *slsp_list =
2847 hash_get_sorted_list(zvrf->slsp_table, slsp_cmp);
2848
2849 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) {
2850 for (snhlfe = slsp->snhlfe_list; snhlfe;
2851 snhlfe = snhlfe->next) {
0af35d90 2852 char buf[BUFSIZ];
d62a17ae 2853 char lstr[30];
2854
0af35d90 2855 snhlfe2str(snhlfe, buf, sizeof(buf));
d62a17ae 2856 switch (snhlfe->out_label) {
70e98a7f
DS
2857 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
2858 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
d62a17ae 2859 strlcpy(lstr, "explicit-null", sizeof(lstr));
2860 break;
70e98a7f 2861 case MPLS_LABEL_IMPLICIT_NULL:
d62a17ae 2862 strlcpy(lstr, "implicit-null", sizeof(lstr));
2863 break;
2864 default:
2865 sprintf(lstr, "%u", snhlfe->out_label);
2866 break;
2867 }
2868
2869 vty_out(vty, "mpls lsp %u %s %s\n", slsp->ile.in_label,
2870 buf, lstr);
2871 }
2872 }
b78b820d 2873
affe9e99 2874 list_delete_and_null(&slsp_list);
d62a17ae 2875 return (zvrf->slsp_table->count ? 1 : 0);
7758e3f3 2876}
2877
1b6d5c7e
VV
2878/*
2879 * Add/update global label block.
2880 */
d62a17ae 2881int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, u_int32_t start_label,
2882 u_int32_t end_label)
1b6d5c7e 2883{
d62a17ae 2884 zvrf->mpls_srgb.start_label = start_label;
2885 zvrf->mpls_srgb.end_label = end_label;
28d58fd7 2886
d62a17ae 2887 /* Evaluate registered FECs to see if any get a label or not. */
2888 fec_evaluate(zvrf);
2889 return 0;
1b6d5c7e
VV
2890}
2891
2892/*
2893 * Delete global label block.
2894 */
d62a17ae 2895int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
1b6d5c7e 2896{
d62a17ae 2897 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
2898 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
28d58fd7 2899
d62a17ae 2900 /* Process registered FECs to clear their local label, if needed. */
2901 fec_evaluate(zvrf);
2902 return 0;
1b6d5c7e
VV
2903}
2904
2905/*
2906 * Display MPLS global label block configuration (VTY command handler).
2907 */
d62a17ae 2908int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
1b6d5c7e 2909{
d62a17ae 2910 if (zvrf->mpls_srgb.start_label == 0)
2911 return 0;
1b6d5c7e 2912
d62a17ae 2913 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
2914 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
2915 vty_out(vty, "mpls label global-block %u %u\n",
2916 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
2917 }
1b6d5c7e 2918
d62a17ae 2919 return 1;
1b6d5c7e
VV
2920}
2921
84915b0a 2922/*
2923 * Called when VRF becomes inactive, cleans up information but keeps
2924 * the table itself.
2925 * NOTE: Currently supported only for default VRF.
2926 */
2927void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
2928{
2929 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
2930}
2931
40c7bdb0 2932/*
2933 * Called upon process exiting, need to delete LSP forwarding
2934 * entries from the kernel.
2935 * NOTE: Currently supported only for default VRF.
2936 */
d62a17ae 2937void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
40c7bdb0 2938{
d62a17ae 2939 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
2940 hash_clean(zvrf->lsp_table, NULL);
2941 hash_free(zvrf->lsp_table);
2942 hash_clean(zvrf->slsp_table, NULL);
2943 hash_free(zvrf->slsp_table);
9b67b514
DS
2944 route_table_finish(zvrf->fec_table[AFI_IP]);
2945 route_table_finish(zvrf->fec_table[AFI_IP6]);
40c7bdb0 2946}
2947
7758e3f3 2948/*
2949 * Allocate MPLS tables for this VRF and do other initialization.
2950 * NOTE: Currently supported only for default VRF.
2951 */
d62a17ae 2952void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
7758e3f3 2953{
d62a17ae 2954 if (!zvrf)
2955 return;
996c9314
LB
2956 zvrf->slsp_table =
2957 hash_create(label_hash, label_cmp, "ZEBRA SLSP table");
2958 zvrf->lsp_table = hash_create(label_hash, label_cmp, "ZEBRA LSP table");
d62a17ae 2959 zvrf->fec_table[AFI_IP] = route_table_init();
2960 zvrf->fec_table[AFI_IP6] = route_table_init();
2961 zvrf->mpls_flags = 0;
2962 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
2963 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
7758e3f3 2964}
2965
2966/*
2967 * Global MPLS initialization.
2968 */
d62a17ae 2969void zebra_mpls_init(void)
7758e3f3 2970{
d62a17ae 2971 mpls_enabled = 0;
33c32282 2972
d62a17ae 2973 if (mpls_kernel_init() < 0) {
2974 zlog_warn("Disabling MPLS support (no kernel support)");
2975 return;
2976 }
fe6c7157 2977
d62a17ae 2978 if (!mpls_processq_init(&zebrad))
2979 mpls_enabled = 1;
7758e3f3 2980}