]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_mpls.c
Merge pull request #9345 from mjstapp/fix_lib_zmq_free
[mirror_frr.git] / zebra / zebra_mpls.c
CommitLineData
7758e3f3 1/* Zebra MPLS code
2 * Copyright (C) 2013 Cumulus Networks, Inc.
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
896014f4
DL
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
7758e3f3 19 */
20
21#include <zebra.h>
22
23#include "prefix.h"
24#include "table.h"
25#include "memory.h"
7758e3f3 26#include "command.h"
27#include "if.h"
28#include "log.h"
29#include "sockunion.h"
30#include "linklist.h"
31#include "thread.h"
32#include "workqueue.h"
33#include "prefix.h"
34#include "routemap.h"
35#include "stream.h"
36#include "nexthop.h"
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;
40c7bdb0 1040
d62a17ae 1041 zvrf = vrf_info_lookup(VRF_DEFAULT);
1042 assert(zvrf);
40c7bdb0 1043
d62a17ae 1044 lsp_table = zvrf->lsp_table;
1045 if (!lsp_table) // unexpected
1046 return;
40c7bdb0 1047
8f74a383 1048 lsp = (struct zebra_lsp *)data;
d62a17ae 1049 if (!lsp) // unexpected
1050 return;
40c7bdb0 1051
d62a17ae 1052 /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
1053 * exist,
1054 * delete LSP entry also.
1055 */
1056 UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
40c7bdb0 1057
ee70f629 1058 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
d62a17ae 1059 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1060 nhlfe_del(nhlfe);
1061 }
40c7bdb0 1062
1323491d
MS
1063 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1064 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1065 nhlfe_del(nhlfe);
1066 }
1067
1068 lsp_check_free(lsp_table, &lsp);
40c7bdb0 1069}
1070
1071/*
1072 * Callback upon finishing the processing of all scheduled
1073 * LSP forwarding entries.
1074 */
d62a17ae 1075static void lsp_processq_complete(struct work_queue *wq)
40c7bdb0 1076{
d62a17ae 1077 /* Nothing to do for now. */
40c7bdb0 1078}
1079
1080/*
1081 * Add LSP forwarding entry to queue for subsequent processing.
1082 */
8f74a383 1083static int lsp_processq_add(struct zebra_lsp *lsp)
40c7bdb0 1084{
d62a17ae 1085 /* If already scheduled, exit. */
1086 if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1087 return 0;
40c7bdb0 1088
e2353ec2 1089 if (zrouter.lsp_process_q == NULL) {
e914ccbe 1090 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1c50c1c0 1091 "%s: work_queue does not exist!", __func__);
d62a17ae 1092 return -1;
1093 }
33c32282 1094
e2353ec2 1095 work_queue_add(zrouter.lsp_process_q, lsp);
d62a17ae 1096 SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1097 return 0;
40c7bdb0 1098}
1099
1100/*
1101 * Callback to allocate LSP forwarding table entry.
1102 */
d62a17ae 1103static void *lsp_alloc(void *p)
40c7bdb0 1104{
a7d2146a 1105 const struct zebra_ile *ile = p;
8f74a383 1106 struct zebra_lsp *lsp;
40c7bdb0 1107
8f74a383 1108 lsp = XCALLOC(MTYPE_LSP, sizeof(struct zebra_lsp));
d62a17ae 1109 lsp->ile = *ile;
ee70f629 1110 nhlfe_list_init(&lsp->nhlfe_list);
cd4bb96f 1111 nhlfe_list_init(&lsp->backup_nhlfe_list);
40c7bdb0 1112
d62a17ae 1113 if (IS_ZEBRA_DEBUG_MPLS)
1114 zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label);
40c7bdb0 1115
d62a17ae 1116 return ((void *)lsp);
40c7bdb0 1117}
1118
1323491d
MS
1119/*
1120 * Check whether lsp can be freed - no nhlfes, e.g., and call free api
1121 */
8f74a383 1122static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp)
1323491d 1123{
8f74a383 1124 struct zebra_lsp *lsp;
1323491d
MS
1125
1126 if (plsp == NULL || *plsp == NULL)
1127 return;
1128
1129 lsp = *plsp;
1130
1131 if ((nhlfe_list_first(&lsp->nhlfe_list) == NULL) &&
1132 (nhlfe_list_first(&lsp->backup_nhlfe_list) == NULL) &&
1133 !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1134 lsp_free(lsp_table, plsp);
1135}
1136
ebab422a
MS
1137/*
1138 * Dtor for an LSP: remove from ile hash, release any internal allocations,
1139 * free LSP object.
1140 */
8f74a383 1141static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp)
ebab422a 1142{
8f74a383 1143 struct zebra_lsp *lsp;
f2595bd5 1144 struct zebra_nhlfe *nhlfe;
ebab422a
MS
1145
1146 if (plsp == NULL || *plsp == NULL)
1147 return;
1148
1149 lsp = *plsp;
1150
1151 if (IS_ZEBRA_DEBUG_MPLS)
1152 zlog_debug("Free LSP in-label %u flags 0x%x",
1153 lsp->ile.in_label, lsp->flags);
1154
1155 /* Free nhlfes, if any. */
ee70f629 1156 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe)
ebab422a 1157 nhlfe_del(nhlfe);
ebab422a 1158
cd4bb96f
MS
1159 /* Free backup nhlfes, if any. */
1160 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe)
1161 nhlfe_del(nhlfe);
1162
ebab422a
MS
1163 hash_release(lsp_table, &lsp->ile);
1164 XFREE(MTYPE_LSP, lsp);
1165
1166 *plsp = NULL;
1167}
1168
40c7bdb0 1169/*
1170 * Create printable string for NHLFE entry.
1171 */
f2595bd5 1172static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size)
40c7bdb0 1173{
608a57c0 1174 const struct nexthop *nexthop;
40c7bdb0 1175
d62a17ae 1176 buf[0] = '\0';
1177 nexthop = nhlfe->nexthop;
1178 switch (nexthop->type) {
1179 case NEXTHOP_TYPE_IPV4:
1180 case NEXTHOP_TYPE_IPV4_IFINDEX:
1181 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
1182 break;
1183 case NEXTHOP_TYPE_IPV6:
be489c57 1184 case NEXTHOP_TYPE_IPV6_IFINDEX:
d62a17ae 1185 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
1186 break;
b9abd9ad
DS
1187 case NEXTHOP_TYPE_IFINDEX:
1188 snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
10cc80ca 1189 case NEXTHOP_TYPE_BLACKHOLE:
d62a17ae 1190 break;
1191 }
40c7bdb0 1192
d62a17ae 1193 return buf;
40c7bdb0 1194}
1195
1196/*
1197 * Check if NHLFE matches with search info passed.
1198 */
f2595bd5
DS
1199static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
1200 enum nexthop_types_t gtype,
e4a1ec74 1201 const union g_addr *gate, ifindex_t ifindex)
40c7bdb0 1202{
d62a17ae 1203 struct nexthop *nhop;
1204 int cmp = 1;
40c7bdb0 1205
d62a17ae 1206 nhop = nhlfe->nexthop;
1207 if (!nhop)
1208 return 1;
40c7bdb0 1209
d62a17ae 1210 if (nhop->type != gtype)
1211 return 1;
40c7bdb0 1212
d62a17ae 1213 switch (nhop->type) {
1214 case NEXTHOP_TYPE_IPV4:
1215 case NEXTHOP_TYPE_IPV4_IFINDEX:
1216 cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
1217 sizeof(struct in_addr));
1218 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1219 cmp = !(nhop->ifindex == ifindex);
1220 break;
1221 case NEXTHOP_TYPE_IPV6:
1222 case NEXTHOP_TYPE_IPV6_IFINDEX:
1223 cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
1224 sizeof(struct in6_addr));
1225 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1226 cmp = !(nhop->ifindex == ifindex);
1227 break;
b9abd9ad
DS
1228 case NEXTHOP_TYPE_IFINDEX:
1229 cmp = !(nhop->ifindex == ifindex);
1230 break;
10cc80ca 1231 case NEXTHOP_TYPE_BLACKHOLE:
d62a17ae 1232 break;
1233 }
40c7bdb0 1234
d62a17ae 1235 return cmp;
40c7bdb0 1236}
1237
1238
1239/*
1240 * Locate NHLFE that matches with passed info.
1241 */
f2595bd5
DS
1242static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
1243 enum lsp_types_t lsp_type,
1244 enum nexthop_types_t gtype,
1245 const union g_addr *gate,
1246 ifindex_t ifindex)
40c7bdb0 1247{
f2595bd5 1248 struct zebra_nhlfe *nhlfe;
40c7bdb0 1249
ee70f629 1250 frr_each_safe(nhlfe_list, list, nhlfe) {
d62a17ae 1251 if (nhlfe->type != lsp_type)
1252 continue;
1253 if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex))
1254 break;
1255 }
40c7bdb0 1256
d62a17ae 1257 return nhlfe;
40c7bdb0 1258}
1259
ee70f629
MS
1260/*
1261 * Allocate and init new NHLFE.
1262 */
f2595bd5 1263static struct zebra_nhlfe *
8f74a383 1264nhlfe_alloc(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
f2595bd5
DS
1265 enum nexthop_types_t gtype, const union g_addr *gate,
1266 ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels)
d62a17ae 1267{
f2595bd5 1268 struct zebra_nhlfe *nhlfe;
d62a17ae 1269 struct nexthop *nexthop;
1270
3e0a9b40 1271 assert(lsp);
d62a17ae 1272
f2595bd5 1273 nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(struct zebra_nhlfe));
d62a17ae 1274
1275 nhlfe->lsp = lsp;
1276 nhlfe->type = lsp_type;
1277 nhlfe->distance = lsp_distance(lsp_type);
1278
1279 nexthop = nexthop_new();
cd4bb96f 1280
5065db0a 1281 nexthop_add_labels(nexthop, lsp_type, num_labels, labels);
d62a17ae 1282
4a7371e9 1283 nexthop->vrf_id = VRF_DEFAULT;
d62a17ae 1284 nexthop->type = gtype;
1285 switch (nexthop->type) {
1286 case NEXTHOP_TYPE_IPV4:
1287 case NEXTHOP_TYPE_IPV4_IFINDEX:
1288 nexthop->gate.ipv4 = gate->ipv4;
1289 if (ifindex)
1290 nexthop->ifindex = ifindex;
1291 break;
1292 case NEXTHOP_TYPE_IPV6:
1293 case NEXTHOP_TYPE_IPV6_IFINDEX:
1294 nexthop->gate.ipv6 = gate->ipv6;
1295 if (ifindex)
1296 nexthop->ifindex = ifindex;
1297 break;
b9abd9ad
DS
1298 case NEXTHOP_TYPE_IFINDEX:
1299 nexthop->ifindex = ifindex;
1300 break;
10cc80ca 1301 case NEXTHOP_TYPE_BLACKHOLE:
a44e3106
MS
1302 if (IS_ZEBRA_DEBUG_MPLS)
1303 zlog_debug("%s: invalid: blackhole nexthop", __func__);
1304
d62a17ae 1305 nexthop_free(nexthop);
1306 XFREE(MTYPE_NHLFE, nhlfe);
1307 return NULL;
d62a17ae 1308 }
d62a17ae 1309 nhlfe->nexthop = nexthop;
ee70f629
MS
1310
1311 return nhlfe;
1312}
1313
1314/*
cc1b9746
MS
1315 * Add primary or backup NHLFE. Base entry must have been created and
1316 * duplicate check done.
ee70f629 1317 */
8f74a383 1318static struct zebra_nhlfe *nhlfe_add(struct zebra_lsp *lsp,
f2595bd5
DS
1319 enum lsp_types_t lsp_type,
1320 enum nexthop_types_t gtype,
1321 const union g_addr *gate,
1322 ifindex_t ifindex, uint8_t num_labels,
1323 const mpls_label_t *labels, bool is_backup)
ee70f629 1324{
f2595bd5 1325 struct zebra_nhlfe *nhlfe;
ee70f629
MS
1326
1327 if (!lsp)
1328 return NULL;
1329
a44e3106
MS
1330 /* Must have labels */
1331 if (num_labels == 0 || labels == NULL) {
1332 if (IS_ZEBRA_DEBUG_MPLS)
1333 zlog_debug("%s: invalid nexthop: no labels", __func__);
1334
1335 return NULL;
1336 }
1337
ee70f629 1338 /* Allocate new object */
cd4bb96f
MS
1339 nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels,
1340 labels);
1341
6140b3b4
DS
1342 if (!nhlfe)
1343 return NULL;
1344
cc1b9746
MS
1345 /* Enqueue to LSP: primaries at head of list, backups at tail */
1346 if (is_backup) {
1347 SET_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP);
1348 nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe);
1349 } else
1350 nhlfe_list_add_head(&lsp->nhlfe_list, nhlfe);
d62a17ae 1351
1352 return nhlfe;
40c7bdb0 1353}
1354
1355/*
cd4bb96f
MS
1356 * Common delete for NHLFEs.
1357 */
f2595bd5 1358static void nhlfe_free(struct zebra_nhlfe *nhlfe)
cd4bb96f
MS
1359{
1360 if (!nhlfe)
1361 return;
1362
1363 /* Free nexthop. */
1364 if (nhlfe->nexthop)
1365 nexthop_free(nhlfe->nexthop);
1366
1367 nhlfe->nexthop = NULL;
1368
1369 XFREE(MTYPE_NHLFE, nhlfe);
1370}
1371
1372
1373/*
1374 * Disconnect NHLFE from LSP, and free. Entry must be present on LSP's list.
40c7bdb0 1375 */
f2595bd5 1376static int nhlfe_del(struct zebra_nhlfe *nhlfe)
40c7bdb0 1377{
8f74a383 1378 struct zebra_lsp *lsp;
40c7bdb0 1379
d62a17ae 1380 if (!nhlfe)
1381 return -1;
40c7bdb0 1382
d62a17ae 1383 lsp = nhlfe->lsp;
1384 if (!lsp)
1385 return -1;
40c7bdb0 1386
d62a17ae 1387 if (nhlfe == lsp->best_nhlfe)
1388 lsp->best_nhlfe = NULL;
bb49a121 1389
ee70f629 1390 /* Unlink from LSP */
cd4bb96f
MS
1391 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP))
1392 nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
1393 else
1394 nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
ee70f629 1395
cd4bb96f
MS
1396 nhlfe->lsp = NULL;
1397
1398 nhlfe_free(nhlfe);
40c7bdb0 1399
d62a17ae 1400 return 0;
40c7bdb0 1401}
1402
a64448ba
DS
1403/*
1404 * Update label for NHLFE entry.
1405 */
f2595bd5 1406static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
8ecdb26e 1407 struct mpls_label_stack *nh_label)
d62a17ae 1408{
1409 nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
1410}
1411
8f74a383 1412static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
d62a17ae 1413 enum lsp_types_t type)
1414{
f2595bd5 1415 struct zebra_nhlfe *nhlfe;
d62a17ae 1416 int schedule_lsp = 0;
1417 char buf[BUFSIZ];
1418
4a2a5236
MS
1419 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1420 schedule_lsp = 1;
1421
d62a17ae 1422 /* Mark NHLFEs for delete or directly delete, as appropriate. */
ee70f629 1423 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
d62a17ae 1424 /* Skip non-static NHLFEs */
1425 if (nhlfe->type != type)
1426 continue;
1427
1428 if (IS_ZEBRA_DEBUG_MPLS) {
608a57c0 1429 nhlfe2str(nhlfe, buf, sizeof(buf));
d62a17ae 1430 zlog_debug(
1431 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
1432 lsp->ile.in_label, type, buf, nhlfe->flags);
1433 }
1434
1435 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1436 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1437 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1438 schedule_lsp = 1;
1439 } else {
1440 nhlfe_del(nhlfe);
1441 }
1442 }
1443
f2e7f4eb
MS
1444 frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1445 /* Skip non-static NHLFEs */
1446 if (nhlfe->type != type)
1447 continue;
1448
1449 if (IS_ZEBRA_DEBUG_MPLS) {
608a57c0 1450 nhlfe2str(nhlfe, buf, sizeof(buf));
f2e7f4eb
MS
1451 zlog_debug(
1452 "Del backup LSP in-label %u type %d nexthop %s flags 0x%x",
1453 lsp->ile.in_label, type, buf, nhlfe->flags);
1454 }
1455
1456 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1457 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1458 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1459 schedule_lsp = 1;
1460 } else {
1461 nhlfe_del(nhlfe);
1462 }
1463 }
1464
d62a17ae 1465 /* Queue LSP for processing, if needed, else delete. */
1466 if (schedule_lsp) {
4a2a5236
MS
1467 if (IS_ZEBRA_DEBUG_MPLS) {
1468 zlog_debug("Schedule LSP in-label %u flags 0x%x",
1469 lsp->ile.in_label, lsp->flags);
1470 }
d62a17ae 1471 if (lsp_processq_add(lsp))
1472 return -1;
1323491d
MS
1473 } else {
1474 lsp_check_free(lsp_table, &lsp);
1475 }
d62a17ae 1476
1477 return 0;
40c7bdb0 1478}
1479
ce549947
RW
1480/*
1481 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
1482 * If no other NHLFEs exist, the entry would be deleted.
1483 */
d62a17ae 1484static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
1485 mpls_label_t in_label)
ce549947 1486{
d62a17ae 1487 struct hash *lsp_table;
a7d2146a 1488 struct zebra_ile tmp_ile;
8f74a383 1489 struct zebra_lsp *lsp;
ce549947 1490
d62a17ae 1491 /* Lookup table. */
1492 lsp_table = zvrf->lsp_table;
1493 if (!lsp_table)
1494 return -1;
ce549947 1495
d62a17ae 1496 /* If entry is not present, exit. */
1497 tmp_ile.in_label = in_label;
1498 lsp = hash_lookup(lsp_table, &tmp_ile);
ee70f629 1499 if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
d62a17ae 1500 return 0;
ce549947 1501
d62a17ae 1502 return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC);
ce549947
RW
1503}
1504
f2595bd5 1505static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe)
b78b820d 1506{
d62a17ae 1507 char buf[BUFSIZ];
1508 json_object *json_nhlfe = NULL;
3c0e1622 1509 json_object *json_backups = NULL;
31f937fb 1510 json_object *json_label_stack;
d62a17ae 1511 struct nexthop *nexthop = nhlfe->nexthop;
3c0e1622 1512 int i;
b78b820d 1513
d62a17ae 1514 json_nhlfe = json_object_new_object();
1515 json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
1516 json_object_int_add(json_nhlfe, "outLabel",
1517 nexthop->nh_label->label[0]);
31f937fb
SM
1518
1519 json_label_stack = json_object_new_array();
1520 json_object_object_add(json_nhlfe, "outLabelStack", json_label_stack);
1521 for (i = 0; i < nexthop->nh_label->num_labels; i++)
1522 json_object_array_add(
1523 json_label_stack,
1524 json_object_new_int(nexthop->nh_label->label[i]));
1525
d62a17ae 1526 json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
b78b820d 1527
d62a17ae 1528 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
1529 json_object_boolean_true_add(json_nhlfe, "installed");
b78b820d 1530
d62a17ae 1531 switch (nexthop->type) {
1532 case NEXTHOP_TYPE_IPV4:
1533 case NEXTHOP_TYPE_IPV4_IFINDEX:
1534 json_object_string_add(json_nhlfe, "nexthop",
9bcef951
MS
1535 inet_ntop(AF_INET, &nexthop->gate.ipv4,
1536 buf, sizeof(buf)));
d62a17ae 1537 break;
1538 case NEXTHOP_TYPE_IPV6:
1539 case NEXTHOP_TYPE_IPV6_IFINDEX:
1540 json_object_string_add(
1541 json_nhlfe, "nexthop",
1542 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1543
1544 if (nexthop->ifindex)
4a7371e9
DS
1545 json_object_string_add(json_nhlfe, "interface",
1546 ifindex2ifname(nexthop->ifindex,
1547 nexthop->vrf_id));
d62a17ae 1548 break;
10cc80ca 1549 case NEXTHOP_TYPE_IFINDEX:
a44e3106
MS
1550 if (nexthop->ifindex)
1551 json_object_string_add(json_nhlfe, "interface",
1552 ifindex2ifname(nexthop->ifindex,
1553 nexthop->vrf_id));
1554 break;
1555 case NEXTHOP_TYPE_BLACKHOLE:
d62a17ae 1556 break;
1557 }
3c0e1622
MS
1558
1559 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
1560 json_backups = json_object_new_array();
1561 for (i = 0; i < nexthop->backup_num; i++) {
1562 json_object_array_add(
1563 json_backups,
1564 json_object_new_int(nexthop->backup_idx[i]));
1565 }
1566
1567 json_object_object_add(json_nhlfe, "backupIndex",
1568 json_backups);
1569 }
1570
d62a17ae 1571 return json_nhlfe;
b78b820d 1572}
1573
3ab18ff2 1574/*
1575 * Print the NHLFE for a LSP forwarding entry.
1576 */
f2595bd5 1577static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
3c0e1622 1578 const char *indent)
d62a17ae 1579{
1580 struct nexthop *nexthop;
a29c2887 1581 char buf[MPLS_LABEL_STRLEN];
d62a17ae 1582
1583 nexthop = nhlfe->nexthop;
1584 if (!nexthop || !nexthop->nh_label) // unexpected
1585 return;
1586
1587 vty_out(vty, " type: %s remote label: %s distance: %d\n",
1588 nhlfe_type2str(nhlfe->type),
a29c2887
MS
1589 mpls_label2str(nexthop->nh_label->num_labels,
1590 nexthop->nh_label->label,
1591 buf, sizeof(buf), 0),
d62a17ae 1592 nhlfe->distance);
3c0e1622
MS
1593
1594 if (indent)
1595 vty_out(vty, "%s", indent);
1596
d62a17ae 1597 switch (nexthop->type) {
1598 case NEXTHOP_TYPE_IPV4:
1599 case NEXTHOP_TYPE_IPV4_IFINDEX:
9bcef951 1600 vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
d62a17ae 1601 if (nexthop->ifindex)
1602 vty_out(vty, " dev %s",
4a7371e9
DS
1603 ifindex2ifname(nexthop->ifindex,
1604 nexthop->vrf_id));
d62a17ae 1605 break;
1606 case NEXTHOP_TYPE_IPV6:
1607 case NEXTHOP_TYPE_IPV6_IFINDEX:
1608 vty_out(vty, " via %s",
2896f40e
MS
1609 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
1610 sizeof(buf)));
d62a17ae 1611 if (nexthop->ifindex)
1612 vty_out(vty, " dev %s",
4a7371e9
DS
1613 ifindex2ifname(nexthop->ifindex,
1614 nexthop->vrf_id));
d62a17ae 1615 break;
10cc80ca 1616 case NEXTHOP_TYPE_IFINDEX:
a44e3106
MS
1617 if (nexthop->ifindex)
1618 vty_out(vty, " dev %s",
1619 ifindex2ifname(nexthop->ifindex,
1620 nexthop->vrf_id));
1621 break;
1622 case NEXTHOP_TYPE_BLACKHOLE:
d62a17ae 1623 break;
1624 }
5e29e1a1
MS
1625 vty_out(vty, "%s",
1626 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP) ? " (backup)"
1627 : "");
996c9314
LB
1628 vty_out(vty, "%s",
1629 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
1630 : "");
d62a17ae 1631 vty_out(vty, "\n");
3ab18ff2 1632}
1633
1634/*
1635 * Print an LSP forwarding entry.
1636 */
8f74a383 1637static void lsp_print(struct vty *vty, struct zebra_lsp *lsp)
3ab18ff2 1638{
f2595bd5 1639 struct zebra_nhlfe *nhlfe, *backup;
474aebd9 1640 int i, j;
3ab18ff2 1641
d62a17ae 1642 vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label,
1643 CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)"
1644 : "");
3ab18ff2 1645
a29c2887 1646 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3c0e1622 1647 nhlfe_print(nhlfe, vty, NULL);
a29c2887 1648
3c0e1622 1649 if (nhlfe->nexthop == NULL ||
474aebd9
MS
1650 !CHECK_FLAG(nhlfe->nexthop->flags,
1651 NEXTHOP_FLAG_HAS_BACKUP))
1652 continue;
a29c2887 1653
474aebd9 1654 /* Backup nhlfes: find backups in backup list */
a29c2887 1655
474aebd9 1656 for (j = 0; j < nhlfe->nexthop->backup_num; j++) {
a29c2887 1657 i = 0;
5e29e1a1 1658 backup = NULL;
a29c2887 1659 frr_each(nhlfe_list, &lsp->backup_nhlfe_list, backup) {
474aebd9 1660 if (i == nhlfe->nexthop->backup_idx[j])
a29c2887
MS
1661 break;
1662 i++;
1663 }
1664
1665 if (backup) {
1666 vty_out(vty, " [backup %d]", i);
3c0e1622 1667 nhlfe_print(backup, vty, " ");
a29c2887
MS
1668 }
1669 }
1670 }
3ab18ff2 1671}
1672
1673/*
b78b820d 1674 * JSON objects for an LSP forwarding entry.
3ab18ff2 1675 */
8f74a383 1676static json_object *lsp_json(struct zebra_lsp *lsp)
3ab18ff2 1677{
f2595bd5 1678 struct zebra_nhlfe *nhlfe = NULL;
d62a17ae 1679 json_object *json = json_object_new_object();
1680 json_object *json_nhlfe_list = json_object_new_array();
3ab18ff2 1681
d62a17ae 1682 json_object_int_add(json, "inLabel", lsp->ile.in_label);
b78b820d 1683
d62a17ae 1684 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1685 json_object_boolean_true_add(json, "installed");
3ab18ff2 1686
ee70f629 1687 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe)
d62a17ae 1688 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
b78b820d 1689
d62a17ae 1690 json_object_object_add(json, "nexthops", json_nhlfe_list);
3c0e1622
MS
1691 json_nhlfe_list = NULL;
1692
1693
1694 frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1695 if (json_nhlfe_list == NULL)
1696 json_nhlfe_list = json_object_new_array();
1697
1698 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1699 }
1700
1701 if (json_nhlfe_list)
1702 json_object_object_add(json, "backupNexthops", json_nhlfe_list);
1703
d62a17ae 1704 return json;
b78b820d 1705}
1706
1707
1708/* Return a sorted linked list of the hash contents */
d62a17ae 1709static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
b78b820d 1710{
d62a17ae 1711 unsigned int i;
e3b78da8 1712 struct hash_bucket *hb;
d62a17ae 1713 struct list *sorted_list = list_new();
b78b820d 1714
d62a17ae 1715 sorted_list->cmp = (int (*)(void *, void *))cmp;
b78b820d 1716
d62a17ae 1717 for (i = 0; i < hash->size; i++)
1718 for (hb = hash->index[i]; hb; hb = hb->next)
1719 listnode_add_sort(sorted_list, hb->data);
b78b820d 1720
d62a17ae 1721 return sorted_list;
3ab18ff2 1722}
1723
7758e3f3 1724/*
b78b820d 1725 * Compare two LSPs based on their label values.
7758e3f3 1726 */
8f74a383 1727static int lsp_cmp(const struct zebra_lsp *lsp1, const struct zebra_lsp *lsp2)
7758e3f3 1728{
d62a17ae 1729 if (lsp1->ile.in_label < lsp2->ile.in_label)
1730 return -1;
7758e3f3 1731
d62a17ae 1732 if (lsp1->ile.in_label > lsp2->ile.in_label)
1733 return 1;
7758e3f3 1734
d62a17ae 1735 return 0;
7758e3f3 1736}
1737
40c7bdb0 1738/*
1739 * Initialize work queue for processing changed LSPs.
1740 */
2561d12e 1741static int mpls_processq_init(void)
40c7bdb0 1742{
e2353ec2
DS
1743 zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
1744 if (!zrouter.lsp_process_q) {
e914ccbe 1745 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1c50c1c0 1746 "%s: could not initialise work queue!", __func__);
d62a17ae 1747 return -1;
1748 }
40c7bdb0 1749
e2353ec2
DS
1750 zrouter.lsp_process_q->spec.workfunc = &lsp_process;
1751 zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
1752 zrouter.lsp_process_q->spec.errorfunc = NULL;
1753 zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
1754 zrouter.lsp_process_q->spec.max_retries = 0;
1755 zrouter.lsp_process_q->spec.hold = 10;
33c32282 1756
d62a17ae 1757 return 0;
40c7bdb0 1758}
1759
7758e3f3 1760
d37f4d6c
MS
1761/*
1762 * Process LSP update results from zebra dataplane.
1763 */
1764void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
1765{
1766 struct zebra_vrf *zvrf;
31f937fb 1767 mpls_label_t label;
a7d2146a 1768 struct zebra_ile tmp_ile;
d37f4d6c 1769 struct hash *lsp_table;
8f74a383 1770 struct zebra_lsp *lsp;
f2595bd5 1771 struct zebra_nhlfe *nhlfe;
d37f4d6c
MS
1772 struct nexthop *nexthop;
1773 enum dplane_op_e op;
8841f96e 1774 enum zebra_dplane_result status;
31f937fb 1775 enum zebra_sr_policy_update_label_mode update_mode;
d37f4d6c
MS
1776
1777 op = dplane_ctx_get_op(ctx);
1778 status = dplane_ctx_get_status(ctx);
1779
1780 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1781 zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
1782 ctx, dplane_op2str(op),
1783 dplane_ctx_get_in_label(ctx),
1784 dplane_res2str(status));
1785
31f937fb
SM
1786 label = dplane_ctx_get_in_label(ctx);
1787
d37f4d6c
MS
1788 switch (op) {
1789 case DPLANE_OP_LSP_INSTALL:
1790 case DPLANE_OP_LSP_UPDATE:
1791 /* Look for zebra LSP object */
1792 zvrf = vrf_info_lookup(VRF_DEFAULT);
1793 if (zvrf == NULL)
1794 break;
1795
1796 lsp_table = zvrf->lsp_table;
1797
31f937fb 1798 tmp_ile.in_label = label;
d37f4d6c
MS
1799 lsp = hash_lookup(lsp_table, &tmp_ile);
1800 if (lsp == NULL) {
1801 if (IS_ZEBRA_DEBUG_DPLANE)
1802 zlog_debug("LSP ctx %p: in-label %u not found",
1803 ctx, dplane_ctx_get_in_label(ctx));
1804 break;
1805 }
1806
1807 /* TODO -- Confirm that this result is still 'current' */
1808
c3753405 1809 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
d37f4d6c
MS
1810 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1811 clear_nhlfe_installed(lsp);
1812 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1813 "LSP Install Failure: in-label %u",
1814 lsp->ile.in_label);
c3753405
MS
1815 break;
1816 }
1817
1818 /* Update zebra object */
1819 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1820 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1821 nexthop = nhlfe->nexthop;
1822 if (!nexthop)
1823 continue;
1824
1825 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) &&
1826 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
1827 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1828 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1829 }
d37f4d6c
MS
1830 }
1831
31f937fb
SM
1832 update_mode = (op == DPLANE_OP_LSP_INSTALL)
1833 ? ZEBRA_SR_POLICY_LABEL_CREATED
1834 : ZEBRA_SR_POLICY_LABEL_UPDATED;
1835 zebra_sr_policy_label_update(label, update_mode);
d37f4d6c
MS
1836 break;
1837
1838 case DPLANE_OP_LSP_DELETE:
31f937fb 1839 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
3fd385c6
DS
1840 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
1841 "LSP Deletion Failure: in-label %u",
1842 dplane_ctx_get_in_label(ctx));
31f937fb
SM
1843 break;
1844 }
1845 zebra_sr_policy_label_update(label,
1846 ZEBRA_SR_POLICY_LABEL_REMOVED);
d37f4d6c
MS
1847 break;
1848
1849 default:
1850 break;
1851
1852 } /* Switch */
1853
1854 dplane_ctx_fini(&ctx);
1855}
1856
104e3ad9 1857/*
68110c42
MS
1858 * Process LSP installation info from two sets of nhlfes: a set from
1859 * a dplane notification, and a set from the zebra LSP object. Update
1860 * counters of installed nexthops, and return whether the LSP has changed.
104e3ad9 1861 */
68110c42
MS
1862static bool compare_notif_nhlfes(const struct nhlfe_list_head *ctx_head,
1863 struct nhlfe_list_head *nhlfe_head,
1864 int *start_counter, int *end_counter)
104e3ad9 1865{
f2595bd5
DS
1866 struct zebra_nhlfe *nhlfe;
1867 const struct zebra_nhlfe *ctx_nhlfe;
104e3ad9
MS
1868 struct nexthop *nexthop;
1869 const struct nexthop *ctx_nexthop;
68110c42 1870 int start_count = 0, end_count = 0;
188a00e0 1871 bool changed_p = false;
104e3ad9
MS
1872 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1873
68110c42 1874 frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
104e3ad9
MS
1875 char buf[NEXTHOP_STRLEN];
1876
1877 nexthop = nhlfe->nexthop;
1878 if (!nexthop)
1879 continue;
1880
1881 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
1882 start_count++;
1883
68110c42 1884 ctx_nhlfe = NULL;
104e3ad9 1885 ctx_nexthop = NULL;
68110c42 1886 frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
104e3ad9
MS
1887 ctx_nexthop = ctx_nhlfe->nexthop;
1888 if (!ctx_nexthop)
1889 continue;
1890
1891 if ((ctx_nexthop->type == nexthop->type) &&
1892 nexthop_same(ctx_nexthop, nexthop)) {
1893 /* Matched */
1894 break;
1895 }
1896 }
1897
1898 if (is_debug)
1899 nexthop2str(nexthop, buf, sizeof(buf));
1900
1901 if (ctx_nhlfe && ctx_nexthop) {
1902 if (is_debug) {
1903 const char *tstr = "";
1904
1905 if (!CHECK_FLAG(ctx_nhlfe->flags,
1906 NHLFE_FLAG_INSTALLED))
1907 tstr = "not ";
1908
1909 zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
1910 buf, tstr);
1911 }
1912
188a00e0 1913 /* Test zebra nhlfe install state */
104e3ad9
MS
1914 if (CHECK_FLAG(ctx_nhlfe->flags,
1915 NHLFE_FLAG_INSTALLED)) {
188a00e0
MS
1916
1917 if (!CHECK_FLAG(nhlfe->flags,
1918 NHLFE_FLAG_INSTALLED))
1919 changed_p = true;
104e3ad9
MS
1920
1921 /* Update counter */
1922 end_count++;
188a00e0
MS
1923 } else {
1924
1925 if (CHECK_FLAG(nhlfe->flags,
1926 NHLFE_FLAG_INSTALLED))
1927 changed_p = true;
1928 }
1929
1930 } else {
1931 /* Not mentioned in lfib set -> uninstalled */
1932 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ||
1933 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ||
1934 CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
1935 changed_p = true;
1936 }
1937
1938 if (is_debug)
1939 zlog_debug("LSP dplane notif: no match, nh %s",
1940 buf);
1941 }
1942 }
1943
68110c42
MS
1944 if (start_counter)
1945 *start_counter += start_count;
1946 if (end_counter)
1947 *end_counter += end_count;
188a00e0 1948
68110c42
MS
1949 return changed_p;
1950}
188a00e0 1951
68110c42
MS
1952/*
1953 * Update an lsp nhlfe list from a dplane context, typically an async
1954 * notification context. Update the LSP list to match the installed
1955 * status from the context's list.
1956 */
1957static int update_nhlfes_from_ctx(struct nhlfe_list_head *nhlfe_head,
1958 const struct nhlfe_list_head *ctx_head)
1959{
1960 int ret = 0;
f2595bd5
DS
1961 struct zebra_nhlfe *nhlfe;
1962 const struct zebra_nhlfe *ctx_nhlfe;
68110c42
MS
1963 struct nexthop *nexthop;
1964 const struct nexthop *ctx_nexthop;
1965 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1966
1967 frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
188a00e0
MS
1968 char buf[NEXTHOP_STRLEN];
1969
1970 nexthop = nhlfe->nexthop;
1971 if (!nexthop)
1972 continue;
1973
c3753405 1974 ctx_nhlfe = NULL;
188a00e0 1975 ctx_nexthop = NULL;
c3753405 1976 frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
188a00e0
MS
1977 ctx_nexthop = ctx_nhlfe->nexthop;
1978 if (!ctx_nexthop)
1979 continue;
1980
1981 if ((ctx_nexthop->type == nexthop->type) &&
1982 nexthop_same(ctx_nexthop, nexthop)) {
1983 /* Matched */
1984 break;
1985 }
1986 }
1987
1988 if (is_debug)
1989 nexthop2str(nexthop, buf, sizeof(buf));
1990
1991 if (ctx_nhlfe && ctx_nexthop) {
1992
1993 /* Bring zebra nhlfe install state into sync */
1994 if (CHECK_FLAG(ctx_nhlfe->flags,
1995 NHLFE_FLAG_INSTALLED)) {
c3753405
MS
1996 if (is_debug)
1997 zlog_debug("%s: matched lsp nhlfe %s (installed)",
1998 __func__, buf);
188a00e0
MS
1999
2000 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
00a9b150 2001 SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
188a00e0
MS
2002
2003 } else {
c3753405
MS
2004 if (is_debug)
2005 zlog_debug("%s: matched lsp nhlfe %s (not installed)",
2006 __func__, buf);
188a00e0 2007
104e3ad9 2008 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
00a9b150 2009 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
188a00e0 2010 }
104e3ad9
MS
2011
2012 if (CHECK_FLAG(ctx_nhlfe->nexthop->flags,
188a00e0
MS
2013 NEXTHOP_FLAG_FIB)) {
2014 SET_FLAG(nhlfe->nexthop->flags,
2015 NEXTHOP_FLAG_ACTIVE);
104e3ad9
MS
2016 SET_FLAG(nhlfe->nexthop->flags,
2017 NEXTHOP_FLAG_FIB);
188a00e0
MS
2018 } else {
2019 UNSET_FLAG(nhlfe->nexthop->flags,
2020 NEXTHOP_FLAG_ACTIVE);
104e3ad9
MS
2021 UNSET_FLAG(nhlfe->nexthop->flags,
2022 NEXTHOP_FLAG_FIB);
188a00e0
MS
2023 }
2024
104e3ad9
MS
2025 } else {
2026 /* Not mentioned in lfib set -> uninstalled */
c3753405
MS
2027 if (is_debug)
2028 zlog_debug("%s: no match for lsp nhlfe %s",
2029 __func__, buf);
104e3ad9 2030 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
00a9b150 2031 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
104e3ad9 2032 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
188a00e0 2033 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
104e3ad9
MS
2034 }
2035 }
2036
68110c42
MS
2037 return ret;
2038}
2039
2040/*
2041 * Process async dplane notifications.
2042 */
2043void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
2044{
2045 struct zebra_vrf *zvrf;
a7d2146a 2046 struct zebra_ile tmp_ile;
68110c42 2047 struct hash *lsp_table;
8f74a383 2048 struct zebra_lsp *lsp;
68110c42
MS
2049 const struct nhlfe_list_head *ctx_list;
2050 int start_count = 0, end_count = 0; /* Installed counts */
2051 bool changed_p = false;
2052 bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
8283551d 2053 enum zebra_sr_policy_update_label_mode update_mode;
68110c42
MS
2054
2055 if (is_debug)
2056 zlog_debug("LSP dplane notif, in-label %u",
2057 dplane_ctx_get_in_label(ctx));
2058
2059 /* Look for zebra LSP object */
2060 zvrf = vrf_info_lookup(VRF_DEFAULT);
2061 if (zvrf == NULL)
2062 goto done;
2063
2064 lsp_table = zvrf->lsp_table;
2065
2066 tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
2067 lsp = hash_lookup(lsp_table, &tmp_ile);
2068 if (lsp == NULL) {
2069 if (is_debug)
2070 zlog_debug("dplane LSP notif: in-label %u not found",
2071 dplane_ctx_get_in_label(ctx));
2072 goto done;
2073 }
2074
2075 /*
2076 * The dataplane/forwarding plane is notifying zebra about the state
2077 * of the nexthops associated with this LSP. First, we take a
2078 * pre-scan pass to determine whether the LSP has transitioned
2079 * from installed -> uninstalled. In that case, we need to have
2080 * the existing state of the LSP objects available before making
2081 * any changes.
2082 */
2083 ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2084
2085 changed_p = compare_notif_nhlfes(ctx_list, &lsp->nhlfe_list,
2086 &start_count, &end_count);
2087
2088 if (is_debug)
2089 zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
2090 start_count, end_count,
2091 changed_p ? ", changed" : "");
2092
2093 ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2094
2095 if (compare_notif_nhlfes(ctx_list, &lsp->backup_nhlfe_list,
2096 &start_count, &end_count))
2097 /* Avoid accidentally setting back to 'false' */
2098 changed_p = true;
2099
2100 if (is_debug)
2101 zlog_debug("LSP dplane notif: lfib backups, start_count %d, end_count %d%s",
2102 start_count, end_count,
2103 changed_p ? ", changed" : "");
2104
2105 /*
2106 * Has the LSP become uninstalled? We need the existing state of the
2107 * nexthops/nhlfes at this point so we know what to delete.
2108 */
2109 if (start_count > 0 && end_count == 0) {
2110 /* Inform other lfibs */
2111 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
2112 }
2113
2114 /*
2115 * Now we take a second pass and bring the zebra
2116 * nexthop state into sync with the forwarding-plane state.
2117 */
2118 ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2119 update_nhlfes_from_ctx(&lsp->nhlfe_list, ctx_list);
2120
2121 ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2122 update_nhlfes_from_ctx(&lsp->backup_nhlfe_list, ctx_list);
2123
188a00e0 2124 if (end_count > 0) {
104e3ad9 2125 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
188a00e0 2126
8283551d
MS
2127 /* SR-TE update too */
2128 if (start_count == 0)
2129 update_mode = ZEBRA_SR_POLICY_LABEL_CREATED;
2130 else
2131 update_mode = ZEBRA_SR_POLICY_LABEL_UPDATED;
2132 zebra_sr_policy_label_update(lsp->ile.in_label, update_mode);
2133
188a00e0
MS
2134 if (changed_p)
2135 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
2136
2137 } else {
8283551d
MS
2138 /* SR-TE update too */
2139 zebra_sr_policy_label_update(lsp->ile.in_label,
2140 ZEBRA_SR_POLICY_LABEL_REMOVED);
2141
104e3ad9
MS
2142 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2143 clear_nhlfe_installed(lsp);
2144 }
2145
2146done:
2147 dplane_ctx_fini(&ctx);
2148}
2149
a64448ba
DS
2150/*
2151 * Install dynamic LSP entry.
2152 */
d62a17ae 2153int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
2154 struct route_entry *re)
a64448ba 2155{
d62a17ae 2156 struct route_table *table;
60e36561 2157 struct zebra_fec *fec;
a64448ba 2158
d62a17ae 2159 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2160 if (!table)
2161 return -1;
a64448ba 2162
d62a17ae 2163 /* See if there is a configured label binding for this FEC. */
2164 fec = fec_find(table, &rn->p);
2165 if (!fec || fec->label == MPLS_INVALID_LABEL)
2166 return 0;
a64448ba 2167
d62a17ae 2168 /* We cannot install a label forwarding entry if local label is the
2169 * implicit-null label.
2170 */
70e98a7f 2171 if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
d62a17ae 2172 return 0;
a64448ba 2173
d62a17ae 2174 if (lsp_install(zvrf, fec->label, rn, re))
2175 return -1;
a64448ba 2176
d62a17ae 2177 return 0;
a64448ba
DS
2178}
2179
2180/*
2181 * Uninstall dynamic LSP entry, if any.
2182 */
d62a17ae 2183int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
2184 struct route_entry *re)
a64448ba 2185{
d62a17ae 2186 struct route_table *table;
60e36561 2187 struct zebra_fec *fec;
a64448ba 2188
d62a17ae 2189 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2190 if (!table)
2191 return -1;
a64448ba 2192
d62a17ae 2193 /* See if there is a configured label binding for this FEC. */
2194 fec = fec_find(table, &rn->p);
2195 if (!fec || fec->label == MPLS_INVALID_LABEL)
2196 return 0;
a64448ba 2197
d62a17ae 2198 /* Uninstall always removes all dynamic NHLFEs. */
2199 return lsp_uninstall(zvrf, fec->label);
a64448ba
DS
2200}
2201
d4cb23d7 2202/*
cd4bb96f
MS
2203 * Add an NHLFE to an LSP, return the newly-added object. This path only changes
2204 * the LSP object - nothing is scheduled for processing, for example.
d4cb23d7 2205 */
f2595bd5 2206struct zebra_nhlfe *
8f74a383 2207zebra_mpls_lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
f2595bd5
DS
2208 enum nexthop_types_t gtype, const union g_addr *gate,
2209 ifindex_t ifindex, uint8_t num_labels,
2210 const mpls_label_t *out_labels)
d4cb23d7
MS
2211{
2212 /* Just a public pass-through to the internal implementation */
5065db0a 2213 return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
cc1b9746 2214 out_labels, false /*backup*/);
d4cb23d7
MS
2215}
2216
cd4bb96f
MS
2217/*
2218 * Add a backup NHLFE to an LSP, return the newly-added object.
2219 * This path only changes the LSP object - nothing is scheduled for
2220 * processing, for example.
2221 */
f2595bd5 2222struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nhlfe(
8f74a383
DS
2223 struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
2224 enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex,
2225 uint8_t num_labels, const mpls_label_t *out_labels)
cd4bb96f
MS
2226{
2227 /* Just a public pass-through to the internal implementation */
cc1b9746
MS
2228 return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
2229 out_labels, true);
cd4bb96f
MS
2230}
2231
2232/*
2233 * Add an NHLFE to an LSP based on a nexthop; return the newly-added object
2234 */
8f74a383 2235struct zebra_nhlfe *zebra_mpls_lsp_add_nh(struct zebra_lsp *lsp,
f2595bd5
DS
2236 enum lsp_types_t lsp_type,
2237 const struct nexthop *nh)
cd4bb96f 2238{
f2595bd5 2239 struct zebra_nhlfe *nhlfe;
cd4bb96f
MS
2240
2241 if (nh->nh_label == NULL || nh->nh_label->num_labels == 0)
2242 return NULL;
2243
2244 nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, nh->ifindex,
cc1b9746
MS
2245 nh->nh_label->num_labels, nh->nh_label->label,
2246 false /*backup*/);
cd4bb96f
MS
2247
2248 return nhlfe;
2249}
2250
2251/*
2252 * Add a backup NHLFE to an LSP based on a nexthop;
2253 * return the newly-added object.
2254 */
8f74a383 2255struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nh(struct zebra_lsp *lsp,
f2595bd5
DS
2256 enum lsp_types_t lsp_type,
2257 const struct nexthop *nh)
cd4bb96f 2258{
f2595bd5 2259 struct zebra_nhlfe *nhlfe;
cd4bb96f
MS
2260
2261 if (nh->nh_label == NULL || nh->nh_label->num_labels == 0)
2262 return NULL;
2263
cc1b9746 2264 nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate,
cd4bb96f 2265 nh->ifindex, nh->nh_label->num_labels,
cc1b9746 2266 nh->nh_label->label, true);
cd4bb96f
MS
2267
2268 return nhlfe;
2269}
2270
d4cb23d7
MS
2271/*
2272 * Free an allocated NHLFE
2273 */
f2595bd5 2274void zebra_mpls_nhlfe_free(struct zebra_nhlfe *nhlfe)
d4cb23d7
MS
2275{
2276 /* Just a pass-through to the internal implementation */
cd4bb96f 2277 nhlfe_free(nhlfe);
d4cb23d7
MS
2278}
2279
5aba114a
DS
2280/*
2281 * Registration from a client for the label binding for a FEC. If a binding
2282 * already exists, it is informed to the client.
28d58fd7 2283 * NOTE: If there is a manually configured label binding, that is used.
9bedbb1e 2284 * Otherwise, if a label index is specified, it means we have to allocate the
28d58fd7 2285 * label from a locally configured label block (SRGB), if one exists and index
57592a53
AD
2286 * is acceptable. If no label index then just register the specified label.
2287 * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
2288 * by the calling function. Register requests with both will be rejected.
5aba114a 2289 */
d62a17ae 2290int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
57592a53
AD
2291 uint32_t label, uint32_t label_index,
2292 struct zserv *client)
d62a17ae 2293{
2294 struct route_table *table;
60e36561 2295 struct zebra_fec *fec;
57592a53
AD
2296 bool new_client;
2297 bool label_change = false;
d7c0a89a 2298 uint32_t old_label;
57592a53
AD
2299 bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
2300 bool is_configured_fec = false; /* indicate statically configured FEC */
d62a17ae 2301
2302 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2303 if (!table)
2304 return -1;
2305
57592a53
AD
2306 if (label != MPLS_INVALID_LABEL && have_label_index) {
2307 flog_err(
2308 EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
b467b4b4
DS
2309 "Rejecting FEC register for %pFX with both label %u and Label Index %u specified, client %s",
2310 p, label, label_index,
57592a53
AD
2311 zebra_route_string(client->proto));
2312 return -1;
2313 }
2314
d62a17ae 2315 /* Locate FEC */
2316 fec = fec_find(table, p);
2317 if (!fec) {
57592a53 2318 fec = fec_add(table, p, label, 0, label_index);
d62a17ae 2319 if (!fec) {
af4c2728 2320 flog_err(
e914ccbe 2321 EC_ZEBRA_FEC_ADD_FAILED,
b467b4b4
DS
2322 "Failed to add FEC %pFX upon register, client %s",
2323 p, zebra_route_string(client->proto));
d62a17ae 2324 return -1;
2325 }
2326
2327 old_label = MPLS_INVALID_LABEL;
57592a53 2328 new_client = true;
d62a17ae 2329 } else {
57592a53
AD
2330 /* Check if the FEC has been statically defined in the config */
2331 is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
d62a17ae 2332 /* Client may register same FEC with different label index. */
2333 new_client =
2334 (listnode_lookup(fec->client_list, client) == NULL);
57592a53
AD
2335 if (!new_client && fec->label_index == label_index
2336 && fec->label == label)
d62a17ae 2337 /* Duplicate register */
2338 return 0;
2339
57592a53 2340 /* Save current label, update the FEC */
d62a17ae 2341 old_label = fec->label;
2342 fec->label_index = label_index;
2343 }
2344
2345 if (new_client)
2346 listnode_add(fec->client_list, client);
2347
2348 if (IS_ZEBRA_DEBUG_MPLS)
b467b4b4 2349 zlog_debug("FEC %pFX label%s %u %s by client %s%s", p,
57592a53
AD
2350 have_label_index ? " index" : "",
2351 have_label_index ? label_index : label,
2352 new_client ? "registered" : "updated",
2353 zebra_route_string(client->proto),
2354 is_configured_fec
2355 ? ", but using statically configured label"
2356 : "");
2357
2358 /* If not a statically configured FEC, derive the local label
2359 * from label index or use the provided label
d62a17ae 2360 */
57592a53
AD
2361 if (!is_configured_fec) {
2362 if (have_label_index)
2363 fec_derive_label_from_index(zvrf, fec);
2364 else
2365 fec->label = label;
d62a17ae 2366
2367 /* If no label change, exit. */
2368 if (fec->label == old_label)
2369 return 0;
2370
57592a53 2371 label_change = true;
d62a17ae 2372 }
2373
2374 /* If new client or label change, update client and install or uninstall
2375 * label forwarding entry as needed.
2376 */
2377 /* Inform client of label, if needed. */
2378 if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
2379 if (IS_ZEBRA_DEBUG_MPLS)
2380 zlog_debug("Update client label %u", fec->label);
2381 fec_send(fec, client);
2382 }
2383
2384 if (new_client || label_change)
2385 return fec_change_update_lsp(zvrf, fec, old_label);
2386
2387 return 0;
5aba114a
DS
2388}
2389
2390/*
2391 * Deregistration from a client for the label binding for a FEC. The FEC
2392 * itself is deleted if no other registered clients exist and there is no
2393 * label bound to the FEC.
2394 */
d62a17ae 2395int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
2396 struct zserv *client)
5aba114a 2397{
d62a17ae 2398 struct route_table *table;
60e36561 2399 struct zebra_fec *fec;
5aba114a 2400
d62a17ae 2401 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2402 if (!table)
2403 return -1;
5aba114a 2404
d62a17ae 2405 fec = fec_find(table, p);
2406 if (!fec) {
e914ccbe 2407 flog_err(EC_ZEBRA_FEC_RM_FAILED,
2dbe669b
DA
2408 "Failed to find FEC %pFX upon unregister, client %s",
2409 p, zebra_route_string(client->proto));
d62a17ae 2410 return -1;
2411 }
5aba114a 2412
d62a17ae 2413 listnode_delete(fec->client_list, client);
2414
2415 if (IS_ZEBRA_DEBUG_MPLS)
b467b4b4 2416 zlog_debug("FEC %pFX unregistered by client %s", p,
d62a17ae 2417 zebra_route_string(client->proto));
2418
2419 /* If not a configured entry, delete the FEC if no other clients. Before
2420 * deleting, see if any LSP needs to be uninstalled.
2421 */
2422 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2423 && list_isempty(fec->client_list)) {
2424 mpls_label_t old_label = fec->label;
2425 fec->label = MPLS_INVALID_LABEL; /* reset */
2426 fec_change_update_lsp(zvrf, fec, old_label);
2427 fec_del(fec);
2428 }
5aba114a 2429
d62a17ae 2430 return 0;
5aba114a
DS
2431}
2432
2433/*
2434 * Cleanup any FECs registered by this client.
2435 */
453844ab 2436static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
d62a17ae 2437{
453844ab 2438 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
d62a17ae 2439 struct route_node *rn;
60e36561 2440 struct zebra_fec *fec;
d62a17ae 2441 struct listnode *node;
2442 struct zserv *fec_client;
2443 int af;
2444
2445 for (af = AFI_IP; af < AFI_MAX; af++) {
2446 if (zvrf->fec_table[af] == NULL)
2447 continue;
2448
2449 for (rn = route_top(zvrf->fec_table[af]); rn;
2450 rn = route_next(rn)) {
2451 fec = rn->info;
2452 if (!fec || list_isempty(fec->client_list))
2453 continue;
2454
2455 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
2456 fec_client)) {
2457 if (fec_client == client) {
2458 listnode_delete(fec->client_list,
2459 fec_client);
2460 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2461 && list_isempty(fec->client_list))
2462 fec_del(fec);
2463 break;
2464 }
2465 }
2466 }
2467 }
5aba114a 2468
d62a17ae 2469 return 0;
5aba114a
DS
2470}
2471
651105b5
RW
2472struct lsp_uninstall_args {
2473 struct hash *lsp_table;
2474 enum lsp_types_t type;
2475};
2476
2477/*
2478 * Cleanup MPLS labels registered by this client.
2479 */
2480static int zebra_mpls_cleanup_zclient_labels(struct zserv *client)
2481{
2482 struct vrf *vrf;
2483 struct zebra_vrf *zvrf;
2484
2485 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
2486 struct lsp_uninstall_args args;
2487
2488 zvrf = vrf->info;
2489 if (!zvrf)
2490 continue;
2491
2492 /* Cleanup LSPs. */
2493 args.lsp_table = zvrf->lsp_table;
2494 args.type = lsp_type_from_re_type(client->proto);
2495 hash_iterate(zvrf->lsp_table, mpls_lsp_uninstall_all_type,
2496 &args);
2497
2498 /* Cleanup FTNs. */
90a570ed
EDP
2499 mpls_ftn_uninstall_all(zvrf, AFI_IP,
2500 lsp_type_from_re_type(client->proto));
2501 mpls_ftn_uninstall_all(zvrf, AFI_IP6,
2502 lsp_type_from_re_type(client->proto));
651105b5
RW
2503 }
2504
2505 return 0;
2506}
2507
f31e084c
DS
2508/*
2509 * Return FEC (if any) to which this label is bound.
2510 * Note: Only works for per-prefix binding and when the label is not
2511 * implicit-null.
2512 * TODO: Currently walks entire table, can optimize later with another
2513 * hash..
2514 */
60e36561
DS
2515struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
2516 mpls_label_t label)
d62a17ae 2517{
2518 struct route_node *rn;
60e36561 2519 struct zebra_fec *fec;
d62a17ae 2520 int af;
2521
2522 for (af = AFI_IP; af < AFI_MAX; af++) {
2523 if (zvrf->fec_table[af] == NULL)
2524 continue;
2525
2526 for (rn = route_top(zvrf->fec_table[af]); rn;
2527 rn = route_next(rn)) {
2528 if (!rn->info)
2529 continue;
2530 fec = rn->info;
2531 if (fec->label == label)
2532 return fec;
2533 }
2534 }
f31e084c 2535
d62a17ae 2536 return NULL;
f31e084c
DS
2537}
2538
2539/*
2540 * Inform if specified label is currently bound to a FEC or not.
2541 */
d62a17ae 2542int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
f31e084c 2543{
d62a17ae 2544 return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
f31e084c
DS
2545}
2546
2547/*
5aba114a 2548 * Add static FEC to label binding. If there are clients registered for this
a64448ba
DS
2549 * FEC, notify them. If there are labeled routes for this FEC, install the
2550 * label forwarding entry.
9d303b37 2551*/
d62a17ae 2552int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
2553 mpls_label_t in_label)
2554{
2555 struct route_table *table;
60e36561 2556 struct zebra_fec *fec;
d62a17ae 2557 mpls_label_t old_label;
2558 int ret = 0;
2559
2560 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2561 if (!table)
2562 return -1;
2563
d62a17ae 2564 /* Update existing FEC or create a new one. */
2565 fec = fec_find(table, p);
2566 if (!fec) {
2567 fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
2568 MPLS_INVALID_LABEL_INDEX);
2569 if (!fec) {
e914ccbe 2570 flog_err(EC_ZEBRA_FEC_ADD_FAILED,
2dbe669b 2571 "Failed to add FEC %pFX upon config", p);
d62a17ae 2572 return -1;
2573 }
2574
2575 if (IS_ZEBRA_DEBUG_MPLS)
b467b4b4 2576 zlog_debug("Add fec %pFX label %u", p, in_label);
d62a17ae 2577 } else {
2578 fec->flags |= FEC_FLAG_CONFIGURED;
2579 if (fec->label == in_label)
2580 /* Duplicate config */
2581 return 0;
2582
2583 /* Label change, update clients. */
2584 old_label = fec->label;
2585 if (IS_ZEBRA_DEBUG_MPLS)
b467b4b4 2586 zlog_debug("Update fec %pFX new label %u", p, in_label);
d62a17ae 2587
2588 fec->label = in_label;
2589 fec_update_clients(fec);
2590
2591 /* Update label forwarding entries appropriately */
2592 ret = fec_change_update_lsp(zvrf, fec, old_label);
2593 }
2594
2595 return ret;
f31e084c
DS
2596}
2597
2598/*
5aba114a
DS
2599 * Remove static FEC to label binding. If there are no clients registered
2600 * for this FEC, delete the FEC; else notify clients
28d58fd7
VV
2601 * Note: Upon delete of static binding, if label index exists for this FEC,
2602 * client may need to be updated with derived label.
f31e084c 2603 */
d62a17ae 2604int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
2605{
2606 struct route_table *table;
60e36561 2607 struct zebra_fec *fec;
d62a17ae 2608 mpls_label_t old_label;
d62a17ae 2609
2610 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2611 if (!table)
2612 return -1;
2613
2614 fec = fec_find(table, p);
2615 if (!fec) {
e914ccbe 2616 flog_err(EC_ZEBRA_FEC_RM_FAILED,
b467b4b4 2617 "Failed to find FEC %pFX upon delete", p);
d62a17ae 2618 return -1;
2619 }
2620
2621 if (IS_ZEBRA_DEBUG_MPLS) {
2dbe669b 2622 zlog_debug("Delete fec %pFX label %u label index %u", p,
57592a53 2623 fec->label, fec->label_index);
d62a17ae 2624 }
2625
2626 old_label = fec->label;
2627 fec->flags &= ~FEC_FLAG_CONFIGURED;
2628 fec->label = MPLS_INVALID_LABEL;
2629
2630 /* If no client exists, just delete the FEC. */
2631 if (list_isempty(fec->client_list)) {
2632 fec_del(fec);
2633 return 0;
2634 }
2635
2636 /* Derive the local label (from label index) or reset it. */
2637 fec_derive_label_from_index(zvrf, fec);
2638
2639 /* If there is a label change, update clients. */
2640 if (fec->label == old_label)
2641 return 0;
2642 fec_update_clients(fec);
2643
2644 /* Update label forwarding entries appropriately */
2645 return fec_change_update_lsp(zvrf, fec, old_label);
f31e084c
DS
2646}
2647
2648/*
2649 * Display MPLS FEC to label binding configuration (VTY command handler).
2650 */
d62a17ae 2651int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
f31e084c 2652{
d62a17ae 2653 struct route_node *rn;
2654 int af;
60e36561 2655 struct zebra_fec *fec;
d62a17ae 2656 int write = 0;
f31e084c 2657
d62a17ae 2658 for (af = AFI_IP; af < AFI_MAX; af++) {
2659 if (zvrf->fec_table[af] == NULL)
2660 continue;
f31e084c 2661
d62a17ae 2662 for (rn = route_top(zvrf->fec_table[af]); rn;
2663 rn = route_next(rn)) {
2664 if (!rn->info)
2665 continue;
f31e084c 2666
d62a17ae 2667 char lstr[BUFSIZ];
2668 fec = rn->info;
f31e084c 2669
d62a17ae 2670 if (!(fec->flags & FEC_FLAG_CONFIGURED))
2671 continue;
f31e084c 2672
d62a17ae 2673 write = 1;
2dbe669b 2674 vty_out(vty, "mpls label bind %pFX %s\n", &rn->p,
d62a17ae 2675 label2str(fec->label, lstr, BUFSIZ));
2676 }
2677 }
f31e084c 2678
d62a17ae 2679 return write;
f31e084c
DS
2680}
2681
2682/*
2683 * Display MPLS FEC to label binding (VTY command handler).
2684 */
d62a17ae 2685void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
f31e084c 2686{
d62a17ae 2687 struct route_node *rn;
2688 int af;
f31e084c 2689
d62a17ae 2690 for (af = AFI_IP; af < AFI_MAX; af++) {
2691 if (zvrf->fec_table[af] == NULL)
2692 continue;
f31e084c 2693
d62a17ae 2694 for (rn = route_top(zvrf->fec_table[af]); rn;
2695 rn = route_next(rn)) {
2696 if (!rn->info)
2697 continue;
2698 fec_print(rn->info, vty);
2699 }
2700 }
f31e084c
DS
2701}
2702
2703/*
2704 * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2705 */
d62a17ae 2706void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
2707 struct prefix *p)
f31e084c 2708{
d62a17ae 2709 struct route_table *table;
2710 struct route_node *rn;
f31e084c 2711
d62a17ae 2712 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2713 if (!table)
2714 return;
f31e084c 2715
d62a17ae 2716 apply_mask(p);
2717 rn = route_node_lookup(table, p);
2718 if (!rn)
2719 return;
f31e084c 2720
d62a17ae 2721 route_unlock_node(rn);
2722 if (!rn->info)
2723 return;
f31e084c 2724
d62a17ae 2725 fec_print(rn->info, vty);
f31e084c
DS
2726}
2727
f2e7f4eb
MS
2728static void mpls_zebra_nhe_update(struct route_entry *re, afi_t afi,
2729 struct nhg_hash_entry *new_nhe)
19474c9c
SW
2730{
2731 struct nhg_hash_entry *nhe;
2732
f2e7f4eb 2733 nhe = zebra_nhg_rib_find_nhe(new_nhe, afi);
19474c9c 2734
5463ce26 2735 route_entry_update_nhe(re, nhe);
19474c9c
SW
2736}
2737
f2e7f4eb
MS
2738static bool ftn_update_nexthop(bool add_p, struct nexthop *nexthop,
2739 enum lsp_types_t type,
2740 const struct zapi_nexthop *znh)
8f77d0ee 2741{
f2e7f4eb
MS
2742 if (add_p && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2743 nexthop_add_labels(nexthop, type, znh->label_num, znh->labels);
2744 else if (!add_p && nexthop->nh_label_type == type)
8f77d0ee
DS
2745 nexthop_del_labels(nexthop);
2746 else
2747 return false;
2748
2749 return true;
2750}
2751
f2e7f4eb
MS
2752int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2753 struct prefix *prefix, uint8_t route_type,
2754 unsigned short route_instance)
d62a17ae 2755{
2756 struct route_table *table;
2757 struct route_node *rn;
2758 struct route_entry *re;
2759 struct nexthop *nexthop;
f2e7f4eb 2760 struct nhg_hash_entry *new_nhe;
da137142 2761 afi_t afi = family2afi(prefix->family);
d62a17ae 2762
2763 /* Lookup table. */
da137142 2764 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
d62a17ae 2765 if (!table)
2766 return -1;
2767
2768 /* Lookup existing route */
2769 rn = route_node_get(table, prefix);
a2addae8 2770 RNODE_FOREACH_RE (rn, re) {
d62a17ae 2771 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2772 continue;
e132dea0 2773 if (re->type == route_type && re->instance == route_instance)
d62a17ae 2774 break;
88d88a9c 2775 }
d62a17ae 2776 if (re == NULL)
2777 return -1;
2778
da137142 2779 /*
f2e7f4eb
MS
2780 * Nexthops are now shared by multiple routes, so we have to make
2781 * a local copy, modify the copy, then update the route.
da137142 2782 */
f2e7f4eb 2783 new_nhe = zebra_nhe_copy(re->nhe, 0);
da137142 2784
f2e7f4eb
MS
2785 for (nexthop = new_nhe->nhg.nexthop; nexthop; nexthop = nexthop->next)
2786 nexthop_del_labels(nexthop);
2787
2788 /* Update backup routes/nexthops also, if present. */
2789 if (zebra_nhg_get_backup_nhg(new_nhe) != NULL) {
2790 for (nexthop = new_nhe->backup_info->nhe->nhg.nexthop; nexthop;
2791 nexthop = nexthop->next)
2792 nexthop_del_labels(nexthop);
2793 }
2794
2795 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2796 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
2797
68110c42
MS
2798 /* This will create (or ref) a new nhe, so we will discard the local
2799 * temporary nhe
2800 */
f2e7f4eb
MS
2801 mpls_zebra_nhe_update(re, afi, new_nhe);
2802
2803 zebra_nhg_free(new_nhe);
2804
2805 rib_queue_add(rn);
2806
2807 return 0;
2808}
2809
2810/*
2811 * Iterate through a list of nexthops, for a match for 'znh'. If found,
2812 * update its labels according to 'add_p', and return 'true' if successful.
2813 */
2814static bool ftn_update_znh(bool add_p, enum lsp_types_t type,
2815 struct nexthop *head, const struct zapi_nexthop *znh)
2816{
2817 bool found = false, success = false;
2818 struct nexthop *nexthop;
2819
2820 for (nexthop = head; nexthop; nexthop = nexthop->next) {
d62a17ae 2821 switch (nexthop->type) {
2822 case NEXTHOP_TYPE_IPV4:
2823 case NEXTHOP_TYPE_IPV4_IFINDEX:
f2e7f4eb
MS
2824 if (znh->type != NEXTHOP_TYPE_IPV4
2825 && znh->type != NEXTHOP_TYPE_IPV4_IFINDEX)
d62a17ae 2826 continue;
f2e7f4eb
MS
2827 if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4,
2828 &znh->gate.ipv4))
d62a17ae 2829 continue;
2830 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
f2e7f4eb 2831 && nexthop->ifindex != znh->ifindex)
d62a17ae 2832 continue;
f2e7f4eb 2833
8f77d0ee 2834 found = true;
f2e7f4eb
MS
2835
2836 if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2837 break;
2838
2839 success = true;
8f77d0ee 2840 break;
d62a17ae 2841 case NEXTHOP_TYPE_IPV6:
2842 case NEXTHOP_TYPE_IPV6_IFINDEX:
f2e7f4eb
MS
2843 if (znh->type != NEXTHOP_TYPE_IPV6
2844 && znh->type != NEXTHOP_TYPE_IPV6_IFINDEX)
d62a17ae 2845 continue;
f2e7f4eb
MS
2846 if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6,
2847 &znh->gate.ipv6))
d62a17ae 2848 continue;
2849 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
f2e7f4eb 2850 && nexthop->ifindex != znh->ifindex)
d62a17ae 2851 continue;
f2e7f4eb 2852
8f77d0ee 2853 found = true;
f2e7f4eb
MS
2854
2855 if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2856 break;
2857 success = true;
8f77d0ee 2858 break;
10cc80ca 2859 case NEXTHOP_TYPE_IFINDEX:
a44e3106
MS
2860 if (znh->type != NEXTHOP_TYPE_IFINDEX)
2861 continue;
2862 if (nexthop->ifindex != znh->ifindex)
2863 continue;
2864
2865 found = true;
2866
2867 if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2868 break;
2869 success = true;
d62a17ae 2870 break;
a44e3106
MS
2871 case NEXTHOP_TYPE_BLACKHOLE:
2872 /* Not valid */
2873 continue;
d62a17ae 2874 }
f2e7f4eb
MS
2875
2876 if (found)
2877 break;
d62a17ae 2878 }
d62a17ae 2879
f2e7f4eb
MS
2880 return success;
2881}
19474c9c 2882
f2e7f4eb
MS
2883/*
2884 * Install/uninstall LSP and (optionally) FEC-To-NHLFE (FTN) bindings,
2885 * using zapi message info.
2886 * There are several changes that need to be made, in several zebra
2887 * data structures, so we want to do all the work required at once.
2888 */
2889int mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
2890 const struct zapi_labels *zl)
2891{
2892 int i, counter, ret = 0;
2dbe669b 2893 char buf[NEXTHOP_STRLEN];
f2e7f4eb
MS
2894 const struct zapi_nexthop *znh;
2895 struct route_table *table;
2896 struct route_node *rn = NULL;
2897 struct route_entry *re = NULL;
2898 struct nhg_hash_entry *new_nhe = NULL;
2899 bool found;
2900 afi_t afi = AFI_IP;
2901 const struct prefix *prefix = NULL;
2902 struct hash *lsp_table;
a7d2146a 2903 struct zebra_ile tmp_ile;
8f74a383 2904 struct zebra_lsp *lsp = NULL;
19474c9c 2905
f2e7f4eb
MS
2906 /* Prep LSP for add case */
2907 if (add_p) {
2908 /* Lookup table. */
2909 lsp_table = zvrf->lsp_table;
2910 if (!lsp_table)
2911 return -1;
2912
2913 /* Find or create LSP object */
2914 tmp_ile.in_label = zl->local_label;
2915 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2916 if (!lsp)
2917 return -1;
da137142
SW
2918 }
2919
f2e7f4eb
MS
2920 /* Prep for route/FEC update if requested */
2921 if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
2922 prefix = &zl->route.prefix;
da137142 2923
f2e7f4eb 2924 afi = family2afi(prefix->family);
ce549947 2925
f2e7f4eb
MS
2926 /* Lookup table. */
2927 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2928 if (table) {
2929 /* Lookup existing route */
2930 rn = route_node_get(table, prefix);
2931 RNODE_FOREACH_RE(rn, re) {
2932 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2933 continue;
2934 if (re->type == zl->route.type &&
2935 re->instance == zl->route.instance)
2936 break;
2937 }
2938 }
ea6b290b 2939
f2e7f4eb
MS
2940 if (re) {
2941 /*
2942 * Copy over current nexthops into a temporary group.
2943 * We can't just change the values here since the nhgs
2944 * are shared and if the labels change, we'll need
2945 * to find or create a new nhg. We need to create
2946 * a whole temporary group, make changes to it,
2947 * then attach that to the route.
2948 */
2949 new_nhe = zebra_nhe_copy(re->nhe, 0);
ea6b290b 2950
f2e7f4eb
MS
2951 } else {
2952 /*
2953 * The old version of the zapi code
2954 * attempted to manage LSPs before trying to
2955 * find a route/FEC, so we'll continue that way.
2956 */
2dbe669b
DA
2957 if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS)
2958 zlog_debug(
2959 "%s: FTN update requested: no route for prefix %pFX",
2960 __func__, prefix);
f2e7f4eb
MS
2961 }
2962 }
2963
2964 /*
2965 * Use info from the zapi nexthops to add/replace/remove LSP/FECs
2966 */
2967
2968 counter = 0;
2969 for (i = 0; i < zl->nexthop_num; i++) {
2970
2971 znh = &zl->nexthops[i];
2972
2973 /* Attempt LSP update */
2974 if (add_p)
2975 ret = lsp_znh_install(lsp, zl->type, znh);
2976 else
2977 ret = mpls_lsp_uninstall(zvrf, zl->type,
2978 zl->local_label, znh->type,
cc1b9746
MS
2979 &znh->gate, znh->ifindex,
2980 false);
f2e7f4eb
MS
2981 if (ret < 0) {
2982 if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS) {
2983 zapi_nexthop2str(znh, buf, sizeof(buf));
2984 zlog_debug("%s: Unable to %sinstall LSP: label %u, znh %s",
2985 __func__, (add_p ? "" : "un"),
2986 zl->local_label, buf);
2987 }
ea6b290b 2988 continue;
f2e7f4eb
MS
2989 }
2990
2991 /* Attempt route/FEC update if requested */
2992 if (re == NULL)
2993 continue;
2994
2995 /* Search the route's nexthops for a match, and update it. */
2996 found = ftn_update_znh(add_p, zl->type, new_nhe->nhg.nexthop,
2997 znh);
2998 if (found) {
2999 counter++;
3000 } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
3001 zapi_nexthop2str(znh, buf, sizeof(buf));
2dbe669b
DA
3002 zlog_debug(
3003 "%s: Unable to update FEC: prefix %pFX, label %u, znh %s",
3004 __func__, prefix, zl->local_label, buf);
f2e7f4eb 3005 }
ea6b290b 3006 }
ea6b290b 3007
f2e7f4eb
MS
3008 /*
3009 * Process backup LSPs/nexthop entries also. We associate backup
3010 * LSP info with backup nexthops.
3011 */
3012 if (!CHECK_FLAG(zl->message, ZAPI_LABELS_HAS_BACKUPS))
3013 goto znh_done;
19474c9c 3014
f2e7f4eb 3015 for (i = 0; i < zl->backup_nexthop_num; i++) {
ea6b290b 3016
f2e7f4eb 3017 znh = &zl->backup_nexthops[i];
19474c9c 3018
f2e7f4eb
MS
3019 if (add_p)
3020 ret = lsp_backup_znh_install(lsp, zl->type, znh);
3021 else
cc1b9746
MS
3022 ret = mpls_lsp_uninstall(zvrf, zl->type,
3023 zl->local_label,
3024 znh->type, &znh->gate,
3025 znh->ifindex, true);
f2e7f4eb
MS
3026
3027 if (ret < 0) {
3028 if (IS_ZEBRA_DEBUG_RECV ||
3029 IS_ZEBRA_DEBUG_MPLS) {
3030 zapi_nexthop2str(znh, buf, sizeof(buf));
3031 zlog_debug("%s: Unable to %sinstall backup LSP: label %u, znh %s",
3032 __func__, (add_p ? "" : "un"),
3033 zl->local_label, buf);
3034 }
3035 continue;
3036 }
19474c9c 3037
f2e7f4eb
MS
3038 /* Attempt backup nexthop/FEC update if requested */
3039 if (re == NULL || zebra_nhg_get_backup_nhg(new_nhe) == NULL)
3040 continue;
19474c9c 3041
f2e7f4eb
MS
3042 /* Search the route's backup nexthops for a match
3043 * and update it.
3044 */
3045 found = ftn_update_znh(add_p, zl->type,
3046 new_nhe->backup_info->nhe->nhg.nexthop,
3047 znh);
3048 if (found) {
3049 counter++;
3050 } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
3051 zapi_nexthop2str(znh, buf, sizeof(buf));
2dbe669b
DA
3052 zlog_debug(
3053 "%s: Unable to update backup FEC: prefix %pFX, label %u, znh %s",
3054 __func__, prefix, zl->local_label, buf);
f2e7f4eb
MS
3055 }
3056 }
ea6b290b 3057
f2e7f4eb
MS
3058znh_done:
3059
3060 /*
3061 * If we made changes, update the route, and schedule it
3062 * for rib processing
3063 */
3064 if (re != NULL && counter > 0) {
3065 assert(rn != NULL);
3066
3067 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
3068 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
3069
3070 mpls_zebra_nhe_update(re, afi, new_nhe);
3071
3072 rib_queue_add(rn);
3073 }
3074
3075 if (new_nhe)
3076 zebra_nhg_free(new_nhe);
3077
3078 return ret;
ea6b290b
RW
3079}
3080
ce549947
RW
3081/*
3082 * Install/update a NHLFE for an LSP in the forwarding table. This may be
3083 * a new LSP entry or a new NHLFE for an existing in-label or an update of
3084 * the out-label for an existing NHLFE (update case).
3085 */
f2595bd5 3086static struct zebra_nhlfe *
8f74a383
DS
3087lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type,
3088 uint8_t num_out_labels, const mpls_label_t *out_labels,
3089 enum nexthop_types_t gtype, const union g_addr *gate,
3090 ifindex_t ifindex, bool is_backup)
d62a17ae 3091{
f2595bd5 3092 struct zebra_nhlfe *nhlfe;
cd4bb96f 3093 char buf[MPLS_LABEL_STRLEN];
cc1b9746 3094 const char *backup_str;
e4a1ec74 3095
cc1b9746
MS
3096 if (is_backup) {
3097 nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
3098 gate, ifindex);
3099 backup_str = "backup ";
d62a17ae 3100 } else {
cc1b9746
MS
3101 nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
3102 ifindex);
3103 backup_str = "";
d62a17ae 3104 }
3105
cd4bb96f
MS
3106 if (nhlfe) {
3107 struct nexthop *nh = nhlfe->nexthop;
3108
3109 assert(nh);
3110 assert(nh->nh_label);
3111
3112 /* Clear deleted flag (in case it was set) */
3113 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
3114 if (nh->nh_label->num_labels == num_out_labels
3115 && !memcmp(nh->nh_label->label, out_labels,
3116 sizeof(mpls_label_t) * num_out_labels))
3117 /* No change */
3118 return nhlfe;
3119
3120 if (IS_ZEBRA_DEBUG_MPLS) {
3121 char buf2[MPLS_LABEL_STRLEN];
3122 char buf3[MPLS_LABEL_STRLEN];
3123
3124 nhlfe2str(nhlfe, buf, sizeof(buf));
3125 mpls_label2str(num_out_labels, out_labels, buf2,
3126 sizeof(buf2), 0);
3127 mpls_label2str(nh->nh_label->num_labels,
3128 nh->nh_label->label, buf3, sizeof(buf3),
3129 0);
3130
cc1b9746
MS
3131 zlog_debug("LSP in-label %u type %d %snexthop %s out-label(s) changed to %s (old %s)",
3132 lsp->ile.in_label, type, backup_str, buf,
3133 buf2, buf3);
cd4bb96f
MS
3134 }
3135
3136 /* Update out label(s), trigger processing. */
3137 if (nh->nh_label->num_labels == num_out_labels)
3138 memcpy(nh->nh_label->label, out_labels,
3139 sizeof(mpls_label_t) * num_out_labels);
3140 else {
3141 nexthop_del_labels(nh);
3142 nexthop_add_labels(nh, type, num_out_labels,
3143 out_labels);
3144 }
3145 } else {
3146 /* Add LSP entry to this nexthop */
cc1b9746
MS
3147 nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex,
3148 num_out_labels, out_labels, is_backup);
cd4bb96f
MS
3149 if (!nhlfe)
3150 return NULL;
3151
3152 if (IS_ZEBRA_DEBUG_MPLS) {
3153 char buf2[MPLS_LABEL_STRLEN];
3154
3155 nhlfe2str(nhlfe, buf, sizeof(buf));
3156 mpls_label2str(num_out_labels, out_labels, buf2,
3157 sizeof(buf2), 0);
3158
cc1b9746
MS
3159 zlog_debug("Add LSP in-label %u type %d %snexthop %s out-label(s) %s",
3160 lsp->ile.in_label, type, backup_str, buf,
3161 buf2);
cd4bb96f
MS
3162 }
3163
3164 lsp->addr_family = NHLFE_FAMILY(nhlfe);
3165 }
3166
3167 /* Mark NHLFE, queue LSP for processing. */
3168 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
3169
3170 return nhlfe;
3171}
3172
3173/*
3174 * Install an LSP and forwarding entry; used primarily
301a687a 3175 * from vrf zapi message processing.
cd4bb96f
MS
3176 */
3177int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
3178 mpls_label_t in_label, uint8_t num_out_labels,
3179 const mpls_label_t *out_labels, enum nexthop_types_t gtype,
3180 const union g_addr *gate, ifindex_t ifindex)
3181{
3182 struct hash *lsp_table;
a7d2146a 3183 struct zebra_ile tmp_ile;
8f74a383 3184 struct zebra_lsp *lsp;
f2595bd5 3185 struct zebra_nhlfe *nhlfe;
cd4bb96f
MS
3186
3187 /* Lookup table. */
3188 lsp_table = zvrf->lsp_table;
3189 if (!lsp_table)
3190 return -1;
3191
3192 /* Find or create LSP object */
3193 tmp_ile.in_label = in_label;
3194 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
3195 if (!lsp)
3196 return -1;
3197
3198 nhlfe = lsp_add_nhlfe(lsp, type, num_out_labels, out_labels, gtype,
cc1b9746 3199 gate, ifindex, false /*backup*/);
cd4bb96f
MS
3200 if (nhlfe == NULL)
3201 return -1;
3202
3203 /* Queue LSP for processing. */
3204 if (lsp_processq_add(lsp))
3205 return -1;
3206
3207 return 0;
3208}
3209
3210/*
3211 * Install or replace NHLFE, using info from zapi nexthop
3212 */
8f74a383 3213static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
f2e7f4eb 3214 const struct zapi_nexthop *znh)
cd4bb96f 3215{
f2595bd5 3216 struct zebra_nhlfe *nhlfe;
cd4bb96f 3217
cd4bb96f 3218 nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels,
cc1b9746
MS
3219 znh->type, &znh->gate, znh->ifindex,
3220 false /*backup*/);
cd4bb96f
MS
3221 if (nhlfe == NULL)
3222 return -1;
3223
3224 /* Update backup info if present */
3225 if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
474aebd9
MS
3226 if (znh->backup_num > NEXTHOP_MAX_BACKUPS) {
3227 nhlfe_del(nhlfe);
3228 return -1;
3229 }
3230
3231 nhlfe->nexthop->backup_num = znh->backup_num;
3232 memcpy(nhlfe->nexthop->backup_idx, znh->backup_idx,
3233 znh->backup_num);
cd4bb96f 3234 SET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
301a687a
MS
3235 } else {
3236 /* Ensure there's no stale backup info */
3237 UNSET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
3238 nhlfe->nexthop->backup_num = 0;
cd4bb96f
MS
3239 }
3240
3241 /* Queue LSP for processing. */
3242 if (lsp_processq_add(lsp))
3243 return -1;
3244
3245 return 0;
3246}
3247
3248/*
3249 * Install/update backup NHLFE for an LSP, using info from a zapi message.
3250 */
8f74a383 3251static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
f2e7f4eb 3252 const struct zapi_nexthop *znh)
cd4bb96f 3253{
f2595bd5 3254 struct zebra_nhlfe *nhlfe;
cd4bb96f 3255
cc1b9746
MS
3256 nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num,
3257 znh->labels, znh->type, &znh->gate,
3258 znh->ifindex, true /*backup*/);
cd4bb96f
MS
3259 if (nhlfe == NULL) {
3260 if (IS_ZEBRA_DEBUG_MPLS)
3261 zlog_debug("%s: unable to add backup nhlfe, label: %u",
f2e7f4eb 3262 __func__, lsp->ile.in_label);
cd4bb96f
MS
3263 return -1;
3264 }
3265
3266 /* Queue LSP for processing. */
d62a17ae 3267 if (lsp_processq_add(lsp))
3268 return -1;
3269
3270 return 0;
ce549947
RW
3271}
3272
8f74a383 3273struct zebra_lsp *mpls_lsp_find(struct zebra_vrf *zvrf, mpls_label_t in_label)
31f937fb
SM
3274{
3275 struct hash *lsp_table;
a7d2146a 3276 struct zebra_ile tmp_ile;
31f937fb
SM
3277
3278 /* Lookup table. */
3279 lsp_table = zvrf->lsp_table;
3280 if (!lsp_table)
3281 return NULL;
3282
3283 /* If entry is not present, exit. */
3284 tmp_ile.in_label = in_label;
3285 return hash_lookup(lsp_table, &tmp_ile);
3286}
3287
ce549947
RW
3288/*
3289 * Uninstall a particular NHLFE in the forwarding table. If this is
3290 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
3291 */
d62a17ae 3292int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
3293 mpls_label_t in_label, enum nexthop_types_t gtype,
cc1b9746
MS
3294 const union g_addr *gate, ifindex_t ifindex,
3295 bool backup_p)
d62a17ae 3296{
3297 struct hash *lsp_table;
a7d2146a 3298 struct zebra_ile tmp_ile;
8f74a383 3299 struct zebra_lsp *lsp;
f2595bd5 3300 struct zebra_nhlfe *nhlfe;
cc1b9746 3301 char buf[NEXTHOP_STRLEN];
4a2a5236 3302 bool schedule_lsp = false;
d62a17ae 3303
3304 /* Lookup table. */
3305 lsp_table = zvrf->lsp_table;
3306 if (!lsp_table)
3307 return -1;
3308
3309 /* If entry is not present, exit. */
3310 tmp_ile.in_label = in_label;
3311 lsp = hash_lookup(lsp_table, &tmp_ile);
3312 if (!lsp)
3313 return 0;
cc1b9746
MS
3314
3315 if (backup_p)
3316 nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
3317 gate, ifindex);
3318 else
3319 nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
3320 ifindex);
d62a17ae 3321 if (!nhlfe)
3322 return 0;
3323
3324 if (IS_ZEBRA_DEBUG_MPLS) {
43a9f66c 3325 nhlfe2str(nhlfe, buf, sizeof(buf));
d62a17ae 3326 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
3327 in_label, type, buf, nhlfe->flags);
3328 }
3329
4a2a5236
MS
3330 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ||
3331 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
3332 schedule_lsp = true;
3333
d62a17ae 3334 /* Mark NHLFE for delete or directly delete, as appropriate. */
4a2a5236 3335 if (schedule_lsp) {
d62a17ae 3336 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
4a2a5236
MS
3337 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
3338
3339 if (IS_ZEBRA_DEBUG_MPLS)
3340 zlog_debug("Schedule LSP in-label %u flags 0x%x",
3341 lsp->ile.in_label, lsp->flags);
d62a17ae 3342 if (lsp_processq_add(lsp))
3343 return -1;
3344 } else {
3345 nhlfe_del(nhlfe);
3346
3347 /* Free LSP entry if no other NHLFEs and not scheduled. */
f2e7f4eb 3348 lsp_check_free(lsp_table, &lsp);
d62a17ae 3349 }
3350 return 0;
ce549947
RW
3351}
3352
ea6b290b
RW
3353int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
3354 mpls_label_t in_label)
3355{
3356 struct hash *lsp_table;
a7d2146a 3357 struct zebra_ile tmp_ile;
8f74a383 3358 struct zebra_lsp *lsp;
ea6b290b
RW
3359
3360 /* Lookup table. */
3361 lsp_table = zvrf->lsp_table;
3362 if (!lsp_table)
3363 return -1;
3364
3365 /* If entry is not present, exit. */
3366 tmp_ile.in_label = in_label;
3367 lsp = hash_lookup(lsp_table, &tmp_ile);
3368 if (!lsp)
3369 return 0;
3370
3371 return mpls_lsp_uninstall_all(lsp_table, lsp, type);
3372}
3373
ce549947 3374/*
651105b5 3375 * Uninstall all NHLFEs for a particular LSP forwarding entry.
ce549947
RW
3376 * If no other NHLFEs exist, the entry would be deleted.
3377 */
651105b5 3378static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt)
ce549947 3379{
651105b5 3380 struct lsp_uninstall_args *args = ctxt;
8f74a383 3381 struct zebra_lsp *lsp;
d62a17ae 3382 struct hash *lsp_table;
ce549947 3383
8f74a383 3384 lsp = (struct zebra_lsp *)bucket->data;
ee70f629 3385 if (nhlfe_list_first(&lsp->nhlfe_list) == NULL)
d62a17ae 3386 return;
ce549947 3387
651105b5 3388 lsp_table = args->lsp_table;
d62a17ae 3389 if (!lsp_table)
3390 return;
ce549947 3391
651105b5 3392 mpls_lsp_uninstall_all(lsp_table, lsp, args->type);
ce549947
RW
3393}
3394
3395/*
651105b5
RW
3396 * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and
3397 * LSP type.
ce549947 3398 */
651105b5
RW
3399static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
3400 int afi, enum lsp_types_t lsp_type)
d62a17ae 3401{
3402 struct route_table *table;
3403 struct route_node *rn;
3404 struct route_entry *re;
3405 struct nexthop *nexthop;
f2e7f4eb
MS
3406 struct nexthop_group *nhg;
3407 bool update;
d62a17ae 3408
3409 /* Process routes of interested address-families. */
3410 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
3411 if (!table)
3412 return;
3413
3414 for (rn = route_top(table); rn; rn = route_next(rn)) {
f2e7f4eb
MS
3415 update = false;
3416
a2addae8 3417 RNODE_FOREACH_RE (rn, re) {
f2e7f4eb 3418 struct nhg_hash_entry *new_nhe;
da137142 3419
f2e7f4eb 3420 new_nhe = zebra_nhe_copy(re->nhe, 0);
da137142 3421
f2e7f4eb
MS
3422 nhg = &new_nhe->nhg;
3423 for (nexthop = nhg->nexthop; nexthop;
407c87a6 3424 nexthop = nexthop->next) {
651105b5 3425 if (nexthop->nh_label_type != lsp_type)
407c87a6
DS
3426 continue;
3427
d62a17ae 3428 nexthop_del_labels(nexthop);
3429 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
3430 SET_FLAG(re->status,
332ad713 3431 ROUTE_ENTRY_LABELS_CHANGED);
f2e7f4eb
MS
3432 update = true;
3433 }
3434
3435 /* Check for backup info and update that also */
3436 nhg = zebra_nhg_get_backup_nhg(new_nhe);
3437 if (nhg != NULL) {
3438 for (nexthop = nhg->nexthop; nexthop;
3439 nexthop = nexthop->next) {
3440 if (nexthop->nh_label_type != lsp_type)
3441 continue;
3442
3443 nexthop_del_labels(nexthop);
3444 SET_FLAG(re->status,
3445 ROUTE_ENTRY_CHANGED);
3446 SET_FLAG(re->status,
3447 ROUTE_ENTRY_LABELS_CHANGED);
3448 update = true;
3449 }
d62a17ae 3450 }
da137142 3451
19474c9c 3452 if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
f2e7f4eb 3453 mpls_zebra_nhe_update(re, afi, new_nhe);
da137142 3454
f2e7f4eb 3455 zebra_nhg_free(new_nhe);
407c87a6 3456 }
d62a17ae 3457
3458 if (update)
3459 rib_queue_add(rn);
3460 }
ce549947
RW
3461}
3462
1c1cf002 3463#if defined(HAVE_CUMULUS)
7758e3f3 3464/*
3465 * Check that the label values used in LSP creation are consistent. The
3466 * main criteria is that if there is ECMP, the label operation must still
3467 * be consistent - i.e., all paths either do a swap or do PHP. This is due
3468 * to current HW restrictions.
3469 */
d62a17ae 3470int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
3471 mpls_label_t in_label,
3472 mpls_label_t out_label,
3473 enum nexthop_types_t gtype,
3474 union g_addr *gate, ifindex_t ifindex)
3475{
3476 struct hash *slsp_table;
a7d2146a 3477 struct zebra_ile tmp_ile;
8f74a383 3478 struct zebra_lsp *lsp;
f2595bd5 3479 struct zebra_nhlfe *nhlfe;
608a57c0 3480 const struct nexthop *nh;
d62a17ae 3481
3482 /* Lookup table. */
3483 slsp_table = zvrf->slsp_table;
3484 if (!slsp_table)
3485 return 0;
3486
3487 /* If entry is not present, exit. */
3488 tmp_ile.in_label = in_label;
608a57c0
MS
3489 lsp = hash_lookup(slsp_table, &tmp_ile);
3490 if (!lsp)
d62a17ae 3491 return 1;
3492
608a57c0
MS
3493 nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
3494 gtype, gate, ifindex);
3495 if (nhlfe) {
3496 nh = nhlfe->nexthop;
3497
3498 if (nh == NULL || nh->nh_label == NULL)
3499 return 0;
3500
3501 if (nh->nh_label->label[0] == out_label)
d62a17ae 3502 return 1;
3503
3504 /* If not only NHLFE, cannot allow label change. */
608a57c0
MS
3505 if (nhlfe != nhlfe_list_first(&lsp->nhlfe_list) ||
3506 nhlfe_list_next(&lsp->nhlfe_list, nhlfe) != NULL)
d62a17ae 3507 return 0;
3508 } else {
3509 /* If other NHLFEs exist, label operation must match. */
608a57c0
MS
3510 nhlfe = nhlfe_list_first(&lsp->nhlfe_list);
3511 if (nhlfe != NULL) {
d62a17ae 3512 int cur_op, new_op;
3513
608a57c0
MS
3514 nh = nhlfe->nexthop;
3515
3516 if (nh == NULL || nh->nh_label == NULL)
3517 return 0;
3518
3519 cur_op = (nh->nh_label->label[0] ==
ee70f629 3520 MPLS_LABEL_IMPLICIT_NULL);
70e98a7f 3521 new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
d62a17ae 3522 if (cur_op != new_op)
3523 return 0;
3524 }
3525 }
3526
3527 /* Label values are good. */
3528 return 1;
7758e3f3 3529}
1c1cf002 3530#endif /* HAVE_CUMULUS */
7758e3f3 3531
3532/*
3533 * Add static LSP entry. This may be the first entry for this incoming label
3534 * or an additional nexthop; an existing entry may also have outgoing label
3535 * changed.
3536 * Note: The label operation (swap or PHP) is common for the LSP entry (all
3537 * NHLFEs).
3538 */
d62a17ae 3539int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
3540 mpls_label_t out_label,
3541 enum nexthop_types_t gtype, union g_addr *gate,
3542 ifindex_t ifindex)
3543{
3544 struct hash *slsp_table;
a7d2146a 3545 struct zebra_ile tmp_ile;
8f74a383 3546 struct zebra_lsp *lsp;
f2595bd5 3547 struct zebra_nhlfe *nhlfe;
d62a17ae 3548 char buf[BUFSIZ];
3549
3550 /* Lookup table. */
3551 slsp_table = zvrf->slsp_table;
3552 if (!slsp_table)
3553 return -1;
3554
e4a1ec74 3555 /* Find or create LSP. */
d62a17ae 3556 tmp_ile.in_label = in_label;
608a57c0
MS
3557 lsp = hash_get(slsp_table, &tmp_ile, lsp_alloc);
3558 if (!lsp)
d62a17ae 3559 return -1;
e4a1ec74 3560
608a57c0
MS
3561 nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC, gtype, gate,
3562 ifindex);
3563 if (nhlfe) {
3564 struct nexthop *nh = nhlfe->nexthop;
3565
3566 assert(nh);
3567 assert(nh->nh_label);
3568
3569 /* Compare existing nexthop */
3570 if (nh->nh_label->num_labels == 1 &&
3571 nh->nh_label->label[0] == out_label)
d62a17ae 3572 /* No change */
3573 return 0;
3574
3575 if (IS_ZEBRA_DEBUG_MPLS) {
608a57c0 3576 nhlfe2str(nhlfe, buf, sizeof(buf));
d62a17ae 3577 zlog_debug(
3efd0893 3578 "Upd static LSP in-label %u nexthop %s out-label %u (old %u)",
608a57c0
MS
3579 in_label, buf, out_label,
3580 nh->nh_label->label[0]);
3581 }
3582 if (nh->nh_label->num_labels == 1)
3583 nh->nh_label->label[0] = out_label;
3584 else {
3585 nexthop_del_labels(nh);
3586 nexthop_add_labels(nh, ZEBRA_LSP_STATIC, 1, &out_label);
d62a17ae 3587 }
608a57c0 3588
d62a17ae 3589 } else {
3590 /* Add static LSP entry to this nexthop */
608a57c0
MS
3591 nhlfe = nhlfe_add(lsp, ZEBRA_LSP_STATIC, gtype, gate,
3592 ifindex, 1, &out_label, false /*backup*/);
3593 if (!nhlfe)
d62a17ae 3594 return -1;
3595
3596 if (IS_ZEBRA_DEBUG_MPLS) {
608a57c0 3597 nhlfe2str(nhlfe, buf, sizeof(buf));
d62a17ae 3598 zlog_debug(
3599 "Add static LSP in-label %u nexthop %s out-label %u",
3600 in_label, buf, out_label);
3601 }
3602 }
3603
3604 /* (Re)Install LSP in the main table. */
5065db0a
RW
3605 if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, 1, &out_label,
3606 gtype, gate, ifindex))
d62a17ae 3607 return -1;
3608
3609 return 0;
7758e3f3 3610}
3611
3612/*
3613 * Delete static LSP entry. This may be the delete of one particular
3614 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
3615 * all NHLFEs).
3616 * NOTE: Delete of the only NHLFE will also end up deleting the entire
3617 * LSP configuration.
3618 */
d62a17ae 3619int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
3620 enum nexthop_types_t gtype, union g_addr *gate,
3621 ifindex_t ifindex)
3622{
3623 struct hash *slsp_table;
a7d2146a 3624 struct zebra_ile tmp_ile;
8f74a383 3625 struct zebra_lsp *lsp;
f2595bd5 3626 struct zebra_nhlfe *nhlfe;
d62a17ae 3627
3628 /* Lookup table. */
3629 slsp_table = zvrf->slsp_table;
3630 if (!slsp_table)
3631 return -1;
3632
3633 /* If entry is not present, exit. */
3634 tmp_ile.in_label = in_label;
608a57c0
MS
3635 lsp = hash_lookup(slsp_table, &tmp_ile);
3636 if (!lsp)
d62a17ae 3637 return 0;
3638
3639 /* Is it delete of entire LSP or a specific NHLFE? */
3640 if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
3641 if (IS_ZEBRA_DEBUG_MPLS)
3642 zlog_debug("Del static LSP in-label %u", in_label);
3643
3644 /* Uninstall entire LSP from the main table. */
3645 mpls_static_lsp_uninstall_all(zvrf, in_label);
3646
3647 /* Delete all static NHLFEs */
608a57c0
MS
3648 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3649 nhlfe_del(nhlfe);
3650 }
d62a17ae 3651 } else {
3652 /* Find specific NHLFE, exit if not found. */
608a57c0
MS
3653 nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
3654 gtype, gate, ifindex);
3655 if (!nhlfe)
d62a17ae 3656 return 0;
3657
3658 if (IS_ZEBRA_DEBUG_MPLS) {
3659 char buf[BUFSIZ];
608a57c0 3660 nhlfe2str(nhlfe, buf, sizeof(buf));
d62a17ae 3661 zlog_debug("Del static LSP in-label %u nexthop %s",
3662 in_label, buf);
3663 }
3664
3665 /* Uninstall LSP from the main table. */
3666 mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
cc1b9746 3667 gate, ifindex, false);
d62a17ae 3668
3669 /* Delete static LSP NHLFE */
608a57c0 3670 nhlfe_del(nhlfe);
d62a17ae 3671 }
3672
3673 /* Remove entire static LSP entry if no NHLFE - valid in either case
608a57c0
MS
3674 * above.
3675 */
3676 if (nhlfe_list_first(&lsp->nhlfe_list) == NULL) {
3677 lsp = hash_release(slsp_table, &tmp_ile);
3678 XFREE(MTYPE_LSP, lsp);
d62a17ae 3679 }
3680
3681 return 0;
7758e3f3 3682}
3683
40c7bdb0 3684/*
3685 * Schedule all MPLS label forwarding entries for processing.
3686 * Called upon changes that may affect one or more of them such as
3687 * interface or nexthop state changes.
3688 */
d62a17ae 3689void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
40c7bdb0 3690{
d62a17ae 3691 if (!zvrf)
3692 return;
3693 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
40c7bdb0 3694}
3695
3ab18ff2 3696/*
3697 * Display MPLS label forwarding table for a specific LSP
3698 * (VTY command handler).
3699 */
d62a17ae 3700void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
9f049418 3701 mpls_label_t label, bool use_json)
3ab18ff2 3702{
d62a17ae 3703 struct hash *lsp_table;
8f74a383 3704 struct zebra_lsp *lsp;
a7d2146a 3705 struct zebra_ile tmp_ile;
d62a17ae 3706 json_object *json = NULL;
3ab18ff2 3707
d62a17ae 3708 /* Lookup table. */
3709 lsp_table = zvrf->lsp_table;
3710 if (!lsp_table)
3711 return;
3ab18ff2 3712
d62a17ae 3713 /* If entry is not present, exit. */
3714 tmp_ile.in_label = label;
3715 lsp = hash_lookup(lsp_table, &tmp_ile);
3716 if (!lsp)
3717 return;
3ab18ff2 3718
d62a17ae 3719 if (use_json) {
3720 json = lsp_json(lsp);
9d303b37
DL
3721 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3722 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 3723 json_object_free(json);
3724 } else
a29c2887 3725 lsp_print(vty, lsp);
3ab18ff2 3726}
3727
3728/*
3729 * Display MPLS label forwarding table (VTY command handler).
3730 */
d62a17ae 3731void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
9f049418 3732 bool use_json)
d62a17ae 3733{
3734 char buf[BUFSIZ];
3735 json_object *json = NULL;
8f74a383 3736 struct zebra_lsp *lsp = NULL;
f2595bd5 3737 struct zebra_nhlfe *nhlfe = NULL;
d62a17ae 3738 struct listnode *node = NULL;
3739 struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
3740
3741 if (use_json) {
3742 json = json_object_new_object();
3743
3744 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
3745 json_object_object_add(
43a9f66c
MS
3746 json, label2str(lsp->ile.in_label, buf,
3747 sizeof(buf)),
d62a17ae 3748 lsp_json(lsp));
3749
9d303b37
DL
3750 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3751 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 3752 json_object_free(json);
3753 } else {
a971aeb6
RW
3754 struct ttable *tt;
3755
3756 /* Prepare table. */
3757 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3758 ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label");
3759 tt->style.cell.rpad = 2;
3760 tt->style.corner = '+';
3761 ttable_restyle(tt);
3762 ttable_rowseps(tt, 0, BOTTOM, true, '-');
d62a17ae 3763
3764 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
ee70f629 3765 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
a971aeb6
RW
3766 struct nexthop *nexthop;
3767 const char *out_label_str;
3768 char nh_buf[NEXTHOP_STRLEN];
3769
d62a17ae 3770 nexthop = nhlfe->nexthop;
3771
3772 switch (nexthop->type) {
996c9314 3773 case NEXTHOP_TYPE_IFINDEX: {
86f07f44 3774 struct zebra_ns *zns;
b9abd9ad
DS
3775 struct interface *ifp;
3776
86f07f44
PG
3777 zns = zebra_ns_lookup(NS_DEFAULT);
3778 ifp = if_lookup_by_index_per_ns(
a971aeb6
RW
3779 zns, nexthop->ifindex);
3780 snprintf(nh_buf, sizeof(nh_buf), "%s",
3781 ifp ? ifp->name : "Null");
b9abd9ad
DS
3782 break;
3783 }
d62a17ae 3784 case NEXTHOP_TYPE_IPV4:
3785 case NEXTHOP_TYPE_IPV4_IFINDEX:
a971aeb6
RW
3786 inet_ntop(AF_INET, &nexthop->gate.ipv4,
3787 nh_buf, sizeof(nh_buf));
d62a17ae 3788 break;
3789 case NEXTHOP_TYPE_IPV6:
3790 case NEXTHOP_TYPE_IPV6_IFINDEX:
a971aeb6
RW
3791 inet_ntop(AF_INET6, &nexthop->gate.ipv6,
3792 nh_buf, sizeof(nh_buf));
d62a17ae 3793 break;
10cc80ca 3794 case NEXTHOP_TYPE_BLACKHOLE:
d62a17ae 3795 break;
3796 }
3797
b9abd9ad 3798 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
a971aeb6
RW
3799 out_label_str = mpls_label2str(
3800 nexthop->nh_label->num_labels,
3801 &nexthop->nh_label->label[0],
43a9f66c 3802 buf, sizeof(buf), 1);
b9abd9ad 3803 else
a971aeb6
RW
3804 out_label_str = "-";
3805
3806 ttable_add_row(tt, "%u|%s|%s|%s",
3807 lsp->ile.in_label,
3808 nhlfe_type2str(nhlfe->type),
3809 nh_buf, out_label_str);
d62a17ae 3810 }
3811 }
3812
a971aeb6
RW
3813 /* Dump the generated table. */
3814 if (tt->nrows > 1) {
3815 char *table = ttable_dump(tt, "\n");
3816 vty_out(vty, "%s\n", table);
3817 XFREE(MTYPE_TMP, table);
3818 }
3819 ttable_del(tt);
d62a17ae 3820 }
3821
6a154c88 3822 list_delete(&lsp_list);
3ab18ff2 3823}
3824
608a57c0
MS
3825/*
3826 * Create printable string for static LSP configuration.
3827 */
f2595bd5
DS
3828static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
3829 int size)
608a57c0
MS
3830{
3831 const struct nexthop *nh;
3832
3833 nh = nhlfe->nexthop;
3834
3835 buf[0] = '\0';
3836 switch (nh->type) {
3837 case NEXTHOP_TYPE_IPV4:
10cc80ca 3838 case NEXTHOP_TYPE_IPV4_IFINDEX:
608a57c0 3839 inet_ntop(AF_INET, &nh->gate.ipv4, buf, size);
10cc80ca
DS
3840 if (nh->ifindex)
3841 strlcat(buf, ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3842 size);
608a57c0
MS
3843 break;
3844 case NEXTHOP_TYPE_IPV6:
3845 case NEXTHOP_TYPE_IPV6_IFINDEX:
3846 inet_ntop(AF_INET6, &nh->gate.ipv6, buf, size);
3847 if (nh->ifindex)
3848 strlcat(buf,
3849 ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3850 size);
3851 break;
10cc80ca 3852 case NEXTHOP_TYPE_IFINDEX:
a44e3106
MS
3853 if (nh->ifindex)
3854 strlcat(buf,
3855 ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3856 size);
3857 break;
3858 case NEXTHOP_TYPE_BLACKHOLE:
608a57c0
MS
3859 break;
3860 }
3861
3862 return buf;
3863}
3864
7758e3f3 3865/*
3866 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
3867 */
d62a17ae 3868int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
3869{
8f74a383 3870 struct zebra_lsp *lsp;
f2595bd5 3871 struct zebra_nhlfe *nhlfe;
608a57c0 3872 struct nexthop *nh;
d62a17ae 3873 struct listnode *node;
3874 struct list *slsp_list =
608a57c0 3875 hash_get_sorted_list(zvrf->slsp_table, lsp_cmp);
d62a17ae 3876
608a57c0
MS
3877 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, lsp)) {
3878 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
0af35d90 3879 char buf[BUFSIZ];
d62a17ae 3880 char lstr[30];
3881
608a57c0
MS
3882 nh = nhlfe->nexthop;
3883 if (nh == NULL || nh->nh_label == NULL)
3884 continue;
3885
3886 nhlfe_config_str(nhlfe, buf, sizeof(buf));
3887
3888 switch (nh->nh_label->label[0]) {
70e98a7f
DS
3889 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
3890 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
d62a17ae 3891 strlcpy(lstr, "explicit-null", sizeof(lstr));
3892 break;
70e98a7f 3893 case MPLS_LABEL_IMPLICIT_NULL:
d62a17ae 3894 strlcpy(lstr, "implicit-null", sizeof(lstr));
3895 break;
3896 default:
772270f3 3897 snprintf(lstr, sizeof(lstr), "%u",
608a57c0 3898 nh->nh_label->label[0]);
d62a17ae 3899 break;
3900 }
3901
608a57c0 3902 vty_out(vty, "mpls lsp %u %s %s\n", lsp->ile.in_label,
d62a17ae 3903 buf, lstr);
3904 }
3905 }
b78b820d 3906
6a154c88 3907 list_delete(&slsp_list);
d62a17ae 3908 return (zvrf->slsp_table->count ? 1 : 0);
7758e3f3 3909}
3910
1b6d5c7e
VV
3911/*
3912 * Add/update global label block.
3913 */
d7c0a89a
QY
3914int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
3915 uint32_t end_label)
1b6d5c7e 3916{
d62a17ae 3917 zvrf->mpls_srgb.start_label = start_label;
3918 zvrf->mpls_srgb.end_label = end_label;
28d58fd7 3919
d62a17ae 3920 /* Evaluate registered FECs to see if any get a label or not. */
3921 fec_evaluate(zvrf);
3922 return 0;
1b6d5c7e
VV
3923}
3924
3925/*
3926 * Delete global label block.
3927 */
d62a17ae 3928int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
1b6d5c7e 3929{
d62a17ae 3930 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3931 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
28d58fd7 3932
d62a17ae 3933 /* Process registered FECs to clear their local label, if needed. */
3934 fec_evaluate(zvrf);
3935 return 0;
1b6d5c7e
VV
3936}
3937
3938/*
3939 * Display MPLS global label block configuration (VTY command handler).
3940 */
d62a17ae 3941int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
1b6d5c7e 3942{
d62a17ae 3943 if (zvrf->mpls_srgb.start_label == 0)
3944 return 0;
1b6d5c7e 3945
d62a17ae 3946 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
3947 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
3948 vty_out(vty, "mpls label global-block %u %u\n",
3949 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
3950 }
1b6d5c7e 3951
d62a17ae 3952 return 1;
1b6d5c7e
VV
3953}
3954
84915b0a 3955/*
3956 * Called when VRF becomes inactive, cleans up information but keeps
3957 * the table itself.
84915b0a 3958 */
3959void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
3960{
c2e10644
MS
3961 struct zebra_vrf *def_zvrf;
3962 afi_t afi;
3963
3964 if (zvrf_id(zvrf) == VRF_DEFAULT)
3965 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3966 else {
3967 /*
3968 * For other vrfs, we try to remove associated LSPs; we locate
3969 * the LSPs in the default vrf.
3970 */
3971 def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3972
3973 /* At shutdown, the default may be gone already */
3974 if (def_zvrf == NULL)
3975 return;
3976
3977 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
3978 if (zvrf->label[afi] != MPLS_LABEL_NONE)
3979 lsp_uninstall(def_zvrf, zvrf->label[afi]);
3980 }
3981 }
84915b0a 3982}
3983
06302ecb
DS
3984/*
3985 * When a vrf label is assigned and the client goes away
3986 * we should cleanup the vrf labels associated with
3987 * that zclient.
3988 */
3989void zebra_mpls_client_cleanup_vrf_label(uint8_t proto)
3990{
3991 struct vrf *vrf;
3992 struct zebra_vrf *def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3993
3994 if (def_zvrf == NULL)
3995 return;
3996
3997 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
3998 struct zebra_vrf *zvrf = vrf->info;
3999 afi_t afi;
4000
4001 if (!zvrf)
4002 continue;
4003
4004 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4005 if (zvrf->label_proto[afi] == proto
4006 && zvrf->label[afi] != MPLS_LABEL_NONE)
4007 lsp_uninstall(def_zvrf, zvrf->label[afi]);
4008
4009 /*
4010 * Cleanup data structures by fiat
4011 */
4012 zvrf->label_proto[afi] = 0;
4013 zvrf->label[afi] = MPLS_LABEL_NONE;
4014 }
4015 }
4016}
4017
40c7bdb0 4018/*
4019 * Called upon process exiting, need to delete LSP forwarding
4020 * entries from the kernel.
4021 * NOTE: Currently supported only for default VRF.
4022 */
d62a17ae 4023void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
40c7bdb0 4024{
d62a17ae 4025 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
4026 hash_clean(zvrf->lsp_table, NULL);
4027 hash_free(zvrf->lsp_table);
4028 hash_clean(zvrf->slsp_table, NULL);
4029 hash_free(zvrf->slsp_table);
9b67b514
DS
4030 route_table_finish(zvrf->fec_table[AFI_IP]);
4031 route_table_finish(zvrf->fec_table[AFI_IP6]);
40c7bdb0 4032}
4033
7758e3f3 4034/*
4035 * Allocate MPLS tables for this VRF and do other initialization.
4036 * NOTE: Currently supported only for default VRF.
4037 */
d62a17ae 4038void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
7758e3f3 4039{
4a73887e
DS
4040 char buffer[80];
4041
d62a17ae 4042 if (!zvrf)
4043 return;
4a73887e
DS
4044
4045 snprintf(buffer, sizeof(buffer), "ZEBRA SLSP table: %s",
4046 zvrf->vrf->name);
e2071325 4047 zvrf->slsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
4a73887e
DS
4048
4049 snprintf(buffer, sizeof(buffer), "ZEBRA LSP table: %s",
4050 zvrf->vrf->name);
4051 zvrf->lsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
d62a17ae 4052 zvrf->fec_table[AFI_IP] = route_table_init();
4053 zvrf->fec_table[AFI_IP6] = route_table_init();
4054 zvrf->mpls_flags = 0;
4055 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
4056 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
7758e3f3 4057}
4058
4059/*
4060 * Global MPLS initialization.
4061 */
d62a17ae 4062void zebra_mpls_init(void)
7758e3f3 4063{
d62a17ae 4064 mpls_enabled = 0;
6fb35808 4065 mpls_pw_reach_strict = false;
33c32282 4066
d62a17ae 4067 if (mpls_kernel_init() < 0) {
e914ccbe 4068 flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
9df414fe 4069 "Disabling MPLS support (no kernel support)");
d62a17ae 4070 return;
4071 }
fe6c7157 4072
2561d12e 4073 if (!mpls_processq_init())
d62a17ae 4074 mpls_enabled = 1;
453844ab 4075
21ccc0cf 4076 hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
651105b5 4077 hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
7758e3f3 4078}