Line data Source code
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 : *
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
19 : */
20 :
21 : #include <zebra.h>
22 :
23 : #include "prefix.h"
24 : #include "table.h"
25 : #include "memory.h"
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"
37 : #include "termtable.h"
38 : #include "lib/json.h"
39 :
40 : #include "zebra/rib.h"
41 : #include "zebra/rt.h"
42 : #include "zebra/interface.h"
43 : #include "zebra/zserv.h"
44 : #include "zebra/zebra_router.h"
45 : #include "zebra/redistribute.h"
46 : #include "zebra/debug.h"
47 : #include "zebra/zebra_vrf.h"
48 : #include "zebra/zebra_mpls.h"
49 : #include "zebra/zebra_srte.h"
50 : #include "zebra/zebra_errors.h"
51 :
52 9 : DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object");
53 9 : DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object");
54 9 : DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object");
55 :
56 : bool mpls_enabled;
57 : bool mpls_pw_reach_strict; /* Strict reachability checking */
58 :
59 : /* static function declarations */
60 :
61 : static void fec_evaluate(struct zebra_vrf *zvrf);
62 : static uint32_t fec_derive_label_from_index(struct zebra_vrf *vrf,
63 : struct zebra_fec *fec);
64 : static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
65 : struct route_node *rn, struct route_entry *re);
66 : static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label);
67 : static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
68 : mpls_label_t old_label);
69 : static int fec_send(struct zebra_fec *fec, struct zserv *client);
70 : static void fec_update_clients(struct zebra_fec *fec);
71 : static void fec_print(struct zebra_fec *fec, struct vty *vty);
72 : static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p);
73 : static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
74 : mpls_label_t label, uint32_t flags,
75 : uint32_t label_index);
76 : static int fec_del(struct zebra_fec *fec);
77 :
78 : static unsigned int label_hash(const void *p);
79 : static bool label_cmp(const void *p1, const void *p2);
80 : static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
81 : struct nexthop *nexthop);
82 : static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
83 : struct nexthop *nexthop);
84 : static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe);
85 :
86 : static void lsp_select_best_nhlfe(struct zebra_lsp *lsp);
87 : static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt);
88 : static void lsp_schedule(struct hash_bucket *bucket, void *ctxt);
89 : static wq_item_status lsp_process(struct work_queue *wq, void *data);
90 : static void lsp_processq_del(struct work_queue *wq, void *data);
91 : static void lsp_processq_complete(struct work_queue *wq);
92 : static int lsp_processq_add(struct zebra_lsp *lsp);
93 : static void *lsp_alloc(void *p);
94 :
95 : /* Check whether lsp can be freed - no nhlfes, e.g., and call free api */
96 : static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp);
97 :
98 : /* Free lsp; sets caller's pointer to NULL */
99 : static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp);
100 :
101 : static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size);
102 : static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
103 : int size);
104 : static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
105 : enum nexthop_types_t gtype,
106 : const union g_addr *gate, ifindex_t ifindex);
107 : static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
108 : enum lsp_types_t lsp_type,
109 : enum nexthop_types_t gtype,
110 : const union g_addr *gate,
111 : ifindex_t ifindex);
112 : static struct zebra_nhlfe *
113 : nhlfe_add(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
114 : enum nexthop_types_t gtype, const union g_addr *gate,
115 : ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels,
116 : bool is_backup);
117 : static int nhlfe_del(struct zebra_nhlfe *nhlfe);
118 : static void nhlfe_free(struct zebra_nhlfe *nhlfe);
119 : static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
120 : struct mpls_label_stack *nh_label);
121 : static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
122 : enum lsp_types_t type);
123 : static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
124 : mpls_label_t in_label);
125 : static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
126 : const char *indent);
127 : static void lsp_print(struct vty *vty, struct zebra_lsp *lsp);
128 : static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt);
129 : static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
130 : int afi, enum lsp_types_t lsp_type);
131 : static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
132 : const struct zapi_nexthop *znh);
133 : static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
134 : const struct zapi_nexthop *znh);
135 :
136 : /* Static functions */
137 :
138 : /*
139 : * Handle failure in LSP install, clear flags for NHLFE.
140 : */
141 0 : static void clear_nhlfe_installed(struct zebra_lsp *lsp)
142 : {
143 0 : struct zebra_nhlfe *nhlfe;
144 0 : struct nexthop *nexthop;
145 :
146 0 : frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
147 0 : nexthop = nhlfe->nexthop;
148 0 : if (!nexthop)
149 0 : continue;
150 :
151 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
152 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
153 : }
154 :
155 0 : frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
156 0 : nexthop = nhlfe->nexthop;
157 0 : if (!nexthop)
158 0 : continue;
159 :
160 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
161 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
162 : }
163 0 : }
164 :
165 : /*
166 : * Install label forwarding entry based on labeled-route entry.
167 : */
168 0 : static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
169 : struct route_node *rn, struct route_entry *re)
170 : {
171 0 : struct hash *lsp_table;
172 0 : struct zebra_ile tmp_ile;
173 0 : struct zebra_lsp *lsp;
174 0 : struct zebra_nhlfe *nhlfe;
175 0 : struct nexthop *nexthop;
176 0 : enum lsp_types_t lsp_type;
177 0 : char buf[BUFSIZ];
178 0 : int added, changed;
179 :
180 : /* Lookup table. */
181 0 : lsp_table = zvrf->lsp_table;
182 0 : if (!lsp_table)
183 : return -1;
184 :
185 0 : lsp_type = lsp_type_from_re_type(re->type);
186 0 : added = changed = 0;
187 :
188 : /* Locate or allocate LSP entry. */
189 0 : tmp_ile.in_label = label;
190 0 : lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
191 :
192 : /* For each active nexthop, create NHLFE. Note that we deliberately skip
193 : * recursive nexthops right now, because intermediate hops won't
194 : * understand
195 : * the label advertised by the recursive nexthop (plus we don't have the
196 : * logic yet to push multiple labels).
197 : */
198 0 : for (nexthop = re->nhe->nhg.nexthop;
199 0 : nexthop; nexthop = nexthop->next) {
200 : /* Skip inactive and recursive entries. */
201 0 : if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
202 0 : continue;
203 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
204 0 : continue;
205 :
206 0 : nhlfe = nhlfe_find(&lsp->nhlfe_list, lsp_type,
207 0 : nexthop->type, &nexthop->gate,
208 : nexthop->ifindex);
209 0 : if (nhlfe) {
210 : /* Clear deleted flag (in case it was set) */
211 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
212 0 : if (nexthop_labels_match(nhlfe->nexthop, nexthop))
213 : /* No change */
214 0 : continue;
215 :
216 :
217 0 : if (IS_ZEBRA_DEBUG_MPLS) {
218 0 : nhlfe2str(nhlfe, buf, BUFSIZ);
219 0 : zlog_debug(
220 : "LSP in-label %u type %d nexthop %s out-label changed",
221 : lsp->ile.in_label, lsp_type, buf);
222 : }
223 :
224 : /* Update out label, trigger processing. */
225 0 : nhlfe_out_label_update(nhlfe, nexthop->nh_label);
226 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
227 0 : changed++;
228 : } else {
229 : /* Add LSP entry to this nexthop */
230 0 : nhlfe = nhlfe_add(lsp, lsp_type, nexthop->type,
231 : &nexthop->gate, nexthop->ifindex,
232 0 : nexthop->nh_label->num_labels,
233 0 : nexthop->nh_label->label,
234 : false /*backup*/);
235 0 : if (!nhlfe)
236 : return -1;
237 :
238 0 : if (IS_ZEBRA_DEBUG_MPLS) {
239 0 : nhlfe2str(nhlfe, buf, BUFSIZ);
240 0 : zlog_debug(
241 : "Add LSP in-label %u type %d nexthop %s out-label %u",
242 : lsp->ile.in_label, lsp_type, buf,
243 : nexthop->nh_label->label[0]);
244 : }
245 :
246 0 : lsp->addr_family = NHLFE_FAMILY(nhlfe);
247 :
248 : /* Mark NHLFE as changed. */
249 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
250 0 : added++;
251 : }
252 : }
253 :
254 : /* Queue LSP for processing if necessary. If no NHLFE got added (special
255 : * case), delete the LSP entry; this case results in somewhat ugly
256 : * logging.
257 : */
258 0 : if (added || changed) {
259 0 : if (lsp_processq_add(lsp))
260 : return -1;
261 : } else {
262 0 : lsp_check_free(lsp_table, &lsp);
263 : }
264 :
265 : return 0;
266 : }
267 :
268 : /*
269 : * Uninstall all non-static NHLFEs of a label forwarding entry. If all
270 : * NHLFEs are removed, the entire entry is deleted.
271 : */
272 0 : static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label)
273 : {
274 0 : struct hash *lsp_table;
275 0 : struct zebra_ile tmp_ile;
276 0 : struct zebra_lsp *lsp;
277 0 : struct zebra_nhlfe *nhlfe;
278 0 : char buf[BUFSIZ];
279 :
280 : /* Lookup table. */
281 0 : lsp_table = zvrf->lsp_table;
282 0 : if (!lsp_table)
283 : return -1;
284 :
285 : /* If entry is not present, exit. */
286 0 : tmp_ile.in_label = label;
287 0 : lsp = hash_lookup(lsp_table, &tmp_ile);
288 0 : if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
289 : return 0;
290 :
291 : /* Mark NHLFEs for delete or directly delete, as appropriate. */
292 0 : frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
293 :
294 : /* Skip static NHLFEs */
295 0 : if (nhlfe->type == ZEBRA_LSP_STATIC)
296 0 : continue;
297 :
298 0 : if (IS_ZEBRA_DEBUG_MPLS) {
299 0 : nhlfe2str(nhlfe, buf, BUFSIZ);
300 0 : zlog_debug(
301 : "Del LSP in-label %u type %d nexthop %s flags 0x%x",
302 : label, nhlfe->type, buf, nhlfe->flags);
303 : }
304 :
305 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)) {
306 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
307 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
308 : } else {
309 0 : nhlfe_del(nhlfe);
310 : }
311 : }
312 :
313 : /* Queue LSP for processing, if needed, else delete. */
314 0 : if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
315 0 : if (lsp_processq_add(lsp))
316 : return -1;
317 : } else {
318 0 : lsp_check_free(lsp_table, &lsp);
319 : }
320 :
321 : return 0;
322 : }
323 :
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 : */
329 0 : static void fec_evaluate(struct zebra_vrf *zvrf)
330 : {
331 0 : struct route_node *rn;
332 0 : struct zebra_fec *fec;
333 0 : uint32_t old_label, new_label;
334 0 : int af;
335 :
336 0 : for (af = AFI_IP; af < AFI_MAX; af++) {
337 0 : if (zvrf->fec_table[af] == NULL)
338 0 : continue;
339 :
340 0 : for (rn = route_top(zvrf->fec_table[af]); rn;
341 0 : rn = route_next(rn)) {
342 0 : if ((fec = rn->info) == NULL)
343 0 : continue;
344 :
345 : /* Skip configured FECs and those without a label index.
346 : */
347 0 : if (fec->flags & FEC_FLAG_CONFIGURED
348 0 : || fec->label_index == MPLS_INVALID_LABEL_INDEX)
349 0 : continue;
350 :
351 : /* Save old label, determine new label. */
352 0 : old_label = fec->label;
353 0 : new_label =
354 0 : zvrf->mpls_srgb.start_label + fec->label_index;
355 0 : if (new_label >= zvrf->mpls_srgb.end_label)
356 0 : new_label = MPLS_INVALID_LABEL;
357 :
358 : /* If label has changed, update FEC and clients. */
359 0 : if (new_label == old_label)
360 0 : continue;
361 :
362 0 : if (IS_ZEBRA_DEBUG_MPLS)
363 0 : zlog_debug(
364 : "Update fec %pRN new label %u upon label block",
365 : rn, new_label);
366 :
367 0 : fec->label = new_label;
368 0 : fec_update_clients(fec);
369 :
370 : /* Update label forwarding entries appropriately */
371 0 : fec_change_update_lsp(zvrf, fec, old_label);
372 : }
373 : }
374 0 : }
375 :
376 : /*
377 : * Derive (if possible) and update the local label for the FEC based on
378 : * its label index. The index is "acceptable" if it falls within the
379 : * globally configured label block (SRGB).
380 : */
381 0 : static uint32_t fec_derive_label_from_index(struct zebra_vrf *zvrf,
382 : struct zebra_fec *fec)
383 : {
384 0 : uint32_t label;
385 :
386 0 : if (fec->label_index != MPLS_INVALID_LABEL_INDEX
387 0 : && zvrf->mpls_srgb.start_label
388 0 : && ((label = zvrf->mpls_srgb.start_label + fec->label_index)
389 0 : < zvrf->mpls_srgb.end_label))
390 0 : fec->label = label;
391 : else
392 0 : fec->label = MPLS_INVALID_LABEL;
393 :
394 0 : return fec->label;
395 : }
396 :
397 : /*
398 : * There is a change for this FEC. Install or uninstall label forwarding
399 : * entries, as appropriate.
400 : */
401 0 : static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
402 : mpls_label_t old_label)
403 : {
404 0 : struct route_table *table;
405 0 : struct route_node *rn;
406 0 : struct route_entry *re;
407 0 : afi_t afi;
408 :
409 : /* Uninstall label forwarding entry, if previously installed. */
410 0 : if (old_label != MPLS_INVALID_LABEL
411 0 : && old_label != MPLS_LABEL_IMPLICIT_NULL)
412 0 : lsp_uninstall(zvrf, old_label);
413 :
414 : /* Install label forwarding entry corr. to new label, if needed. */
415 0 : if (fec->label == MPLS_INVALID_LABEL
416 0 : || fec->label == MPLS_LABEL_IMPLICIT_NULL)
417 : return 0;
418 :
419 0 : afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
420 0 : table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
421 0 : if (!table)
422 : return 0;
423 :
424 : /* See if labeled route exists. */
425 0 : rn = route_node_lookup(table, &fec->rn->p);
426 0 : if (!rn)
427 : return 0;
428 :
429 0 : RNODE_FOREACH_RE (rn, re) {
430 0 : if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
431 : break;
432 : }
433 :
434 0 : if (!re || !zebra_rib_labeled_unicast(re))
435 0 : return 0;
436 :
437 0 : if (lsp_install(zvrf, fec->label, rn, re))
438 : return -1;
439 :
440 : return 0;
441 : }
442 :
443 : /*
444 : * Inform about FEC to a registered client.
445 : */
446 0 : static int fec_send(struct zebra_fec *fec, struct zserv *client)
447 : {
448 0 : struct stream *s;
449 0 : struct route_node *rn;
450 :
451 0 : rn = fec->rn;
452 :
453 : /* Get output stream. */
454 0 : s = stream_new(ZEBRA_MAX_PACKET_SIZ);
455 :
456 0 : zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
457 :
458 0 : stream_putw(s, rn->p.family);
459 0 : stream_put_prefix(s, &rn->p);
460 0 : stream_putl(s, fec->label);
461 0 : stream_putw_at(s, 0, stream_get_endp(s));
462 0 : return zserv_send_message(client, s);
463 : }
464 :
465 : /*
466 : * Update all registered clients about this FEC. Caller should've updated
467 : * FEC and ensure no duplicate updates.
468 : */
469 0 : static void fec_update_clients(struct zebra_fec *fec)
470 : {
471 0 : struct listnode *node;
472 0 : struct zserv *client;
473 :
474 0 : for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) {
475 0 : if (IS_ZEBRA_DEBUG_MPLS)
476 0 : zlog_debug("Update client %s",
477 : zebra_route_string(client->proto));
478 0 : fec_send(fec, client);
479 : }
480 0 : }
481 :
482 :
483 : /*
484 : * Print a FEC-label binding entry.
485 : */
486 0 : static void fec_print(struct zebra_fec *fec, struct vty *vty)
487 : {
488 0 : struct route_node *rn;
489 0 : struct listnode *node;
490 0 : struct zserv *client;
491 0 : char buf[BUFSIZ];
492 :
493 0 : rn = fec->rn;
494 0 : vty_out(vty, "%pRN\n", rn);
495 0 : vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
496 0 : if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
497 0 : vty_out(vty, ", Label Index: %u", fec->label_index);
498 0 : vty_out(vty, "\n");
499 0 : if (!list_isempty(fec->client_list)) {
500 0 : vty_out(vty, " Client list:");
501 0 : for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
502 0 : vty_out(vty, " %s(fd %d)",
503 0 : zebra_route_string(client->proto),
504 : client->sock);
505 0 : vty_out(vty, "\n");
506 : }
507 0 : }
508 :
509 : /*
510 : * Locate FEC-label binding that matches with passed info.
511 : */
512 0 : static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p)
513 : {
514 0 : struct route_node *rn;
515 :
516 0 : apply_mask(p);
517 0 : rn = route_node_lookup(table, p);
518 0 : if (!rn)
519 : return NULL;
520 :
521 0 : route_unlock_node(rn);
522 0 : return (rn->info);
523 : }
524 :
525 : /*
526 : * Add a FEC. This may be upon a client registering for a binding
527 : * or when a binding is configured.
528 : */
529 0 : static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
530 : mpls_label_t label, uint32_t flags,
531 : uint32_t label_index)
532 : {
533 0 : struct route_node *rn;
534 0 : struct zebra_fec *fec;
535 :
536 0 : apply_mask(p);
537 :
538 : /* Lookup (or add) route node.*/
539 0 : rn = route_node_get(table, p);
540 0 : if (!rn)
541 : return NULL;
542 :
543 0 : fec = rn->info;
544 :
545 0 : if (!fec) {
546 0 : fec = XCALLOC(MTYPE_FEC, sizeof(struct zebra_fec));
547 :
548 0 : rn->info = fec;
549 0 : fec->rn = rn;
550 0 : fec->label = label;
551 0 : fec->client_list = list_new();
552 : } else
553 0 : route_unlock_node(rn); /* for the route_node_get */
554 :
555 0 : fec->label_index = label_index;
556 0 : fec->flags = flags;
557 :
558 0 : return fec;
559 : }
560 :
561 : /*
562 : * Delete a FEC. This may be upon the last client deregistering for
563 : * a FEC and no binding exists or when the binding is deleted and there
564 : * are no registered clients.
565 : */
566 0 : static int fec_del(struct zebra_fec *fec)
567 : {
568 0 : list_delete(&fec->client_list);
569 0 : fec->rn->info = NULL;
570 0 : route_unlock_node(fec->rn);
571 0 : XFREE(MTYPE_FEC, fec);
572 0 : return 0;
573 : }
574 :
575 : /*
576 : * Hash function for label.
577 : */
578 0 : static unsigned int label_hash(const void *p)
579 : {
580 0 : const struct zebra_ile *ile = p;
581 :
582 0 : return (jhash_1word(ile->in_label, 0));
583 : }
584 :
585 : /*
586 : * Compare 2 LSP hash entries based on in-label.
587 : */
588 0 : static bool label_cmp(const void *p1, const void *p2)
589 : {
590 0 : const struct zebra_ile *ile1 = p1;
591 0 : const struct zebra_ile *ile2 = p2;
592 :
593 0 : return (ile1->in_label == ile2->in_label);
594 : }
595 :
596 : /*
597 : * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
598 : * the passed flag.
599 : * NOTE: Looking only for connected routes right now.
600 : */
601 0 : static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
602 : struct nexthop *nexthop)
603 : {
604 0 : struct route_table *table;
605 0 : struct prefix_ipv4 p;
606 0 : struct route_node *rn;
607 0 : struct route_entry *match;
608 0 : struct nexthop *match_nh;
609 :
610 0 : table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, nexthop->vrf_id);
611 0 : if (!table)
612 : return 0;
613 :
614 : /* Lookup nexthop in IPv4 routing table. */
615 0 : memset(&p, 0, sizeof(p));
616 0 : p.family = AF_INET;
617 0 : p.prefixlen = IPV4_MAX_BITLEN;
618 0 : p.prefix = nexthop->gate.ipv4;
619 :
620 0 : rn = route_node_match(table, (struct prefix *)&p);
621 0 : if (!rn)
622 : return 0;
623 :
624 0 : route_unlock_node(rn);
625 :
626 : /* Locate a valid connected route. */
627 0 : RNODE_FOREACH_RE (rn, match) {
628 0 : if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
629 0 : || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
630 0 : continue;
631 :
632 0 : for (match_nh = match->nhe->nhg.nexthop; match_nh;
633 0 : match_nh = match_nh->next) {
634 0 : if (match->type == ZEBRA_ROUTE_CONNECT
635 0 : || nexthop->ifindex == match_nh->ifindex) {
636 0 : nexthop->ifindex = match_nh->ifindex;
637 0 : return 1;
638 : }
639 : }
640 : }
641 :
642 : return 0;
643 : }
644 :
645 :
646 : /*
647 : * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
648 : * the passed flag.
649 : * NOTE: Looking only for connected routes right now.
650 : */
651 0 : static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
652 : struct nexthop *nexthop)
653 : {
654 0 : struct route_table *table;
655 0 : struct prefix_ipv6 p;
656 0 : struct route_node *rn;
657 0 : struct route_entry *match;
658 :
659 0 : table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
660 0 : if (!table)
661 : return 0;
662 :
663 : /* Lookup nexthop in IPv6 routing table. */
664 0 : memset(&p, 0, sizeof(p));
665 0 : p.family = AF_INET6;
666 0 : p.prefixlen = IPV6_MAX_BITLEN;
667 0 : p.prefix = nexthop->gate.ipv6;
668 :
669 0 : rn = route_node_match(table, (struct prefix *)&p);
670 0 : if (!rn)
671 : return 0;
672 :
673 0 : route_unlock_node(rn);
674 :
675 : /* Locate a valid connected route. */
676 0 : RNODE_FOREACH_RE (rn, match) {
677 0 : if ((match->type == ZEBRA_ROUTE_CONNECT)
678 : && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
679 0 : && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
680 : break;
681 : }
682 :
683 0 : if (!match || !match->nhe->nhg.nexthop)
684 : return 0;
685 :
686 0 : nexthop->ifindex = match->nhe->nhg.nexthop->ifindex;
687 0 : return 1;
688 : }
689 :
690 :
691 : /*
692 : * Check the nexthop reachability for a NHLFE and return if valid (reachable)
693 : * or not.
694 : * NOTE: Each NHLFE points to only 1 nexthop.
695 : */
696 0 : static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe)
697 : {
698 0 : struct nexthop *nexthop;
699 0 : struct interface *ifp;
700 0 : struct zebra_ns *zns;
701 :
702 0 : nexthop = nhlfe->nexthop;
703 0 : if (!nexthop) // unexpected
704 : return 0;
705 :
706 : /* Check on nexthop based on type. */
707 0 : switch (nexthop->type) {
708 0 : case NEXTHOP_TYPE_IFINDEX:
709 : /*
710 : * Lookup if this type is special. The
711 : * NEXTHOP_TYPE_IFINDEX is a pop and
712 : * forward into a different table for
713 : * processing. As such this ifindex
714 : * passed to us may be a VRF device
715 : * which will not be in the default
716 : * VRF. So let's look in all of them
717 : */
718 0 : zns = zebra_ns_lookup(NS_DEFAULT);
719 0 : ifp = if_lookup_by_index_per_ns(zns, nexthop->ifindex);
720 0 : if (ifp && if_is_operative(ifp))
721 0 : SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
722 : else
723 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
724 : break;
725 0 : case NEXTHOP_TYPE_IPV4:
726 : case NEXTHOP_TYPE_IPV4_IFINDEX:
727 0 : if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop))
728 0 : SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
729 : else
730 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
731 : break;
732 :
733 0 : case NEXTHOP_TYPE_IPV6:
734 0 : if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
735 0 : SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
736 : else
737 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
738 : break;
739 :
740 0 : case NEXTHOP_TYPE_IPV6_IFINDEX:
741 0 : if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
742 0 : ifp = if_lookup_by_index(nexthop->ifindex,
743 : nexthop->vrf_id);
744 0 : if (ifp && if_is_operative(ifp))
745 0 : SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
746 : else
747 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
748 : } else {
749 0 : if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
750 0 : SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
751 : else
752 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
753 : }
754 : break;
755 :
756 : case NEXTHOP_TYPE_BLACKHOLE:
757 : break;
758 : }
759 :
760 0 : return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
761 : }
762 :
763 : /*
764 : * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
765 : * reachability and select the best. Multipath entries are also
766 : * marked. This is invoked when an LSP scheduled for processing (due
767 : * to some change) is examined.
768 : */
769 0 : static void lsp_select_best_nhlfe(struct zebra_lsp *lsp)
770 : {
771 0 : struct zebra_nhlfe *nhlfe;
772 0 : struct zebra_nhlfe *best;
773 0 : struct nexthop *nexthop;
774 0 : int changed = 0;
775 :
776 0 : if (!lsp)
777 : return;
778 :
779 0 : best = NULL;
780 0 : lsp->num_ecmp = 0;
781 0 : UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
782 :
783 : /*
784 : * First compute the best path, after checking nexthop status. We are
785 : * only concerned with non-deleted NHLFEs.
786 : */
787 0 : frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
788 : /* Clear selection flags. */
789 0 : UNSET_FLAG(nhlfe->flags,
790 : (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
791 :
792 0 : if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
793 0 : && nhlfe_nexthop_active(nhlfe)) {
794 0 : if (!best || (nhlfe->distance < best->distance))
795 0 : best = nhlfe;
796 : }
797 : }
798 :
799 0 : lsp->best_nhlfe = best;
800 0 : if (!lsp->best_nhlfe)
801 : return;
802 :
803 : /*
804 : * Check the active status of backup nhlfes also
805 : */
806 0 : frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
807 0 : if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
808 0 : (void)nhlfe_nexthop_active(nhlfe);
809 : }
810 :
811 : /* Mark best NHLFE as selected. */
812 0 : SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
813 :
814 : /*
815 : * If best path exists, see if there is ECMP. While doing this, note if
816 : * a
817 : * new (uninstalled) NHLFE has been selected, an installed entry that is
818 : * still selected has a change or an installed entry is to be removed.
819 : */
820 0 : frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
821 0 : int nh_chg, nh_sel, nh_inst;
822 :
823 0 : nexthop = nhlfe->nexthop;
824 0 : if (!nexthop) // unexpected
825 0 : continue;
826 :
827 0 : if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
828 0 : && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
829 0 : && (nhlfe->distance == lsp->best_nhlfe->distance)) {
830 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
831 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_MULTIPATH);
832 0 : lsp->num_ecmp++;
833 : }
834 :
835 0 : if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) && !changed) {
836 0 : nh_chg = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
837 0 : nh_sel = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
838 0 : nh_inst =
839 : CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
840 :
841 0 : if ((nh_sel && !nh_inst)
842 0 : || (nh_sel && nh_inst && nh_chg)
843 0 : || (nh_inst && !nh_sel))
844 0 : changed = 1;
845 : }
846 :
847 : /* We have finished examining, clear changed flag. */
848 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
849 : }
850 :
851 0 : if (changed)
852 0 : SET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
853 : }
854 :
855 : /*
856 : * Delete LSP forwarding entry from kernel, if installed. Called upon
857 : * process exit.
858 : */
859 0 : static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt)
860 : {
861 0 : struct zebra_lsp *lsp;
862 :
863 0 : lsp = (struct zebra_lsp *)bucket->data;
864 0 : if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
865 0 : (void)dplane_lsp_delete(lsp);
866 0 : }
867 :
868 : /*
869 : * Schedule LSP forwarding entry for processing. Called upon changes
870 : * that may impact LSPs such as nexthop / connected route changes.
871 : */
872 0 : static void lsp_schedule(struct hash_bucket *bucket, void *ctxt)
873 : {
874 0 : struct zebra_lsp *lsp;
875 :
876 0 : lsp = (struct zebra_lsp *)bucket->data;
877 :
878 : /* In the common flow, this is used when external events occur. For
879 : * LSPs with backup nhlfes, we'll assume that the forwarding
880 : * plane will use the backups to handle these events, until the
881 : * owning protocol can react.
882 : */
883 0 : if (ctxt == NULL) {
884 : /* Skip LSPs with backups */
885 0 : if (nhlfe_list_first(&lsp->backup_nhlfe_list) != NULL) {
886 0 : if (IS_ZEBRA_DEBUG_MPLS_DETAIL)
887 0 : zlog_debug("%s: skip LSP in-label %u",
888 : __func__, lsp->ile.in_label);
889 0 : return;
890 : }
891 : }
892 :
893 0 : (void)lsp_processq_add(lsp);
894 : }
895 :
896 : /*
897 : * Process a LSP entry that is in the queue. Recalculate best NHLFE and
898 : * any multipaths and update or delete from the kernel, as needed.
899 : */
900 0 : static wq_item_status lsp_process(struct work_queue *wq, void *data)
901 : {
902 0 : struct zebra_lsp *lsp;
903 0 : struct zebra_nhlfe *oldbest, *newbest;
904 0 : char buf[BUFSIZ], buf2[BUFSIZ];
905 0 : struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
906 0 : enum zebra_dplane_result res;
907 :
908 0 : lsp = (struct zebra_lsp *)data;
909 0 : if (!lsp) // unexpected
910 : return WQ_SUCCESS;
911 :
912 0 : oldbest = lsp->best_nhlfe;
913 :
914 : /* Select best NHLFE(s) */
915 0 : lsp_select_best_nhlfe(lsp);
916 :
917 0 : newbest = lsp->best_nhlfe;
918 :
919 0 : if (IS_ZEBRA_DEBUG_MPLS) {
920 0 : if (oldbest)
921 0 : nhlfe2str(oldbest, buf, sizeof(buf));
922 0 : if (newbest)
923 0 : nhlfe2str(newbest, buf2, sizeof(buf2));
924 0 : zlog_debug(
925 : "Process LSP in-label %u oldbest %s newbest %s flags 0x%x ecmp# %d",
926 : lsp->ile.in_label, oldbest ? buf : "NULL",
927 : newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
928 : }
929 :
930 0 : if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
931 : /* Not already installed */
932 0 : if (newbest) {
933 :
934 0 : UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
935 :
936 0 : switch (dplane_lsp_add(lsp)) {
937 0 : case ZEBRA_DPLANE_REQUEST_QUEUED:
938 : /* Set 'installed' flag so we will know
939 : * that an install is in-flight.
940 : */
941 0 : SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
942 :
943 0 : zvrf->lsp_installs_queued++;
944 0 : break;
945 0 : case ZEBRA_DPLANE_REQUEST_FAILURE:
946 0 : flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
947 : "LSP Install Failure: %u",
948 : lsp->ile.in_label);
949 0 : break;
950 0 : case ZEBRA_DPLANE_REQUEST_SUCCESS:
951 0 : zvrf->lsp_installs++;
952 0 : break;
953 : }
954 : }
955 : } else {
956 : /* Installed, may need an update and/or delete. */
957 0 : if (!newbest) {
958 0 : res = dplane_lsp_delete(lsp);
959 :
960 : /* We do some of the lsp cleanup immediately for
961 : * deletes.
962 : */
963 0 : UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
964 0 : clear_nhlfe_installed(lsp);
965 :
966 0 : switch (res) {
967 0 : case ZEBRA_DPLANE_REQUEST_QUEUED:
968 0 : zvrf->lsp_removals_queued++;
969 0 : break;
970 0 : case ZEBRA_DPLANE_REQUEST_FAILURE:
971 0 : flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
972 : "LSP Deletion Failure: %u",
973 : lsp->ile.in_label);
974 0 : break;
975 0 : case ZEBRA_DPLANE_REQUEST_SUCCESS:
976 0 : zvrf->lsp_removals++;
977 0 : break;
978 : }
979 0 : } else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) {
980 0 : struct zebra_nhlfe *nhlfe;
981 0 : struct nexthop *nexthop;
982 :
983 0 : UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
984 :
985 : /* We leave the INSTALLED flag set here
986 : * so we know an update is in-flight.
987 : */
988 :
989 : /*
990 : * Any NHLFE that was installed but is not
991 : * selected now needs to have its flags updated.
992 : */
993 0 : frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
994 0 : nexthop = nhlfe->nexthop;
995 0 : if (!nexthop)
996 0 : continue;
997 :
998 0 : if (CHECK_FLAG(nhlfe->flags,
999 : NHLFE_FLAG_INSTALLED)
1000 0 : && !CHECK_FLAG(nhlfe->flags,
1001 : NHLFE_FLAG_SELECTED)) {
1002 0 : UNSET_FLAG(nhlfe->flags,
1003 : NHLFE_FLAG_INSTALLED);
1004 0 : UNSET_FLAG(nexthop->flags,
1005 : NEXTHOP_FLAG_FIB);
1006 : }
1007 : }
1008 :
1009 0 : switch (dplane_lsp_update(lsp)) {
1010 0 : case ZEBRA_DPLANE_REQUEST_QUEUED:
1011 0 : zvrf->lsp_installs_queued++;
1012 0 : break;
1013 0 : case ZEBRA_DPLANE_REQUEST_FAILURE:
1014 0 : flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1015 : "LSP Update Failure: %u",
1016 : lsp->ile.in_label);
1017 0 : break;
1018 0 : case ZEBRA_DPLANE_REQUEST_SUCCESS:
1019 0 : zvrf->lsp_installs++;
1020 0 : break;
1021 : }
1022 : }
1023 : }
1024 :
1025 : return WQ_SUCCESS;
1026 : }
1027 :
1028 :
1029 : /*
1030 : * Callback upon processing completion of a LSP forwarding entry.
1031 : */
1032 0 : static void lsp_processq_del(struct work_queue *wq, void *data)
1033 : {
1034 0 : struct zebra_vrf *zvrf;
1035 0 : struct zebra_lsp *lsp;
1036 0 : struct hash *lsp_table;
1037 0 : struct zebra_nhlfe *nhlfe;
1038 :
1039 : /* If zebra is shutting down, don't delete any structs,
1040 : * just ignore this callback. The LSPs will be cleaned up
1041 : * during the shutdown processing.
1042 : */
1043 0 : if (zebra_router_in_shutdown())
1044 0 : return;
1045 :
1046 0 : zvrf = vrf_info_lookup(VRF_DEFAULT);
1047 0 : assert(zvrf);
1048 :
1049 0 : lsp_table = zvrf->lsp_table;
1050 0 : if (!lsp_table) // unexpected
1051 : return;
1052 :
1053 0 : lsp = (struct zebra_lsp *)data;
1054 0 : if (!lsp) // unexpected
1055 : return;
1056 :
1057 : /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
1058 : * exist,
1059 : * delete LSP entry also.
1060 : */
1061 0 : UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1062 :
1063 0 : frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1064 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1065 0 : nhlfe_del(nhlfe);
1066 : }
1067 :
1068 0 : frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1069 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1070 0 : nhlfe_del(nhlfe);
1071 : }
1072 :
1073 0 : lsp_check_free(lsp_table, &lsp);
1074 : }
1075 :
1076 : /*
1077 : * Callback upon finishing the processing of all scheduled
1078 : * LSP forwarding entries.
1079 : */
1080 0 : static void lsp_processq_complete(struct work_queue *wq)
1081 : {
1082 : /* Nothing to do for now. */
1083 0 : }
1084 :
1085 : /*
1086 : * Add LSP forwarding entry to queue for subsequent processing.
1087 : */
1088 0 : static int lsp_processq_add(struct zebra_lsp *lsp)
1089 : {
1090 : /* If already scheduled, exit. */
1091 0 : if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1092 : return 0;
1093 :
1094 0 : if (zrouter.lsp_process_q == NULL) {
1095 0 : flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1096 : "%s: work_queue does not exist!", __func__);
1097 0 : return -1;
1098 : }
1099 :
1100 0 : work_queue_add(zrouter.lsp_process_q, lsp);
1101 0 : SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1102 0 : return 0;
1103 : }
1104 :
1105 : /*
1106 : * Callback to allocate LSP forwarding table entry.
1107 : */
1108 0 : static void *lsp_alloc(void *p)
1109 : {
1110 0 : const struct zebra_ile *ile = p;
1111 0 : struct zebra_lsp *lsp;
1112 :
1113 0 : lsp = XCALLOC(MTYPE_LSP, sizeof(struct zebra_lsp));
1114 0 : lsp->ile = *ile;
1115 0 : nhlfe_list_init(&lsp->nhlfe_list);
1116 0 : nhlfe_list_init(&lsp->backup_nhlfe_list);
1117 :
1118 0 : if (IS_ZEBRA_DEBUG_MPLS)
1119 0 : zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label);
1120 :
1121 0 : return ((void *)lsp);
1122 : }
1123 :
1124 : /*
1125 : * Check whether lsp can be freed - no nhlfes, e.g., and call free api
1126 : */
1127 0 : static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp)
1128 : {
1129 0 : struct zebra_lsp *lsp;
1130 :
1131 0 : if (plsp == NULL || *plsp == NULL)
1132 : return;
1133 :
1134 0 : lsp = *plsp;
1135 :
1136 0 : if ((nhlfe_list_first(&lsp->nhlfe_list) == NULL) &&
1137 0 : (nhlfe_list_first(&lsp->backup_nhlfe_list) == NULL) &&
1138 0 : !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1139 0 : lsp_free(lsp_table, plsp);
1140 : }
1141 :
1142 0 : static void lsp_free_nhlfe(struct zebra_lsp *lsp)
1143 : {
1144 0 : struct zebra_nhlfe *nhlfe;
1145 :
1146 0 : while ((nhlfe = nhlfe_list_first(&lsp->nhlfe_list))) {
1147 0 : nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
1148 0 : nhlfe_free(nhlfe);
1149 : }
1150 :
1151 0 : while ((nhlfe = nhlfe_list_first(&lsp->backup_nhlfe_list))) {
1152 0 : nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
1153 0 : nhlfe_free(nhlfe);
1154 : }
1155 0 : }
1156 :
1157 : /*
1158 : * Dtor for an LSP: remove from ile hash, release any internal allocations,
1159 : * free LSP object.
1160 : */
1161 0 : static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp)
1162 : {
1163 0 : struct zebra_lsp *lsp;
1164 :
1165 0 : if (plsp == NULL || *plsp == NULL)
1166 : return;
1167 :
1168 0 : lsp = *plsp;
1169 :
1170 0 : if (IS_ZEBRA_DEBUG_MPLS)
1171 0 : zlog_debug("Free LSP in-label %u flags 0x%x",
1172 : lsp->ile.in_label, lsp->flags);
1173 :
1174 0 : lsp_free_nhlfe(lsp);
1175 :
1176 0 : hash_release(lsp_table, &lsp->ile);
1177 0 : XFREE(MTYPE_LSP, lsp);
1178 :
1179 0 : *plsp = NULL;
1180 : }
1181 :
1182 : /*
1183 : * Create printable string for NHLFE entry.
1184 : */
1185 0 : static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size)
1186 : {
1187 0 : const struct nexthop *nexthop;
1188 :
1189 0 : buf[0] = '\0';
1190 0 : nexthop = nhlfe->nexthop;
1191 0 : switch (nexthop->type) {
1192 0 : case NEXTHOP_TYPE_IPV4:
1193 : case NEXTHOP_TYPE_IPV4_IFINDEX:
1194 0 : inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
1195 0 : break;
1196 0 : case NEXTHOP_TYPE_IPV6:
1197 : case NEXTHOP_TYPE_IPV6_IFINDEX:
1198 0 : inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
1199 0 : break;
1200 0 : case NEXTHOP_TYPE_IFINDEX:
1201 0 : snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
1202 : case NEXTHOP_TYPE_BLACKHOLE:
1203 : break;
1204 : }
1205 :
1206 0 : return buf;
1207 : }
1208 :
1209 : /*
1210 : * Check if NHLFE matches with search info passed.
1211 : */
1212 0 : static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
1213 : enum nexthop_types_t gtype,
1214 : const union g_addr *gate, ifindex_t ifindex)
1215 : {
1216 0 : struct nexthop *nhop;
1217 0 : int cmp = 1;
1218 :
1219 0 : nhop = nhlfe->nexthop;
1220 0 : if (!nhop)
1221 : return 1;
1222 :
1223 0 : if (nhop->type != gtype)
1224 : return 1;
1225 :
1226 0 : switch (nhop->type) {
1227 0 : case NEXTHOP_TYPE_IPV4:
1228 : case NEXTHOP_TYPE_IPV4_IFINDEX:
1229 0 : cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
1230 : sizeof(struct in_addr));
1231 0 : if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1232 0 : cmp = !(nhop->ifindex == ifindex);
1233 : break;
1234 0 : case NEXTHOP_TYPE_IPV6:
1235 : case NEXTHOP_TYPE_IPV6_IFINDEX:
1236 0 : cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
1237 : sizeof(struct in6_addr));
1238 0 : if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1239 0 : cmp = !(nhop->ifindex == ifindex);
1240 : break;
1241 0 : case NEXTHOP_TYPE_IFINDEX:
1242 0 : cmp = !(nhop->ifindex == ifindex);
1243 0 : break;
1244 : case NEXTHOP_TYPE_BLACKHOLE:
1245 : break;
1246 : }
1247 :
1248 : return cmp;
1249 : }
1250 :
1251 :
1252 : /*
1253 : * Locate NHLFE that matches with passed info.
1254 : */
1255 0 : static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
1256 : enum lsp_types_t lsp_type,
1257 : enum nexthop_types_t gtype,
1258 : const union g_addr *gate,
1259 : ifindex_t ifindex)
1260 : {
1261 0 : struct zebra_nhlfe *nhlfe;
1262 :
1263 0 : frr_each_safe(nhlfe_list, list, nhlfe) {
1264 0 : if (nhlfe->type != lsp_type)
1265 0 : continue;
1266 0 : if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex))
1267 : break;
1268 : }
1269 :
1270 0 : return nhlfe;
1271 : }
1272 :
1273 : /*
1274 : * Allocate and init new NHLFE.
1275 : */
1276 : static struct zebra_nhlfe *
1277 0 : nhlfe_alloc(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
1278 : enum nexthop_types_t gtype, const union g_addr *gate,
1279 : ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels)
1280 : {
1281 0 : struct zebra_nhlfe *nhlfe;
1282 0 : struct nexthop *nexthop;
1283 :
1284 0 : assert(lsp);
1285 :
1286 0 : nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(struct zebra_nhlfe));
1287 :
1288 0 : nhlfe->lsp = lsp;
1289 0 : nhlfe->type = lsp_type;
1290 0 : nhlfe->distance = lsp_distance(lsp_type);
1291 :
1292 0 : nexthop = nexthop_new();
1293 :
1294 0 : nexthop_add_labels(nexthop, lsp_type, num_labels, labels);
1295 :
1296 0 : nexthop->vrf_id = VRF_DEFAULT;
1297 0 : nexthop->type = gtype;
1298 0 : switch (nexthop->type) {
1299 0 : case NEXTHOP_TYPE_IPV4:
1300 : case NEXTHOP_TYPE_IPV4_IFINDEX:
1301 0 : nexthop->gate.ipv4 = gate->ipv4;
1302 0 : if (ifindex)
1303 0 : nexthop->ifindex = ifindex;
1304 : break;
1305 0 : case NEXTHOP_TYPE_IPV6:
1306 : case NEXTHOP_TYPE_IPV6_IFINDEX:
1307 0 : nexthop->gate.ipv6 = gate->ipv6;
1308 0 : if (ifindex)
1309 0 : nexthop->ifindex = ifindex;
1310 : break;
1311 0 : case NEXTHOP_TYPE_IFINDEX:
1312 0 : nexthop->ifindex = ifindex;
1313 0 : break;
1314 0 : case NEXTHOP_TYPE_BLACKHOLE:
1315 0 : if (IS_ZEBRA_DEBUG_MPLS)
1316 0 : zlog_debug("%s: invalid: blackhole nexthop", __func__);
1317 :
1318 0 : nexthop_free(nexthop);
1319 0 : XFREE(MTYPE_NHLFE, nhlfe);
1320 0 : return NULL;
1321 : }
1322 0 : nhlfe->nexthop = nexthop;
1323 :
1324 0 : return nhlfe;
1325 : }
1326 :
1327 : /*
1328 : * Add primary or backup NHLFE. Base entry must have been created and
1329 : * duplicate check done.
1330 : */
1331 0 : static struct zebra_nhlfe *nhlfe_add(struct zebra_lsp *lsp,
1332 : enum lsp_types_t lsp_type,
1333 : enum nexthop_types_t gtype,
1334 : const union g_addr *gate,
1335 : ifindex_t ifindex, uint8_t num_labels,
1336 : const mpls_label_t *labels, bool is_backup)
1337 : {
1338 0 : struct zebra_nhlfe *nhlfe;
1339 :
1340 0 : if (!lsp)
1341 : return NULL;
1342 :
1343 : /* Must have labels */
1344 0 : if (num_labels == 0 || labels == NULL) {
1345 0 : if (IS_ZEBRA_DEBUG_MPLS)
1346 0 : zlog_debug("%s: invalid nexthop: no labels", __func__);
1347 :
1348 0 : return NULL;
1349 : }
1350 :
1351 : /* Allocate new object */
1352 0 : nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels,
1353 : labels);
1354 :
1355 0 : if (!nhlfe)
1356 : return NULL;
1357 :
1358 : /* Enqueue to LSP: primaries at head of list, backups at tail */
1359 0 : if (is_backup) {
1360 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP);
1361 0 : nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe);
1362 : } else
1363 0 : nhlfe_list_add_head(&lsp->nhlfe_list, nhlfe);
1364 :
1365 : return nhlfe;
1366 : }
1367 :
1368 : /*
1369 : * Common delete for NHLFEs.
1370 : */
1371 0 : static void nhlfe_free(struct zebra_nhlfe *nhlfe)
1372 : {
1373 0 : if (!nhlfe)
1374 : return;
1375 :
1376 : /* Free nexthop. */
1377 0 : if (nhlfe->nexthop)
1378 0 : nexthop_free(nhlfe->nexthop);
1379 :
1380 0 : nhlfe->nexthop = NULL;
1381 :
1382 0 : XFREE(MTYPE_NHLFE, nhlfe);
1383 : }
1384 :
1385 :
1386 : /*
1387 : * Disconnect NHLFE from LSP, and free. Entry must be present on LSP's list.
1388 : */
1389 0 : static int nhlfe_del(struct zebra_nhlfe *nhlfe)
1390 : {
1391 0 : struct zebra_lsp *lsp;
1392 :
1393 0 : if (!nhlfe)
1394 : return -1;
1395 :
1396 0 : lsp = nhlfe->lsp;
1397 0 : if (!lsp)
1398 : return -1;
1399 :
1400 0 : if (nhlfe == lsp->best_nhlfe)
1401 0 : lsp->best_nhlfe = NULL;
1402 :
1403 : /* Unlink from LSP */
1404 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP))
1405 0 : nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
1406 : else
1407 0 : nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
1408 :
1409 0 : nhlfe->lsp = NULL;
1410 :
1411 0 : nhlfe_free(nhlfe);
1412 :
1413 0 : return 0;
1414 : }
1415 :
1416 : /*
1417 : * Update label for NHLFE entry.
1418 : */
1419 0 : static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
1420 : struct mpls_label_stack *nh_label)
1421 : {
1422 0 : nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
1423 : }
1424 :
1425 0 : static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
1426 : enum lsp_types_t type)
1427 : {
1428 0 : struct zebra_nhlfe *nhlfe;
1429 0 : int schedule_lsp = 0;
1430 0 : char buf[BUFSIZ];
1431 :
1432 0 : if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1433 0 : schedule_lsp = 1;
1434 :
1435 : /* Mark NHLFEs for delete or directly delete, as appropriate. */
1436 0 : frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1437 : /* Skip non-static NHLFEs */
1438 0 : if (nhlfe->type != type)
1439 0 : continue;
1440 :
1441 0 : if (IS_ZEBRA_DEBUG_MPLS) {
1442 0 : nhlfe2str(nhlfe, buf, sizeof(buf));
1443 0 : zlog_debug(
1444 : "Del LSP in-label %u type %d nexthop %s flags 0x%x",
1445 : lsp->ile.in_label, type, buf, nhlfe->flags);
1446 : }
1447 :
1448 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1449 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1450 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1451 0 : schedule_lsp = 1;
1452 : } else {
1453 0 : nhlfe_del(nhlfe);
1454 : }
1455 : }
1456 :
1457 0 : frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1458 : /* Skip non-static NHLFEs */
1459 0 : if (nhlfe->type != type)
1460 0 : continue;
1461 :
1462 0 : if (IS_ZEBRA_DEBUG_MPLS) {
1463 0 : nhlfe2str(nhlfe, buf, sizeof(buf));
1464 0 : zlog_debug(
1465 : "Del backup LSP in-label %u type %d nexthop %s flags 0x%x",
1466 : lsp->ile.in_label, type, buf, nhlfe->flags);
1467 : }
1468 :
1469 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1470 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1471 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1472 0 : schedule_lsp = 1;
1473 : } else {
1474 0 : nhlfe_del(nhlfe);
1475 : }
1476 : }
1477 :
1478 : /* Queue LSP for processing, if needed, else delete. */
1479 0 : if (schedule_lsp) {
1480 0 : if (IS_ZEBRA_DEBUG_MPLS) {
1481 0 : zlog_debug("Schedule LSP in-label %u flags 0x%x",
1482 : lsp->ile.in_label, lsp->flags);
1483 : }
1484 0 : if (lsp_processq_add(lsp))
1485 : return -1;
1486 : } else {
1487 0 : lsp_check_free(lsp_table, &lsp);
1488 : }
1489 :
1490 : return 0;
1491 : }
1492 :
1493 : /*
1494 : * Uninstall all static NHLFEs for a particular LSP forwarding entry.
1495 : * If no other NHLFEs exist, the entry would be deleted.
1496 : */
1497 0 : static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
1498 : mpls_label_t in_label)
1499 : {
1500 0 : struct hash *lsp_table;
1501 0 : struct zebra_ile tmp_ile;
1502 0 : struct zebra_lsp *lsp;
1503 :
1504 : /* Lookup table. */
1505 0 : lsp_table = zvrf->lsp_table;
1506 0 : if (!lsp_table)
1507 : return -1;
1508 :
1509 : /* If entry is not present, exit. */
1510 0 : tmp_ile.in_label = in_label;
1511 0 : lsp = hash_lookup(lsp_table, &tmp_ile);
1512 0 : if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
1513 : return 0;
1514 :
1515 0 : return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC);
1516 : }
1517 :
1518 0 : static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe)
1519 : {
1520 0 : json_object *json_nhlfe = NULL;
1521 0 : json_object *json_backups = NULL;
1522 0 : json_object *json_label_stack;
1523 0 : struct nexthop *nexthop = nhlfe->nexthop;
1524 0 : int i;
1525 :
1526 0 : json_nhlfe = json_object_new_object();
1527 0 : json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
1528 0 : json_object_int_add(json_nhlfe, "outLabel",
1529 0 : nexthop->nh_label->label[0]);
1530 :
1531 0 : json_label_stack = json_object_new_array();
1532 0 : json_object_object_add(json_nhlfe, "outLabelStack", json_label_stack);
1533 0 : for (i = 0; i < nexthop->nh_label->num_labels; i++)
1534 0 : json_object_array_add(
1535 : json_label_stack,
1536 0 : json_object_new_int(nexthop->nh_label->label[i]));
1537 :
1538 0 : json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
1539 :
1540 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
1541 0 : json_object_boolean_true_add(json_nhlfe, "installed");
1542 :
1543 0 : switch (nexthop->type) {
1544 0 : case NEXTHOP_TYPE_IPV4:
1545 : case NEXTHOP_TYPE_IPV4_IFINDEX:
1546 0 : json_object_string_addf(json_nhlfe, "nexthop", "%pI4",
1547 : &nexthop->gate.ipv4);
1548 0 : break;
1549 0 : case NEXTHOP_TYPE_IPV6:
1550 : case NEXTHOP_TYPE_IPV6_IFINDEX:
1551 0 : json_object_string_addf(json_nhlfe, "nexthop", "%pI6",
1552 : &nexthop->gate.ipv6);
1553 :
1554 0 : if (nexthop->ifindex)
1555 0 : json_object_string_add(json_nhlfe, "interface",
1556 : ifindex2ifname(nexthop->ifindex,
1557 : nexthop->vrf_id));
1558 : break;
1559 0 : case NEXTHOP_TYPE_IFINDEX:
1560 0 : if (nexthop->ifindex)
1561 0 : json_object_string_add(json_nhlfe, "interface",
1562 : ifindex2ifname(nexthop->ifindex,
1563 : nexthop->vrf_id));
1564 : break;
1565 : case NEXTHOP_TYPE_BLACKHOLE:
1566 : break;
1567 : }
1568 :
1569 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
1570 0 : json_backups = json_object_new_array();
1571 0 : for (i = 0; i < nexthop->backup_num; i++) {
1572 0 : json_object_array_add(
1573 : json_backups,
1574 0 : json_object_new_int(nexthop->backup_idx[i]));
1575 : }
1576 :
1577 0 : json_object_object_add(json_nhlfe, "backupIndex",
1578 : json_backups);
1579 : }
1580 :
1581 0 : return json_nhlfe;
1582 : }
1583 :
1584 : /*
1585 : * Print the NHLFE for a LSP forwarding entry.
1586 : */
1587 0 : static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
1588 : const char *indent)
1589 : {
1590 0 : struct nexthop *nexthop;
1591 0 : char buf[MPLS_LABEL_STRLEN];
1592 :
1593 0 : nexthop = nhlfe->nexthop;
1594 0 : if (!nexthop || !nexthop->nh_label) // unexpected
1595 0 : return;
1596 :
1597 0 : vty_out(vty, " type: %s remote label: %s distance: %d\n",
1598 : nhlfe_type2str(nhlfe->type),
1599 0 : mpls_label2str(nexthop->nh_label->num_labels,
1600 0 : nexthop->nh_label->label,
1601 : buf, sizeof(buf), 0),
1602 0 : nhlfe->distance);
1603 :
1604 0 : if (indent)
1605 0 : vty_out(vty, "%s", indent);
1606 :
1607 0 : switch (nexthop->type) {
1608 0 : case NEXTHOP_TYPE_IPV4:
1609 : case NEXTHOP_TYPE_IPV4_IFINDEX:
1610 0 : vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
1611 0 : if (nexthop->ifindex)
1612 0 : vty_out(vty, " dev %s",
1613 : ifindex2ifname(nexthop->ifindex,
1614 : nexthop->vrf_id));
1615 : break;
1616 0 : case NEXTHOP_TYPE_IPV6:
1617 : case NEXTHOP_TYPE_IPV6_IFINDEX:
1618 0 : vty_out(vty, " via %s",
1619 0 : inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
1620 : sizeof(buf)));
1621 0 : if (nexthop->ifindex)
1622 0 : vty_out(vty, " dev %s",
1623 : ifindex2ifname(nexthop->ifindex,
1624 : nexthop->vrf_id));
1625 : break;
1626 0 : case NEXTHOP_TYPE_IFINDEX:
1627 0 : if (nexthop->ifindex)
1628 0 : vty_out(vty, " dev %s",
1629 : ifindex2ifname(nexthop->ifindex,
1630 : nexthop->vrf_id));
1631 : break;
1632 : case NEXTHOP_TYPE_BLACKHOLE:
1633 : break;
1634 : }
1635 0 : vty_out(vty, "%s",
1636 0 : CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP) ? " (backup)"
1637 : : "");
1638 0 : vty_out(vty, "%s",
1639 0 : CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
1640 : : "");
1641 0 : vty_out(vty, "\n");
1642 : }
1643 :
1644 : /*
1645 : * Print an LSP forwarding entry.
1646 : */
1647 0 : static void lsp_print(struct vty *vty, struct zebra_lsp *lsp)
1648 : {
1649 0 : struct zebra_nhlfe *nhlfe, *backup;
1650 0 : int i, j;
1651 :
1652 0 : vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label,
1653 0 : CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)"
1654 : : "");
1655 :
1656 0 : frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1657 0 : nhlfe_print(nhlfe, vty, NULL);
1658 :
1659 0 : if (nhlfe->nexthop == NULL ||
1660 0 : !CHECK_FLAG(nhlfe->nexthop->flags,
1661 : NEXTHOP_FLAG_HAS_BACKUP))
1662 0 : continue;
1663 :
1664 : /* Backup nhlfes: find backups in backup list */
1665 :
1666 0 : for (j = 0; j < nhlfe->nexthop->backup_num; j++) {
1667 0 : i = 0;
1668 0 : backup = NULL;
1669 0 : frr_each(nhlfe_list, &lsp->backup_nhlfe_list, backup) {
1670 0 : if (i == nhlfe->nexthop->backup_idx[j])
1671 : break;
1672 0 : i++;
1673 : }
1674 :
1675 0 : if (backup) {
1676 0 : vty_out(vty, " [backup %d]", i);
1677 0 : nhlfe_print(backup, vty, " ");
1678 : }
1679 : }
1680 : }
1681 0 : }
1682 :
1683 : /*
1684 : * JSON objects for an LSP forwarding entry.
1685 : */
1686 0 : static json_object *lsp_json(struct zebra_lsp *lsp)
1687 : {
1688 0 : struct zebra_nhlfe *nhlfe = NULL;
1689 0 : json_object *json = json_object_new_object();
1690 0 : json_object *json_nhlfe_list = json_object_new_array();
1691 :
1692 0 : json_object_int_add(json, "inLabel", lsp->ile.in_label);
1693 :
1694 0 : if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1695 0 : json_object_boolean_true_add(json, "installed");
1696 :
1697 0 : frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe)
1698 0 : json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1699 :
1700 0 : json_object_object_add(json, "nexthops", json_nhlfe_list);
1701 0 : json_nhlfe_list = NULL;
1702 :
1703 :
1704 0 : frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1705 0 : if (json_nhlfe_list == NULL)
1706 0 : json_nhlfe_list = json_object_new_array();
1707 :
1708 0 : json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1709 : }
1710 :
1711 0 : if (json_nhlfe_list)
1712 0 : json_object_object_add(json, "backupNexthops", json_nhlfe_list);
1713 :
1714 0 : return json;
1715 : }
1716 :
1717 :
1718 : /* Return a sorted linked list of the hash contents */
1719 0 : static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
1720 : {
1721 0 : unsigned int i;
1722 0 : struct hash_bucket *hb;
1723 0 : struct list *sorted_list = list_new();
1724 :
1725 0 : sorted_list->cmp = (int (*)(void *, void *))cmp;
1726 :
1727 0 : for (i = 0; i < hash->size; i++)
1728 0 : for (hb = hash->index[i]; hb; hb = hb->next)
1729 0 : listnode_add_sort(sorted_list, hb->data);
1730 :
1731 0 : return sorted_list;
1732 : }
1733 :
1734 : /*
1735 : * Compare two LSPs based on their label values.
1736 : */
1737 0 : static int lsp_cmp(const struct zebra_lsp *lsp1, const struct zebra_lsp *lsp2)
1738 : {
1739 0 : if (lsp1->ile.in_label < lsp2->ile.in_label)
1740 : return -1;
1741 :
1742 0 : if (lsp1->ile.in_label > lsp2->ile.in_label)
1743 0 : return 1;
1744 :
1745 : return 0;
1746 : }
1747 :
1748 : /*
1749 : * Initialize work queue for processing changed LSPs.
1750 : */
1751 0 : static void mpls_processq_init(void)
1752 : {
1753 0 : zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
1754 :
1755 0 : zrouter.lsp_process_q->spec.workfunc = &lsp_process;
1756 0 : zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
1757 0 : zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
1758 0 : zrouter.lsp_process_q->spec.max_retries = 0;
1759 0 : zrouter.lsp_process_q->spec.hold = 10;
1760 0 : }
1761 :
1762 :
1763 : /*
1764 : * Process LSP update results from zebra dataplane.
1765 : */
1766 0 : void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
1767 : {
1768 0 : struct zebra_vrf *zvrf;
1769 0 : mpls_label_t label;
1770 0 : struct zebra_ile tmp_ile;
1771 0 : struct hash *lsp_table;
1772 0 : struct zebra_lsp *lsp;
1773 0 : struct zebra_nhlfe *nhlfe;
1774 0 : struct nexthop *nexthop;
1775 0 : enum dplane_op_e op;
1776 0 : enum zebra_dplane_result status;
1777 0 : enum zebra_sr_policy_update_label_mode update_mode;
1778 :
1779 0 : op = dplane_ctx_get_op(ctx);
1780 0 : status = dplane_ctx_get_status(ctx);
1781 :
1782 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1783 0 : zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
1784 : ctx, dplane_op2str(op),
1785 : dplane_ctx_get_in_label(ctx),
1786 : dplane_res2str(status));
1787 :
1788 0 : label = dplane_ctx_get_in_label(ctx);
1789 :
1790 0 : switch (op) {
1791 0 : case DPLANE_OP_LSP_INSTALL:
1792 : case DPLANE_OP_LSP_UPDATE:
1793 : /* Look for zebra LSP object */
1794 0 : zvrf = vrf_info_lookup(VRF_DEFAULT);
1795 0 : if (zvrf == NULL)
1796 : break;
1797 :
1798 0 : lsp_table = zvrf->lsp_table;
1799 :
1800 0 : tmp_ile.in_label = label;
1801 0 : lsp = hash_lookup(lsp_table, &tmp_ile);
1802 0 : if (lsp == NULL) {
1803 0 : if (IS_ZEBRA_DEBUG_DPLANE)
1804 0 : zlog_debug("LSP ctx %p: in-label %u not found",
1805 : ctx, dplane_ctx_get_in_label(ctx));
1806 : break;
1807 : }
1808 :
1809 : /* TODO -- Confirm that this result is still 'current' */
1810 :
1811 0 : if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
1812 0 : UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1813 0 : clear_nhlfe_installed(lsp);
1814 0 : flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1815 : "LSP Install Failure: in-label %u",
1816 : lsp->ile.in_label);
1817 0 : break;
1818 : }
1819 :
1820 : /* Update zebra object */
1821 0 : SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1822 0 : frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1823 0 : nexthop = nhlfe->nexthop;
1824 0 : if (!nexthop)
1825 0 : continue;
1826 :
1827 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) &&
1828 0 : CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
1829 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1830 0 : SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1831 : }
1832 : }
1833 :
1834 0 : update_mode = (op == DPLANE_OP_LSP_INSTALL)
1835 : ? ZEBRA_SR_POLICY_LABEL_CREATED
1836 0 : : ZEBRA_SR_POLICY_LABEL_UPDATED;
1837 0 : zebra_sr_policy_label_update(label, update_mode);
1838 0 : break;
1839 :
1840 0 : case DPLANE_OP_LSP_DELETE:
1841 0 : if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
1842 0 : flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
1843 : "LSP Deletion Failure: in-label %u",
1844 : dplane_ctx_get_in_label(ctx));
1845 0 : break;
1846 : }
1847 0 : zebra_sr_policy_label_update(label,
1848 : ZEBRA_SR_POLICY_LABEL_REMOVED);
1849 0 : break;
1850 :
1851 : case DPLANE_OP_LSP_NOTIFY:
1852 : case DPLANE_OP_NONE:
1853 : case DPLANE_OP_ROUTE_INSTALL:
1854 : case DPLANE_OP_ROUTE_UPDATE:
1855 : case DPLANE_OP_ROUTE_DELETE:
1856 : case DPLANE_OP_ROUTE_NOTIFY:
1857 : case DPLANE_OP_NH_INSTALL:
1858 : case DPLANE_OP_NH_UPDATE:
1859 : case DPLANE_OP_NH_DELETE:
1860 : case DPLANE_OP_PW_INSTALL:
1861 : case DPLANE_OP_PW_UNINSTALL:
1862 : case DPLANE_OP_SYS_ROUTE_ADD:
1863 : case DPLANE_OP_SYS_ROUTE_DELETE:
1864 : case DPLANE_OP_ADDR_INSTALL:
1865 : case DPLANE_OP_ADDR_UNINSTALL:
1866 : case DPLANE_OP_MAC_INSTALL:
1867 : case DPLANE_OP_MAC_DELETE:
1868 : case DPLANE_OP_NEIGH_INSTALL:
1869 : case DPLANE_OP_NEIGH_UPDATE:
1870 : case DPLANE_OP_NEIGH_DELETE:
1871 : case DPLANE_OP_VTEP_ADD:
1872 : case DPLANE_OP_VTEP_DELETE:
1873 : case DPLANE_OP_RULE_ADD:
1874 : case DPLANE_OP_RULE_DELETE:
1875 : case DPLANE_OP_RULE_UPDATE:
1876 : case DPLANE_OP_NEIGH_DISCOVER:
1877 : case DPLANE_OP_BR_PORT_UPDATE:
1878 : case DPLANE_OP_IPTABLE_ADD:
1879 : case DPLANE_OP_IPTABLE_DELETE:
1880 : case DPLANE_OP_IPSET_ADD:
1881 : case DPLANE_OP_IPSET_DELETE:
1882 : case DPLANE_OP_IPSET_ENTRY_ADD:
1883 : case DPLANE_OP_IPSET_ENTRY_DELETE:
1884 : case DPLANE_OP_NEIGH_IP_INSTALL:
1885 : case DPLANE_OP_NEIGH_IP_DELETE:
1886 : case DPLANE_OP_NEIGH_TABLE_UPDATE:
1887 : case DPLANE_OP_GRE_SET:
1888 : case DPLANE_OP_INTF_ADDR_ADD:
1889 : case DPLANE_OP_INTF_ADDR_DEL:
1890 : case DPLANE_OP_INTF_NETCONFIG:
1891 : case DPLANE_OP_INTF_INSTALL:
1892 : case DPLANE_OP_INTF_UPDATE:
1893 : case DPLANE_OP_INTF_DELETE:
1894 : case DPLANE_OP_TC_QDISC_INSTALL:
1895 : case DPLANE_OP_TC_QDISC_UNINSTALL:
1896 : case DPLANE_OP_TC_CLASS_ADD:
1897 : case DPLANE_OP_TC_CLASS_DELETE:
1898 : case DPLANE_OP_TC_CLASS_UPDATE:
1899 : case DPLANE_OP_TC_FILTER_ADD:
1900 : case DPLANE_OP_TC_FILTER_DELETE:
1901 : case DPLANE_OP_TC_FILTER_UPDATE:
1902 : break;
1903 :
1904 : } /* Switch */
1905 0 : }
1906 :
1907 : /*
1908 : * Process LSP installation info from two sets of nhlfes: a set from
1909 : * a dplane notification, and a set from the zebra LSP object. Update
1910 : * counters of installed nexthops, and return whether the LSP has changed.
1911 : */
1912 0 : static bool compare_notif_nhlfes(const struct nhlfe_list_head *ctx_head,
1913 : struct nhlfe_list_head *nhlfe_head,
1914 : int *start_counter, int *end_counter)
1915 : {
1916 0 : struct zebra_nhlfe *nhlfe;
1917 0 : const struct zebra_nhlfe *ctx_nhlfe;
1918 0 : struct nexthop *nexthop;
1919 0 : const struct nexthop *ctx_nexthop;
1920 0 : int start_count = 0, end_count = 0;
1921 0 : bool changed_p = false;
1922 0 : bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1923 :
1924 0 : frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
1925 0 : char buf[NEXTHOP_STRLEN];
1926 :
1927 0 : nexthop = nhlfe->nexthop;
1928 0 : if (!nexthop)
1929 0 : continue;
1930 :
1931 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
1932 0 : start_count++;
1933 :
1934 0 : ctx_nhlfe = NULL;
1935 0 : ctx_nexthop = NULL;
1936 0 : frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
1937 0 : ctx_nexthop = ctx_nhlfe->nexthop;
1938 0 : if (!ctx_nexthop)
1939 0 : continue;
1940 :
1941 0 : if ((ctx_nexthop->type == nexthop->type) &&
1942 0 : nexthop_same(ctx_nexthop, nexthop)) {
1943 : /* Matched */
1944 : break;
1945 : }
1946 : }
1947 :
1948 0 : if (is_debug)
1949 0 : nexthop2str(nexthop, buf, sizeof(buf));
1950 :
1951 0 : if (ctx_nhlfe && ctx_nexthop) {
1952 0 : if (is_debug) {
1953 0 : const char *tstr = "";
1954 :
1955 0 : if (!CHECK_FLAG(ctx_nhlfe->flags,
1956 : NHLFE_FLAG_INSTALLED))
1957 0 : tstr = "not ";
1958 :
1959 0 : zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
1960 : buf, tstr);
1961 : }
1962 :
1963 : /* Test zebra nhlfe install state */
1964 0 : if (CHECK_FLAG(ctx_nhlfe->flags,
1965 : NHLFE_FLAG_INSTALLED)) {
1966 :
1967 0 : if (!CHECK_FLAG(nhlfe->flags,
1968 : NHLFE_FLAG_INSTALLED))
1969 0 : changed_p = true;
1970 :
1971 : /* Update counter */
1972 0 : end_count++;
1973 : } else {
1974 :
1975 0 : if (CHECK_FLAG(nhlfe->flags,
1976 : NHLFE_FLAG_INSTALLED))
1977 0 : changed_p = true;
1978 : }
1979 :
1980 : } else {
1981 : /* Not mentioned in lfib set -> uninstalled */
1982 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ||
1983 0 : CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ||
1984 : CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
1985 0 : changed_p = true;
1986 : }
1987 :
1988 0 : if (is_debug)
1989 0 : zlog_debug("LSP dplane notif: no match, nh %s",
1990 : buf);
1991 : }
1992 : }
1993 :
1994 0 : if (start_counter)
1995 0 : *start_counter += start_count;
1996 0 : if (end_counter)
1997 0 : *end_counter += end_count;
1998 :
1999 0 : return changed_p;
2000 : }
2001 :
2002 : /*
2003 : * Update an lsp nhlfe list from a dplane context, typically an async
2004 : * notification context. Update the LSP list to match the installed
2005 : * status from the context's list.
2006 : */
2007 0 : static int update_nhlfes_from_ctx(struct nhlfe_list_head *nhlfe_head,
2008 : const struct nhlfe_list_head *ctx_head)
2009 : {
2010 0 : int ret = 0;
2011 0 : struct zebra_nhlfe *nhlfe;
2012 0 : const struct zebra_nhlfe *ctx_nhlfe;
2013 0 : struct nexthop *nexthop;
2014 0 : const struct nexthop *ctx_nexthop;
2015 0 : bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
2016 :
2017 0 : frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
2018 0 : char buf[NEXTHOP_STRLEN];
2019 :
2020 0 : nexthop = nhlfe->nexthop;
2021 0 : if (!nexthop)
2022 0 : continue;
2023 :
2024 0 : ctx_nhlfe = NULL;
2025 0 : ctx_nexthop = NULL;
2026 0 : frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
2027 0 : ctx_nexthop = ctx_nhlfe->nexthop;
2028 0 : if (!ctx_nexthop)
2029 0 : continue;
2030 :
2031 0 : if ((ctx_nexthop->type == nexthop->type) &&
2032 0 : nexthop_same(ctx_nexthop, nexthop)) {
2033 : /* Matched */
2034 : break;
2035 : }
2036 : }
2037 :
2038 0 : if (is_debug)
2039 0 : nexthop2str(nexthop, buf, sizeof(buf));
2040 :
2041 0 : if (ctx_nhlfe && ctx_nexthop) {
2042 :
2043 : /* Bring zebra nhlfe install state into sync */
2044 0 : if (CHECK_FLAG(ctx_nhlfe->flags,
2045 : NHLFE_FLAG_INSTALLED)) {
2046 0 : if (is_debug)
2047 0 : zlog_debug("%s: matched lsp nhlfe %s (installed)",
2048 : __func__, buf);
2049 :
2050 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2051 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2052 :
2053 : } else {
2054 0 : if (is_debug)
2055 0 : zlog_debug("%s: matched lsp nhlfe %s (not installed)",
2056 : __func__, buf);
2057 :
2058 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2059 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2060 : }
2061 :
2062 0 : if (CHECK_FLAG(ctx_nhlfe->nexthop->flags,
2063 : NEXTHOP_FLAG_FIB)) {
2064 0 : SET_FLAG(nhlfe->nexthop->flags,
2065 : NEXTHOP_FLAG_ACTIVE);
2066 0 : SET_FLAG(nhlfe->nexthop->flags,
2067 : NEXTHOP_FLAG_FIB);
2068 : } else {
2069 0 : UNSET_FLAG(nhlfe->nexthop->flags,
2070 : NEXTHOP_FLAG_ACTIVE);
2071 0 : UNSET_FLAG(nhlfe->nexthop->flags,
2072 : NEXTHOP_FLAG_FIB);
2073 : }
2074 :
2075 : } else {
2076 : /* Not mentioned in lfib set -> uninstalled */
2077 0 : if (is_debug)
2078 0 : zlog_debug("%s: no match for lsp nhlfe %s",
2079 : __func__, buf);
2080 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2081 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2082 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
2083 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2084 : }
2085 : }
2086 :
2087 0 : return ret;
2088 : }
2089 :
2090 : /*
2091 : * Process async dplane notifications.
2092 : */
2093 0 : void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
2094 : {
2095 0 : struct zebra_vrf *zvrf;
2096 0 : struct zebra_ile tmp_ile;
2097 0 : struct hash *lsp_table;
2098 0 : struct zebra_lsp *lsp;
2099 0 : const struct nhlfe_list_head *ctx_list;
2100 0 : int start_count = 0, end_count = 0; /* Installed counts */
2101 0 : bool changed_p = false;
2102 0 : bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
2103 0 : enum zebra_sr_policy_update_label_mode update_mode;
2104 :
2105 0 : if (is_debug)
2106 0 : zlog_debug("LSP dplane notif, in-label %u",
2107 : dplane_ctx_get_in_label(ctx));
2108 :
2109 : /* Look for zebra LSP object */
2110 0 : zvrf = vrf_info_lookup(VRF_DEFAULT);
2111 0 : if (zvrf == NULL)
2112 0 : return;
2113 :
2114 0 : lsp_table = zvrf->lsp_table;
2115 :
2116 0 : tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
2117 0 : lsp = hash_lookup(lsp_table, &tmp_ile);
2118 0 : if (lsp == NULL) {
2119 0 : if (is_debug)
2120 0 : zlog_debug("dplane LSP notif: in-label %u not found",
2121 : dplane_ctx_get_in_label(ctx));
2122 0 : return;
2123 : }
2124 :
2125 : /*
2126 : * The dataplane/forwarding plane is notifying zebra about the state
2127 : * of the nexthops associated with this LSP. First, we take a
2128 : * pre-scan pass to determine whether the LSP has transitioned
2129 : * from installed -> uninstalled. In that case, we need to have
2130 : * the existing state of the LSP objects available before making
2131 : * any changes.
2132 : */
2133 0 : ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2134 :
2135 0 : changed_p = compare_notif_nhlfes(ctx_list, &lsp->nhlfe_list,
2136 : &start_count, &end_count);
2137 :
2138 0 : if (is_debug)
2139 0 : zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
2140 : start_count, end_count,
2141 : changed_p ? ", changed" : "");
2142 :
2143 0 : ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2144 :
2145 0 : if (compare_notif_nhlfes(ctx_list, &lsp->backup_nhlfe_list,
2146 : &start_count, &end_count))
2147 : /* Avoid accidentally setting back to 'false' */
2148 0 : changed_p = true;
2149 :
2150 0 : if (is_debug)
2151 0 : zlog_debug("LSP dplane notif: lfib backups, start_count %d, end_count %d%s",
2152 : start_count, end_count,
2153 : changed_p ? ", changed" : "");
2154 :
2155 : /*
2156 : * Has the LSP become uninstalled? We need the existing state of the
2157 : * nexthops/nhlfes at this point so we know what to delete.
2158 : */
2159 0 : if (start_count > 0 && end_count == 0) {
2160 : /* Inform other lfibs */
2161 0 : dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
2162 : }
2163 :
2164 : /*
2165 : * Now we take a second pass and bring the zebra
2166 : * nexthop state into sync with the forwarding-plane state.
2167 : */
2168 0 : ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2169 0 : update_nhlfes_from_ctx(&lsp->nhlfe_list, ctx_list);
2170 :
2171 0 : ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2172 0 : update_nhlfes_from_ctx(&lsp->backup_nhlfe_list, ctx_list);
2173 :
2174 0 : if (end_count > 0) {
2175 0 : SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2176 :
2177 : /* SR-TE update too */
2178 0 : if (start_count == 0)
2179 : update_mode = ZEBRA_SR_POLICY_LABEL_CREATED;
2180 : else
2181 0 : update_mode = ZEBRA_SR_POLICY_LABEL_UPDATED;
2182 0 : zebra_sr_policy_label_update(lsp->ile.in_label, update_mode);
2183 :
2184 0 : if (changed_p)
2185 0 : dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
2186 :
2187 : } else {
2188 : /* SR-TE update too */
2189 0 : zebra_sr_policy_label_update(lsp->ile.in_label,
2190 : ZEBRA_SR_POLICY_LABEL_REMOVED);
2191 :
2192 0 : UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2193 0 : clear_nhlfe_installed(lsp);
2194 : }
2195 : }
2196 :
2197 : /*
2198 : * Install dynamic LSP entry.
2199 : */
2200 0 : int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
2201 : struct route_entry *re)
2202 : {
2203 0 : struct route_table *table;
2204 0 : struct zebra_fec *fec;
2205 :
2206 0 : table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2207 0 : if (!table)
2208 : return -1;
2209 :
2210 : /* See if there is a configured label binding for this FEC. */
2211 0 : fec = fec_find(table, &rn->p);
2212 0 : if (!fec || fec->label == MPLS_INVALID_LABEL)
2213 : return 0;
2214 :
2215 : /* We cannot install a label forwarding entry if local label is the
2216 : * implicit-null label.
2217 : */
2218 0 : if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
2219 : return 0;
2220 :
2221 0 : if (lsp_install(zvrf, fec->label, rn, re))
2222 : return -1;
2223 :
2224 : return 0;
2225 : }
2226 :
2227 : /*
2228 : * Uninstall dynamic LSP entry, if any.
2229 : */
2230 0 : int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
2231 : struct route_entry *re)
2232 : {
2233 0 : struct route_table *table;
2234 0 : struct zebra_fec *fec;
2235 :
2236 0 : table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2237 0 : if (!table)
2238 : return -1;
2239 :
2240 : /* See if there is a configured label binding for this FEC. */
2241 0 : fec = fec_find(table, &rn->p);
2242 0 : if (!fec || fec->label == MPLS_INVALID_LABEL)
2243 : return 0;
2244 :
2245 : /* Uninstall always removes all dynamic NHLFEs. */
2246 0 : return lsp_uninstall(zvrf, fec->label);
2247 : }
2248 :
2249 : /*
2250 : * Add an NHLFE to an LSP, return the newly-added object. This path only changes
2251 : * the LSP object - nothing is scheduled for processing, for example.
2252 : */
2253 : struct zebra_nhlfe *
2254 0 : zebra_mpls_lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
2255 : enum nexthop_types_t gtype, const union g_addr *gate,
2256 : ifindex_t ifindex, uint8_t num_labels,
2257 : const mpls_label_t *out_labels)
2258 : {
2259 : /* Just a public pass-through to the internal implementation */
2260 0 : return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
2261 : out_labels, false /*backup*/);
2262 : }
2263 :
2264 : /*
2265 : * Add a backup NHLFE to an LSP, return the newly-added object.
2266 : * This path only changes the LSP object - nothing is scheduled for
2267 : * processing, for example.
2268 : */
2269 0 : struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nhlfe(
2270 : struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
2271 : enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex,
2272 : uint8_t num_labels, const mpls_label_t *out_labels)
2273 : {
2274 : /* Just a public pass-through to the internal implementation */
2275 0 : return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
2276 : out_labels, true);
2277 : }
2278 :
2279 : /*
2280 : * Add an NHLFE to an LSP based on a nexthop; return the newly-added object
2281 : */
2282 0 : struct zebra_nhlfe *zebra_mpls_lsp_add_nh(struct zebra_lsp *lsp,
2283 : enum lsp_types_t lsp_type,
2284 : const struct nexthop *nh)
2285 : {
2286 0 : struct zebra_nhlfe *nhlfe;
2287 :
2288 0 : if (nh->nh_label == NULL || nh->nh_label->num_labels == 0)
2289 : return NULL;
2290 :
2291 0 : nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, nh->ifindex,
2292 0 : nh->nh_label->num_labels, nh->nh_label->label,
2293 : false /*backup*/);
2294 :
2295 0 : return nhlfe;
2296 : }
2297 :
2298 : /*
2299 : * Add a backup NHLFE to an LSP based on a nexthop;
2300 : * return the newly-added object.
2301 : */
2302 0 : struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nh(struct zebra_lsp *lsp,
2303 : enum lsp_types_t lsp_type,
2304 : const struct nexthop *nh)
2305 : {
2306 0 : struct zebra_nhlfe *nhlfe;
2307 :
2308 0 : if (nh->nh_label == NULL || nh->nh_label->num_labels == 0)
2309 : return NULL;
2310 :
2311 0 : nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate,
2312 0 : nh->ifindex, nh->nh_label->num_labels,
2313 0 : nh->nh_label->label, true);
2314 :
2315 0 : return nhlfe;
2316 : }
2317 :
2318 : /*
2319 : * Free an allocated NHLFE
2320 : */
2321 0 : void zebra_mpls_nhlfe_free(struct zebra_nhlfe *nhlfe)
2322 : {
2323 : /* Just a pass-through to the internal implementation */
2324 0 : nhlfe_free(nhlfe);
2325 0 : }
2326 :
2327 : /*
2328 : * Registration from a client for the label binding for a FEC. If a binding
2329 : * already exists, it is informed to the client.
2330 : * NOTE: If there is a manually configured label binding, that is used.
2331 : * Otherwise, if a label index is specified, it means we have to allocate the
2332 : * label from a locally configured label block (SRGB), if one exists and index
2333 : * is acceptable. If no label index then just register the specified label.
2334 : * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
2335 : * by the calling function. Register requests with both will be rejected.
2336 : */
2337 0 : int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
2338 : uint32_t label, uint32_t label_index,
2339 : struct zserv *client)
2340 : {
2341 0 : struct route_table *table;
2342 0 : struct zebra_fec *fec;
2343 0 : bool new_client;
2344 0 : bool label_change = false;
2345 0 : uint32_t old_label;
2346 0 : bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
2347 0 : bool is_configured_fec = false; /* indicate statically configured FEC */
2348 :
2349 0 : table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2350 0 : if (!table)
2351 : return -1;
2352 :
2353 0 : if (label != MPLS_INVALID_LABEL && have_label_index) {
2354 0 : flog_err(
2355 : EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
2356 : "Rejecting FEC register for %pFX with both label %u and Label Index %u specified, client %s",
2357 : p, label, label_index,
2358 : zebra_route_string(client->proto));
2359 0 : return -1;
2360 : }
2361 :
2362 : /* Locate FEC */
2363 0 : fec = fec_find(table, p);
2364 0 : if (!fec) {
2365 0 : fec = fec_add(table, p, label, 0, label_index);
2366 0 : if (!fec) {
2367 0 : flog_err(
2368 : EC_ZEBRA_FEC_ADD_FAILED,
2369 : "Failed to add FEC %pFX upon register, client %s",
2370 : p, zebra_route_string(client->proto));
2371 0 : return -1;
2372 : }
2373 :
2374 : old_label = MPLS_INVALID_LABEL;
2375 : new_client = true;
2376 : } else {
2377 : /* Check if the FEC has been statically defined in the config */
2378 0 : is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
2379 : /* Client may register same FEC with different label index. */
2380 0 : new_client =
2381 0 : (listnode_lookup(fec->client_list, client) == NULL);
2382 0 : if (!new_client && fec->label_index == label_index
2383 0 : && fec->label == label)
2384 : /* Duplicate register */
2385 : return 0;
2386 :
2387 : /* Save current label, update the FEC */
2388 0 : old_label = fec->label;
2389 0 : fec->label_index = label_index;
2390 : }
2391 :
2392 0 : if (new_client)
2393 0 : listnode_add(fec->client_list, client);
2394 :
2395 0 : if (IS_ZEBRA_DEBUG_MPLS)
2396 0 : zlog_debug("FEC %pFX label%s %u %s by client %s%s", p,
2397 : have_label_index ? " index" : "",
2398 : have_label_index ? label_index : label,
2399 : new_client ? "registered" : "updated",
2400 : zebra_route_string(client->proto),
2401 : is_configured_fec
2402 : ? ", but using statically configured label"
2403 : : "");
2404 :
2405 : /* If not a statically configured FEC, derive the local label
2406 : * from label index or use the provided label
2407 : */
2408 0 : if (!is_configured_fec) {
2409 0 : if (have_label_index)
2410 0 : fec_derive_label_from_index(zvrf, fec);
2411 : else
2412 0 : fec->label = label;
2413 :
2414 : /* If no label change, exit. */
2415 0 : if (fec->label == old_label)
2416 : return 0;
2417 :
2418 : label_change = true;
2419 : }
2420 :
2421 : /* If new client or label change, update client and install or uninstall
2422 : * label forwarding entry as needed.
2423 : */
2424 : /* Inform client of label, if needed. */
2425 0 : if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
2426 0 : if (IS_ZEBRA_DEBUG_MPLS)
2427 0 : zlog_debug("Update client label %u", fec->label);
2428 0 : fec_send(fec, client);
2429 : }
2430 :
2431 0 : if (new_client || label_change)
2432 0 : return fec_change_update_lsp(zvrf, fec, old_label);
2433 :
2434 : return 0;
2435 : }
2436 :
2437 : /*
2438 : * Deregistration from a client for the label binding for a FEC. The FEC
2439 : * itself is deleted if no other registered clients exist and there is no
2440 : * label bound to the FEC.
2441 : */
2442 0 : int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
2443 : struct zserv *client)
2444 : {
2445 0 : struct route_table *table;
2446 0 : struct zebra_fec *fec;
2447 :
2448 0 : table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2449 0 : if (!table)
2450 : return -1;
2451 :
2452 0 : fec = fec_find(table, p);
2453 0 : if (!fec) {
2454 0 : flog_err(EC_ZEBRA_FEC_RM_FAILED,
2455 : "Failed to find FEC %pFX upon unregister, client %s",
2456 : p, zebra_route_string(client->proto));
2457 0 : return -1;
2458 : }
2459 :
2460 0 : listnode_delete(fec->client_list, client);
2461 :
2462 0 : if (IS_ZEBRA_DEBUG_MPLS)
2463 0 : zlog_debug("FEC %pFX unregistered by client %s", p,
2464 : zebra_route_string(client->proto));
2465 :
2466 : /* If not a configured entry, delete the FEC if no other clients. Before
2467 : * deleting, see if any LSP needs to be uninstalled.
2468 : */
2469 0 : if (!(fec->flags & FEC_FLAG_CONFIGURED)
2470 0 : && list_isempty(fec->client_list)) {
2471 0 : mpls_label_t old_label = fec->label;
2472 0 : fec->label = MPLS_INVALID_LABEL; /* reset */
2473 0 : fec_change_update_lsp(zvrf, fec, old_label);
2474 0 : fec_del(fec);
2475 : }
2476 :
2477 : return 0;
2478 : }
2479 :
2480 : /*
2481 : * Cleanup any FECs registered by this client.
2482 : */
2483 0 : static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
2484 : {
2485 0 : struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
2486 0 : struct route_node *rn;
2487 0 : struct zebra_fec *fec;
2488 0 : struct listnode *node;
2489 0 : struct zserv *fec_client;
2490 0 : int af;
2491 :
2492 0 : for (af = AFI_IP; af < AFI_MAX; af++) {
2493 0 : if (zvrf->fec_table[af] == NULL)
2494 0 : continue;
2495 :
2496 0 : for (rn = route_top(zvrf->fec_table[af]); rn;
2497 0 : rn = route_next(rn)) {
2498 0 : fec = rn->info;
2499 0 : if (!fec || list_isempty(fec->client_list))
2500 0 : continue;
2501 :
2502 0 : for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
2503 : fec_client)) {
2504 0 : if (fec_client == client) {
2505 0 : listnode_delete(fec->client_list,
2506 : fec_client);
2507 0 : if (!(fec->flags & FEC_FLAG_CONFIGURED)
2508 0 : && list_isempty(fec->client_list))
2509 0 : fec_del(fec);
2510 : break;
2511 : }
2512 : }
2513 : }
2514 : }
2515 :
2516 0 : return 0;
2517 : }
2518 :
2519 : struct lsp_uninstall_args {
2520 : struct hash *lsp_table;
2521 : enum lsp_types_t type;
2522 : };
2523 :
2524 : /*
2525 : * Cleanup MPLS labels registered by this client.
2526 : */
2527 0 : static int zebra_mpls_cleanup_zclient_labels(struct zserv *client)
2528 : {
2529 0 : struct vrf *vrf;
2530 0 : struct zebra_vrf *zvrf;
2531 :
2532 0 : RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
2533 0 : struct lsp_uninstall_args args;
2534 :
2535 0 : zvrf = vrf->info;
2536 0 : if (!zvrf)
2537 0 : continue;
2538 :
2539 : /* Cleanup LSPs. */
2540 0 : args.lsp_table = zvrf->lsp_table;
2541 0 : args.type = lsp_type_from_re_type(client->proto);
2542 0 : hash_iterate(zvrf->lsp_table, mpls_lsp_uninstall_all_type,
2543 : &args);
2544 :
2545 : /* Cleanup FTNs. */
2546 0 : mpls_ftn_uninstall_all(zvrf, AFI_IP,
2547 0 : lsp_type_from_re_type(client->proto));
2548 0 : mpls_ftn_uninstall_all(zvrf, AFI_IP6,
2549 0 : lsp_type_from_re_type(client->proto));
2550 : }
2551 :
2552 0 : return 0;
2553 : }
2554 :
2555 : /*
2556 : * Return FEC (if any) to which this label is bound.
2557 : * Note: Only works for per-prefix binding and when the label is not
2558 : * implicit-null.
2559 : * TODO: Currently walks entire table, can optimize later with another
2560 : * hash..
2561 : */
2562 0 : struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
2563 : mpls_label_t label)
2564 : {
2565 0 : struct route_node *rn;
2566 0 : struct zebra_fec *fec;
2567 0 : int af;
2568 :
2569 0 : for (af = AFI_IP; af < AFI_MAX; af++) {
2570 0 : if (zvrf->fec_table[af] == NULL)
2571 0 : continue;
2572 :
2573 0 : for (rn = route_top(zvrf->fec_table[af]); rn;
2574 0 : rn = route_next(rn)) {
2575 0 : if (!rn->info)
2576 0 : continue;
2577 0 : fec = rn->info;
2578 0 : if (fec->label == label)
2579 0 : return fec;
2580 : }
2581 : }
2582 :
2583 : return NULL;
2584 : }
2585 :
2586 : /*
2587 : * Inform if specified label is currently bound to a FEC or not.
2588 : */
2589 0 : int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
2590 : {
2591 0 : return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
2592 : }
2593 :
2594 : /*
2595 : * Add static FEC to label binding. If there are clients registered for this
2596 : * FEC, notify them. If there are labeled routes for this FEC, install the
2597 : * label forwarding entry.
2598 : */
2599 0 : int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
2600 : mpls_label_t in_label)
2601 : {
2602 0 : struct route_table *table;
2603 0 : struct zebra_fec *fec;
2604 0 : mpls_label_t old_label;
2605 0 : int ret = 0;
2606 :
2607 0 : table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2608 0 : if (!table)
2609 : return -1;
2610 :
2611 : /* Update existing FEC or create a new one. */
2612 0 : fec = fec_find(table, p);
2613 0 : if (!fec) {
2614 0 : fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
2615 : MPLS_INVALID_LABEL_INDEX);
2616 0 : if (!fec) {
2617 0 : flog_err(EC_ZEBRA_FEC_ADD_FAILED,
2618 : "Failed to add FEC %pFX upon config", p);
2619 0 : return -1;
2620 : }
2621 :
2622 0 : if (IS_ZEBRA_DEBUG_MPLS)
2623 0 : zlog_debug("Add fec %pFX label %u", p, in_label);
2624 : } else {
2625 0 : fec->flags |= FEC_FLAG_CONFIGURED;
2626 0 : if (fec->label == in_label)
2627 : /* Duplicate config */
2628 : return 0;
2629 :
2630 : /* Label change, update clients. */
2631 0 : old_label = fec->label;
2632 0 : if (IS_ZEBRA_DEBUG_MPLS)
2633 0 : zlog_debug("Update fec %pFX new label %u", p, in_label);
2634 :
2635 0 : fec->label = in_label;
2636 0 : fec_update_clients(fec);
2637 :
2638 : /* Update label forwarding entries appropriately */
2639 0 : ret = fec_change_update_lsp(zvrf, fec, old_label);
2640 : }
2641 :
2642 : return ret;
2643 : }
2644 :
2645 : /*
2646 : * Remove static FEC to label binding. If there are no clients registered
2647 : * for this FEC, delete the FEC; else notify clients
2648 : * Note: Upon delete of static binding, if label index exists for this FEC,
2649 : * client may need to be updated with derived label.
2650 : */
2651 0 : int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
2652 : {
2653 0 : struct route_table *table;
2654 0 : struct zebra_fec *fec;
2655 0 : mpls_label_t old_label;
2656 :
2657 0 : table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2658 0 : if (!table)
2659 : return -1;
2660 :
2661 0 : fec = fec_find(table, p);
2662 0 : if (!fec) {
2663 0 : flog_err(EC_ZEBRA_FEC_RM_FAILED,
2664 : "Failed to find FEC %pFX upon delete", p);
2665 0 : return -1;
2666 : }
2667 :
2668 0 : if (IS_ZEBRA_DEBUG_MPLS) {
2669 0 : zlog_debug("Delete fec %pFX label %u label index %u", p,
2670 : fec->label, fec->label_index);
2671 : }
2672 :
2673 0 : old_label = fec->label;
2674 0 : fec->flags &= ~FEC_FLAG_CONFIGURED;
2675 0 : fec->label = MPLS_INVALID_LABEL;
2676 :
2677 : /* If no client exists, just delete the FEC. */
2678 0 : if (list_isempty(fec->client_list)) {
2679 0 : fec_del(fec);
2680 0 : return 0;
2681 : }
2682 :
2683 : /* Derive the local label (from label index) or reset it. */
2684 0 : fec_derive_label_from_index(zvrf, fec);
2685 :
2686 : /* If there is a label change, update clients. */
2687 0 : if (fec->label == old_label)
2688 : return 0;
2689 0 : fec_update_clients(fec);
2690 :
2691 : /* Update label forwarding entries appropriately */
2692 0 : return fec_change_update_lsp(zvrf, fec, old_label);
2693 : }
2694 :
2695 : /*
2696 : * Display MPLS FEC to label binding configuration (VTY command handler).
2697 : */
2698 0 : int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
2699 : {
2700 0 : struct route_node *rn;
2701 0 : int af;
2702 0 : struct zebra_fec *fec;
2703 0 : int write = 0;
2704 :
2705 0 : for (af = AFI_IP; af < AFI_MAX; af++) {
2706 0 : if (zvrf->fec_table[af] == NULL)
2707 0 : continue;
2708 :
2709 0 : for (rn = route_top(zvrf->fec_table[af]); rn;
2710 0 : rn = route_next(rn)) {
2711 0 : if (!rn->info)
2712 0 : continue;
2713 :
2714 0 : char lstr[BUFSIZ];
2715 0 : fec = rn->info;
2716 :
2717 0 : if (!(fec->flags & FEC_FLAG_CONFIGURED))
2718 0 : continue;
2719 :
2720 0 : write = 1;
2721 0 : vty_out(vty, "mpls label bind %pFX %s\n", &rn->p,
2722 : label2str(fec->label, lstr, BUFSIZ));
2723 : }
2724 : }
2725 :
2726 0 : return write;
2727 : }
2728 :
2729 : /*
2730 : * Display MPLS FEC to label binding (VTY command handler).
2731 : */
2732 0 : void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
2733 : {
2734 0 : struct route_node *rn;
2735 0 : int af;
2736 :
2737 0 : for (af = AFI_IP; af < AFI_MAX; af++) {
2738 0 : if (zvrf->fec_table[af] == NULL)
2739 0 : continue;
2740 :
2741 0 : for (rn = route_top(zvrf->fec_table[af]); rn;
2742 0 : rn = route_next(rn)) {
2743 0 : if (!rn->info)
2744 0 : continue;
2745 0 : fec_print(rn->info, vty);
2746 : }
2747 : }
2748 0 : }
2749 :
2750 : /*
2751 : * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2752 : */
2753 0 : void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
2754 : struct prefix *p)
2755 : {
2756 0 : struct route_table *table;
2757 0 : struct route_node *rn;
2758 :
2759 0 : table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2760 0 : if (!table)
2761 : return;
2762 :
2763 0 : apply_mask(p);
2764 0 : rn = route_node_lookup(table, p);
2765 0 : if (!rn)
2766 : return;
2767 :
2768 0 : route_unlock_node(rn);
2769 0 : if (!rn->info)
2770 : return;
2771 :
2772 0 : fec_print(rn->info, vty);
2773 : }
2774 :
2775 0 : static void mpls_zebra_nhe_update(struct route_entry *re, afi_t afi,
2776 : struct nhg_hash_entry *new_nhe)
2777 : {
2778 0 : struct nhg_hash_entry *nhe;
2779 :
2780 0 : nhe = zebra_nhg_rib_find_nhe(new_nhe, afi);
2781 :
2782 0 : route_entry_update_nhe(re, nhe);
2783 0 : }
2784 :
2785 0 : static bool ftn_update_nexthop(bool add_p, struct nexthop *nexthop,
2786 : enum lsp_types_t type,
2787 : const struct zapi_nexthop *znh)
2788 : {
2789 0 : if (add_p && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2790 0 : nexthop_add_labels(nexthop, type, znh->label_num, znh->labels);
2791 0 : else if (!add_p && nexthop->nh_label_type == type)
2792 0 : nexthop_del_labels(nexthop);
2793 : else
2794 : return false;
2795 :
2796 : return true;
2797 : }
2798 :
2799 0 : void zebra_mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2800 : struct prefix *prefix, uint8_t route_type,
2801 : uint8_t route_instance)
2802 : {
2803 0 : struct route_table *table;
2804 0 : struct route_node *rn;
2805 0 : struct route_entry *re;
2806 0 : struct nexthop *nexthop;
2807 0 : struct nhg_hash_entry *new_nhe;
2808 0 : afi_t afi = family2afi(prefix->family);
2809 :
2810 : /* Lookup table. */
2811 0 : table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2812 0 : if (!table)
2813 : return;
2814 :
2815 : /* Lookup existing route */
2816 0 : rn = route_node_get(table, prefix);
2817 0 : RNODE_FOREACH_RE (rn, re) {
2818 0 : if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2819 0 : continue;
2820 0 : if (re->type == route_type && re->instance == route_instance)
2821 : break;
2822 : }
2823 0 : if (re == NULL)
2824 : return;
2825 :
2826 : /*
2827 : * Nexthops are now shared by multiple routes, so we have to make
2828 : * a local copy, modify the copy, then update the route.
2829 : */
2830 0 : new_nhe = zebra_nhe_copy(re->nhe, 0);
2831 :
2832 0 : for (nexthop = new_nhe->nhg.nexthop; nexthop; nexthop = nexthop->next)
2833 0 : nexthop_del_labels(nexthop);
2834 :
2835 : /* Update backup routes/nexthops also, if present. */
2836 0 : if (zebra_nhg_get_backup_nhg(new_nhe) != NULL) {
2837 0 : for (nexthop = new_nhe->backup_info->nhe->nhg.nexthop; nexthop;
2838 0 : nexthop = nexthop->next)
2839 0 : nexthop_del_labels(nexthop);
2840 : }
2841 :
2842 0 : SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2843 0 : SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
2844 :
2845 : /* This will create (or ref) a new nhe, so we will discard the local
2846 : * temporary nhe
2847 : */
2848 0 : mpls_zebra_nhe_update(re, afi, new_nhe);
2849 :
2850 0 : zebra_nhg_free(new_nhe);
2851 :
2852 0 : rib_queue_add(rn);
2853 : }
2854 :
2855 : /*
2856 : * Iterate through a list of nexthops, for a match for 'znh'. If found,
2857 : * update its labels according to 'add_p', and return 'true' if successful.
2858 : */
2859 0 : static bool ftn_update_znh(bool add_p, enum lsp_types_t type,
2860 : struct nexthop *head, const struct zapi_nexthop *znh)
2861 : {
2862 0 : bool found = false, success = false;
2863 0 : struct nexthop *nexthop;
2864 :
2865 0 : for (nexthop = head; nexthop; nexthop = nexthop->next) {
2866 0 : switch (nexthop->type) {
2867 0 : case NEXTHOP_TYPE_IPV4:
2868 : case NEXTHOP_TYPE_IPV4_IFINDEX:
2869 0 : if (znh->type != NEXTHOP_TYPE_IPV4
2870 0 : && znh->type != NEXTHOP_TYPE_IPV4_IFINDEX)
2871 0 : continue;
2872 0 : if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4,
2873 : &znh->gate.ipv4))
2874 0 : continue;
2875 0 : if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
2876 0 : && nexthop->ifindex != znh->ifindex)
2877 0 : continue;
2878 :
2879 0 : found = true;
2880 :
2881 0 : if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2882 : break;
2883 :
2884 : success = true;
2885 : break;
2886 0 : case NEXTHOP_TYPE_IPV6:
2887 : case NEXTHOP_TYPE_IPV6_IFINDEX:
2888 0 : if (znh->type != NEXTHOP_TYPE_IPV6
2889 0 : && znh->type != NEXTHOP_TYPE_IPV6_IFINDEX)
2890 0 : continue;
2891 0 : if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6,
2892 : &znh->gate.ipv6))
2893 0 : continue;
2894 0 : if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
2895 0 : && nexthop->ifindex != znh->ifindex)
2896 0 : continue;
2897 :
2898 0 : found = true;
2899 :
2900 0 : if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2901 : break;
2902 : success = true;
2903 : break;
2904 0 : case NEXTHOP_TYPE_IFINDEX:
2905 0 : if (znh->type != NEXTHOP_TYPE_IFINDEX)
2906 0 : continue;
2907 0 : if (nexthop->ifindex != znh->ifindex)
2908 0 : continue;
2909 :
2910 0 : found = true;
2911 :
2912 0 : if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2913 : break;
2914 : success = true;
2915 : break;
2916 0 : case NEXTHOP_TYPE_BLACKHOLE:
2917 : /* Not valid */
2918 0 : continue;
2919 : }
2920 :
2921 : if (found)
2922 : break;
2923 : }
2924 :
2925 0 : return success;
2926 : }
2927 :
2928 : /*
2929 : * Install/uninstall LSP and (optionally) FEC-To-NHLFE (FTN) bindings,
2930 : * using zapi message info.
2931 : * There are several changes that need to be made, in several zebra
2932 : * data structures, so we want to do all the work required at once.
2933 : */
2934 0 : void zebra_mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
2935 : const struct zapi_labels *zl)
2936 : {
2937 0 : int i, counter, ret = 0;
2938 0 : char buf[NEXTHOP_STRLEN];
2939 0 : const struct zapi_nexthop *znh;
2940 0 : struct route_table *table;
2941 0 : struct route_node *rn = NULL;
2942 0 : struct route_entry *re = NULL;
2943 0 : struct nhg_hash_entry *new_nhe = NULL;
2944 0 : bool found;
2945 0 : afi_t afi = AFI_IP;
2946 0 : const struct prefix *prefix = NULL;
2947 0 : struct hash *lsp_table;
2948 0 : struct zebra_ile tmp_ile;
2949 0 : struct zebra_lsp *lsp = NULL;
2950 :
2951 : /* Prep LSP for add case */
2952 0 : if (add_p) {
2953 : /* Lookup table. */
2954 0 : lsp_table = zvrf->lsp_table;
2955 0 : if (!lsp_table)
2956 0 : return;
2957 :
2958 : /* Find or create LSP object */
2959 0 : tmp_ile.in_label = zl->local_label;
2960 0 : lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2961 : }
2962 :
2963 : /* Prep for route/FEC update if requested */
2964 0 : if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
2965 0 : prefix = &zl->route.prefix;
2966 :
2967 0 : afi = family2afi(prefix->family);
2968 :
2969 : /* Lookup table. */
2970 0 : table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2971 0 : if (table) {
2972 : /* Lookup existing route */
2973 0 : rn = route_node_get(table, prefix);
2974 0 : RNODE_FOREACH_RE(rn, re) {
2975 0 : if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2976 0 : continue;
2977 0 : if (re->type == zl->route.type &&
2978 0 : re->instance == zl->route.instance)
2979 : break;
2980 : }
2981 : }
2982 :
2983 0 : if (re) {
2984 : /*
2985 : * Copy over current nexthops into a temporary group.
2986 : * We can't just change the values here since the nhgs
2987 : * are shared and if the labels change, we'll need
2988 : * to find or create a new nhg. We need to create
2989 : * a whole temporary group, make changes to it,
2990 : * then attach that to the route.
2991 : */
2992 0 : new_nhe = zebra_nhe_copy(re->nhe, 0);
2993 :
2994 : } else {
2995 : /*
2996 : * The old version of the zapi code
2997 : * attempted to manage LSPs before trying to
2998 : * find a route/FEC, so we'll continue that way.
2999 : */
3000 0 : if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS)
3001 0 : zlog_debug(
3002 : "%s: FTN update requested: no route for prefix %pFX",
3003 : __func__, prefix);
3004 : }
3005 : }
3006 :
3007 : /*
3008 : * Use info from the zapi nexthops to add/replace/remove LSP/FECs
3009 : */
3010 :
3011 0 : counter = 0;
3012 0 : for (i = 0; i < zl->nexthop_num; i++) {
3013 :
3014 0 : znh = &zl->nexthops[i];
3015 :
3016 : /* Attempt LSP update */
3017 0 : if (add_p)
3018 0 : ret = lsp_znh_install(lsp, zl->type, znh);
3019 : else
3020 0 : ret = mpls_lsp_uninstall(zvrf, zl->type,
3021 0 : zl->local_label, znh->type,
3022 0 : &znh->gate, znh->ifindex,
3023 : false);
3024 0 : if (ret < 0) {
3025 0 : if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS) {
3026 0 : zapi_nexthop2str(znh, buf, sizeof(buf));
3027 0 : zlog_debug("%s: Unable to %sinstall LSP: label %u, znh %s",
3028 : __func__, (add_p ? "" : "un"),
3029 : zl->local_label, buf);
3030 : }
3031 0 : continue;
3032 : }
3033 :
3034 : /* Attempt route/FEC update if requested */
3035 0 : if (re == NULL)
3036 0 : continue;
3037 :
3038 : /* Search the route's nexthops for a match, and update it. */
3039 0 : found = ftn_update_znh(add_p, zl->type, new_nhe->nhg.nexthop,
3040 : znh);
3041 0 : if (found) {
3042 0 : counter++;
3043 0 : } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
3044 0 : zapi_nexthop2str(znh, buf, sizeof(buf));
3045 0 : zlog_debug(
3046 : "%s: Unable to update FEC: prefix %pFX, label %u, znh %s",
3047 : __func__, prefix, zl->local_label, buf);
3048 : }
3049 : }
3050 :
3051 : /*
3052 : * Process backup LSPs/nexthop entries also. We associate backup
3053 : * LSP info with backup nexthops.
3054 : */
3055 0 : if (!CHECK_FLAG(zl->message, ZAPI_LABELS_HAS_BACKUPS))
3056 0 : goto znh_done;
3057 :
3058 0 : for (i = 0; i < zl->backup_nexthop_num; i++) {
3059 :
3060 0 : znh = &zl->backup_nexthops[i];
3061 :
3062 0 : if (add_p)
3063 0 : ret = lsp_backup_znh_install(lsp, zl->type, znh);
3064 : else
3065 0 : ret = mpls_lsp_uninstall(zvrf, zl->type,
3066 0 : zl->local_label,
3067 0 : znh->type, &znh->gate,
3068 0 : znh->ifindex, true);
3069 :
3070 0 : if (ret < 0) {
3071 0 : if (IS_ZEBRA_DEBUG_RECV ||
3072 0 : IS_ZEBRA_DEBUG_MPLS) {
3073 0 : zapi_nexthop2str(znh, buf, sizeof(buf));
3074 0 : zlog_debug("%s: Unable to %sinstall backup LSP: label %u, znh %s",
3075 : __func__, (add_p ? "" : "un"),
3076 : zl->local_label, buf);
3077 : }
3078 0 : continue;
3079 : }
3080 :
3081 : /* Attempt backup nexthop/FEC update if requested */
3082 0 : if (re == NULL || zebra_nhg_get_backup_nhg(new_nhe) == NULL)
3083 0 : continue;
3084 :
3085 : /* Search the route's backup nexthops for a match
3086 : * and update it.
3087 : */
3088 0 : found = ftn_update_znh(add_p, zl->type,
3089 0 : new_nhe->backup_info->nhe->nhg.nexthop,
3090 : znh);
3091 0 : if (found) {
3092 0 : counter++;
3093 0 : } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
3094 0 : zapi_nexthop2str(znh, buf, sizeof(buf));
3095 0 : zlog_debug(
3096 : "%s: Unable to update backup FEC: prefix %pFX, label %u, znh %s",
3097 : __func__, prefix, zl->local_label, buf);
3098 : }
3099 : }
3100 :
3101 0 : znh_done:
3102 :
3103 : /*
3104 : * If we made changes, update the route, and schedule it
3105 : * for rib processing
3106 : */
3107 0 : if (re != NULL && counter > 0) {
3108 0 : assert(rn != NULL);
3109 :
3110 0 : SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
3111 0 : SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
3112 :
3113 0 : mpls_zebra_nhe_update(re, afi, new_nhe);
3114 :
3115 0 : rib_queue_add(rn);
3116 : }
3117 :
3118 0 : if (new_nhe)
3119 0 : zebra_nhg_free(new_nhe);
3120 : }
3121 :
3122 : /*
3123 : * Install/update a NHLFE for an LSP in the forwarding table. This may be
3124 : * a new LSP entry or a new NHLFE for an existing in-label or an update of
3125 : * the out-label for an existing NHLFE (update case).
3126 : */
3127 : static struct zebra_nhlfe *
3128 0 : lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type,
3129 : uint8_t num_out_labels, const mpls_label_t *out_labels,
3130 : enum nexthop_types_t gtype, const union g_addr *gate,
3131 : ifindex_t ifindex, bool is_backup)
3132 : {
3133 0 : struct zebra_nhlfe *nhlfe;
3134 0 : char buf[MPLS_LABEL_STRLEN];
3135 0 : const char *backup_str;
3136 :
3137 0 : if (is_backup) {
3138 0 : nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
3139 : gate, ifindex);
3140 0 : backup_str = "backup ";
3141 : } else {
3142 0 : nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
3143 : ifindex);
3144 0 : backup_str = "";
3145 : }
3146 :
3147 0 : if (nhlfe) {
3148 0 : struct nexthop *nh = nhlfe->nexthop;
3149 :
3150 0 : assert(nh);
3151 0 : assert(nh->nh_label);
3152 :
3153 : /* Clear deleted flag (in case it was set) */
3154 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
3155 0 : if (nh->nh_label->num_labels == num_out_labels
3156 0 : && !memcmp(nh->nh_label->label, out_labels,
3157 : sizeof(mpls_label_t) * num_out_labels))
3158 : /* No change */
3159 : return nhlfe;
3160 :
3161 0 : if (IS_ZEBRA_DEBUG_MPLS) {
3162 0 : char buf2[MPLS_LABEL_STRLEN];
3163 0 : char buf3[MPLS_LABEL_STRLEN];
3164 :
3165 0 : nhlfe2str(nhlfe, buf, sizeof(buf));
3166 0 : mpls_label2str(num_out_labels, out_labels, buf2,
3167 : sizeof(buf2), 0);
3168 0 : mpls_label2str(nh->nh_label->num_labels,
3169 0 : nh->nh_label->label, buf3, sizeof(buf3),
3170 : 0);
3171 :
3172 0 : zlog_debug("LSP in-label %u type %d %snexthop %s out-label(s) changed to %s (old %s)",
3173 : lsp->ile.in_label, type, backup_str, buf,
3174 : buf2, buf3);
3175 : }
3176 :
3177 : /* Update out label(s), trigger processing. */
3178 0 : if (nh->nh_label->num_labels == num_out_labels)
3179 0 : memcpy(nh->nh_label->label, out_labels,
3180 : sizeof(mpls_label_t) * num_out_labels);
3181 : else {
3182 0 : nexthop_del_labels(nh);
3183 0 : nexthop_add_labels(nh, type, num_out_labels,
3184 : out_labels);
3185 : }
3186 : } else {
3187 : /* Add LSP entry to this nexthop */
3188 0 : nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex,
3189 : num_out_labels, out_labels, is_backup);
3190 0 : if (!nhlfe)
3191 : return NULL;
3192 :
3193 0 : if (IS_ZEBRA_DEBUG_MPLS) {
3194 0 : char buf2[MPLS_LABEL_STRLEN];
3195 :
3196 0 : nhlfe2str(nhlfe, buf, sizeof(buf));
3197 0 : mpls_label2str(num_out_labels, out_labels, buf2,
3198 : sizeof(buf2), 0);
3199 :
3200 0 : zlog_debug("Add LSP in-label %u type %d %snexthop %s out-label(s) %s",
3201 : lsp->ile.in_label, type, backup_str, buf,
3202 : buf2);
3203 : }
3204 :
3205 0 : lsp->addr_family = NHLFE_FAMILY(nhlfe);
3206 : }
3207 :
3208 : /* Mark NHLFE, queue LSP for processing. */
3209 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
3210 :
3211 0 : return nhlfe;
3212 : }
3213 :
3214 : /*
3215 : * Install an LSP and forwarding entry; used primarily
3216 : * from vrf zapi message processing.
3217 : */
3218 0 : int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
3219 : mpls_label_t in_label, uint8_t num_out_labels,
3220 : const mpls_label_t *out_labels, enum nexthop_types_t gtype,
3221 : const union g_addr *gate, ifindex_t ifindex)
3222 : {
3223 0 : struct hash *lsp_table;
3224 0 : struct zebra_ile tmp_ile;
3225 0 : struct zebra_lsp *lsp;
3226 0 : struct zebra_nhlfe *nhlfe;
3227 :
3228 : /* Lookup table. */
3229 0 : lsp_table = zvrf->lsp_table;
3230 0 : if (!lsp_table)
3231 : return -1;
3232 :
3233 : /* Find or create LSP object */
3234 0 : tmp_ile.in_label = in_label;
3235 0 : lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
3236 :
3237 0 : nhlfe = lsp_add_nhlfe(lsp, type, num_out_labels, out_labels, gtype,
3238 : gate, ifindex, false /*backup*/);
3239 0 : if (nhlfe == NULL)
3240 : return -1;
3241 :
3242 : /* Queue LSP for processing. */
3243 0 : if (lsp_processq_add(lsp))
3244 : return -1;
3245 :
3246 : return 0;
3247 : }
3248 :
3249 : /*
3250 : * Install or replace NHLFE, using info from zapi nexthop
3251 : */
3252 0 : static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
3253 : const struct zapi_nexthop *znh)
3254 : {
3255 0 : struct zebra_nhlfe *nhlfe;
3256 :
3257 0 : nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels,
3258 0 : znh->type, &znh->gate, znh->ifindex,
3259 : false /*backup*/);
3260 0 : if (nhlfe == NULL)
3261 : return -1;
3262 :
3263 : /* Update backup info if present */
3264 0 : if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
3265 0 : if (znh->backup_num > NEXTHOP_MAX_BACKUPS) {
3266 0 : nhlfe_del(nhlfe);
3267 0 : return -1;
3268 : }
3269 :
3270 0 : nhlfe->nexthop->backup_num = znh->backup_num;
3271 0 : memcpy(nhlfe->nexthop->backup_idx, znh->backup_idx,
3272 : znh->backup_num);
3273 0 : SET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
3274 : } else {
3275 : /* Ensure there's no stale backup info */
3276 0 : UNSET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
3277 0 : nhlfe->nexthop->backup_num = 0;
3278 : }
3279 :
3280 : /* Queue LSP for processing. */
3281 0 : if (lsp_processq_add(lsp))
3282 : return -1;
3283 :
3284 : return 0;
3285 : }
3286 :
3287 : /*
3288 : * Install/update backup NHLFE for an LSP, using info from a zapi message.
3289 : */
3290 0 : static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
3291 : const struct zapi_nexthop *znh)
3292 : {
3293 0 : struct zebra_nhlfe *nhlfe;
3294 :
3295 0 : nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num,
3296 0 : znh->labels, znh->type, &znh->gate,
3297 0 : znh->ifindex, true /*backup*/);
3298 0 : if (nhlfe == NULL) {
3299 0 : if (IS_ZEBRA_DEBUG_MPLS)
3300 0 : zlog_debug("%s: unable to add backup nhlfe, label: %u",
3301 : __func__, lsp->ile.in_label);
3302 0 : return -1;
3303 : }
3304 :
3305 : /* Queue LSP for processing. */
3306 0 : if (lsp_processq_add(lsp))
3307 : return -1;
3308 :
3309 : return 0;
3310 : }
3311 :
3312 0 : struct zebra_lsp *mpls_lsp_find(struct zebra_vrf *zvrf, mpls_label_t in_label)
3313 : {
3314 0 : struct hash *lsp_table;
3315 0 : struct zebra_ile tmp_ile;
3316 :
3317 : /* Lookup table. */
3318 0 : lsp_table = zvrf->lsp_table;
3319 0 : if (!lsp_table)
3320 : return NULL;
3321 :
3322 : /* If entry is not present, exit. */
3323 0 : tmp_ile.in_label = in_label;
3324 0 : return hash_lookup(lsp_table, &tmp_ile);
3325 : }
3326 :
3327 : /*
3328 : * Uninstall a particular NHLFE in the forwarding table. If this is
3329 : * the only NHLFE, the entire LSP forwarding entry has to be deleted.
3330 : */
3331 0 : int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
3332 : mpls_label_t in_label, enum nexthop_types_t gtype,
3333 : const union g_addr *gate, ifindex_t ifindex,
3334 : bool backup_p)
3335 : {
3336 0 : struct hash *lsp_table;
3337 0 : struct zebra_ile tmp_ile;
3338 0 : struct zebra_lsp *lsp;
3339 0 : struct zebra_nhlfe *nhlfe;
3340 0 : char buf[NEXTHOP_STRLEN];
3341 0 : bool schedule_lsp = false;
3342 :
3343 : /* Lookup table. */
3344 0 : lsp_table = zvrf->lsp_table;
3345 0 : if (!lsp_table)
3346 : return -1;
3347 :
3348 : /* If entry is not present, exit. */
3349 0 : tmp_ile.in_label = in_label;
3350 0 : lsp = hash_lookup(lsp_table, &tmp_ile);
3351 0 : if (!lsp)
3352 : return 0;
3353 :
3354 0 : if (backup_p)
3355 0 : nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
3356 : gate, ifindex);
3357 : else
3358 0 : nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
3359 : ifindex);
3360 0 : if (!nhlfe)
3361 : return 0;
3362 :
3363 0 : if (IS_ZEBRA_DEBUG_MPLS) {
3364 0 : nhlfe2str(nhlfe, buf, sizeof(buf));
3365 0 : zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
3366 : in_label, type, buf, nhlfe->flags);
3367 : }
3368 :
3369 0 : if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ||
3370 0 : CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
3371 0 : schedule_lsp = true;
3372 :
3373 : /* Mark NHLFE for delete or directly delete, as appropriate. */
3374 0 : if (schedule_lsp) {
3375 0 : SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
3376 0 : UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
3377 :
3378 0 : if (IS_ZEBRA_DEBUG_MPLS)
3379 0 : zlog_debug("Schedule LSP in-label %u flags 0x%x",
3380 : lsp->ile.in_label, lsp->flags);
3381 0 : if (lsp_processq_add(lsp))
3382 : return -1;
3383 : } else {
3384 0 : nhlfe_del(nhlfe);
3385 :
3386 : /* Free LSP entry if no other NHLFEs and not scheduled. */
3387 0 : lsp_check_free(lsp_table, &lsp);
3388 : }
3389 : return 0;
3390 : }
3391 :
3392 0 : int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
3393 : mpls_label_t in_label)
3394 : {
3395 0 : struct hash *lsp_table;
3396 0 : struct zebra_ile tmp_ile;
3397 0 : struct zebra_lsp *lsp;
3398 :
3399 : /* Lookup table. */
3400 0 : lsp_table = zvrf->lsp_table;
3401 0 : if (!lsp_table)
3402 : return -1;
3403 :
3404 : /* If entry is not present, exit. */
3405 0 : tmp_ile.in_label = in_label;
3406 0 : lsp = hash_lookup(lsp_table, &tmp_ile);
3407 0 : if (!lsp)
3408 : return 0;
3409 :
3410 0 : return mpls_lsp_uninstall_all(lsp_table, lsp, type);
3411 : }
3412 :
3413 : /*
3414 : * Uninstall all NHLFEs for a particular LSP forwarding entry.
3415 : * If no other NHLFEs exist, the entry would be deleted.
3416 : */
3417 0 : static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt)
3418 : {
3419 0 : struct lsp_uninstall_args *args = ctxt;
3420 0 : struct zebra_lsp *lsp;
3421 0 : struct hash *lsp_table;
3422 :
3423 0 : lsp = (struct zebra_lsp *)bucket->data;
3424 0 : if (nhlfe_list_first(&lsp->nhlfe_list) == NULL)
3425 : return;
3426 :
3427 0 : lsp_table = args->lsp_table;
3428 0 : if (!lsp_table)
3429 : return;
3430 :
3431 0 : mpls_lsp_uninstall_all(lsp_table, lsp, args->type);
3432 : }
3433 :
3434 : /*
3435 : * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and
3436 : * LSP type.
3437 : */
3438 0 : static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
3439 : int afi, enum lsp_types_t lsp_type)
3440 : {
3441 0 : struct route_table *table;
3442 0 : struct route_node *rn;
3443 0 : struct route_entry *re;
3444 0 : struct nexthop *nexthop;
3445 0 : struct nexthop_group *nhg;
3446 0 : bool update;
3447 :
3448 : /* Process routes of interested address-families. */
3449 0 : table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
3450 0 : if (!table)
3451 : return;
3452 :
3453 0 : for (rn = route_top(table); rn; rn = route_next(rn)) {
3454 0 : update = false;
3455 :
3456 0 : RNODE_FOREACH_RE (rn, re) {
3457 0 : struct nhg_hash_entry *new_nhe;
3458 :
3459 0 : new_nhe = zebra_nhe_copy(re->nhe, 0);
3460 :
3461 0 : nhg = &new_nhe->nhg;
3462 0 : for (nexthop = nhg->nexthop; nexthop;
3463 0 : nexthop = nexthop->next) {
3464 0 : if (nexthop->nh_label_type != lsp_type)
3465 0 : continue;
3466 :
3467 0 : nexthop_del_labels(nexthop);
3468 0 : SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
3469 0 : SET_FLAG(re->status,
3470 : ROUTE_ENTRY_LABELS_CHANGED);
3471 0 : update = true;
3472 : }
3473 :
3474 : /* Check for backup info and update that also */
3475 0 : nhg = zebra_nhg_get_backup_nhg(new_nhe);
3476 0 : if (nhg != NULL) {
3477 0 : for (nexthop = nhg->nexthop; nexthop;
3478 0 : nexthop = nexthop->next) {
3479 0 : if (nexthop->nh_label_type != lsp_type)
3480 0 : continue;
3481 :
3482 0 : nexthop_del_labels(nexthop);
3483 0 : SET_FLAG(re->status,
3484 : ROUTE_ENTRY_CHANGED);
3485 0 : SET_FLAG(re->status,
3486 : ROUTE_ENTRY_LABELS_CHANGED);
3487 0 : update = true;
3488 : }
3489 : }
3490 :
3491 0 : if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
3492 0 : mpls_zebra_nhe_update(re, afi, new_nhe);
3493 :
3494 0 : zebra_nhg_free(new_nhe);
3495 : }
3496 :
3497 0 : if (update)
3498 0 : rib_queue_add(rn);
3499 : }
3500 : }
3501 :
3502 : #if defined(HAVE_CUMULUS)
3503 : /*
3504 : * Check that the label values used in LSP creation are consistent. The
3505 : * main criteria is that if there is ECMP, the label operation must still
3506 : * be consistent - i.e., all paths either do a swap or do PHP. This is due
3507 : * to current HW restrictions.
3508 : */
3509 : int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
3510 : mpls_label_t in_label,
3511 : mpls_label_t out_label,
3512 : enum nexthop_types_t gtype,
3513 : union g_addr *gate, ifindex_t ifindex)
3514 : {
3515 : struct hash *slsp_table;
3516 : struct zebra_ile tmp_ile;
3517 : struct zebra_lsp *lsp;
3518 : struct zebra_nhlfe *nhlfe;
3519 : const struct nexthop *nh;
3520 :
3521 : /* Lookup table. */
3522 : slsp_table = zvrf->slsp_table;
3523 : if (!slsp_table)
3524 : return 0;
3525 :
3526 : /* If entry is not present, exit. */
3527 : tmp_ile.in_label = in_label;
3528 : lsp = hash_lookup(slsp_table, &tmp_ile);
3529 : if (!lsp)
3530 : return 1;
3531 :
3532 : nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
3533 : gtype, gate, ifindex);
3534 : if (nhlfe) {
3535 : nh = nhlfe->nexthop;
3536 :
3537 : if (nh == NULL || nh->nh_label == NULL)
3538 : return 0;
3539 :
3540 : if (nh->nh_label->label[0] == out_label)
3541 : return 1;
3542 :
3543 : /* If not only NHLFE, cannot allow label change. */
3544 : if (nhlfe != nhlfe_list_first(&lsp->nhlfe_list) ||
3545 : nhlfe_list_next(&lsp->nhlfe_list, nhlfe) != NULL)
3546 : return 0;
3547 : } else {
3548 : /* If other NHLFEs exist, label operation must match. */
3549 : nhlfe = nhlfe_list_first(&lsp->nhlfe_list);
3550 : if (nhlfe != NULL) {
3551 : int cur_op, new_op;
3552 :
3553 : nh = nhlfe->nexthop;
3554 :
3555 : if (nh == NULL || nh->nh_label == NULL)
3556 : return 0;
3557 :
3558 : cur_op = (nh->nh_label->label[0] ==
3559 : MPLS_LABEL_IMPLICIT_NULL);
3560 : new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
3561 : if (cur_op != new_op)
3562 : return 0;
3563 : }
3564 : }
3565 :
3566 : /* Label values are good. */
3567 : return 1;
3568 : }
3569 : #endif /* HAVE_CUMULUS */
3570 :
3571 : /*
3572 : * Add static LSP entry. This may be the first entry for this incoming label
3573 : * or an additional nexthop; an existing entry may also have outgoing label
3574 : * changed.
3575 : * Note: The label operation (swap or PHP) is common for the LSP entry (all
3576 : * NHLFEs).
3577 : */
3578 0 : int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
3579 : mpls_label_t out_label,
3580 : enum nexthop_types_t gtype, union g_addr *gate,
3581 : ifindex_t ifindex)
3582 : {
3583 0 : struct hash *slsp_table;
3584 0 : struct zebra_ile tmp_ile;
3585 0 : struct zebra_lsp *lsp;
3586 0 : struct zebra_nhlfe *nhlfe;
3587 0 : char buf[BUFSIZ];
3588 :
3589 : /* Lookup table. */
3590 0 : slsp_table = zvrf->slsp_table;
3591 0 : if (!slsp_table)
3592 : return -1;
3593 :
3594 : /* Find or create LSP. */
3595 0 : tmp_ile.in_label = in_label;
3596 0 : lsp = hash_get(slsp_table, &tmp_ile, lsp_alloc);
3597 :
3598 0 : nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC, gtype, gate,
3599 : ifindex);
3600 0 : if (nhlfe) {
3601 0 : struct nexthop *nh = nhlfe->nexthop;
3602 :
3603 0 : assert(nh);
3604 0 : assert(nh->nh_label);
3605 :
3606 : /* Compare existing nexthop */
3607 0 : if (nh->nh_label->num_labels == 1 &&
3608 0 : nh->nh_label->label[0] == out_label)
3609 : /* No change */
3610 : return 0;
3611 :
3612 0 : if (IS_ZEBRA_DEBUG_MPLS) {
3613 0 : nhlfe2str(nhlfe, buf, sizeof(buf));
3614 0 : zlog_debug(
3615 : "Upd static LSP in-label %u nexthop %s out-label %u (old %u)",
3616 : in_label, buf, out_label,
3617 : nh->nh_label->label[0]);
3618 : }
3619 0 : if (nh->nh_label->num_labels == 1)
3620 0 : nh->nh_label->label[0] = out_label;
3621 : else {
3622 0 : nexthop_del_labels(nh);
3623 0 : nexthop_add_labels(nh, ZEBRA_LSP_STATIC, 1, &out_label);
3624 : }
3625 :
3626 : } else {
3627 : /* Add static LSP entry to this nexthop */
3628 0 : nhlfe = nhlfe_add(lsp, ZEBRA_LSP_STATIC, gtype, gate,
3629 : ifindex, 1, &out_label, false /*backup*/);
3630 0 : if (!nhlfe)
3631 : return -1;
3632 :
3633 0 : if (IS_ZEBRA_DEBUG_MPLS) {
3634 0 : nhlfe2str(nhlfe, buf, sizeof(buf));
3635 0 : zlog_debug(
3636 : "Add static LSP in-label %u nexthop %s out-label %u",
3637 : in_label, buf, out_label);
3638 : }
3639 : }
3640 :
3641 : /* (Re)Install LSP in the main table. */
3642 0 : if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, 1, &out_label,
3643 : gtype, gate, ifindex))
3644 : return -1;
3645 :
3646 : return 0;
3647 : }
3648 :
3649 : /*
3650 : * Delete static LSP entry. This may be the delete of one particular
3651 : * NHLFE for this incoming label or the delete of the entire entry (i.e.,
3652 : * all NHLFEs).
3653 : * NOTE: Delete of the only NHLFE will also end up deleting the entire
3654 : * LSP configuration.
3655 : */
3656 0 : int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
3657 : enum nexthop_types_t gtype, union g_addr *gate,
3658 : ifindex_t ifindex)
3659 : {
3660 0 : struct hash *slsp_table;
3661 0 : struct zebra_ile tmp_ile;
3662 0 : struct zebra_lsp *lsp;
3663 0 : struct zebra_nhlfe *nhlfe;
3664 :
3665 : /* Lookup table. */
3666 0 : slsp_table = zvrf->slsp_table;
3667 0 : if (!slsp_table)
3668 : return -1;
3669 :
3670 : /* If entry is not present, exit. */
3671 0 : tmp_ile.in_label = in_label;
3672 0 : lsp = hash_lookup(slsp_table, &tmp_ile);
3673 0 : if (!lsp)
3674 : return 0;
3675 :
3676 : /* Is it delete of entire LSP or a specific NHLFE? */
3677 0 : if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
3678 0 : if (IS_ZEBRA_DEBUG_MPLS)
3679 0 : zlog_debug("Del static LSP in-label %u", in_label);
3680 :
3681 : /* Uninstall entire LSP from the main table. */
3682 0 : mpls_static_lsp_uninstall_all(zvrf, in_label);
3683 :
3684 : /* Delete all static NHLFEs */
3685 0 : frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3686 0 : nhlfe_del(nhlfe);
3687 : }
3688 : } else {
3689 : /* Find specific NHLFE, exit if not found. */
3690 0 : nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
3691 : gtype, gate, ifindex);
3692 0 : if (!nhlfe)
3693 : return 0;
3694 :
3695 0 : if (IS_ZEBRA_DEBUG_MPLS) {
3696 0 : char buf[BUFSIZ];
3697 0 : nhlfe2str(nhlfe, buf, sizeof(buf));
3698 0 : zlog_debug("Del static LSP in-label %u nexthop %s",
3699 : in_label, buf);
3700 : }
3701 :
3702 : /* Uninstall LSP from the main table. */
3703 0 : mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
3704 : gate, ifindex, false);
3705 :
3706 : /* Delete static LSP NHLFE */
3707 0 : nhlfe_del(nhlfe);
3708 : }
3709 :
3710 : /* Remove entire static LSP entry if no NHLFE - valid in either case
3711 : * above.
3712 : */
3713 0 : if (nhlfe_list_first(&lsp->nhlfe_list) == NULL) {
3714 0 : lsp = hash_release(slsp_table, &tmp_ile);
3715 0 : lsp_free_nhlfe(lsp);
3716 0 : XFREE(MTYPE_LSP, lsp);
3717 : }
3718 :
3719 : return 0;
3720 : }
3721 :
3722 : /*
3723 : * Schedule all MPLS label forwarding entries for processing.
3724 : * Called upon changes that may affect one or more of them such as
3725 : * interface or nexthop state changes.
3726 : */
3727 4 : void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
3728 : {
3729 4 : if (!zvrf)
3730 : return;
3731 4 : hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
3732 : }
3733 :
3734 : /*
3735 : * Display MPLS label forwarding table for a specific LSP
3736 : * (VTY command handler).
3737 : */
3738 0 : void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
3739 : mpls_label_t label, bool use_json)
3740 : {
3741 0 : struct hash *lsp_table;
3742 0 : struct zebra_lsp *lsp;
3743 0 : struct zebra_ile tmp_ile;
3744 0 : json_object *json = NULL;
3745 :
3746 : /* Lookup table. */
3747 0 : lsp_table = zvrf->lsp_table;
3748 0 : if (!lsp_table)
3749 0 : return;
3750 :
3751 : /* If entry is not present, exit. */
3752 0 : tmp_ile.in_label = label;
3753 0 : lsp = hash_lookup(lsp_table, &tmp_ile);
3754 0 : if (!lsp)
3755 : return;
3756 :
3757 0 : if (use_json) {
3758 0 : json = lsp_json(lsp);
3759 0 : vty_json(vty, json);
3760 : } else
3761 0 : lsp_print(vty, lsp);
3762 : }
3763 :
3764 : /*
3765 : * Display MPLS label forwarding table (VTY command handler).
3766 : */
3767 0 : void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
3768 : bool use_json)
3769 : {
3770 0 : char buf[BUFSIZ];
3771 0 : json_object *json = NULL;
3772 0 : struct zebra_lsp *lsp = NULL;
3773 0 : struct zebra_nhlfe *nhlfe = NULL;
3774 0 : struct listnode *node = NULL;
3775 0 : struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
3776 :
3777 0 : if (use_json) {
3778 0 : json = json_object_new_object();
3779 :
3780 0 : for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
3781 0 : json_object_object_add(
3782 0 : json, label2str(lsp->ile.in_label, buf,
3783 : sizeof(buf)),
3784 0 : lsp_json(lsp));
3785 :
3786 0 : vty_json(vty, json);
3787 : } else {
3788 0 : struct ttable *tt;
3789 :
3790 : /* Prepare table. */
3791 0 : tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3792 0 : ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label");
3793 0 : tt->style.cell.rpad = 2;
3794 0 : tt->style.corner = '+';
3795 0 : ttable_restyle(tt);
3796 0 : ttable_rowseps(tt, 0, BOTTOM, true, '-');
3797 :
3798 0 : for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
3799 0 : frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3800 0 : struct nexthop *nexthop;
3801 0 : const char *out_label_str;
3802 0 : char nh_buf[NEXTHOP_STRLEN];
3803 :
3804 0 : nexthop = nhlfe->nexthop;
3805 :
3806 0 : switch (nexthop->type) {
3807 0 : case NEXTHOP_TYPE_IFINDEX: {
3808 0 : struct zebra_ns *zns;
3809 0 : struct interface *ifp;
3810 :
3811 0 : zns = zebra_ns_lookup(NS_DEFAULT);
3812 0 : ifp = if_lookup_by_index_per_ns(
3813 0 : zns, nexthop->ifindex);
3814 0 : snprintf(nh_buf, sizeof(nh_buf), "%s",
3815 : ifp ? ifp->name : "Null");
3816 0 : break;
3817 : }
3818 0 : case NEXTHOP_TYPE_IPV4:
3819 : case NEXTHOP_TYPE_IPV4_IFINDEX:
3820 0 : inet_ntop(AF_INET, &nexthop->gate.ipv4,
3821 : nh_buf, sizeof(nh_buf));
3822 0 : break;
3823 0 : case NEXTHOP_TYPE_IPV6:
3824 : case NEXTHOP_TYPE_IPV6_IFINDEX:
3825 0 : inet_ntop(AF_INET6, &nexthop->gate.ipv6,
3826 : nh_buf, sizeof(nh_buf));
3827 0 : break;
3828 : case NEXTHOP_TYPE_BLACKHOLE:
3829 : break;
3830 : }
3831 :
3832 0 : if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
3833 0 : out_label_str = mpls_label2str(
3834 0 : nexthop->nh_label->num_labels,
3835 0 : &nexthop->nh_label->label[0],
3836 : buf, sizeof(buf), 1);
3837 : else
3838 : out_label_str = "-";
3839 :
3840 0 : ttable_add_row(tt, "%u|%s|%s|%s",
3841 : lsp->ile.in_label,
3842 : nhlfe_type2str(nhlfe->type),
3843 : nh_buf, out_label_str);
3844 : }
3845 : }
3846 :
3847 : /* Dump the generated table. */
3848 0 : if (tt->nrows > 1) {
3849 0 : char *table = ttable_dump(tt, "\n");
3850 0 : vty_out(vty, "%s\n", table);
3851 0 : XFREE(MTYPE_TMP, table);
3852 : }
3853 0 : ttable_del(tt);
3854 : }
3855 :
3856 0 : list_delete(&lsp_list);
3857 0 : }
3858 :
3859 : /*
3860 : * Create printable string for static LSP configuration.
3861 : */
3862 0 : static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
3863 : int size)
3864 : {
3865 0 : const struct nexthop *nh;
3866 :
3867 0 : nh = nhlfe->nexthop;
3868 :
3869 0 : buf[0] = '\0';
3870 0 : switch (nh->type) {
3871 0 : case NEXTHOP_TYPE_IPV4:
3872 : case NEXTHOP_TYPE_IPV4_IFINDEX:
3873 0 : inet_ntop(AF_INET, &nh->gate.ipv4, buf, size);
3874 0 : if (nh->ifindex)
3875 0 : strlcat(buf, ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3876 : size);
3877 : break;
3878 0 : case NEXTHOP_TYPE_IPV6:
3879 : case NEXTHOP_TYPE_IPV6_IFINDEX:
3880 0 : inet_ntop(AF_INET6, &nh->gate.ipv6, buf, size);
3881 0 : if (nh->ifindex)
3882 0 : strlcat(buf,
3883 : ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3884 : size);
3885 : break;
3886 0 : case NEXTHOP_TYPE_IFINDEX:
3887 0 : if (nh->ifindex)
3888 0 : strlcat(buf,
3889 : ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3890 : size);
3891 : break;
3892 : case NEXTHOP_TYPE_BLACKHOLE:
3893 : break;
3894 : }
3895 :
3896 0 : return buf;
3897 : }
3898 :
3899 : /*
3900 : * Display MPLS LSP configuration of all static LSPs (VTY command handler).
3901 : */
3902 0 : int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
3903 : {
3904 0 : struct zebra_lsp *lsp;
3905 0 : struct zebra_nhlfe *nhlfe;
3906 0 : struct nexthop *nh;
3907 0 : struct listnode *node;
3908 0 : struct list *slsp_list =
3909 0 : hash_get_sorted_list(zvrf->slsp_table, lsp_cmp);
3910 :
3911 0 : for (ALL_LIST_ELEMENTS_RO(slsp_list, node, lsp)) {
3912 0 : frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3913 0 : char buf[BUFSIZ];
3914 0 : char lstr[30];
3915 :
3916 0 : nh = nhlfe->nexthop;
3917 0 : if (nh == NULL || nh->nh_label == NULL)
3918 0 : continue;
3919 :
3920 0 : nhlfe_config_str(nhlfe, buf, sizeof(buf));
3921 :
3922 0 : switch (nh->nh_label->label[0]) {
3923 0 : case MPLS_LABEL_IPV4_EXPLICIT_NULL:
3924 : case MPLS_LABEL_IPV6_EXPLICIT_NULL:
3925 0 : strlcpy(lstr, "explicit-null", sizeof(lstr));
3926 0 : break;
3927 0 : case MPLS_LABEL_IMPLICIT_NULL:
3928 0 : strlcpy(lstr, "implicit-null", sizeof(lstr));
3929 0 : break;
3930 0 : default:
3931 0 : snprintf(lstr, sizeof(lstr), "%u",
3932 : nh->nh_label->label[0]);
3933 0 : break;
3934 : }
3935 :
3936 0 : vty_out(vty, "mpls lsp %u %s %s\n", lsp->ile.in_label,
3937 : buf, lstr);
3938 : }
3939 : }
3940 :
3941 0 : list_delete(&slsp_list);
3942 0 : return (zvrf->slsp_table->count ? 1 : 0);
3943 : }
3944 :
3945 : /*
3946 : * Add/update global label block.
3947 : */
3948 0 : int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
3949 : uint32_t end_label)
3950 : {
3951 0 : zvrf->mpls_srgb.start_label = start_label;
3952 0 : zvrf->mpls_srgb.end_label = end_label;
3953 :
3954 : /* Evaluate registered FECs to see if any get a label or not. */
3955 0 : fec_evaluate(zvrf);
3956 0 : return 0;
3957 : }
3958 :
3959 : /*
3960 : * Delete global label block.
3961 : */
3962 0 : int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
3963 : {
3964 0 : zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3965 0 : zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
3966 :
3967 : /* Process registered FECs to clear their local label, if needed. */
3968 0 : fec_evaluate(zvrf);
3969 0 : return 0;
3970 : }
3971 :
3972 : /*
3973 : * Display MPLS global label block configuration (VTY command handler).
3974 : */
3975 0 : int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
3976 : {
3977 0 : if (zvrf->mpls_srgb.start_label == 0)
3978 : return 0;
3979 :
3980 0 : if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
3981 0 : || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
3982 0 : vty_out(vty, "mpls label global-block %u %u\n",
3983 : zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
3984 : }
3985 :
3986 : return 1;
3987 : }
3988 :
3989 : /*
3990 : * Called when VRF becomes inactive, cleans up information but keeps
3991 : * the table itself.
3992 : */
3993 3 : void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
3994 : {
3995 3 : struct zebra_vrf *def_zvrf;
3996 3 : afi_t afi;
3997 :
3998 6 : if (zvrf_id(zvrf) == VRF_DEFAULT)
3999 3 : hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
4000 : else {
4001 : /*
4002 : * For other vrfs, we try to remove associated LSPs; we locate
4003 : * the LSPs in the default vrf.
4004 : */
4005 0 : def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
4006 :
4007 : /* At shutdown, the default may be gone already */
4008 0 : if (def_zvrf == NULL)
4009 : return;
4010 :
4011 0 : for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4012 0 : if (zvrf->label[afi] != MPLS_LABEL_NONE)
4013 0 : lsp_uninstall(def_zvrf, zvrf->label[afi]);
4014 : }
4015 : }
4016 : }
4017 :
4018 : /*
4019 : * When a vrf label is assigned and the client goes away
4020 : * we should cleanup the vrf labels associated with
4021 : * that zclient.
4022 : */
4023 9 : void zebra_mpls_client_cleanup_vrf_label(uint8_t proto)
4024 : {
4025 9 : struct vrf *vrf;
4026 9 : struct zebra_vrf *def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
4027 :
4028 9 : if (def_zvrf == NULL)
4029 : return;
4030 :
4031 27 : RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
4032 9 : struct zebra_vrf *zvrf = vrf->info;
4033 9 : afi_t afi;
4034 :
4035 9 : if (!zvrf)
4036 0 : continue;
4037 :
4038 36 : for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4039 27 : if (zvrf->label_proto[afi] == proto
4040 9 : && zvrf->label[afi] != MPLS_LABEL_NONE)
4041 0 : lsp_uninstall(def_zvrf, zvrf->label[afi]);
4042 :
4043 : /*
4044 : * Cleanup data structures by fiat
4045 : */
4046 27 : zvrf->label_proto[afi] = 0;
4047 27 : zvrf->label[afi] = MPLS_LABEL_NONE;
4048 : }
4049 : }
4050 : }
4051 :
4052 0 : static void lsp_table_free(void *p)
4053 : {
4054 0 : struct zebra_lsp *lsp = p;
4055 :
4056 0 : lsp_free_nhlfe(lsp);
4057 :
4058 0 : XFREE(MTYPE_LSP, lsp);
4059 0 : }
4060 :
4061 : /*
4062 : * Called upon process exiting, need to delete LSP forwarding
4063 : * entries from the kernel.
4064 : * NOTE: Currently supported only for default VRF.
4065 : */
4066 3 : void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
4067 : {
4068 3 : hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
4069 3 : hash_clean(zvrf->lsp_table, lsp_table_free);
4070 3 : hash_free(zvrf->lsp_table);
4071 3 : hash_clean(zvrf->slsp_table, lsp_table_free);
4072 3 : hash_free(zvrf->slsp_table);
4073 3 : route_table_finish(zvrf->fec_table[AFI_IP]);
4074 3 : route_table_finish(zvrf->fec_table[AFI_IP6]);
4075 3 : }
4076 :
4077 : /*
4078 : * Allocate MPLS tables for this VRF and do other initialization.
4079 : * NOTE: Currently supported only for default VRF.
4080 : */
4081 3 : void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
4082 : {
4083 3 : char buffer[80];
4084 :
4085 3 : if (!zvrf)
4086 0 : return;
4087 :
4088 3 : snprintf(buffer, sizeof(buffer), "ZEBRA SLSP table: %s",
4089 3 : zvrf->vrf->name);
4090 3 : zvrf->slsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
4091 :
4092 3 : snprintf(buffer, sizeof(buffer), "ZEBRA LSP table: %s",
4093 3 : zvrf->vrf->name);
4094 3 : zvrf->lsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
4095 3 : zvrf->fec_table[AFI_IP] = route_table_init();
4096 3 : zvrf->fec_table[AFI_IP6] = route_table_init();
4097 3 : zvrf->mpls_flags = 0;
4098 3 : zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
4099 3 : zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
4100 : }
4101 :
4102 0 : void zebra_mpls_turned_on(void)
4103 : {
4104 0 : if (!mpls_enabled) {
4105 0 : mpls_processq_init();
4106 0 : mpls_enabled = true;
4107 : }
4108 :
4109 0 : hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
4110 0 : hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
4111 0 : }
4112 :
4113 : /*
4114 : * Global MPLS initialization.
4115 : */
4116 3 : void zebra_mpls_init(void)
4117 : {
4118 3 : mpls_enabled = false;
4119 3 : mpls_pw_reach_strict = false;
4120 :
4121 3 : if (mpls_kernel_init() < 0) {
4122 3 : flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
4123 : "Disabling MPLS support (no kernel support)");
4124 3 : return;
4125 : }
4126 :
4127 0 : zebra_mpls_turned_on();
4128 : }
|