]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_mpls.c
zebra: reorganize zserv, batch i/o
[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 */
7ee30f28 185 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
d62a17ae 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. */
1002497a 458 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
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));
1002497a 466 return zebra_server_send_message(client, s);
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
7ee30f28 639 for (match_nh = match->ng.nexthop; match_nh;
d62a17ae 640 match_nh = match_nh->next) {
641 if (match->type == ZEBRA_ROUTE_CONNECT
642 || nexthop->ifindex == match_nh->ifindex) {
643 nexthop->ifindex = match_nh->ifindex;
644 return 1;
645 }
646 }
88d88a9c 647 }
40c7bdb0 648
d62a17ae 649 return 0;
40c7bdb0 650}
651
652
653/*
654 * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
655 * the passed flag.
656 * NOTE: Looking only for connected routes right now.
657 */
d62a17ae 658static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe,
659 struct nexthop *nexthop)
40c7bdb0 660{
d62a17ae 661 struct route_table *table;
662 struct prefix_ipv6 p;
663 struct route_node *rn;
664 struct route_entry *match;
40c7bdb0 665
4a7371e9 666 table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
d62a17ae 667 if (!table)
668 return 0;
40c7bdb0 669
d62a17ae 670 /* Lookup nexthop in IPv6 routing table. */
671 memset(&p, 0, sizeof(struct prefix_ipv6));
672 p.family = AF_INET6;
673 p.prefixlen = IPV6_MAX_PREFIXLEN;
674 p.prefix = nexthop->gate.ipv6;
40c7bdb0 675
d62a17ae 676 rn = route_node_match(table, (struct prefix *)&p);
677 if (!rn)
678 return 0;
40c7bdb0 679
d62a17ae 680 route_unlock_node(rn);
40c7bdb0 681
d62a17ae 682 /* Locate a valid connected route. */
a2addae8 683 RNODE_FOREACH_RE (rn, match) {
d62a17ae 684 if ((match->type == ZEBRA_ROUTE_CONNECT)
685 && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
686 && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
687 break;
688 }
40c7bdb0 689
7ee30f28 690 if (!match || !match->ng.nexthop)
d62a17ae 691 return 0;
40c7bdb0 692
7ee30f28 693 nexthop->ifindex = match->ng.nexthop->ifindex;
d62a17ae 694 return 1;
40c7bdb0 695}
696
697
698/*
699 * Check the nexthop reachability for a NHLFE and return if valid (reachable)
700 * or not.
701 * NOTE: Each NHLFE points to only 1 nexthop.
702 */
d62a17ae 703static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe)
704{
705 struct nexthop *nexthop;
706 struct interface *ifp;
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 */
996c9314
LB
939 for (nhlfe = lsp->nhlfe_list; nhlfe;
940 nhlfe = nhlfe->next) {
9fa38ec6
DS
941 nexthop = nhlfe->nexthop;
942 if (!nexthop)
943 continue;
944
945 if (CHECK_FLAG(nhlfe->flags,
996c9314
LB
946 NHLFE_FLAG_INSTALLED)
947 && !CHECK_FLAG(nhlfe->flags,
948 NHLFE_FLAG_SELECTED)) {
9fa38ec6
DS
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 }
996c9314
LB
1400 vty_out(vty, "%s",
1401 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (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
996c9314 1690void kernel_lsp_pass_fail(zebra_lsp_t *lsp, enum southbound_results res)
4a83e7a0
DS
1691{
1692 struct nexthop *nexthop;
1693 zebra_nhlfe_t *nhlfe;
1694
1695 if (!lsp)
1696 return;
1697
1698 switch (res) {
1699 case SOUTHBOUND_INSTALL_FAILURE:
1700 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1701 clear_nhlfe_installed(lsp);
1702 zlog_warn("LSP Install Failure: %u", lsp->ile.in_label);
1703 break;
1704 case SOUTHBOUND_INSTALL_SUCCESS:
1705 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1706 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1707 nexthop = nhlfe->nexthop;
1708 if (!nexthop)
1709 continue;
1710
1711 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1712 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1713 }
1714 break;
1715 case SOUTHBOUND_DELETE_SUCCESS:
1716 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1717 clear_nhlfe_installed(lsp);
1718 break;
1719 case SOUTHBOUND_DELETE_FAILURE:
1720 zlog_warn("LSP Deletion Failure: %u", lsp->ile.in_label);
1721 break;
1722 }
1723}
1724
a22f3f5d 1725/*
1726 * String to label conversion, labels separated by '/'.
8062bf1c
QY
1727 *
1728 * @param label_str labels separated by /
1729 * @param num_labels number of labels; zero if conversion was unsuccessful
1730 * @param labels preallocated mpls_label_t array of size MPLS_MAX_LABELS; only
1731 * modified if the conversion succeeded
1732 * @return 0 on success
1733 * -1 if the string could not be parsed as integers
1734 * -2 if a label was inside the reserved range (0-15)
1735 * -3 if the number of labels given exceeds MPLS_MAX_LABELS
a22f3f5d 1736 */
d62a17ae 1737int mpls_str2label(const char *label_str, u_int8_t *num_labels,
1738 mpls_label_t *labels)
1739{
1740 char *ostr; // copy of label string (start)
1741 char *lstr; // copy of label string
1742 char *nump; // pointer to next segment
1743 char *endp; // end pointer
1744 int i; // for iterating label_str
1745 int rc; // return code
1746 mpls_label_t pl[MPLS_MAX_LABELS]; // parsed labels
1747
1748 /* labels to zero until we have a successful parse */
1749 ostr = lstr = XSTRDUP(MTYPE_TMP, label_str);
1750 *num_labels = 0;
1751 rc = 0;
1752
1753 for (i = 0; i < MPLS_MAX_LABELS && lstr && !rc; i++) {
1754 nump = strsep(&lstr, "/");
1755 pl[i] = strtoul(nump, &endp, 10);
1756
1757 /* format check */
1758 if (*endp != '\0')
1759 rc = -1;
1760 /* validity check */
1761 else if (!IS_MPLS_UNRESERVED_LABEL(pl[i]))
1762 rc = -2;
1763 }
a22f3f5d 1764
d62a17ae 1765 /* excess labels */
1766 if (!rc && i == MPLS_MAX_LABELS && lstr)
1767 rc = -3;
a22f3f5d 1768
d62a17ae 1769 if (!rc) {
1770 *num_labels = i;
1771 memcpy(labels, pl, *num_labels * sizeof(mpls_label_t));
1772 }
a22f3f5d 1773
d62a17ae 1774 XFREE(MTYPE_TMP, ostr);
8062bf1c 1775
d62a17ae 1776 return rc;
a22f3f5d 1777}
1778
1779/*
1780 * Label to string conversion, labels in string separated by '/'.
1781 */
d62a17ae 1782char *mpls_label2str(u_int8_t num_labels, mpls_label_t *labels, char *buf,
1783 int len, int pretty)
1784{
5e8c8947
RW
1785 char label_buf[BUFSIZ];
1786 int i;
d62a17ae 1787
5e8c8947
RW
1788 buf[0] = '\0';
1789 for (i = 0; i < num_labels; i++) {
1790 if (i != 0)
1791 strlcat(buf, "/", len);
1792 if (pretty)
1793 label2str(labels[i], label_buf, sizeof(label_buf));
1794 else
1795 snprintf(label_buf, sizeof(label_buf), "%u", labels[i]);
1796 strlcat(buf, label_buf, len);
d62a17ae 1797 }
5e8c8947 1798
d62a17ae 1799 return buf;
a22f3f5d 1800}
1801
a64448ba
DS
1802/*
1803 * Install dynamic LSP entry.
1804 */
d62a17ae 1805int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
1806 struct route_entry *re)
a64448ba 1807{
d62a17ae 1808 struct route_table *table;
1809 zebra_fec_t *fec;
a64448ba 1810
d62a17ae 1811 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
1812 if (!table)
1813 return -1;
a64448ba 1814
d62a17ae 1815 /* See if there is a configured label binding for this FEC. */
1816 fec = fec_find(table, &rn->p);
1817 if (!fec || fec->label == MPLS_INVALID_LABEL)
1818 return 0;
a64448ba 1819
d62a17ae 1820 /* We cannot install a label forwarding entry if local label is the
1821 * implicit-null label.
1822 */
70e98a7f 1823 if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
d62a17ae 1824 return 0;
a64448ba 1825
d62a17ae 1826 if (lsp_install(zvrf, fec->label, rn, re))
1827 return -1;
a64448ba 1828
d62a17ae 1829 return 0;
a64448ba
DS
1830}
1831
1832/*
1833 * Uninstall dynamic LSP entry, if any.
1834 */
d62a17ae 1835int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
1836 struct route_entry *re)
a64448ba 1837{
d62a17ae 1838 struct route_table *table;
1839 zebra_fec_t *fec;
a64448ba 1840
d62a17ae 1841 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
1842 if (!table)
1843 return -1;
a64448ba 1844
d62a17ae 1845 /* See if there is a configured label binding for this FEC. */
1846 fec = fec_find(table, &rn->p);
1847 if (!fec || fec->label == MPLS_INVALID_LABEL)
1848 return 0;
a64448ba 1849
d62a17ae 1850 /* Uninstall always removes all dynamic NHLFEs. */
1851 return lsp_uninstall(zvrf, fec->label);
a64448ba
DS
1852}
1853
5aba114a
DS
1854/*
1855 * Registration from a client for the label binding for a FEC. If a binding
1856 * already exists, it is informed to the client.
28d58fd7 1857 * NOTE: If there is a manually configured label binding, that is used.
9bedbb1e 1858 * Otherwise, if a label index is specified, it means we have to allocate the
28d58fd7
VV
1859 * label from a locally configured label block (SRGB), if one exists and index
1860 * is acceptable.
5aba114a 1861 */
d62a17ae 1862int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
1863 u_int32_t label_index, struct zserv *client)
1864{
1865 struct route_table *table;
1866 zebra_fec_t *fec;
1867 char buf[BUFSIZ];
1868 int new_client;
1869 int label_change = 0;
1870 u_int32_t old_label;
1871
1872 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
1873 if (!table)
1874 return -1;
1875
1876 if (IS_ZEBRA_DEBUG_MPLS)
1877 prefix2str(p, buf, BUFSIZ);
1878
1879 /* Locate FEC */
1880 fec = fec_find(table, p);
1881 if (!fec) {
1882 fec = fec_add(table, p, MPLS_INVALID_LABEL, 0, label_index);
1883 if (!fec) {
1884 prefix2str(p, buf, BUFSIZ);
1885 zlog_err(
1886 "Failed to add FEC %s upon register, client %s",
1887 buf, zebra_route_string(client->proto));
1888 return -1;
1889 }
1890
1891 old_label = MPLS_INVALID_LABEL;
1892 new_client = 1;
1893 } else {
1894 /* Client may register same FEC with different label index. */
1895 new_client =
1896 (listnode_lookup(fec->client_list, client) == NULL);
1897 if (!new_client && fec->label_index == label_index)
1898 /* Duplicate register */
1899 return 0;
1900
1901 /* Save current label, update label index */
1902 old_label = fec->label;
1903 fec->label_index = label_index;
1904 }
1905
1906 if (new_client)
1907 listnode_add(fec->client_list, client);
1908
1909 if (IS_ZEBRA_DEBUG_MPLS)
1910 zlog_debug("FEC %s Label Index %u %s by client %s", buf,
1911 label_index, new_client ? "registered" : "updated",
1912 zebra_route_string(client->proto));
1913
1914 /* If not a configured FEC, derive the local label (from label index)
1915 * or reset it.
1916 */
1917 if (!(fec->flags & FEC_FLAG_CONFIGURED)) {
1918 fec_derive_label_from_index(zvrf, fec);
1919
1920 /* If no label change, exit. */
1921 if (fec->label == old_label)
1922 return 0;
1923
1924 label_change = 1;
1925 }
1926
1927 /* If new client or label change, update client and install or uninstall
1928 * label forwarding entry as needed.
1929 */
1930 /* Inform client of label, if needed. */
1931 if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
1932 if (IS_ZEBRA_DEBUG_MPLS)
1933 zlog_debug("Update client label %u", fec->label);
1934 fec_send(fec, client);
1935 }
1936
1937 if (new_client || label_change)
1938 return fec_change_update_lsp(zvrf, fec, old_label);
1939
1940 return 0;
5aba114a
DS
1941}
1942
1943/*
1944 * Deregistration from a client for the label binding for a FEC. The FEC
1945 * itself is deleted if no other registered clients exist and there is no
1946 * label bound to the FEC.
1947 */
d62a17ae 1948int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
1949 struct zserv *client)
5aba114a 1950{
d62a17ae 1951 struct route_table *table;
1952 zebra_fec_t *fec;
1953 char buf[BUFSIZ];
5aba114a 1954
d62a17ae 1955 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
1956 if (!table)
1957 return -1;
5aba114a 1958
d62a17ae 1959 if (IS_ZEBRA_DEBUG_MPLS)
1960 prefix2str(p, buf, BUFSIZ);
5aba114a 1961
d62a17ae 1962 fec = fec_find(table, p);
1963 if (!fec) {
1964 prefix2str(p, buf, BUFSIZ);
1965 zlog_err("Failed to find FEC %s upon unregister, client %s",
1966 buf, zebra_route_string(client->proto));
1967 return -1;
1968 }
5aba114a 1969
d62a17ae 1970 listnode_delete(fec->client_list, client);
1971
1972 if (IS_ZEBRA_DEBUG_MPLS)
1973 zlog_debug("FEC %s unregistered by client %s", buf,
1974 zebra_route_string(client->proto));
1975
1976 /* If not a configured entry, delete the FEC if no other clients. Before
1977 * deleting, see if any LSP needs to be uninstalled.
1978 */
1979 if (!(fec->flags & FEC_FLAG_CONFIGURED)
1980 && list_isempty(fec->client_list)) {
1981 mpls_label_t old_label = fec->label;
1982 fec->label = MPLS_INVALID_LABEL; /* reset */
1983 fec_change_update_lsp(zvrf, fec, old_label);
1984 fec_del(fec);
1985 }
5aba114a 1986
d62a17ae 1987 return 0;
5aba114a
DS
1988}
1989
1990/*
1991 * Cleanup any FECs registered by this client.
1992 */
d62a17ae 1993int zebra_mpls_cleanup_fecs_for_client(struct zebra_vrf *zvrf,
1994 struct zserv *client)
1995{
1996 struct route_node *rn;
1997 zebra_fec_t *fec;
1998 struct listnode *node;
1999 struct zserv *fec_client;
2000 int af;
2001
2002 for (af = AFI_IP; af < AFI_MAX; af++) {
2003 if (zvrf->fec_table[af] == NULL)
2004 continue;
2005
2006 for (rn = route_top(zvrf->fec_table[af]); rn;
2007 rn = route_next(rn)) {
2008 fec = rn->info;
2009 if (!fec || list_isempty(fec->client_list))
2010 continue;
2011
2012 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
2013 fec_client)) {
2014 if (fec_client == client) {
2015 listnode_delete(fec->client_list,
2016 fec_client);
2017 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2018 && list_isempty(fec->client_list))
2019 fec_del(fec);
2020 break;
2021 }
2022 }
2023 }
2024 }
5aba114a 2025
d62a17ae 2026 return 0;
5aba114a
DS
2027}
2028
f31e084c
DS
2029/*
2030 * Return FEC (if any) to which this label is bound.
2031 * Note: Only works for per-prefix binding and when the label is not
2032 * implicit-null.
2033 * TODO: Currently walks entire table, can optimize later with another
2034 * hash..
2035 */
d62a17ae 2036zebra_fec_t *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
2037 mpls_label_t label)
2038{
2039 struct route_node *rn;
2040 zebra_fec_t *fec;
2041 int af;
2042
2043 for (af = AFI_IP; af < AFI_MAX; af++) {
2044 if (zvrf->fec_table[af] == NULL)
2045 continue;
2046
2047 for (rn = route_top(zvrf->fec_table[af]); rn;
2048 rn = route_next(rn)) {
2049 if (!rn->info)
2050 continue;
2051 fec = rn->info;
2052 if (fec->label == label)
2053 return fec;
2054 }
2055 }
f31e084c 2056
d62a17ae 2057 return NULL;
f31e084c
DS
2058}
2059
2060/*
2061 * Inform if specified label is currently bound to a FEC or not.
2062 */
d62a17ae 2063int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
f31e084c 2064{
d62a17ae 2065 return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
f31e084c
DS
2066}
2067
2068/*
5aba114a 2069 * Add static FEC to label binding. If there are clients registered for this
a64448ba
DS
2070 * FEC, notify them. If there are labeled routes for this FEC, install the
2071 * label forwarding entry.
9d303b37 2072*/
d62a17ae 2073int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
2074 mpls_label_t in_label)
2075{
2076 struct route_table *table;
2077 zebra_fec_t *fec;
2078 char buf[BUFSIZ];
2079 mpls_label_t old_label;
2080 int ret = 0;
2081
2082 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2083 if (!table)
2084 return -1;
2085
2086 if (IS_ZEBRA_DEBUG_MPLS)
2087 prefix2str(p, buf, BUFSIZ);
2088
2089 /* Update existing FEC or create a new one. */
2090 fec = fec_find(table, p);
2091 if (!fec) {
2092 fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
2093 MPLS_INVALID_LABEL_INDEX);
2094 if (!fec) {
2095 prefix2str(p, buf, BUFSIZ);
2096 zlog_err("Failed to add FEC %s upon config", buf);
2097 return -1;
2098 }
2099
2100 if (IS_ZEBRA_DEBUG_MPLS)
2101 zlog_debug("Add fec %s label %u", buf, in_label);
2102 } else {
2103 fec->flags |= FEC_FLAG_CONFIGURED;
2104 if (fec->label == in_label)
2105 /* Duplicate config */
2106 return 0;
2107
2108 /* Label change, update clients. */
2109 old_label = fec->label;
2110 if (IS_ZEBRA_DEBUG_MPLS)
2111 zlog_debug("Update fec %s new label %u", buf, in_label);
2112
2113 fec->label = in_label;
2114 fec_update_clients(fec);
2115
2116 /* Update label forwarding entries appropriately */
2117 ret = fec_change_update_lsp(zvrf, fec, old_label);
2118 }
2119
2120 return ret;
f31e084c
DS
2121}
2122
2123/*
5aba114a
DS
2124 * Remove static FEC to label binding. If there are no clients registered
2125 * for this FEC, delete the FEC; else notify clients
28d58fd7
VV
2126 * Note: Upon delete of static binding, if label index exists for this FEC,
2127 * client may need to be updated with derived label.
f31e084c 2128 */
d62a17ae 2129int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
2130{
2131 struct route_table *table;
2132 zebra_fec_t *fec;
2133 mpls_label_t old_label;
2134 char buf[BUFSIZ];
2135
2136 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2137 if (!table)
2138 return -1;
2139
2140 fec = fec_find(table, p);
2141 if (!fec) {
2142 prefix2str(p, buf, BUFSIZ);
2143 zlog_err("Failed to find FEC %s upon delete", buf);
2144 return -1;
2145 }
2146
2147 if (IS_ZEBRA_DEBUG_MPLS) {
2148 prefix2str(p, buf, BUFSIZ);
2149 zlog_debug("Delete fec %s label index %u", buf,
2150 fec->label_index);
2151 }
2152
2153 old_label = fec->label;
2154 fec->flags &= ~FEC_FLAG_CONFIGURED;
2155 fec->label = MPLS_INVALID_LABEL;
2156
2157 /* If no client exists, just delete the FEC. */
2158 if (list_isempty(fec->client_list)) {
2159 fec_del(fec);
2160 return 0;
2161 }
2162
2163 /* Derive the local label (from label index) or reset it. */
2164 fec_derive_label_from_index(zvrf, fec);
2165
2166 /* If there is a label change, update clients. */
2167 if (fec->label == old_label)
2168 return 0;
2169 fec_update_clients(fec);
2170
2171 /* Update label forwarding entries appropriately */
2172 return fec_change_update_lsp(zvrf, fec, old_label);
f31e084c
DS
2173}
2174
2175/*
2176 * Display MPLS FEC to label binding configuration (VTY command handler).
2177 */
d62a17ae 2178int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
f31e084c 2179{
d62a17ae 2180 struct route_node *rn;
2181 int af;
2182 zebra_fec_t *fec;
2183 char buf[BUFSIZ];
2184 int write = 0;
f31e084c 2185
d62a17ae 2186 for (af = AFI_IP; af < AFI_MAX; af++) {
2187 if (zvrf->fec_table[af] == NULL)
2188 continue;
f31e084c 2189
d62a17ae 2190 for (rn = route_top(zvrf->fec_table[af]); rn;
2191 rn = route_next(rn)) {
2192 if (!rn->info)
2193 continue;
f31e084c 2194
d62a17ae 2195 char lstr[BUFSIZ];
2196 fec = rn->info;
f31e084c 2197
d62a17ae 2198 if (!(fec->flags & FEC_FLAG_CONFIGURED))
2199 continue;
f31e084c 2200
d62a17ae 2201 write = 1;
2202 prefix2str(&rn->p, buf, BUFSIZ);
2203 vty_out(vty, "mpls label bind %s %s\n", buf,
2204 label2str(fec->label, lstr, BUFSIZ));
2205 }
2206 }
f31e084c 2207
d62a17ae 2208 return write;
f31e084c
DS
2209}
2210
2211/*
2212 * Display MPLS FEC to label binding (VTY command handler).
2213 */
d62a17ae 2214void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
f31e084c 2215{
d62a17ae 2216 struct route_node *rn;
2217 int af;
f31e084c 2218
d62a17ae 2219 for (af = AFI_IP; af < AFI_MAX; af++) {
2220 if (zvrf->fec_table[af] == NULL)
2221 continue;
f31e084c 2222
d62a17ae 2223 for (rn = route_top(zvrf->fec_table[af]); rn;
2224 rn = route_next(rn)) {
2225 if (!rn->info)
2226 continue;
2227 fec_print(rn->info, vty);
2228 }
2229 }
f31e084c
DS
2230}
2231
2232/*
2233 * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2234 */
d62a17ae 2235void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
2236 struct prefix *p)
f31e084c 2237{
d62a17ae 2238 struct route_table *table;
2239 struct route_node *rn;
f31e084c 2240
d62a17ae 2241 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2242 if (!table)
2243 return;
f31e084c 2244
d62a17ae 2245 apply_mask(p);
2246 rn = route_node_lookup(table, p);
2247 if (!rn)
2248 return;
f31e084c 2249
d62a17ae 2250 route_unlock_node(rn);
2251 if (!rn->info)
2252 return;
f31e084c 2253
d62a17ae 2254 fec_print(rn->info, vty);
f31e084c
DS
2255}
2256
ce549947
RW
2257/*
2258 * Install/uninstall a FEC-To-NHLFE (FTN) binding.
2259 */
d62a17ae 2260int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
2261 struct prefix *prefix, enum nexthop_types_t gtype,
2262 union g_addr *gate, ifindex_t ifindex, u_int8_t distance,
2263 mpls_label_t out_label)
2264{
2265 struct route_table *table;
2266 struct route_node *rn;
2267 struct route_entry *re;
2268 struct nexthop *nexthop;
2269
2270 /* Lookup table. */
2271 table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
2272 zvrf_id(zvrf));
2273 if (!table)
2274 return -1;
2275
2276 /* Lookup existing route */
2277 rn = route_node_get(table, prefix);
a2addae8 2278 RNODE_FOREACH_RE (rn, re) {
d62a17ae 2279 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2280 continue;
2281 if (re->distance == distance)
2282 break;
88d88a9c 2283 }
ce549947 2284
d62a17ae 2285 if (re == NULL)
2286 return -1;
2287
7ee30f28 2288 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
d62a17ae 2289 switch (nexthop->type) {
2290 case NEXTHOP_TYPE_IPV4:
2291 case NEXTHOP_TYPE_IPV4_IFINDEX:
2292 if (gtype != NEXTHOP_TYPE_IPV4
2293 && gtype != NEXTHOP_TYPE_IPV4_IFINDEX)
2294 continue;
2295 if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4))
2296 continue;
2297 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
2298 && nexthop->ifindex != ifindex)
2299 continue;
2300 goto found;
2301 case NEXTHOP_TYPE_IPV6:
2302 case NEXTHOP_TYPE_IPV6_IFINDEX:
2303 if (gtype != NEXTHOP_TYPE_IPV6
2304 && gtype != NEXTHOP_TYPE_IPV6_IFINDEX)
2305 continue;
2306 if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, &gate->ipv6))
2307 continue;
2308 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
2309 && nexthop->ifindex != ifindex)
2310 continue;
2311 goto found;
2312 default:
2313 break;
2314 }
2315 }
2316 /* nexthop not found */
2317 return -1;
2318
2319found:
2320 if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2321 nexthop_add_labels(nexthop, type, 1, &out_label);
2322 else if (!add && nexthop->nh_label_type == type)
2323 nexthop_del_labels(nexthop);
2324 else
2325 return 0;
ce549947 2326
d62a17ae 2327 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
332ad713 2328 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
d62a17ae 2329 rib_queue_add(rn);
ce549947 2330
d62a17ae 2331 return 0;
ce549947
RW
2332}
2333
2334/*
2335 * Install/update a NHLFE for an LSP in the forwarding table. This may be
2336 * a new LSP entry or a new NHLFE for an existing in-label or an update of
2337 * the out-label for an existing NHLFE (update case).
2338 */
d62a17ae 2339int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
2340 mpls_label_t in_label, mpls_label_t out_label,
2341 enum nexthop_types_t gtype, union g_addr *gate,
2342 ifindex_t ifindex)
2343{
2344 struct hash *lsp_table;
2345 zebra_ile_t tmp_ile;
2346 zebra_lsp_t *lsp;
2347 zebra_nhlfe_t *nhlfe;
2348 char buf[BUFSIZ];
2349
2350 /* Lookup table. */
2351 lsp_table = zvrf->lsp_table;
2352 if (!lsp_table)
2353 return -1;
2354
2355 /* If entry is present, exit. */
2356 tmp_ile.in_label = in_label;
2357 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2358 if (!lsp)
2359 return -1;
2360 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2361 if (nhlfe) {
2362 struct nexthop *nh = nhlfe->nexthop;
2363
2364 assert(nh);
2365 assert(nh->nh_label);
2366
2367 /* Clear deleted flag (in case it was set) */
2368 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2369 if (nh->nh_label->label[0] == out_label)
2370 /* No change */
2371 return 0;
2372
2373 if (IS_ZEBRA_DEBUG_MPLS) {
2374 nhlfe2str(nhlfe, buf, BUFSIZ);
2375 zlog_debug(
2376 "LSP in-label %u type %d nexthop %s "
2377 "out-label changed to %u (old %u)",
2378 in_label, type, buf, out_label,
2379 nh->nh_label->label[0]);
2380 }
2381
2382 /* Update out label, trigger processing. */
2383 nh->nh_label->label[0] = out_label;
2384 } else {
2385 /* Add LSP entry to this nexthop */
2386 nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, out_label);
2387 if (!nhlfe)
2388 return -1;
2389
2390 if (IS_ZEBRA_DEBUG_MPLS) {
2391 nhlfe2str(nhlfe, buf, BUFSIZ);
2392 zlog_debug(
2393 "Add LSP in-label %u type %d nexthop %s "
2394 "out-label %u",
2395 in_label, type, buf, out_label);
2396 }
2397
2398 lsp->addr_family = NHLFE_FAMILY(nhlfe);
2399 }
2400
2401 /* Mark NHLFE, queue LSP for processing. */
2402 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2403 if (lsp_processq_add(lsp))
2404 return -1;
2405
2406 return 0;
ce549947
RW
2407}
2408
2409/*
2410 * Uninstall a particular NHLFE in the forwarding table. If this is
2411 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
2412 */
d62a17ae 2413int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2414 mpls_label_t in_label, enum nexthop_types_t gtype,
2415 union g_addr *gate, ifindex_t ifindex)
2416{
2417 struct hash *lsp_table;
2418 zebra_ile_t tmp_ile;
2419 zebra_lsp_t *lsp;
2420 zebra_nhlfe_t *nhlfe;
2421 char buf[BUFSIZ];
2422
2423 /* Lookup table. */
2424 lsp_table = zvrf->lsp_table;
2425 if (!lsp_table)
2426 return -1;
2427
2428 /* If entry is not present, exit. */
2429 tmp_ile.in_label = in_label;
2430 lsp = hash_lookup(lsp_table, &tmp_ile);
2431 if (!lsp)
2432 return 0;
2433 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2434 if (!nhlfe)
2435 return 0;
2436
2437 if (IS_ZEBRA_DEBUG_MPLS) {
2438 nhlfe2str(nhlfe, buf, BUFSIZ);
2439 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
2440 in_label, type, buf, nhlfe->flags);
2441 }
2442
2443 /* Mark NHLFE for delete or directly delete, as appropriate. */
2444 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
2445 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2446 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2447 if (lsp_processq_add(lsp))
2448 return -1;
2449 } else {
2450 nhlfe_del(nhlfe);
2451
2452 /* Free LSP entry if no other NHLFEs and not scheduled. */
2453 if (!lsp->nhlfe_list
2454 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
2455 if (IS_ZEBRA_DEBUG_MPLS)
2456 zlog_debug("Free LSP in-label %u flags 0x%x",
2457 lsp->ile.in_label, lsp->flags);
2458
2459 lsp = hash_release(lsp_table, &lsp->ile);
2460 if (lsp)
2461 XFREE(MTYPE_LSP, lsp);
2462 }
2463 }
2464 return 0;
ce549947
RW
2465}
2466
2467/*
2468 * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
2469 * If no other NHLFEs exist, the entry would be deleted.
2470 */
d62a17ae 2471void mpls_ldp_lsp_uninstall_all(struct hash_backet *backet, void *ctxt)
ce549947 2472{
d62a17ae 2473 zebra_lsp_t *lsp;
2474 struct hash *lsp_table;
ce549947 2475
d62a17ae 2476 lsp = (zebra_lsp_t *)backet->data;
2477 if (!lsp || !lsp->nhlfe_list)
2478 return;
ce549947 2479
d62a17ae 2480 lsp_table = ctxt;
2481 if (!lsp_table)
2482 return;
ce549947 2483
d62a17ae 2484 mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP);
ce549947
RW
2485}
2486
2487/*
2488 * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
2489 */
d62a17ae 2490void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
2491{
2492 struct route_table *table;
2493 struct route_node *rn;
2494 struct route_entry *re;
2495 struct nexthop *nexthop;
2496 int update;
2497
2498 /* Process routes of interested address-families. */
2499 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2500 if (!table)
2501 return;
2502
2503 for (rn = route_top(table); rn; rn = route_next(rn)) {
2504 update = 0;
a2addae8 2505 RNODE_FOREACH_RE (rn, re) {
7ee30f28 2506 for (nexthop = re->ng.nexthop; nexthop;
407c87a6
DS
2507 nexthop = nexthop->next) {
2508 if (nexthop->nh_label_type != ZEBRA_LSP_LDP)
2509 continue;
2510
d62a17ae 2511 nexthop_del_labels(nexthop);
2512 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2513 SET_FLAG(re->status,
332ad713 2514 ROUTE_ENTRY_LABELS_CHANGED);
d62a17ae 2515 update = 1;
2516 }
407c87a6 2517 }
d62a17ae 2518
2519 if (update)
2520 rib_queue_add(rn);
2521 }
ce549947
RW
2522}
2523
1c1cf002 2524#if defined(HAVE_CUMULUS)
7758e3f3 2525/*
2526 * Check that the label values used in LSP creation are consistent. The
2527 * main criteria is that if there is ECMP, the label operation must still
2528 * be consistent - i.e., all paths either do a swap or do PHP. This is due
2529 * to current HW restrictions.
2530 */
d62a17ae 2531int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
2532 mpls_label_t in_label,
2533 mpls_label_t out_label,
2534 enum nexthop_types_t gtype,
2535 union g_addr *gate, ifindex_t ifindex)
2536{
2537 struct hash *slsp_table;
2538 zebra_ile_t tmp_ile;
2539 zebra_slsp_t *slsp;
2540 zebra_snhlfe_t *snhlfe;
2541
2542 /* Lookup table. */
2543 slsp_table = zvrf->slsp_table;
2544 if (!slsp_table)
2545 return 0;
2546
2547 /* If entry is not present, exit. */
2548 tmp_ile.in_label = in_label;
2549 slsp = hash_lookup(slsp_table, &tmp_ile);
2550 if (!slsp)
2551 return 1;
2552
2553 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2554 if (snhlfe) {
2555 if (snhlfe->out_label == out_label)
2556 return 1;
2557
2558 /* If not only NHLFE, cannot allow label change. */
2559 if (snhlfe != slsp->snhlfe_list || snhlfe->next)
2560 return 0;
2561 } else {
2562 /* If other NHLFEs exist, label operation must match. */
2563 if (slsp->snhlfe_list) {
2564 int cur_op, new_op;
2565
2566 cur_op = (slsp->snhlfe_list->out_label
70e98a7f
DS
2567 == MPLS_LABEL_IMPLICIT_NULL);
2568 new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
d62a17ae 2569 if (cur_op != new_op)
2570 return 0;
2571 }
2572 }
2573
2574 /* Label values are good. */
2575 return 1;
7758e3f3 2576}
1c1cf002 2577#endif /* HAVE_CUMULUS */
7758e3f3 2578
2579/*
2580 * Add static LSP entry. This may be the first entry for this incoming label
2581 * or an additional nexthop; an existing entry may also have outgoing label
2582 * changed.
2583 * Note: The label operation (swap or PHP) is common for the LSP entry (all
2584 * NHLFEs).
2585 */
d62a17ae 2586int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
2587 mpls_label_t out_label,
2588 enum nexthop_types_t gtype, union g_addr *gate,
2589 ifindex_t ifindex)
2590{
2591 struct hash *slsp_table;
2592 zebra_ile_t tmp_ile;
2593 zebra_slsp_t *slsp;
2594 zebra_snhlfe_t *snhlfe;
2595 char buf[BUFSIZ];
2596
2597 /* Lookup table. */
2598 slsp_table = zvrf->slsp_table;
2599 if (!slsp_table)
2600 return -1;
2601
2602 /* If entry is present, exit. */
2603 tmp_ile.in_label = in_label;
2604 slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc);
2605 if (!slsp)
2606 return -1;
2607 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2608 if (snhlfe) {
2609 if (snhlfe->out_label == out_label)
2610 /* No change */
2611 return 0;
2612
2613 if (IS_ZEBRA_DEBUG_MPLS) {
2614 snhlfe2str(snhlfe, buf, BUFSIZ);
2615 zlog_debug(
2616 "Upd static LSP in-label %u nexthop %s "
2617 "out-label %u (old %u)",
2618 in_label, buf, out_label, snhlfe->out_label);
2619 }
2620 snhlfe->out_label = out_label;
2621 } else {
2622 /* Add static LSP entry to this nexthop */
2623 snhlfe = snhlfe_add(slsp, gtype, gate, ifindex, out_label);
2624 if (!snhlfe)
2625 return -1;
2626
2627 if (IS_ZEBRA_DEBUG_MPLS) {
2628 snhlfe2str(snhlfe, buf, BUFSIZ);
2629 zlog_debug(
2630 "Add static LSP in-label %u nexthop %s out-label %u",
2631 in_label, buf, out_label);
2632 }
2633 }
2634
2635 /* (Re)Install LSP in the main table. */
2636 if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
2637 gate, ifindex))
2638 return -1;
2639
2640 return 0;
7758e3f3 2641}
2642
2643/*
2644 * Delete static LSP entry. This may be the delete of one particular
2645 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
2646 * all NHLFEs).
2647 * NOTE: Delete of the only NHLFE will also end up deleting the entire
2648 * LSP configuration.
2649 */
d62a17ae 2650int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
2651 enum nexthop_types_t gtype, union g_addr *gate,
2652 ifindex_t ifindex)
2653{
2654 struct hash *slsp_table;
2655 zebra_ile_t tmp_ile;
2656 zebra_slsp_t *slsp;
2657 zebra_snhlfe_t *snhlfe;
2658
2659 /* Lookup table. */
2660 slsp_table = zvrf->slsp_table;
2661 if (!slsp_table)
2662 return -1;
2663
2664 /* If entry is not present, exit. */
2665 tmp_ile.in_label = in_label;
2666 slsp = hash_lookup(slsp_table, &tmp_ile);
2667 if (!slsp)
2668 return 0;
2669
2670 /* Is it delete of entire LSP or a specific NHLFE? */
2671 if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
2672 if (IS_ZEBRA_DEBUG_MPLS)
2673 zlog_debug("Del static LSP in-label %u", in_label);
2674
2675 /* Uninstall entire LSP from the main table. */
2676 mpls_static_lsp_uninstall_all(zvrf, in_label);
2677
2678 /* Delete all static NHLFEs */
2679 snhlfe_del_all(slsp);
2680 } else {
2681 /* Find specific NHLFE, exit if not found. */
2682 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2683 if (!snhlfe)
2684 return 0;
2685
2686 if (IS_ZEBRA_DEBUG_MPLS) {
2687 char buf[BUFSIZ];
2688 snhlfe2str(snhlfe, buf, BUFSIZ);
2689 zlog_debug("Del static LSP in-label %u nexthop %s",
2690 in_label, buf);
2691 }
2692
2693 /* Uninstall LSP from the main table. */
2694 mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
2695 gate, ifindex);
2696
2697 /* Delete static LSP NHLFE */
2698 snhlfe_del(snhlfe);
2699 }
2700
2701 /* Remove entire static LSP entry if no NHLFE - valid in either case
2702 * above. */
2703 if (!slsp->snhlfe_list) {
2704 slsp = hash_release(slsp_table, &tmp_ile);
2705 if (slsp)
2706 XFREE(MTYPE_SLSP, slsp);
2707 }
2708
2709 return 0;
7758e3f3 2710}
2711
40c7bdb0 2712/*
2713 * Schedule all MPLS label forwarding entries for processing.
2714 * Called upon changes that may affect one or more of them such as
2715 * interface or nexthop state changes.
2716 */
d62a17ae 2717void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
40c7bdb0 2718{
d62a17ae 2719 if (!zvrf)
2720 return;
2721 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
40c7bdb0 2722}
2723
3ab18ff2 2724/*
2725 * Display MPLS label forwarding table for a specific LSP
2726 * (VTY command handler).
2727 */
d62a17ae 2728void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
2729 mpls_label_t label, u_char use_json)
3ab18ff2 2730{
d62a17ae 2731 struct hash *lsp_table;
2732 zebra_lsp_t *lsp;
2733 zebra_ile_t tmp_ile;
2734 json_object *json = NULL;
3ab18ff2 2735
d62a17ae 2736 /* Lookup table. */
2737 lsp_table = zvrf->lsp_table;
2738 if (!lsp_table)
2739 return;
3ab18ff2 2740
d62a17ae 2741 /* If entry is not present, exit. */
2742 tmp_ile.in_label = label;
2743 lsp = hash_lookup(lsp_table, &tmp_ile);
2744 if (!lsp)
2745 return;
3ab18ff2 2746
d62a17ae 2747 if (use_json) {
2748 json = lsp_json(lsp);
9d303b37
DL
2749 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2750 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 2751 json_object_free(json);
2752 } else
2753 lsp_print(lsp, (void *)vty);
3ab18ff2 2754}
2755
2756/*
2757 * Display MPLS label forwarding table (VTY command handler).
2758 */
d62a17ae 2759void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
2760 u_char use_json)
2761{
2762 char buf[BUFSIZ];
2763 json_object *json = NULL;
2764 zebra_lsp_t *lsp = NULL;
2765 zebra_nhlfe_t *nhlfe = NULL;
2766 struct nexthop *nexthop = NULL;
2767 struct listnode *node = NULL;
2768 struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
2769
2770 if (use_json) {
2771 json = json_object_new_object();
2772
2773 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
2774 json_object_object_add(
2775 json, label2str(lsp->ile.in_label, buf, BUFSIZ),
2776 lsp_json(lsp));
2777
9d303b37
DL
2778 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2779 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 2780 json_object_free(json);
2781 } else {
2782 vty_out(vty, " Inbound Outbound\n");
2783 vty_out(vty, " Label Type Nexthop Label\n");
2784 vty_out(vty, "-------- ------- --------------- --------\n");
2785
2786 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
2787 for (nhlfe = lsp->nhlfe_list; nhlfe;
2788 nhlfe = nhlfe->next) {
2789 vty_out(vty, "%8d %7s ", lsp->ile.in_label,
2790 nhlfe_type2str(nhlfe->type));
2791 nexthop = nhlfe->nexthop;
2792
2793 switch (nexthop->type) {
996c9314 2794 case NEXTHOP_TYPE_IFINDEX: {
b9abd9ad
DS
2795 struct interface *ifp;
2796
2797 ifp = if_lookup_by_index(
2798 nexthop->ifindex, VRF_UNKNOWN);
2799 vty_out(vty, "%15s", ifp->name);
2800 break;
2801 }
d62a17ae 2802 case NEXTHOP_TYPE_IPV4:
2803 case NEXTHOP_TYPE_IPV4_IFINDEX:
2804 vty_out(vty, "%15s",
2805 inet_ntoa(nexthop->gate.ipv4));
2806 break;
2807 case NEXTHOP_TYPE_IPV6:
2808 case NEXTHOP_TYPE_IPV6_IFINDEX:
2809 vty_out(vty, "%15s",
2810 inet_ntop(AF_INET6,
2811 &nexthop->gate.ipv6,
2812 buf, BUFSIZ));
2813 break;
2814 default:
2815 break;
2816 }
2817
b9abd9ad 2818 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
fc5cca9f
DS
2819 vty_out(vty, " %8s\n",
2820 mpls_label2str(
2821 nexthop->nh_label
2822 ->num_labels,
2823 &nexthop->nh_label
2824 ->label[0],
2825 buf, BUFSIZ, 1));
b9abd9ad
DS
2826 else
2827 vty_out(vty, "\n");
d62a17ae 2828 }
2829 }
2830
2831 vty_out(vty, "\n");
2832 }
2833
affe9e99 2834 list_delete_and_null(&lsp_list);
3ab18ff2 2835}
2836
7758e3f3 2837/*
2838 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
2839 */
d62a17ae 2840int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
2841{
2842 zebra_slsp_t *slsp;
2843 zebra_snhlfe_t *snhlfe;
2844 struct listnode *node;
2845 struct list *slsp_list =
2846 hash_get_sorted_list(zvrf->slsp_table, slsp_cmp);
2847
2848 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) {
2849 for (snhlfe = slsp->snhlfe_list; snhlfe;
2850 snhlfe = snhlfe->next) {
0af35d90 2851 char buf[BUFSIZ];
d62a17ae 2852 char lstr[30];
2853
0af35d90 2854 snhlfe2str(snhlfe, buf, sizeof(buf));
d62a17ae 2855 switch (snhlfe->out_label) {
70e98a7f
DS
2856 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
2857 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
d62a17ae 2858 strlcpy(lstr, "explicit-null", sizeof(lstr));
2859 break;
70e98a7f 2860 case MPLS_LABEL_IMPLICIT_NULL:
d62a17ae 2861 strlcpy(lstr, "implicit-null", sizeof(lstr));
2862 break;
2863 default:
2864 sprintf(lstr, "%u", snhlfe->out_label);
2865 break;
2866 }
2867
2868 vty_out(vty, "mpls lsp %u %s %s\n", slsp->ile.in_label,
2869 buf, lstr);
2870 }
2871 }
b78b820d 2872
affe9e99 2873 list_delete_and_null(&slsp_list);
d62a17ae 2874 return (zvrf->slsp_table->count ? 1 : 0);
7758e3f3 2875}
2876
1b6d5c7e
VV
2877/*
2878 * Add/update global label block.
2879 */
d62a17ae 2880int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, u_int32_t start_label,
2881 u_int32_t end_label)
1b6d5c7e 2882{
d62a17ae 2883 zvrf->mpls_srgb.start_label = start_label;
2884 zvrf->mpls_srgb.end_label = end_label;
28d58fd7 2885
d62a17ae 2886 /* Evaluate registered FECs to see if any get a label or not. */
2887 fec_evaluate(zvrf);
2888 return 0;
1b6d5c7e
VV
2889}
2890
2891/*
2892 * Delete global label block.
2893 */
d62a17ae 2894int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
1b6d5c7e 2895{
d62a17ae 2896 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
2897 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
28d58fd7 2898
d62a17ae 2899 /* Process registered FECs to clear their local label, if needed. */
2900 fec_evaluate(zvrf);
2901 return 0;
1b6d5c7e
VV
2902}
2903
2904/*
2905 * Display MPLS global label block configuration (VTY command handler).
2906 */
d62a17ae 2907int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
1b6d5c7e 2908{
d62a17ae 2909 if (zvrf->mpls_srgb.start_label == 0)
2910 return 0;
1b6d5c7e 2911
d62a17ae 2912 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
2913 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
2914 vty_out(vty, "mpls label global-block %u %u\n",
2915 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
2916 }
1b6d5c7e 2917
d62a17ae 2918 return 1;
1b6d5c7e
VV
2919}
2920
84915b0a 2921/*
2922 * Called when VRF becomes inactive, cleans up information but keeps
2923 * the table itself.
2924 * NOTE: Currently supported only for default VRF.
2925 */
2926void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
2927{
2928 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
2929}
2930
40c7bdb0 2931/*
2932 * Called upon process exiting, need to delete LSP forwarding
2933 * entries from the kernel.
2934 * NOTE: Currently supported only for default VRF.
2935 */
d62a17ae 2936void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
40c7bdb0 2937{
d62a17ae 2938 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
2939 hash_clean(zvrf->lsp_table, NULL);
2940 hash_free(zvrf->lsp_table);
2941 hash_clean(zvrf->slsp_table, NULL);
2942 hash_free(zvrf->slsp_table);
9b67b514
DS
2943 route_table_finish(zvrf->fec_table[AFI_IP]);
2944 route_table_finish(zvrf->fec_table[AFI_IP6]);
40c7bdb0 2945}
2946
7758e3f3 2947/*
2948 * Allocate MPLS tables for this VRF and do other initialization.
2949 * NOTE: Currently supported only for default VRF.
2950 */
d62a17ae 2951void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
7758e3f3 2952{
d62a17ae 2953 if (!zvrf)
2954 return;
996c9314
LB
2955 zvrf->slsp_table =
2956 hash_create(label_hash, label_cmp, "ZEBRA SLSP table");
2957 zvrf->lsp_table = hash_create(label_hash, label_cmp, "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}