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