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