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