]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_dplane.c
Merge pull request #7372 from mjstapp/fix_ntoa_ripd
[mirror_frr.git] / zebra / zebra_dplane.c
1 /*
2 * Zebra dataplane layer.
3 * Copyright (c) 2018 Volta Networks, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "lib/libfrr.h"
25 #include "lib/debug.h"
26 #include "lib/frratomic.h"
27 #include "lib/frr_pthread.h"
28 #include "lib/memory.h"
29 #include "lib/queue.h"
30 #include "lib/zebra.h"
31 #include "zebra/zebra_memory.h"
32 #include "zebra/zebra_router.h"
33 #include "zebra/zebra_dplane.h"
34 #include "zebra/zebra_vxlan_private.h"
35 #include "zebra/zebra_mpls.h"
36 #include "zebra/rt.h"
37 #include "zebra/debug.h"
38 #include "zebra/zebra_pbr.h"
39
40 /* Memory type for context blocks */
41 DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx")
42 DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider")
43
44 #ifndef AOK
45 # define AOK 0
46 #endif
47
48 /* Enable test dataplane provider */
49 /*#define DPLANE_TEST_PROVIDER 1 */
50
51 /* Default value for max queued incoming updates */
52 const uint32_t DPLANE_DEFAULT_MAX_QUEUED = 200;
53
54 /* Default value for new work per cycle */
55 const uint32_t DPLANE_DEFAULT_NEW_WORK = 100;
56
57 /* Validation check macro for context blocks */
58 /* #define DPLANE_DEBUG 1 */
59
60 #ifdef DPLANE_DEBUG
61
62 # define DPLANE_CTX_VALID(p) \
63 assert((p) != NULL)
64
65 #else
66
67 # define DPLANE_CTX_VALID(p)
68
69 #endif /* DPLANE_DEBUG */
70
71 /*
72 * Nexthop information captured for nexthop/nexthop group updates
73 */
74 struct dplane_nexthop_info {
75 uint32_t id;
76 uint32_t old_id;
77 afi_t afi;
78 vrf_id_t vrf_id;
79 int type;
80
81 struct nexthop_group ng;
82 struct nh_grp nh_grp[MULTIPATH_NUM];
83 uint8_t nh_grp_count;
84 };
85
86 /*
87 * Route information captured for route updates.
88 */
89 struct dplane_route_info {
90
91 /* Dest and (optional) source prefixes */
92 struct prefix zd_dest;
93 struct prefix zd_src;
94
95 afi_t zd_afi;
96 safi_t zd_safi;
97
98 int zd_type;
99 int zd_old_type;
100
101 route_tag_t zd_tag;
102 route_tag_t zd_old_tag;
103 uint32_t zd_metric;
104 uint32_t zd_old_metric;
105
106 uint16_t zd_instance;
107 uint16_t zd_old_instance;
108
109 uint8_t zd_distance;
110 uint8_t zd_old_distance;
111
112 uint32_t zd_mtu;
113 uint32_t zd_nexthop_mtu;
114
115 /* Nexthop hash entry info */
116 struct dplane_nexthop_info nhe;
117
118 /* Nexthops */
119 uint32_t zd_nhg_id;
120 struct nexthop_group zd_ng;
121
122 /* Backup nexthops (if present) */
123 struct nexthop_group backup_ng;
124
125 /* "Previous" nexthops, used only in route updates without netlink */
126 struct nexthop_group zd_old_ng;
127 struct nexthop_group old_backup_ng;
128
129 /* TODO -- use fixed array of nexthops, to avoid mallocs? */
130
131 };
132
133 /*
134 * Pseudowire info for the dataplane
135 */
136 struct dplane_pw_info {
137 int type;
138 int af;
139 int status;
140 uint32_t flags;
141 union g_addr dest;
142 mpls_label_t local_label;
143 mpls_label_t remote_label;
144
145 /* Nexthops */
146 struct nexthop_group nhg;
147
148 union pw_protocol_fields fields;
149 };
150
151 /*
152 * Interface/prefix info for the dataplane
153 */
154 struct dplane_intf_info {
155
156 uint32_t metric;
157 uint32_t flags;
158
159 #define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */
160 #define DPLANE_INTF_SECONDARY (1 << 1)
161 #define DPLANE_INTF_BROADCAST (1 << 2)
162 #define DPLANE_INTF_HAS_DEST DPLANE_INTF_CONNECTED
163 #define DPLANE_INTF_HAS_LABEL (1 << 4)
164
165 /* Interface address/prefix */
166 struct prefix prefix;
167
168 /* Dest address, for p2p, or broadcast prefix */
169 struct prefix dest_prefix;
170
171 char *label;
172 char label_buf[32];
173 };
174
175 /*
176 * EVPN MAC address info for the dataplane.
177 */
178 struct dplane_mac_info {
179 vlanid_t vid;
180 ifindex_t br_ifindex;
181 struct ethaddr mac;
182 struct in_addr vtep_ip;
183 bool is_sticky;
184 uint32_t nhg_id;
185 uint32_t update_flags;
186 };
187
188 /*
189 * Neighbor info for the dataplane
190 */
191 struct dplane_neigh_info {
192 struct ipaddr ip_addr;
193 struct ethaddr mac;
194 uint32_t flags;
195 uint16_t state;
196 uint32_t update_flags;
197 };
198
199 /*
200 * Policy based routing rule info for the dataplane
201 */
202 struct dplane_ctx_rule {
203 uint32_t priority;
204
205 /* The route table pointed by this rule */
206 uint32_t table;
207
208 /* Filter criteria */
209 uint32_t filter_bm;
210 uint32_t fwmark;
211 uint8_t dsfield;
212 struct prefix src_ip;
213 struct prefix dst_ip;
214 char ifname[INTERFACE_NAMSIZ + 1];
215 };
216
217 struct dplane_rule_info {
218 /*
219 * Originating zclient sock fd, so we can know who to send
220 * back to.
221 */
222 int sock;
223
224 int unique;
225 int seq;
226
227 struct dplane_ctx_rule new;
228 struct dplane_ctx_rule old;
229 };
230
231 /*
232 * The context block used to exchange info about route updates across
233 * the boundary between the zebra main context (and pthread) and the
234 * dataplane layer (and pthread).
235 */
236 struct zebra_dplane_ctx {
237
238 /* Operation code */
239 enum dplane_op_e zd_op;
240
241 /* Status on return */
242 enum zebra_dplane_result zd_status;
243
244 /* Dplane provider id */
245 uint32_t zd_provider;
246
247 /* Flags - used by providers, e.g. */
248 int zd_flags;
249
250 bool zd_is_update;
251
252 uint32_t zd_seq;
253 uint32_t zd_old_seq;
254
255 /* Some updates may be generated by notifications: allow the
256 * plugin to notice and ignore results from its own notifications.
257 */
258 uint32_t zd_notif_provider;
259
260 /* TODO -- internal/sub-operation status? */
261 enum zebra_dplane_result zd_remote_status;
262 enum zebra_dplane_result zd_kernel_status;
263
264 vrf_id_t zd_vrf_id;
265 uint32_t zd_table_id;
266
267 char zd_ifname[INTERFACE_NAMSIZ];
268 ifindex_t zd_ifindex;
269
270 /* Support info for different kinds of updates */
271 union {
272 struct dplane_route_info rinfo;
273 zebra_lsp_t lsp;
274 struct dplane_pw_info pw;
275 struct dplane_intf_info intf;
276 struct dplane_mac_info macinfo;
277 struct dplane_neigh_info neigh;
278 struct dplane_rule_info rule;
279 } u;
280
281 /* Namespace info, used especially for netlink kernel communication */
282 struct zebra_dplane_info zd_ns_info;
283
284 /* Embedded list linkage */
285 TAILQ_ENTRY(zebra_dplane_ctx) zd_q_entries;
286 };
287
288 /* Flag that can be set by a pre-kernel provider as a signal that an update
289 * should bypass the kernel.
290 */
291 #define DPLANE_CTX_FLAG_NO_KERNEL 0x01
292
293
294 /*
295 * Registration block for one dataplane provider.
296 */
297 struct zebra_dplane_provider {
298 /* Name */
299 char dp_name[DPLANE_PROVIDER_NAMELEN + 1];
300
301 /* Priority, for ordering among providers */
302 uint8_t dp_priority;
303
304 /* Id value */
305 uint32_t dp_id;
306
307 /* Mutex */
308 pthread_mutex_t dp_mutex;
309
310 /* Plugin-provided extra data */
311 void *dp_data;
312
313 /* Flags */
314 int dp_flags;
315
316 int (*dp_start)(struct zebra_dplane_provider *prov);
317
318 int (*dp_fp)(struct zebra_dplane_provider *prov);
319
320 int (*dp_fini)(struct zebra_dplane_provider *prov, bool early_p);
321
322 _Atomic uint32_t dp_in_counter;
323 _Atomic uint32_t dp_in_queued;
324 _Atomic uint32_t dp_in_max;
325 _Atomic uint32_t dp_out_counter;
326 _Atomic uint32_t dp_out_queued;
327 _Atomic uint32_t dp_out_max;
328 _Atomic uint32_t dp_error_counter;
329
330 /* Queue of contexts inbound to the provider */
331 struct dplane_ctx_q dp_ctx_in_q;
332
333 /* Queue of completed contexts outbound from the provider back
334 * towards the dataplane module.
335 */
336 struct dplane_ctx_q dp_ctx_out_q;
337
338 /* Embedded list linkage for provider objects */
339 TAILQ_ENTRY(zebra_dplane_provider) dp_prov_link;
340 };
341
342 /*
343 * Globals
344 */
345 static struct zebra_dplane_globals {
346 /* Mutex to control access to dataplane components */
347 pthread_mutex_t dg_mutex;
348
349 /* Results callback registered by zebra 'core' */
350 int (*dg_results_cb)(struct dplane_ctx_q *ctxlist);
351
352 /* Sentinel for beginning of shutdown */
353 volatile bool dg_is_shutdown;
354
355 /* Sentinel for end of shutdown */
356 volatile bool dg_run;
357
358 /* Update context queue inbound to the dataplane */
359 TAILQ_HEAD(zdg_ctx_q, zebra_dplane_ctx) dg_update_ctx_q;
360
361 /* Ordered list of providers */
362 TAILQ_HEAD(zdg_prov_q, zebra_dplane_provider) dg_providers_q;
363
364 /* Counter used to assign internal ids to providers */
365 uint32_t dg_provider_id;
366
367 /* Limit number of pending, unprocessed updates */
368 _Atomic uint32_t dg_max_queued_updates;
369
370 /* Control whether system route notifications should be produced. */
371 bool dg_sys_route_notifs;
372
373 /* Limit number of new updates dequeued at once, to pace an
374 * incoming burst.
375 */
376 uint32_t dg_updates_per_cycle;
377
378 _Atomic uint32_t dg_routes_in;
379 _Atomic uint32_t dg_routes_queued;
380 _Atomic uint32_t dg_routes_queued_max;
381 _Atomic uint32_t dg_route_errors;
382 _Atomic uint32_t dg_other_errors;
383
384 _Atomic uint32_t dg_nexthops_in;
385 _Atomic uint32_t dg_nexthop_errors;
386
387 _Atomic uint32_t dg_lsps_in;
388 _Atomic uint32_t dg_lsp_errors;
389
390 _Atomic uint32_t dg_pws_in;
391 _Atomic uint32_t dg_pw_errors;
392
393 _Atomic uint32_t dg_intf_addrs_in;
394 _Atomic uint32_t dg_intf_addr_errors;
395
396 _Atomic uint32_t dg_macs_in;
397 _Atomic uint32_t dg_mac_errors;
398
399 _Atomic uint32_t dg_neighs_in;
400 _Atomic uint32_t dg_neigh_errors;
401
402 _Atomic uint32_t dg_rules_in;
403 _Atomic uint32_t dg_rule_errors;
404
405 _Atomic uint32_t dg_update_yields;
406
407 /* Dataplane pthread */
408 struct frr_pthread *dg_pthread;
409
410 /* Event-delivery context 'master' for the dplane */
411 struct thread_master *dg_master;
412
413 /* Event/'thread' pointer for queued updates */
414 struct thread *dg_t_update;
415
416 /* Event pointer for pending shutdown check loop */
417 struct thread *dg_t_shutdown_check;
418
419 } zdplane_info;
420
421 /*
422 * Lock and unlock for interactions with the zebra 'core' pthread
423 */
424 #define DPLANE_LOCK() pthread_mutex_lock(&zdplane_info.dg_mutex)
425 #define DPLANE_UNLOCK() pthread_mutex_unlock(&zdplane_info.dg_mutex)
426
427
428 /*
429 * Lock and unlock for individual providers
430 */
431 #define DPLANE_PROV_LOCK(p) pthread_mutex_lock(&((p)->dp_mutex))
432 #define DPLANE_PROV_UNLOCK(p) pthread_mutex_unlock(&((p)->dp_mutex))
433
434 /* Prototypes */
435 static int dplane_thread_loop(struct thread *event);
436 static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
437 struct zebra_ns *zns);
438 static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
439 enum dplane_op_e op);
440 static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
441 enum dplane_op_e op);
442 static enum zebra_dplane_result intf_addr_update_internal(
443 const struct interface *ifp, const struct connected *ifc,
444 enum dplane_op_e op);
445 static enum zebra_dplane_result mac_update_common(
446 enum dplane_op_e op, const struct interface *ifp,
447 const struct interface *br_ifp,
448 vlanid_t vid, const struct ethaddr *mac,
449 struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
450 uint32_t update_flags);
451 static enum zebra_dplane_result neigh_update_internal(
452 enum dplane_op_e op,
453 const struct interface *ifp,
454 const struct ethaddr *mac,
455 const struct ipaddr *ip,
456 uint32_t flags, uint16_t state, uint32_t update_flags);
457
458 /*
459 * Public APIs
460 */
461
462 /* Obtain thread_master for dataplane thread */
463 struct thread_master *dplane_get_thread_master(void)
464 {
465 return zdplane_info.dg_master;
466 }
467
468 /*
469 * Allocate a dataplane update context
470 */
471 struct zebra_dplane_ctx *dplane_ctx_alloc(void)
472 {
473 struct zebra_dplane_ctx *p;
474
475 /* TODO -- just alloc'ing memory, but would like to maintain
476 * a pool
477 */
478 p = XCALLOC(MTYPE_DP_CTX, sizeof(struct zebra_dplane_ctx));
479
480 return p;
481 }
482
483 /* Enable system route notifications */
484 void dplane_enable_sys_route_notifs(void)
485 {
486 zdplane_info.dg_sys_route_notifs = true;
487 }
488
489 /*
490 * Clean up dependent/internal allocations inside a context object
491 */
492 static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
493 {
494 /*
495 * Some internal allocations may need to be freed, depending on
496 * the type of info captured in the ctx.
497 */
498 switch (ctx->zd_op) {
499 case DPLANE_OP_ROUTE_INSTALL:
500 case DPLANE_OP_ROUTE_UPDATE:
501 case DPLANE_OP_ROUTE_DELETE:
502 case DPLANE_OP_SYS_ROUTE_ADD:
503 case DPLANE_OP_SYS_ROUTE_DELETE:
504 case DPLANE_OP_ROUTE_NOTIFY:
505
506 /* Free allocated nexthops */
507 if (ctx->u.rinfo.zd_ng.nexthop) {
508 /* This deals with recursive nexthops too */
509 nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
510
511 ctx->u.rinfo.zd_ng.nexthop = NULL;
512 }
513
514 /* Free backup info also (if present) */
515 if (ctx->u.rinfo.backup_ng.nexthop) {
516 /* This deals with recursive nexthops too */
517 nexthops_free(ctx->u.rinfo.backup_ng.nexthop);
518
519 ctx->u.rinfo.backup_ng.nexthop = NULL;
520 }
521
522 if (ctx->u.rinfo.zd_old_ng.nexthop) {
523 /* This deals with recursive nexthops too */
524 nexthops_free(ctx->u.rinfo.zd_old_ng.nexthop);
525
526 ctx->u.rinfo.zd_old_ng.nexthop = NULL;
527 }
528
529 if (ctx->u.rinfo.old_backup_ng.nexthop) {
530 /* This deals with recursive nexthops too */
531 nexthops_free(ctx->u.rinfo.old_backup_ng.nexthop);
532
533 ctx->u.rinfo.old_backup_ng.nexthop = NULL;
534 }
535
536 break;
537
538 case DPLANE_OP_NH_INSTALL:
539 case DPLANE_OP_NH_UPDATE:
540 case DPLANE_OP_NH_DELETE: {
541 if (ctx->u.rinfo.nhe.ng.nexthop) {
542 /* This deals with recursive nexthops too */
543 nexthops_free(ctx->u.rinfo.nhe.ng.nexthop);
544
545 ctx->u.rinfo.nhe.ng.nexthop = NULL;
546 }
547 break;
548 }
549
550 case DPLANE_OP_LSP_INSTALL:
551 case DPLANE_OP_LSP_UPDATE:
552 case DPLANE_OP_LSP_DELETE:
553 case DPLANE_OP_LSP_NOTIFY:
554 {
555 zebra_nhlfe_t *nhlfe;
556
557 /* Unlink and free allocated NHLFEs */
558 frr_each_safe(nhlfe_list, &ctx->u.lsp.nhlfe_list, nhlfe) {
559 nhlfe_list_del(&ctx->u.lsp.nhlfe_list, nhlfe);
560 zebra_mpls_nhlfe_free(nhlfe);
561 }
562
563 /* Unlink and free allocated backup NHLFEs, if present */
564 frr_each_safe(nhlfe_list,
565 &(ctx->u.lsp.backup_nhlfe_list), nhlfe) {
566 nhlfe_list_del(&ctx->u.lsp.backup_nhlfe_list,
567 nhlfe);
568 zebra_mpls_nhlfe_free(nhlfe);
569 }
570
571 /* Clear pointers in lsp struct, in case we're caching
572 * free context structs.
573 */
574 nhlfe_list_init(&ctx->u.lsp.nhlfe_list);
575 ctx->u.lsp.best_nhlfe = NULL;
576 nhlfe_list_init(&ctx->u.lsp.backup_nhlfe_list);
577
578 break;
579 }
580
581 case DPLANE_OP_PW_INSTALL:
582 case DPLANE_OP_PW_UNINSTALL:
583 /* Free allocated nexthops */
584 if (ctx->u.pw.nhg.nexthop) {
585 /* This deals with recursive nexthops too */
586 nexthops_free(ctx->u.pw.nhg.nexthop);
587
588 ctx->u.pw.nhg.nexthop = NULL;
589 }
590 break;
591
592 case DPLANE_OP_ADDR_INSTALL:
593 case DPLANE_OP_ADDR_UNINSTALL:
594 /* Maybe free label string, if allocated */
595 if (ctx->u.intf.label != NULL &&
596 ctx->u.intf.label != ctx->u.intf.label_buf) {
597 free(ctx->u.intf.label);
598 ctx->u.intf.label = NULL;
599 }
600 break;
601
602 case DPLANE_OP_MAC_INSTALL:
603 case DPLANE_OP_MAC_DELETE:
604 case DPLANE_OP_NEIGH_INSTALL:
605 case DPLANE_OP_NEIGH_UPDATE:
606 case DPLANE_OP_NEIGH_DELETE:
607 case DPLANE_OP_VTEP_ADD:
608 case DPLANE_OP_VTEP_DELETE:
609 case DPLANE_OP_RULE_ADD:
610 case DPLANE_OP_RULE_DELETE:
611 case DPLANE_OP_RULE_UPDATE:
612 case DPLANE_OP_NEIGH_DISCOVER:
613 case DPLANE_OP_NONE:
614 break;
615 }
616 }
617
618 /*
619 * Free a dataplane results context.
620 */
621 static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
622 {
623 if (pctx == NULL)
624 return;
625
626 DPLANE_CTX_VALID(*pctx);
627
628 /* TODO -- just freeing memory, but would like to maintain
629 * a pool
630 */
631
632 /* Some internal allocations may need to be freed, depending on
633 * the type of info captured in the ctx.
634 */
635 dplane_ctx_free_internal(*pctx);
636
637 XFREE(MTYPE_DP_CTX, *pctx);
638 }
639
640 /*
641 * Reset an allocated context object for re-use. All internal allocations are
642 * freed and the context is memset.
643 */
644 void dplane_ctx_reset(struct zebra_dplane_ctx *ctx)
645 {
646 dplane_ctx_free_internal(ctx);
647 memset(ctx, 0, sizeof(*ctx));
648 }
649
650 /*
651 * Return a context block to the dplane module after processing
652 */
653 void dplane_ctx_fini(struct zebra_dplane_ctx **pctx)
654 {
655 /* TODO -- maintain pool; for now, just free */
656 dplane_ctx_free(pctx);
657 }
658
659 /* Enqueue a context block */
660 void dplane_ctx_enqueue_tail(struct dplane_ctx_q *q,
661 const struct zebra_dplane_ctx *ctx)
662 {
663 TAILQ_INSERT_TAIL(q, (struct zebra_dplane_ctx *)ctx, zd_q_entries);
664 }
665
666 /* Append a list of context blocks to another list */
667 void dplane_ctx_list_append(struct dplane_ctx_q *to_list,
668 struct dplane_ctx_q *from_list)
669 {
670 if (TAILQ_FIRST(from_list)) {
671 TAILQ_CONCAT(to_list, from_list, zd_q_entries);
672
673 /* And clear 'from' list */
674 TAILQ_INIT(from_list);
675 }
676 }
677
678 /* Dequeue a context block from the head of a list */
679 struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_q *q)
680 {
681 struct zebra_dplane_ctx *ctx = TAILQ_FIRST(q);
682
683 if (ctx)
684 TAILQ_REMOVE(q, ctx, zd_q_entries);
685
686 return ctx;
687 }
688
689 /*
690 * Accessors for information from the context object
691 */
692 enum zebra_dplane_result dplane_ctx_get_status(
693 const struct zebra_dplane_ctx *ctx)
694 {
695 DPLANE_CTX_VALID(ctx);
696
697 return ctx->zd_status;
698 }
699
700 void dplane_ctx_set_status(struct zebra_dplane_ctx *ctx,
701 enum zebra_dplane_result status)
702 {
703 DPLANE_CTX_VALID(ctx);
704
705 ctx->zd_status = status;
706 }
707
708 /* Retrieve last/current provider id */
709 uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx)
710 {
711 DPLANE_CTX_VALID(ctx);
712 return ctx->zd_provider;
713 }
714
715 /* Providers run before the kernel can control whether a kernel
716 * update should be done.
717 */
718 void dplane_ctx_set_skip_kernel(struct zebra_dplane_ctx *ctx)
719 {
720 DPLANE_CTX_VALID(ctx);
721
722 SET_FLAG(ctx->zd_flags, DPLANE_CTX_FLAG_NO_KERNEL);
723 }
724
725 bool dplane_ctx_is_skip_kernel(const struct zebra_dplane_ctx *ctx)
726 {
727 DPLANE_CTX_VALID(ctx);
728
729 return CHECK_FLAG(ctx->zd_flags, DPLANE_CTX_FLAG_NO_KERNEL);
730 }
731
732 void dplane_ctx_set_op(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
733 {
734 DPLANE_CTX_VALID(ctx);
735 ctx->zd_op = op;
736 }
737
738 enum dplane_op_e dplane_ctx_get_op(const struct zebra_dplane_ctx *ctx)
739 {
740 DPLANE_CTX_VALID(ctx);
741
742 return ctx->zd_op;
743 }
744
745 const char *dplane_op2str(enum dplane_op_e op)
746 {
747 const char *ret = "UNKNOWN";
748
749 switch (op) {
750 case DPLANE_OP_NONE:
751 ret = "NONE";
752 break;
753
754 /* Route update */
755 case DPLANE_OP_ROUTE_INSTALL:
756 ret = "ROUTE_INSTALL";
757 break;
758 case DPLANE_OP_ROUTE_UPDATE:
759 ret = "ROUTE_UPDATE";
760 break;
761 case DPLANE_OP_ROUTE_DELETE:
762 ret = "ROUTE_DELETE";
763 break;
764 case DPLANE_OP_ROUTE_NOTIFY:
765 ret = "ROUTE_NOTIFY";
766 break;
767
768 /* Nexthop update */
769 case DPLANE_OP_NH_INSTALL:
770 ret = "NH_INSTALL";
771 break;
772 case DPLANE_OP_NH_UPDATE:
773 ret = "NH_UPDATE";
774 break;
775 case DPLANE_OP_NH_DELETE:
776 ret = "NH_DELETE";
777 break;
778
779 case DPLANE_OP_LSP_INSTALL:
780 ret = "LSP_INSTALL";
781 break;
782 case DPLANE_OP_LSP_UPDATE:
783 ret = "LSP_UPDATE";
784 break;
785 case DPLANE_OP_LSP_DELETE:
786 ret = "LSP_DELETE";
787 break;
788 case DPLANE_OP_LSP_NOTIFY:
789 ret = "LSP_NOTIFY";
790 break;
791
792 case DPLANE_OP_PW_INSTALL:
793 ret = "PW_INSTALL";
794 break;
795 case DPLANE_OP_PW_UNINSTALL:
796 ret = "PW_UNINSTALL";
797 break;
798
799 case DPLANE_OP_SYS_ROUTE_ADD:
800 ret = "SYS_ROUTE_ADD";
801 break;
802 case DPLANE_OP_SYS_ROUTE_DELETE:
803 ret = "SYS_ROUTE_DEL";
804 break;
805
806 case DPLANE_OP_ADDR_INSTALL:
807 ret = "ADDR_INSTALL";
808 break;
809 case DPLANE_OP_ADDR_UNINSTALL:
810 ret = "ADDR_UNINSTALL";
811 break;
812
813 case DPLANE_OP_MAC_INSTALL:
814 ret = "MAC_INSTALL";
815 break;
816 case DPLANE_OP_MAC_DELETE:
817 ret = "MAC_DELETE";
818 break;
819
820 case DPLANE_OP_NEIGH_INSTALL:
821 ret = "NEIGH_INSTALL";
822 break;
823 case DPLANE_OP_NEIGH_UPDATE:
824 ret = "NEIGH_UPDATE";
825 break;
826 case DPLANE_OP_NEIGH_DELETE:
827 ret = "NEIGH_DELETE";
828 break;
829 case DPLANE_OP_VTEP_ADD:
830 ret = "VTEP_ADD";
831 break;
832 case DPLANE_OP_VTEP_DELETE:
833 ret = "VTEP_DELETE";
834 break;
835
836 case DPLANE_OP_RULE_ADD:
837 ret = "RULE_ADD";
838 break;
839 case DPLANE_OP_RULE_DELETE:
840 ret = "RULE_DELETE";
841 break;
842 case DPLANE_OP_RULE_UPDATE:
843 ret = "RULE_UPDATE";
844 break;
845
846 case DPLANE_OP_NEIGH_DISCOVER:
847 ret = "NEIGH_DISCOVER";
848 break;
849 }
850
851 return ret;
852 }
853
854 const char *dplane_res2str(enum zebra_dplane_result res)
855 {
856 const char *ret = "<Unknown>";
857
858 switch (res) {
859 case ZEBRA_DPLANE_REQUEST_FAILURE:
860 ret = "FAILURE";
861 break;
862 case ZEBRA_DPLANE_REQUEST_QUEUED:
863 ret = "QUEUED";
864 break;
865 case ZEBRA_DPLANE_REQUEST_SUCCESS:
866 ret = "SUCCESS";
867 break;
868 }
869
870 return ret;
871 }
872
873 void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx,
874 const struct prefix *dest)
875 {
876 DPLANE_CTX_VALID(ctx);
877
878 prefix_copy(&(ctx->u.rinfo.zd_dest), dest);
879 }
880
881 const struct prefix *dplane_ctx_get_dest(const struct zebra_dplane_ctx *ctx)
882 {
883 DPLANE_CTX_VALID(ctx);
884
885 return &(ctx->u.rinfo.zd_dest);
886 }
887
888 void dplane_ctx_set_src(struct zebra_dplane_ctx *ctx, const struct prefix *src)
889 {
890 DPLANE_CTX_VALID(ctx);
891
892 if (src)
893 prefix_copy(&(ctx->u.rinfo.zd_src), src);
894 else
895 memset(&(ctx->u.rinfo.zd_src), 0, sizeof(struct prefix));
896 }
897
898 /* Source prefix is a little special - return NULL for "no src prefix" */
899 const struct prefix *dplane_ctx_get_src(const struct zebra_dplane_ctx *ctx)
900 {
901 DPLANE_CTX_VALID(ctx);
902
903 if (ctx->u.rinfo.zd_src.prefixlen == 0 &&
904 IN6_IS_ADDR_UNSPECIFIED(&(ctx->u.rinfo.zd_src.u.prefix6))) {
905 return NULL;
906 } else {
907 return &(ctx->u.rinfo.zd_src);
908 }
909 }
910
911 bool dplane_ctx_is_update(const struct zebra_dplane_ctx *ctx)
912 {
913 DPLANE_CTX_VALID(ctx);
914
915 return ctx->zd_is_update;
916 }
917
918 uint32_t dplane_ctx_get_seq(const struct zebra_dplane_ctx *ctx)
919 {
920 DPLANE_CTX_VALID(ctx);
921
922 return ctx->zd_seq;
923 }
924
925 uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx)
926 {
927 DPLANE_CTX_VALID(ctx);
928
929 return ctx->zd_old_seq;
930 }
931
932 void dplane_ctx_set_vrf(struct zebra_dplane_ctx *ctx, vrf_id_t vrf)
933 {
934 DPLANE_CTX_VALID(ctx);
935
936 ctx->zd_vrf_id = vrf;
937 }
938
939 vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
940 {
941 DPLANE_CTX_VALID(ctx);
942
943 return ctx->zd_vrf_id;
944 }
945
946 bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx)
947 {
948 DPLANE_CTX_VALID(ctx);
949
950 return (ctx->zd_notif_provider != 0);
951 }
952
953 uint32_t dplane_ctx_get_notif_provider(const struct zebra_dplane_ctx *ctx)
954 {
955 DPLANE_CTX_VALID(ctx);
956
957 return ctx->zd_notif_provider;
958 }
959
960 void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx,
961 uint32_t id)
962 {
963 DPLANE_CTX_VALID(ctx);
964
965 ctx->zd_notif_provider = id;
966 }
967
968 const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx)
969 {
970 DPLANE_CTX_VALID(ctx);
971
972 return ctx->zd_ifname;
973 }
974
975 void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname)
976 {
977 DPLANE_CTX_VALID(ctx);
978
979 if (!ifname)
980 return;
981
982 strlcpy(ctx->zd_ifname, ifname, sizeof(ctx->zd_ifname));
983 }
984
985 ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx)
986 {
987 DPLANE_CTX_VALID(ctx);
988
989 return ctx->zd_ifindex;
990 }
991
992 void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type)
993 {
994 DPLANE_CTX_VALID(ctx);
995
996 ctx->u.rinfo.zd_type = type;
997 }
998
999 int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx)
1000 {
1001 DPLANE_CTX_VALID(ctx);
1002
1003 return ctx->u.rinfo.zd_type;
1004 }
1005
1006 int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx)
1007 {
1008 DPLANE_CTX_VALID(ctx);
1009
1010 return ctx->u.rinfo.zd_old_type;
1011 }
1012
1013 void dplane_ctx_set_afi(struct zebra_dplane_ctx *ctx, afi_t afi)
1014 {
1015 DPLANE_CTX_VALID(ctx);
1016
1017 ctx->u.rinfo.zd_afi = afi;
1018 }
1019
1020 afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx)
1021 {
1022 DPLANE_CTX_VALID(ctx);
1023
1024 return ctx->u.rinfo.zd_afi;
1025 }
1026
1027 void dplane_ctx_set_safi(struct zebra_dplane_ctx *ctx, safi_t safi)
1028 {
1029 DPLANE_CTX_VALID(ctx);
1030
1031 ctx->u.rinfo.zd_safi = safi;
1032 }
1033
1034 safi_t dplane_ctx_get_safi(const struct zebra_dplane_ctx *ctx)
1035 {
1036 DPLANE_CTX_VALID(ctx);
1037
1038 return ctx->u.rinfo.zd_safi;
1039 }
1040
1041 void dplane_ctx_set_table(struct zebra_dplane_ctx *ctx, uint32_t table)
1042 {
1043 DPLANE_CTX_VALID(ctx);
1044
1045 ctx->zd_table_id = table;
1046 }
1047
1048 uint32_t dplane_ctx_get_table(const struct zebra_dplane_ctx *ctx)
1049 {
1050 DPLANE_CTX_VALID(ctx);
1051
1052 return ctx->zd_table_id;
1053 }
1054
1055 route_tag_t dplane_ctx_get_tag(const struct zebra_dplane_ctx *ctx)
1056 {
1057 DPLANE_CTX_VALID(ctx);
1058
1059 return ctx->u.rinfo.zd_tag;
1060 }
1061
1062 void dplane_ctx_set_tag(struct zebra_dplane_ctx *ctx, route_tag_t tag)
1063 {
1064 DPLANE_CTX_VALID(ctx);
1065
1066 ctx->u.rinfo.zd_tag = tag;
1067 }
1068
1069 route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx)
1070 {
1071 DPLANE_CTX_VALID(ctx);
1072
1073 return ctx->u.rinfo.zd_old_tag;
1074 }
1075
1076 uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx)
1077 {
1078 DPLANE_CTX_VALID(ctx);
1079
1080 return ctx->u.rinfo.zd_instance;
1081 }
1082
1083 void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance)
1084 {
1085 DPLANE_CTX_VALID(ctx);
1086
1087 ctx->u.rinfo.zd_instance = instance;
1088 }
1089
1090 uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx)
1091 {
1092 DPLANE_CTX_VALID(ctx);
1093
1094 return ctx->u.rinfo.zd_old_instance;
1095 }
1096
1097 uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx)
1098 {
1099 DPLANE_CTX_VALID(ctx);
1100
1101 return ctx->u.rinfo.zd_metric;
1102 }
1103
1104 uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx)
1105 {
1106 DPLANE_CTX_VALID(ctx);
1107
1108 return ctx->u.rinfo.zd_old_metric;
1109 }
1110
1111 uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx)
1112 {
1113 DPLANE_CTX_VALID(ctx);
1114
1115 return ctx->u.rinfo.zd_mtu;
1116 }
1117
1118 uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx)
1119 {
1120 DPLANE_CTX_VALID(ctx);
1121
1122 return ctx->u.rinfo.zd_nexthop_mtu;
1123 }
1124
1125 uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx)
1126 {
1127 DPLANE_CTX_VALID(ctx);
1128
1129 return ctx->u.rinfo.zd_distance;
1130 }
1131
1132 void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance)
1133 {
1134 DPLANE_CTX_VALID(ctx);
1135
1136 ctx->u.rinfo.zd_distance = distance;
1137 }
1138
1139 uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
1140 {
1141 DPLANE_CTX_VALID(ctx);
1142
1143 return ctx->u.rinfo.zd_old_distance;
1144 }
1145
1146 /*
1147 * Set the nexthops associated with a context: note that processing code
1148 * may well expect that nexthops are in canonical (sorted) order, so we
1149 * will enforce that here.
1150 */
1151 void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
1152 {
1153 DPLANE_CTX_VALID(ctx);
1154
1155 if (ctx->u.rinfo.zd_ng.nexthop) {
1156 nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
1157 ctx->u.rinfo.zd_ng.nexthop = NULL;
1158 }
1159 nexthop_group_copy_nh_sorted(&(ctx->u.rinfo.zd_ng), nh);
1160 }
1161
1162 /*
1163 * Set the list of backup nexthops; their ordering is preserved (they're not
1164 * re-sorted.)
1165 */
1166 void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx,
1167 const struct nexthop_group *nhg)
1168 {
1169 struct nexthop *nh, *last_nh, *nexthop;
1170
1171 DPLANE_CTX_VALID(ctx);
1172
1173 if (ctx->u.rinfo.backup_ng.nexthop) {
1174 nexthops_free(ctx->u.rinfo.backup_ng.nexthop);
1175 ctx->u.rinfo.backup_ng.nexthop = NULL;
1176 }
1177
1178 last_nh = NULL;
1179
1180 /* Be careful to preserve the order of the backup list */
1181 for (nh = nhg->nexthop; nh; nh = nh->next) {
1182 nexthop = nexthop_dup(nh, NULL);
1183
1184 if (last_nh)
1185 NEXTHOP_APPEND(last_nh, nexthop);
1186 else
1187 ctx->u.rinfo.backup_ng.nexthop = nexthop;
1188
1189 last_nh = nexthop;
1190 }
1191 }
1192
1193 uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx)
1194 {
1195 DPLANE_CTX_VALID(ctx);
1196 return ctx->u.rinfo.zd_nhg_id;
1197 }
1198
1199 const struct nexthop_group *dplane_ctx_get_ng(
1200 const struct zebra_dplane_ctx *ctx)
1201 {
1202 DPLANE_CTX_VALID(ctx);
1203
1204 return &(ctx->u.rinfo.zd_ng);
1205 }
1206
1207 const struct nexthop_group *
1208 dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx)
1209 {
1210 DPLANE_CTX_VALID(ctx);
1211
1212 return &(ctx->u.rinfo.backup_ng);
1213 }
1214
1215 const struct nexthop_group *
1216 dplane_ctx_get_old_ng(const struct zebra_dplane_ctx *ctx)
1217 {
1218 DPLANE_CTX_VALID(ctx);
1219
1220 return &(ctx->u.rinfo.zd_old_ng);
1221 }
1222
1223 const struct nexthop_group *
1224 dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx)
1225 {
1226 DPLANE_CTX_VALID(ctx);
1227
1228 return &(ctx->u.rinfo.old_backup_ng);
1229 }
1230
1231 const struct zebra_dplane_info *dplane_ctx_get_ns(
1232 const struct zebra_dplane_ctx *ctx)
1233 {
1234 DPLANE_CTX_VALID(ctx);
1235
1236 return &(ctx->zd_ns_info);
1237 }
1238
1239 /* Accessors for nexthop information */
1240 uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx)
1241 {
1242 DPLANE_CTX_VALID(ctx);
1243 return ctx->u.rinfo.nhe.id;
1244 }
1245
1246 uint32_t dplane_ctx_get_old_nhe_id(const struct zebra_dplane_ctx *ctx)
1247 {
1248 DPLANE_CTX_VALID(ctx);
1249 return ctx->u.rinfo.nhe.old_id;
1250 }
1251
1252 afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx)
1253 {
1254 DPLANE_CTX_VALID(ctx);
1255 return ctx->u.rinfo.nhe.afi;
1256 }
1257
1258 vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx)
1259 {
1260 DPLANE_CTX_VALID(ctx);
1261 return ctx->u.rinfo.nhe.vrf_id;
1262 }
1263
1264 int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx)
1265 {
1266 DPLANE_CTX_VALID(ctx);
1267 return ctx->u.rinfo.nhe.type;
1268 }
1269
1270 const struct nexthop_group *
1271 dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx)
1272 {
1273 DPLANE_CTX_VALID(ctx);
1274 return &(ctx->u.rinfo.nhe.ng);
1275 }
1276
1277 const struct nh_grp *
1278 dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx)
1279 {
1280 DPLANE_CTX_VALID(ctx);
1281 return ctx->u.rinfo.nhe.nh_grp;
1282 }
1283
1284 uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx)
1285 {
1286 DPLANE_CTX_VALID(ctx);
1287 return ctx->u.rinfo.nhe.nh_grp_count;
1288 }
1289
1290 /* Accessors for LSP information */
1291
1292 mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx)
1293 {
1294 DPLANE_CTX_VALID(ctx);
1295
1296 return ctx->u.lsp.ile.in_label;
1297 }
1298
1299 void dplane_ctx_set_in_label(struct zebra_dplane_ctx *ctx, mpls_label_t label)
1300 {
1301 DPLANE_CTX_VALID(ctx);
1302
1303 ctx->u.lsp.ile.in_label = label;
1304 }
1305
1306 uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx)
1307 {
1308 DPLANE_CTX_VALID(ctx);
1309
1310 return ctx->u.lsp.addr_family;
1311 }
1312
1313 void dplane_ctx_set_addr_family(struct zebra_dplane_ctx *ctx,
1314 uint8_t family)
1315 {
1316 DPLANE_CTX_VALID(ctx);
1317
1318 ctx->u.lsp.addr_family = family;
1319 }
1320
1321 uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx)
1322 {
1323 DPLANE_CTX_VALID(ctx);
1324
1325 return ctx->u.lsp.flags;
1326 }
1327
1328 void dplane_ctx_set_lsp_flags(struct zebra_dplane_ctx *ctx,
1329 uint32_t flags)
1330 {
1331 DPLANE_CTX_VALID(ctx);
1332
1333 ctx->u.lsp.flags = flags;
1334 }
1335
1336 const struct nhlfe_list_head *dplane_ctx_get_nhlfe_list(
1337 const struct zebra_dplane_ctx *ctx)
1338 {
1339 DPLANE_CTX_VALID(ctx);
1340 return &(ctx->u.lsp.nhlfe_list);
1341 }
1342
1343 const struct nhlfe_list_head *dplane_ctx_get_backup_nhlfe_list(
1344 const struct zebra_dplane_ctx *ctx)
1345 {
1346 DPLANE_CTX_VALID(ctx);
1347 return &(ctx->u.lsp.backup_nhlfe_list);
1348 }
1349
1350 zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
1351 enum lsp_types_t lsp_type,
1352 enum nexthop_types_t nh_type,
1353 const union g_addr *gate,
1354 ifindex_t ifindex,
1355 uint8_t num_labels,
1356 mpls_label_t *out_labels)
1357 {
1358 zebra_nhlfe_t *nhlfe;
1359
1360 DPLANE_CTX_VALID(ctx);
1361
1362 nhlfe = zebra_mpls_lsp_add_nhlfe(&(ctx->u.lsp),
1363 lsp_type, nh_type, gate,
1364 ifindex, num_labels, out_labels);
1365
1366 return nhlfe;
1367 }
1368
1369 zebra_nhlfe_t *dplane_ctx_add_backup_nhlfe(struct zebra_dplane_ctx *ctx,
1370 enum lsp_types_t lsp_type,
1371 enum nexthop_types_t nh_type,
1372 const union g_addr *gate,
1373 ifindex_t ifindex,
1374 uint8_t num_labels,
1375 mpls_label_t *out_labels)
1376 {
1377 zebra_nhlfe_t *nhlfe;
1378
1379 DPLANE_CTX_VALID(ctx);
1380
1381 nhlfe = zebra_mpls_lsp_add_backup_nhlfe(&(ctx->u.lsp),
1382 lsp_type, nh_type, gate,
1383 ifindex, num_labels,
1384 out_labels);
1385
1386 return nhlfe;
1387 }
1388
1389 const zebra_nhlfe_t *
1390 dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx)
1391 {
1392 DPLANE_CTX_VALID(ctx);
1393
1394 return ctx->u.lsp.best_nhlfe;
1395 }
1396
1397 const zebra_nhlfe_t *
1398 dplane_ctx_set_best_nhlfe(struct zebra_dplane_ctx *ctx,
1399 zebra_nhlfe_t *nhlfe)
1400 {
1401 DPLANE_CTX_VALID(ctx);
1402
1403 ctx->u.lsp.best_nhlfe = nhlfe;
1404 return ctx->u.lsp.best_nhlfe;
1405 }
1406
1407 uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx)
1408 {
1409 DPLANE_CTX_VALID(ctx);
1410
1411 return ctx->u.lsp.num_ecmp;
1412 }
1413
1414 mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx)
1415 {
1416 DPLANE_CTX_VALID(ctx);
1417
1418 return ctx->u.pw.local_label;
1419 }
1420
1421 mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx)
1422 {
1423 DPLANE_CTX_VALID(ctx);
1424
1425 return ctx->u.pw.remote_label;
1426 }
1427
1428 int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx)
1429 {
1430 DPLANE_CTX_VALID(ctx);
1431
1432 return ctx->u.pw.type;
1433 }
1434
1435 int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx)
1436 {
1437 DPLANE_CTX_VALID(ctx);
1438
1439 return ctx->u.pw.af;
1440 }
1441
1442 uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx)
1443 {
1444 DPLANE_CTX_VALID(ctx);
1445
1446 return ctx->u.pw.flags;
1447 }
1448
1449 int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx)
1450 {
1451 DPLANE_CTX_VALID(ctx);
1452
1453 return ctx->u.pw.status;
1454 }
1455
1456 void dplane_ctx_set_pw_status(struct zebra_dplane_ctx *ctx, int status)
1457 {
1458 DPLANE_CTX_VALID(ctx);
1459
1460 ctx->u.pw.status = status;
1461 }
1462
1463 const union g_addr *dplane_ctx_get_pw_dest(
1464 const struct zebra_dplane_ctx *ctx)
1465 {
1466 DPLANE_CTX_VALID(ctx);
1467
1468 return &(ctx->u.pw.dest);
1469 }
1470
1471 const union pw_protocol_fields *dplane_ctx_get_pw_proto(
1472 const struct zebra_dplane_ctx *ctx)
1473 {
1474 DPLANE_CTX_VALID(ctx);
1475
1476 return &(ctx->u.pw.fields);
1477 }
1478
1479 const struct nexthop_group *
1480 dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx)
1481 {
1482 DPLANE_CTX_VALID(ctx);
1483
1484 return &(ctx->u.pw.nhg);
1485 }
1486
1487 /* Accessors for interface information */
1488 uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx)
1489 {
1490 DPLANE_CTX_VALID(ctx);
1491
1492 return ctx->u.intf.metric;
1493 }
1494
1495 /* Is interface addr p2p? */
1496 bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
1497 {
1498 DPLANE_CTX_VALID(ctx);
1499
1500 return (ctx->u.intf.flags & DPLANE_INTF_CONNECTED);
1501 }
1502
1503 bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx)
1504 {
1505 DPLANE_CTX_VALID(ctx);
1506
1507 return (ctx->u.intf.flags & DPLANE_INTF_SECONDARY);
1508 }
1509
1510 bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx)
1511 {
1512 DPLANE_CTX_VALID(ctx);
1513
1514 return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST);
1515 }
1516
1517 const struct prefix *dplane_ctx_get_intf_addr(
1518 const struct zebra_dplane_ctx *ctx)
1519 {
1520 DPLANE_CTX_VALID(ctx);
1521
1522 return &(ctx->u.intf.prefix);
1523 }
1524
1525 bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx)
1526 {
1527 DPLANE_CTX_VALID(ctx);
1528
1529 return (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST);
1530 }
1531
1532 const struct prefix *dplane_ctx_get_intf_dest(
1533 const struct zebra_dplane_ctx *ctx)
1534 {
1535 DPLANE_CTX_VALID(ctx);
1536
1537 if (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST)
1538 return &(ctx->u.intf.dest_prefix);
1539 else
1540 return NULL;
1541 }
1542
1543 bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx)
1544 {
1545 DPLANE_CTX_VALID(ctx);
1546
1547 return (ctx->u.intf.flags & DPLANE_INTF_HAS_LABEL);
1548 }
1549
1550 const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx)
1551 {
1552 DPLANE_CTX_VALID(ctx);
1553
1554 return ctx->u.intf.label;
1555 }
1556
1557 /* Accessors for MAC information */
1558 vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx)
1559 {
1560 DPLANE_CTX_VALID(ctx);
1561 return ctx->u.macinfo.vid;
1562 }
1563
1564 bool dplane_ctx_mac_is_sticky(const struct zebra_dplane_ctx *ctx)
1565 {
1566 DPLANE_CTX_VALID(ctx);
1567 return ctx->u.macinfo.is_sticky;
1568 }
1569
1570 uint32_t dplane_ctx_mac_get_nhg_id(const struct zebra_dplane_ctx *ctx)
1571 {
1572 DPLANE_CTX_VALID(ctx);
1573 return ctx->u.macinfo.nhg_id;
1574 }
1575
1576 uint32_t dplane_ctx_mac_get_update_flags(const struct zebra_dplane_ctx *ctx)
1577 {
1578 DPLANE_CTX_VALID(ctx);
1579 return ctx->u.macinfo.update_flags;
1580 }
1581
1582 const struct ethaddr *dplane_ctx_mac_get_addr(
1583 const struct zebra_dplane_ctx *ctx)
1584 {
1585 DPLANE_CTX_VALID(ctx);
1586 return &(ctx->u.macinfo.mac);
1587 }
1588
1589 const struct in_addr *dplane_ctx_mac_get_vtep_ip(
1590 const struct zebra_dplane_ctx *ctx)
1591 {
1592 DPLANE_CTX_VALID(ctx);
1593 return &(ctx->u.macinfo.vtep_ip);
1594 }
1595
1596 ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx)
1597 {
1598 DPLANE_CTX_VALID(ctx);
1599 return ctx->u.macinfo.br_ifindex;
1600 }
1601
1602 /* Accessors for neighbor information */
1603 const struct ipaddr *dplane_ctx_neigh_get_ipaddr(
1604 const struct zebra_dplane_ctx *ctx)
1605 {
1606 DPLANE_CTX_VALID(ctx);
1607 return &(ctx->u.neigh.ip_addr);
1608 }
1609
1610 const struct ethaddr *dplane_ctx_neigh_get_mac(
1611 const struct zebra_dplane_ctx *ctx)
1612 {
1613 DPLANE_CTX_VALID(ctx);
1614 return &(ctx->u.neigh.mac);
1615 }
1616
1617 uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx)
1618 {
1619 DPLANE_CTX_VALID(ctx);
1620 return ctx->u.neigh.flags;
1621 }
1622
1623 uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx)
1624 {
1625 DPLANE_CTX_VALID(ctx);
1626 return ctx->u.neigh.state;
1627 }
1628
1629 uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx)
1630 {
1631 DPLANE_CTX_VALID(ctx);
1632 return ctx->u.neigh.update_flags;
1633 }
1634
1635 /* Accessors for PBR rule information */
1636 int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx)
1637 {
1638 DPLANE_CTX_VALID(ctx);
1639
1640 return ctx->u.rule.sock;
1641 }
1642
1643 const char *dplane_ctx_rule_get_ifname(const struct zebra_dplane_ctx *ctx)
1644 {
1645 DPLANE_CTX_VALID(ctx);
1646
1647 return ctx->u.rule.new.ifname;
1648 }
1649
1650 int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx)
1651 {
1652 DPLANE_CTX_VALID(ctx);
1653
1654 return ctx->u.rule.unique;
1655 }
1656
1657 int dplane_ctx_rule_get_seq(const struct zebra_dplane_ctx *ctx)
1658 {
1659 DPLANE_CTX_VALID(ctx);
1660
1661 return ctx->u.rule.seq;
1662 }
1663
1664 uint32_t dplane_ctx_rule_get_priority(const struct zebra_dplane_ctx *ctx)
1665 {
1666 DPLANE_CTX_VALID(ctx);
1667
1668 return ctx->u.rule.new.priority;
1669 }
1670
1671 uint32_t dplane_ctx_rule_get_old_priority(const struct zebra_dplane_ctx *ctx)
1672 {
1673 DPLANE_CTX_VALID(ctx);
1674
1675 return ctx->u.rule.old.priority;
1676 }
1677
1678 uint32_t dplane_ctx_rule_get_table(const struct zebra_dplane_ctx *ctx)
1679 {
1680 DPLANE_CTX_VALID(ctx);
1681
1682 return ctx->u.rule.new.table;
1683 }
1684
1685 uint32_t dplane_ctx_rule_get_old_table(const struct zebra_dplane_ctx *ctx)
1686 {
1687 DPLANE_CTX_VALID(ctx);
1688
1689 return ctx->u.rule.old.table;
1690 }
1691
1692 uint32_t dplane_ctx_rule_get_filter_bm(const struct zebra_dplane_ctx *ctx)
1693 {
1694 DPLANE_CTX_VALID(ctx);
1695
1696 return ctx->u.rule.new.filter_bm;
1697 }
1698
1699 uint32_t dplane_ctx_rule_get_old_filter_bm(const struct zebra_dplane_ctx *ctx)
1700 {
1701 DPLANE_CTX_VALID(ctx);
1702
1703 return ctx->u.rule.old.filter_bm;
1704 }
1705
1706 uint32_t dplane_ctx_rule_get_fwmark(const struct zebra_dplane_ctx *ctx)
1707 {
1708 DPLANE_CTX_VALID(ctx);
1709
1710 return ctx->u.rule.new.fwmark;
1711 }
1712
1713 uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx)
1714 {
1715 DPLANE_CTX_VALID(ctx);
1716
1717 return ctx->u.rule.old.fwmark;
1718 }
1719
1720 uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx)
1721 {
1722 DPLANE_CTX_VALID(ctx);
1723
1724 return ctx->u.rule.new.dsfield;
1725 }
1726
1727 uint8_t dplane_ctx_rule_get_old_dsfield(const struct zebra_dplane_ctx *ctx)
1728 {
1729 DPLANE_CTX_VALID(ctx);
1730
1731 return ctx->u.rule.old.dsfield;
1732 }
1733
1734 const struct prefix *
1735 dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx)
1736 {
1737 DPLANE_CTX_VALID(ctx);
1738
1739 return &(ctx->u.rule.new.src_ip);
1740 }
1741
1742 const struct prefix *
1743 dplane_ctx_rule_get_old_src_ip(const struct zebra_dplane_ctx *ctx)
1744 {
1745 DPLANE_CTX_VALID(ctx);
1746
1747 return &(ctx->u.rule.old.src_ip);
1748 }
1749
1750 const struct prefix *
1751 dplane_ctx_rule_get_dst_ip(const struct zebra_dplane_ctx *ctx)
1752 {
1753 DPLANE_CTX_VALID(ctx);
1754
1755 return &(ctx->u.rule.new.dst_ip);
1756 }
1757
1758 const struct prefix *
1759 dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx)
1760 {
1761 DPLANE_CTX_VALID(ctx);
1762
1763 return &(ctx->u.rule.old.dst_ip);
1764 }
1765
1766 /*
1767 * End of dplane context accessors
1768 */
1769
1770
1771 /*
1772 * Retrieve the limit on the number of pending, unprocessed updates.
1773 */
1774 uint32_t dplane_get_in_queue_limit(void)
1775 {
1776 return atomic_load_explicit(&zdplane_info.dg_max_queued_updates,
1777 memory_order_relaxed);
1778 }
1779
1780 /*
1781 * Configure limit on the number of pending, queued updates.
1782 */
1783 void dplane_set_in_queue_limit(uint32_t limit, bool set)
1784 {
1785 /* Reset to default on 'unset' */
1786 if (!set)
1787 limit = DPLANE_DEFAULT_MAX_QUEUED;
1788
1789 atomic_store_explicit(&zdplane_info.dg_max_queued_updates, limit,
1790 memory_order_relaxed);
1791 }
1792
1793 /*
1794 * Retrieve the current queue depth of incoming, unprocessed updates
1795 */
1796 uint32_t dplane_get_in_queue_len(void)
1797 {
1798 return atomic_load_explicit(&zdplane_info.dg_routes_queued,
1799 memory_order_seq_cst);
1800 }
1801
1802 /*
1803 * Common dataplane context init with zebra namespace info.
1804 */
1805 static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
1806 struct zebra_ns *zns,
1807 bool is_update)
1808 {
1809 dplane_info_from_zns(&(ctx->zd_ns_info), zns);
1810
1811 #if defined(HAVE_NETLINK)
1812 /* Increment message counter after copying to context struct - may need
1813 * two messages in some 'update' cases.
1814 */
1815 if (is_update)
1816 zns->netlink_dplane.seq += 2;
1817 else
1818 zns->netlink_dplane.seq++;
1819 #endif /* HAVE_NETLINK */
1820
1821 return AOK;
1822 }
1823
1824 /*
1825 * Initialize a context block for a route update from zebra data structs.
1826 */
1827 int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
1828 struct route_node *rn, struct route_entry *re)
1829 {
1830 int ret = EINVAL;
1831 const struct route_table *table = NULL;
1832 const struct rib_table_info *info;
1833 const struct prefix *p, *src_p;
1834 struct zebra_ns *zns;
1835 struct zebra_vrf *zvrf;
1836 struct nexthop *nexthop;
1837 zebra_l3vni_t *zl3vni;
1838
1839 if (!ctx || !rn || !re)
1840 goto done;
1841
1842 ctx->zd_op = op;
1843 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
1844
1845 ctx->u.rinfo.zd_type = re->type;
1846 ctx->u.rinfo.zd_old_type = re->type;
1847
1848 /* Prefixes: dest, and optional source */
1849 srcdest_rnode_prefixes(rn, &p, &src_p);
1850
1851 prefix_copy(&(ctx->u.rinfo.zd_dest), p);
1852
1853 if (src_p)
1854 prefix_copy(&(ctx->u.rinfo.zd_src), src_p);
1855 else
1856 memset(&(ctx->u.rinfo.zd_src), 0, sizeof(ctx->u.rinfo.zd_src));
1857
1858 ctx->zd_table_id = re->table;
1859
1860 ctx->u.rinfo.zd_metric = re->metric;
1861 ctx->u.rinfo.zd_old_metric = re->metric;
1862 ctx->zd_vrf_id = re->vrf_id;
1863 ctx->u.rinfo.zd_mtu = re->mtu;
1864 ctx->u.rinfo.zd_nexthop_mtu = re->nexthop_mtu;
1865 ctx->u.rinfo.zd_instance = re->instance;
1866 ctx->u.rinfo.zd_tag = re->tag;
1867 ctx->u.rinfo.zd_old_tag = re->tag;
1868 ctx->u.rinfo.zd_distance = re->distance;
1869
1870 table = srcdest_rnode_table(rn);
1871 info = table->info;
1872
1873 ctx->u.rinfo.zd_afi = info->afi;
1874 ctx->u.rinfo.zd_safi = info->safi;
1875
1876 /* Copy nexthops; recursive info is included too */
1877 copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop),
1878 re->nhe->nhg.nexthop, NULL);
1879 ctx->u.rinfo.zd_nhg_id = re->nhe->id;
1880
1881 /* Copy backup nexthop info, if present */
1882 if (re->nhe->backup_info && re->nhe->backup_info->nhe) {
1883 copy_nexthops(&(ctx->u.rinfo.backup_ng.nexthop),
1884 re->nhe->backup_info->nhe->nhg.nexthop, NULL);
1885 }
1886
1887 /*
1888 * Ensure that the dplane nexthops' flags are clear and copy
1889 * encapsulation information.
1890 */
1891 for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) {
1892 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1893
1894 /* Check for available encapsulations. */
1895 if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
1896 continue;
1897
1898 zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
1899 if (zl3vni && is_l3vni_oper_up(zl3vni)) {
1900 nexthop->nh_encap_type = NET_VXLAN;
1901 nexthop->nh_encap.vni = zl3vni->vni;
1902 }
1903 }
1904
1905 /* Don't need some info when capturing a system notification */
1906 if (op == DPLANE_OP_SYS_ROUTE_ADD ||
1907 op == DPLANE_OP_SYS_ROUTE_DELETE) {
1908 ret = AOK;
1909 goto done;
1910 }
1911
1912 /* Extract ns info - can't use pointers to 'core' structs */
1913 zvrf = vrf_info_lookup(re->vrf_id);
1914 zns = zvrf->zns;
1915 dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
1916
1917 #ifdef HAVE_NETLINK
1918 {
1919 struct nhg_hash_entry *nhe = zebra_nhg_resolve(re->nhe);
1920
1921 ctx->u.rinfo.nhe.id = nhe->id;
1922 ctx->u.rinfo.nhe.old_id = 0;
1923 /*
1924 * Check if the nhe is installed/queued before doing anything
1925 * with this route.
1926 *
1927 * If its a delete we only use the prefix anyway, so this only
1928 * matters for INSTALL/UPDATE.
1929 */
1930 if (zebra_nhg_kernel_nexthops_enabled()
1931 && (((op == DPLANE_OP_ROUTE_INSTALL)
1932 || (op == DPLANE_OP_ROUTE_UPDATE))
1933 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
1934 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED))) {
1935 ret = ENOENT;
1936 goto done;
1937 }
1938 }
1939 #endif /* HAVE_NETLINK */
1940
1941 /* Trying out the sequence number idea, so we can try to detect
1942 * when a result is stale.
1943 */
1944 re->dplane_sequence = zebra_router_get_next_sequence();
1945 ctx->zd_seq = re->dplane_sequence;
1946
1947 ret = AOK;
1948
1949 done:
1950 return ret;
1951 }
1952
1953 /**
1954 * dplane_ctx_nexthop_init() - Initialize a context block for a nexthop update
1955 *
1956 * @ctx: Dataplane context to init
1957 * @op: Operation being performed
1958 * @nhe: Nexthop group hash entry
1959 *
1960 * Return: Result status
1961 */
1962 int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
1963 struct nhg_hash_entry *nhe)
1964 {
1965 struct zebra_vrf *zvrf = NULL;
1966 struct zebra_ns *zns = NULL;
1967 int ret = EINVAL;
1968
1969 if (!ctx || !nhe)
1970 goto done;
1971
1972 ctx->zd_op = op;
1973 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
1974
1975 /* Copy over nhe info */
1976 ctx->u.rinfo.nhe.id = nhe->id;
1977 ctx->u.rinfo.nhe.afi = nhe->afi;
1978 ctx->u.rinfo.nhe.vrf_id = nhe->vrf_id;
1979 ctx->u.rinfo.nhe.type = nhe->type;
1980
1981 nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), &(nhe->nhg));
1982
1983 /* If this is a group, convert it to a grp array of ids */
1984 if (!zebra_nhg_depends_is_empty(nhe)
1985 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE))
1986 ctx->u.rinfo.nhe.nh_grp_count = zebra_nhg_nhe2grp(
1987 ctx->u.rinfo.nhe.nh_grp, nhe, MULTIPATH_NUM);
1988
1989 zvrf = vrf_info_lookup(nhe->vrf_id);
1990
1991 /*
1992 * Fallback to default namespace if the vrf got ripped out from under
1993 * us.
1994 */
1995 zns = zvrf ? zvrf->zns : zebra_ns_lookup(NS_DEFAULT);
1996
1997 /*
1998 * TODO: Might not need to mark this as an update, since
1999 * it probably won't require two messages
2000 */
2001 dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE));
2002 ctx->zd_is_update = (op == DPLANE_OP_NH_UPDATE);
2003
2004 ret = AOK;
2005
2006 done:
2007 return ret;
2008 }
2009
2010 /*
2011 * Capture information for an LSP update in a dplane context.
2012 */
2013 int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
2014 zebra_lsp_t *lsp)
2015 {
2016 int ret = AOK;
2017 zebra_nhlfe_t *nhlfe, *new_nhlfe;
2018
2019 ctx->zd_op = op;
2020 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2021
2022 /* Capture namespace info */
2023 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
2024 (op == DPLANE_OP_LSP_UPDATE));
2025 ctx->zd_is_update = (op == DPLANE_OP_LSP_UPDATE);
2026
2027 memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp));
2028
2029 nhlfe_list_init(&(ctx->u.lsp.nhlfe_list));
2030 nhlfe_list_init(&(ctx->u.lsp.backup_nhlfe_list));
2031
2032 /* This may be called to create/init a dplane context, not necessarily
2033 * to copy an lsp object.
2034 */
2035 if (lsp == NULL) {
2036 ret = AOK;
2037 goto done;
2038 }
2039
2040 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
2041 zlog_debug("init dplane ctx %s: in-label %u ecmp# %d",
2042 dplane_op2str(op), lsp->ile.in_label,
2043 lsp->num_ecmp);
2044
2045 ctx->u.lsp.ile = lsp->ile;
2046 ctx->u.lsp.addr_family = lsp->addr_family;
2047 ctx->u.lsp.num_ecmp = lsp->num_ecmp;
2048 ctx->u.lsp.flags = lsp->flags;
2049
2050 /* Copy source LSP's nhlfes, and capture 'best' nhlfe */
2051 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
2052 /* Not sure if this is meaningful... */
2053 if (nhlfe->nexthop == NULL)
2054 continue;
2055
2056 new_nhlfe = zebra_mpls_lsp_add_nh(&(ctx->u.lsp), nhlfe->type,
2057 nhlfe->nexthop);
2058 if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) {
2059 ret = ENOMEM;
2060 break;
2061 }
2062
2063 /* Need to copy flags and backup info too */
2064 new_nhlfe->flags = nhlfe->flags;
2065 new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
2066
2067 if (CHECK_FLAG(new_nhlfe->nexthop->flags,
2068 NEXTHOP_FLAG_HAS_BACKUP)) {
2069 new_nhlfe->nexthop->backup_num =
2070 nhlfe->nexthop->backup_num;
2071 memcpy(new_nhlfe->nexthop->backup_idx,
2072 nhlfe->nexthop->backup_idx,
2073 new_nhlfe->nexthop->backup_num);
2074 }
2075
2076 if (nhlfe == lsp->best_nhlfe)
2077 ctx->u.lsp.best_nhlfe = new_nhlfe;
2078 }
2079
2080 if (ret != AOK)
2081 goto done;
2082
2083 /* Capture backup nhlfes/nexthops */
2084 frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
2085 /* Not sure if this is meaningful... */
2086 if (nhlfe->nexthop == NULL)
2087 continue;
2088
2089 new_nhlfe = zebra_mpls_lsp_add_backup_nh(&(ctx->u.lsp),
2090 nhlfe->type,
2091 nhlfe->nexthop);
2092 if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) {
2093 ret = ENOMEM;
2094 break;
2095 }
2096
2097 /* Need to copy flags too */
2098 new_nhlfe->flags = nhlfe->flags;
2099 new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
2100 }
2101
2102 /* On error the ctx will be cleaned-up, so we don't need to
2103 * deal with any allocated nhlfe or nexthop structs here.
2104 */
2105 done:
2106
2107 return ret;
2108 }
2109
2110 /*
2111 * Capture information for an LSP update in a dplane context.
2112 */
2113 static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
2114 enum dplane_op_e op,
2115 struct zebra_pw *pw)
2116 {
2117 struct prefix p;
2118 afi_t afi;
2119 struct route_table *table;
2120 struct route_node *rn;
2121 struct route_entry *re;
2122 const struct nexthop_group *nhg;
2123
2124 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
2125 zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
2126 dplane_op2str(op), pw->ifname, pw->local_label,
2127 pw->remote_label);
2128
2129 ctx->zd_op = op;
2130 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2131
2132 /* Capture namespace info: no netlink support as of 12/18,
2133 * but just in case...
2134 */
2135 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
2136
2137 memset(&ctx->u.pw, 0, sizeof(ctx->u.pw));
2138
2139 /* This name appears to be c-string, so we use string copy. */
2140 strlcpy(ctx->zd_ifname, pw->ifname, sizeof(ctx->zd_ifname));
2141
2142 ctx->zd_vrf_id = pw->vrf_id;
2143 ctx->zd_ifindex = pw->ifindex;
2144 ctx->u.pw.type = pw->type;
2145 ctx->u.pw.af = pw->af;
2146 ctx->u.pw.local_label = pw->local_label;
2147 ctx->u.pw.remote_label = pw->remote_label;
2148 ctx->u.pw.flags = pw->flags;
2149
2150 ctx->u.pw.dest = pw->nexthop;
2151
2152 ctx->u.pw.fields = pw->data;
2153
2154 /* Capture nexthop info for the pw destination. We need to look
2155 * up and use zebra datastructs, but we're running in the zebra
2156 * pthread here so that should be ok.
2157 */
2158 memcpy(&p.u, &pw->nexthop, sizeof(pw->nexthop));
2159 p.family = pw->af;
2160 p.prefixlen = ((pw->af == AF_INET) ?
2161 IPV4_MAX_PREFIXLEN : IPV6_MAX_PREFIXLEN);
2162
2163 afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6;
2164 table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id);
2165 if (table) {
2166 rn = route_node_match(table, &p);
2167 if (rn) {
2168 RNODE_FOREACH_RE(rn, re) {
2169 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
2170 break;
2171 }
2172
2173 if (re) {
2174 nhg = rib_get_fib_nhg(re);
2175 if (nhg && nhg->nexthop)
2176 copy_nexthops(&(ctx->u.pw.nhg.nexthop),
2177 nhg->nexthop, NULL);
2178
2179 /* Include any installed backup nexthops */
2180 nhg = rib_get_fib_backup_nhg(re);
2181 if (nhg && nhg->nexthop)
2182 copy_nexthops(&(ctx->u.pw.nhg.nexthop),
2183 nhg->nexthop, NULL);
2184 }
2185 route_unlock_node(rn);
2186 }
2187 }
2188
2189 return AOK;
2190 }
2191
2192 /**
2193 * dplane_ctx_rule_init_single() - Initialize a dataplane representation of a
2194 * PBR rule.
2195 *
2196 * @dplane_rule: Dataplane internal representation of a rule
2197 * @rule: PBR rule
2198 */
2199 static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
2200 struct zebra_pbr_rule *rule)
2201 {
2202 dplane_rule->priority = rule->rule.priority;
2203 dplane_rule->table = rule->rule.action.table;
2204
2205 dplane_rule->filter_bm = rule->rule.filter.filter_bm;
2206 dplane_rule->fwmark = rule->rule.filter.fwmark;
2207 dplane_rule->dsfield = rule->rule.filter.dsfield;
2208 prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip);
2209 prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip);
2210 strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ);
2211 }
2212
2213 /**
2214 * dplane_ctx_rule_init() - Initialize a context block for a PBR rule update.
2215 *
2216 * @ctx: Dataplane context to init
2217 * @op: Operation being performed
2218 * @new_rule: PBR rule
2219 *
2220 * Return: Result status
2221 */
2222 static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx,
2223 enum dplane_op_e op,
2224 struct zebra_pbr_rule *new_rule,
2225 struct zebra_pbr_rule *old_rule)
2226 {
2227 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
2228 zlog_debug(
2229 "init dplane ctx %s: IF %s Prio %u Fwmark %u Src %pFX Dst %pFX Table %u",
2230 dplane_op2str(op), new_rule->ifname,
2231 new_rule->rule.priority, new_rule->rule.filter.fwmark,
2232 &new_rule->rule.filter.src_ip,
2233 &new_rule->rule.filter.dst_ip,
2234 new_rule->rule.action.table);
2235
2236 ctx->zd_op = op;
2237 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2238
2239 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
2240 op == DPLANE_OP_RULE_UPDATE);
2241 ctx->zd_is_update = (op == DPLANE_OP_RULE_UPDATE);
2242
2243 ctx->zd_vrf_id = new_rule->vrf_id;
2244 memcpy(ctx->zd_ifname, new_rule->ifname, sizeof(new_rule->ifname));
2245
2246 ctx->u.rule.sock = new_rule->sock;
2247 ctx->u.rule.unique = new_rule->rule.unique;
2248 ctx->u.rule.seq = new_rule->rule.seq;
2249
2250 dplane_ctx_rule_init_single(&ctx->u.rule.new, new_rule);
2251 if (op == DPLANE_OP_RULE_UPDATE)
2252 dplane_ctx_rule_init_single(&ctx->u.rule.old, old_rule);
2253
2254 return AOK;
2255 }
2256
2257 /*
2258 * Enqueue a new update,
2259 * and ensure an event is active for the dataplane pthread.
2260 */
2261 static int dplane_update_enqueue(struct zebra_dplane_ctx *ctx)
2262 {
2263 int ret = EINVAL;
2264 uint32_t high, curr;
2265
2266 /* Enqueue for processing by the dataplane pthread */
2267 DPLANE_LOCK();
2268 {
2269 TAILQ_INSERT_TAIL(&zdplane_info.dg_update_ctx_q, ctx,
2270 zd_q_entries);
2271 }
2272 DPLANE_UNLOCK();
2273
2274 curr = atomic_fetch_add_explicit(
2275 &(zdplane_info.dg_routes_queued),
2276 1, memory_order_seq_cst);
2277
2278 curr++; /* We got the pre-incremented value */
2279
2280 /* Maybe update high-water counter also */
2281 high = atomic_load_explicit(&zdplane_info.dg_routes_queued_max,
2282 memory_order_seq_cst);
2283 while (high < curr) {
2284 if (atomic_compare_exchange_weak_explicit(
2285 &zdplane_info.dg_routes_queued_max,
2286 &high, curr,
2287 memory_order_seq_cst,
2288 memory_order_seq_cst))
2289 break;
2290 }
2291
2292 /* Ensure that an event for the dataplane thread is active */
2293 ret = dplane_provider_work_ready();
2294
2295 return ret;
2296 }
2297
2298 /*
2299 * Utility that prepares a route update and enqueues it for processing
2300 */
2301 static enum zebra_dplane_result
2302 dplane_route_update_internal(struct route_node *rn,
2303 struct route_entry *re,
2304 struct route_entry *old_re,
2305 enum dplane_op_e op)
2306 {
2307 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2308 int ret = EINVAL;
2309 struct zebra_dplane_ctx *ctx = NULL;
2310
2311 /* Obtain context block */
2312 ctx = dplane_ctx_alloc();
2313
2314 /* Init context with info from zebra data structs */
2315 ret = dplane_ctx_route_init(ctx, op, rn, re);
2316 if (ret == AOK) {
2317 /* Capture some extra info for update case
2318 * where there's a different 'old' route.
2319 */
2320 if ((op == DPLANE_OP_ROUTE_UPDATE) &&
2321 old_re && (old_re != re)) {
2322 ctx->zd_is_update = true;
2323
2324 old_re->dplane_sequence =
2325 zebra_router_get_next_sequence();
2326 ctx->zd_old_seq = old_re->dplane_sequence;
2327
2328 ctx->u.rinfo.zd_old_tag = old_re->tag;
2329 ctx->u.rinfo.zd_old_type = old_re->type;
2330 ctx->u.rinfo.zd_old_instance = old_re->instance;
2331 ctx->u.rinfo.zd_old_distance = old_re->distance;
2332 ctx->u.rinfo.zd_old_metric = old_re->metric;
2333 ctx->u.rinfo.nhe.old_id = old_re->nhe->id;
2334
2335 #ifndef HAVE_NETLINK
2336 /* For bsd, capture previous re's nexthops too, sigh.
2337 * We'll need these to do per-nexthop deletes.
2338 */
2339 copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
2340 old_re->nhe->nhg.nexthop, NULL);
2341
2342 if (zebra_nhg_get_backup_nhg(old_re->nhe) != NULL) {
2343 struct nexthop_group *nhg;
2344 struct nexthop **nh;
2345
2346 nhg = zebra_nhg_get_backup_nhg(old_re->nhe);
2347 nh = &(ctx->u.rinfo.old_backup_ng.nexthop);
2348
2349 if (nhg->nexthop)
2350 copy_nexthops(nh, nhg->nexthop, NULL);
2351 }
2352 #endif /* !HAVE_NETLINK */
2353 }
2354
2355 /*
2356 * If the old and new context type, and nexthop group id
2357 * are the same there is no need to send down a route replace
2358 * as that we know we have sent a nexthop group replace
2359 * or an upper level protocol has sent us the exact
2360 * same route again.
2361 */
2362 if ((dplane_ctx_get_type(ctx) == dplane_ctx_get_old_type(ctx))
2363 && (dplane_ctx_get_nhe_id(ctx)
2364 == dplane_ctx_get_old_nhe_id(ctx))
2365 && (dplane_ctx_get_nhe_id(ctx) >= ZEBRA_NHG_PROTO_LOWER)) {
2366 struct nexthop *nexthop;
2367
2368 if (IS_ZEBRA_DEBUG_DPLANE)
2369 zlog_debug(
2370 "%s: Ignoring Route exactly the same",
2371 __func__);
2372
2373 for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
2374 nexthop)) {
2375 if (CHECK_FLAG(nexthop->flags,
2376 NEXTHOP_FLAG_RECURSIVE))
2377 continue;
2378
2379 if (CHECK_FLAG(nexthop->flags,
2380 NEXTHOP_FLAG_ACTIVE))
2381 SET_FLAG(nexthop->flags,
2382 NEXTHOP_FLAG_FIB);
2383 }
2384
2385 dplane_ctx_free(&ctx);
2386 return ZEBRA_DPLANE_REQUEST_SUCCESS;
2387 }
2388
2389 /* Enqueue context for processing */
2390 ret = dplane_update_enqueue(ctx);
2391 }
2392
2393 /* Update counter */
2394 atomic_fetch_add_explicit(&zdplane_info.dg_routes_in, 1,
2395 memory_order_relaxed);
2396
2397 if (ret == AOK)
2398 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2399 else {
2400 atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, 1,
2401 memory_order_relaxed);
2402 if (ctx)
2403 dplane_ctx_free(&ctx);
2404 }
2405
2406 return result;
2407 }
2408
2409 /**
2410 * dplane_nexthop_update_internal() - Helper for enqueuing nexthop changes
2411 *
2412 * @nhe: Nexthop group hash entry where the change occured
2413 * @op: The operation to be enqued
2414 *
2415 * Return: Result of the change
2416 */
2417 static enum zebra_dplane_result
2418 dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op)
2419 {
2420 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2421 int ret = EINVAL;
2422 struct zebra_dplane_ctx *ctx = NULL;
2423
2424 /* Obtain context block */
2425 ctx = dplane_ctx_alloc();
2426 if (!ctx) {
2427 ret = ENOMEM;
2428 goto done;
2429 }
2430
2431 ret = dplane_ctx_nexthop_init(ctx, op, nhe);
2432 if (ret == AOK)
2433 ret = dplane_update_enqueue(ctx);
2434
2435 done:
2436 /* Update counter */
2437 atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, 1,
2438 memory_order_relaxed);
2439
2440 if (ret == AOK)
2441 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2442 else {
2443 atomic_fetch_add_explicit(&zdplane_info.dg_nexthop_errors, 1,
2444 memory_order_relaxed);
2445 if (ctx)
2446 dplane_ctx_free(&ctx);
2447 }
2448
2449 return result;
2450 }
2451
2452 /*
2453 * Enqueue a route 'add' for the dataplane.
2454 */
2455 enum zebra_dplane_result dplane_route_add(struct route_node *rn,
2456 struct route_entry *re)
2457 {
2458 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
2459
2460 if (rn == NULL || re == NULL)
2461 goto done;
2462
2463 ret = dplane_route_update_internal(rn, re, NULL,
2464 DPLANE_OP_ROUTE_INSTALL);
2465
2466 done:
2467 return ret;
2468 }
2469
2470 /*
2471 * Enqueue a route update for the dataplane.
2472 */
2473 enum zebra_dplane_result dplane_route_update(struct route_node *rn,
2474 struct route_entry *re,
2475 struct route_entry *old_re)
2476 {
2477 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
2478
2479 if (rn == NULL || re == NULL)
2480 goto done;
2481
2482 ret = dplane_route_update_internal(rn, re, old_re,
2483 DPLANE_OP_ROUTE_UPDATE);
2484 done:
2485 return ret;
2486 }
2487
2488 /*
2489 * Enqueue a route removal for the dataplane.
2490 */
2491 enum zebra_dplane_result dplane_route_delete(struct route_node *rn,
2492 struct route_entry *re)
2493 {
2494 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
2495
2496 if (rn == NULL || re == NULL)
2497 goto done;
2498
2499 ret = dplane_route_update_internal(rn, re, NULL,
2500 DPLANE_OP_ROUTE_DELETE);
2501
2502 done:
2503 return ret;
2504 }
2505
2506 /*
2507 * Notify the dplane when system/connected routes change.
2508 */
2509 enum zebra_dplane_result dplane_sys_route_add(struct route_node *rn,
2510 struct route_entry *re)
2511 {
2512 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
2513
2514 /* Ignore this event unless a provider plugin has requested it. */
2515 if (!zdplane_info.dg_sys_route_notifs) {
2516 ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
2517 goto done;
2518 }
2519
2520 if (rn == NULL || re == NULL)
2521 goto done;
2522
2523 ret = dplane_route_update_internal(rn, re, NULL,
2524 DPLANE_OP_SYS_ROUTE_ADD);
2525
2526 done:
2527 return ret;
2528 }
2529
2530 /*
2531 * Notify the dplane when system/connected routes are deleted.
2532 */
2533 enum zebra_dplane_result dplane_sys_route_del(struct route_node *rn,
2534 struct route_entry *re)
2535 {
2536 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
2537
2538 /* Ignore this event unless a provider plugin has requested it. */
2539 if (!zdplane_info.dg_sys_route_notifs) {
2540 ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
2541 goto done;
2542 }
2543
2544 if (rn == NULL || re == NULL)
2545 goto done;
2546
2547 ret = dplane_route_update_internal(rn, re, NULL,
2548 DPLANE_OP_SYS_ROUTE_DELETE);
2549
2550 done:
2551 return ret;
2552 }
2553
2554 /*
2555 * Update from an async notification, to bring other fibs up-to-date.
2556 */
2557 enum zebra_dplane_result
2558 dplane_route_notif_update(struct route_node *rn,
2559 struct route_entry *re,
2560 enum dplane_op_e op,
2561 struct zebra_dplane_ctx *ctx)
2562 {
2563 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2564 int ret = EINVAL;
2565 struct zebra_dplane_ctx *new_ctx = NULL;
2566 struct nexthop *nexthop;
2567 struct nexthop_group *nhg;
2568
2569 if (rn == NULL || re == NULL)
2570 goto done;
2571
2572 new_ctx = dplane_ctx_alloc();
2573 if (new_ctx == NULL)
2574 goto done;
2575
2576 /* Init context with info from zebra data structs */
2577 dplane_ctx_route_init(new_ctx, op, rn, re);
2578
2579 /* For add/update, need to adjust the nexthops so that we match
2580 * the notification state, which may not be the route-entry/RIB
2581 * state.
2582 */
2583 if (op == DPLANE_OP_ROUTE_UPDATE ||
2584 op == DPLANE_OP_ROUTE_INSTALL) {
2585
2586 nexthops_free(new_ctx->u.rinfo.zd_ng.nexthop);
2587 new_ctx->u.rinfo.zd_ng.nexthop = NULL;
2588
2589 nhg = rib_get_fib_nhg(re);
2590 if (nhg && nhg->nexthop)
2591 copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
2592 nhg->nexthop, NULL);
2593
2594 /* Check for installed backup nexthops also */
2595 nhg = rib_get_fib_backup_nhg(re);
2596 if (nhg && nhg->nexthop) {
2597 copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
2598 nhg->nexthop, NULL);
2599 }
2600
2601 for (ALL_NEXTHOPS(new_ctx->u.rinfo.zd_ng, nexthop))
2602 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
2603
2604 }
2605
2606 /* Capture info about the source of the notification, in 'ctx' */
2607 dplane_ctx_set_notif_provider(new_ctx,
2608 dplane_ctx_get_notif_provider(ctx));
2609
2610 ret = dplane_update_enqueue(new_ctx);
2611
2612 done:
2613 if (ret == AOK)
2614 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2615 else if (new_ctx)
2616 dplane_ctx_free(&new_ctx);
2617
2618 return result;
2619 }
2620
2621 /*
2622 * Enqueue a nexthop add for the dataplane.
2623 */
2624 enum zebra_dplane_result dplane_nexthop_add(struct nhg_hash_entry *nhe)
2625 {
2626 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
2627
2628 if (nhe)
2629 ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_INSTALL);
2630 return ret;
2631 }
2632
2633 /*
2634 * Enqueue a nexthop update for the dataplane.
2635 *
2636 * Might not need this func since zebra's nexthop objects should be immutable?
2637 */
2638 enum zebra_dplane_result dplane_nexthop_update(struct nhg_hash_entry *nhe)
2639 {
2640 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
2641
2642 if (nhe)
2643 ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_UPDATE);
2644 return ret;
2645 }
2646
2647 /*
2648 * Enqueue a nexthop removal for the dataplane.
2649 */
2650 enum zebra_dplane_result dplane_nexthop_delete(struct nhg_hash_entry *nhe)
2651 {
2652 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
2653
2654 if (nhe)
2655 ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_DELETE);
2656
2657 return ret;
2658 }
2659
2660 /*
2661 * Enqueue LSP add for the dataplane.
2662 */
2663 enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp)
2664 {
2665 enum zebra_dplane_result ret =
2666 lsp_update_internal(lsp, DPLANE_OP_LSP_INSTALL);
2667
2668 return ret;
2669 }
2670
2671 /*
2672 * Enqueue LSP update for the dataplane.
2673 */
2674 enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp)
2675 {
2676 enum zebra_dplane_result ret =
2677 lsp_update_internal(lsp, DPLANE_OP_LSP_UPDATE);
2678
2679 return ret;
2680 }
2681
2682 /*
2683 * Enqueue LSP delete for the dataplane.
2684 */
2685 enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp)
2686 {
2687 enum zebra_dplane_result ret =
2688 lsp_update_internal(lsp, DPLANE_OP_LSP_DELETE);
2689
2690 return ret;
2691 }
2692
2693 /* Update or un-install resulting from an async notification */
2694 enum zebra_dplane_result
2695 dplane_lsp_notif_update(zebra_lsp_t *lsp,
2696 enum dplane_op_e op,
2697 struct zebra_dplane_ctx *notif_ctx)
2698 {
2699 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2700 int ret = EINVAL;
2701 struct zebra_dplane_ctx *ctx = NULL;
2702 struct nhlfe_list_head *head;
2703 zebra_nhlfe_t *nhlfe, *new_nhlfe;
2704
2705 /* Obtain context block */
2706 ctx = dplane_ctx_alloc();
2707 if (ctx == NULL) {
2708 ret = ENOMEM;
2709 goto done;
2710 }
2711
2712 /* Copy info from zebra LSP */
2713 ret = dplane_ctx_lsp_init(ctx, op, lsp);
2714 if (ret != AOK)
2715 goto done;
2716
2717 /* Add any installed backup nhlfes */
2718 head = &(ctx->u.lsp.backup_nhlfe_list);
2719 frr_each(nhlfe_list, head, nhlfe) {
2720
2721 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) &&
2722 CHECK_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_FIB)) {
2723 new_nhlfe = zebra_mpls_lsp_add_nh(&(ctx->u.lsp),
2724 nhlfe->type,
2725 nhlfe->nexthop);
2726
2727 /* Need to copy flags too */
2728 new_nhlfe->flags = nhlfe->flags;
2729 new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
2730 }
2731 }
2732
2733 /* Capture info about the source of the notification */
2734 dplane_ctx_set_notif_provider(
2735 ctx,
2736 dplane_ctx_get_notif_provider(notif_ctx));
2737
2738 ret = dplane_update_enqueue(ctx);
2739
2740 done:
2741 /* Update counter */
2742 atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
2743 memory_order_relaxed);
2744
2745 if (ret == AOK)
2746 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2747 else {
2748 atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
2749 memory_order_relaxed);
2750 if (ctx)
2751 dplane_ctx_free(&ctx);
2752 }
2753 return result;
2754 }
2755
2756 /*
2757 * Enqueue pseudowire install for the dataplane.
2758 */
2759 enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw)
2760 {
2761 return pw_update_internal(pw, DPLANE_OP_PW_INSTALL);
2762 }
2763
2764 /*
2765 * Enqueue pseudowire un-install for the dataplane.
2766 */
2767 enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw)
2768 {
2769 return pw_update_internal(pw, DPLANE_OP_PW_UNINSTALL);
2770 }
2771
2772 /*
2773 * Common internal LSP update utility
2774 */
2775 static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
2776 enum dplane_op_e op)
2777 {
2778 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2779 int ret = EINVAL;
2780 struct zebra_dplane_ctx *ctx = NULL;
2781
2782 /* Obtain context block */
2783 ctx = dplane_ctx_alloc();
2784
2785 ret = dplane_ctx_lsp_init(ctx, op, lsp);
2786 if (ret != AOK)
2787 goto done;
2788
2789 ret = dplane_update_enqueue(ctx);
2790
2791 done:
2792 /* Update counter */
2793 atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
2794 memory_order_relaxed);
2795
2796 if (ret == AOK)
2797 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2798 else {
2799 atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
2800 memory_order_relaxed);
2801 dplane_ctx_free(&ctx);
2802 }
2803
2804 return result;
2805 }
2806
2807 /*
2808 * Internal, common handler for pseudowire updates.
2809 */
2810 static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
2811 enum dplane_op_e op)
2812 {
2813 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2814 int ret;
2815 struct zebra_dplane_ctx *ctx = NULL;
2816
2817 ctx = dplane_ctx_alloc();
2818
2819 ret = dplane_ctx_pw_init(ctx, op, pw);
2820 if (ret != AOK)
2821 goto done;
2822
2823 ret = dplane_update_enqueue(ctx);
2824
2825 done:
2826 /* Update counter */
2827 atomic_fetch_add_explicit(&zdplane_info.dg_pws_in, 1,
2828 memory_order_relaxed);
2829
2830 if (ret == AOK)
2831 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2832 else {
2833 atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
2834 memory_order_relaxed);
2835 dplane_ctx_free(&ctx);
2836 }
2837
2838 return result;
2839 }
2840
2841 /*
2842 * Enqueue interface address add for the dataplane.
2843 */
2844 enum zebra_dplane_result dplane_intf_addr_set(const struct interface *ifp,
2845 const struct connected *ifc)
2846 {
2847 #if !defined(HAVE_NETLINK) && defined(HAVE_STRUCT_IFALIASREQ)
2848 /* Extra checks for this OS path. */
2849
2850 /* Don't configure PtP addresses on broadcast ifs or reverse */
2851 if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) {
2852 if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_DPLANE)
2853 zlog_debug("Failed to set intf addr: mismatch p2p and connected");
2854
2855 return ZEBRA_DPLANE_REQUEST_FAILURE;
2856 }
2857
2858 /* Ensure that no existing installed v4 route conflicts with
2859 * the new interface prefix. This check must be done in the
2860 * zebra pthread context, and any route delete (if needed)
2861 * is enqueued before the interface address programming attempt.
2862 */
2863 if (ifc->address->family == AF_INET) {
2864 struct prefix_ipv4 *p;
2865
2866 p = (struct prefix_ipv4 *)ifc->address;
2867 rib_lookup_and_pushup(p, ifp->vrf_id);
2868 }
2869 #endif
2870
2871 return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_INSTALL);
2872 }
2873
2874 /*
2875 * Enqueue interface address remove/uninstall for the dataplane.
2876 */
2877 enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
2878 const struct connected *ifc)
2879 {
2880 return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_UNINSTALL);
2881 }
2882
2883 static enum zebra_dplane_result intf_addr_update_internal(
2884 const struct interface *ifp, const struct connected *ifc,
2885 enum dplane_op_e op)
2886 {
2887 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2888 int ret = EINVAL;
2889 struct zebra_dplane_ctx *ctx = NULL;
2890 struct zebra_ns *zns;
2891
2892 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
2893 zlog_debug("init intf ctx %s: idx %d, addr %u:%pFX",
2894 dplane_op2str(op), ifp->ifindex, ifp->vrf_id,
2895 ifc->address);
2896
2897 ctx = dplane_ctx_alloc();
2898
2899 ctx->zd_op = op;
2900 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2901 ctx->zd_vrf_id = ifp->vrf_id;
2902
2903 zns = zebra_ns_lookup(ifp->vrf_id);
2904 dplane_ctx_ns_init(ctx, zns, false);
2905
2906 /* Init the interface-addr-specific area */
2907 memset(&ctx->u.intf, 0, sizeof(ctx->u.intf));
2908
2909 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
2910 ctx->zd_ifindex = ifp->ifindex;
2911 ctx->u.intf.prefix = *(ifc->address);
2912
2913 if (if_is_broadcast(ifp))
2914 ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
2915
2916 if (CONNECTED_PEER(ifc)) {
2917 ctx->u.intf.dest_prefix = *(ifc->destination);
2918 ctx->u.intf.flags |=
2919 (DPLANE_INTF_CONNECTED | DPLANE_INTF_HAS_DEST);
2920 }
2921
2922 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
2923 ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
2924
2925 if (ifc->label) {
2926 size_t len;
2927
2928 ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
2929
2930 /* Use embedded buffer if it's adequate; else allocate. */
2931 len = strlen(ifc->label);
2932
2933 if (len < sizeof(ctx->u.intf.label_buf)) {
2934 strlcpy(ctx->u.intf.label_buf, ifc->label,
2935 sizeof(ctx->u.intf.label_buf));
2936 ctx->u.intf.label = ctx->u.intf.label_buf;
2937 } else {
2938 ctx->u.intf.label = strdup(ifc->label);
2939 }
2940 }
2941
2942 ret = dplane_update_enqueue(ctx);
2943
2944 /* Increment counter */
2945 atomic_fetch_add_explicit(&zdplane_info.dg_intf_addrs_in, 1,
2946 memory_order_relaxed);
2947
2948 if (ret == AOK)
2949 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2950 else {
2951 /* Error counter */
2952 atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors,
2953 1, memory_order_relaxed);
2954 dplane_ctx_free(&ctx);
2955 }
2956
2957 return result;
2958 }
2959
2960 /*
2961 * Enqueue vxlan/evpn mac add (or update).
2962 */
2963 enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
2964 const struct interface *bridge_ifp,
2965 vlanid_t vid,
2966 const struct ethaddr *mac,
2967 struct in_addr vtep_ip,
2968 bool sticky,
2969 uint32_t nhg_id,
2970 bool was_static)
2971 {
2972 enum zebra_dplane_result result;
2973 uint32_t update_flags = 0;
2974
2975 update_flags |= DPLANE_MAC_REMOTE;
2976 if (was_static)
2977 update_flags |= DPLANE_MAC_WAS_STATIC;
2978
2979 /* Use common helper api */
2980 result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
2981 vid, mac, vtep_ip, sticky, nhg_id, update_flags);
2982 return result;
2983 }
2984
2985 /*
2986 * Enqueue vxlan/evpn mac delete.
2987 */
2988 enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
2989 const struct interface *bridge_ifp,
2990 vlanid_t vid,
2991 const struct ethaddr *mac,
2992 struct in_addr vtep_ip)
2993 {
2994 enum zebra_dplane_result result;
2995 uint32_t update_flags = 0;
2996
2997 update_flags |= DPLANE_MAC_REMOTE;
2998
2999 /* Use common helper api */
3000 result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
3001 vid, mac, vtep_ip, false, 0, update_flags);
3002 return result;
3003 }
3004
3005 /*
3006 * Enqueue local mac add (or update).
3007 */
3008 enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp,
3009 const struct interface *bridge_ifp,
3010 vlanid_t vid,
3011 const struct ethaddr *mac,
3012 bool sticky,
3013 uint32_t set_static,
3014 uint32_t set_inactive)
3015 {
3016 enum zebra_dplane_result result;
3017 uint32_t update_flags = 0;
3018 struct in_addr vtep_ip;
3019
3020 if (set_static)
3021 update_flags |= DPLANE_MAC_SET_STATIC;
3022
3023 if (set_inactive)
3024 update_flags |= DPLANE_MAC_SET_INACTIVE;
3025
3026 vtep_ip.s_addr = 0;
3027
3028 /* Use common helper api */
3029 result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
3030 vid, mac, vtep_ip, sticky, 0,
3031 update_flags);
3032 return result;
3033 }
3034
3035 /*
3036 * Public api to init an empty context - either newly-allocated or
3037 * reset/cleared - for a MAC update.
3038 */
3039 void dplane_mac_init(struct zebra_dplane_ctx *ctx,
3040 const struct interface *ifp,
3041 const struct interface *br_ifp,
3042 vlanid_t vid,
3043 const struct ethaddr *mac,
3044 struct in_addr vtep_ip,
3045 bool sticky,
3046 uint32_t nhg_id,
3047 uint32_t update_flags)
3048 {
3049 struct zebra_ns *zns;
3050
3051 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3052 ctx->zd_vrf_id = ifp->vrf_id;
3053
3054 zns = zebra_ns_lookup(ifp->vrf_id);
3055 dplane_ctx_ns_init(ctx, zns, false);
3056
3057 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
3058 ctx->zd_ifindex = ifp->ifindex;
3059
3060 /* Init the mac-specific data area */
3061 memset(&ctx->u.macinfo, 0, sizeof(ctx->u.macinfo));
3062
3063 ctx->u.macinfo.br_ifindex = br_ifp->ifindex;
3064 ctx->u.macinfo.vtep_ip = vtep_ip;
3065 ctx->u.macinfo.mac = *mac;
3066 ctx->u.macinfo.vid = vid;
3067 ctx->u.macinfo.is_sticky = sticky;
3068 ctx->u.macinfo.nhg_id = nhg_id;
3069 ctx->u.macinfo.update_flags = update_flags;
3070 }
3071
3072 /*
3073 * Common helper api for MAC address/vxlan updates
3074 */
3075 static enum zebra_dplane_result
3076 mac_update_common(enum dplane_op_e op,
3077 const struct interface *ifp,
3078 const struct interface *br_ifp,
3079 vlanid_t vid,
3080 const struct ethaddr *mac,
3081 struct in_addr vtep_ip,
3082 bool sticky,
3083 uint32_t nhg_id,
3084 uint32_t update_flags)
3085 {
3086 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3087 int ret;
3088 struct zebra_dplane_ctx *ctx = NULL;
3089
3090 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
3091 char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN];
3092
3093 zlog_debug("init mac ctx %s: mac %s, ifp %s, vtep %s",
3094 dplane_op2str(op),
3095 prefix_mac2str(mac, buf1, sizeof(buf1)),
3096 ifp->name,
3097 inet_ntop(AF_INET, &vtep_ip, buf2, sizeof(buf2)));
3098 }
3099
3100 ctx = dplane_ctx_alloc();
3101 ctx->zd_op = op;
3102
3103 /* Common init for the ctx */
3104 dplane_mac_init(ctx, ifp, br_ifp, vid, mac, vtep_ip, sticky,
3105 nhg_id, update_flags);
3106
3107 /* Enqueue for processing on the dplane pthread */
3108 ret = dplane_update_enqueue(ctx);
3109
3110 /* Increment counter */
3111 atomic_fetch_add_explicit(&zdplane_info.dg_macs_in, 1,
3112 memory_order_relaxed);
3113
3114 if (ret == AOK)
3115 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3116 else {
3117 /* Error counter */
3118 atomic_fetch_add_explicit(&zdplane_info.dg_mac_errors, 1,
3119 memory_order_relaxed);
3120 dplane_ctx_free(&ctx);
3121 }
3122
3123 return result;
3124 }
3125
3126 /*
3127 * Enqueue evpn neighbor add for the dataplane.
3128 */
3129 enum zebra_dplane_result dplane_rem_neigh_add(const struct interface *ifp,
3130 const struct ipaddr *ip,
3131 const struct ethaddr *mac,
3132 uint32_t flags, bool was_static)
3133 {
3134 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3135 uint32_t update_flags = 0;
3136
3137 update_flags |= DPLANE_NEIGH_REMOTE;
3138
3139 if (was_static)
3140 update_flags |= DPLANE_NEIGH_WAS_STATIC;
3141
3142 result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL,
3143 ifp, mac, ip, flags, DPLANE_NUD_NOARP,
3144 update_flags);
3145
3146 return result;
3147 }
3148
3149 /*
3150 * Enqueue local neighbor add for the dataplane.
3151 */
3152 enum zebra_dplane_result dplane_local_neigh_add(const struct interface *ifp,
3153 const struct ipaddr *ip,
3154 const struct ethaddr *mac,
3155 bool set_router, bool set_static,
3156 bool set_inactive)
3157 {
3158 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3159 uint32_t update_flags = 0;
3160 uint32_t ntf = 0;
3161 uint16_t state;
3162
3163 if (set_static)
3164 update_flags |= DPLANE_NEIGH_SET_STATIC;
3165
3166 if (set_inactive) {
3167 update_flags |= DPLANE_NEIGH_SET_INACTIVE;
3168 state = DPLANE_NUD_STALE;
3169 } else {
3170 state = DPLANE_NUD_REACHABLE;
3171 }
3172
3173 if (set_router)
3174 ntf |= DPLANE_NTF_ROUTER;
3175
3176 result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL,
3177 ifp, mac, ip, ntf,
3178 state, update_flags);
3179
3180 return result;
3181 }
3182
3183 /*
3184 * Enqueue evpn neighbor delete for the dataplane.
3185 */
3186 enum zebra_dplane_result dplane_rem_neigh_delete(const struct interface *ifp,
3187 const struct ipaddr *ip)
3188 {
3189 enum zebra_dplane_result result;
3190 uint32_t update_flags = 0;
3191
3192 update_flags |= DPLANE_NEIGH_REMOTE;
3193
3194 result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE,
3195 ifp, NULL, ip, 0, 0, update_flags);
3196
3197 return result;
3198 }
3199
3200 /*
3201 * Enqueue evpn VTEP add for the dataplane.
3202 */
3203 enum zebra_dplane_result dplane_vtep_add(const struct interface *ifp,
3204 const struct in_addr *ip,
3205 vni_t vni)
3206 {
3207 enum zebra_dplane_result result;
3208 struct ethaddr mac = { {0, 0, 0, 0, 0, 0} };
3209 struct ipaddr addr;
3210
3211 if (IS_ZEBRA_DEBUG_VXLAN)
3212 zlog_debug("Install %pI4 into flood list for VNI %u intf %s(%u)",
3213 ip, vni, ifp->name, ifp->ifindex);
3214
3215 SET_IPADDR_V4(&addr);
3216 addr.ipaddr_v4 = *ip;
3217
3218 result = neigh_update_internal(DPLANE_OP_VTEP_ADD,
3219 ifp, &mac, &addr, 0, 0, 0);
3220
3221 return result;
3222 }
3223
3224 /*
3225 * Enqueue evpn VTEP add for the dataplane.
3226 */
3227 enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
3228 const struct in_addr *ip,
3229 vni_t vni)
3230 {
3231 enum zebra_dplane_result result;
3232 struct ethaddr mac = { {0, 0, 0, 0, 0, 0} };
3233 struct ipaddr addr;
3234
3235 if (IS_ZEBRA_DEBUG_VXLAN)
3236 zlog_debug(
3237 "Uninstall %pI4 from flood list for VNI %u intf %s(%u)",
3238 ip, vni, ifp->name, ifp->ifindex);
3239
3240 SET_IPADDR_V4(&addr);
3241 addr.ipaddr_v4 = *ip;
3242
3243 result = neigh_update_internal(DPLANE_OP_VTEP_DELETE,
3244 ifp, &mac, &addr, 0, 0, 0);
3245
3246 return result;
3247 }
3248
3249 enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
3250 const struct ipaddr *ip)
3251 {
3252 enum zebra_dplane_result result;
3253
3254 result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL, ip,
3255 DPLANE_NTF_USE, DPLANE_NUD_INCOMPLETE, 0);
3256
3257 return result;
3258 }
3259
3260 /*
3261 * Common helper api for neighbor updates
3262 */
3263 static enum zebra_dplane_result
3264 neigh_update_internal(enum dplane_op_e op,
3265 const struct interface *ifp,
3266 const struct ethaddr *mac,
3267 const struct ipaddr *ip,
3268 uint32_t flags, uint16_t state,
3269 uint32_t update_flags)
3270 {
3271 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3272 int ret;
3273 struct zebra_dplane_ctx *ctx = NULL;
3274 struct zebra_ns *zns;
3275
3276 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
3277 char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN];
3278
3279 zlog_debug("init neigh ctx %s: ifp %s, mac %s, ip %s",
3280 dplane_op2str(op), ifp->name,
3281 prefix_mac2str(mac, buf1, sizeof(buf1)),
3282 ipaddr2str(ip, buf2, sizeof(buf2)));
3283 }
3284
3285 ctx = dplane_ctx_alloc();
3286
3287 ctx->zd_op = op;
3288 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3289 ctx->zd_vrf_id = ifp->vrf_id;
3290
3291 zns = zebra_ns_lookup(ifp->vrf_id);
3292 dplane_ctx_ns_init(ctx, zns, false);
3293
3294 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
3295 ctx->zd_ifindex = ifp->ifindex;
3296
3297 /* Init the neighbor-specific data area */
3298 memset(&ctx->u.neigh, 0, sizeof(ctx->u.neigh));
3299
3300 ctx->u.neigh.ip_addr = *ip;
3301 if (mac)
3302 ctx->u.neigh.mac = *mac;
3303 ctx->u.neigh.flags = flags;
3304 ctx->u.neigh.state = state;
3305 ctx->u.neigh.update_flags = update_flags;
3306
3307 /* Enqueue for processing on the dplane pthread */
3308 ret = dplane_update_enqueue(ctx);
3309
3310 /* Increment counter */
3311 atomic_fetch_add_explicit(&zdplane_info.dg_neighs_in, 1,
3312 memory_order_relaxed);
3313
3314 if (ret == AOK)
3315 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3316 else {
3317 /* Error counter */
3318 atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors, 1,
3319 memory_order_relaxed);
3320 dplane_ctx_free(&ctx);
3321 }
3322
3323 return result;
3324 }
3325
3326 /*
3327 * Common helper api for PBR rule updates
3328 */
3329 static enum zebra_dplane_result
3330 rule_update_internal(enum dplane_op_e op, struct zebra_pbr_rule *new_rule,
3331 struct zebra_pbr_rule *old_rule)
3332 {
3333 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3334 struct zebra_dplane_ctx *ctx;
3335 int ret;
3336
3337 ctx = dplane_ctx_alloc();
3338
3339 ret = dplane_ctx_rule_init(ctx, op, new_rule, old_rule);
3340 if (ret != AOK)
3341 goto done;
3342
3343 ret = dplane_update_enqueue(ctx);
3344
3345 done:
3346 atomic_fetch_add_explicit(&zdplane_info.dg_rules_in, 1,
3347 memory_order_relaxed);
3348
3349 if (ret == AOK)
3350 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3351 else {
3352 atomic_fetch_add_explicit(&zdplane_info.dg_rule_errors, 1,
3353 memory_order_relaxed);
3354 dplane_ctx_free(&ctx);
3355 }
3356
3357 return result;
3358 }
3359
3360 enum zebra_dplane_result dplane_pbr_rule_add(struct zebra_pbr_rule *rule)
3361 {
3362 return rule_update_internal(DPLANE_OP_RULE_ADD, rule, NULL);
3363 }
3364
3365 enum zebra_dplane_result dplane_pbr_rule_delete(struct zebra_pbr_rule *rule)
3366 {
3367 return rule_update_internal(DPLANE_OP_RULE_DELETE, rule, NULL);
3368 }
3369
3370 enum zebra_dplane_result dplane_pbr_rule_update(struct zebra_pbr_rule *old_rule,
3371 struct zebra_pbr_rule *new_rule)
3372 {
3373 return rule_update_internal(DPLANE_OP_RULE_UPDATE, new_rule, old_rule);
3374 }
3375
3376 /*
3377 * Handler for 'show dplane'
3378 */
3379 int dplane_show_helper(struct vty *vty, bool detailed)
3380 {
3381 uint64_t queued, queue_max, limit, errs, incoming, yields,
3382 other_errs;
3383
3384 /* Using atomics because counters are being changed in different
3385 * pthread contexts.
3386 */
3387 incoming = atomic_load_explicit(&zdplane_info.dg_routes_in,
3388 memory_order_relaxed);
3389 limit = atomic_load_explicit(&zdplane_info.dg_max_queued_updates,
3390 memory_order_relaxed);
3391 queued = atomic_load_explicit(&zdplane_info.dg_routes_queued,
3392 memory_order_relaxed);
3393 queue_max = atomic_load_explicit(&zdplane_info.dg_routes_queued_max,
3394 memory_order_relaxed);
3395 errs = atomic_load_explicit(&zdplane_info.dg_route_errors,
3396 memory_order_relaxed);
3397 yields = atomic_load_explicit(&zdplane_info.dg_update_yields,
3398 memory_order_relaxed);
3399 other_errs = atomic_load_explicit(&zdplane_info.dg_other_errors,
3400 memory_order_relaxed);
3401
3402 vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n",
3403 incoming);
3404 vty_out(vty, "Route update errors: %"PRIu64"\n", errs);
3405 vty_out(vty, "Other errors : %"PRIu64"\n", other_errs);
3406 vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit);
3407 vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued);
3408 vty_out(vty, "Route update queue max: %"PRIu64"\n", queue_max);
3409 vty_out(vty, "Dplane update yields: %"PRIu64"\n", yields);
3410
3411 incoming = atomic_load_explicit(&zdplane_info.dg_lsps_in,
3412 memory_order_relaxed);
3413 errs = atomic_load_explicit(&zdplane_info.dg_lsp_errors,
3414 memory_order_relaxed);
3415 vty_out(vty, "LSP updates: %"PRIu64"\n", incoming);
3416 vty_out(vty, "LSP update errors: %"PRIu64"\n", errs);
3417
3418 incoming = atomic_load_explicit(&zdplane_info.dg_pws_in,
3419 memory_order_relaxed);
3420 errs = atomic_load_explicit(&zdplane_info.dg_pw_errors,
3421 memory_order_relaxed);
3422 vty_out(vty, "PW updates: %"PRIu64"\n", incoming);
3423 vty_out(vty, "PW update errors: %"PRIu64"\n", errs);
3424
3425 incoming = atomic_load_explicit(&zdplane_info.dg_intf_addrs_in,
3426 memory_order_relaxed);
3427 errs = atomic_load_explicit(&zdplane_info.dg_intf_addr_errors,
3428 memory_order_relaxed);
3429 vty_out(vty, "Intf addr updates: %"PRIu64"\n", incoming);
3430 vty_out(vty, "Intf addr errors: %"PRIu64"\n", errs);
3431
3432 incoming = atomic_load_explicit(&zdplane_info.dg_macs_in,
3433 memory_order_relaxed);
3434 errs = atomic_load_explicit(&zdplane_info.dg_mac_errors,
3435 memory_order_relaxed);
3436 vty_out(vty, "EVPN MAC updates: %"PRIu64"\n", incoming);
3437 vty_out(vty, "EVPN MAC errors: %"PRIu64"\n", errs);
3438
3439 incoming = atomic_load_explicit(&zdplane_info.dg_neighs_in,
3440 memory_order_relaxed);
3441 errs = atomic_load_explicit(&zdplane_info.dg_neigh_errors,
3442 memory_order_relaxed);
3443 vty_out(vty, "EVPN neigh updates: %"PRIu64"\n", incoming);
3444 vty_out(vty, "EVPN neigh errors: %"PRIu64"\n", errs);
3445
3446 incoming = atomic_load_explicit(&zdplane_info.dg_rules_in,
3447 memory_order_relaxed);
3448 errs = atomic_load_explicit(&zdplane_info.dg_rule_errors,
3449 memory_order_relaxed);
3450 vty_out(vty, "Rule updates: %" PRIu64 "\n", incoming);
3451 vty_out(vty, "Rule errors: %" PRIu64 "\n", errs);
3452
3453 return CMD_SUCCESS;
3454 }
3455
3456 /*
3457 * Handler for 'show dplane providers'
3458 */
3459 int dplane_show_provs_helper(struct vty *vty, bool detailed)
3460 {
3461 struct zebra_dplane_provider *prov;
3462 uint64_t in, in_max, out, out_max;
3463
3464 vty_out(vty, "Zebra dataplane providers:\n");
3465
3466 DPLANE_LOCK();
3467 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
3468 DPLANE_UNLOCK();
3469
3470 /* Show counters, useful info from each registered provider */
3471 while (prov) {
3472
3473 in = atomic_load_explicit(&prov->dp_in_counter,
3474 memory_order_relaxed);
3475 in_max = atomic_load_explicit(&prov->dp_in_max,
3476 memory_order_relaxed);
3477 out = atomic_load_explicit(&prov->dp_out_counter,
3478 memory_order_relaxed);
3479 out_max = atomic_load_explicit(&prov->dp_out_max,
3480 memory_order_relaxed);
3481
3482 vty_out(vty,
3483 "%s (%u): in: %" PRIu64 ", q_max: %" PRIu64
3484 ", out: %" PRIu64 ", q_max: %" PRIu64 "\n",
3485 prov->dp_name, prov->dp_id, in, in_max, out, out_max);
3486
3487 DPLANE_LOCK();
3488 prov = TAILQ_NEXT(prov, dp_prov_link);
3489 DPLANE_UNLOCK();
3490 }
3491
3492 return CMD_SUCCESS;
3493 }
3494
3495 /*
3496 * Helper for 'show run' etc.
3497 */
3498 int dplane_config_write_helper(struct vty *vty)
3499 {
3500 if (zdplane_info.dg_max_queued_updates != DPLANE_DEFAULT_MAX_QUEUED)
3501 vty_out(vty, "zebra dplane limit %u\n",
3502 zdplane_info.dg_max_queued_updates);
3503
3504 return 0;
3505 }
3506
3507 /*
3508 * Provider registration
3509 */
3510 int dplane_provider_register(const char *name,
3511 enum dplane_provider_prio prio,
3512 int flags,
3513 int (*start_fp)(struct zebra_dplane_provider *),
3514 int (*fp)(struct zebra_dplane_provider *),
3515 int (*fini_fp)(struct zebra_dplane_provider *,
3516 bool early),
3517 void *data,
3518 struct zebra_dplane_provider **prov_p)
3519 {
3520 int ret = 0;
3521 struct zebra_dplane_provider *p = NULL, *last;
3522
3523 /* Validate */
3524 if (fp == NULL) {
3525 ret = EINVAL;
3526 goto done;
3527 }
3528
3529 if (prio <= DPLANE_PRIO_NONE ||
3530 prio > DPLANE_PRIO_LAST) {
3531 ret = EINVAL;
3532 goto done;
3533 }
3534
3535 /* Allocate and init new provider struct */
3536 p = XCALLOC(MTYPE_DP_PROV, sizeof(struct zebra_dplane_provider));
3537
3538 pthread_mutex_init(&(p->dp_mutex), NULL);
3539 TAILQ_INIT(&(p->dp_ctx_in_q));
3540 TAILQ_INIT(&(p->dp_ctx_out_q));
3541
3542 p->dp_flags = flags;
3543 p->dp_priority = prio;
3544 p->dp_fp = fp;
3545 p->dp_start = start_fp;
3546 p->dp_fini = fini_fp;
3547 p->dp_data = data;
3548
3549 /* Lock - the dplane pthread may be running */
3550 DPLANE_LOCK();
3551
3552 p->dp_id = ++zdplane_info.dg_provider_id;
3553
3554 if (name)
3555 strlcpy(p->dp_name, name, DPLANE_PROVIDER_NAMELEN);
3556 else
3557 snprintf(p->dp_name, DPLANE_PROVIDER_NAMELEN,
3558 "provider-%u", p->dp_id);
3559
3560 /* Insert into list ordered by priority */
3561 TAILQ_FOREACH(last, &zdplane_info.dg_providers_q, dp_prov_link) {
3562 if (last->dp_priority > p->dp_priority)
3563 break;
3564 }
3565
3566 if (last)
3567 TAILQ_INSERT_BEFORE(last, p, dp_prov_link);
3568 else
3569 TAILQ_INSERT_TAIL(&zdplane_info.dg_providers_q, p,
3570 dp_prov_link);
3571
3572 /* And unlock */
3573 DPLANE_UNLOCK();
3574
3575 if (IS_ZEBRA_DEBUG_DPLANE)
3576 zlog_debug("dplane: registered new provider '%s' (%u), prio %d",
3577 p->dp_name, p->dp_id, p->dp_priority);
3578
3579 done:
3580 if (prov_p)
3581 *prov_p = p;
3582
3583 return ret;
3584 }
3585
3586 /* Accessors for provider attributes */
3587 const char *dplane_provider_get_name(const struct zebra_dplane_provider *prov)
3588 {
3589 return prov->dp_name;
3590 }
3591
3592 uint32_t dplane_provider_get_id(const struct zebra_dplane_provider *prov)
3593 {
3594 return prov->dp_id;
3595 }
3596
3597 void *dplane_provider_get_data(const struct zebra_dplane_provider *prov)
3598 {
3599 return prov->dp_data;
3600 }
3601
3602 int dplane_provider_get_work_limit(const struct zebra_dplane_provider *prov)
3603 {
3604 return zdplane_info.dg_updates_per_cycle;
3605 }
3606
3607 /* Lock/unlock a provider's mutex - iff the provider was registered with
3608 * the THREADED flag.
3609 */
3610 void dplane_provider_lock(struct zebra_dplane_provider *prov)
3611 {
3612 if (dplane_provider_is_threaded(prov))
3613 DPLANE_PROV_LOCK(prov);
3614 }
3615
3616 void dplane_provider_unlock(struct zebra_dplane_provider *prov)
3617 {
3618 if (dplane_provider_is_threaded(prov))
3619 DPLANE_PROV_UNLOCK(prov);
3620 }
3621
3622 /*
3623 * Dequeue and maintain associated counter
3624 */
3625 struct zebra_dplane_ctx *dplane_provider_dequeue_in_ctx(
3626 struct zebra_dplane_provider *prov)
3627 {
3628 struct zebra_dplane_ctx *ctx = NULL;
3629
3630 dplane_provider_lock(prov);
3631
3632 ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
3633 if (ctx) {
3634 TAILQ_REMOVE(&(prov->dp_ctx_in_q), ctx, zd_q_entries);
3635
3636 atomic_fetch_sub_explicit(&prov->dp_in_queued, 1,
3637 memory_order_relaxed);
3638 }
3639
3640 dplane_provider_unlock(prov);
3641
3642 return ctx;
3643 }
3644
3645 /*
3646 * Dequeue work to a list, return count
3647 */
3648 int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov,
3649 struct dplane_ctx_q *listp)
3650 {
3651 int limit, ret;
3652 struct zebra_dplane_ctx *ctx;
3653
3654 limit = zdplane_info.dg_updates_per_cycle;
3655
3656 dplane_provider_lock(prov);
3657
3658 for (ret = 0; ret < limit; ret++) {
3659 ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
3660 if (ctx) {
3661 TAILQ_REMOVE(&(prov->dp_ctx_in_q), ctx, zd_q_entries);
3662
3663 TAILQ_INSERT_TAIL(listp, ctx, zd_q_entries);
3664 } else {
3665 break;
3666 }
3667 }
3668
3669 if (ret > 0)
3670 atomic_fetch_sub_explicit(&prov->dp_in_queued, ret,
3671 memory_order_relaxed);
3672
3673 dplane_provider_unlock(prov);
3674
3675 return ret;
3676 }
3677
3678 /*
3679 * Enqueue and maintain associated counter
3680 */
3681 void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
3682 struct zebra_dplane_ctx *ctx)
3683 {
3684 dplane_provider_lock(prov);
3685
3686 TAILQ_INSERT_TAIL(&(prov->dp_ctx_out_q), ctx,
3687 zd_q_entries);
3688
3689 dplane_provider_unlock(prov);
3690
3691 atomic_fetch_add_explicit(&(prov->dp_out_counter), 1,
3692 memory_order_relaxed);
3693 }
3694
3695 /*
3696 * Accessor for provider object
3697 */
3698 bool dplane_provider_is_threaded(const struct zebra_dplane_provider *prov)
3699 {
3700 return (prov->dp_flags & DPLANE_PROV_FLAG_THREADED);
3701 }
3702
3703 /*
3704 * Internal helper that copies information from a zebra ns object; this is
3705 * called in the zebra main pthread context as part of dplane ctx init.
3706 */
3707 static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
3708 struct zebra_ns *zns)
3709 {
3710 ns_info->ns_id = zns->ns_id;
3711
3712 #if defined(HAVE_NETLINK)
3713 ns_info->is_cmd = true;
3714 ns_info->nls = zns->netlink_dplane;
3715 #endif /* NETLINK */
3716 }
3717
3718 /*
3719 * Provider api to signal that work/events are available
3720 * for the dataplane pthread.
3721 */
3722 int dplane_provider_work_ready(void)
3723 {
3724 /* Note that during zebra startup, we may be offered work before
3725 * the dataplane pthread (and thread-master) are ready. We want to
3726 * enqueue the work, but the event-scheduling machinery may not be
3727 * available.
3728 */
3729 if (zdplane_info.dg_run) {
3730 thread_add_event(zdplane_info.dg_master,
3731 dplane_thread_loop, NULL, 0,
3732 &zdplane_info.dg_t_update);
3733 }
3734
3735 return AOK;
3736 }
3737
3738 /*
3739 * Enqueue a context directly to zebra main.
3740 */
3741 void dplane_provider_enqueue_to_zebra(struct zebra_dplane_ctx *ctx)
3742 {
3743 struct dplane_ctx_q temp_list;
3744
3745 /* Zebra's api takes a list, so we need to use a temporary list */
3746 TAILQ_INIT(&temp_list);
3747
3748 TAILQ_INSERT_TAIL(&temp_list, ctx, zd_q_entries);
3749 (zdplane_info.dg_results_cb)(&temp_list);
3750 }
3751
3752 /*
3753 * Kernel dataplane provider
3754 */
3755
3756 static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
3757 {
3758 char buf[PREFIX_STRLEN];
3759
3760 switch (dplane_ctx_get_op(ctx)) {
3761
3762 case DPLANE_OP_ROUTE_INSTALL:
3763 case DPLANE_OP_ROUTE_UPDATE:
3764 case DPLANE_OP_ROUTE_DELETE:
3765 zlog_debug("%u:%pFX Dplane route update ctx %p op %s",
3766 dplane_ctx_get_vrf(ctx), dplane_ctx_get_dest(ctx),
3767 ctx, dplane_op2str(dplane_ctx_get_op(ctx)));
3768 break;
3769
3770 case DPLANE_OP_NH_INSTALL:
3771 case DPLANE_OP_NH_UPDATE:
3772 case DPLANE_OP_NH_DELETE:
3773 zlog_debug("ID (%u) Dplane nexthop update ctx %p op %s",
3774 dplane_ctx_get_nhe_id(ctx), ctx,
3775 dplane_op2str(dplane_ctx_get_op(ctx)));
3776 break;
3777
3778 case DPLANE_OP_LSP_INSTALL:
3779 case DPLANE_OP_LSP_UPDATE:
3780 case DPLANE_OP_LSP_DELETE:
3781 break;
3782
3783 case DPLANE_OP_PW_INSTALL:
3784 case DPLANE_OP_PW_UNINSTALL:
3785 zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u",
3786 dplane_ctx_get_ifname(ctx),
3787 dplane_op2str(ctx->zd_op), dplane_ctx_get_pw_af(ctx),
3788 dplane_ctx_get_pw_local_label(ctx),
3789 dplane_ctx_get_pw_remote_label(ctx));
3790 break;
3791
3792 case DPLANE_OP_ADDR_INSTALL:
3793 case DPLANE_OP_ADDR_UNINSTALL:
3794 zlog_debug("Dplane intf %s, idx %u, addr %pFX",
3795 dplane_op2str(dplane_ctx_get_op(ctx)),
3796 dplane_ctx_get_ifindex(ctx),
3797 dplane_ctx_get_intf_addr(ctx));
3798 break;
3799
3800 case DPLANE_OP_MAC_INSTALL:
3801 case DPLANE_OP_MAC_DELETE:
3802 prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf,
3803 sizeof(buf));
3804
3805 zlog_debug("Dplane %s, mac %s, ifindex %u",
3806 dplane_op2str(dplane_ctx_get_op(ctx)),
3807 buf, dplane_ctx_get_ifindex(ctx));
3808 break;
3809
3810 case DPLANE_OP_NEIGH_INSTALL:
3811 case DPLANE_OP_NEIGH_UPDATE:
3812 case DPLANE_OP_NEIGH_DELETE:
3813 case DPLANE_OP_VTEP_ADD:
3814 case DPLANE_OP_VTEP_DELETE:
3815 case DPLANE_OP_NEIGH_DISCOVER:
3816 ipaddr2str(dplane_ctx_neigh_get_ipaddr(ctx), buf,
3817 sizeof(buf));
3818
3819 zlog_debug("Dplane %s, ip %s, ifindex %u",
3820 dplane_op2str(dplane_ctx_get_op(ctx)),
3821 buf, dplane_ctx_get_ifindex(ctx));
3822 break;
3823
3824 case DPLANE_OP_RULE_ADD:
3825 case DPLANE_OP_RULE_DELETE:
3826 case DPLANE_OP_RULE_UPDATE:
3827 zlog_debug("Dplane rule update op %s, if %s(%u), ctx %p",
3828 dplane_op2str(dplane_ctx_get_op(ctx)),
3829 dplane_ctx_get_ifname(ctx),
3830 dplane_ctx_get_ifindex(ctx), ctx);
3831 break;
3832
3833 case DPLANE_OP_SYS_ROUTE_ADD:
3834 case DPLANE_OP_SYS_ROUTE_DELETE:
3835 case DPLANE_OP_ROUTE_NOTIFY:
3836 case DPLANE_OP_LSP_NOTIFY:
3837
3838 case DPLANE_OP_NONE:
3839 break;
3840 }
3841 }
3842
3843 static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
3844 {
3845 enum zebra_dplane_result res = dplane_ctx_get_status(ctx);
3846
3847 switch (dplane_ctx_get_op(ctx)) {
3848
3849 case DPLANE_OP_ROUTE_INSTALL:
3850 case DPLANE_OP_ROUTE_UPDATE:
3851 case DPLANE_OP_ROUTE_DELETE:
3852 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
3853 atomic_fetch_add_explicit(&zdplane_info.dg_route_errors,
3854 1, memory_order_relaxed);
3855
3856 if ((dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE)
3857 && (res == ZEBRA_DPLANE_REQUEST_SUCCESS)) {
3858 struct nexthop *nexthop;
3859
3860 /* Update installed nexthops to signal which have been
3861 * installed.
3862 */
3863 for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
3864 nexthop)) {
3865 if (CHECK_FLAG(nexthop->flags,
3866 NEXTHOP_FLAG_RECURSIVE))
3867 continue;
3868
3869 if (CHECK_FLAG(nexthop->flags,
3870 NEXTHOP_FLAG_ACTIVE)) {
3871 SET_FLAG(nexthop->flags,
3872 NEXTHOP_FLAG_FIB);
3873 }
3874 }
3875 }
3876 break;
3877
3878 case DPLANE_OP_NH_INSTALL:
3879 case DPLANE_OP_NH_UPDATE:
3880 case DPLANE_OP_NH_DELETE:
3881 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
3882 atomic_fetch_add_explicit(
3883 &zdplane_info.dg_nexthop_errors, 1,
3884 memory_order_relaxed);
3885 break;
3886
3887 case DPLANE_OP_LSP_INSTALL:
3888 case DPLANE_OP_LSP_UPDATE:
3889 case DPLANE_OP_LSP_DELETE:
3890 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
3891 atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors,
3892 1, memory_order_relaxed);
3893 break;
3894
3895 case DPLANE_OP_PW_INSTALL:
3896 case DPLANE_OP_PW_UNINSTALL:
3897 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
3898 atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
3899 memory_order_relaxed);
3900 break;
3901
3902 case DPLANE_OP_ADDR_INSTALL:
3903 case DPLANE_OP_ADDR_UNINSTALL:
3904 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
3905 atomic_fetch_add_explicit(
3906 &zdplane_info.dg_intf_addr_errors, 1,
3907 memory_order_relaxed);
3908 break;
3909
3910 case DPLANE_OP_MAC_INSTALL:
3911 case DPLANE_OP_MAC_DELETE:
3912 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
3913 atomic_fetch_add_explicit(&zdplane_info.dg_mac_errors,
3914 1, memory_order_relaxed);
3915 break;
3916
3917 case DPLANE_OP_NEIGH_INSTALL:
3918 case DPLANE_OP_NEIGH_UPDATE:
3919 case DPLANE_OP_NEIGH_DELETE:
3920 case DPLANE_OP_VTEP_ADD:
3921 case DPLANE_OP_VTEP_DELETE:
3922 case DPLANE_OP_NEIGH_DISCOVER:
3923 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
3924 atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors,
3925 1, memory_order_relaxed);
3926 break;
3927
3928 case DPLANE_OP_RULE_ADD:
3929 case DPLANE_OP_RULE_DELETE:
3930 case DPLANE_OP_RULE_UPDATE:
3931 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
3932 atomic_fetch_add_explicit(&zdplane_info.dg_rule_errors,
3933 1, memory_order_relaxed);
3934 break;
3935
3936 /* Ignore 'notifications' - no-op */
3937 case DPLANE_OP_SYS_ROUTE_ADD:
3938 case DPLANE_OP_SYS_ROUTE_DELETE:
3939 case DPLANE_OP_ROUTE_NOTIFY:
3940 case DPLANE_OP_LSP_NOTIFY:
3941 break;
3942
3943 case DPLANE_OP_NONE:
3944 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
3945 atomic_fetch_add_explicit(&zdplane_info.dg_other_errors,
3946 1, memory_order_relaxed);
3947 break;
3948 }
3949 }
3950
3951 /*
3952 * Kernel provider callback
3953 */
3954 static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
3955 {
3956 struct zebra_dplane_ctx *ctx, *tctx;
3957 struct dplane_ctx_q work_list;
3958 int counter, limit;
3959
3960 TAILQ_INIT(&work_list);
3961
3962 limit = dplane_provider_get_work_limit(prov);
3963
3964 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3965 zlog_debug("dplane provider '%s': processing",
3966 dplane_provider_get_name(prov));
3967
3968 for (counter = 0; counter < limit; counter++) {
3969 ctx = dplane_provider_dequeue_in_ctx(prov);
3970 if (ctx == NULL)
3971 break;
3972
3973 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3974 kernel_dplane_log_detail(ctx);
3975
3976 TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
3977 }
3978
3979 kernel_update_multi(&work_list);
3980
3981 TAILQ_FOREACH_SAFE (ctx, &work_list, zd_q_entries, tctx) {
3982 kernel_dplane_handle_result(ctx);
3983
3984 TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
3985 dplane_provider_enqueue_out_ctx(prov, ctx);
3986 }
3987
3988 /* Ensure that we'll run the work loop again if there's still
3989 * more work to do.
3990 */
3991 if (counter >= limit) {
3992 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3993 zlog_debug("dplane provider '%s' reached max updates %d",
3994 dplane_provider_get_name(prov), counter);
3995
3996 atomic_fetch_add_explicit(&zdplane_info.dg_update_yields,
3997 1, memory_order_relaxed);
3998
3999 dplane_provider_work_ready();
4000 }
4001
4002 return 0;
4003 }
4004
4005 #ifdef DPLANE_TEST_PROVIDER
4006
4007 /*
4008 * Test dataplane provider plugin
4009 */
4010
4011 /*
4012 * Test provider process callback
4013 */
4014 static int test_dplane_process_func(struct zebra_dplane_provider *prov)
4015 {
4016 struct zebra_dplane_ctx *ctx;
4017 int counter, limit;
4018
4019 /* Just moving from 'in' queue to 'out' queue */
4020
4021 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4022 zlog_debug("dplane provider '%s': processing",
4023 dplane_provider_get_name(prov));
4024
4025 limit = dplane_provider_get_work_limit(prov);
4026
4027 for (counter = 0; counter < limit; counter++) {
4028 ctx = dplane_provider_dequeue_in_ctx(prov);
4029 if (ctx == NULL)
4030 break;
4031
4032 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4033 zlog_debug("dplane provider '%s': op %s",
4034 dplane_provider_get_name(prov),
4035 dplane_op2str(dplane_ctx_get_op(ctx)));
4036
4037 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
4038
4039 dplane_provider_enqueue_out_ctx(prov, ctx);
4040 }
4041
4042 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4043 zlog_debug("dplane provider '%s': processed %d",
4044 dplane_provider_get_name(prov), counter);
4045
4046 /* Ensure that we'll run the work loop again if there's still
4047 * more work to do.
4048 */
4049 if (counter >= limit)
4050 dplane_provider_work_ready();
4051
4052 return 0;
4053 }
4054
4055 /*
4056 * Test provider shutdown/fini callback
4057 */
4058 static int test_dplane_shutdown_func(struct zebra_dplane_provider *prov,
4059 bool early)
4060 {
4061 if (IS_ZEBRA_DEBUG_DPLANE)
4062 zlog_debug("dplane provider '%s': %sshutdown",
4063 dplane_provider_get_name(prov),
4064 early ? "early " : "");
4065
4066 return 0;
4067 }
4068 #endif /* DPLANE_TEST_PROVIDER */
4069
4070 /*
4071 * Register default kernel provider
4072 */
4073 static void dplane_provider_init(void)
4074 {
4075 int ret;
4076
4077 ret = dplane_provider_register("Kernel",
4078 DPLANE_PRIO_KERNEL,
4079 DPLANE_PROV_FLAGS_DEFAULT, NULL,
4080 kernel_dplane_process_func,
4081 NULL,
4082 NULL, NULL);
4083
4084 if (ret != AOK)
4085 zlog_err("Unable to register kernel dplane provider: %d",
4086 ret);
4087
4088 #ifdef DPLANE_TEST_PROVIDER
4089 /* Optional test provider ... */
4090 ret = dplane_provider_register("Test",
4091 DPLANE_PRIO_PRE_KERNEL,
4092 DPLANE_PROV_FLAGS_DEFAULT, NULL,
4093 test_dplane_process_func,
4094 test_dplane_shutdown_func,
4095 NULL /* data */, NULL);
4096
4097 if (ret != AOK)
4098 zlog_err("Unable to register test dplane provider: %d",
4099 ret);
4100 #endif /* DPLANE_TEST_PROVIDER */
4101 }
4102
4103 /* Indicates zebra shutdown/exit is in progress. Some operations may be
4104 * simplified or skipped during shutdown processing.
4105 */
4106 bool dplane_is_in_shutdown(void)
4107 {
4108 return zdplane_info.dg_is_shutdown;
4109 }
4110
4111 /*
4112 * Early or pre-shutdown, de-init notification api. This runs pretty
4113 * early during zebra shutdown, as a signal to stop new work and prepare
4114 * for updates generated by shutdown/cleanup activity, as zebra tries to
4115 * remove everything it's responsible for.
4116 * NB: This runs in the main zebra pthread context.
4117 */
4118 void zebra_dplane_pre_finish(void)
4119 {
4120 struct zebra_dplane_provider *prov;
4121
4122 if (IS_ZEBRA_DEBUG_DPLANE)
4123 zlog_debug("Zebra dataplane pre-finish called");
4124
4125 zdplane_info.dg_is_shutdown = true;
4126
4127 /* Notify provider(s) of pending shutdown. */
4128 TAILQ_FOREACH(prov, &zdplane_info.dg_providers_q, dp_prov_link) {
4129 if (prov->dp_fini == NULL)
4130 continue;
4131
4132 prov->dp_fini(prov, true /* early */);
4133 }
4134 }
4135
4136 /*
4137 * Utility to determine whether work remains enqueued within the dplane;
4138 * used during system shutdown processing.
4139 */
4140 static bool dplane_work_pending(void)
4141 {
4142 bool ret = false;
4143 struct zebra_dplane_ctx *ctx;
4144 struct zebra_dplane_provider *prov;
4145
4146 /* TODO -- just checking incoming/pending work for now, must check
4147 * providers
4148 */
4149 DPLANE_LOCK();
4150 {
4151 ctx = TAILQ_FIRST(&zdplane_info.dg_update_ctx_q);
4152 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
4153 }
4154 DPLANE_UNLOCK();
4155
4156 if (ctx != NULL) {
4157 ret = true;
4158 goto done;
4159 }
4160
4161 while (prov) {
4162
4163 dplane_provider_lock(prov);
4164
4165 ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
4166 if (ctx == NULL)
4167 ctx = TAILQ_FIRST(&(prov->dp_ctx_out_q));
4168
4169 dplane_provider_unlock(prov);
4170
4171 if (ctx != NULL)
4172 break;
4173
4174 DPLANE_LOCK();
4175 prov = TAILQ_NEXT(prov, dp_prov_link);
4176 DPLANE_UNLOCK();
4177 }
4178
4179 if (ctx != NULL)
4180 ret = true;
4181
4182 done:
4183 return ret;
4184 }
4185
4186 /*
4187 * Shutdown-time intermediate callback, used to determine when all pending
4188 * in-flight updates are done. If there's still work to do, reschedules itself.
4189 * If all work is done, schedules an event to the main zebra thread for
4190 * final zebra shutdown.
4191 * This runs in the dplane pthread context.
4192 */
4193 static int dplane_check_shutdown_status(struct thread *event)
4194 {
4195 if (IS_ZEBRA_DEBUG_DPLANE)
4196 zlog_debug("Zebra dataplane shutdown status check called");
4197
4198 if (dplane_work_pending()) {
4199 /* Reschedule dplane check on a short timer */
4200 thread_add_timer_msec(zdplane_info.dg_master,
4201 dplane_check_shutdown_status,
4202 NULL, 100,
4203 &zdplane_info.dg_t_shutdown_check);
4204
4205 /* TODO - give up and stop waiting after a short time? */
4206
4207 } else {
4208 /* We appear to be done - schedule a final callback event
4209 * for the zebra main pthread.
4210 */
4211 thread_add_event(zrouter.master, zebra_finalize, NULL, 0, NULL);
4212 }
4213
4214 return 0;
4215 }
4216
4217 /*
4218 * Shutdown, de-init api. This runs pretty late during shutdown,
4219 * after zebra has tried to free/remove/uninstall all routes during shutdown.
4220 * At this point, dplane work may still remain to be done, so we can't just
4221 * blindly terminate. If there's still work to do, we'll periodically check
4222 * and when done, we'll enqueue a task to the zebra main thread for final
4223 * termination processing.
4224 *
4225 * NB: This runs in the main zebra thread context.
4226 */
4227 void zebra_dplane_finish(void)
4228 {
4229 if (IS_ZEBRA_DEBUG_DPLANE)
4230 zlog_debug("Zebra dataplane fini called");
4231
4232 thread_add_event(zdplane_info.dg_master,
4233 dplane_check_shutdown_status, NULL, 0,
4234 &zdplane_info.dg_t_shutdown_check);
4235 }
4236
4237 /*
4238 * Main dataplane pthread event loop. The thread takes new incoming work
4239 * and offers it to the first provider. It then iterates through the
4240 * providers, taking complete work from each one and offering it
4241 * to the next in order. At each step, a limited number of updates are
4242 * processed during a cycle in order to provide some fairness.
4243 *
4244 * This loop through the providers is only run once, so that the dataplane
4245 * pthread can look for other pending work - such as i/o work on behalf of
4246 * providers.
4247 */
4248 static int dplane_thread_loop(struct thread *event)
4249 {
4250 struct dplane_ctx_q work_list;
4251 struct dplane_ctx_q error_list;
4252 struct zebra_dplane_provider *prov;
4253 struct zebra_dplane_ctx *ctx, *tctx;
4254 int limit, counter, error_counter;
4255 uint64_t curr, high;
4256
4257 /* Capture work limit per cycle */
4258 limit = zdplane_info.dg_updates_per_cycle;
4259
4260 /* Init temporary lists used to move contexts among providers */
4261 TAILQ_INIT(&work_list);
4262 TAILQ_INIT(&error_list);
4263 error_counter = 0;
4264
4265 /* Check for zebra shutdown */
4266 if (!zdplane_info.dg_run)
4267 goto done;
4268
4269 /* Dequeue some incoming work from zebra (if any) onto the temporary
4270 * working list.
4271 */
4272 DPLANE_LOCK();
4273
4274 /* Locate initial registered provider */
4275 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
4276
4277 /* Move new work from incoming list to temp list */
4278 for (counter = 0; counter < limit; counter++) {
4279 ctx = TAILQ_FIRST(&zdplane_info.dg_update_ctx_q);
4280 if (ctx) {
4281 TAILQ_REMOVE(&zdplane_info.dg_update_ctx_q, ctx,
4282 zd_q_entries);
4283
4284 ctx->zd_provider = prov->dp_id;
4285
4286 TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
4287 } else {
4288 break;
4289 }
4290 }
4291
4292 DPLANE_UNLOCK();
4293
4294 atomic_fetch_sub_explicit(&zdplane_info.dg_routes_queued, counter,
4295 memory_order_relaxed);
4296
4297 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4298 zlog_debug("dplane: incoming new work counter: %d", counter);
4299
4300 /* Iterate through the registered providers, offering new incoming
4301 * work. If the provider has outgoing work in its queue, take that
4302 * work for the next provider
4303 */
4304 while (prov) {
4305
4306 /* At each iteration, the temporary work list has 'counter'
4307 * items.
4308 */
4309 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4310 zlog_debug("dplane enqueues %d new work to provider '%s'",
4311 counter, dplane_provider_get_name(prov));
4312
4313 /* Capture current provider id in each context; check for
4314 * error status.
4315 */
4316 TAILQ_FOREACH_SAFE(ctx, &work_list, zd_q_entries, tctx) {
4317 if (dplane_ctx_get_status(ctx) ==
4318 ZEBRA_DPLANE_REQUEST_SUCCESS) {
4319 ctx->zd_provider = prov->dp_id;
4320 } else {
4321 /*
4322 * TODO -- improve error-handling: recirc
4323 * errors backwards so that providers can
4324 * 'undo' their work (if they want to)
4325 */
4326
4327 /* Move to error list; will be returned
4328 * zebra main.
4329 */
4330 TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
4331 TAILQ_INSERT_TAIL(&error_list,
4332 ctx, zd_q_entries);
4333 error_counter++;
4334 }
4335 }
4336
4337 /* Enqueue new work to the provider */
4338 dplane_provider_lock(prov);
4339
4340 if (TAILQ_FIRST(&work_list))
4341 TAILQ_CONCAT(&(prov->dp_ctx_in_q), &work_list,
4342 zd_q_entries);
4343
4344 atomic_fetch_add_explicit(&prov->dp_in_counter, counter,
4345 memory_order_relaxed);
4346 atomic_fetch_add_explicit(&prov->dp_in_queued, counter,
4347 memory_order_relaxed);
4348 curr = atomic_load_explicit(&prov->dp_in_queued,
4349 memory_order_relaxed);
4350 high = atomic_load_explicit(&prov->dp_in_max,
4351 memory_order_relaxed);
4352 if (curr > high)
4353 atomic_store_explicit(&prov->dp_in_max, curr,
4354 memory_order_relaxed);
4355
4356 dplane_provider_unlock(prov);
4357
4358 /* Reset the temp list (though the 'concat' may have done this
4359 * already), and the counter
4360 */
4361 TAILQ_INIT(&work_list);
4362 counter = 0;
4363
4364 /* Call into the provider code. Note that this is
4365 * unconditional: we offer to do work even if we don't enqueue
4366 * any _new_ work.
4367 */
4368 (*prov->dp_fp)(prov);
4369
4370 /* Check for zebra shutdown */
4371 if (!zdplane_info.dg_run)
4372 break;
4373
4374 /* Dequeue completed work from the provider */
4375 dplane_provider_lock(prov);
4376
4377 while (counter < limit) {
4378 ctx = TAILQ_FIRST(&(prov->dp_ctx_out_q));
4379 if (ctx) {
4380 TAILQ_REMOVE(&(prov->dp_ctx_out_q), ctx,
4381 zd_q_entries);
4382
4383 TAILQ_INSERT_TAIL(&work_list,
4384 ctx, zd_q_entries);
4385 counter++;
4386 } else
4387 break;
4388 }
4389
4390 dplane_provider_unlock(prov);
4391
4392 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4393 zlog_debug("dplane dequeues %d completed work from provider %s",
4394 counter, dplane_provider_get_name(prov));
4395
4396 /* Locate next provider */
4397 DPLANE_LOCK();
4398 prov = TAILQ_NEXT(prov, dp_prov_link);
4399 DPLANE_UNLOCK();
4400 }
4401
4402 /* After all providers have been serviced, enqueue any completed
4403 * work and any errors back to zebra so it can process the results.
4404 */
4405 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4406 zlog_debug("dplane has %d completed, %d errors, for zebra main",
4407 counter, error_counter);
4408
4409 /*
4410 * Hand lists through the api to zebra main,
4411 * to reduce the number of lock/unlock cycles
4412 */
4413
4414 /* Call through to zebra main */
4415 (zdplane_info.dg_results_cb)(&error_list);
4416
4417 TAILQ_INIT(&error_list);
4418
4419 /* Call through to zebra main */
4420 (zdplane_info.dg_results_cb)(&work_list);
4421
4422 TAILQ_INIT(&work_list);
4423
4424 done:
4425 return 0;
4426 }
4427
4428 /*
4429 * Final phase of shutdown, after all work enqueued to dplane has been
4430 * processed. This is called from the zebra main pthread context.
4431 */
4432 void zebra_dplane_shutdown(void)
4433 {
4434 struct zebra_dplane_provider *dp;
4435
4436 if (IS_ZEBRA_DEBUG_DPLANE)
4437 zlog_debug("Zebra dataplane shutdown called");
4438
4439 /* Stop dplane thread, if it's running */
4440
4441 zdplane_info.dg_run = false;
4442
4443 if (zdplane_info.dg_t_update)
4444 thread_cancel_async(zdplane_info.dg_t_update->master,
4445 &zdplane_info.dg_t_update, NULL);
4446
4447 frr_pthread_stop(zdplane_info.dg_pthread, NULL);
4448
4449 /* Destroy pthread */
4450 frr_pthread_destroy(zdplane_info.dg_pthread);
4451 zdplane_info.dg_pthread = NULL;
4452 zdplane_info.dg_master = NULL;
4453
4454 /* Notify provider(s) of final shutdown.
4455 * Note that this call is in the main pthread, so providers must
4456 * be prepared for that.
4457 */
4458 TAILQ_FOREACH(dp, &zdplane_info.dg_providers_q, dp_prov_link) {
4459 if (dp->dp_fini == NULL)
4460 continue;
4461
4462 dp->dp_fini(dp, false);
4463 }
4464
4465 /* TODO -- Clean-up provider objects */
4466
4467 /* TODO -- Clean queue(s), free memory */
4468 }
4469
4470 /*
4471 * Initialize the dataplane module during startup, internal/private version
4472 */
4473 static void zebra_dplane_init_internal(void)
4474 {
4475 memset(&zdplane_info, 0, sizeof(zdplane_info));
4476
4477 pthread_mutex_init(&zdplane_info.dg_mutex, NULL);
4478
4479 TAILQ_INIT(&zdplane_info.dg_update_ctx_q);
4480 TAILQ_INIT(&zdplane_info.dg_providers_q);
4481
4482 zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK;
4483
4484 zdplane_info.dg_max_queued_updates = DPLANE_DEFAULT_MAX_QUEUED;
4485
4486 /* Register default kernel 'provider' during init */
4487 dplane_provider_init();
4488 }
4489
4490 /*
4491 * Start the dataplane pthread. This step needs to be run later than the
4492 * 'init' step, in case zebra has fork-ed.
4493 */
4494 void zebra_dplane_start(void)
4495 {
4496 struct zebra_dplane_provider *prov;
4497 struct frr_pthread_attr pattr = {
4498 .start = frr_pthread_attr_default.start,
4499 .stop = frr_pthread_attr_default.stop
4500 };
4501
4502 /* Start dataplane pthread */
4503
4504 zdplane_info.dg_pthread = frr_pthread_new(&pattr, "Zebra dplane thread",
4505 "zebra_dplane");
4506
4507 zdplane_info.dg_master = zdplane_info.dg_pthread->master;
4508
4509 zdplane_info.dg_run = true;
4510
4511 /* Enqueue an initial event for the dataplane pthread */
4512 thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0,
4513 &zdplane_info.dg_t_update);
4514
4515 /* Call start callbacks for registered providers */
4516
4517 DPLANE_LOCK();
4518 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
4519 DPLANE_UNLOCK();
4520
4521 while (prov) {
4522
4523 if (prov->dp_start)
4524 (prov->dp_start)(prov);
4525
4526 /* Locate next provider */
4527 DPLANE_LOCK();
4528 prov = TAILQ_NEXT(prov, dp_prov_link);
4529 DPLANE_UNLOCK();
4530 }
4531
4532 frr_pthread_run(zdplane_info.dg_pthread, NULL);
4533 }
4534
4535 /*
4536 * Initialize the dataplane module at startup; called by zebra rib_init()
4537 */
4538 void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_q *))
4539 {
4540 zebra_dplane_init_internal();
4541 zdplane_info.dg_results_cb = results_fp;
4542 }