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