]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_mpls.c
zebra: Don't error on nexthop object support check
[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
8f77d0ee
DS
2568static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop,
2569 enum lsp_types_t type, mpls_label_t label)
2570{
2571 if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2572 nexthop_add_labels(nexthop, type, 1, &label);
2573 else if (!add && nexthop->nh_label_type == type)
2574 nexthop_del_labels(nexthop);
2575 else
2576 return false;
2577
2578 return true;
2579}
2580
ce549947
RW
2581/*
2582 * Install/uninstall a FEC-To-NHLFE (FTN) binding.
2583 */
d62a17ae 2584int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
2585 struct prefix *prefix, enum nexthop_types_t gtype,
e132dea0
RW
2586 union g_addr *gate, ifindex_t ifindex, uint8_t route_type,
2587 unsigned short route_instance, mpls_label_t out_label)
d62a17ae 2588{
2589 struct route_table *table;
2590 struct route_node *rn;
2591 struct route_entry *re;
2592 struct nexthop *nexthop;
8f77d0ee 2593 bool found;
d62a17ae 2594
2595 /* Lookup table. */
2596 table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
2597 zvrf_id(zvrf));
2598 if (!table)
2599 return -1;
2600
2601 /* Lookup existing route */
2602 rn = route_node_get(table, prefix);
a2addae8 2603 RNODE_FOREACH_RE (rn, re) {
d62a17ae 2604 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2605 continue;
e132dea0 2606 if (re->type == route_type && re->instance == route_instance)
d62a17ae 2607 break;
88d88a9c 2608 }
ce549947 2609
d62a17ae 2610 if (re == NULL)
2611 return -1;
2612
8f77d0ee 2613 found = false;
6b468511 2614 for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) {
d62a17ae 2615 switch (nexthop->type) {
2616 case NEXTHOP_TYPE_IPV4:
2617 case NEXTHOP_TYPE_IPV4_IFINDEX:
2618 if (gtype != NEXTHOP_TYPE_IPV4
2619 && gtype != NEXTHOP_TYPE_IPV4_IFINDEX)
2620 continue;
2621 if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4))
2622 continue;
2623 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
2624 && nexthop->ifindex != ifindex)
2625 continue;
8f77d0ee
DS
2626 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2627 out_label))
2628 return 0;
2629 found = true;
2630 break;
d62a17ae 2631 case NEXTHOP_TYPE_IPV6:
2632 case NEXTHOP_TYPE_IPV6_IFINDEX:
2633 if (gtype != NEXTHOP_TYPE_IPV6
2634 && gtype != NEXTHOP_TYPE_IPV6_IFINDEX)
2635 continue;
2636 if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, &gate->ipv6))
2637 continue;
2638 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
2639 && nexthop->ifindex != ifindex)
2640 continue;
8f77d0ee
DS
2641 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2642 out_label))
2643 return 0;
2644 found = true;
2645 break;
d62a17ae 2646 default:
2647 break;
2648 }
2649 }
d62a17ae 2650
8f77d0ee
DS
2651 if (!found)
2652 return -1;
ce549947 2653
d62a17ae 2654 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
332ad713 2655 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
d62a17ae 2656 rib_queue_add(rn);
ce549947 2657
d62a17ae 2658 return 0;
ce549947
RW
2659}
2660
ea6b290b
RW
2661int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2662 struct prefix *prefix, uint8_t route_type,
2663 unsigned short route_instance)
2664{
2665 struct route_table *table;
2666 struct route_node *rn;
2667 struct route_entry *re;
2668 struct nexthop *nexthop;
2669
2670 /* Lookup table. */
2671 table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
2672 zvrf_id(zvrf));
2673 if (!table)
2674 return -1;
2675
2676 /* Lookup existing route */
2677 rn = route_node_get(table, prefix);
2678 RNODE_FOREACH_RE (rn, re) {
2679 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2680 continue;
2681 if (re->type == route_type && re->instance == route_instance)
2682 break;
2683 }
2684 if (re == NULL)
2685 return -1;
2686
2687 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
2688 nexthop_del_labels(nexthop);
2689
2690 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2691 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
2692 rib_queue_add(rn);
2693
2694 return 0;
2695}
2696
ce549947
RW
2697/*
2698 * Install/update a NHLFE for an LSP in the forwarding table. This may be
2699 * a new LSP entry or a new NHLFE for an existing in-label or an update of
2700 * the out-label for an existing NHLFE (update case).
2701 */
d62a17ae 2702int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
2703 mpls_label_t in_label, mpls_label_t out_label,
2704 enum nexthop_types_t gtype, union g_addr *gate,
2705 ifindex_t ifindex)
2706{
2707 struct hash *lsp_table;
2708 zebra_ile_t tmp_ile;
2709 zebra_lsp_t *lsp;
2710 zebra_nhlfe_t *nhlfe;
2711 char buf[BUFSIZ];
2712
2713 /* Lookup table. */
2714 lsp_table = zvrf->lsp_table;
2715 if (!lsp_table)
2716 return -1;
2717
2718 /* If entry is present, exit. */
2719 tmp_ile.in_label = in_label;
2720 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2721 if (!lsp)
2722 return -1;
2723 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2724 if (nhlfe) {
2725 struct nexthop *nh = nhlfe->nexthop;
2726
2727 assert(nh);
2728 assert(nh->nh_label);
2729
2730 /* Clear deleted flag (in case it was set) */
2731 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2732 if (nh->nh_label->label[0] == out_label)
2733 /* No change */
2734 return 0;
2735
2736 if (IS_ZEBRA_DEBUG_MPLS) {
2737 nhlfe2str(nhlfe, buf, BUFSIZ);
2738 zlog_debug(
2739 "LSP in-label %u type %d nexthop %s "
2740 "out-label changed to %u (old %u)",
2741 in_label, type, buf, out_label,
2742 nh->nh_label->label[0]);
2743 }
2744
2745 /* Update out label, trigger processing. */
2746 nh->nh_label->label[0] = out_label;
2747 } else {
2748 /* Add LSP entry to this nexthop */
2749 nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, out_label);
2750 if (!nhlfe)
2751 return -1;
2752
2753 if (IS_ZEBRA_DEBUG_MPLS) {
2754 nhlfe2str(nhlfe, buf, BUFSIZ);
2755 zlog_debug(
2756 "Add LSP in-label %u type %d nexthop %s "
2757 "out-label %u",
2758 in_label, type, buf, out_label);
2759 }
2760
2761 lsp->addr_family = NHLFE_FAMILY(nhlfe);
2762 }
2763
2764 /* Mark NHLFE, queue LSP for processing. */
2765 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2766 if (lsp_processq_add(lsp))
2767 return -1;
2768
2769 return 0;
ce549947
RW
2770}
2771
2772/*
2773 * Uninstall a particular NHLFE in the forwarding table. If this is
2774 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
2775 */
d62a17ae 2776int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2777 mpls_label_t in_label, enum nexthop_types_t gtype,
2778 union g_addr *gate, ifindex_t ifindex)
2779{
2780 struct hash *lsp_table;
2781 zebra_ile_t tmp_ile;
2782 zebra_lsp_t *lsp;
2783 zebra_nhlfe_t *nhlfe;
2784 char buf[BUFSIZ];
2785
2786 /* Lookup table. */
2787 lsp_table = zvrf->lsp_table;
2788 if (!lsp_table)
2789 return -1;
2790
2791 /* If entry is not present, exit. */
2792 tmp_ile.in_label = in_label;
2793 lsp = hash_lookup(lsp_table, &tmp_ile);
2794 if (!lsp)
2795 return 0;
2796 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2797 if (!nhlfe)
2798 return 0;
2799
2800 if (IS_ZEBRA_DEBUG_MPLS) {
2801 nhlfe2str(nhlfe, buf, BUFSIZ);
2802 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
2803 in_label, type, buf, nhlfe->flags);
2804 }
2805
2806 /* Mark NHLFE for delete or directly delete, as appropriate. */
2807 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
2808 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2809 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2810 if (lsp_processq_add(lsp))
2811 return -1;
2812 } else {
2813 nhlfe_del(nhlfe);
2814
2815 /* Free LSP entry if no other NHLFEs and not scheduled. */
2816 if (!lsp->nhlfe_list
2817 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
2818 if (IS_ZEBRA_DEBUG_MPLS)
2819 zlog_debug("Free LSP in-label %u flags 0x%x",
2820 lsp->ile.in_label, lsp->flags);
2821
2822 lsp = hash_release(lsp_table, &lsp->ile);
0a22ddfb 2823 XFREE(MTYPE_LSP, lsp);
d62a17ae 2824 }
2825 }
2826 return 0;
ce549947
RW
2827}
2828
ea6b290b
RW
2829int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
2830 mpls_label_t in_label)
2831{
2832 struct hash *lsp_table;
2833 zebra_ile_t tmp_ile;
2834 zebra_lsp_t *lsp;
2835
2836 /* Lookup table. */
2837 lsp_table = zvrf->lsp_table;
2838 if (!lsp_table)
2839 return -1;
2840
2841 /* If entry is not present, exit. */
2842 tmp_ile.in_label = in_label;
2843 lsp = hash_lookup(lsp_table, &tmp_ile);
2844 if (!lsp)
2845 return 0;
2846
2847 return mpls_lsp_uninstall_all(lsp_table, lsp, type);
2848}
2849
ce549947 2850/*
651105b5 2851 * Uninstall all NHLFEs for a particular LSP forwarding entry.
ce549947
RW
2852 * If no other NHLFEs exist, the entry would be deleted.
2853 */
651105b5 2854static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt)
ce549947 2855{
651105b5 2856 struct lsp_uninstall_args *args = ctxt;
d62a17ae 2857 zebra_lsp_t *lsp;
2858 struct hash *lsp_table;
ce549947 2859
e3b78da8 2860 lsp = (zebra_lsp_t *)bucket->data;
9ea660be 2861 if (!lsp->nhlfe_list)
d62a17ae 2862 return;
ce549947 2863
651105b5 2864 lsp_table = args->lsp_table;
d62a17ae 2865 if (!lsp_table)
2866 return;
ce549947 2867
651105b5 2868 mpls_lsp_uninstall_all(lsp_table, lsp, args->type);
ce549947
RW
2869}
2870
2871/*
651105b5
RW
2872 * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and
2873 * LSP type.
ce549947 2874 */
651105b5
RW
2875static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
2876 int afi, enum lsp_types_t lsp_type)
d62a17ae 2877{
2878 struct route_table *table;
2879 struct route_node *rn;
2880 struct route_entry *re;
2881 struct nexthop *nexthop;
2882 int update;
2883
2884 /* Process routes of interested address-families. */
2885 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2886 if (!table)
2887 return;
2888
2889 for (rn = route_top(table); rn; rn = route_next(rn)) {
2890 update = 0;
a2addae8 2891 RNODE_FOREACH_RE (rn, re) {
6b468511 2892 for (nexthop = re->ng->nexthop; nexthop;
407c87a6 2893 nexthop = nexthop->next) {
651105b5 2894 if (nexthop->nh_label_type != lsp_type)
407c87a6
DS
2895 continue;
2896
d62a17ae 2897 nexthop_del_labels(nexthop);
2898 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2899 SET_FLAG(re->status,
332ad713 2900 ROUTE_ENTRY_LABELS_CHANGED);
d62a17ae 2901 update = 1;
2902 }
407c87a6 2903 }
d62a17ae 2904
2905 if (update)
2906 rib_queue_add(rn);
2907 }
ce549947
RW
2908}
2909
1c1cf002 2910#if defined(HAVE_CUMULUS)
7758e3f3 2911/*
2912 * Check that the label values used in LSP creation are consistent. The
2913 * main criteria is that if there is ECMP, the label operation must still
2914 * be consistent - i.e., all paths either do a swap or do PHP. This is due
2915 * to current HW restrictions.
2916 */
d62a17ae 2917int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
2918 mpls_label_t in_label,
2919 mpls_label_t out_label,
2920 enum nexthop_types_t gtype,
2921 union g_addr *gate, ifindex_t ifindex)
2922{
2923 struct hash *slsp_table;
2924 zebra_ile_t tmp_ile;
2925 zebra_slsp_t *slsp;
2926 zebra_snhlfe_t *snhlfe;
2927
2928 /* Lookup table. */
2929 slsp_table = zvrf->slsp_table;
2930 if (!slsp_table)
2931 return 0;
2932
2933 /* If entry is not present, exit. */
2934 tmp_ile.in_label = in_label;
2935 slsp = hash_lookup(slsp_table, &tmp_ile);
2936 if (!slsp)
2937 return 1;
2938
2939 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2940 if (snhlfe) {
2941 if (snhlfe->out_label == out_label)
2942 return 1;
2943
2944 /* If not only NHLFE, cannot allow label change. */
2945 if (snhlfe != slsp->snhlfe_list || snhlfe->next)
2946 return 0;
2947 } else {
2948 /* If other NHLFEs exist, label operation must match. */
2949 if (slsp->snhlfe_list) {
2950 int cur_op, new_op;
2951
2952 cur_op = (slsp->snhlfe_list->out_label
70e98a7f
DS
2953 == MPLS_LABEL_IMPLICIT_NULL);
2954 new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
d62a17ae 2955 if (cur_op != new_op)
2956 return 0;
2957 }
2958 }
2959
2960 /* Label values are good. */
2961 return 1;
7758e3f3 2962}
1c1cf002 2963#endif /* HAVE_CUMULUS */
7758e3f3 2964
2965/*
2966 * Add static LSP entry. This may be the first entry for this incoming label
2967 * or an additional nexthop; an existing entry may also have outgoing label
2968 * changed.
2969 * Note: The label operation (swap or PHP) is common for the LSP entry (all
2970 * NHLFEs).
2971 */
d62a17ae 2972int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
2973 mpls_label_t out_label,
2974 enum nexthop_types_t gtype, union g_addr *gate,
2975 ifindex_t ifindex)
2976{
2977 struct hash *slsp_table;
2978 zebra_ile_t tmp_ile;
2979 zebra_slsp_t *slsp;
2980 zebra_snhlfe_t *snhlfe;
2981 char buf[BUFSIZ];
2982
2983 /* Lookup table. */
2984 slsp_table = zvrf->slsp_table;
2985 if (!slsp_table)
2986 return -1;
2987
2988 /* If entry is present, exit. */
2989 tmp_ile.in_label = in_label;
2990 slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc);
2991 if (!slsp)
2992 return -1;
2993 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2994 if (snhlfe) {
2995 if (snhlfe->out_label == out_label)
2996 /* No change */
2997 return 0;
2998
2999 if (IS_ZEBRA_DEBUG_MPLS) {
3000 snhlfe2str(snhlfe, buf, BUFSIZ);
3001 zlog_debug(
3002 "Upd static LSP in-label %u nexthop %s "
3003 "out-label %u (old %u)",
3004 in_label, buf, out_label, snhlfe->out_label);
3005 }
3006 snhlfe->out_label = out_label;
3007 } else {
3008 /* Add static LSP entry to this nexthop */
3009 snhlfe = snhlfe_add(slsp, gtype, gate, ifindex, out_label);
3010 if (!snhlfe)
3011 return -1;
3012
3013 if (IS_ZEBRA_DEBUG_MPLS) {
3014 snhlfe2str(snhlfe, buf, BUFSIZ);
3015 zlog_debug(
3016 "Add static LSP in-label %u nexthop %s out-label %u",
3017 in_label, buf, out_label);
3018 }
3019 }
3020
3021 /* (Re)Install LSP in the main table. */
3022 if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
3023 gate, ifindex))
3024 return -1;
3025
3026 return 0;
7758e3f3 3027}
3028
3029/*
3030 * Delete static LSP entry. This may be the delete of one particular
3031 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
3032 * all NHLFEs).
3033 * NOTE: Delete of the only NHLFE will also end up deleting the entire
3034 * LSP configuration.
3035 */
d62a17ae 3036int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
3037 enum nexthop_types_t gtype, union g_addr *gate,
3038 ifindex_t ifindex)
3039{
3040 struct hash *slsp_table;
3041 zebra_ile_t tmp_ile;
3042 zebra_slsp_t *slsp;
3043 zebra_snhlfe_t *snhlfe;
3044
3045 /* Lookup table. */
3046 slsp_table = zvrf->slsp_table;
3047 if (!slsp_table)
3048 return -1;
3049
3050 /* If entry is not present, exit. */
3051 tmp_ile.in_label = in_label;
3052 slsp = hash_lookup(slsp_table, &tmp_ile);
3053 if (!slsp)
3054 return 0;
3055
3056 /* Is it delete of entire LSP or a specific NHLFE? */
3057 if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
3058 if (IS_ZEBRA_DEBUG_MPLS)
3059 zlog_debug("Del static LSP in-label %u", in_label);
3060
3061 /* Uninstall entire LSP from the main table. */
3062 mpls_static_lsp_uninstall_all(zvrf, in_label);
3063
3064 /* Delete all static NHLFEs */
3065 snhlfe_del_all(slsp);
3066 } else {
3067 /* Find specific NHLFE, exit if not found. */
3068 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
3069 if (!snhlfe)
3070 return 0;
3071
3072 if (IS_ZEBRA_DEBUG_MPLS) {
3073 char buf[BUFSIZ];
3074 snhlfe2str(snhlfe, buf, BUFSIZ);
3075 zlog_debug("Del static LSP in-label %u nexthop %s",
3076 in_label, buf);
3077 }
3078
3079 /* Uninstall LSP from the main table. */
3080 mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
3081 gate, ifindex);
3082
3083 /* Delete static LSP NHLFE */
3084 snhlfe_del(snhlfe);
3085 }
3086
3087 /* Remove entire static LSP entry if no NHLFE - valid in either case
3088 * above. */
3089 if (!slsp->snhlfe_list) {
3090 slsp = hash_release(slsp_table, &tmp_ile);
0a22ddfb 3091 XFREE(MTYPE_SLSP, slsp);
d62a17ae 3092 }
3093
3094 return 0;
7758e3f3 3095}
3096
40c7bdb0 3097/*
3098 * Schedule all MPLS label forwarding entries for processing.
3099 * Called upon changes that may affect one or more of them such as
3100 * interface or nexthop state changes.
3101 */
d62a17ae 3102void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
40c7bdb0 3103{
d62a17ae 3104 if (!zvrf)
3105 return;
3106 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
40c7bdb0 3107}
3108
3ab18ff2 3109/*
3110 * Display MPLS label forwarding table for a specific LSP
3111 * (VTY command handler).
3112 */
d62a17ae 3113void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
9f049418 3114 mpls_label_t label, bool use_json)
3ab18ff2 3115{
d62a17ae 3116 struct hash *lsp_table;
3117 zebra_lsp_t *lsp;
3118 zebra_ile_t tmp_ile;
3119 json_object *json = NULL;
3ab18ff2 3120
d62a17ae 3121 /* Lookup table. */
3122 lsp_table = zvrf->lsp_table;
3123 if (!lsp_table)
3124 return;
3ab18ff2 3125
d62a17ae 3126 /* If entry is not present, exit. */
3127 tmp_ile.in_label = label;
3128 lsp = hash_lookup(lsp_table, &tmp_ile);
3129 if (!lsp)
3130 return;
3ab18ff2 3131
d62a17ae 3132 if (use_json) {
3133 json = lsp_json(lsp);
9d303b37
DL
3134 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3135 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 3136 json_object_free(json);
3137 } else
3138 lsp_print(lsp, (void *)vty);
3ab18ff2 3139}
3140
3141/*
3142 * Display MPLS label forwarding table (VTY command handler).
3143 */
d62a17ae 3144void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
9f049418 3145 bool use_json)
d62a17ae 3146{
3147 char buf[BUFSIZ];
3148 json_object *json = NULL;
3149 zebra_lsp_t *lsp = NULL;
3150 zebra_nhlfe_t *nhlfe = NULL;
d62a17ae 3151 struct listnode *node = NULL;
3152 struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
3153
3154 if (use_json) {
3155 json = json_object_new_object();
3156
3157 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
3158 json_object_object_add(
3159 json, label2str(lsp->ile.in_label, buf, BUFSIZ),
3160 lsp_json(lsp));
3161
9d303b37
DL
3162 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3163 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 3164 json_object_free(json);
3165 } else {
a971aeb6
RW
3166 struct ttable *tt;
3167
3168 /* Prepare table. */
3169 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3170 ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label");
3171 tt->style.cell.rpad = 2;
3172 tt->style.corner = '+';
3173 ttable_restyle(tt);
3174 ttable_rowseps(tt, 0, BOTTOM, true, '-');
d62a17ae 3175
3176 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
3177 for (nhlfe = lsp->nhlfe_list; nhlfe;
3178 nhlfe = nhlfe->next) {
a971aeb6
RW
3179 struct nexthop *nexthop;
3180 const char *out_label_str;
3181 char nh_buf[NEXTHOP_STRLEN];
3182
d62a17ae 3183 nexthop = nhlfe->nexthop;
3184
3185 switch (nexthop->type) {
996c9314 3186 case NEXTHOP_TYPE_IFINDEX: {
86f07f44 3187 struct zebra_ns *zns;
b9abd9ad
DS
3188 struct interface *ifp;
3189
86f07f44
PG
3190 zns = zebra_ns_lookup(NS_DEFAULT);
3191 ifp = if_lookup_by_index_per_ns(
a971aeb6
RW
3192 zns, nexthop->ifindex);
3193 snprintf(nh_buf, sizeof(nh_buf), "%s",
3194 ifp ? ifp->name : "Null");
b9abd9ad
DS
3195 break;
3196 }
d62a17ae 3197 case NEXTHOP_TYPE_IPV4:
3198 case NEXTHOP_TYPE_IPV4_IFINDEX:
a971aeb6
RW
3199 inet_ntop(AF_INET, &nexthop->gate.ipv4,
3200 nh_buf, sizeof(nh_buf));
d62a17ae 3201 break;
3202 case NEXTHOP_TYPE_IPV6:
3203 case NEXTHOP_TYPE_IPV6_IFINDEX:
a971aeb6
RW
3204 inet_ntop(AF_INET6, &nexthop->gate.ipv6,
3205 nh_buf, sizeof(nh_buf));
d62a17ae 3206 break;
3207 default:
3208 break;
3209 }
3210
b9abd9ad 3211 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
a971aeb6
RW
3212 out_label_str = mpls_label2str(
3213 nexthop->nh_label->num_labels,
3214 &nexthop->nh_label->label[0],
3215 buf, BUFSIZ, 1);
b9abd9ad 3216 else
a971aeb6
RW
3217 out_label_str = "-";
3218
3219 ttable_add_row(tt, "%u|%s|%s|%s",
3220 lsp->ile.in_label,
3221 nhlfe_type2str(nhlfe->type),
3222 nh_buf, out_label_str);
d62a17ae 3223 }
3224 }
3225
a971aeb6
RW
3226 /* Dump the generated table. */
3227 if (tt->nrows > 1) {
3228 char *table = ttable_dump(tt, "\n");
3229 vty_out(vty, "%s\n", table);
3230 XFREE(MTYPE_TMP, table);
3231 }
3232 ttable_del(tt);
d62a17ae 3233 }
3234
6a154c88 3235 list_delete(&lsp_list);
3ab18ff2 3236}
3237
7758e3f3 3238/*
3239 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
3240 */
d62a17ae 3241int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
3242{
3243 zebra_slsp_t *slsp;
3244 zebra_snhlfe_t *snhlfe;
3245 struct listnode *node;
3246 struct list *slsp_list =
3247 hash_get_sorted_list(zvrf->slsp_table, slsp_cmp);
3248
3249 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) {
3250 for (snhlfe = slsp->snhlfe_list; snhlfe;
3251 snhlfe = snhlfe->next) {
0af35d90 3252 char buf[BUFSIZ];
d62a17ae 3253 char lstr[30];
3254
0af35d90 3255 snhlfe2str(snhlfe, buf, sizeof(buf));
d62a17ae 3256 switch (snhlfe->out_label) {
70e98a7f
DS
3257 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
3258 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
d62a17ae 3259 strlcpy(lstr, "explicit-null", sizeof(lstr));
3260 break;
70e98a7f 3261 case MPLS_LABEL_IMPLICIT_NULL:
d62a17ae 3262 strlcpy(lstr, "implicit-null", sizeof(lstr));
3263 break;
3264 default:
3265 sprintf(lstr, "%u", snhlfe->out_label);
3266 break;
3267 }
3268
3269 vty_out(vty, "mpls lsp %u %s %s\n", slsp->ile.in_label,
3270 buf, lstr);
3271 }
3272 }
b78b820d 3273
6a154c88 3274 list_delete(&slsp_list);
d62a17ae 3275 return (zvrf->slsp_table->count ? 1 : 0);
7758e3f3 3276}
3277
1b6d5c7e
VV
3278/*
3279 * Add/update global label block.
3280 */
d7c0a89a
QY
3281int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
3282 uint32_t end_label)
1b6d5c7e 3283{
d62a17ae 3284 zvrf->mpls_srgb.start_label = start_label;
3285 zvrf->mpls_srgb.end_label = end_label;
28d58fd7 3286
d62a17ae 3287 /* Evaluate registered FECs to see if any get a label or not. */
3288 fec_evaluate(zvrf);
3289 return 0;
1b6d5c7e
VV
3290}
3291
3292/*
3293 * Delete global label block.
3294 */
d62a17ae 3295int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
1b6d5c7e 3296{
d62a17ae 3297 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3298 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
28d58fd7 3299
d62a17ae 3300 /* Process registered FECs to clear their local label, if needed. */
3301 fec_evaluate(zvrf);
3302 return 0;
1b6d5c7e
VV
3303}
3304
3305/*
3306 * Display MPLS global label block configuration (VTY command handler).
3307 */
d62a17ae 3308int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
1b6d5c7e 3309{
d62a17ae 3310 if (zvrf->mpls_srgb.start_label == 0)
3311 return 0;
1b6d5c7e 3312
d62a17ae 3313 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
3314 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
3315 vty_out(vty, "mpls label global-block %u %u\n",
3316 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
3317 }
1b6d5c7e 3318
d62a17ae 3319 return 1;
1b6d5c7e
VV
3320}
3321
84915b0a 3322/*
3323 * Called when VRF becomes inactive, cleans up information but keeps
3324 * the table itself.
84915b0a 3325 */
3326void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
3327{
c2e10644
MS
3328 struct zebra_vrf *def_zvrf;
3329 afi_t afi;
3330
3331 if (zvrf_id(zvrf) == VRF_DEFAULT)
3332 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3333 else {
3334 /*
3335 * For other vrfs, we try to remove associated LSPs; we locate
3336 * the LSPs in the default vrf.
3337 */
3338 def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3339
3340 /* At shutdown, the default may be gone already */
3341 if (def_zvrf == NULL)
3342 return;
3343
3344 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
3345 if (zvrf->label[afi] != MPLS_LABEL_NONE)
3346 lsp_uninstall(def_zvrf, zvrf->label[afi]);
3347 }
3348 }
84915b0a 3349}
3350
40c7bdb0 3351/*
3352 * Called upon process exiting, need to delete LSP forwarding
3353 * entries from the kernel.
3354 * NOTE: Currently supported only for default VRF.
3355 */
d62a17ae 3356void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
40c7bdb0 3357{
d62a17ae 3358 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3359 hash_clean(zvrf->lsp_table, NULL);
3360 hash_free(zvrf->lsp_table);
3361 hash_clean(zvrf->slsp_table, NULL);
3362 hash_free(zvrf->slsp_table);
9b67b514
DS
3363 route_table_finish(zvrf->fec_table[AFI_IP]);
3364 route_table_finish(zvrf->fec_table[AFI_IP6]);
40c7bdb0 3365}
3366
7758e3f3 3367/*
3368 * Allocate MPLS tables for this VRF and do other initialization.
3369 * NOTE: Currently supported only for default VRF.
3370 */
d62a17ae 3371void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
7758e3f3 3372{
d62a17ae 3373 if (!zvrf)
3374 return;
996c9314
LB
3375 zvrf->slsp_table =
3376 hash_create(label_hash, label_cmp, "ZEBRA SLSP table");
3377 zvrf->lsp_table = hash_create(label_hash, label_cmp, "ZEBRA LSP table");
d62a17ae 3378 zvrf->fec_table[AFI_IP] = route_table_init();
3379 zvrf->fec_table[AFI_IP6] = route_table_init();
3380 zvrf->mpls_flags = 0;
3381 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3382 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
7758e3f3 3383}
3384
3385/*
3386 * Global MPLS initialization.
3387 */
d62a17ae 3388void zebra_mpls_init(void)
7758e3f3 3389{
d62a17ae 3390 mpls_enabled = 0;
33c32282 3391
d62a17ae 3392 if (mpls_kernel_init() < 0) {
e914ccbe 3393 flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
9df414fe 3394 "Disabling MPLS support (no kernel support)");
d62a17ae 3395 return;
3396 }
fe6c7157 3397
2561d12e 3398 if (!mpls_processq_init())
d62a17ae 3399 mpls_enabled = 1;
453844ab 3400
21ccc0cf 3401 hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
651105b5 3402 hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
7758e3f3 3403}