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