]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_mpls.c
bgpd: Rework BGP dampening to be per AFI/SAFI
[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
79static unsigned int label_hash(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 */
d62a17ae 580static unsigned int label_hash(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)
1696 strcat(buf,
1697 ifindex2ifname(snhlfe->ifindex, VRF_DEFAULT));
1698 break;
1699 default:
1700 break;
1701 }
7758e3f3 1702
d62a17ae 1703 return buf;
7758e3f3 1704}
1705
40c7bdb0 1706/*
1707 * Initialize work queue for processing changed LSPs.
1708 */
2561d12e 1709static int mpls_processq_init(void)
40c7bdb0 1710{
e2353ec2
DS
1711 zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
1712 if (!zrouter.lsp_process_q) {
e914ccbe 1713 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1c50c1c0 1714 "%s: could not initialise work queue!", __func__);
d62a17ae 1715 return -1;
1716 }
40c7bdb0 1717
e2353ec2
DS
1718 zrouter.lsp_process_q->spec.workfunc = &lsp_process;
1719 zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
1720 zrouter.lsp_process_q->spec.errorfunc = NULL;
1721 zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
1722 zrouter.lsp_process_q->spec.max_retries = 0;
1723 zrouter.lsp_process_q->spec.hold = 10;
33c32282 1724
d62a17ae 1725 return 0;
40c7bdb0 1726}
1727
7758e3f3 1728
7758e3f3 1729/* Public functions */
1730
d37f4d6c
MS
1731/*
1732 * Process LSP update results from zebra dataplane.
1733 */
1734void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
1735{
1736 struct zebra_vrf *zvrf;
1737 zebra_ile_t tmp_ile;
1738 struct hash *lsp_table;
1739 zebra_lsp_t *lsp;
1740 zebra_nhlfe_t *nhlfe;
1741 struct nexthop *nexthop;
1742 enum dplane_op_e op;
8841f96e 1743 enum zebra_dplane_result status;
d37f4d6c
MS
1744
1745 op = dplane_ctx_get_op(ctx);
1746 status = dplane_ctx_get_status(ctx);
1747
1748 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1749 zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
1750 ctx, dplane_op2str(op),
1751 dplane_ctx_get_in_label(ctx),
1752 dplane_res2str(status));
1753
1754 switch (op) {
1755 case DPLANE_OP_LSP_INSTALL:
1756 case DPLANE_OP_LSP_UPDATE:
1757 /* Look for zebra LSP object */
1758 zvrf = vrf_info_lookup(VRF_DEFAULT);
1759 if (zvrf == NULL)
1760 break;
1761
1762 lsp_table = zvrf->lsp_table;
1763
1764 tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
1765 lsp = hash_lookup(lsp_table, &tmp_ile);
1766 if (lsp == NULL) {
1767 if (IS_ZEBRA_DEBUG_DPLANE)
1768 zlog_debug("LSP ctx %p: in-label %u not found",
1769 ctx, dplane_ctx_get_in_label(ctx));
1770 break;
1771 }
1772
1773 /* TODO -- Confirm that this result is still 'current' */
1774
8841f96e 1775 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
d37f4d6c
MS
1776 /* Update zebra object */
1777 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1778 for (nhlfe = lsp->nhlfe_list; nhlfe;
1779 nhlfe = nhlfe->next) {
1780 nexthop = nhlfe->nexthop;
1781 if (!nexthop)
1782 continue;
1783
1784 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1785 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1786 }
1787 } else {
1788 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1789 clear_nhlfe_installed(lsp);
1790 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1791 "LSP Install Failure: in-label %u",
1792 lsp->ile.in_label);
1793 }
1794
1795 break;
1796
1797 case DPLANE_OP_LSP_DELETE:
3fd385c6
DS
1798 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
1799 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
1800 "LSP Deletion Failure: in-label %u",
1801 dplane_ctx_get_in_label(ctx));
d37f4d6c
MS
1802 break;
1803
1804 default:
1805 break;
1806
1807 } /* Switch */
1808
1809 dplane_ctx_fini(&ctx);
1810}
1811
a64448ba
DS
1812/*
1813 * Install dynamic LSP entry.
1814 */
d62a17ae 1815int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
1816 struct route_entry *re)
a64448ba 1817{
d62a17ae 1818 struct route_table *table;
1819 zebra_fec_t *fec;
a64448ba 1820
d62a17ae 1821 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
1822 if (!table)
1823 return -1;
a64448ba 1824
d62a17ae 1825 /* See if there is a configured label binding for this FEC. */
1826 fec = fec_find(table, &rn->p);
1827 if (!fec || fec->label == MPLS_INVALID_LABEL)
1828 return 0;
a64448ba 1829
d62a17ae 1830 /* We cannot install a label forwarding entry if local label is the
1831 * implicit-null label.
1832 */
70e98a7f 1833 if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
d62a17ae 1834 return 0;
a64448ba 1835
d62a17ae 1836 if (lsp_install(zvrf, fec->label, rn, re))
1837 return -1;
a64448ba 1838
d62a17ae 1839 return 0;
a64448ba
DS
1840}
1841
1842/*
1843 * Uninstall dynamic LSP entry, if any.
1844 */
d62a17ae 1845int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
1846 struct route_entry *re)
a64448ba 1847{
d62a17ae 1848 struct route_table *table;
1849 zebra_fec_t *fec;
a64448ba 1850
d62a17ae 1851 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
1852 if (!table)
1853 return -1;
a64448ba 1854
d62a17ae 1855 /* See if there is a configured label binding for this FEC. */
1856 fec = fec_find(table, &rn->p);
1857 if (!fec || fec->label == MPLS_INVALID_LABEL)
1858 return 0;
a64448ba 1859
d62a17ae 1860 /* Uninstall always removes all dynamic NHLFEs. */
1861 return lsp_uninstall(zvrf, fec->label);
a64448ba
DS
1862}
1863
d4cb23d7
MS
1864/*
1865 * Add an NHLFE to an LSP, return the newly-added object
1866 */
1867zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
1868 enum lsp_types_t lsp_type,
1869 enum nexthop_types_t gtype,
1870 union g_addr *gate,
1871 ifindex_t ifindex,
1872 mpls_label_t out_label)
1873{
1874 /* Just a public pass-through to the internal implementation */
1875 return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, out_label);
1876}
1877
1878/*
1879 * Free an allocated NHLFE
1880 */
1881void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe)
1882{
1883 /* Just a pass-through to the internal implementation */
1884 nhlfe_del(nhlfe);
1885}
1886
5aba114a
DS
1887/*
1888 * Registration from a client for the label binding for a FEC. If a binding
1889 * already exists, it is informed to the client.
28d58fd7 1890 * NOTE: If there is a manually configured label binding, that is used.
9bedbb1e 1891 * Otherwise, if a label index is specified, it means we have to allocate the
28d58fd7 1892 * label from a locally configured label block (SRGB), if one exists and index
57592a53
AD
1893 * is acceptable. If no label index then just register the specified label.
1894 * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
1895 * by the calling function. Register requests with both will be rejected.
5aba114a 1896 */
d62a17ae 1897int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
57592a53
AD
1898 uint32_t label, uint32_t label_index,
1899 struct zserv *client)
d62a17ae 1900{
1901 struct route_table *table;
1902 zebra_fec_t *fec;
1903 char buf[BUFSIZ];
57592a53
AD
1904 bool new_client;
1905 bool label_change = false;
d7c0a89a 1906 uint32_t old_label;
57592a53
AD
1907 bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
1908 bool is_configured_fec = false; /* indicate statically configured FEC */
d62a17ae 1909
1910 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
1911 if (!table)
1912 return -1;
1913
1914 if (IS_ZEBRA_DEBUG_MPLS)
1915 prefix2str(p, buf, BUFSIZ);
1916
57592a53
AD
1917 if (label != MPLS_INVALID_LABEL && have_label_index) {
1918 flog_err(
1919 EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
1920 "Rejecting FEC register for %s with both label %u and Label Index %u specified, client %s",
1921 buf, label, label_index,
1922 zebra_route_string(client->proto));
1923 return -1;
1924 }
1925
d62a17ae 1926 /* Locate FEC */
1927 fec = fec_find(table, p);
1928 if (!fec) {
57592a53 1929 fec = fec_add(table, p, label, 0, label_index);
d62a17ae 1930 if (!fec) {
af4c2728 1931 flog_err(
e914ccbe 1932 EC_ZEBRA_FEC_ADD_FAILED,
d62a17ae 1933 "Failed to add FEC %s upon register, client %s",
1934 buf, zebra_route_string(client->proto));
1935 return -1;
1936 }
1937
1938 old_label = MPLS_INVALID_LABEL;
57592a53 1939 new_client = true;
d62a17ae 1940 } else {
57592a53
AD
1941 /* Check if the FEC has been statically defined in the config */
1942 is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
d62a17ae 1943 /* Client may register same FEC with different label index. */
1944 new_client =
1945 (listnode_lookup(fec->client_list, client) == NULL);
57592a53
AD
1946 if (!new_client && fec->label_index == label_index
1947 && fec->label == label)
d62a17ae 1948 /* Duplicate register */
1949 return 0;
1950
57592a53 1951 /* Save current label, update the FEC */
d62a17ae 1952 old_label = fec->label;
1953 fec->label_index = label_index;
1954 }
1955
1956 if (new_client)
1957 listnode_add(fec->client_list, client);
1958
1959 if (IS_ZEBRA_DEBUG_MPLS)
57592a53
AD
1960 zlog_debug("FEC %s label%s %u %s by client %s%s", buf,
1961 have_label_index ? " index" : "",
1962 have_label_index ? label_index : label,
1963 new_client ? "registered" : "updated",
1964 zebra_route_string(client->proto),
1965 is_configured_fec
1966 ? ", but using statically configured label"
1967 : "");
1968
1969 /* If not a statically configured FEC, derive the local label
1970 * from label index or use the provided label
d62a17ae 1971 */
57592a53
AD
1972 if (!is_configured_fec) {
1973 if (have_label_index)
1974 fec_derive_label_from_index(zvrf, fec);
1975 else
1976 fec->label = label;
d62a17ae 1977
1978 /* If no label change, exit. */
1979 if (fec->label == old_label)
1980 return 0;
1981
57592a53 1982 label_change = true;
d62a17ae 1983 }
1984
1985 /* If new client or label change, update client and install or uninstall
1986 * label forwarding entry as needed.
1987 */
1988 /* Inform client of label, if needed. */
1989 if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
1990 if (IS_ZEBRA_DEBUG_MPLS)
1991 zlog_debug("Update client label %u", fec->label);
1992 fec_send(fec, client);
1993 }
1994
1995 if (new_client || label_change)
1996 return fec_change_update_lsp(zvrf, fec, old_label);
1997
1998 return 0;
5aba114a
DS
1999}
2000
2001/*
2002 * Deregistration from a client for the label binding for a FEC. The FEC
2003 * itself is deleted if no other registered clients exist and there is no
2004 * label bound to the FEC.
2005 */
d62a17ae 2006int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
2007 struct zserv *client)
5aba114a 2008{
d62a17ae 2009 struct route_table *table;
2010 zebra_fec_t *fec;
2011 char buf[BUFSIZ];
5aba114a 2012
d62a17ae 2013 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2014 if (!table)
2015 return -1;
5aba114a 2016
d62a17ae 2017 if (IS_ZEBRA_DEBUG_MPLS)
2018 prefix2str(p, buf, BUFSIZ);
5aba114a 2019
d62a17ae 2020 fec = fec_find(table, p);
2021 if (!fec) {
2022 prefix2str(p, buf, BUFSIZ);
e914ccbe 2023 flog_err(EC_ZEBRA_FEC_RM_FAILED,
1c50c1c0
QY
2024 "Failed to find FEC %s upon unregister, client %s",
2025 buf, zebra_route_string(client->proto));
d62a17ae 2026 return -1;
2027 }
5aba114a 2028
d62a17ae 2029 listnode_delete(fec->client_list, client);
2030
2031 if (IS_ZEBRA_DEBUG_MPLS)
2032 zlog_debug("FEC %s unregistered by client %s", buf,
2033 zebra_route_string(client->proto));
2034
2035 /* If not a configured entry, delete the FEC if no other clients. Before
2036 * deleting, see if any LSP needs to be uninstalled.
2037 */
2038 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2039 && list_isempty(fec->client_list)) {
2040 mpls_label_t old_label = fec->label;
2041 fec->label = MPLS_INVALID_LABEL; /* reset */
2042 fec_change_update_lsp(zvrf, fec, old_label);
2043 fec_del(fec);
2044 }
5aba114a 2045
d62a17ae 2046 return 0;
5aba114a
DS
2047}
2048
2049/*
2050 * Cleanup any FECs registered by this client.
2051 */
453844ab 2052static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
d62a17ae 2053{
453844ab 2054 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
d62a17ae 2055 struct route_node *rn;
2056 zebra_fec_t *fec;
2057 struct listnode *node;
2058 struct zserv *fec_client;
2059 int af;
2060
2061 for (af = AFI_IP; af < AFI_MAX; af++) {
2062 if (zvrf->fec_table[af] == NULL)
2063 continue;
2064
2065 for (rn = route_top(zvrf->fec_table[af]); rn;
2066 rn = route_next(rn)) {
2067 fec = rn->info;
2068 if (!fec || list_isempty(fec->client_list))
2069 continue;
2070
2071 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
2072 fec_client)) {
2073 if (fec_client == client) {
2074 listnode_delete(fec->client_list,
2075 fec_client);
2076 if (!(fec->flags & FEC_FLAG_CONFIGURED)
2077 && list_isempty(fec->client_list))
2078 fec_del(fec);
2079 break;
2080 }
2081 }
2082 }
2083 }
5aba114a 2084
d62a17ae 2085 return 0;
5aba114a
DS
2086}
2087
f31e084c
DS
2088/*
2089 * Return FEC (if any) to which this label is bound.
2090 * Note: Only works for per-prefix binding and when the label is not
2091 * implicit-null.
2092 * TODO: Currently walks entire table, can optimize later with another
2093 * hash..
2094 */
d62a17ae 2095zebra_fec_t *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
2096 mpls_label_t label)
2097{
2098 struct route_node *rn;
2099 zebra_fec_t *fec;
2100 int af;
2101
2102 for (af = AFI_IP; af < AFI_MAX; af++) {
2103 if (zvrf->fec_table[af] == NULL)
2104 continue;
2105
2106 for (rn = route_top(zvrf->fec_table[af]); rn;
2107 rn = route_next(rn)) {
2108 if (!rn->info)
2109 continue;
2110 fec = rn->info;
2111 if (fec->label == label)
2112 return fec;
2113 }
2114 }
f31e084c 2115
d62a17ae 2116 return NULL;
f31e084c
DS
2117}
2118
2119/*
2120 * Inform if specified label is currently bound to a FEC or not.
2121 */
d62a17ae 2122int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
f31e084c 2123{
d62a17ae 2124 return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
f31e084c
DS
2125}
2126
2127/*
5aba114a 2128 * Add static FEC to label binding. If there are clients registered for this
a64448ba
DS
2129 * FEC, notify them. If there are labeled routes for this FEC, install the
2130 * label forwarding entry.
9d303b37 2131*/
d62a17ae 2132int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
2133 mpls_label_t in_label)
2134{
2135 struct route_table *table;
2136 zebra_fec_t *fec;
2137 char buf[BUFSIZ];
2138 mpls_label_t old_label;
2139 int ret = 0;
2140
2141 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2142 if (!table)
2143 return -1;
2144
2145 if (IS_ZEBRA_DEBUG_MPLS)
2146 prefix2str(p, buf, BUFSIZ);
2147
2148 /* Update existing FEC or create a new one. */
2149 fec = fec_find(table, p);
2150 if (!fec) {
2151 fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
2152 MPLS_INVALID_LABEL_INDEX);
2153 if (!fec) {
2154 prefix2str(p, buf, BUFSIZ);
e914ccbe 2155 flog_err(EC_ZEBRA_FEC_ADD_FAILED,
1c50c1c0 2156 "Failed to add FEC %s upon config", buf);
d62a17ae 2157 return -1;
2158 }
2159
2160 if (IS_ZEBRA_DEBUG_MPLS)
2161 zlog_debug("Add fec %s label %u", buf, in_label);
2162 } else {
2163 fec->flags |= FEC_FLAG_CONFIGURED;
2164 if (fec->label == in_label)
2165 /* Duplicate config */
2166 return 0;
2167
2168 /* Label change, update clients. */
2169 old_label = fec->label;
2170 if (IS_ZEBRA_DEBUG_MPLS)
2171 zlog_debug("Update fec %s new label %u", buf, in_label);
2172
2173 fec->label = in_label;
2174 fec_update_clients(fec);
2175
2176 /* Update label forwarding entries appropriately */
2177 ret = fec_change_update_lsp(zvrf, fec, old_label);
2178 }
2179
2180 return ret;
f31e084c
DS
2181}
2182
2183/*
5aba114a
DS
2184 * Remove static FEC to label binding. If there are no clients registered
2185 * for this FEC, delete the FEC; else notify clients
28d58fd7
VV
2186 * Note: Upon delete of static binding, if label index exists for this FEC,
2187 * client may need to be updated with derived label.
f31e084c 2188 */
d62a17ae 2189int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
2190{
2191 struct route_table *table;
2192 zebra_fec_t *fec;
2193 mpls_label_t old_label;
2194 char buf[BUFSIZ];
2195
2196 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2197 if (!table)
2198 return -1;
2199
2200 fec = fec_find(table, p);
2201 if (!fec) {
2202 prefix2str(p, buf, BUFSIZ);
e914ccbe 2203 flog_err(EC_ZEBRA_FEC_RM_FAILED,
1c50c1c0 2204 "Failed to find FEC %s upon delete", buf);
d62a17ae 2205 return -1;
2206 }
2207
2208 if (IS_ZEBRA_DEBUG_MPLS) {
2209 prefix2str(p, buf, BUFSIZ);
57592a53
AD
2210 zlog_debug("Delete fec %s label %u label index %u", buf,
2211 fec->label, fec->label_index);
d62a17ae 2212 }
2213
2214 old_label = fec->label;
2215 fec->flags &= ~FEC_FLAG_CONFIGURED;
2216 fec->label = MPLS_INVALID_LABEL;
2217
2218 /* If no client exists, just delete the FEC. */
2219 if (list_isempty(fec->client_list)) {
2220 fec_del(fec);
2221 return 0;
2222 }
2223
2224 /* Derive the local label (from label index) or reset it. */
2225 fec_derive_label_from_index(zvrf, fec);
2226
2227 /* If there is a label change, update clients. */
2228 if (fec->label == old_label)
2229 return 0;
2230 fec_update_clients(fec);
2231
2232 /* Update label forwarding entries appropriately */
2233 return fec_change_update_lsp(zvrf, fec, old_label);
f31e084c
DS
2234}
2235
2236/*
2237 * Display MPLS FEC to label binding configuration (VTY command handler).
2238 */
d62a17ae 2239int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
f31e084c 2240{
d62a17ae 2241 struct route_node *rn;
2242 int af;
2243 zebra_fec_t *fec;
2244 char buf[BUFSIZ];
2245 int write = 0;
f31e084c 2246
d62a17ae 2247 for (af = AFI_IP; af < AFI_MAX; af++) {
2248 if (zvrf->fec_table[af] == NULL)
2249 continue;
f31e084c 2250
d62a17ae 2251 for (rn = route_top(zvrf->fec_table[af]); rn;
2252 rn = route_next(rn)) {
2253 if (!rn->info)
2254 continue;
f31e084c 2255
d62a17ae 2256 char lstr[BUFSIZ];
2257 fec = rn->info;
f31e084c 2258
d62a17ae 2259 if (!(fec->flags & FEC_FLAG_CONFIGURED))
2260 continue;
f31e084c 2261
d62a17ae 2262 write = 1;
2263 prefix2str(&rn->p, buf, BUFSIZ);
2264 vty_out(vty, "mpls label bind %s %s\n", buf,
2265 label2str(fec->label, lstr, BUFSIZ));
2266 }
2267 }
f31e084c 2268
d62a17ae 2269 return write;
f31e084c
DS
2270}
2271
2272/*
2273 * Display MPLS FEC to label binding (VTY command handler).
2274 */
d62a17ae 2275void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
f31e084c 2276{
d62a17ae 2277 struct route_node *rn;
2278 int af;
f31e084c 2279
d62a17ae 2280 for (af = AFI_IP; af < AFI_MAX; af++) {
2281 if (zvrf->fec_table[af] == NULL)
2282 continue;
f31e084c 2283
d62a17ae 2284 for (rn = route_top(zvrf->fec_table[af]); rn;
2285 rn = route_next(rn)) {
2286 if (!rn->info)
2287 continue;
2288 fec_print(rn->info, vty);
2289 }
2290 }
f31e084c
DS
2291}
2292
2293/*
2294 * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2295 */
d62a17ae 2296void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
2297 struct prefix *p)
f31e084c 2298{
d62a17ae 2299 struct route_table *table;
2300 struct route_node *rn;
f31e084c 2301
d62a17ae 2302 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2303 if (!table)
2304 return;
f31e084c 2305
d62a17ae 2306 apply_mask(p);
2307 rn = route_node_lookup(table, p);
2308 if (!rn)
2309 return;
f31e084c 2310
d62a17ae 2311 route_unlock_node(rn);
2312 if (!rn->info)
2313 return;
f31e084c 2314
d62a17ae 2315 fec_print(rn->info, vty);
f31e084c
DS
2316}
2317
8f77d0ee
DS
2318static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop,
2319 enum lsp_types_t type, mpls_label_t label)
2320{
2321 if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2322 nexthop_add_labels(nexthop, type, 1, &label);
2323 else if (!add && nexthop->nh_label_type == type)
2324 nexthop_del_labels(nexthop);
2325 else
2326 return false;
2327
2328 return true;
2329}
2330
ce549947
RW
2331/*
2332 * Install/uninstall a FEC-To-NHLFE (FTN) binding.
2333 */
d62a17ae 2334int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
2335 struct prefix *prefix, enum nexthop_types_t gtype,
d7c0a89a 2336 union g_addr *gate, ifindex_t ifindex, uint8_t distance,
d62a17ae 2337 mpls_label_t out_label)
2338{
2339 struct route_table *table;
2340 struct route_node *rn;
2341 struct route_entry *re;
2342 struct nexthop *nexthop;
8f77d0ee 2343 bool found;
d62a17ae 2344
2345 /* Lookup table. */
2346 table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
2347 zvrf_id(zvrf));
2348 if (!table)
2349 return -1;
2350
2351 /* Lookup existing route */
2352 rn = route_node_get(table, prefix);
a2addae8 2353 RNODE_FOREACH_RE (rn, re) {
d62a17ae 2354 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2355 continue;
2356 if (re->distance == distance)
2357 break;
88d88a9c 2358 }
ce549947 2359
d62a17ae 2360 if (re == NULL)
2361 return -1;
2362
8f77d0ee 2363 found = false;
7ee30f28 2364 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
d62a17ae 2365 switch (nexthop->type) {
2366 case NEXTHOP_TYPE_IPV4:
2367 case NEXTHOP_TYPE_IPV4_IFINDEX:
2368 if (gtype != NEXTHOP_TYPE_IPV4
2369 && gtype != NEXTHOP_TYPE_IPV4_IFINDEX)
2370 continue;
2371 if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4))
2372 continue;
2373 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
2374 && nexthop->ifindex != ifindex)
2375 continue;
8f77d0ee
DS
2376 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2377 out_label))
2378 return 0;
2379 found = true;
2380 break;
d62a17ae 2381 case NEXTHOP_TYPE_IPV6:
2382 case NEXTHOP_TYPE_IPV6_IFINDEX:
2383 if (gtype != NEXTHOP_TYPE_IPV6
2384 && gtype != NEXTHOP_TYPE_IPV6_IFINDEX)
2385 continue;
2386 if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, &gate->ipv6))
2387 continue;
2388 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
2389 && nexthop->ifindex != ifindex)
2390 continue;
8f77d0ee
DS
2391 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2392 out_label))
2393 return 0;
2394 found = true;
2395 break;
d62a17ae 2396 default:
2397 break;
2398 }
2399 }
d62a17ae 2400
8f77d0ee
DS
2401 if (!found)
2402 return -1;
ce549947 2403
d62a17ae 2404 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
332ad713 2405 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
d62a17ae 2406 rib_queue_add(rn);
ce549947 2407
d62a17ae 2408 return 0;
ce549947
RW
2409}
2410
2411/*
2412 * Install/update a NHLFE for an LSP in the forwarding table. This may be
2413 * a new LSP entry or a new NHLFE for an existing in-label or an update of
2414 * the out-label for an existing NHLFE (update case).
2415 */
d62a17ae 2416int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
2417 mpls_label_t in_label, mpls_label_t out_label,
2418 enum nexthop_types_t gtype, union g_addr *gate,
2419 ifindex_t ifindex)
2420{
2421 struct hash *lsp_table;
2422 zebra_ile_t tmp_ile;
2423 zebra_lsp_t *lsp;
2424 zebra_nhlfe_t *nhlfe;
2425 char buf[BUFSIZ];
2426
2427 /* Lookup table. */
2428 lsp_table = zvrf->lsp_table;
2429 if (!lsp_table)
2430 return -1;
2431
2432 /* If entry is present, exit. */
2433 tmp_ile.in_label = in_label;
2434 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2435 if (!lsp)
2436 return -1;
2437 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2438 if (nhlfe) {
2439 struct nexthop *nh = nhlfe->nexthop;
2440
2441 assert(nh);
2442 assert(nh->nh_label);
2443
2444 /* Clear deleted flag (in case it was set) */
2445 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2446 if (nh->nh_label->label[0] == out_label)
2447 /* No change */
2448 return 0;
2449
2450 if (IS_ZEBRA_DEBUG_MPLS) {
2451 nhlfe2str(nhlfe, buf, BUFSIZ);
2452 zlog_debug(
2453 "LSP in-label %u type %d nexthop %s "
2454 "out-label changed to %u (old %u)",
2455 in_label, type, buf, out_label,
2456 nh->nh_label->label[0]);
2457 }
2458
2459 /* Update out label, trigger processing. */
2460 nh->nh_label->label[0] = out_label;
2461 } else {
2462 /* Add LSP entry to this nexthop */
2463 nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, out_label);
2464 if (!nhlfe)
2465 return -1;
2466
2467 if (IS_ZEBRA_DEBUG_MPLS) {
2468 nhlfe2str(nhlfe, buf, BUFSIZ);
2469 zlog_debug(
2470 "Add LSP in-label %u type %d nexthop %s "
2471 "out-label %u",
2472 in_label, type, buf, out_label);
2473 }
2474
2475 lsp->addr_family = NHLFE_FAMILY(nhlfe);
2476 }
2477
2478 /* Mark NHLFE, queue LSP for processing. */
2479 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2480 if (lsp_processq_add(lsp))
2481 return -1;
2482
2483 return 0;
ce549947
RW
2484}
2485
2486/*
2487 * Uninstall a particular NHLFE in the forwarding table. If this is
2488 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
2489 */
d62a17ae 2490int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2491 mpls_label_t in_label, enum nexthop_types_t gtype,
2492 union g_addr *gate, ifindex_t ifindex)
2493{
2494 struct hash *lsp_table;
2495 zebra_ile_t tmp_ile;
2496 zebra_lsp_t *lsp;
2497 zebra_nhlfe_t *nhlfe;
2498 char buf[BUFSIZ];
2499
2500 /* Lookup table. */
2501 lsp_table = zvrf->lsp_table;
2502 if (!lsp_table)
2503 return -1;
2504
2505 /* If entry is not present, exit. */
2506 tmp_ile.in_label = in_label;
2507 lsp = hash_lookup(lsp_table, &tmp_ile);
2508 if (!lsp)
2509 return 0;
2510 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2511 if (!nhlfe)
2512 return 0;
2513
2514 if (IS_ZEBRA_DEBUG_MPLS) {
2515 nhlfe2str(nhlfe, buf, BUFSIZ);
2516 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
2517 in_label, type, buf, nhlfe->flags);
2518 }
2519
2520 /* Mark NHLFE for delete or directly delete, as appropriate. */
2521 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
2522 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2523 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2524 if (lsp_processq_add(lsp))
2525 return -1;
2526 } else {
2527 nhlfe_del(nhlfe);
2528
2529 /* Free LSP entry if no other NHLFEs and not scheduled. */
2530 if (!lsp->nhlfe_list
2531 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
2532 if (IS_ZEBRA_DEBUG_MPLS)
2533 zlog_debug("Free LSP in-label %u flags 0x%x",
2534 lsp->ile.in_label, lsp->flags);
2535
2536 lsp = hash_release(lsp_table, &lsp->ile);
0a22ddfb 2537 XFREE(MTYPE_LSP, lsp);
d62a17ae 2538 }
2539 }
2540 return 0;
ce549947
RW
2541}
2542
2543/*
2544 * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
2545 * If no other NHLFEs exist, the entry would be deleted.
2546 */
e3b78da8 2547void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt)
ce549947 2548{
d62a17ae 2549 zebra_lsp_t *lsp;
2550 struct hash *lsp_table;
ce549947 2551
e3b78da8 2552 lsp = (zebra_lsp_t *)bucket->data;
9ea660be 2553 if (!lsp->nhlfe_list)
d62a17ae 2554 return;
ce549947 2555
d62a17ae 2556 lsp_table = ctxt;
2557 if (!lsp_table)
2558 return;
ce549947 2559
d62a17ae 2560 mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP);
ce549947
RW
2561}
2562
2563/*
2564 * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
2565 */
d62a17ae 2566void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
2567{
2568 struct route_table *table;
2569 struct route_node *rn;
2570 struct route_entry *re;
2571 struct nexthop *nexthop;
2572 int update;
2573
2574 /* Process routes of interested address-families. */
2575 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2576 if (!table)
2577 return;
2578
2579 for (rn = route_top(table); rn; rn = route_next(rn)) {
2580 update = 0;
a2addae8 2581 RNODE_FOREACH_RE (rn, re) {
7ee30f28 2582 for (nexthop = re->ng.nexthop; nexthop;
407c87a6
DS
2583 nexthop = nexthop->next) {
2584 if (nexthop->nh_label_type != ZEBRA_LSP_LDP)
2585 continue;
2586
d62a17ae 2587 nexthop_del_labels(nexthop);
2588 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2589 SET_FLAG(re->status,
332ad713 2590 ROUTE_ENTRY_LABELS_CHANGED);
d62a17ae 2591 update = 1;
2592 }
407c87a6 2593 }
d62a17ae 2594
2595 if (update)
2596 rib_queue_add(rn);
2597 }
ce549947
RW
2598}
2599
1c1cf002 2600#if defined(HAVE_CUMULUS)
7758e3f3 2601/*
2602 * Check that the label values used in LSP creation are consistent. The
2603 * main criteria is that if there is ECMP, the label operation must still
2604 * be consistent - i.e., all paths either do a swap or do PHP. This is due
2605 * to current HW restrictions.
2606 */
d62a17ae 2607int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
2608 mpls_label_t in_label,
2609 mpls_label_t out_label,
2610 enum nexthop_types_t gtype,
2611 union g_addr *gate, ifindex_t ifindex)
2612{
2613 struct hash *slsp_table;
2614 zebra_ile_t tmp_ile;
2615 zebra_slsp_t *slsp;
2616 zebra_snhlfe_t *snhlfe;
2617
2618 /* Lookup table. */
2619 slsp_table = zvrf->slsp_table;
2620 if (!slsp_table)
2621 return 0;
2622
2623 /* If entry is not present, exit. */
2624 tmp_ile.in_label = in_label;
2625 slsp = hash_lookup(slsp_table, &tmp_ile);
2626 if (!slsp)
2627 return 1;
2628
2629 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2630 if (snhlfe) {
2631 if (snhlfe->out_label == out_label)
2632 return 1;
2633
2634 /* If not only NHLFE, cannot allow label change. */
2635 if (snhlfe != slsp->snhlfe_list || snhlfe->next)
2636 return 0;
2637 } else {
2638 /* If other NHLFEs exist, label operation must match. */
2639 if (slsp->snhlfe_list) {
2640 int cur_op, new_op;
2641
2642 cur_op = (slsp->snhlfe_list->out_label
70e98a7f
DS
2643 == MPLS_LABEL_IMPLICIT_NULL);
2644 new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
d62a17ae 2645 if (cur_op != new_op)
2646 return 0;
2647 }
2648 }
2649
2650 /* Label values are good. */
2651 return 1;
7758e3f3 2652}
1c1cf002 2653#endif /* HAVE_CUMULUS */
7758e3f3 2654
2655/*
2656 * Add static LSP entry. This may be the first entry for this incoming label
2657 * or an additional nexthop; an existing entry may also have outgoing label
2658 * changed.
2659 * Note: The label operation (swap or PHP) is common for the LSP entry (all
2660 * NHLFEs).
2661 */
d62a17ae 2662int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
2663 mpls_label_t out_label,
2664 enum nexthop_types_t gtype, union g_addr *gate,
2665 ifindex_t ifindex)
2666{
2667 struct hash *slsp_table;
2668 zebra_ile_t tmp_ile;
2669 zebra_slsp_t *slsp;
2670 zebra_snhlfe_t *snhlfe;
2671 char buf[BUFSIZ];
2672
2673 /* Lookup table. */
2674 slsp_table = zvrf->slsp_table;
2675 if (!slsp_table)
2676 return -1;
2677
2678 /* If entry is present, exit. */
2679 tmp_ile.in_label = in_label;
2680 slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc);
2681 if (!slsp)
2682 return -1;
2683 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2684 if (snhlfe) {
2685 if (snhlfe->out_label == out_label)
2686 /* No change */
2687 return 0;
2688
2689 if (IS_ZEBRA_DEBUG_MPLS) {
2690 snhlfe2str(snhlfe, buf, BUFSIZ);
2691 zlog_debug(
2692 "Upd static LSP in-label %u nexthop %s "
2693 "out-label %u (old %u)",
2694 in_label, buf, out_label, snhlfe->out_label);
2695 }
2696 snhlfe->out_label = out_label;
2697 } else {
2698 /* Add static LSP entry to this nexthop */
2699 snhlfe = snhlfe_add(slsp, gtype, gate, ifindex, out_label);
2700 if (!snhlfe)
2701 return -1;
2702
2703 if (IS_ZEBRA_DEBUG_MPLS) {
2704 snhlfe2str(snhlfe, buf, BUFSIZ);
2705 zlog_debug(
2706 "Add static LSP in-label %u nexthop %s out-label %u",
2707 in_label, buf, out_label);
2708 }
2709 }
2710
2711 /* (Re)Install LSP in the main table. */
2712 if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
2713 gate, ifindex))
2714 return -1;
2715
2716 return 0;
7758e3f3 2717}
2718
2719/*
2720 * Delete static LSP entry. This may be the delete of one particular
2721 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
2722 * all NHLFEs).
2723 * NOTE: Delete of the only NHLFE will also end up deleting the entire
2724 * LSP configuration.
2725 */
d62a17ae 2726int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
2727 enum nexthop_types_t gtype, union g_addr *gate,
2728 ifindex_t ifindex)
2729{
2730 struct hash *slsp_table;
2731 zebra_ile_t tmp_ile;
2732 zebra_slsp_t *slsp;
2733 zebra_snhlfe_t *snhlfe;
2734
2735 /* Lookup table. */
2736 slsp_table = zvrf->slsp_table;
2737 if (!slsp_table)
2738 return -1;
2739
2740 /* If entry is not present, exit. */
2741 tmp_ile.in_label = in_label;
2742 slsp = hash_lookup(slsp_table, &tmp_ile);
2743 if (!slsp)
2744 return 0;
2745
2746 /* Is it delete of entire LSP or a specific NHLFE? */
2747 if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
2748 if (IS_ZEBRA_DEBUG_MPLS)
2749 zlog_debug("Del static LSP in-label %u", in_label);
2750
2751 /* Uninstall entire LSP from the main table. */
2752 mpls_static_lsp_uninstall_all(zvrf, in_label);
2753
2754 /* Delete all static NHLFEs */
2755 snhlfe_del_all(slsp);
2756 } else {
2757 /* Find specific NHLFE, exit if not found. */
2758 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2759 if (!snhlfe)
2760 return 0;
2761
2762 if (IS_ZEBRA_DEBUG_MPLS) {
2763 char buf[BUFSIZ];
2764 snhlfe2str(snhlfe, buf, BUFSIZ);
2765 zlog_debug("Del static LSP in-label %u nexthop %s",
2766 in_label, buf);
2767 }
2768
2769 /* Uninstall LSP from the main table. */
2770 mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
2771 gate, ifindex);
2772
2773 /* Delete static LSP NHLFE */
2774 snhlfe_del(snhlfe);
2775 }
2776
2777 /* Remove entire static LSP entry if no NHLFE - valid in either case
2778 * above. */
2779 if (!slsp->snhlfe_list) {
2780 slsp = hash_release(slsp_table, &tmp_ile);
0a22ddfb 2781 XFREE(MTYPE_SLSP, slsp);
d62a17ae 2782 }
2783
2784 return 0;
7758e3f3 2785}
2786
40c7bdb0 2787/*
2788 * Schedule all MPLS label forwarding entries for processing.
2789 * Called upon changes that may affect one or more of them such as
2790 * interface or nexthop state changes.
2791 */
d62a17ae 2792void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
40c7bdb0 2793{
d62a17ae 2794 if (!zvrf)
2795 return;
2796 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
40c7bdb0 2797}
2798
3ab18ff2 2799/*
2800 * Display MPLS label forwarding table for a specific LSP
2801 * (VTY command handler).
2802 */
d62a17ae 2803void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
9f049418 2804 mpls_label_t label, bool use_json)
3ab18ff2 2805{
d62a17ae 2806 struct hash *lsp_table;
2807 zebra_lsp_t *lsp;
2808 zebra_ile_t tmp_ile;
2809 json_object *json = NULL;
3ab18ff2 2810
d62a17ae 2811 /* Lookup table. */
2812 lsp_table = zvrf->lsp_table;
2813 if (!lsp_table)
2814 return;
3ab18ff2 2815
d62a17ae 2816 /* If entry is not present, exit. */
2817 tmp_ile.in_label = label;
2818 lsp = hash_lookup(lsp_table, &tmp_ile);
2819 if (!lsp)
2820 return;
3ab18ff2 2821
d62a17ae 2822 if (use_json) {
2823 json = lsp_json(lsp);
9d303b37
DL
2824 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2825 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 2826 json_object_free(json);
2827 } else
2828 lsp_print(lsp, (void *)vty);
3ab18ff2 2829}
2830
2831/*
2832 * Display MPLS label forwarding table (VTY command handler).
2833 */
d62a17ae 2834void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
9f049418 2835 bool use_json)
d62a17ae 2836{
2837 char buf[BUFSIZ];
2838 json_object *json = NULL;
2839 zebra_lsp_t *lsp = NULL;
2840 zebra_nhlfe_t *nhlfe = NULL;
2841 struct nexthop *nexthop = NULL;
2842 struct listnode *node = NULL;
2843 struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
2844
2845 if (use_json) {
2846 json = json_object_new_object();
2847
2848 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
2849 json_object_object_add(
2850 json, label2str(lsp->ile.in_label, buf, BUFSIZ),
2851 lsp_json(lsp));
2852
9d303b37
DL
2853 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2854 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 2855 json_object_free(json);
2856 } else {
2857 vty_out(vty, " Inbound Outbound\n");
2858 vty_out(vty, " Label Type Nexthop Label\n");
2859 vty_out(vty, "-------- ------- --------------- --------\n");
2860
2861 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
2862 for (nhlfe = lsp->nhlfe_list; nhlfe;
2863 nhlfe = nhlfe->next) {
2864 vty_out(vty, "%8d %7s ", lsp->ile.in_label,
2865 nhlfe_type2str(nhlfe->type));
2866 nexthop = nhlfe->nexthop;
2867
2868 switch (nexthop->type) {
996c9314 2869 case NEXTHOP_TYPE_IFINDEX: {
86f07f44 2870 struct zebra_ns *zns;
b9abd9ad
DS
2871 struct interface *ifp;
2872
86f07f44
PG
2873 zns = zebra_ns_lookup(NS_DEFAULT);
2874 ifp = if_lookup_by_index_per_ns(
2875 zns,
2876 nexthop->ifindex);
94cb112b
MS
2877 if (ifp)
2878 vty_out(vty, "%15s", ifp->name);
2879 else
2880 vty_out(vty, "%15s", "Null");
2881
b9abd9ad
DS
2882 break;
2883 }
d62a17ae 2884 case NEXTHOP_TYPE_IPV4:
2885 case NEXTHOP_TYPE_IPV4_IFINDEX:
2886 vty_out(vty, "%15s",
2887 inet_ntoa(nexthop->gate.ipv4));
2888 break;
2889 case NEXTHOP_TYPE_IPV6:
2890 case NEXTHOP_TYPE_IPV6_IFINDEX:
2891 vty_out(vty, "%15s",
2892 inet_ntop(AF_INET6,
2893 &nexthop->gate.ipv6,
2894 buf, BUFSIZ));
2895 break;
2896 default:
2897 break;
2898 }
2899
b9abd9ad 2900 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
fc5cca9f
DS
2901 vty_out(vty, " %8s\n",
2902 mpls_label2str(
2903 nexthop->nh_label
2904 ->num_labels,
2905 &nexthop->nh_label
2906 ->label[0],
2907 buf, BUFSIZ, 1));
b9abd9ad
DS
2908 else
2909 vty_out(vty, "\n");
d62a17ae 2910 }
2911 }
2912
2913 vty_out(vty, "\n");
2914 }
2915
6a154c88 2916 list_delete(&lsp_list);
3ab18ff2 2917}
2918
7758e3f3 2919/*
2920 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
2921 */
d62a17ae 2922int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
2923{
2924 zebra_slsp_t *slsp;
2925 zebra_snhlfe_t *snhlfe;
2926 struct listnode *node;
2927 struct list *slsp_list =
2928 hash_get_sorted_list(zvrf->slsp_table, slsp_cmp);
2929
2930 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) {
2931 for (snhlfe = slsp->snhlfe_list; snhlfe;
2932 snhlfe = snhlfe->next) {
0af35d90 2933 char buf[BUFSIZ];
d62a17ae 2934 char lstr[30];
2935
0af35d90 2936 snhlfe2str(snhlfe, buf, sizeof(buf));
d62a17ae 2937 switch (snhlfe->out_label) {
70e98a7f
DS
2938 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
2939 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
d62a17ae 2940 strlcpy(lstr, "explicit-null", sizeof(lstr));
2941 break;
70e98a7f 2942 case MPLS_LABEL_IMPLICIT_NULL:
d62a17ae 2943 strlcpy(lstr, "implicit-null", sizeof(lstr));
2944 break;
2945 default:
2946 sprintf(lstr, "%u", snhlfe->out_label);
2947 break;
2948 }
2949
2950 vty_out(vty, "mpls lsp %u %s %s\n", slsp->ile.in_label,
2951 buf, lstr);
2952 }
2953 }
b78b820d 2954
6a154c88 2955 list_delete(&slsp_list);
d62a17ae 2956 return (zvrf->slsp_table->count ? 1 : 0);
7758e3f3 2957}
2958
1b6d5c7e
VV
2959/*
2960 * Add/update global label block.
2961 */
d7c0a89a
QY
2962int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
2963 uint32_t end_label)
1b6d5c7e 2964{
d62a17ae 2965 zvrf->mpls_srgb.start_label = start_label;
2966 zvrf->mpls_srgb.end_label = end_label;
28d58fd7 2967
d62a17ae 2968 /* Evaluate registered FECs to see if any get a label or not. */
2969 fec_evaluate(zvrf);
2970 return 0;
1b6d5c7e
VV
2971}
2972
2973/*
2974 * Delete global label block.
2975 */
d62a17ae 2976int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
1b6d5c7e 2977{
d62a17ae 2978 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
2979 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
28d58fd7 2980
d62a17ae 2981 /* Process registered FECs to clear their local label, if needed. */
2982 fec_evaluate(zvrf);
2983 return 0;
1b6d5c7e
VV
2984}
2985
2986/*
2987 * Display MPLS global label block configuration (VTY command handler).
2988 */
d62a17ae 2989int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
1b6d5c7e 2990{
d62a17ae 2991 if (zvrf->mpls_srgb.start_label == 0)
2992 return 0;
1b6d5c7e 2993
d62a17ae 2994 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
2995 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
2996 vty_out(vty, "mpls label global-block %u %u\n",
2997 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
2998 }
1b6d5c7e 2999
d62a17ae 3000 return 1;
1b6d5c7e
VV
3001}
3002
84915b0a 3003/*
3004 * Called when VRF becomes inactive, cleans up information but keeps
3005 * the table itself.
84915b0a 3006 */
3007void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
3008{
94cb112b
MS
3009 struct zebra_vrf *def_zvrf;
3010 afi_t afi;
3011
3012 if (zvrf_id(zvrf) == VRF_DEFAULT)
3013 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3014 else {
3015 /*
3016 * For other vrfs, we try to remove associated LSPs; we locate
3017 * the LSPs in the default vrf.
3018 */
3019 def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
3020
3021 /* At shutdown, the default may be gone already */
3022 if (def_zvrf == NULL)
3023 return;
3024
3025 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
3026 if (zvrf->label[afi] != MPLS_LABEL_NONE)
3027 lsp_uninstall(def_zvrf, zvrf->label[afi]);
3028 }
3029 }
84915b0a 3030}
3031
40c7bdb0 3032/*
3033 * Called upon process exiting, need to delete LSP forwarding
3034 * entries from the kernel.
3035 * NOTE: Currently supported only for default VRF.
3036 */
d62a17ae 3037void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
40c7bdb0 3038{
d62a17ae 3039 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3040 hash_clean(zvrf->lsp_table, NULL);
3041 hash_free(zvrf->lsp_table);
3042 hash_clean(zvrf->slsp_table, NULL);
3043 hash_free(zvrf->slsp_table);
9b67b514
DS
3044 route_table_finish(zvrf->fec_table[AFI_IP]);
3045 route_table_finish(zvrf->fec_table[AFI_IP6]);
40c7bdb0 3046}
3047
7758e3f3 3048/*
3049 * Allocate MPLS tables for this VRF and do other initialization.
3050 * NOTE: Currently supported only for default VRF.
3051 */
d62a17ae 3052void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
7758e3f3 3053{
d62a17ae 3054 if (!zvrf)
3055 return;
996c9314
LB
3056 zvrf->slsp_table =
3057 hash_create(label_hash, label_cmp, "ZEBRA SLSP table");
3058 zvrf->lsp_table = hash_create(label_hash, label_cmp, "ZEBRA LSP table");
d62a17ae 3059 zvrf->fec_table[AFI_IP] = route_table_init();
3060 zvrf->fec_table[AFI_IP6] = route_table_init();
3061 zvrf->mpls_flags = 0;
3062 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3063 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
7758e3f3 3064}
3065
3066/*
3067 * Global MPLS initialization.
3068 */
d62a17ae 3069void zebra_mpls_init(void)
7758e3f3 3070{
d62a17ae 3071 mpls_enabled = 0;
33c32282 3072
d62a17ae 3073 if (mpls_kernel_init() < 0) {
e914ccbe 3074 flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
9df414fe 3075 "Disabling MPLS support (no kernel support)");
d62a17ae 3076 return;
3077 }
fe6c7157 3078
2561d12e 3079 if (!mpls_processq_init())
d62a17ae 3080 mpls_enabled = 1;
453844ab 3081
21ccc0cf 3082 hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
7758e3f3 3083}