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