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