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