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