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