]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_mpls.c
zebra: add packet length into pbr support
[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);
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);
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,
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);
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 */
7ee30f28 185 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
d62a17ae 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;
d7c0a89a 333 uint32_t old_label, new_label;
d62a17ae 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 */
d7c0a89a
QY
385static uint32_t fec_derive_label_from_index(struct zebra_vrf *zvrf,
386 zebra_fec_t *fec)
28d58fd7 387{
d7c0a89a 388 uint32_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. */
996c9314
LB
414 if (old_label != MPLS_INVALID_LABEL
415 && old_label != MPLS_LABEL_IMPLICIT_NULL)
d62a17ae 416 lsp_uninstall(zvrf, old_label);
a64448ba 417
d62a17ae 418 /* Install label forwarding entry corr. to new label, if needed. */
419 if (fec->label == MPLS_INVALID_LABEL
70e98a7f 420 || fec->label == MPLS_LABEL_IMPLICIT_NULL)
d62a17ae 421 return 0;
a64448ba 422
d62a17ae 423 afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
424 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
425 if (!table)
426 return 0;
a64448ba 427
d62a17ae 428 /* See if labeled route exists. */
429 rn = route_node_lookup(table, &fec->rn->p);
430 if (!rn)
431 return 0;
a64448ba 432
a2addae8 433 RNODE_FOREACH_RE (rn, re) {
d62a17ae 434 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
435 break;
436 }
a64448ba 437
d62a17ae 438 if (!re || !zebra_rib_labeled_unicast(re))
439 return 0;
a64448ba 440
d62a17ae 441 if (lsp_install(zvrf, fec->label, rn, re))
442 return -1;
a64448ba 443
d62a17ae 444 return 0;
a64448ba
DS
445}
446
5aba114a
DS
447/*
448 * Inform about FEC to a registered client.
449 */
d62a17ae 450static int fec_send(zebra_fec_t *fec, struct zserv *client)
5aba114a 451{
d62a17ae 452 struct stream *s;
453 struct route_node *rn;
5aba114a 454
d62a17ae 455 rn = fec->rn;
5aba114a 456
d62a17ae 457 /* Get output stream. */
1002497a 458 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
5aba114a 459
7cf15b25 460 zclient_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));
1002497a 466 return zebra_server_send_message(client, s);
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,
d7c0a89a
QY
535 mpls_label_t label, uint32_t flags,
536 uint32_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
4a7371e9 617 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, nexthop->vrf_id);
d62a17ae 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
7ee30f28 639 for (match_nh = match->ng.nexthop; match_nh;
d62a17ae 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
4a7371e9 666 table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
d62a17ae 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
7ee30f28 690 if (!match || !match->ng.nexthop)
d62a17ae 691 return 0;
40c7bdb0 692
7ee30f28 693 nexthop->ifindex = match->ng.nexthop->ifindex;
d62a17ae 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) {
b9abd9ad
DS
714 case NEXTHOP_TYPE_IFINDEX:
715 /*
716 * Lookup if this type is special. The
717 * NEXTHOP_TYPE_IFINDEX is a pop and
718 * forward into a different table for
719 * processing. As such this ifindex
720 * passed to us may be a VRF device
721 * which will not be in the default
722 * VRF. So let's look in all of them
723 */
724 ifp = if_lookup_by_index(nexthop->ifindex, VRF_UNKNOWN);
725 if (ifp && if_is_operative(ifp))
726 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
727 else
728 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
729 break;
d62a17ae 730 case NEXTHOP_TYPE_IPV4:
731 case NEXTHOP_TYPE_IPV4_IFINDEX:
732 if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop))
733 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
734 else
735 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
736 break;
737
738 case NEXTHOP_TYPE_IPV6:
739 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
740 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
741 else
742 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
743 break;
744
745 case NEXTHOP_TYPE_IPV6_IFINDEX:
746 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
4a7371e9
DS
747 ifp = if_lookup_by_index(nexthop->ifindex,
748 nexthop->vrf_id);
d62a17ae 749 if (ifp && if_is_operative(ifp))
750 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
751 else
752 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
753 } else {
754 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
755 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
756 else
757 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
758 }
759 break;
760
761 default:
762 break;
763 }
764
765 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
40c7bdb0 766}
767
768/*
769 * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
770 * reachability and select the best. Multipath entries are also
771 * marked. This is invoked when an LSP scheduled for processing (due
772 * to some change) is examined.
773 */
d62a17ae 774static void lsp_select_best_nhlfe(zebra_lsp_t *lsp)
775{
776 zebra_nhlfe_t *nhlfe;
777 zebra_nhlfe_t *best;
778 struct nexthop *nexthop;
779 int changed = 0;
780
781 if (!lsp)
782 return;
783
784 best = NULL;
785 lsp->num_ecmp = 0;
786 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
787
788 /*
789 * First compute the best path, after checking nexthop status. We are
790 * only
791 * concerned with non-deleted NHLFEs.
792 */
793 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
794 /* Clear selection flags. */
795 UNSET_FLAG(nhlfe->flags,
796 (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
797
798 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
799 && nhlfe_nexthop_active(nhlfe)) {
800 if (!best || (nhlfe->distance < best->distance))
801 best = nhlfe;
802 }
803 }
804
805 lsp->best_nhlfe = best;
806 if (!lsp->best_nhlfe)
807 return;
808
809 /* Mark best NHLFE as selected. */
810 SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
811
812 /*
813 * If best path exists, see if there is ECMP. While doing this, note if
814 * a
815 * new (uninstalled) NHLFE has been selected, an installed entry that is
816 * still selected has a change or an installed entry is to be removed.
817 */
818 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
819 int nh_chg, nh_sel, nh_inst;
820
821 nexthop = nhlfe->nexthop;
822 if (!nexthop) // unexpected
823 continue;
824
825 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
826 && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
827 && (nhlfe->distance == lsp->best_nhlfe->distance)) {
828 SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
829 SET_FLAG(nhlfe->flags, NHLFE_FLAG_MULTIPATH);
830 lsp->num_ecmp++;
831 }
832
833 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) && !changed) {
834 nh_chg = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
835 nh_sel = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
836 nh_inst =
837 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
838
839 if ((nh_sel && !nh_inst)
840 || (nh_sel && nh_inst && nh_chg)
841 || (nh_inst && !nh_sel))
842 changed = 1;
843 }
844
845 /* We have finished examining, clear changed flag. */
846 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
847 }
848
849 if (changed)
850 SET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
40c7bdb0 851}
852
853/*
854 * Delete LSP forwarding entry from kernel, if installed. Called upon
855 * process exit.
856 */
d62a17ae 857static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt)
40c7bdb0 858{
d62a17ae 859 zebra_lsp_t *lsp;
40c7bdb0 860
d62a17ae 861 lsp = (zebra_lsp_t *)backet->data;
4a83e7a0
DS
862 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
863 kernel_del_lsp(lsp);
40c7bdb0 864}
865
866/*
867 * Schedule LSP forwarding entry for processing. Called upon changes
868 * that may impact LSPs such as nexthop / connected route changes.
869 */
d62a17ae 870static void lsp_schedule(struct hash_backet *backet, void *ctxt)
40c7bdb0 871{
d62a17ae 872 zebra_lsp_t *lsp;
40c7bdb0 873
d62a17ae 874 lsp = (zebra_lsp_t *)backet->data;
0af35d90 875 (void)lsp_processq_add(lsp);
40c7bdb0 876}
877
878/*
879 * Process a LSP entry that is in the queue. Recalculate best NHLFE and
880 * any multipaths and update or delete from the kernel, as needed.
881 */
d62a17ae 882static wq_item_status lsp_process(struct work_queue *wq, void *data)
883{
884 zebra_lsp_t *lsp;
885 zebra_nhlfe_t *oldbest, *newbest;
886 char buf[BUFSIZ], buf2[BUFSIZ];
887 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
888
889 lsp = (zebra_lsp_t *)data;
890 if (!lsp) // unexpected
891 return WQ_SUCCESS;
892
893 oldbest = lsp->best_nhlfe;
894
895 /* Select best NHLFE(s) */
896 lsp_select_best_nhlfe(lsp);
897
898 newbest = lsp->best_nhlfe;
899
900 if (IS_ZEBRA_DEBUG_MPLS) {
901 if (oldbest)
902 nhlfe2str(oldbest, buf, BUFSIZ);
903 if (newbest)
904 nhlfe2str(newbest, buf2, BUFSIZ);
905 zlog_debug(
906 "Process LSP in-label %u oldbest %s newbest %s "
907 "flags 0x%x ecmp# %d",
908 lsp->ile.in_label, oldbest ? buf : "NULL",
909 newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
910 }
911
912 if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
913 /* Not already installed */
914 if (newbest) {
2b63430c
DS
915
916 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
4a83e7a0 917 kernel_add_lsp(lsp);
2b63430c 918
d62a17ae 919 zvrf->lsp_installs++;
920 }
921 } else {
922 /* Installed, may need an update and/or delete. */
923 if (!newbest) {
e6d44ec7 924
4a83e7a0 925 kernel_del_lsp(lsp);
e6d44ec7 926
d62a17ae 927 zvrf->lsp_removals++;
928 } else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) {
9fa38ec6
DS
929 zebra_nhlfe_t *nhlfe;
930 struct nexthop *nexthop;
2b63430c
DS
931
932 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
933 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
e6d44ec7 934
9fa38ec6
DS
935 /*
936 * Any NHLFE that was installed but is not
937 * selected now needs to have its flags updated.
938 */
996c9314
LB
939 for (nhlfe = lsp->nhlfe_list; nhlfe;
940 nhlfe = nhlfe->next) {
9fa38ec6
DS
941 nexthop = nhlfe->nexthop;
942 if (!nexthop)
943 continue;
944
945 if (CHECK_FLAG(nhlfe->flags,
996c9314
LB
946 NHLFE_FLAG_INSTALLED)
947 && !CHECK_FLAG(nhlfe->flags,
948 NHLFE_FLAG_SELECTED)) {
9fa38ec6
DS
949 UNSET_FLAG(nhlfe->flags,
950 NHLFE_FLAG_INSTALLED);
951 UNSET_FLAG(nexthop->flags,
952 NEXTHOP_FLAG_FIB);
953 }
954 }
955
4a83e7a0 956 kernel_upd_lsp(lsp);
2b63430c 957
d62a17ae 958 zvrf->lsp_installs++;
959 }
960 }
961
962 return WQ_SUCCESS;
40c7bdb0 963}
964
965
966/*
967 * Callback upon processing completion of a LSP forwarding entry.
968 */
d62a17ae 969static void lsp_processq_del(struct work_queue *wq, void *data)
40c7bdb0 970{
d62a17ae 971 struct zebra_vrf *zvrf;
972 zebra_lsp_t *lsp;
973 struct hash *lsp_table;
974 zebra_nhlfe_t *nhlfe, *nhlfe_next;
40c7bdb0 975
d62a17ae 976 zvrf = vrf_info_lookup(VRF_DEFAULT);
977 assert(zvrf);
40c7bdb0 978
d62a17ae 979 lsp_table = zvrf->lsp_table;
980 if (!lsp_table) // unexpected
981 return;
40c7bdb0 982
d62a17ae 983 lsp = (zebra_lsp_t *)data;
984 if (!lsp) // unexpected
985 return;
40c7bdb0 986
d62a17ae 987 /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
988 * exist,
989 * delete LSP entry also.
990 */
991 UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
40c7bdb0 992
d62a17ae 993 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) {
994 nhlfe_next = nhlfe->next;
995 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
996 nhlfe_del(nhlfe);
997 }
40c7bdb0 998
d62a17ae 999 if (!lsp->nhlfe_list) {
1000 if (IS_ZEBRA_DEBUG_MPLS)
1001 zlog_debug("Free LSP in-label %u flags 0x%x",
1002 lsp->ile.in_label, lsp->flags);
40c7bdb0 1003
d62a17ae 1004 lsp = hash_release(lsp_table, &lsp->ile);
1005 if (lsp)
1006 XFREE(MTYPE_LSP, lsp);
1007 }
40c7bdb0 1008}
1009
1010/*
1011 * Callback upon finishing the processing of all scheduled
1012 * LSP forwarding entries.
1013 */
d62a17ae 1014static void lsp_processq_complete(struct work_queue *wq)
40c7bdb0 1015{
d62a17ae 1016 /* Nothing to do for now. */
40c7bdb0 1017}
1018
1019/*
1020 * Add LSP forwarding entry to queue for subsequent processing.
1021 */
d62a17ae 1022static int lsp_processq_add(zebra_lsp_t *lsp)
40c7bdb0 1023{
d62a17ae 1024 /* If already scheduled, exit. */
1025 if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1026 return 0;
40c7bdb0 1027
d62a17ae 1028 if (zebrad.lsp_process_q == NULL) {
1029 zlog_err("%s: work_queue does not exist!", __func__);
1030 return -1;
1031 }
33c32282 1032
d62a17ae 1033 work_queue_add(zebrad.lsp_process_q, lsp);
1034 SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1035 return 0;
40c7bdb0 1036}
1037
1038/*
1039 * Callback to allocate LSP forwarding table entry.
1040 */
d62a17ae 1041static void *lsp_alloc(void *p)
40c7bdb0 1042{
d62a17ae 1043 const zebra_ile_t *ile = p;
1044 zebra_lsp_t *lsp;
40c7bdb0 1045
d62a17ae 1046 lsp = XCALLOC(MTYPE_LSP, sizeof(zebra_lsp_t));
1047 lsp->ile = *ile;
40c7bdb0 1048
d62a17ae 1049 if (IS_ZEBRA_DEBUG_MPLS)
1050 zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label);
40c7bdb0 1051
d62a17ae 1052 return ((void *)lsp);
40c7bdb0 1053}
1054
1055/*
1056 * Create printable string for NHLFE entry.
1057 */
d62a17ae 1058static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size)
40c7bdb0 1059{
d62a17ae 1060 struct nexthop *nexthop;
40c7bdb0 1061
d62a17ae 1062 buf[0] = '\0';
1063 nexthop = nhlfe->nexthop;
1064 switch (nexthop->type) {
1065 case NEXTHOP_TYPE_IPV4:
1066 case NEXTHOP_TYPE_IPV4_IFINDEX:
1067 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
1068 break;
1069 case NEXTHOP_TYPE_IPV6:
1070 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
1071 break;
b9abd9ad
DS
1072 case NEXTHOP_TYPE_IFINDEX:
1073 snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
d62a17ae 1074 default:
1075 break;
1076 }
40c7bdb0 1077
d62a17ae 1078 return buf;
40c7bdb0 1079}
1080
1081/*
1082 * Check if NHLFE matches with search info passed.
1083 */
d62a17ae 1084static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
1085 union g_addr *gate, ifindex_t ifindex)
40c7bdb0 1086{
d62a17ae 1087 struct nexthop *nhop;
1088 int cmp = 1;
40c7bdb0 1089
d62a17ae 1090 nhop = nhlfe->nexthop;
1091 if (!nhop)
1092 return 1;
40c7bdb0 1093
d62a17ae 1094 if (nhop->type != gtype)
1095 return 1;
40c7bdb0 1096
d62a17ae 1097 switch (nhop->type) {
1098 case NEXTHOP_TYPE_IPV4:
1099 case NEXTHOP_TYPE_IPV4_IFINDEX:
1100 cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
1101 sizeof(struct in_addr));
1102 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1103 cmp = !(nhop->ifindex == ifindex);
1104 break;
1105 case NEXTHOP_TYPE_IPV6:
1106 case NEXTHOP_TYPE_IPV6_IFINDEX:
1107 cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
1108 sizeof(struct in6_addr));
1109 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1110 cmp = !(nhop->ifindex == ifindex);
1111 break;
b9abd9ad
DS
1112 case NEXTHOP_TYPE_IFINDEX:
1113 cmp = !(nhop->ifindex == ifindex);
1114 break;
d62a17ae 1115 default:
1116 break;
1117 }
40c7bdb0 1118
d62a17ae 1119 return cmp;
40c7bdb0 1120}
1121
1122
1123/*
1124 * Locate NHLFE that matches with passed info.
1125 */
d62a17ae 1126static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
1127 enum nexthop_types_t gtype, union g_addr *gate,
1128 ifindex_t ifindex)
40c7bdb0 1129{
d62a17ae 1130 zebra_nhlfe_t *nhlfe;
40c7bdb0 1131
d62a17ae 1132 if (!lsp)
1133 return NULL;
40c7bdb0 1134
d62a17ae 1135 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1136 if (nhlfe->type != lsp_type)
1137 continue;
1138 if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex))
1139 break;
1140 }
40c7bdb0 1141
d62a17ae 1142 return nhlfe;
40c7bdb0 1143}
1144
1145/*
1146 * Add NHLFE. Base entry must have been created and duplicate
1147 * check done.
1148 */
d62a17ae 1149static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
1150 enum nexthop_types_t gtype, union g_addr *gate,
1151 ifindex_t ifindex, mpls_label_t out_label)
1152{
1153 zebra_nhlfe_t *nhlfe;
1154 struct nexthop *nexthop;
1155
1156 if (!lsp)
1157 return NULL;
1158
1159 nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(zebra_nhlfe_t));
1160 if (!nhlfe)
1161 return NULL;
1162
1163 nhlfe->lsp = lsp;
1164 nhlfe->type = lsp_type;
1165 nhlfe->distance = lsp_distance(lsp_type);
1166
1167 nexthop = nexthop_new();
1168 if (!nexthop) {
1169 XFREE(MTYPE_NHLFE, nhlfe);
1170 return NULL;
1171 }
1172 nexthop_add_labels(nexthop, lsp_type, 1, &out_label);
1173
4a7371e9 1174 nexthop->vrf_id = VRF_DEFAULT;
d62a17ae 1175 nexthop->type = gtype;
1176 switch (nexthop->type) {
1177 case NEXTHOP_TYPE_IPV4:
1178 case NEXTHOP_TYPE_IPV4_IFINDEX:
1179 nexthop->gate.ipv4 = gate->ipv4;
1180 if (ifindex)
1181 nexthop->ifindex = ifindex;
1182 break;
1183 case NEXTHOP_TYPE_IPV6:
1184 case NEXTHOP_TYPE_IPV6_IFINDEX:
1185 nexthop->gate.ipv6 = gate->ipv6;
1186 if (ifindex)
1187 nexthop->ifindex = ifindex;
1188 break;
b9abd9ad
DS
1189 case NEXTHOP_TYPE_IFINDEX:
1190 nexthop->ifindex = ifindex;
1191 break;
d62a17ae 1192 default:
1193 nexthop_free(nexthop);
1194 XFREE(MTYPE_NHLFE, nhlfe);
1195 return NULL;
1196 break;
1197 }
1198
1199 nhlfe->nexthop = nexthop;
1200 if (lsp->nhlfe_list)
1201 lsp->nhlfe_list->prev = nhlfe;
1202 nhlfe->next = lsp->nhlfe_list;
1203 lsp->nhlfe_list = nhlfe;
1204
1205 return nhlfe;
40c7bdb0 1206}
1207
1208/*
1209 * Delete NHLFE. Entry must be present on list.
1210 */
d62a17ae 1211static int nhlfe_del(zebra_nhlfe_t *nhlfe)
40c7bdb0 1212{
d62a17ae 1213 zebra_lsp_t *lsp;
40c7bdb0 1214
d62a17ae 1215 if (!nhlfe)
1216 return -1;
40c7bdb0 1217
d62a17ae 1218 lsp = nhlfe->lsp;
1219 if (!lsp)
1220 return -1;
40c7bdb0 1221
d62a17ae 1222 /* Free nexthop. */
1223 if (nhlfe->nexthop)
1224 nexthop_free(nhlfe->nexthop);
40c7bdb0 1225
d62a17ae 1226 /* Unlink from LSP */
1227 if (nhlfe->next)
1228 nhlfe->next->prev = nhlfe->prev;
1229 if (nhlfe->prev)
1230 nhlfe->prev->next = nhlfe->next;
1231 else
1232 lsp->nhlfe_list = nhlfe->next;
40c7bdb0 1233
d62a17ae 1234 if (nhlfe == lsp->best_nhlfe)
1235 lsp->best_nhlfe = NULL;
bb49a121 1236
d62a17ae 1237 XFREE(MTYPE_NHLFE, nhlfe);
40c7bdb0 1238
d62a17ae 1239 return 0;
40c7bdb0 1240}
1241
a64448ba
DS
1242/*
1243 * Update label for NHLFE entry.
1244 */
d62a17ae 1245static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
8ecdb26e 1246 struct mpls_label_stack *nh_label)
d62a17ae 1247{
1248 nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
1249}
1250
1251static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp,
1252 enum lsp_types_t type)
1253{
1254 zebra_nhlfe_t *nhlfe, *nhlfe_next;
1255 int schedule_lsp = 0;
1256 char buf[BUFSIZ];
1257
1258 /* Mark NHLFEs for delete or directly delete, as appropriate. */
1259 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) {
1260 nhlfe_next = nhlfe->next;
1261
1262 /* Skip non-static NHLFEs */
1263 if (nhlfe->type != type)
1264 continue;
1265
1266 if (IS_ZEBRA_DEBUG_MPLS) {
1267 nhlfe2str(nhlfe, buf, BUFSIZ);
1268 zlog_debug(
1269 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
1270 lsp->ile.in_label, type, buf, nhlfe->flags);
1271 }
1272
1273 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1274 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1275 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1276 schedule_lsp = 1;
1277 } else {
1278 nhlfe_del(nhlfe);
1279 }
1280 }
1281
1282 /* Queue LSP for processing, if needed, else delete. */
1283 if (schedule_lsp) {
1284 if (lsp_processq_add(lsp))
1285 return -1;
1286 } else if (!lsp->nhlfe_list
1287 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
1288 if (IS_ZEBRA_DEBUG_MPLS)
1289 zlog_debug("Free LSP in-label %u flags 0x%x",
1290 lsp->ile.in_label, lsp->flags);
1291
1292 lsp = hash_release(lsp_table, &lsp->ile);
1293 if (lsp)
1294 XFREE(MTYPE_LSP, lsp);
1295 }
1296
1297 return 0;
40c7bdb0 1298}
1299
ce549947
RW
1300/*
1301 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
1302 * If no other NHLFEs exist, the entry would be deleted.
1303 */
d62a17ae 1304static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
1305 mpls_label_t in_label)
ce549947 1306{
d62a17ae 1307 struct hash *lsp_table;
1308 zebra_ile_t tmp_ile;
1309 zebra_lsp_t *lsp;
ce549947 1310
d62a17ae 1311 /* Lookup table. */
1312 lsp_table = zvrf->lsp_table;
1313 if (!lsp_table)
1314 return -1;
ce549947 1315
d62a17ae 1316 /* If entry is not present, exit. */
1317 tmp_ile.in_label = in_label;
1318 lsp = hash_lookup(lsp_table, &tmp_ile);
1319 if (!lsp || !lsp->nhlfe_list)
1320 return 0;
ce549947 1321
d62a17ae 1322 return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC);
ce549947
RW
1323}
1324
d62a17ae 1325static json_object *nhlfe_json(zebra_nhlfe_t *nhlfe)
b78b820d 1326{
d62a17ae 1327 char buf[BUFSIZ];
1328 json_object *json_nhlfe = NULL;
1329 struct nexthop *nexthop = nhlfe->nexthop;
b78b820d 1330
d62a17ae 1331 json_nhlfe = json_object_new_object();
1332 json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
1333 json_object_int_add(json_nhlfe, "outLabel",
1334 nexthop->nh_label->label[0]);
1335 json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
b78b820d 1336
d62a17ae 1337 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
1338 json_object_boolean_true_add(json_nhlfe, "installed");
b78b820d 1339
d62a17ae 1340 switch (nexthop->type) {
1341 case NEXTHOP_TYPE_IPV4:
1342 case NEXTHOP_TYPE_IPV4_IFINDEX:
1343 json_object_string_add(json_nhlfe, "nexthop",
1344 inet_ntoa(nexthop->gate.ipv4));
1345 break;
1346 case NEXTHOP_TYPE_IPV6:
1347 case NEXTHOP_TYPE_IPV6_IFINDEX:
1348 json_object_string_add(
1349 json_nhlfe, "nexthop",
1350 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1351
1352 if (nexthop->ifindex)
4a7371e9
DS
1353 json_object_string_add(json_nhlfe, "interface",
1354 ifindex2ifname(nexthop->ifindex,
1355 nexthop->vrf_id));
d62a17ae 1356 break;
1357 default:
1358 break;
1359 }
1360 return json_nhlfe;
b78b820d 1361}
1362
3ab18ff2 1363/*
1364 * Print the NHLFE for a LSP forwarding entry.
1365 */
d62a17ae 1366static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty)
1367{
1368 struct nexthop *nexthop;
1369 char buf[BUFSIZ];
1370
1371 nexthop = nhlfe->nexthop;
1372 if (!nexthop || !nexthop->nh_label) // unexpected
1373 return;
1374
1375 vty_out(vty, " type: %s remote label: %s distance: %d\n",
1376 nhlfe_type2str(nhlfe->type),
1377 label2str(nexthop->nh_label->label[0], buf, BUFSIZ),
1378 nhlfe->distance);
1379 switch (nexthop->type) {
1380 case NEXTHOP_TYPE_IPV4:
1381 case NEXTHOP_TYPE_IPV4_IFINDEX:
1382 vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
1383 if (nexthop->ifindex)
1384 vty_out(vty, " dev %s",
4a7371e9
DS
1385 ifindex2ifname(nexthop->ifindex,
1386 nexthop->vrf_id));
d62a17ae 1387 break;
1388 case NEXTHOP_TYPE_IPV6:
1389 case NEXTHOP_TYPE_IPV6_IFINDEX:
1390 vty_out(vty, " via %s",
1391 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1392 if (nexthop->ifindex)
1393 vty_out(vty, " dev %s",
4a7371e9
DS
1394 ifindex2ifname(nexthop->ifindex,
1395 nexthop->vrf_id));
d62a17ae 1396 break;
1397 default:
1398 break;
1399 }
996c9314
LB
1400 vty_out(vty, "%s",
1401 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
1402 : "");
d62a17ae 1403 vty_out(vty, "\n");
3ab18ff2 1404}
1405
1406/*
1407 * Print an LSP forwarding entry.
1408 */
d62a17ae 1409static void lsp_print(zebra_lsp_t *lsp, void *ctxt)
3ab18ff2 1410{
d62a17ae 1411 zebra_nhlfe_t *nhlfe;
1412 struct vty *vty;
3ab18ff2 1413
d62a17ae 1414 vty = (struct vty *)ctxt;
3ab18ff2 1415
d62a17ae 1416 vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label,
1417 CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)"
1418 : "");
3ab18ff2 1419
d62a17ae 1420 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1421 nhlfe_print(nhlfe, vty);
3ab18ff2 1422}
1423
1424/*
b78b820d 1425 * JSON objects for an LSP forwarding entry.
3ab18ff2 1426 */
d62a17ae 1427static json_object *lsp_json(zebra_lsp_t *lsp)
3ab18ff2 1428{
d62a17ae 1429 zebra_nhlfe_t *nhlfe = NULL;
1430 json_object *json = json_object_new_object();
1431 json_object *json_nhlfe_list = json_object_new_array();
3ab18ff2 1432
d62a17ae 1433 json_object_int_add(json, "inLabel", lsp->ile.in_label);
b78b820d 1434
d62a17ae 1435 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1436 json_object_boolean_true_add(json, "installed");
3ab18ff2 1437
d62a17ae 1438 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1439 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
b78b820d 1440
d62a17ae 1441 json_object_object_add(json, "nexthops", json_nhlfe_list);
1442 return json;
b78b820d 1443}
1444
1445
1446/* Return a sorted linked list of the hash contents */
d62a17ae 1447static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
b78b820d 1448{
d62a17ae 1449 unsigned int i;
1450 struct hash_backet *hb;
1451 struct list *sorted_list = list_new();
b78b820d 1452
d62a17ae 1453 sorted_list->cmp = (int (*)(void *, void *))cmp;
b78b820d 1454
d62a17ae 1455 for (i = 0; i < hash->size; i++)
1456 for (hb = hash->index[i]; hb; hb = hb->next)
1457 listnode_add_sort(sorted_list, hb->data);
b78b820d 1458
d62a17ae 1459 return sorted_list;
3ab18ff2 1460}
1461
7758e3f3 1462/*
b78b820d 1463 * Compare two LSPs based on their label values.
7758e3f3 1464 */
d62a17ae 1465static int lsp_cmp(zebra_lsp_t *lsp1, zebra_lsp_t *lsp2)
7758e3f3 1466{
d62a17ae 1467 if (lsp1->ile.in_label < lsp2->ile.in_label)
1468 return -1;
7758e3f3 1469
d62a17ae 1470 if (lsp1->ile.in_label > lsp2->ile.in_label)
1471 return 1;
7758e3f3 1472
d62a17ae 1473 return 0;
7758e3f3 1474}
1475
1476/*
1477 * Callback to allocate static LSP.
1478 */
d62a17ae 1479static void *slsp_alloc(void *p)
7758e3f3 1480{
d62a17ae 1481 const zebra_ile_t *ile = p;
1482 zebra_slsp_t *slsp;
7758e3f3 1483
d62a17ae 1484 slsp = XCALLOC(MTYPE_SLSP, sizeof(zebra_slsp_t));
1485 slsp->ile = *ile;
1486 return ((void *)slsp);
7758e3f3 1487}
1488
b78b820d 1489/*
1490 * Compare two static LSPs based on their label values.
1491 */
d62a17ae 1492static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
b78b820d 1493{
d62a17ae 1494 if (slsp1->ile.in_label < slsp2->ile.in_label)
1495 return -1;
b78b820d 1496
d62a17ae 1497 if (slsp1->ile.in_label > slsp2->ile.in_label)
1498 return 1;
b78b820d 1499
d62a17ae 1500 return 0;
b78b820d 1501}
1502
7758e3f3 1503/*
1504 * Check if static NHLFE matches with search info passed.
1505 */
d62a17ae 1506static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
1507 union g_addr *gate, ifindex_t ifindex)
7758e3f3 1508{
d62a17ae 1509 int cmp = 1;
7758e3f3 1510
d62a17ae 1511 if (snhlfe->gtype != gtype)
1512 return 1;
7758e3f3 1513
d62a17ae 1514 switch (snhlfe->gtype) {
1515 case NEXTHOP_TYPE_IPV4:
1516 cmp = memcmp(&(snhlfe->gate.ipv4), &(gate->ipv4),
1517 sizeof(struct in_addr));
1518 break;
1519 case NEXTHOP_TYPE_IPV6:
1520 case NEXTHOP_TYPE_IPV6_IFINDEX:
1521 cmp = memcmp(&(snhlfe->gate.ipv6), &(gate->ipv6),
1522 sizeof(struct in6_addr));
1523 if (!cmp && snhlfe->gtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1524 cmp = !(snhlfe->ifindex == ifindex);
1525 break;
1526 default:
1527 break;
1528 }
7758e3f3 1529
d62a17ae 1530 return cmp;
7758e3f3 1531}
1532
1533/*
1534 * Locate static NHLFE that matches with passed info.
1535 */
d62a17ae 1536static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
1537 enum nexthop_types_t gtype,
1538 union g_addr *gate, ifindex_t ifindex)
7758e3f3 1539{
d62a17ae 1540 zebra_snhlfe_t *snhlfe;
7758e3f3 1541
d62a17ae 1542 if (!slsp)
1543 return NULL;
7758e3f3 1544
d62a17ae 1545 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next) {
1546 if (!snhlfe_match(snhlfe, gtype, gate, ifindex))
1547 break;
1548 }
7758e3f3 1549
d62a17ae 1550 return snhlfe;
7758e3f3 1551}
1552
1553
1554/*
1555 * Add static NHLFE. Base LSP config entry must have been created
1556 * and duplicate check done.
1557 */
d62a17ae 1558static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
1559 enum nexthop_types_t gtype,
1560 union g_addr *gate, ifindex_t ifindex,
1561 mpls_label_t out_label)
1562{
1563 zebra_snhlfe_t *snhlfe;
1564
1565 if (!slsp)
1566 return NULL;
1567
1568 snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t));
1569 snhlfe->slsp = slsp;
1570 snhlfe->out_label = out_label;
1571 snhlfe->gtype = gtype;
1572 switch (gtype) {
1573 case NEXTHOP_TYPE_IPV4:
1574 snhlfe->gate.ipv4 = gate->ipv4;
1575 break;
1576 case NEXTHOP_TYPE_IPV6:
1577 case NEXTHOP_TYPE_IPV6_IFINDEX:
1578 snhlfe->gate.ipv6 = gate->ipv6;
1579 if (ifindex)
1580 snhlfe->ifindex = ifindex;
1581 break;
1582 default:
1583 XFREE(MTYPE_SNHLFE, snhlfe);
1584 return NULL;
1585 }
1586
1587 if (slsp->snhlfe_list)
1588 slsp->snhlfe_list->prev = snhlfe;
1589 snhlfe->next = slsp->snhlfe_list;
1590 slsp->snhlfe_list = snhlfe;
1591
1592 return snhlfe;
7758e3f3 1593}
1594
1595/*
1596 * Delete static NHLFE. Entry must be present on list.
1597 */
d62a17ae 1598static int snhlfe_del(zebra_snhlfe_t *snhlfe)
7758e3f3 1599{
d62a17ae 1600 zebra_slsp_t *slsp;
7758e3f3 1601
d62a17ae 1602 if (!snhlfe)
1603 return -1;
7758e3f3 1604
d62a17ae 1605 slsp = snhlfe->slsp;
1606 if (!slsp)
1607 return -1;
7758e3f3 1608
d62a17ae 1609 if (snhlfe->next)
1610 snhlfe->next->prev = snhlfe->prev;
1611 if (snhlfe->prev)
1612 snhlfe->prev->next = snhlfe->next;
1613 else
1614 slsp->snhlfe_list = snhlfe->next;
7758e3f3 1615
d62a17ae 1616 snhlfe->prev = snhlfe->next = NULL;
1617 if (snhlfe->ifname)
1618 XFREE(MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
1619 XFREE(MTYPE_SNHLFE, snhlfe);
7758e3f3 1620
d62a17ae 1621 return 0;
7758e3f3 1622}
1623
1624/*
1625 * Delete all static NHLFE entries for this LSP (in label).
1626 */
d62a17ae 1627static int snhlfe_del_all(zebra_slsp_t *slsp)
7758e3f3 1628{
d62a17ae 1629 zebra_snhlfe_t *snhlfe, *snhlfe_next;
7758e3f3 1630
d62a17ae 1631 if (!slsp)
1632 return -1;
7758e3f3 1633
d62a17ae 1634 for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next) {
1635 snhlfe_next = snhlfe->next;
1636 snhlfe_del(snhlfe);
1637 }
7758e3f3 1638
d62a17ae 1639 return 0;
7758e3f3 1640}
1641
1642/*
1643 * Create printable string for NHLFE configuration.
1644 */
d62a17ae 1645static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size)
7758e3f3 1646{
d62a17ae 1647 buf[0] = '\0';
1648 switch (snhlfe->gtype) {
1649 case NEXTHOP_TYPE_IPV4:
1650 inet_ntop(AF_INET, &snhlfe->gate.ipv4, buf, size);
1651 break;
1652 case NEXTHOP_TYPE_IPV6:
1653 case NEXTHOP_TYPE_IPV6_IFINDEX:
1654 inet_ntop(AF_INET6, &snhlfe->gate.ipv6, buf, size);
1655 if (snhlfe->ifindex)
1656 strcat(buf,
1657 ifindex2ifname(snhlfe->ifindex, VRF_DEFAULT));
1658 break;
1659 default:
1660 break;
1661 }
7758e3f3 1662
d62a17ae 1663 return buf;
7758e3f3 1664}
1665
40c7bdb0 1666/*
1667 * Initialize work queue for processing changed LSPs.
1668 */
d62a17ae 1669static int mpls_processq_init(struct zebra_t *zebra)
40c7bdb0 1670{
d62a17ae 1671 zebra->lsp_process_q = work_queue_new(zebra->master, "LSP processing");
1672 if (!zebra->lsp_process_q) {
1673 zlog_err("%s: could not initialise work queue!", __func__);
1674 return -1;
1675 }
40c7bdb0 1676
d62a17ae 1677 zebra->lsp_process_q->spec.workfunc = &lsp_process;
1678 zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del;
1679 zebra->lsp_process_q->spec.errorfunc = NULL;
1680 zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete;
1681 zebra->lsp_process_q->spec.max_retries = 0;
1682 zebra->lsp_process_q->spec.hold = 10;
33c32282 1683
d62a17ae 1684 return 0;
40c7bdb0 1685}
1686
7758e3f3 1687
7758e3f3 1688/* Public functions */
1689
996c9314 1690void kernel_lsp_pass_fail(zebra_lsp_t *lsp, enum southbound_results res)
4a83e7a0
DS
1691{
1692 struct nexthop *nexthop;
1693 zebra_nhlfe_t *nhlfe;
1694
1695 if (!lsp)
1696 return;
1697
1698 switch (res) {
1699 case SOUTHBOUND_INSTALL_FAILURE:
1700 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1701 clear_nhlfe_installed(lsp);
1702 zlog_warn("LSP Install Failure: %u", lsp->ile.in_label);
1703 break;
1704 case SOUTHBOUND_INSTALL_SUCCESS:
1705 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1706 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1707 nexthop = nhlfe->nexthop;
1708 if (!nexthop)
1709 continue;
1710
1711 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1712 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1713 }
1714 break;
1715 case SOUTHBOUND_DELETE_SUCCESS:
1716 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1717 clear_nhlfe_installed(lsp);
1718 break;
1719 case SOUTHBOUND_DELETE_FAILURE:
1720 zlog_warn("LSP Deletion Failure: %u", lsp->ile.in_label);
1721 break;
1722 }
1723}
1724
a64448ba
DS
1725/*
1726 * Install dynamic LSP entry.
1727 */
d62a17ae 1728int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
1729 struct route_entry *re)
a64448ba 1730{
d62a17ae 1731 struct route_table *table;
1732 zebra_fec_t *fec;
a64448ba 1733
d62a17ae 1734 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
1735 if (!table)
1736 return -1;
a64448ba 1737
d62a17ae 1738 /* See if there is a configured label binding for this FEC. */
1739 fec = fec_find(table, &rn->p);
1740 if (!fec || fec->label == MPLS_INVALID_LABEL)
1741 return 0;
a64448ba 1742
d62a17ae 1743 /* We cannot install a label forwarding entry if local label is the
1744 * implicit-null label.
1745 */
70e98a7f 1746 if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
d62a17ae 1747 return 0;
a64448ba 1748
d62a17ae 1749 if (lsp_install(zvrf, fec->label, rn, re))
1750 return -1;
a64448ba 1751
d62a17ae 1752 return 0;
a64448ba
DS
1753}
1754
1755/*
1756 * Uninstall dynamic LSP entry, if any.
1757 */
d62a17ae 1758int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
1759 struct route_entry *re)
a64448ba 1760{
d62a17ae 1761 struct route_table *table;
1762 zebra_fec_t *fec;
a64448ba 1763
d62a17ae 1764 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
1765 if (!table)
1766 return -1;
a64448ba 1767
d62a17ae 1768 /* See if there is a configured label binding for this FEC. */
1769 fec = fec_find(table, &rn->p);
1770 if (!fec || fec->label == MPLS_INVALID_LABEL)
1771 return 0;
a64448ba 1772
d62a17ae 1773 /* Uninstall always removes all dynamic NHLFEs. */
1774 return lsp_uninstall(zvrf, fec->label);
a64448ba
DS
1775}
1776
5aba114a
DS
1777/*
1778 * Registration from a client for the label binding for a FEC. If a binding
1779 * already exists, it is informed to the client.
28d58fd7 1780 * NOTE: If there is a manually configured label binding, that is used.
9bedbb1e 1781 * Otherwise, if a label index is specified, it means we have to allocate the
28d58fd7
VV
1782 * label from a locally configured label block (SRGB), if one exists and index
1783 * is acceptable.
5aba114a 1784 */
d62a17ae 1785int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
d7c0a89a 1786 uint32_t label_index, struct zserv *client)
d62a17ae 1787{
1788 struct route_table *table;
1789 zebra_fec_t *fec;
1790 char buf[BUFSIZ];
1791 int new_client;
1792 int label_change = 0;
d7c0a89a 1793 uint32_t old_label;
d62a17ae 1794
1795 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
1796 if (!table)
1797 return -1;
1798
1799 if (IS_ZEBRA_DEBUG_MPLS)
1800 prefix2str(p, buf, BUFSIZ);
1801
1802 /* Locate FEC */
1803 fec = fec_find(table, p);
1804 if (!fec) {
1805 fec = fec_add(table, p, MPLS_INVALID_LABEL, 0, label_index);
1806 if (!fec) {
1807 prefix2str(p, buf, BUFSIZ);
1808 zlog_err(
1809 "Failed to add FEC %s upon register, client %s",
1810 buf, zebra_route_string(client->proto));
1811 return -1;
1812 }
1813
1814 old_label = MPLS_INVALID_LABEL;
1815 new_client = 1;
1816 } else {
1817 /* Client may register same FEC with different label index. */
1818 new_client =
1819 (listnode_lookup(fec->client_list, client) == NULL);
1820 if (!new_client && fec->label_index == label_index)
1821 /* Duplicate register */
1822 return 0;
1823
1824 /* Save current label, update label index */
1825 old_label = fec->label;
1826 fec->label_index = label_index;
1827 }
1828
1829 if (new_client)
1830 listnode_add(fec->client_list, client);
1831
1832 if (IS_ZEBRA_DEBUG_MPLS)
1833 zlog_debug("FEC %s Label Index %u %s by client %s", buf,
1834 label_index, new_client ? "registered" : "updated",
1835 zebra_route_string(client->proto));
1836
1837 /* If not a configured FEC, derive the local label (from label index)
1838 * or reset it.
1839 */
1840 if (!(fec->flags & FEC_FLAG_CONFIGURED)) {
1841 fec_derive_label_from_index(zvrf, fec);
1842
1843 /* If no label change, exit. */
1844 if (fec->label == old_label)
1845 return 0;
1846
1847 label_change = 1;
1848 }
1849
1850 /* If new client or label change, update client and install or uninstall
1851 * label forwarding entry as needed.
1852 */
1853 /* Inform client of label, if needed. */
1854 if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
1855 if (IS_ZEBRA_DEBUG_MPLS)
1856 zlog_debug("Update client label %u", fec->label);
1857 fec_send(fec, client);
1858 }
1859
1860 if (new_client || label_change)
1861 return fec_change_update_lsp(zvrf, fec, old_label);
1862
1863 return 0;
5aba114a
DS
1864}
1865
1866/*
1867 * Deregistration from a client for the label binding for a FEC. The FEC
1868 * itself is deleted if no other registered clients exist and there is no
1869 * label bound to the FEC.
1870 */
d62a17ae 1871int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
1872 struct zserv *client)
5aba114a 1873{
d62a17ae 1874 struct route_table *table;
1875 zebra_fec_t *fec;
1876 char buf[BUFSIZ];
5aba114a 1877
d62a17ae 1878 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
1879 if (!table)
1880 return -1;
5aba114a 1881
d62a17ae 1882 if (IS_ZEBRA_DEBUG_MPLS)
1883 prefix2str(p, buf, BUFSIZ);
5aba114a 1884
d62a17ae 1885 fec = fec_find(table, p);
1886 if (!fec) {
1887 prefix2str(p, buf, BUFSIZ);
1888 zlog_err("Failed to find FEC %s upon unregister, client %s",
1889 buf, zebra_route_string(client->proto));
1890 return -1;
1891 }
5aba114a 1892
d62a17ae 1893 listnode_delete(fec->client_list, client);
1894
1895 if (IS_ZEBRA_DEBUG_MPLS)
1896 zlog_debug("FEC %s unregistered by client %s", buf,
1897 zebra_route_string(client->proto));
1898
1899 /* If not a configured entry, delete the FEC if no other clients. Before
1900 * deleting, see if any LSP needs to be uninstalled.
1901 */
1902 if (!(fec->flags & FEC_FLAG_CONFIGURED)
1903 && list_isempty(fec->client_list)) {
1904 mpls_label_t old_label = fec->label;
1905 fec->label = MPLS_INVALID_LABEL; /* reset */
1906 fec_change_update_lsp(zvrf, fec, old_label);
1907 fec_del(fec);
1908 }
5aba114a 1909
d62a17ae 1910 return 0;
5aba114a
DS
1911}
1912
1913/*
1914 * Cleanup any FECs registered by this client.
1915 */
453844ab 1916static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
d62a17ae 1917{
453844ab 1918 struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
d62a17ae 1919 struct route_node *rn;
1920 zebra_fec_t *fec;
1921 struct listnode *node;
1922 struct zserv *fec_client;
1923 int af;
1924
1925 for (af = AFI_IP; af < AFI_MAX; af++) {
1926 if (zvrf->fec_table[af] == NULL)
1927 continue;
1928
1929 for (rn = route_top(zvrf->fec_table[af]); rn;
1930 rn = route_next(rn)) {
1931 fec = rn->info;
1932 if (!fec || list_isempty(fec->client_list))
1933 continue;
1934
1935 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
1936 fec_client)) {
1937 if (fec_client == client) {
1938 listnode_delete(fec->client_list,
1939 fec_client);
1940 if (!(fec->flags & FEC_FLAG_CONFIGURED)
1941 && list_isempty(fec->client_list))
1942 fec_del(fec);
1943 break;
1944 }
1945 }
1946 }
1947 }
5aba114a 1948
d62a17ae 1949 return 0;
5aba114a
DS
1950}
1951
f31e084c
DS
1952/*
1953 * Return FEC (if any) to which this label is bound.
1954 * Note: Only works for per-prefix binding and when the label is not
1955 * implicit-null.
1956 * TODO: Currently walks entire table, can optimize later with another
1957 * hash..
1958 */
d62a17ae 1959zebra_fec_t *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
1960 mpls_label_t label)
1961{
1962 struct route_node *rn;
1963 zebra_fec_t *fec;
1964 int af;
1965
1966 for (af = AFI_IP; af < AFI_MAX; af++) {
1967 if (zvrf->fec_table[af] == NULL)
1968 continue;
1969
1970 for (rn = route_top(zvrf->fec_table[af]); rn;
1971 rn = route_next(rn)) {
1972 if (!rn->info)
1973 continue;
1974 fec = rn->info;
1975 if (fec->label == label)
1976 return fec;
1977 }
1978 }
f31e084c 1979
d62a17ae 1980 return NULL;
f31e084c
DS
1981}
1982
1983/*
1984 * Inform if specified label is currently bound to a FEC or not.
1985 */
d62a17ae 1986int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
f31e084c 1987{
d62a17ae 1988 return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
f31e084c
DS
1989}
1990
1991/*
5aba114a 1992 * Add static FEC to label binding. If there are clients registered for this
a64448ba
DS
1993 * FEC, notify them. If there are labeled routes for this FEC, install the
1994 * label forwarding entry.
9d303b37 1995*/
d62a17ae 1996int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
1997 mpls_label_t in_label)
1998{
1999 struct route_table *table;
2000 zebra_fec_t *fec;
2001 char buf[BUFSIZ];
2002 mpls_label_t old_label;
2003 int ret = 0;
2004
2005 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2006 if (!table)
2007 return -1;
2008
2009 if (IS_ZEBRA_DEBUG_MPLS)
2010 prefix2str(p, buf, BUFSIZ);
2011
2012 /* Update existing FEC or create a new one. */
2013 fec = fec_find(table, p);
2014 if (!fec) {
2015 fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
2016 MPLS_INVALID_LABEL_INDEX);
2017 if (!fec) {
2018 prefix2str(p, buf, BUFSIZ);
2019 zlog_err("Failed to add FEC %s upon config", buf);
2020 return -1;
2021 }
2022
2023 if (IS_ZEBRA_DEBUG_MPLS)
2024 zlog_debug("Add fec %s label %u", buf, in_label);
2025 } else {
2026 fec->flags |= FEC_FLAG_CONFIGURED;
2027 if (fec->label == in_label)
2028 /* Duplicate config */
2029 return 0;
2030
2031 /* Label change, update clients. */
2032 old_label = fec->label;
2033 if (IS_ZEBRA_DEBUG_MPLS)
2034 zlog_debug("Update fec %s new label %u", buf, in_label);
2035
2036 fec->label = in_label;
2037 fec_update_clients(fec);
2038
2039 /* Update label forwarding entries appropriately */
2040 ret = fec_change_update_lsp(zvrf, fec, old_label);
2041 }
2042
2043 return ret;
f31e084c
DS
2044}
2045
2046/*
5aba114a
DS
2047 * Remove static FEC to label binding. If there are no clients registered
2048 * for this FEC, delete the FEC; else notify clients
28d58fd7
VV
2049 * Note: Upon delete of static binding, if label index exists for this FEC,
2050 * client may need to be updated with derived label.
f31e084c 2051 */
d62a17ae 2052int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
2053{
2054 struct route_table *table;
2055 zebra_fec_t *fec;
2056 mpls_label_t old_label;
2057 char buf[BUFSIZ];
2058
2059 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2060 if (!table)
2061 return -1;
2062
2063 fec = fec_find(table, p);
2064 if (!fec) {
2065 prefix2str(p, buf, BUFSIZ);
2066 zlog_err("Failed to find FEC %s upon delete", buf);
2067 return -1;
2068 }
2069
2070 if (IS_ZEBRA_DEBUG_MPLS) {
2071 prefix2str(p, buf, BUFSIZ);
2072 zlog_debug("Delete fec %s label index %u", buf,
2073 fec->label_index);
2074 }
2075
2076 old_label = fec->label;
2077 fec->flags &= ~FEC_FLAG_CONFIGURED;
2078 fec->label = MPLS_INVALID_LABEL;
2079
2080 /* If no client exists, just delete the FEC. */
2081 if (list_isempty(fec->client_list)) {
2082 fec_del(fec);
2083 return 0;
2084 }
2085
2086 /* Derive the local label (from label index) or reset it. */
2087 fec_derive_label_from_index(zvrf, fec);
2088
2089 /* If there is a label change, update clients. */
2090 if (fec->label == old_label)
2091 return 0;
2092 fec_update_clients(fec);
2093
2094 /* Update label forwarding entries appropriately */
2095 return fec_change_update_lsp(zvrf, fec, old_label);
f31e084c
DS
2096}
2097
2098/*
2099 * Display MPLS FEC to label binding configuration (VTY command handler).
2100 */
d62a17ae 2101int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
f31e084c 2102{
d62a17ae 2103 struct route_node *rn;
2104 int af;
2105 zebra_fec_t *fec;
2106 char buf[BUFSIZ];
2107 int write = 0;
f31e084c 2108
d62a17ae 2109 for (af = AFI_IP; af < AFI_MAX; af++) {
2110 if (zvrf->fec_table[af] == NULL)
2111 continue;
f31e084c 2112
d62a17ae 2113 for (rn = route_top(zvrf->fec_table[af]); rn;
2114 rn = route_next(rn)) {
2115 if (!rn->info)
2116 continue;
f31e084c 2117
d62a17ae 2118 char lstr[BUFSIZ];
2119 fec = rn->info;
f31e084c 2120
d62a17ae 2121 if (!(fec->flags & FEC_FLAG_CONFIGURED))
2122 continue;
f31e084c 2123
d62a17ae 2124 write = 1;
2125 prefix2str(&rn->p, buf, BUFSIZ);
2126 vty_out(vty, "mpls label bind %s %s\n", buf,
2127 label2str(fec->label, lstr, BUFSIZ));
2128 }
2129 }
f31e084c 2130
d62a17ae 2131 return write;
f31e084c
DS
2132}
2133
2134/*
2135 * Display MPLS FEC to label binding (VTY command handler).
2136 */
d62a17ae 2137void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
f31e084c 2138{
d62a17ae 2139 struct route_node *rn;
2140 int af;
f31e084c 2141
d62a17ae 2142 for (af = AFI_IP; af < AFI_MAX; af++) {
2143 if (zvrf->fec_table[af] == NULL)
2144 continue;
f31e084c 2145
d62a17ae 2146 for (rn = route_top(zvrf->fec_table[af]); rn;
2147 rn = route_next(rn)) {
2148 if (!rn->info)
2149 continue;
2150 fec_print(rn->info, vty);
2151 }
2152 }
f31e084c
DS
2153}
2154
2155/*
2156 * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2157 */
d62a17ae 2158void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
2159 struct prefix *p)
f31e084c 2160{
d62a17ae 2161 struct route_table *table;
2162 struct route_node *rn;
f31e084c 2163
d62a17ae 2164 table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2165 if (!table)
2166 return;
f31e084c 2167
d62a17ae 2168 apply_mask(p);
2169 rn = route_node_lookup(table, p);
2170 if (!rn)
2171 return;
f31e084c 2172
d62a17ae 2173 route_unlock_node(rn);
2174 if (!rn->info)
2175 return;
f31e084c 2176
d62a17ae 2177 fec_print(rn->info, vty);
f31e084c
DS
2178}
2179
8f77d0ee
DS
2180static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop,
2181 enum lsp_types_t type, mpls_label_t label)
2182{
2183 if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2184 nexthop_add_labels(nexthop, type, 1, &label);
2185 else if (!add && nexthop->nh_label_type == type)
2186 nexthop_del_labels(nexthop);
2187 else
2188 return false;
2189
2190 return true;
2191}
2192
ce549947
RW
2193/*
2194 * Install/uninstall a FEC-To-NHLFE (FTN) binding.
2195 */
d62a17ae 2196int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
2197 struct prefix *prefix, enum nexthop_types_t gtype,
d7c0a89a 2198 union g_addr *gate, ifindex_t ifindex, uint8_t distance,
d62a17ae 2199 mpls_label_t out_label)
2200{
2201 struct route_table *table;
2202 struct route_node *rn;
2203 struct route_entry *re;
2204 struct nexthop *nexthop;
8f77d0ee 2205 bool found;
d62a17ae 2206
2207 /* Lookup table. */
2208 table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
2209 zvrf_id(zvrf));
2210 if (!table)
2211 return -1;
2212
2213 /* Lookup existing route */
2214 rn = route_node_get(table, prefix);
a2addae8 2215 RNODE_FOREACH_RE (rn, re) {
d62a17ae 2216 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2217 continue;
2218 if (re->distance == distance)
2219 break;
88d88a9c 2220 }
ce549947 2221
d62a17ae 2222 if (re == NULL)
2223 return -1;
2224
8f77d0ee 2225 found = false;
7ee30f28 2226 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
d62a17ae 2227 switch (nexthop->type) {
2228 case NEXTHOP_TYPE_IPV4:
2229 case NEXTHOP_TYPE_IPV4_IFINDEX:
2230 if (gtype != NEXTHOP_TYPE_IPV4
2231 && gtype != NEXTHOP_TYPE_IPV4_IFINDEX)
2232 continue;
2233 if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4))
2234 continue;
2235 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
2236 && nexthop->ifindex != ifindex)
2237 continue;
8f77d0ee
DS
2238 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2239 out_label))
2240 return 0;
2241 found = true;
2242 break;
d62a17ae 2243 case NEXTHOP_TYPE_IPV6:
2244 case NEXTHOP_TYPE_IPV6_IFINDEX:
2245 if (gtype != NEXTHOP_TYPE_IPV6
2246 && gtype != NEXTHOP_TYPE_IPV6_IFINDEX)
2247 continue;
2248 if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, &gate->ipv6))
2249 continue;
2250 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
2251 && nexthop->ifindex != ifindex)
2252 continue;
8f77d0ee
DS
2253 if (!mpls_ftn_update_nexthop(add, nexthop, type,
2254 out_label))
2255 return 0;
2256 found = true;
2257 break;
d62a17ae 2258 default:
2259 break;
2260 }
2261 }
d62a17ae 2262
8f77d0ee
DS
2263 if (!found)
2264 return -1;
ce549947 2265
d62a17ae 2266 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
332ad713 2267 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
d62a17ae 2268 rib_queue_add(rn);
ce549947 2269
d62a17ae 2270 return 0;
ce549947
RW
2271}
2272
2273/*
2274 * Install/update a NHLFE for an LSP in the forwarding table. This may be
2275 * a new LSP entry or a new NHLFE for an existing in-label or an update of
2276 * the out-label for an existing NHLFE (update case).
2277 */
d62a17ae 2278int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
2279 mpls_label_t in_label, mpls_label_t out_label,
2280 enum nexthop_types_t gtype, union g_addr *gate,
2281 ifindex_t ifindex)
2282{
2283 struct hash *lsp_table;
2284 zebra_ile_t tmp_ile;
2285 zebra_lsp_t *lsp;
2286 zebra_nhlfe_t *nhlfe;
2287 char buf[BUFSIZ];
2288
2289 /* Lookup table. */
2290 lsp_table = zvrf->lsp_table;
2291 if (!lsp_table)
2292 return -1;
2293
2294 /* If entry is present, exit. */
2295 tmp_ile.in_label = in_label;
2296 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2297 if (!lsp)
2298 return -1;
2299 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2300 if (nhlfe) {
2301 struct nexthop *nh = nhlfe->nexthop;
2302
2303 assert(nh);
2304 assert(nh->nh_label);
2305
2306 /* Clear deleted flag (in case it was set) */
2307 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2308 if (nh->nh_label->label[0] == out_label)
2309 /* No change */
2310 return 0;
2311
2312 if (IS_ZEBRA_DEBUG_MPLS) {
2313 nhlfe2str(nhlfe, buf, BUFSIZ);
2314 zlog_debug(
2315 "LSP in-label %u type %d nexthop %s "
2316 "out-label changed to %u (old %u)",
2317 in_label, type, buf, out_label,
2318 nh->nh_label->label[0]);
2319 }
2320
2321 /* Update out label, trigger processing. */
2322 nh->nh_label->label[0] = out_label;
2323 } else {
2324 /* Add LSP entry to this nexthop */
2325 nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, out_label);
2326 if (!nhlfe)
2327 return -1;
2328
2329 if (IS_ZEBRA_DEBUG_MPLS) {
2330 nhlfe2str(nhlfe, buf, BUFSIZ);
2331 zlog_debug(
2332 "Add LSP in-label %u type %d nexthop %s "
2333 "out-label %u",
2334 in_label, type, buf, out_label);
2335 }
2336
2337 lsp->addr_family = NHLFE_FAMILY(nhlfe);
2338 }
2339
2340 /* Mark NHLFE, queue LSP for processing. */
2341 SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2342 if (lsp_processq_add(lsp))
2343 return -1;
2344
2345 return 0;
ce549947
RW
2346}
2347
2348/*
2349 * Uninstall a particular NHLFE in the forwarding table. If this is
2350 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
2351 */
d62a17ae 2352int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2353 mpls_label_t in_label, enum nexthop_types_t gtype,
2354 union g_addr *gate, ifindex_t ifindex)
2355{
2356 struct hash *lsp_table;
2357 zebra_ile_t tmp_ile;
2358 zebra_lsp_t *lsp;
2359 zebra_nhlfe_t *nhlfe;
2360 char buf[BUFSIZ];
2361
2362 /* Lookup table. */
2363 lsp_table = zvrf->lsp_table;
2364 if (!lsp_table)
2365 return -1;
2366
2367 /* If entry is not present, exit. */
2368 tmp_ile.in_label = in_label;
2369 lsp = hash_lookup(lsp_table, &tmp_ile);
2370 if (!lsp)
2371 return 0;
2372 nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
2373 if (!nhlfe)
2374 return 0;
2375
2376 if (IS_ZEBRA_DEBUG_MPLS) {
2377 nhlfe2str(nhlfe, buf, BUFSIZ);
2378 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
2379 in_label, type, buf, nhlfe->flags);
2380 }
2381
2382 /* Mark NHLFE for delete or directly delete, as appropriate. */
2383 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
2384 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
2385 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
2386 if (lsp_processq_add(lsp))
2387 return -1;
2388 } else {
2389 nhlfe_del(nhlfe);
2390
2391 /* Free LSP entry if no other NHLFEs and not scheduled. */
2392 if (!lsp->nhlfe_list
2393 && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) {
2394 if (IS_ZEBRA_DEBUG_MPLS)
2395 zlog_debug("Free LSP in-label %u flags 0x%x",
2396 lsp->ile.in_label, lsp->flags);
2397
2398 lsp = hash_release(lsp_table, &lsp->ile);
2399 if (lsp)
2400 XFREE(MTYPE_LSP, lsp);
2401 }
2402 }
2403 return 0;
ce549947
RW
2404}
2405
2406/*
2407 * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
2408 * If no other NHLFEs exist, the entry would be deleted.
2409 */
d62a17ae 2410void mpls_ldp_lsp_uninstall_all(struct hash_backet *backet, void *ctxt)
ce549947 2411{
d62a17ae 2412 zebra_lsp_t *lsp;
2413 struct hash *lsp_table;
ce549947 2414
d62a17ae 2415 lsp = (zebra_lsp_t *)backet->data;
2416 if (!lsp || !lsp->nhlfe_list)
2417 return;
ce549947 2418
d62a17ae 2419 lsp_table = ctxt;
2420 if (!lsp_table)
2421 return;
ce549947 2422
d62a17ae 2423 mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP);
ce549947
RW
2424}
2425
2426/*
2427 * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
2428 */
d62a17ae 2429void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
2430{
2431 struct route_table *table;
2432 struct route_node *rn;
2433 struct route_entry *re;
2434 struct nexthop *nexthop;
2435 int update;
2436
2437 /* Process routes of interested address-families. */
2438 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2439 if (!table)
2440 return;
2441
2442 for (rn = route_top(table); rn; rn = route_next(rn)) {
2443 update = 0;
a2addae8 2444 RNODE_FOREACH_RE (rn, re) {
7ee30f28 2445 for (nexthop = re->ng.nexthop; nexthop;
407c87a6
DS
2446 nexthop = nexthop->next) {
2447 if (nexthop->nh_label_type != ZEBRA_LSP_LDP)
2448 continue;
2449
d62a17ae 2450 nexthop_del_labels(nexthop);
2451 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2452 SET_FLAG(re->status,
332ad713 2453 ROUTE_ENTRY_LABELS_CHANGED);
d62a17ae 2454 update = 1;
2455 }
407c87a6 2456 }
d62a17ae 2457
2458 if (update)
2459 rib_queue_add(rn);
2460 }
ce549947
RW
2461}
2462
1c1cf002 2463#if defined(HAVE_CUMULUS)
7758e3f3 2464/*
2465 * Check that the label values used in LSP creation are consistent. The
2466 * main criteria is that if there is ECMP, the label operation must still
2467 * be consistent - i.e., all paths either do a swap or do PHP. This is due
2468 * to current HW restrictions.
2469 */
d62a17ae 2470int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
2471 mpls_label_t in_label,
2472 mpls_label_t out_label,
2473 enum nexthop_types_t gtype,
2474 union g_addr *gate, ifindex_t ifindex)
2475{
2476 struct hash *slsp_table;
2477 zebra_ile_t tmp_ile;
2478 zebra_slsp_t *slsp;
2479 zebra_snhlfe_t *snhlfe;
2480
2481 /* Lookup table. */
2482 slsp_table = zvrf->slsp_table;
2483 if (!slsp_table)
2484 return 0;
2485
2486 /* If entry is not present, exit. */
2487 tmp_ile.in_label = in_label;
2488 slsp = hash_lookup(slsp_table, &tmp_ile);
2489 if (!slsp)
2490 return 1;
2491
2492 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2493 if (snhlfe) {
2494 if (snhlfe->out_label == out_label)
2495 return 1;
2496
2497 /* If not only NHLFE, cannot allow label change. */
2498 if (snhlfe != slsp->snhlfe_list || snhlfe->next)
2499 return 0;
2500 } else {
2501 /* If other NHLFEs exist, label operation must match. */
2502 if (slsp->snhlfe_list) {
2503 int cur_op, new_op;
2504
2505 cur_op = (slsp->snhlfe_list->out_label
70e98a7f
DS
2506 == MPLS_LABEL_IMPLICIT_NULL);
2507 new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
d62a17ae 2508 if (cur_op != new_op)
2509 return 0;
2510 }
2511 }
2512
2513 /* Label values are good. */
2514 return 1;
7758e3f3 2515}
1c1cf002 2516#endif /* HAVE_CUMULUS */
7758e3f3 2517
2518/*
2519 * Add static LSP entry. This may be the first entry for this incoming label
2520 * or an additional nexthop; an existing entry may also have outgoing label
2521 * changed.
2522 * Note: The label operation (swap or PHP) is common for the LSP entry (all
2523 * NHLFEs).
2524 */
d62a17ae 2525int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
2526 mpls_label_t out_label,
2527 enum nexthop_types_t gtype, union g_addr *gate,
2528 ifindex_t ifindex)
2529{
2530 struct hash *slsp_table;
2531 zebra_ile_t tmp_ile;
2532 zebra_slsp_t *slsp;
2533 zebra_snhlfe_t *snhlfe;
2534 char buf[BUFSIZ];
2535
2536 /* Lookup table. */
2537 slsp_table = zvrf->slsp_table;
2538 if (!slsp_table)
2539 return -1;
2540
2541 /* If entry is present, exit. */
2542 tmp_ile.in_label = in_label;
2543 slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc);
2544 if (!slsp)
2545 return -1;
2546 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2547 if (snhlfe) {
2548 if (snhlfe->out_label == out_label)
2549 /* No change */
2550 return 0;
2551
2552 if (IS_ZEBRA_DEBUG_MPLS) {
2553 snhlfe2str(snhlfe, buf, BUFSIZ);
2554 zlog_debug(
2555 "Upd static LSP in-label %u nexthop %s "
2556 "out-label %u (old %u)",
2557 in_label, buf, out_label, snhlfe->out_label);
2558 }
2559 snhlfe->out_label = out_label;
2560 } else {
2561 /* Add static LSP entry to this nexthop */
2562 snhlfe = snhlfe_add(slsp, gtype, gate, ifindex, out_label);
2563 if (!snhlfe)
2564 return -1;
2565
2566 if (IS_ZEBRA_DEBUG_MPLS) {
2567 snhlfe2str(snhlfe, buf, BUFSIZ);
2568 zlog_debug(
2569 "Add static LSP in-label %u nexthop %s out-label %u",
2570 in_label, buf, out_label);
2571 }
2572 }
2573
2574 /* (Re)Install LSP in the main table. */
2575 if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
2576 gate, ifindex))
2577 return -1;
2578
2579 return 0;
7758e3f3 2580}
2581
2582/*
2583 * Delete static LSP entry. This may be the delete of one particular
2584 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
2585 * all NHLFEs).
2586 * NOTE: Delete of the only NHLFE will also end up deleting the entire
2587 * LSP configuration.
2588 */
d62a17ae 2589int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
2590 enum nexthop_types_t gtype, union g_addr *gate,
2591 ifindex_t ifindex)
2592{
2593 struct hash *slsp_table;
2594 zebra_ile_t tmp_ile;
2595 zebra_slsp_t *slsp;
2596 zebra_snhlfe_t *snhlfe;
2597
2598 /* Lookup table. */
2599 slsp_table = zvrf->slsp_table;
2600 if (!slsp_table)
2601 return -1;
2602
2603 /* If entry is not present, exit. */
2604 tmp_ile.in_label = in_label;
2605 slsp = hash_lookup(slsp_table, &tmp_ile);
2606 if (!slsp)
2607 return 0;
2608
2609 /* Is it delete of entire LSP or a specific NHLFE? */
2610 if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
2611 if (IS_ZEBRA_DEBUG_MPLS)
2612 zlog_debug("Del static LSP in-label %u", in_label);
2613
2614 /* Uninstall entire LSP from the main table. */
2615 mpls_static_lsp_uninstall_all(zvrf, in_label);
2616
2617 /* Delete all static NHLFEs */
2618 snhlfe_del_all(slsp);
2619 } else {
2620 /* Find specific NHLFE, exit if not found. */
2621 snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
2622 if (!snhlfe)
2623 return 0;
2624
2625 if (IS_ZEBRA_DEBUG_MPLS) {
2626 char buf[BUFSIZ];
2627 snhlfe2str(snhlfe, buf, BUFSIZ);
2628 zlog_debug("Del static LSP in-label %u nexthop %s",
2629 in_label, buf);
2630 }
2631
2632 /* Uninstall LSP from the main table. */
2633 mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
2634 gate, ifindex);
2635
2636 /* Delete static LSP NHLFE */
2637 snhlfe_del(snhlfe);
2638 }
2639
2640 /* Remove entire static LSP entry if no NHLFE - valid in either case
2641 * above. */
2642 if (!slsp->snhlfe_list) {
2643 slsp = hash_release(slsp_table, &tmp_ile);
2644 if (slsp)
2645 XFREE(MTYPE_SLSP, slsp);
2646 }
2647
2648 return 0;
7758e3f3 2649}
2650
40c7bdb0 2651/*
2652 * Schedule all MPLS label forwarding entries for processing.
2653 * Called upon changes that may affect one or more of them such as
2654 * interface or nexthop state changes.
2655 */
d62a17ae 2656void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
40c7bdb0 2657{
d62a17ae 2658 if (!zvrf)
2659 return;
2660 hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
40c7bdb0 2661}
2662
3ab18ff2 2663/*
2664 * Display MPLS label forwarding table for a specific LSP
2665 * (VTY command handler).
2666 */
d62a17ae 2667void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
d7c0a89a 2668 mpls_label_t label, uint8_t use_json)
3ab18ff2 2669{
d62a17ae 2670 struct hash *lsp_table;
2671 zebra_lsp_t *lsp;
2672 zebra_ile_t tmp_ile;
2673 json_object *json = NULL;
3ab18ff2 2674
d62a17ae 2675 /* Lookup table. */
2676 lsp_table = zvrf->lsp_table;
2677 if (!lsp_table)
2678 return;
3ab18ff2 2679
d62a17ae 2680 /* If entry is not present, exit. */
2681 tmp_ile.in_label = label;
2682 lsp = hash_lookup(lsp_table, &tmp_ile);
2683 if (!lsp)
2684 return;
3ab18ff2 2685
d62a17ae 2686 if (use_json) {
2687 json = lsp_json(lsp);
9d303b37
DL
2688 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2689 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 2690 json_object_free(json);
2691 } else
2692 lsp_print(lsp, (void *)vty);
3ab18ff2 2693}
2694
2695/*
2696 * Display MPLS label forwarding table (VTY command handler).
2697 */
d62a17ae 2698void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
d7c0a89a 2699 uint8_t use_json)
d62a17ae 2700{
2701 char buf[BUFSIZ];
2702 json_object *json = NULL;
2703 zebra_lsp_t *lsp = NULL;
2704 zebra_nhlfe_t *nhlfe = NULL;
2705 struct nexthop *nexthop = NULL;
2706 struct listnode *node = NULL;
2707 struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
2708
2709 if (use_json) {
2710 json = json_object_new_object();
2711
2712 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
2713 json_object_object_add(
2714 json, label2str(lsp->ile.in_label, buf, BUFSIZ),
2715 lsp_json(lsp));
2716
9d303b37
DL
2717 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2718 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 2719 json_object_free(json);
2720 } else {
2721 vty_out(vty, " Inbound Outbound\n");
2722 vty_out(vty, " Label Type Nexthop Label\n");
2723 vty_out(vty, "-------- ------- --------------- --------\n");
2724
2725 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
2726 for (nhlfe = lsp->nhlfe_list; nhlfe;
2727 nhlfe = nhlfe->next) {
2728 vty_out(vty, "%8d %7s ", lsp->ile.in_label,
2729 nhlfe_type2str(nhlfe->type));
2730 nexthop = nhlfe->nexthop;
2731
2732 switch (nexthop->type) {
996c9314 2733 case NEXTHOP_TYPE_IFINDEX: {
b9abd9ad
DS
2734 struct interface *ifp;
2735
2736 ifp = if_lookup_by_index(
2737 nexthop->ifindex, VRF_UNKNOWN);
2738 vty_out(vty, "%15s", ifp->name);
2739 break;
2740 }
d62a17ae 2741 case NEXTHOP_TYPE_IPV4:
2742 case NEXTHOP_TYPE_IPV4_IFINDEX:
2743 vty_out(vty, "%15s",
2744 inet_ntoa(nexthop->gate.ipv4));
2745 break;
2746 case NEXTHOP_TYPE_IPV6:
2747 case NEXTHOP_TYPE_IPV6_IFINDEX:
2748 vty_out(vty, "%15s",
2749 inet_ntop(AF_INET6,
2750 &nexthop->gate.ipv6,
2751 buf, BUFSIZ));
2752 break;
2753 default:
2754 break;
2755 }
2756
b9abd9ad 2757 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
fc5cca9f
DS
2758 vty_out(vty, " %8s\n",
2759 mpls_label2str(
2760 nexthop->nh_label
2761 ->num_labels,
2762 &nexthop->nh_label
2763 ->label[0],
2764 buf, BUFSIZ, 1));
b9abd9ad
DS
2765 else
2766 vty_out(vty, "\n");
d62a17ae 2767 }
2768 }
2769
2770 vty_out(vty, "\n");
2771 }
2772
affe9e99 2773 list_delete_and_null(&lsp_list);
3ab18ff2 2774}
2775
7758e3f3 2776/*
2777 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
2778 */
d62a17ae 2779int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
2780{
2781 zebra_slsp_t *slsp;
2782 zebra_snhlfe_t *snhlfe;
2783 struct listnode *node;
2784 struct list *slsp_list =
2785 hash_get_sorted_list(zvrf->slsp_table, slsp_cmp);
2786
2787 for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) {
2788 for (snhlfe = slsp->snhlfe_list; snhlfe;
2789 snhlfe = snhlfe->next) {
0af35d90 2790 char buf[BUFSIZ];
d62a17ae 2791 char lstr[30];
2792
0af35d90 2793 snhlfe2str(snhlfe, buf, sizeof(buf));
d62a17ae 2794 switch (snhlfe->out_label) {
70e98a7f
DS
2795 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
2796 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
d62a17ae 2797 strlcpy(lstr, "explicit-null", sizeof(lstr));
2798 break;
70e98a7f 2799 case MPLS_LABEL_IMPLICIT_NULL:
d62a17ae 2800 strlcpy(lstr, "implicit-null", sizeof(lstr));
2801 break;
2802 default:
2803 sprintf(lstr, "%u", snhlfe->out_label);
2804 break;
2805 }
2806
2807 vty_out(vty, "mpls lsp %u %s %s\n", slsp->ile.in_label,
2808 buf, lstr);
2809 }
2810 }
b78b820d 2811
affe9e99 2812 list_delete_and_null(&slsp_list);
d62a17ae 2813 return (zvrf->slsp_table->count ? 1 : 0);
7758e3f3 2814}
2815
1b6d5c7e
VV
2816/*
2817 * Add/update global label block.
2818 */
d7c0a89a
QY
2819int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
2820 uint32_t end_label)
1b6d5c7e 2821{
d62a17ae 2822 zvrf->mpls_srgb.start_label = start_label;
2823 zvrf->mpls_srgb.end_label = end_label;
28d58fd7 2824
d62a17ae 2825 /* Evaluate registered FECs to see if any get a label or not. */
2826 fec_evaluate(zvrf);
2827 return 0;
1b6d5c7e
VV
2828}
2829
2830/*
2831 * Delete global label block.
2832 */
d62a17ae 2833int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
1b6d5c7e 2834{
d62a17ae 2835 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
2836 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
28d58fd7 2837
d62a17ae 2838 /* Process registered FECs to clear their local label, if needed. */
2839 fec_evaluate(zvrf);
2840 return 0;
1b6d5c7e
VV
2841}
2842
2843/*
2844 * Display MPLS global label block configuration (VTY command handler).
2845 */
d62a17ae 2846int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
1b6d5c7e 2847{
d62a17ae 2848 if (zvrf->mpls_srgb.start_label == 0)
2849 return 0;
1b6d5c7e 2850
d62a17ae 2851 if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
2852 || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
2853 vty_out(vty, "mpls label global-block %u %u\n",
2854 zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
2855 }
1b6d5c7e 2856
d62a17ae 2857 return 1;
1b6d5c7e
VV
2858}
2859
84915b0a 2860/*
2861 * Called when VRF becomes inactive, cleans up information but keeps
2862 * the table itself.
2863 * NOTE: Currently supported only for default VRF.
2864 */
2865void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
2866{
2867 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
2868}
2869
40c7bdb0 2870/*
2871 * Called upon process exiting, need to delete LSP forwarding
2872 * entries from the kernel.
2873 * NOTE: Currently supported only for default VRF.
2874 */
d62a17ae 2875void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
40c7bdb0 2876{
d62a17ae 2877 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
2878 hash_clean(zvrf->lsp_table, NULL);
2879 hash_free(zvrf->lsp_table);
2880 hash_clean(zvrf->slsp_table, NULL);
2881 hash_free(zvrf->slsp_table);
9b67b514
DS
2882 route_table_finish(zvrf->fec_table[AFI_IP]);
2883 route_table_finish(zvrf->fec_table[AFI_IP6]);
40c7bdb0 2884}
2885
7758e3f3 2886/*
2887 * Allocate MPLS tables for this VRF and do other initialization.
2888 * NOTE: Currently supported only for default VRF.
2889 */
d62a17ae 2890void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
7758e3f3 2891{
d62a17ae 2892 if (!zvrf)
2893 return;
996c9314
LB
2894 zvrf->slsp_table =
2895 hash_create(label_hash, label_cmp, "ZEBRA SLSP table");
2896 zvrf->lsp_table = hash_create(label_hash, label_cmp, "ZEBRA LSP table");
d62a17ae 2897 zvrf->fec_table[AFI_IP] = route_table_init();
2898 zvrf->fec_table[AFI_IP6] = route_table_init();
2899 zvrf->mpls_flags = 0;
2900 zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
2901 zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
7758e3f3 2902}
2903
2904/*
2905 * Global MPLS initialization.
2906 */
d62a17ae 2907void zebra_mpls_init(void)
7758e3f3 2908{
d62a17ae 2909 mpls_enabled = 0;
33c32282 2910
d62a17ae 2911 if (mpls_kernel_init() < 0) {
2912 zlog_warn("Disabling MPLS support (no kernel support)");
2913 return;
2914 }
fe6c7157 2915
d62a17ae 2916 if (!mpls_processq_init(&zebrad))
2917 mpls_enabled = 1;
453844ab 2918
d8647095 2919 hook_register(zapi_client_close, zebra_mpls_cleanup_fecs_for_client);
7758e3f3 2920}