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