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