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