]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_dplane.c
zebra: Replace nexthop_group with pointer in route entry
[mirror_frr.git] / zebra / zebra_dplane.c
CommitLineData
ea1c14f6
MS
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
2618a52e
DL
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
18c37974 24#include "lib/libfrr.h"
1d11b21f
MS
25#include "lib/debug.h"
26#include "lib/frratomic.h"
7cdb1a84 27#include "lib/frr_pthread.h"
1d11b21f 28#include "lib/memory.h"
7cdb1a84 29#include "lib/queue.h"
1d11b21f 30#include "lib/zebra.h"
1485bbe7 31#include "zebra/zebra_router.h"
7cdb1a84 32#include "zebra/zebra_memory.h"
3801e764 33#include "zebra/zebra_router.h"
7cdb1a84
MS
34#include "zebra/zebra_dplane.h"
35#include "zebra/rt.h"
36#include "zebra/debug.h"
37
38/* Memory type for context blocks */
c1344b54
DL
39DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx")
40DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider")
7cdb1a84
MS
41
42#ifndef AOK
43# define AOK 0
44#endif
45
e5a60d82
MS
46/* Enable test dataplane provider */
47/*#define DPLANE_TEST_PROVIDER 1 */
48
91f16812
MS
49/* Default value for max queued incoming updates */
50const uint32_t DPLANE_DEFAULT_MAX_QUEUED = 200;
51
c831033f
MS
52/* Default value for new work per cycle */
53const uint32_t DPLANE_DEFAULT_NEW_WORK = 100;
54
7cdb1a84
MS
55/* Validation check macro for context blocks */
56/* #define DPLANE_DEBUG 1 */
57
58#ifdef DPLANE_DEBUG
59
25779064
MS
60# define DPLANE_CTX_VALID(p) \
61 assert((p) != NULL)
7cdb1a84
MS
62
63#else
64
5709131c 65# define DPLANE_CTX_VALID(p)
7cdb1a84
MS
66
67#endif /* DPLANE_DEBUG */
68
69/*
0f461727 70 * Route information captured for route updates.
7cdb1a84 71 */
0f461727 72struct dplane_route_info {
7cdb1a84
MS
73
74 /* Dest and (optional) source prefixes */
75 struct prefix zd_dest;
76 struct prefix zd_src;
77
0f461727
MS
78 afi_t zd_afi;
79 safi_t zd_safi;
7cdb1a84
MS
80
81 int zd_type;
82 int zd_old_type;
83
7cdb1a84
MS
84 route_tag_t zd_tag;
85 route_tag_t zd_old_tag;
86 uint32_t zd_metric;
01ce7cba 87 uint32_t zd_old_metric;
0f461727 88
7cdb1a84
MS
89 uint16_t zd_instance;
90 uint16_t zd_old_instance;
91
92 uint8_t zd_distance;
93 uint8_t zd_old_distance;
94
95 uint32_t zd_mtu;
96 uint32_t zd_nexthop_mtu;
97
7cdb1a84
MS
98 /* Nexthops */
99 struct nexthop_group zd_ng;
100
4dfd7a02 101 /* "Previous" nexthops, used only in route updates without netlink */
01ce7cba
MS
102 struct nexthop_group zd_old_ng;
103
b8e0423d
MS
104 /* TODO -- use fixed array of nexthops, to avoid mallocs? */
105
0f461727
MS
106};
107
d613b8e1
MS
108/*
109 * Pseudowire info for the dataplane
110 */
111struct dplane_pw_info {
d613b8e1
MS
112 int type;
113 int af;
114 int status;
115 uint32_t flags;
16d69787 116 union g_addr dest;
d613b8e1
MS
117 mpls_label_t local_label;
118 mpls_label_t remote_label;
119
16d69787
MS
120 /* Nexthops */
121 struct nexthop_group nhg;
122
d613b8e1
MS
123 union pw_protocol_fields fields;
124};
125
a4a4802a
MS
126/*
127 * Interface/prefix info for the dataplane
128 */
129struct dplane_intf_info {
130
a4a4802a
MS
131 uint32_t metric;
132 uint32_t flags;
133
134#define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */
135#define DPLANE_INTF_SECONDARY (1 << 1)
64168803 136#define DPLANE_INTF_BROADCAST (1 << 2)
0f3af738 137#define DPLANE_INTF_HAS_DEST DPLANE_INTF_CONNECTED
64168803 138#define DPLANE_INTF_HAS_LABEL (1 << 4)
a4a4802a
MS
139
140 /* Interface address/prefix */
141 struct prefix prefix;
142
143 /* Dest address, for p2p, or broadcast prefix */
144 struct prefix dest_prefix;
145
146 char *label;
147 char label_buf[32];
148};
149
7597ac7b 150/*
0bbd4ff4 151 * EVPN MAC address info for the dataplane.
7597ac7b
MS
152 */
153struct dplane_mac_info {
154 vlanid_t vid;
478566d6 155 ifindex_t br_ifindex;
7597ac7b
MS
156 struct ethaddr mac;
157 struct in_addr vtep_ip;
158 bool is_sticky;
159
160};
161
931fa60c
MS
162/*
163 * EVPN neighbor info for the dataplane
164 */
165struct dplane_neigh_info {
166 struct ipaddr ip_addr;
167 struct ethaddr mac;
168 uint32_t flags;
169 uint16_t state;
170};
171
0f461727
MS
172/*
173 * The context block used to exchange info about route updates across
174 * the boundary between the zebra main context (and pthread) and the
175 * dataplane layer (and pthread).
176 */
177struct zebra_dplane_ctx {
178
179 /* Operation code */
180 enum dplane_op_e zd_op;
181
182 /* Status on return */
183 enum zebra_dplane_result zd_status;
184
185 /* Dplane provider id */
186 uint32_t zd_provider;
187
188 /* Flags - used by providers, e.g. */
189 int zd_flags;
190
191 bool zd_is_update;
192
193 uint32_t zd_seq;
194 uint32_t zd_old_seq;
195
0024a559
MS
196 /* Some updates may be generated by notifications: allow the
197 * plugin to notice and ignore results from its own notifications.
198 */
199 uint32_t zd_notif_provider;
200
0f461727
MS
201 /* TODO -- internal/sub-operation status? */
202 enum zebra_dplane_result zd_remote_status;
203 enum zebra_dplane_result zd_kernel_status;
204
205 vrf_id_t zd_vrf_id;
206 uint32_t zd_table_id;
207
7c7ef4a8
MS
208 char zd_ifname[INTERFACE_NAMSIZ];
209 ifindex_t zd_ifindex;
210
a4a4802a 211 /* Support info for different kinds of updates */
0f461727
MS
212 union {
213 struct dplane_route_info rinfo;
214 zebra_lsp_t lsp;
d613b8e1 215 struct dplane_pw_info pw;
a4a4802a 216 struct dplane_intf_info intf;
7597ac7b 217 struct dplane_mac_info macinfo;
931fa60c 218 struct dplane_neigh_info neigh;
0f461727
MS
219 } u;
220
221 /* Namespace info, used especially for netlink kernel communication */
222 struct zebra_dplane_info zd_ns_info;
223
7cdb1a84 224 /* Embedded list linkage */
25779064 225 TAILQ_ENTRY(zebra_dplane_ctx) zd_q_entries;
7cdb1a84
MS
226};
227
c831033f
MS
228/* Flag that can be set by a pre-kernel provider as a signal that an update
229 * should bypass the kernel.
230 */
231#define DPLANE_CTX_FLAG_NO_KERNEL 0x01
232
233
7cdb1a84
MS
234/*
235 * Registration block for one dataplane provider.
236 */
25779064 237struct zebra_dplane_provider {
7cdb1a84
MS
238 /* Name */
239 char dp_name[DPLANE_PROVIDER_NAMELEN + 1];
240
241 /* Priority, for ordering among providers */
242 uint8_t dp_priority;
243
244 /* Id value */
245 uint32_t dp_id;
246
c831033f
MS
247 /* Mutex */
248 pthread_mutex_t dp_mutex;
249
250 /* Plugin-provided extra data */
251 void *dp_data;
252
253 /* Flags */
254 int dp_flags;
255
1dd4ea8a
MS
256 int (*dp_start)(struct zebra_dplane_provider *prov);
257
4c206c8f 258 int (*dp_fp)(struct zebra_dplane_provider *prov);
7cdb1a84 259
4c206c8f 260 int (*dp_fini)(struct zebra_dplane_provider *prov, bool early_p);
18c37974 261
0545c373 262 _Atomic uint32_t dp_in_counter;
c9d17fe8 263 _Atomic uint32_t dp_in_queued;
c831033f
MS
264 _Atomic uint32_t dp_in_max;
265 _Atomic uint32_t dp_out_counter;
c9d17fe8 266 _Atomic uint32_t dp_out_queued;
c831033f 267 _Atomic uint32_t dp_out_max;
0545c373 268 _Atomic uint32_t dp_error_counter;
1d11b21f 269
c831033f
MS
270 /* Queue of contexts inbound to the provider */
271 struct dplane_ctx_q dp_ctx_in_q;
272
273 /* Queue of completed contexts outbound from the provider back
274 * towards the dataplane module.
275 */
276 struct dplane_ctx_q dp_ctx_out_q;
7cdb1a84 277
c831033f
MS
278 /* Embedded list linkage for provider objects */
279 TAILQ_ENTRY(zebra_dplane_provider) dp_prov_link;
7cdb1a84
MS
280};
281
282/*
283 * Globals
284 */
25779064 285static struct zebra_dplane_globals {
7cdb1a84
MS
286 /* Mutex to control access to dataplane components */
287 pthread_mutex_t dg_mutex;
288
289 /* Results callback registered by zebra 'core' */
4c206c8f 290 int (*dg_results_cb)(struct dplane_ctx_q *ctxlist);
7cdb1a84 291
4dfd7a02
MS
292 /* Sentinel for beginning of shutdown */
293 volatile bool dg_is_shutdown;
294
295 /* Sentinel for end of shutdown */
1d11b21f
MS
296 volatile bool dg_run;
297
3fe4ccc4
MS
298 /* Update context queue inbound to the dataplane */
299 TAILQ_HEAD(zdg_ctx_q, zebra_dplane_ctx) dg_update_ctx_q;
7cdb1a84
MS
300
301 /* Ordered list of providers */
25779064 302 TAILQ_HEAD(zdg_prov_q, zebra_dplane_provider) dg_providers_q;
7cdb1a84 303
1d11b21f 304 /* Counter used to assign internal ids to providers */
b8e0423d
MS
305 uint32_t dg_provider_id;
306
91f16812
MS
307 /* Limit number of pending, unprocessed updates */
308 _Atomic uint32_t dg_max_queued_updates;
309
cf363e1b
MS
310 /* Control whether system route notifications should be produced. */
311 bool dg_sys_route_notifs;
312
c831033f
MS
313 /* Limit number of new updates dequeued at once, to pace an
314 * incoming burst.
315 */
316 uint32_t dg_updates_per_cycle;
317
0545c373 318 _Atomic uint32_t dg_routes_in;
1d11b21f 319 _Atomic uint32_t dg_routes_queued;
4dfd7a02 320 _Atomic uint32_t dg_routes_queued_max;
0545c373 321 _Atomic uint32_t dg_route_errors;
16c628de
MS
322 _Atomic uint32_t dg_other_errors;
323
324 _Atomic uint32_t dg_lsps_in;
16c628de
MS
325 _Atomic uint32_t dg_lsp_errors;
326
97d8d05a
MS
327 _Atomic uint32_t dg_pws_in;
328 _Atomic uint32_t dg_pw_errors;
329
64168803
MS
330 _Atomic uint32_t dg_intf_addrs_in;
331 _Atomic uint32_t dg_intf_addr_errors;
332
7597ac7b
MS
333 _Atomic uint32_t dg_macs_in;
334 _Atomic uint32_t dg_mac_errors;
335
931fa60c
MS
336 _Atomic uint32_t dg_neighs_in;
337 _Atomic uint32_t dg_neigh_errors;
338
c831033f 339 _Atomic uint32_t dg_update_yields;
1d11b21f 340
d8c16a95
MS
341 /* Dataplane pthread */
342 struct frr_pthread *dg_pthread;
343
7cdb1a84
MS
344 /* Event-delivery context 'master' for the dplane */
345 struct thread_master *dg_master;
346
347 /* Event/'thread' pointer for queued updates */
348 struct thread *dg_t_update;
349
4dfd7a02
MS
350 /* Event pointer for pending shutdown check loop */
351 struct thread *dg_t_shutdown_check;
352
25779064 353} zdplane_info;
7cdb1a84
MS
354
355/*
c831033f 356 * Lock and unlock for interactions with the zebra 'core' pthread
7cdb1a84 357 */
25779064 358#define DPLANE_LOCK() pthread_mutex_lock(&zdplane_info.dg_mutex)
25779064 359#define DPLANE_UNLOCK() pthread_mutex_unlock(&zdplane_info.dg_mutex)
7cdb1a84 360
c831033f
MS
361
362/*
363 * Lock and unlock for individual providers
364 */
365#define DPLANE_PROV_LOCK(p) pthread_mutex_lock(&((p)->dp_mutex))
366#define DPLANE_PROV_UNLOCK(p) pthread_mutex_unlock(&((p)->dp_mutex))
367
7cdb1a84 368/* Prototypes */
c831033f 369static int dplane_thread_loop(struct thread *event);
62b8bb7a
MS
370static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
371 struct zebra_ns *zns);
16c628de
MS
372static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
373 enum dplane_op_e op);
97d8d05a
MS
374static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
375 enum dplane_op_e op);
64168803
MS
376static enum zebra_dplane_result intf_addr_update_internal(
377 const struct interface *ifp, const struct connected *ifc,
378 enum dplane_op_e op);
7597ac7b
MS
379static enum zebra_dplane_result mac_update_internal(
380 enum dplane_op_e op, const struct interface *ifp,
478566d6 381 const struct interface *br_ifp,
7597ac7b
MS
382 vlanid_t vid, const struct ethaddr *mac,
383 struct in_addr vtep_ip, bool sticky);
931fa60c
MS
384static enum zebra_dplane_result neigh_update_internal(
385 enum dplane_op_e op,
386 const struct interface *ifp,
387 const struct ethaddr *mac,
388 const struct ipaddr *ip,
389 uint32_t flags, uint16_t state);
7cdb1a84
MS
390
391/*
392 * Public APIs
393 */
394
ad6aad4d
MS
395/* Obtain thread_master for dataplane thread */
396struct thread_master *dplane_get_thread_master(void)
397{
398 return zdplane_info.dg_master;
399}
400
7cdb1a84 401/*
b8e0423d 402 * Allocate a dataplane update context
7cdb1a84 403 */
593e4eb1 404struct zebra_dplane_ctx *dplane_ctx_alloc(void)
7cdb1a84 405{
25779064 406 struct zebra_dplane_ctx *p;
7cdb1a84 407
b8e0423d
MS
408 /* TODO -- just alloc'ing memory, but would like to maintain
409 * a pool
410 */
25779064 411 p = XCALLOC(MTYPE_DP_CTX, sizeof(struct zebra_dplane_ctx));
7cdb1a84 412
5709131c 413 return p;
7cdb1a84
MS
414}
415
cf363e1b
MS
416/* Enable system route notifications */
417void dplane_enable_sys_route_notifs(void)
418{
419 zdplane_info.dg_sys_route_notifs = true;
420}
421
7cdb1a84 422/*
b8e0423d 423 * Free a dataplane results context.
7cdb1a84 424 */
25779064 425static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
7cdb1a84 426{
16c628de
MS
427 if (pctx == NULL)
428 return;
7cdb1a84 429
16c628de
MS
430 DPLANE_CTX_VALID(*pctx);
431
432 /* TODO -- just freeing memory, but would like to maintain
433 * a pool
434 */
435
436 /* Some internal allocations may need to be freed, depending on
437 * the type of info captured in the ctx.
438 */
439 switch ((*pctx)->zd_op) {
440 case DPLANE_OP_ROUTE_INSTALL:
441 case DPLANE_OP_ROUTE_UPDATE:
442 case DPLANE_OP_ROUTE_DELETE:
cf363e1b
MS
443 case DPLANE_OP_SYS_ROUTE_ADD:
444 case DPLANE_OP_SYS_ROUTE_DELETE:
54818e3b 445 case DPLANE_OP_ROUTE_NOTIFY:
b8e0423d 446
16c628de 447 /* Free allocated nexthops */
0f461727 448 if ((*pctx)->u.rinfo.zd_ng.nexthop) {
7cdb1a84 449 /* This deals with recursive nexthops too */
0f461727 450 nexthops_free((*pctx)->u.rinfo.zd_ng.nexthop);
16c628de
MS
451
452 (*pctx)->u.rinfo.zd_ng.nexthop = NULL;
7cdb1a84
MS
453 }
454
0f461727 455 if ((*pctx)->u.rinfo.zd_old_ng.nexthop) {
4dfd7a02 456 /* This deals with recursive nexthops too */
0f461727 457 nexthops_free((*pctx)->u.rinfo.zd_old_ng.nexthop);
16c628de
MS
458
459 (*pctx)->u.rinfo.zd_old_ng.nexthop = NULL;
460 }
461
462 break;
463
464 case DPLANE_OP_LSP_INSTALL:
465 case DPLANE_OP_LSP_UPDATE:
466 case DPLANE_OP_LSP_DELETE:
104e3ad9 467 case DPLANE_OP_LSP_NOTIFY:
16c628de
MS
468 {
469 zebra_nhlfe_t *nhlfe, *next;
470
471 /* Free allocated NHLFEs */
472 for (nhlfe = (*pctx)->u.lsp.nhlfe_list; nhlfe; nhlfe = next) {
473 next = nhlfe->next;
474
475 zebra_mpls_nhlfe_del(nhlfe);
01ce7cba
MS
476 }
477
16c628de
MS
478 /* Clear pointers in lsp struct, in case we're cacheing
479 * free context structs.
480 */
481 (*pctx)->u.lsp.nhlfe_list = NULL;
482 (*pctx)->u.lsp.best_nhlfe = NULL;
483
484 break;
485 }
486
97d8d05a
MS
487 case DPLANE_OP_PW_INSTALL:
488 case DPLANE_OP_PW_UNINSTALL:
16d69787
MS
489 /* Free allocated nexthops */
490 if ((*pctx)->u.pw.nhg.nexthop) {
491 /* This deals with recursive nexthops too */
492 nexthops_free((*pctx)->u.pw.nhg.nexthop);
493
494 (*pctx)->u.pw.nhg.nexthop = NULL;
495 }
496 break;
497
a4a4802a
MS
498 case DPLANE_OP_ADDR_INSTALL:
499 case DPLANE_OP_ADDR_UNINSTALL:
64168803
MS
500 /* Maybe free label string, if allocated */
501 if ((*pctx)->u.intf.label != NULL &&
502 (*pctx)->u.intf.label != (*pctx)->u.intf.label_buf) {
503 free((*pctx)->u.intf.label);
504 (*pctx)->u.intf.label = NULL;
505 }
506 break;
507
7597ac7b
MS
508 case DPLANE_OP_MAC_INSTALL:
509 case DPLANE_OP_MAC_DELETE:
f2412b2d 510 case DPLANE_OP_NEIGH_INSTALL:
931fa60c 511 case DPLANE_OP_NEIGH_UPDATE:
f2412b2d 512 case DPLANE_OP_NEIGH_DELETE:
0bbd4ff4
MS
513 case DPLANE_OP_VTEP_ADD:
514 case DPLANE_OP_VTEP_DELETE:
16c628de
MS
515 case DPLANE_OP_NONE:
516 break;
7cdb1a84 517 }
16c628de
MS
518
519 XFREE(MTYPE_DP_CTX, *pctx);
520 *pctx = NULL;
7cdb1a84
MS
521}
522
523/*
524 * Return a context block to the dplane module after processing
525 */
25779064 526void dplane_ctx_fini(struct zebra_dplane_ctx **pctx)
7cdb1a84 527{
14b0bc8e 528 /* TODO -- maintain pool; for now, just free */
7cdb1a84
MS
529 dplane_ctx_free(pctx);
530}
531
532/* Enqueue a context block */
25779064
MS
533void dplane_ctx_enqueue_tail(struct dplane_ctx_q *q,
534 const struct zebra_dplane_ctx *ctx)
7cdb1a84 535{
25779064 536 TAILQ_INSERT_TAIL(q, (struct zebra_dplane_ctx *)ctx, zd_q_entries);
7cdb1a84
MS
537}
538
14b0bc8e
MS
539/* Append a list of context blocks to another list */
540void dplane_ctx_list_append(struct dplane_ctx_q *to_list,
541 struct dplane_ctx_q *from_list)
542{
543 if (TAILQ_FIRST(from_list)) {
544 TAILQ_CONCAT(to_list, from_list, zd_q_entries);
545
546 /* And clear 'from' list */
547 TAILQ_INIT(from_list);
548 }
549}
550
7cdb1a84 551/* Dequeue a context block from the head of a list */
68b375e0 552struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_q *q)
7cdb1a84 553{
25779064 554 struct zebra_dplane_ctx *ctx = TAILQ_FIRST(q);
5709131c
MS
555
556 if (ctx)
7cdb1a84 557 TAILQ_REMOVE(q, ctx, zd_q_entries);
7cdb1a84 558
68b375e0 559 return ctx;
7cdb1a84
MS
560}
561
562/*
563 * Accessors for information from the context object
564 */
25779064
MS
565enum zebra_dplane_result dplane_ctx_get_status(
566 const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
567{
568 DPLANE_CTX_VALID(ctx);
569
5709131c 570 return ctx->zd_status;
7cdb1a84
MS
571}
572
c831033f
MS
573void dplane_ctx_set_status(struct zebra_dplane_ctx *ctx,
574 enum zebra_dplane_result status)
575{
576 DPLANE_CTX_VALID(ctx);
577
578 ctx->zd_status = status;
579}
580
581/* Retrieve last/current provider id */
582uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx)
583{
584 DPLANE_CTX_VALID(ctx);
585 return ctx->zd_provider;
586}
587
588/* Providers run before the kernel can control whether a kernel
589 * update should be done.
590 */
591void dplane_ctx_set_skip_kernel(struct zebra_dplane_ctx *ctx)
592{
593 DPLANE_CTX_VALID(ctx);
594
595 SET_FLAG(ctx->zd_flags, DPLANE_CTX_FLAG_NO_KERNEL);
596}
597
598bool dplane_ctx_is_skip_kernel(const struct zebra_dplane_ctx *ctx)
599{
600 DPLANE_CTX_VALID(ctx);
601
602 return CHECK_FLAG(ctx->zd_flags, DPLANE_CTX_FLAG_NO_KERNEL);
603}
604
593e4eb1
MS
605void dplane_ctx_set_op(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
606{
607 DPLANE_CTX_VALID(ctx);
608 ctx->zd_op = op;
609}
610
25779064 611enum dplane_op_e dplane_ctx_get_op(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
612{
613 DPLANE_CTX_VALID(ctx);
614
5709131c 615 return ctx->zd_op;
7cdb1a84
MS
616}
617
5709131c 618const char *dplane_op2str(enum dplane_op_e op)
7cdb1a84
MS
619{
620 const char *ret = "UNKNOWN";
621
5709131c 622 switch (op) {
7cdb1a84
MS
623 case DPLANE_OP_NONE:
624 ret = "NONE";
625 break;
626
627 /* Route update */
628 case DPLANE_OP_ROUTE_INSTALL:
629 ret = "ROUTE_INSTALL";
630 break;
631 case DPLANE_OP_ROUTE_UPDATE:
632 ret = "ROUTE_UPDATE";
633 break;
634 case DPLANE_OP_ROUTE_DELETE:
635 ret = "ROUTE_DELETE";
636 break;
54818e3b
MS
637 case DPLANE_OP_ROUTE_NOTIFY:
638 ret = "ROUTE_NOTIFY";
639 break;
7cdb1a84 640
16c628de
MS
641 case DPLANE_OP_LSP_INSTALL:
642 ret = "LSP_INSTALL";
643 break;
644 case DPLANE_OP_LSP_UPDATE:
645 ret = "LSP_UPDATE";
646 break;
647 case DPLANE_OP_LSP_DELETE:
648 ret = "LSP_DELETE";
649 break;
104e3ad9
MS
650 case DPLANE_OP_LSP_NOTIFY:
651 ret = "LSP_NOTIFY";
652 break;
16c628de 653
97d8d05a
MS
654 case DPLANE_OP_PW_INSTALL:
655 ret = "PW_INSTALL";
656 break;
657 case DPLANE_OP_PW_UNINSTALL:
658 ret = "PW_UNINSTALL";
659 break;
660
cf363e1b
MS
661 case DPLANE_OP_SYS_ROUTE_ADD:
662 ret = "SYS_ROUTE_ADD";
663 break;
664 case DPLANE_OP_SYS_ROUTE_DELETE:
665 ret = "SYS_ROUTE_DEL";
666 break;
a4a4802a
MS
667
668 case DPLANE_OP_ADDR_INSTALL:
669 ret = "ADDR_INSTALL";
670 break;
671 case DPLANE_OP_ADDR_UNINSTALL:
672 ret = "ADDR_UNINSTALL";
673 break;
674
7597ac7b
MS
675 case DPLANE_OP_MAC_INSTALL:
676 ret = "MAC_INSTALL";
677 break;
678 case DPLANE_OP_MAC_DELETE:
679 ret = "MAC_DELETE";
680 break;
f2412b2d
MS
681
682 case DPLANE_OP_NEIGH_INSTALL:
683 ret = "NEIGH_INSTALL";
684 break;
931fa60c
MS
685 case DPLANE_OP_NEIGH_UPDATE:
686 ret = "NEIGH_UPDATE";
687 break;
f2412b2d
MS
688 case DPLANE_OP_NEIGH_DELETE:
689 ret = "NEIGH_DELETE";
690 break;
0bbd4ff4
MS
691 case DPLANE_OP_VTEP_ADD:
692 ret = "VTEP_ADD";
693 break;
694 case DPLANE_OP_VTEP_DELETE:
695 ret = "VTEP_DELETE";
696 break;
5b94ec50 697 }
7cdb1a84 698
5709131c 699 return ret;
7cdb1a84
MS
700}
701
f183e380
MS
702const char *dplane_res2str(enum zebra_dplane_result res)
703{
704 const char *ret = "<Unknown>";
705
706 switch (res) {
707 case ZEBRA_DPLANE_REQUEST_FAILURE:
708 ret = "FAILURE";
709 break;
710 case ZEBRA_DPLANE_REQUEST_QUEUED:
711 ret = "QUEUED";
712 break;
713 case ZEBRA_DPLANE_REQUEST_SUCCESS:
714 ret = "SUCCESS";
715 break;
5b94ec50 716 }
f183e380
MS
717
718 return ret;
719}
720
593e4eb1
MS
721void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx,
722 const struct prefix *dest)
723{
724 DPLANE_CTX_VALID(ctx);
725
726 prefix_copy(&(ctx->u.rinfo.zd_dest), dest);
727}
728
25779064 729const struct prefix *dplane_ctx_get_dest(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
730{
731 DPLANE_CTX_VALID(ctx);
732
0f461727 733 return &(ctx->u.rinfo.zd_dest);
7cdb1a84
MS
734}
735
593e4eb1
MS
736void dplane_ctx_set_src(struct zebra_dplane_ctx *ctx, const struct prefix *src)
737{
738 DPLANE_CTX_VALID(ctx);
739
740 if (src)
741 prefix_copy(&(ctx->u.rinfo.zd_src), src);
742 else
743 memset(&(ctx->u.rinfo.zd_src), 0, sizeof(struct prefix));
744}
745
5709131c 746/* Source prefix is a little special - return NULL for "no src prefix" */
25779064 747const struct prefix *dplane_ctx_get_src(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
748{
749 DPLANE_CTX_VALID(ctx);
750
0f461727
MS
751 if (ctx->u.rinfo.zd_src.prefixlen == 0 &&
752 IN6_IS_ADDR_UNSPECIFIED(&(ctx->u.rinfo.zd_src.u.prefix6))) {
5709131c 753 return NULL;
7cdb1a84 754 } else {
0f461727 755 return &(ctx->u.rinfo.zd_src);
7cdb1a84
MS
756 }
757}
758
25779064 759bool dplane_ctx_is_update(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
760{
761 DPLANE_CTX_VALID(ctx);
762
5709131c 763 return ctx->zd_is_update;
7cdb1a84
MS
764}
765
25779064 766uint32_t dplane_ctx_get_seq(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
767{
768 DPLANE_CTX_VALID(ctx);
769
5709131c 770 return ctx->zd_seq;
7cdb1a84
MS
771}
772
25779064 773uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
774{
775 DPLANE_CTX_VALID(ctx);
776
5709131c 777 return ctx->zd_old_seq;
7cdb1a84
MS
778}
779
593e4eb1
MS
780void dplane_ctx_set_vrf(struct zebra_dplane_ctx *ctx, vrf_id_t vrf)
781{
782 DPLANE_CTX_VALID(ctx);
783
784 ctx->zd_vrf_id = vrf;
785}
786
25779064 787vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
788{
789 DPLANE_CTX_VALID(ctx);
790
5709131c 791 return ctx->zd_vrf_id;
7cdb1a84
MS
792}
793
0024a559
MS
794bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx)
795{
796 DPLANE_CTX_VALID(ctx);
797
798 return (ctx->zd_notif_provider != 0);
799}
800
801uint32_t dplane_ctx_get_notif_provider(const struct zebra_dplane_ctx *ctx)
802{
803 DPLANE_CTX_VALID(ctx);
804
805 return ctx->zd_notif_provider;
806}
807
9651af61
MS
808void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx,
809 uint32_t id)
810{
811 DPLANE_CTX_VALID(ctx);
812
813 ctx->zd_notif_provider = id;
814}
7c7ef4a8
MS
815const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx)
816{
817 DPLANE_CTX_VALID(ctx);
818
819 return ctx->zd_ifname;
820}
821
822ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx)
823{
824 DPLANE_CTX_VALID(ctx);
825
826 return ctx->zd_ifindex;
827}
9651af61 828
593e4eb1
MS
829void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type)
830{
831 DPLANE_CTX_VALID(ctx);
832
833 ctx->u.rinfo.zd_type = type;
834}
835
25779064 836int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
837{
838 DPLANE_CTX_VALID(ctx);
839
0f461727 840 return ctx->u.rinfo.zd_type;
7cdb1a84
MS
841}
842
25779064 843int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
844{
845 DPLANE_CTX_VALID(ctx);
846
0f461727 847 return ctx->u.rinfo.zd_old_type;
7cdb1a84
MS
848}
849
593e4eb1
MS
850void dplane_ctx_set_afi(struct zebra_dplane_ctx *ctx, afi_t afi)
851{
852 DPLANE_CTX_VALID(ctx);
853
854 ctx->u.rinfo.zd_afi = afi;
855}
856
25779064 857afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
858{
859 DPLANE_CTX_VALID(ctx);
860
0f461727 861 return ctx->u.rinfo.zd_afi;
7cdb1a84
MS
862}
863
593e4eb1
MS
864void dplane_ctx_set_safi(struct zebra_dplane_ctx *ctx, safi_t safi)
865{
866 DPLANE_CTX_VALID(ctx);
867
868 ctx->u.rinfo.zd_safi = safi;
869}
870
25779064 871safi_t dplane_ctx_get_safi(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
872{
873 DPLANE_CTX_VALID(ctx);
874
0f461727 875 return ctx->u.rinfo.zd_safi;
7cdb1a84
MS
876}
877
593e4eb1
MS
878void dplane_ctx_set_table(struct zebra_dplane_ctx *ctx, uint32_t table)
879{
880 DPLANE_CTX_VALID(ctx);
881
882 ctx->zd_table_id = table;
883}
884
25779064 885uint32_t dplane_ctx_get_table(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
886{
887 DPLANE_CTX_VALID(ctx);
888
5709131c 889 return ctx->zd_table_id;
7cdb1a84
MS
890}
891
25779064 892route_tag_t dplane_ctx_get_tag(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
893{
894 DPLANE_CTX_VALID(ctx);
895
0f461727 896 return ctx->u.rinfo.zd_tag;
7cdb1a84
MS
897}
898
6a91ae98
MS
899void dplane_ctx_set_tag(struct zebra_dplane_ctx *ctx, route_tag_t tag)
900{
901 DPLANE_CTX_VALID(ctx);
902
903 ctx->u.rinfo.zd_tag = tag;
904}
905
25779064 906route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
907{
908 DPLANE_CTX_VALID(ctx);
909
0f461727 910 return ctx->u.rinfo.zd_old_tag;
7cdb1a84
MS
911}
912
25779064 913uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
914{
915 DPLANE_CTX_VALID(ctx);
916
0f461727 917 return ctx->u.rinfo.zd_instance;
7cdb1a84
MS
918}
919
6a91ae98
MS
920void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance)
921{
922 DPLANE_CTX_VALID(ctx);
923
924 ctx->u.rinfo.zd_instance = instance;
925}
926
25779064 927uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
928{
929 DPLANE_CTX_VALID(ctx);
930
0f461727 931 return ctx->u.rinfo.zd_old_instance;
7cdb1a84
MS
932}
933
25779064 934uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
935{
936 DPLANE_CTX_VALID(ctx);
937
0f461727 938 return ctx->u.rinfo.zd_metric;
7cdb1a84
MS
939}
940
25779064 941uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx)
01ce7cba
MS
942{
943 DPLANE_CTX_VALID(ctx);
944
0f461727 945 return ctx->u.rinfo.zd_old_metric;
01ce7cba
MS
946}
947
25779064 948uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
949{
950 DPLANE_CTX_VALID(ctx);
951
0f461727 952 return ctx->u.rinfo.zd_mtu;
7cdb1a84
MS
953}
954
25779064 955uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
956{
957 DPLANE_CTX_VALID(ctx);
958
0f461727 959 return ctx->u.rinfo.zd_nexthop_mtu;
7cdb1a84
MS
960}
961
25779064 962uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
963{
964 DPLANE_CTX_VALID(ctx);
965
0f461727 966 return ctx->u.rinfo.zd_distance;
7cdb1a84
MS
967}
968
6a91ae98
MS
969void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance)
970{
971 DPLANE_CTX_VALID(ctx);
972
973 ctx->u.rinfo.zd_distance = distance;
974}
975
25779064 976uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
977{
978 DPLANE_CTX_VALID(ctx);
979
0f461727 980 return ctx->u.rinfo.zd_old_distance;
7cdb1a84
MS
981}
982
593e4eb1
MS
983void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
984{
985 DPLANE_CTX_VALID(ctx);
986
987 if (ctx->u.rinfo.zd_ng.nexthop) {
988 nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
989 ctx->u.rinfo.zd_ng.nexthop = NULL;
990 }
991 copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), nh, NULL);
992}
993
25779064
MS
994const struct nexthop_group *dplane_ctx_get_ng(
995 const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
996{
997 DPLANE_CTX_VALID(ctx);
998
0f461727 999 return &(ctx->u.rinfo.zd_ng);
7cdb1a84
MS
1000}
1001
25779064
MS
1002const struct nexthop_group *dplane_ctx_get_old_ng(
1003 const struct zebra_dplane_ctx *ctx)
01ce7cba
MS
1004{
1005 DPLANE_CTX_VALID(ctx);
1006
0f461727 1007 return &(ctx->u.rinfo.zd_old_ng);
01ce7cba
MS
1008}
1009
25779064
MS
1010const struct zebra_dplane_info *dplane_ctx_get_ns(
1011 const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1012{
1013 DPLANE_CTX_VALID(ctx);
1014
5709131c 1015 return &(ctx->zd_ns_info);
7cdb1a84
MS
1016}
1017
0f461727
MS
1018/* Accessors for LSP information */
1019
1020mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx)
1021{
1022 DPLANE_CTX_VALID(ctx);
1023
1024 return ctx->u.lsp.ile.in_label;
1025}
1026
3ab54059
MS
1027void dplane_ctx_set_in_label(struct zebra_dplane_ctx *ctx, mpls_label_t label)
1028{
1029 DPLANE_CTX_VALID(ctx);
1030
1031 ctx->u.lsp.ile.in_label = label;
1032}
1033
0f461727
MS
1034uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx)
1035{
1036 DPLANE_CTX_VALID(ctx);
1037
1038 return ctx->u.lsp.addr_family;
1039}
1040
3ab54059
MS
1041void dplane_ctx_set_addr_family(struct zebra_dplane_ctx *ctx,
1042 uint8_t family)
1043{
1044 DPLANE_CTX_VALID(ctx);
1045
1046 ctx->u.lsp.addr_family = family;
1047}
1048
0f461727
MS
1049uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx)
1050{
1051 DPLANE_CTX_VALID(ctx);
1052
1053 return ctx->u.lsp.flags;
1054}
1055
3ab54059
MS
1056void dplane_ctx_set_lsp_flags(struct zebra_dplane_ctx *ctx,
1057 uint32_t flags)
1058{
1059 DPLANE_CTX_VALID(ctx);
1060
1061 ctx->u.lsp.flags = flags;
1062}
1063
81793ac1 1064const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx)
0f461727
MS
1065{
1066 DPLANE_CTX_VALID(ctx);
1067
1068 return ctx->u.lsp.nhlfe_list;
1069}
1070
3ab54059
MS
1071zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
1072 enum lsp_types_t lsp_type,
1073 enum nexthop_types_t nh_type,
1074 union g_addr *gate,
1075 ifindex_t ifindex,
1076 mpls_label_t out_label)
1077{
1078 zebra_nhlfe_t *nhlfe;
1079
1080 DPLANE_CTX_VALID(ctx);
1081
1082 nhlfe = zebra_mpls_lsp_add_nhlfe(&(ctx->u.lsp),
1083 lsp_type, nh_type, gate,
1084 ifindex, out_label);
1085
1086 return nhlfe;
1087}
1088
81793ac1
MS
1089const zebra_nhlfe_t *
1090dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx)
0f461727
MS
1091{
1092 DPLANE_CTX_VALID(ctx);
1093
1094 return ctx->u.lsp.best_nhlfe;
1095}
1096
3ab54059
MS
1097const zebra_nhlfe_t *
1098dplane_ctx_set_best_nhlfe(struct zebra_dplane_ctx *ctx,
1099 zebra_nhlfe_t *nhlfe)
1100{
1101 DPLANE_CTX_VALID(ctx);
1102
1103 ctx->u.lsp.best_nhlfe = nhlfe;
1104 return ctx->u.lsp.best_nhlfe;
1105}
1106
0f461727
MS
1107uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx)
1108{
1109 DPLANE_CTX_VALID(ctx);
1110
1111 return ctx->u.lsp.num_ecmp;
1112}
1113
d613b8e1
MS
1114mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx)
1115{
1116 DPLANE_CTX_VALID(ctx);
1117
1118 return ctx->u.pw.local_label;
1119}
1120
1121mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx)
1122{
1123 DPLANE_CTX_VALID(ctx);
1124
1125 return ctx->u.pw.remote_label;
1126}
1127
1128int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx)
1129{
1130 DPLANE_CTX_VALID(ctx);
1131
1132 return ctx->u.pw.type;
1133}
1134
1135int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx)
1136{
1137 DPLANE_CTX_VALID(ctx);
1138
1139 return ctx->u.pw.af;
1140}
1141
1142uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx)
1143{
1144 DPLANE_CTX_VALID(ctx);
1145
1146 return ctx->u.pw.flags;
1147}
1148
1149int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx)
1150{
1151 DPLANE_CTX_VALID(ctx);
1152
1153 return ctx->u.pw.status;
1154}
1155
16d69787 1156const union g_addr *dplane_ctx_get_pw_dest(
d613b8e1
MS
1157 const struct zebra_dplane_ctx *ctx)
1158{
1159 DPLANE_CTX_VALID(ctx);
1160
16d69787 1161 return &(ctx->u.pw.dest);
d613b8e1
MS
1162}
1163
1164const union pw_protocol_fields *dplane_ctx_get_pw_proto(
1165 const struct zebra_dplane_ctx *ctx)
1166{
1167 DPLANE_CTX_VALID(ctx);
1168
1169 return &(ctx->u.pw.fields);
1170}
1171
09cd307c
MS
1172const struct nexthop_group *
1173dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx)
1174{
1175 DPLANE_CTX_VALID(ctx);
1176
1177 return &(ctx->u.pw.nhg);
1178}
1179
a4a4802a 1180/* Accessors for interface information */
a4a4802a
MS
1181uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx)
1182{
1183 DPLANE_CTX_VALID(ctx);
1184
1185 return ctx->u.intf.metric;
1186}
1187
1188/* Is interface addr p2p? */
1189bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
1190{
1191 DPLANE_CTX_VALID(ctx);
1192
1193 return (ctx->u.intf.flags & DPLANE_INTF_CONNECTED);
1194}
1195
1196bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx)
1197{
1198 DPLANE_CTX_VALID(ctx);
1199
1200 return (ctx->u.intf.flags & DPLANE_INTF_SECONDARY);
1201}
1202
64168803
MS
1203bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx)
1204{
1205 DPLANE_CTX_VALID(ctx);
1206
1207 return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST);
1208}
1209
a4a4802a
MS
1210const struct prefix *dplane_ctx_get_intf_addr(
1211 const struct zebra_dplane_ctx *ctx)
1212{
1213 DPLANE_CTX_VALID(ctx);
1214
1215 return &(ctx->u.intf.prefix);
1216}
1217
1218bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx)
1219{
1220 DPLANE_CTX_VALID(ctx);
1221
1222 return (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST);
1223}
1224
1225const struct prefix *dplane_ctx_get_intf_dest(
1226 const struct zebra_dplane_ctx *ctx)
1227{
1228 DPLANE_CTX_VALID(ctx);
1229
1230 if (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST)
1231 return &(ctx->u.intf.dest_prefix);
1232 else
1233 return NULL;
1234}
1235
1236bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx)
1237{
1238 DPLANE_CTX_VALID(ctx);
1239
1240 return (ctx->u.intf.flags & DPLANE_INTF_HAS_LABEL);
1241}
1242
1243const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx)
1244{
1245 DPLANE_CTX_VALID(ctx);
1246
1247 return ctx->u.intf.label;
1248}
1249
7597ac7b
MS
1250/* Accessors for MAC information */
1251vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx)
1252{
1253 DPLANE_CTX_VALID(ctx);
1254 return ctx->u.macinfo.vid;
1255}
1256
1257bool dplane_ctx_mac_is_sticky(const struct zebra_dplane_ctx *ctx)
1258{
1259 DPLANE_CTX_VALID(ctx);
1260 return ctx->u.macinfo.is_sticky;
1261}
1262
1263const struct ethaddr *dplane_ctx_mac_get_addr(
1264 const struct zebra_dplane_ctx *ctx)
1265{
1266 DPLANE_CTX_VALID(ctx);
1267 return &(ctx->u.macinfo.mac);
1268}
1269
1270const struct in_addr *dplane_ctx_mac_get_vtep_ip(
1271 const struct zebra_dplane_ctx *ctx)
1272{
1273 DPLANE_CTX_VALID(ctx);
1274 return &(ctx->u.macinfo.vtep_ip);
1275}
1276
478566d6
MS
1277ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx)
1278{
1279 DPLANE_CTX_VALID(ctx);
1280 return ctx->u.macinfo.br_ifindex;
1281}
1282
931fa60c
MS
1283/* Accessors for neighbor information */
1284const struct ipaddr *dplane_ctx_neigh_get_ipaddr(
1285 const struct zebra_dplane_ctx *ctx)
1286{
1287 DPLANE_CTX_VALID(ctx);
1288 return &(ctx->u.neigh.ip_addr);
1289}
1290
1291const struct ethaddr *dplane_ctx_neigh_get_mac(
1292 const struct zebra_dplane_ctx *ctx)
1293{
1294 DPLANE_CTX_VALID(ctx);
1295 return &(ctx->u.neigh.mac);
1296}
1297
1298uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx)
1299{
1300 DPLANE_CTX_VALID(ctx);
1301 return ctx->u.neigh.flags;
1302}
1303
1304uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx)
1305{
1306 DPLANE_CTX_VALID(ctx);
1307 return ctx->u.neigh.state;
1308}
1309
7cdb1a84
MS
1310/*
1311 * End of dplane context accessors
1312 */
1313
c831033f 1314
91f16812
MS
1315/*
1316 * Retrieve the limit on the number of pending, unprocessed updates.
1317 */
1318uint32_t dplane_get_in_queue_limit(void)
1319{
1320 return atomic_load_explicit(&zdplane_info.dg_max_queued_updates,
1321 memory_order_relaxed);
1322}
1323
1324/*
1325 * Configure limit on the number of pending, queued updates.
1326 */
1327void dplane_set_in_queue_limit(uint32_t limit, bool set)
1328{
1329 /* Reset to default on 'unset' */
1330 if (!set)
1331 limit = DPLANE_DEFAULT_MAX_QUEUED;
1332
1333 atomic_store_explicit(&zdplane_info.dg_max_queued_updates, limit,
1334 memory_order_relaxed);
1335}
1336
1337/*
1338 * Retrieve the current queue depth of incoming, unprocessed updates
1339 */
1340uint32_t dplane_get_in_queue_len(void)
1341{
1342 return atomic_load_explicit(&zdplane_info.dg_routes_queued,
1343 memory_order_seq_cst);
1344}
1345
16c628de
MS
1346/*
1347 * Common dataplane context init with zebra namespace info.
1348 */
1349static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
1350 struct zebra_ns *zns,
1351 bool is_update)
1352{
1353 dplane_info_from_zns(&(ctx->zd_ns_info), zns);
1354
1355#if defined(HAVE_NETLINK)
1356 /* Increment message counter after copying to context struct - may need
1357 * two messages in some 'update' cases.
1358 */
1359 if (is_update)
1360 zns->netlink_dplane.seq += 2;
1361 else
1362 zns->netlink_dplane.seq++;
1363#endif /* HAVE_NETLINK */
1364
1365 return AOK;
1366}
1367
7cdb1a84
MS
1368/*
1369 * Initialize a context block for a route update from zebra data structs.
1370 */
25779064 1371static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
5709131c 1372 enum dplane_op_e op,
7cdb1a84
MS
1373 struct route_node *rn,
1374 struct route_entry *re)
1375{
1376 int ret = EINVAL;
1377 const struct route_table *table = NULL;
1378 const rib_table_info_t *info;
1379 const struct prefix *p, *src_p;
1380 struct zebra_ns *zns;
1381 struct zebra_vrf *zvrf;
f183e380 1382 struct nexthop *nexthop;
7cdb1a84 1383
5709131c 1384 if (!ctx || !rn || !re)
7cdb1a84 1385 goto done;
7cdb1a84
MS
1386
1387 ctx->zd_op = op;
14b0bc8e 1388 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
7cdb1a84 1389
0f461727
MS
1390 ctx->u.rinfo.zd_type = re->type;
1391 ctx->u.rinfo.zd_old_type = re->type;
7cdb1a84
MS
1392
1393 /* Prefixes: dest, and optional source */
1394 srcdest_rnode_prefixes(rn, &p, &src_p);
1395
0f461727 1396 prefix_copy(&(ctx->u.rinfo.zd_dest), p);
7cdb1a84 1397
5709131c 1398 if (src_p)
0f461727 1399 prefix_copy(&(ctx->u.rinfo.zd_src), src_p);
5709131c 1400 else
0f461727 1401 memset(&(ctx->u.rinfo.zd_src), 0, sizeof(ctx->u.rinfo.zd_src));
7cdb1a84
MS
1402
1403 ctx->zd_table_id = re->table;
1404
0f461727
MS
1405 ctx->u.rinfo.zd_metric = re->metric;
1406 ctx->u.rinfo.zd_old_metric = re->metric;
7cdb1a84 1407 ctx->zd_vrf_id = re->vrf_id;
0f461727
MS
1408 ctx->u.rinfo.zd_mtu = re->mtu;
1409 ctx->u.rinfo.zd_nexthop_mtu = re->nexthop_mtu;
1410 ctx->u.rinfo.zd_instance = re->instance;
1411 ctx->u.rinfo.zd_tag = re->tag;
1412 ctx->u.rinfo.zd_old_tag = re->tag;
1413 ctx->u.rinfo.zd_distance = re->distance;
7cdb1a84
MS
1414
1415 table = srcdest_rnode_table(rn);
1416 info = table->info;
1417
0f461727
MS
1418 ctx->u.rinfo.zd_afi = info->afi;
1419 ctx->u.rinfo.zd_safi = info->safi;
7cdb1a84 1420
7cdb1a84 1421 /* Copy nexthops; recursive info is included too */
6b468511 1422 copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng->nexthop, NULL);
7cdb1a84 1423
14b0bc8e 1424 /* Ensure that the dplane's nexthops flags are clear. */
0f461727 1425 for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop))
f183e380 1426 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
f183e380 1427
cf363e1b
MS
1428 /* Don't need some info when capturing a system notification */
1429 if (op == DPLANE_OP_SYS_ROUTE_ADD ||
1430 op == DPLANE_OP_SYS_ROUTE_DELETE) {
1431 ret = AOK;
1432 goto done;
1433 }
1434
1435 /* Extract ns info - can't use pointers to 'core' structs */
1436 zvrf = vrf_info_lookup(re->vrf_id);
1437 zns = zvrf->zns;
1438 dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
1439
7cdb1a84
MS
1440 /* Trying out the sequence number idea, so we can try to detect
1441 * when a result is stale.
1442 */
1485bbe7 1443 re->dplane_sequence = zebra_router_get_next_sequence();
7cdb1a84
MS
1444 ctx->zd_seq = re->dplane_sequence;
1445
1446 ret = AOK;
1447
1448done:
1449 return ret;
1450}
1451
16c628de
MS
1452/*
1453 * Capture information for an LSP update in a dplane context.
1454 */
1455static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx,
1456 enum dplane_op_e op,
1457 zebra_lsp_t *lsp)
1458{
1459 int ret = AOK;
1460 zebra_nhlfe_t *nhlfe, *new_nhlfe;
1461
1462 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1463 zlog_debug("init dplane ctx %s: in-label %u ecmp# %d",
1464 dplane_op2str(op), lsp->ile.in_label,
1465 lsp->num_ecmp);
1466
1467 ctx->zd_op = op;
1468 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
1469
1470 /* Capture namespace info */
1471 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
1472 (op == DPLANE_OP_LSP_UPDATE));
1473
1474 memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp));
1475
1476 ctx->u.lsp.ile = lsp->ile;
1477 ctx->u.lsp.addr_family = lsp->addr_family;
1478 ctx->u.lsp.num_ecmp = lsp->num_ecmp;
1479 ctx->u.lsp.flags = lsp->flags;
1480
1481 /* Copy source LSP's nhlfes, and capture 'best' nhlfe */
1482 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
1483 /* Not sure if this is meaningful... */
1484 if (nhlfe->nexthop == NULL)
1485 continue;
1486
1487 new_nhlfe =
1488 zebra_mpls_lsp_add_nhlfe(
1489 &(ctx->u.lsp),
1490 nhlfe->type,
1491 nhlfe->nexthop->type,
1492 &(nhlfe->nexthop->gate),
1493 nhlfe->nexthop->ifindex,
1494 nhlfe->nexthop->nh_label->label[0]);
1495
1496 if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) {
1497 ret = ENOMEM;
1498 break;
1499 }
1500
1501 /* Need to copy flags too */
1502 new_nhlfe->flags = nhlfe->flags;
1503 new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
1504
1505 if (nhlfe == lsp->best_nhlfe)
1506 ctx->u.lsp.best_nhlfe = new_nhlfe;
1507 }
1508
1509 /* On error the ctx will be cleaned-up, so we don't need to
1510 * deal with any allocated nhlfe or nexthop structs here.
1511 */
1512
1513 return ret;
1514}
1515
97d8d05a
MS
1516/*
1517 * Capture information for an LSP update in a dplane context.
1518 */
1519static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
1520 enum dplane_op_e op,
1521 struct zebra_pw *pw)
1522{
09cd307c
MS
1523 struct prefix p;
1524 afi_t afi;
1525 struct route_table *table;
1526 struct route_node *rn;
1527 struct route_entry *re;
1528
97d8d05a
MS
1529 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1530 zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
1531 dplane_op2str(op), pw->ifname, pw->local_label,
1532 pw->remote_label);
1533
1534 ctx->zd_op = op;
1535 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
1536
1537 /* Capture namespace info: no netlink support as of 12/18,
1538 * but just in case...
1539 */
1540 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
1541
1542 memset(&ctx->u.pw, 0, sizeof(ctx->u.pw));
1543
1544 /* This name appears to be c-string, so we use string copy. */
7c7ef4a8 1545 strlcpy(ctx->zd_ifname, pw->ifname, sizeof(ctx->zd_ifname));
16d69787 1546
9bd9717b 1547 ctx->zd_vrf_id = pw->vrf_id;
7c7ef4a8 1548 ctx->zd_ifindex = pw->ifindex;
97d8d05a
MS
1549 ctx->u.pw.type = pw->type;
1550 ctx->u.pw.af = pw->af;
1551 ctx->u.pw.local_label = pw->local_label;
1552 ctx->u.pw.remote_label = pw->remote_label;
1553 ctx->u.pw.flags = pw->flags;
1554
16d69787 1555 ctx->u.pw.dest = pw->nexthop;
97d8d05a
MS
1556
1557 ctx->u.pw.fields = pw->data;
1558
09cd307c
MS
1559 /* Capture nexthop info for the pw destination. We need to look
1560 * up and use zebra datastructs, but we're running in the zebra
1561 * pthread here so that should be ok.
1562 */
1563 memcpy(&p.u, &pw->nexthop, sizeof(pw->nexthop));
1564 p.family = pw->af;
1565 p.prefixlen = ((pw->af == AF_INET) ?
1566 IPV4_MAX_PREFIXLEN : IPV6_MAX_PREFIXLEN);
1567
1568 afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6;
1569 table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id);
1570 if (table) {
1571 rn = route_node_match(table, &p);
1572 if (rn) {
1573 RNODE_FOREACH_RE(rn, re) {
1574 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
1575 break;
1576 }
1577
1578 if (re)
1579 copy_nexthops(&(ctx->u.pw.nhg.nexthop),
6b468511 1580 re->ng->nexthop, NULL);
09cd307c
MS
1581
1582 route_unlock_node(rn);
1583 }
1584 }
1585
9f2d0354 1586 return AOK;
97d8d05a
MS
1587}
1588
7cdb1a84 1589/*
3fe4ccc4 1590 * Enqueue a new update,
16c628de 1591 * and ensure an event is active for the dataplane pthread.
7cdb1a84 1592 */
3fe4ccc4 1593static int dplane_update_enqueue(struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1594{
1595 int ret = EINVAL;
91f16812 1596 uint32_t high, curr;
7cdb1a84 1597
16c628de 1598 /* Enqueue for processing by the dataplane pthread */
7cdb1a84
MS
1599 DPLANE_LOCK();
1600 {
3fe4ccc4 1601 TAILQ_INSERT_TAIL(&zdplane_info.dg_update_ctx_q, ctx,
25779064 1602 zd_q_entries);
7cdb1a84
MS
1603 }
1604 DPLANE_UNLOCK();
1605
e07e9549
MS
1606 curr = atomic_add_fetch_explicit(
1607#ifdef __clang__
1608 /* TODO -- issue with the clang atomic/intrinsics currently;
1609 * casting away the 'Atomic'-ness of the variable works.
1610 */
1611 (uint32_t *)&(zdplane_info.dg_routes_queued),
1612#else
1613 &(zdplane_info.dg_routes_queued),
1614#endif
1615 1, memory_order_seq_cst);
91f16812
MS
1616
1617 /* Maybe update high-water counter also */
1618 high = atomic_load_explicit(&zdplane_info.dg_routes_queued_max,
1619 memory_order_seq_cst);
1620 while (high < curr) {
1621 if (atomic_compare_exchange_weak_explicit(
1622 &zdplane_info.dg_routes_queued_max,
1623 &high, curr,
1624 memory_order_seq_cst,
1625 memory_order_seq_cst))
1626 break;
1627 }
1628
7cdb1a84 1629 /* Ensure that an event for the dataplane thread is active */
c831033f 1630 ret = dplane_provider_work_ready();
7cdb1a84 1631
5709131c 1632 return ret;
7cdb1a84
MS
1633}
1634
7cdb1a84
MS
1635/*
1636 * Utility that prepares a route update and enqueues it for processing
1637 */
655d681a
MS
1638static enum zebra_dplane_result
1639dplane_route_update_internal(struct route_node *rn,
1640 struct route_entry *re,
1641 struct route_entry *old_re,
5709131c 1642 enum dplane_op_e op)
7cdb1a84 1643{
655d681a 1644 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
7cdb1a84 1645 int ret = EINVAL;
25779064 1646 struct zebra_dplane_ctx *ctx = NULL;
7cdb1a84
MS
1647
1648 /* Obtain context block */
1649 ctx = dplane_ctx_alloc();
7cdb1a84
MS
1650
1651 /* Init context with info from zebra data structs */
1652 ret = dplane_ctx_route_init(ctx, op, rn, re);
1653 if (ret == AOK) {
1654 /* Capture some extra info for update case
1655 * where there's a different 'old' route.
1656 */
b8e0423d
MS
1657 if ((op == DPLANE_OP_ROUTE_UPDATE) &&
1658 old_re && (old_re != re)) {
7cdb1a84
MS
1659 ctx->zd_is_update = true;
1660
1485bbe7
DS
1661 old_re->dplane_sequence =
1662 zebra_router_get_next_sequence();
7cdb1a84
MS
1663 ctx->zd_old_seq = old_re->dplane_sequence;
1664
0f461727
MS
1665 ctx->u.rinfo.zd_old_tag = old_re->tag;
1666 ctx->u.rinfo.zd_old_type = old_re->type;
1667 ctx->u.rinfo.zd_old_instance = old_re->instance;
1668 ctx->u.rinfo.zd_old_distance = old_re->distance;
1669 ctx->u.rinfo.zd_old_metric = old_re->metric;
01ce7cba
MS
1670
1671#ifndef HAVE_NETLINK
f183e380
MS
1672 /* For bsd, capture previous re's nexthops too, sigh.
1673 * We'll need these to do per-nexthop deletes.
1674 */
0f461727 1675 copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
01ce7cba
MS
1676 old_re->ng.nexthop, NULL);
1677#endif /* !HAVE_NETLINK */
7cdb1a84
MS
1678 }
1679
1680 /* Enqueue context for processing */
3fe4ccc4 1681 ret = dplane_update_enqueue(ctx);
7cdb1a84
MS
1682 }
1683
91f16812 1684 /* Update counter */
25779064 1685 atomic_fetch_add_explicit(&zdplane_info.dg_routes_in, 1,
1d11b21f
MS
1686 memory_order_relaxed);
1687
91f16812 1688 if (ret == AOK)
655d681a 1689 result = ZEBRA_DPLANE_REQUEST_QUEUED;
16c628de 1690 else {
25779064 1691 atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, 1,
1d11b21f 1692 memory_order_relaxed);
16c628de
MS
1693 if (ctx)
1694 dplane_ctx_free(&ctx);
1d11b21f 1695 }
7cdb1a84 1696
5709131c 1697 return result;
7cdb1a84
MS
1698}
1699
1700/*
1701 * Enqueue a route 'add' for the dataplane.
1702 */
655d681a
MS
1703enum zebra_dplane_result dplane_route_add(struct route_node *rn,
1704 struct route_entry *re)
7cdb1a84 1705{
655d681a 1706 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
7cdb1a84 1707
5709131c 1708 if (rn == NULL || re == NULL)
7cdb1a84 1709 goto done;
7cdb1a84
MS
1710
1711 ret = dplane_route_update_internal(rn, re, NULL,
1712 DPLANE_OP_ROUTE_INSTALL);
1713
1714done:
5709131c 1715 return ret;
7cdb1a84
MS
1716}
1717
1718/*
1719 * Enqueue a route update for the dataplane.
1720 */
655d681a
MS
1721enum zebra_dplane_result dplane_route_update(struct route_node *rn,
1722 struct route_entry *re,
1723 struct route_entry *old_re)
7cdb1a84 1724{
655d681a 1725 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
7cdb1a84 1726
5709131c 1727 if (rn == NULL || re == NULL)
7cdb1a84 1728 goto done;
7cdb1a84
MS
1729
1730 ret = dplane_route_update_internal(rn, re, old_re,
1731 DPLANE_OP_ROUTE_UPDATE);
7cdb1a84 1732done:
5709131c 1733 return ret;
7cdb1a84
MS
1734}
1735
1736/*
1737 * Enqueue a route removal for the dataplane.
1738 */
655d681a
MS
1739enum zebra_dplane_result dplane_route_delete(struct route_node *rn,
1740 struct route_entry *re)
7cdb1a84 1741{
655d681a 1742 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
7cdb1a84 1743
5709131c 1744 if (rn == NULL || re == NULL)
7cdb1a84 1745 goto done;
7cdb1a84
MS
1746
1747 ret = dplane_route_update_internal(rn, re, NULL,
1748 DPLANE_OP_ROUTE_DELETE);
1749
1750done:
5709131c 1751 return ret;
7cdb1a84
MS
1752}
1753
cf363e1b
MS
1754/*
1755 * Notify the dplane when system/connected routes change.
1756 */
1757enum zebra_dplane_result dplane_sys_route_add(struct route_node *rn,
1758 struct route_entry *re)
1759{
1760 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
1761
1762 /* Ignore this event unless a provider plugin has requested it. */
1763 if (!zdplane_info.dg_sys_route_notifs) {
1764 ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
1765 goto done;
1766 }
1767
1768 if (rn == NULL || re == NULL)
1769 goto done;
1770
1771 ret = dplane_route_update_internal(rn, re, NULL,
1772 DPLANE_OP_SYS_ROUTE_ADD);
1773
1774done:
1775 return ret;
1776}
1777
1778/*
1779 * Notify the dplane when system/connected routes are deleted.
1780 */
1781enum zebra_dplane_result dplane_sys_route_del(struct route_node *rn,
1782 struct route_entry *re)
1783{
1784 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
1785
1786 /* Ignore this event unless a provider plugin has requested it. */
1787 if (!zdplane_info.dg_sys_route_notifs) {
1788 ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
1789 goto done;
1790 }
1791
1792 if (rn == NULL || re == NULL)
1793 goto done;
1794
1795 ret = dplane_route_update_internal(rn, re, NULL,
1796 DPLANE_OP_SYS_ROUTE_DELETE);
1797
1798done:
1799 return ret;
1800}
1801
188a00e0
MS
1802/*
1803 * Update from an async notification, to bring other fibs up-to-date.
1804 */
1805enum zebra_dplane_result
1806dplane_route_notif_update(struct route_node *rn,
1807 struct route_entry *re,
1808 enum dplane_op_e op,
1809 struct zebra_dplane_ctx *ctx)
1810{
1811 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
1812 struct zebra_dplane_ctx *new_ctx = NULL;
1813 struct nexthop *nexthop;
1814
1815 if (rn == NULL || re == NULL)
1816 goto done;
1817
1818 new_ctx = dplane_ctx_alloc();
1819 if (new_ctx == NULL)
1820 goto done;
1821
1822 /* Init context with info from zebra data structs */
1823 dplane_ctx_route_init(new_ctx, op, rn, re);
1824
1825 /* For add/update, need to adjust the nexthops so that we match
1826 * the notification state, which may not be the route-entry/RIB
1827 * state.
1828 */
1829 if (op == DPLANE_OP_ROUTE_UPDATE ||
1830 op == DPLANE_OP_ROUTE_INSTALL) {
1831
1832 nexthops_free(new_ctx->u.rinfo.zd_ng.nexthop);
1833 new_ctx->u.rinfo.zd_ng.nexthop = NULL;
1834
1835 copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
1836 (rib_active_nhg(re))->nexthop, NULL);
1837
1838 for (ALL_NEXTHOPS(new_ctx->u.rinfo.zd_ng, nexthop))
1839 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1840
1841 }
1842
1843 /* Capture info about the source of the notification, in 'ctx' */
1844 dplane_ctx_set_notif_provider(new_ctx,
1845 dplane_ctx_get_notif_provider(ctx));
1846
3fe4ccc4 1847 dplane_update_enqueue(new_ctx);
188a00e0
MS
1848
1849 ret = ZEBRA_DPLANE_REQUEST_QUEUED;
1850
1851done:
1852 return ret;
1853}
1854
16c628de
MS
1855/*
1856 * Enqueue LSP add for the dataplane.
1857 */
1858enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp)
1859{
1860 enum zebra_dplane_result ret =
1861 lsp_update_internal(lsp, DPLANE_OP_LSP_INSTALL);
1862
1863 return ret;
1864}
1865
1866/*
1867 * Enqueue LSP update for the dataplane.
1868 */
1869enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp)
1870{
1871 enum zebra_dplane_result ret =
1872 lsp_update_internal(lsp, DPLANE_OP_LSP_UPDATE);
1873
1874 return ret;
1875}
1876
1877/*
1878 * Enqueue LSP delete for the dataplane.
1879 */
1880enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp)
1881{
1882 enum zebra_dplane_result ret =
1883 lsp_update_internal(lsp, DPLANE_OP_LSP_DELETE);
1884
1885 return ret;
1886}
1887
188a00e0
MS
1888/* Update or un-install resulting from an async notification */
1889enum zebra_dplane_result
1890dplane_lsp_notif_update(zebra_lsp_t *lsp,
1891 enum dplane_op_e op,
1892 struct zebra_dplane_ctx *notif_ctx)
1893{
1894 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
1895 int ret = EINVAL;
1896 struct zebra_dplane_ctx *ctx = NULL;
1897
1898 /* Obtain context block */
1899 ctx = dplane_ctx_alloc();
1900 if (ctx == NULL) {
1901 ret = ENOMEM;
1902 goto done;
1903 }
1904
1905 ret = dplane_ctx_lsp_init(ctx, op, lsp);
1906 if (ret != AOK)
1907 goto done;
1908
1909 /* Capture info about the source of the notification */
1910 dplane_ctx_set_notif_provider(
1911 ctx,
1912 dplane_ctx_get_notif_provider(notif_ctx));
1913
3fe4ccc4 1914 ret = dplane_update_enqueue(ctx);
188a00e0
MS
1915
1916done:
1917 /* Update counter */
1918 atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
1919 memory_order_relaxed);
1920
1921 if (ret == AOK)
1922 result = ZEBRA_DPLANE_REQUEST_QUEUED;
1923 else {
1924 atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
1925 memory_order_relaxed);
1926 if (ctx)
1927 dplane_ctx_free(&ctx);
1928 }
1929 return result;
1930}
1931
97d8d05a
MS
1932/*
1933 * Enqueue pseudowire install for the dataplane.
1934 */
1935enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw)
1936{
1937 return pw_update_internal(pw, DPLANE_OP_PW_INSTALL);
1938}
1939
1940/*
1941 * Enqueue pseudowire un-install for the dataplane.
1942 */
1943enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw)
1944{
1945 return pw_update_internal(pw, DPLANE_OP_PW_UNINSTALL);
1946}
1947
16c628de
MS
1948/*
1949 * Common internal LSP update utility
1950 */
1951static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
1952 enum dplane_op_e op)
1953{
1954 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
1955 int ret = EINVAL;
1956 struct zebra_dplane_ctx *ctx = NULL;
1957
1958 /* Obtain context block */
1959 ctx = dplane_ctx_alloc();
16c628de
MS
1960
1961 ret = dplane_ctx_lsp_init(ctx, op, lsp);
1962 if (ret != AOK)
1963 goto done;
1964
3fe4ccc4 1965 ret = dplane_update_enqueue(ctx);
16c628de
MS
1966
1967done:
1968 /* Update counter */
1969 atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
1970 memory_order_relaxed);
1971
1972 if (ret == AOK)
1973 result = ZEBRA_DPLANE_REQUEST_QUEUED;
1974 else {
1975 atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
1976 memory_order_relaxed);
d8e479a3 1977 dplane_ctx_free(&ctx);
16c628de
MS
1978 }
1979
1980 return result;
1981}
1982
97d8d05a
MS
1983/*
1984 * Internal, common handler for pseudowire updates.
1985 */
1986static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
1987 enum dplane_op_e op)
1988{
1989 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
1990 int ret;
1991 struct zebra_dplane_ctx *ctx = NULL;
1992
1993 ctx = dplane_ctx_alloc();
97d8d05a
MS
1994
1995 ret = dplane_ctx_pw_init(ctx, op, pw);
1996 if (ret != AOK)
1997 goto done;
1998
3fe4ccc4 1999 ret = dplane_update_enqueue(ctx);
97d8d05a
MS
2000
2001done:
2002 /* Update counter */
2003 atomic_fetch_add_explicit(&zdplane_info.dg_pws_in, 1,
2004 memory_order_relaxed);
2005
2006 if (ret == AOK)
2007 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2008 else {
2009 atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
2010 memory_order_relaxed);
d8e479a3 2011 dplane_ctx_free(&ctx);
97d8d05a
MS
2012 }
2013
2014 return result;
2015}
2016
a4a4802a
MS
2017/*
2018 * Enqueue interface address add for the dataplane.
2019 */
2020enum zebra_dplane_result dplane_intf_addr_set(const struct interface *ifp,
2021 const struct connected *ifc)
2022{
64168803
MS
2023#if !defined(HAVE_NETLINK) && defined(HAVE_STRUCT_IFALIASREQ)
2024 /* Extra checks for this OS path. */
2025
2026 /* Don't configure PtP addresses on broadcast ifs or reverse */
2027 if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) {
2028 if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_DPLANE)
2029 zlog_debug("Failed to set intf addr: mismatch p2p and connected");
2030
2031 return ZEBRA_DPLANE_REQUEST_FAILURE;
2032 }
2033
2034 /* Ensure that no existing installed v4 route conflicts with
2035 * the new interface prefix. This check must be done in the
2036 * zebra pthread context, and any route delete (if needed)
2037 * is enqueued before the interface address programming attempt.
2038 */
2039 if (ifc->address->family == AF_INET) {
2040 struct prefix_ipv4 *p;
2041
2042 p = (struct prefix_ipv4 *)ifc->address;
a36898e7 2043 rib_lookup_and_pushup(p, ifp->vrf_id);
64168803
MS
2044 }
2045#endif
2046
2047 return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_INSTALL);
a4a4802a
MS
2048}
2049
2050/*
2051 * Enqueue interface address remove/uninstall for the dataplane.
2052 */
2053enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
2054 const struct connected *ifc)
2055{
64168803
MS
2056 return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_UNINSTALL);
2057}
2058
2059static enum zebra_dplane_result intf_addr_update_internal(
2060 const struct interface *ifp, const struct connected *ifc,
2061 enum dplane_op_e op)
2062{
2063 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2064 int ret = EINVAL;
2065 struct zebra_dplane_ctx *ctx = NULL;
2066 struct zebra_ns *zns;
2067
2068 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2069 char addr_str[PREFIX_STRLEN];
2070
2071 prefix2str(ifc->address, addr_str, sizeof(addr_str));
2072
2073 zlog_debug("init intf ctx %s: idx %d, addr %u:%s",
a36898e7 2074 dplane_op2str(op), ifp->ifindex, ifp->vrf_id,
64168803
MS
2075 addr_str);
2076 }
2077
2078 ctx = dplane_ctx_alloc();
64168803
MS
2079
2080 ctx->zd_op = op;
2081 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
a36898e7 2082 ctx->zd_vrf_id = ifp->vrf_id;
64168803 2083
a36898e7 2084 zns = zebra_ns_lookup(ifp->vrf_id);
64168803
MS
2085 dplane_ctx_ns_init(ctx, zns, false);
2086
2087 /* Init the interface-addr-specific area */
2088 memset(&ctx->u.intf, 0, sizeof(ctx->u.intf));
2089
7c7ef4a8
MS
2090 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
2091 ctx->zd_ifindex = ifp->ifindex;
64168803
MS
2092 ctx->u.intf.prefix = *(ifc->address);
2093
2094 if (if_is_broadcast(ifp))
2095 ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
2096
2097 if (CONNECTED_PEER(ifc)) {
2098 ctx->u.intf.dest_prefix = *(ifc->destination);
2099 ctx->u.intf.flags |=
2100 (DPLANE_INTF_CONNECTED | DPLANE_INTF_HAS_DEST);
64168803
MS
2101 }
2102
2103 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
2104 ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
2105
2106 if (ifc->label) {
2107 size_t len;
2108
2109 ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
2110
2111 /* Use embedded buffer if it's adequate; else allocate. */
2112 len = strlen(ifc->label);
2113
2114 if (len < sizeof(ctx->u.intf.label_buf)) {
b7b7bf31 2115 strlcpy(ctx->u.intf.label_buf, ifc->label,
64168803
MS
2116 sizeof(ctx->u.intf.label_buf));
2117 ctx->u.intf.label = ctx->u.intf.label_buf;
2118 } else {
2119 ctx->u.intf.label = strdup(ifc->label);
2120 }
2121 }
2122
3fe4ccc4 2123 ret = dplane_update_enqueue(ctx);
64168803 2124
64168803
MS
2125 /* Increment counter */
2126 atomic_fetch_add_explicit(&zdplane_info.dg_intf_addrs_in, 1,
2127 memory_order_relaxed);
2128
2129 if (ret == AOK)
2130 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2131 else {
2132 /* Error counter */
2133 atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors,
2134 1, memory_order_relaxed);
d8e479a3 2135 dplane_ctx_free(&ctx);
64168803
MS
2136 }
2137
2138 return result;
a4a4802a
MS
2139}
2140
7597ac7b
MS
2141/*
2142 * Enqueue vxlan/evpn mac add (or update).
2143 */
2144enum zebra_dplane_result dplane_mac_add(const struct interface *ifp,
478566d6 2145 const struct interface *bridge_ifp,
7597ac7b
MS
2146 vlanid_t vid,
2147 const struct ethaddr *mac,
2148 struct in_addr vtep_ip,
2149 bool sticky)
2150{
2151 enum zebra_dplane_result result;
2152
2153 /* Use common helper api */
478566d6
MS
2154 result = mac_update_internal(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
2155 vid, mac, vtep_ip, sticky);
7597ac7b
MS
2156 return result;
2157}
2158
2159/*
2160 * Enqueue vxlan/evpn mac delete.
2161 */
2162enum zebra_dplane_result dplane_mac_del(const struct interface *ifp,
478566d6 2163 const struct interface *bridge_ifp,
7597ac7b
MS
2164 vlanid_t vid,
2165 const struct ethaddr *mac,
2166 struct in_addr vtep_ip)
2167{
2168 enum zebra_dplane_result result;
2169
2170 /* Use common helper api */
478566d6
MS
2171 result = mac_update_internal(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
2172 vid, mac, vtep_ip, false);
7597ac7b
MS
2173 return result;
2174}
2175
2176/*
2177 * Common helper api for MAC address/vxlan updates
2178 */
2179static enum zebra_dplane_result
2180mac_update_internal(enum dplane_op_e op,
2181 const struct interface *ifp,
478566d6 2182 const struct interface *br_ifp,
7597ac7b
MS
2183 vlanid_t vid,
2184 const struct ethaddr *mac,
2185 struct in_addr vtep_ip,
2186 bool sticky)
2187{
2188 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2189 int ret;
2190 struct zebra_dplane_ctx *ctx = NULL;
2191 struct zebra_ns *zns;
2192
036d93c0
MS
2193 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2194 char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN];
2195
2196 zlog_debug("init mac ctx %s: mac %s, ifp %s, vtep %s",
2197 dplane_op2str(op),
2198 prefix_mac2str(mac, buf1, sizeof(buf1)),
2199 ifp->name,
2200 inet_ntop(AF_INET, &vtep_ip, buf2, sizeof(buf2)));
2201 }
2202
7597ac7b
MS
2203 ctx = dplane_ctx_alloc();
2204
2205 ctx->zd_op = op;
2206 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2207 ctx->zd_vrf_id = ifp->vrf_id;
2208
2209 zns = zebra_ns_lookup(ifp->vrf_id);
2210 dplane_ctx_ns_init(ctx, zns, false);
2211
2212 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
2213 ctx->zd_ifindex = ifp->ifindex;
2214
2215 /* Init the mac-specific data area */
2216 memset(&ctx->u.macinfo, 0, sizeof(ctx->u.macinfo));
2217
478566d6 2218 ctx->u.macinfo.br_ifindex = br_ifp->ifindex;
7597ac7b
MS
2219 ctx->u.macinfo.vtep_ip = vtep_ip;
2220 ctx->u.macinfo.mac = *mac;
2221 ctx->u.macinfo.vid = vid;
2222 ctx->u.macinfo.is_sticky = sticky;
2223
2224 /* Enqueue for processing on the dplane pthread */
2225 ret = dplane_update_enqueue(ctx);
2226
2227 /* Increment counter */
2228 atomic_fetch_add_explicit(&zdplane_info.dg_macs_in, 1,
2229 memory_order_relaxed);
2230
2231 if (ret == AOK)
2232 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2233 else {
2234 /* Error counter */
2235 atomic_fetch_add_explicit(&zdplane_info.dg_mac_errors, 1,
2236 memory_order_relaxed);
2237 dplane_ctx_free(&ctx);
2238 }
2239
2240 return result;
2241}
2242
931fa60c
MS
2243/*
2244 * Enqueue evpn neighbor add for the dataplane.
2245 */
2246enum zebra_dplane_result dplane_neigh_add(const struct interface *ifp,
2247 const struct ipaddr *ip,
2248 const struct ethaddr *mac,
2249 uint32_t flags)
2250{
2251 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2252
2253 result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL,
2254 ifp, mac, ip, flags, 0);
2255
2256 return result;
2257}
2258
2259/*
2260 * Enqueue evpn neighbor update for the dataplane.
2261 */
2262enum zebra_dplane_result dplane_neigh_update(const struct interface *ifp,
2263 const struct ipaddr *ip,
2264 const struct ethaddr *mac)
2265{
0bbd4ff4 2266 enum zebra_dplane_result result;
931fa60c
MS
2267
2268 result = neigh_update_internal(DPLANE_OP_NEIGH_UPDATE,
2269 ifp, mac, ip, 0, DPLANE_NUD_PROBE);
2270
2271 return result;
2272}
2273
2274/*
2275 * Enqueue evpn neighbor delete for the dataplane.
2276 */
2277enum zebra_dplane_result dplane_neigh_delete(const struct interface *ifp,
2278 const struct ipaddr *ip)
2279{
0bbd4ff4 2280 enum zebra_dplane_result result;
931fa60c
MS
2281
2282 result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE,
2283 ifp, NULL, ip, 0, 0);
2284
2285 return result;
2286}
2287
0bbd4ff4
MS
2288/*
2289 * Enqueue evpn VTEP add for the dataplane.
2290 */
2291enum zebra_dplane_result dplane_vtep_add(const struct interface *ifp,
2292 const struct in_addr *ip,
2293 vni_t vni)
2294{
2295 enum zebra_dplane_result result;
2296 struct ethaddr mac = { {0, 0, 0, 0, 0, 0} };
2297 struct ipaddr addr;
2298
2299 if (IS_ZEBRA_DEBUG_VXLAN)
2300 zlog_debug("Install %s into flood list for VNI %u intf %s(%u)",
2301 inet_ntoa(*ip), vni, ifp->name, ifp->ifindex);
2302
2303 SET_IPADDR_V4(&addr);
2304 addr.ipaddr_v4 = *ip;
2305
2306 result = neigh_update_internal(DPLANE_OP_VTEP_ADD,
2307 ifp, &mac, &addr, 0, 0);
2308
2309 return result;
2310}
2311
2312/*
2313 * Enqueue evpn VTEP add for the dataplane.
2314 */
2315enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
2316 const struct in_addr *ip,
2317 vni_t vni)
2318{
2319 enum zebra_dplane_result result;
2320 struct ethaddr mac = { {0, 0, 0, 0, 0, 0} };
2321 struct ipaddr addr;
2322
2323 if (IS_ZEBRA_DEBUG_VXLAN)
2324 zlog_debug(
2325 "Uninstall %s from flood list for VNI %u intf %s(%u)",
2326 inet_ntoa(*ip), vni, ifp->name, ifp->ifindex);
2327
2328 SET_IPADDR_V4(&addr);
2329 addr.ipaddr_v4 = *ip;
2330
2331 result = neigh_update_internal(DPLANE_OP_VTEP_DELETE,
2332 ifp, &mac, &addr, 0, 0);
2333
2334 return result;
2335}
2336
931fa60c
MS
2337/*
2338 * Common helper api for evpn neighbor updates
2339 */
2340static enum zebra_dplane_result
2341neigh_update_internal(enum dplane_op_e op,
2342 const struct interface *ifp,
2343 const struct ethaddr *mac,
2344 const struct ipaddr *ip,
2345 uint32_t flags, uint16_t state)
2346{
2347 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
2348 int ret;
2349 struct zebra_dplane_ctx *ctx = NULL;
2350 struct zebra_ns *zns;
2351
2352 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2353 char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN];
2354
2355 zlog_debug("init neigh ctx %s: ifp %s, mac %s, ip %s",
2356 dplane_op2str(op),
2357 prefix_mac2str(mac, buf1, sizeof(buf1)),
2358 ifp->name,
2359 ipaddr2str(ip, buf2, sizeof(buf2)));
2360 }
2361
2362 ctx = dplane_ctx_alloc();
2363
2364 ctx->zd_op = op;
2365 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2366 ctx->zd_vrf_id = ifp->vrf_id;
2367
2368 zns = zebra_ns_lookup(ifp->vrf_id);
2369 dplane_ctx_ns_init(ctx, zns, false);
2370
2371 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
2372 ctx->zd_ifindex = ifp->ifindex;
2373
2374 /* Init the neighbor-specific data area */
2375 memset(&ctx->u.neigh, 0, sizeof(ctx->u.neigh));
2376
2377 ctx->u.neigh.ip_addr = *ip;
2378 if (mac)
2379 ctx->u.neigh.mac = *mac;
2380 ctx->u.neigh.flags = flags;
2381 ctx->u.neigh.state = state;
2382
2383 /* Enqueue for processing on the dplane pthread */
2384 ret = dplane_update_enqueue(ctx);
2385
2386 /* Increment counter */
2387 atomic_fetch_add_explicit(&zdplane_info.dg_neighs_in, 1,
2388 memory_order_relaxed);
2389
2390 if (ret == AOK)
2391 result = ZEBRA_DPLANE_REQUEST_QUEUED;
2392 else {
2393 /* Error counter */
2394 atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors, 1,
2395 memory_order_relaxed);
2396 dplane_ctx_free(&ctx);
2397 }
2398
2399 return result;
2400}
2401
1d11b21f
MS
2402/*
2403 * Handler for 'show dplane'
2404 */
2405int dplane_show_helper(struct vty *vty, bool detailed)
2406{
16c628de
MS
2407 uint64_t queued, queue_max, limit, errs, incoming, yields,
2408 other_errs;
1d11b21f 2409
4dfd7a02 2410 /* Using atomics because counters are being changed in different
c831033f 2411 * pthread contexts.
4dfd7a02 2412 */
25779064 2413 incoming = atomic_load_explicit(&zdplane_info.dg_routes_in,
1d11b21f 2414 memory_order_relaxed);
91f16812
MS
2415 limit = atomic_load_explicit(&zdplane_info.dg_max_queued_updates,
2416 memory_order_relaxed);
25779064 2417 queued = atomic_load_explicit(&zdplane_info.dg_routes_queued,
1d11b21f 2418 memory_order_relaxed);
25779064 2419 queue_max = atomic_load_explicit(&zdplane_info.dg_routes_queued_max,
4dfd7a02 2420 memory_order_relaxed);
25779064 2421 errs = atomic_load_explicit(&zdplane_info.dg_route_errors,
1d11b21f 2422 memory_order_relaxed);
c831033f
MS
2423 yields = atomic_load_explicit(&zdplane_info.dg_update_yields,
2424 memory_order_relaxed);
16c628de
MS
2425 other_errs = atomic_load_explicit(&zdplane_info.dg_other_errors,
2426 memory_order_relaxed);
1d11b21f 2427
c831033f
MS
2428 vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n",
2429 incoming);
1d11b21f 2430 vty_out(vty, "Route update errors: %"PRIu64"\n", errs);
16c628de 2431 vty_out(vty, "Other errors : %"PRIu64"\n", other_errs);
91f16812 2432 vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit);
1d11b21f 2433 vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued);
4dfd7a02 2434 vty_out(vty, "Route update queue max: %"PRIu64"\n", queue_max);
4280d91c
MS
2435 vty_out(vty, "Dplane update yields: %"PRIu64"\n", yields);
2436
2437 incoming = atomic_load_explicit(&zdplane_info.dg_lsps_in,
2438 memory_order_relaxed);
2439 errs = atomic_load_explicit(&zdplane_info.dg_lsp_errors,
2440 memory_order_relaxed);
2441 vty_out(vty, "LSP updates: %"PRIu64"\n", incoming);
2442 vty_out(vty, "LSP update errors: %"PRIu64"\n", errs);
2443
2444 incoming = atomic_load_explicit(&zdplane_info.dg_pws_in,
2445 memory_order_relaxed);
2446 errs = atomic_load_explicit(&zdplane_info.dg_pw_errors,
2447 memory_order_relaxed);
2448 vty_out(vty, "PW updates: %"PRIu64"\n", incoming);
2449 vty_out(vty, "PW update errors: %"PRIu64"\n", errs);
2450
2451 incoming = atomic_load_explicit(&zdplane_info.dg_intf_addrs_in,
2452 memory_order_relaxed);
2453 errs = atomic_load_explicit(&zdplane_info.dg_intf_addr_errors,
2454 memory_order_relaxed);
2455 vty_out(vty, "Intf addr updates: %"PRIu64"\n", incoming);
2456 vty_out(vty, "Intf addr errors: %"PRIu64"\n", errs);
2457
2458 incoming = atomic_load_explicit(&zdplane_info.dg_macs_in,
2459 memory_order_relaxed);
2460 errs = atomic_load_explicit(&zdplane_info.dg_mac_errors,
2461 memory_order_relaxed);
2462 vty_out(vty, "EVPN MAC updates: %"PRIu64"\n", incoming);
2463 vty_out(vty, "EVPN MAC errors: %"PRIu64"\n", errs);
1d11b21f 2464
931fa60c
MS
2465 incoming = atomic_load_explicit(&zdplane_info.dg_neighs_in,
2466 memory_order_relaxed);
2467 errs = atomic_load_explicit(&zdplane_info.dg_neigh_errors,
2468 memory_order_relaxed);
2469 vty_out(vty, "EVPN neigh updates: %"PRIu64"\n", incoming);
2470 vty_out(vty, "EVPN neigh errors: %"PRIu64"\n", errs);
2471
1d11b21f
MS
2472 return CMD_SUCCESS;
2473}
2474
2475/*
2476 * Handler for 'show dplane providers'
2477 */
2478int dplane_show_provs_helper(struct vty *vty, bool detailed)
2479{
c831033f
MS
2480 struct zebra_dplane_provider *prov;
2481 uint64_t in, in_max, out, out_max;
2482
2483 vty_out(vty, "Zebra dataplane providers:\n");
2484
2485 DPLANE_LOCK();
2486 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
2487 DPLANE_UNLOCK();
2488
2489 /* Show counters, useful info from each registered provider */
2490 while (prov) {
2491
2492 in = atomic_load_explicit(&prov->dp_in_counter,
2493 memory_order_relaxed);
2494 in_max = atomic_load_explicit(&prov->dp_in_max,
2495 memory_order_relaxed);
2496 out = atomic_load_explicit(&prov->dp_out_counter,
2497 memory_order_relaxed);
2498 out_max = atomic_load_explicit(&prov->dp_out_max,
2499 memory_order_relaxed);
2500
c9d17fe8
MS
2501 vty_out(vty, "%s (%u): in: %"PRIu64", q_max: %"PRIu64", "
2502 "out: %"PRIu64", q_max: %"PRIu64"\n",
c831033f
MS
2503 prov->dp_name, prov->dp_id, in, in_max, out, out_max);
2504
2505 DPLANE_LOCK();
2506 prov = TAILQ_NEXT(prov, dp_prov_link);
2507 DPLANE_UNLOCK();
2508 }
1d11b21f
MS
2509
2510 return CMD_SUCCESS;
2511}
2512
f26730e1
MS
2513/*
2514 * Helper for 'show run' etc.
2515 */
2516int dplane_config_write_helper(struct vty *vty)
2517{
2518 if (zdplane_info.dg_max_queued_updates != DPLANE_DEFAULT_MAX_QUEUED)
2519 vty_out(vty, "zebra dplane limit %u\n",
2520 zdplane_info.dg_max_queued_updates);
2521
2522 return 0;
2523}
2524
b8e0423d
MS
2525/*
2526 * Provider registration
2527 */
2528int dplane_provider_register(const char *name,
c831033f
MS
2529 enum dplane_provider_prio prio,
2530 int flags,
1dd4ea8a 2531 int (*start_fp)(struct zebra_dplane_provider *),
4c206c8f
MS
2532 int (*fp)(struct zebra_dplane_provider *),
2533 int (*fini_fp)(struct zebra_dplane_provider *,
2534 bool early),
1ff8a248
MS
2535 void *data,
2536 struct zebra_dplane_provider **prov_p)
b8e0423d
MS
2537{
2538 int ret = 0;
6fb51ccb 2539 struct zebra_dplane_provider *p = NULL, *last;
b8e0423d
MS
2540
2541 /* Validate */
2542 if (fp == NULL) {
2543 ret = EINVAL;
2544 goto done;
2545 }
2546
2547 if (prio <= DPLANE_PRIO_NONE ||
1bcea841 2548 prio > DPLANE_PRIO_LAST) {
b8e0423d
MS
2549 ret = EINVAL;
2550 goto done;
2551 }
2552
2553 /* Allocate and init new provider struct */
25779064 2554 p = XCALLOC(MTYPE_DP_PROV, sizeof(struct zebra_dplane_provider));
b8e0423d 2555
c831033f
MS
2556 pthread_mutex_init(&(p->dp_mutex), NULL);
2557 TAILQ_INIT(&(p->dp_ctx_in_q));
2558 TAILQ_INIT(&(p->dp_ctx_out_q));
b8e0423d
MS
2559
2560 p->dp_priority = prio;
2561 p->dp_fp = fp;
1dd4ea8a 2562 p->dp_start = start_fp;
18c37974 2563 p->dp_fini = fini_fp;
c831033f 2564 p->dp_data = data;
18c37974 2565
c831033f 2566 /* Lock - the dplane pthread may be running */
18c37974 2567 DPLANE_LOCK();
b8e0423d 2568
25779064 2569 p->dp_id = ++zdplane_info.dg_provider_id;
b8e0423d 2570
c831033f
MS
2571 if (name)
2572 strlcpy(p->dp_name, name, DPLANE_PROVIDER_NAMELEN);
2573 else
2574 snprintf(p->dp_name, DPLANE_PROVIDER_NAMELEN,
2575 "provider-%u", p->dp_id);
2576
b8e0423d 2577 /* Insert into list ordered by priority */
c831033f 2578 TAILQ_FOREACH(last, &zdplane_info.dg_providers_q, dp_prov_link) {
5709131c 2579 if (last->dp_priority > p->dp_priority)
b8e0423d 2580 break;
b8e0423d
MS
2581 }
2582
5709131c 2583 if (last)
c831033f 2584 TAILQ_INSERT_BEFORE(last, p, dp_prov_link);
5709131c 2585 else
25779064 2586 TAILQ_INSERT_TAIL(&zdplane_info.dg_providers_q, p,
c831033f 2587 dp_prov_link);
b8e0423d 2588
18c37974
MS
2589 /* And unlock */
2590 DPLANE_UNLOCK();
2591
c831033f
MS
2592 if (IS_ZEBRA_DEBUG_DPLANE)
2593 zlog_debug("dplane: registered new provider '%s' (%u), prio %d",
2594 p->dp_name, p->dp_id, p->dp_priority);
2595
b8e0423d 2596done:
1ff8a248
MS
2597 if (prov_p)
2598 *prov_p = p;
2599
5709131c 2600 return ret;
b8e0423d
MS
2601}
2602
c831033f
MS
2603/* Accessors for provider attributes */
2604const char *dplane_provider_get_name(const struct zebra_dplane_provider *prov)
2605{
2606 return prov->dp_name;
2607}
2608
2609uint32_t dplane_provider_get_id(const struct zebra_dplane_provider *prov)
2610{
2611 return prov->dp_id;
2612}
2613
2614void *dplane_provider_get_data(const struct zebra_dplane_provider *prov)
2615{
2616 return prov->dp_data;
2617}
2618
2619int dplane_provider_get_work_limit(const struct zebra_dplane_provider *prov)
2620{
2621 return zdplane_info.dg_updates_per_cycle;
2622}
2623
ad6aad4d
MS
2624/* Lock/unlock a provider's mutex - iff the provider was registered with
2625 * the THREADED flag.
2626 */
2627void dplane_provider_lock(struct zebra_dplane_provider *prov)
2628{
2629 if (dplane_provider_is_threaded(prov))
2630 DPLANE_PROV_LOCK(prov);
2631}
2632
2633void dplane_provider_unlock(struct zebra_dplane_provider *prov)
2634{
2635 if (dplane_provider_is_threaded(prov))
2636 DPLANE_PROV_UNLOCK(prov);
2637}
2638
c831033f
MS
2639/*
2640 * Dequeue and maintain associated counter
2641 */
2642struct zebra_dplane_ctx *dplane_provider_dequeue_in_ctx(
2643 struct zebra_dplane_provider *prov)
2644{
2645 struct zebra_dplane_ctx *ctx = NULL;
2646
ad6aad4d 2647 dplane_provider_lock(prov);
c831033f
MS
2648
2649 ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
2650 if (ctx) {
2651 TAILQ_REMOVE(&(prov->dp_ctx_in_q), ctx, zd_q_entries);
c9d17fe8
MS
2652
2653 atomic_fetch_sub_explicit(&prov->dp_in_queued, 1,
2654 memory_order_relaxed);
c831033f
MS
2655 }
2656
ad6aad4d 2657 dplane_provider_unlock(prov);
c831033f
MS
2658
2659 return ctx;
2660}
2661
2662/*
2663 * Dequeue work to a list, return count
2664 */
2665int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov,
2666 struct dplane_ctx_q *listp)
2667{
2668 int limit, ret;
2669 struct zebra_dplane_ctx *ctx;
2670
2671 limit = zdplane_info.dg_updates_per_cycle;
2672
ad6aad4d 2673 dplane_provider_lock(prov);
c831033f
MS
2674
2675 for (ret = 0; ret < limit; ret++) {
2676 ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
2677 if (ctx) {
2678 TAILQ_REMOVE(&(prov->dp_ctx_in_q), ctx, zd_q_entries);
2679
2680 TAILQ_INSERT_TAIL(listp, ctx, zd_q_entries);
2681 } else {
2682 break;
2683 }
2684 }
2685
c9d17fe8
MS
2686 if (ret > 0)
2687 atomic_fetch_sub_explicit(&prov->dp_in_queued, ret,
2688 memory_order_relaxed);
2689
ad6aad4d 2690 dplane_provider_unlock(prov);
c831033f
MS
2691
2692 return ret;
2693}
2694
2695/*
2696 * Enqueue and maintain associated counter
2697 */
2698void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
2699 struct zebra_dplane_ctx *ctx)
2700{
ad6aad4d 2701 dplane_provider_lock(prov);
c831033f
MS
2702
2703 TAILQ_INSERT_TAIL(&(prov->dp_ctx_out_q), ctx,
2704 zd_q_entries);
2705
ad6aad4d 2706 dplane_provider_unlock(prov);
c831033f
MS
2707
2708 atomic_fetch_add_explicit(&(prov->dp_out_counter), 1,
2709 memory_order_relaxed);
2710}
2711
62b8bb7a
MS
2712/*
2713 * Accessor for provider object
2714 */
c831033f
MS
2715bool dplane_provider_is_threaded(const struct zebra_dplane_provider *prov)
2716{
2717 return (prov->dp_flags & DPLANE_PROV_FLAG_THREADED);
2718}
2719
62b8bb7a
MS
2720/*
2721 * Internal helper that copies information from a zebra ns object; this is
2722 * called in the zebra main pthread context as part of dplane ctx init.
2723 */
2724static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
2725 struct zebra_ns *zns)
2726{
2727 ns_info->ns_id = zns->ns_id;
2728
2729#if defined(HAVE_NETLINK)
2730 ns_info->is_cmd = true;
2731 ns_info->nls = zns->netlink_dplane;
2732#endif /* NETLINK */
2733}
2734
c831033f
MS
2735/*
2736 * Provider api to signal that work/events are available
2737 * for the dataplane pthread.
2738 */
2739int dplane_provider_work_ready(void)
2740{
e5a60d82
MS
2741 /* Note that during zebra startup, we may be offered work before
2742 * the dataplane pthread (and thread-master) are ready. We want to
2743 * enqueue the work, but the event-scheduling machinery may not be
2744 * available.
2745 */
2746 if (zdplane_info.dg_run) {
2747 thread_add_event(zdplane_info.dg_master,
2748 dplane_thread_loop, NULL, 0,
2749 &zdplane_info.dg_t_update);
2750 }
c831033f
MS
2751
2752 return AOK;
2753}
2754
593e4eb1
MS
2755/*
2756 * Enqueue a context directly to zebra main.
2757 */
2758void dplane_provider_enqueue_to_zebra(struct zebra_dplane_ctx *ctx)
2759{
2760 struct dplane_ctx_q temp_list;
2761
2762 /* Zebra's api takes a list, so we need to use a temporary list */
2763 TAILQ_INIT(&temp_list);
2764
2765 TAILQ_INSERT_TAIL(&temp_list, ctx, zd_q_entries);
2766 (zdplane_info.dg_results_cb)(&temp_list);
2767}
2768
7cdb1a84 2769/*
c831033f 2770 * Kernel dataplane provider
7cdb1a84 2771 */
c831033f 2772
16c628de
MS
2773/*
2774 * Handler for kernel LSP updates
2775 */
2776static enum zebra_dplane_result
2777kernel_dplane_lsp_update(struct zebra_dplane_ctx *ctx)
2778{
2779 enum zebra_dplane_result res;
2780
2781 /* Call into the synchronous kernel-facing code here */
2782 res = kernel_lsp_update(ctx);
2783
2784 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
2785 atomic_fetch_add_explicit(
2786 &zdplane_info.dg_lsp_errors, 1,
2787 memory_order_relaxed);
2788
2789 return res;
2790}
2791
c10a646d
MS
2792/*
2793 * Handler for kernel pseudowire updates
2794 */
2795static enum zebra_dplane_result
2796kernel_dplane_pw_update(struct zebra_dplane_ctx *ctx)
2797{
2798 enum zebra_dplane_result res;
2799
2800 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
2801 zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u",
7c7ef4a8 2802 dplane_ctx_get_ifname(ctx),
c10a646d
MS
2803 dplane_op2str(ctx->zd_op),
2804 dplane_ctx_get_pw_af(ctx),
2805 dplane_ctx_get_pw_local_label(ctx),
2806 dplane_ctx_get_pw_remote_label(ctx));
2807
2808 res = kernel_pw_update(ctx);
2809
2810 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
2811 atomic_fetch_add_explicit(
2812 &zdplane_info.dg_pw_errors, 1,
2813 memory_order_relaxed);
2814
2815 return res;
2816}
2817
16c628de
MS
2818/*
2819 * Handler for kernel route updates
2820 */
2821static enum zebra_dplane_result
2822kernel_dplane_route_update(struct zebra_dplane_ctx *ctx)
2823{
2824 enum zebra_dplane_result res;
2825
2826 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2827 char dest_str[PREFIX_STRLEN];
2828
2829 prefix2str(dplane_ctx_get_dest(ctx),
2830 dest_str, sizeof(dest_str));
2831
2832 zlog_debug("%u:%s Dplane route update ctx %p op %s",
2833 dplane_ctx_get_vrf(ctx), dest_str,
2834 ctx, dplane_op2str(dplane_ctx_get_op(ctx)));
2835 }
2836
2837 /* Call into the synchronous kernel-facing code here */
2838 res = kernel_route_update(ctx);
2839
2840 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
2841 atomic_fetch_add_explicit(
2842 &zdplane_info.dg_route_errors, 1,
2843 memory_order_relaxed);
2844
2845 return res;
2846}
2847
64168803
MS
2848/*
2849 * Handler for kernel-facing interface address updates
2850 */
2851static enum zebra_dplane_result
2852kernel_dplane_address_update(struct zebra_dplane_ctx *ctx)
2853{
2854 enum zebra_dplane_result res;
2855
64168803
MS
2856 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2857 char dest_str[PREFIX_STRLEN];
2858
2859 prefix2str(dplane_ctx_get_intf_addr(ctx), dest_str,
2860 sizeof(dest_str));
2861
2862 zlog_debug("Dplane intf %s, idx %u, addr %s",
2863 dplane_op2str(dplane_ctx_get_op(ctx)),
2864 dplane_ctx_get_ifindex(ctx), dest_str);
2865 }
2866
2867 res = kernel_address_update_ctx(ctx);
2868
2869 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
2870 atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors,
2871 1, memory_order_relaxed);
2872
2873 return res;
2874}
2875
036d93c0 2876/*
931fa60c 2877 * Handler for kernel-facing EVPN MAC address updates
036d93c0
MS
2878 */
2879static enum zebra_dplane_result
2880kernel_dplane_mac_update(struct zebra_dplane_ctx *ctx)
2881{
2882 enum zebra_dplane_result res;
2883
2884 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2885 char buf[ETHER_ADDR_STRLEN];
2886
2887 prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf,
2888 sizeof(buf));
2889
2890 zlog_debug("Dplane %s, mac %s, ifindex %u",
2891 dplane_op2str(dplane_ctx_get_op(ctx)),
2892 buf, dplane_ctx_get_ifindex(ctx));
2893 }
2894
2895 res = kernel_mac_update_ctx(ctx);
2896
2897 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
2898 atomic_fetch_add_explicit(&zdplane_info.dg_mac_errors,
2899 1, memory_order_relaxed);
2900
2901 return res;
2902}
2903
931fa60c
MS
2904/*
2905 * Handler for kernel-facing EVPN neighbor updates
2906 */
2907static enum zebra_dplane_result
2908kernel_dplane_neigh_update(struct zebra_dplane_ctx *ctx)
2909{
2910 enum zebra_dplane_result res;
2911
2912 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2913 char buf[PREFIX_STRLEN];
2914
2915 ipaddr2str(dplane_ctx_neigh_get_ipaddr(ctx), buf,
2916 sizeof(buf));
2917
2918 zlog_debug("Dplane %s, ip %s, ifindex %u",
2919 dplane_op2str(dplane_ctx_get_op(ctx)),
2920 buf, dplane_ctx_get_ifindex(ctx));
2921 }
2922
2923 res = kernel_neigh_update_ctx(ctx);
2924
2925 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
2926 atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors,
2927 1, memory_order_relaxed);
2928
2929 return res;
2930}
2931
c831033f
MS
2932/*
2933 * Kernel provider callback
2934 */
2935static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
7cdb1a84 2936{
c831033f
MS
2937 enum zebra_dplane_result res;
2938 struct zebra_dplane_ctx *ctx;
2939 int counter, limit;
7cdb1a84 2940
c831033f 2941 limit = dplane_provider_get_work_limit(prov);
7cdb1a84 2942
c831033f
MS
2943 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
2944 zlog_debug("dplane provider '%s': processing",
2945 dplane_provider_get_name(prov));
7cdb1a84 2946
c831033f 2947 for (counter = 0; counter < limit; counter++) {
91f16812 2948
c831033f
MS
2949 ctx = dplane_provider_dequeue_in_ctx(prov);
2950 if (ctx == NULL)
2951 break;
d8c16a95 2952
9677961e
MS
2953 /* A previous provider plugin may have asked to skip the
2954 * kernel update.
2955 */
2956 if (dplane_ctx_is_skip_kernel(ctx)) {
2957 res = ZEBRA_DPLANE_REQUEST_SUCCESS;
2958 goto skip_one;
2959 }
2960
16c628de
MS
2961 /* Dispatch to appropriate kernel-facing apis */
2962 switch (dplane_ctx_get_op(ctx)) {
1d11b21f 2963
16c628de
MS
2964 case DPLANE_OP_ROUTE_INSTALL:
2965 case DPLANE_OP_ROUTE_UPDATE:
2966 case DPLANE_OP_ROUTE_DELETE:
2967 res = kernel_dplane_route_update(ctx);
2968 break;
d8c16a95 2969
16c628de
MS
2970 case DPLANE_OP_LSP_INSTALL:
2971 case DPLANE_OP_LSP_UPDATE:
2972 case DPLANE_OP_LSP_DELETE:
2973 res = kernel_dplane_lsp_update(ctx);
2974 break;
d8c16a95 2975
c10a646d
MS
2976 case DPLANE_OP_PW_INSTALL:
2977 case DPLANE_OP_PW_UNINSTALL:
2978 res = kernel_dplane_pw_update(ctx);
2979 break;
2980
64168803
MS
2981 case DPLANE_OP_ADDR_INSTALL:
2982 case DPLANE_OP_ADDR_UNINSTALL:
2983 res = kernel_dplane_address_update(ctx);
2984 break;
2985
036d93c0
MS
2986 case DPLANE_OP_MAC_INSTALL:
2987 case DPLANE_OP_MAC_DELETE:
2988 res = kernel_dplane_mac_update(ctx);
2989 break;
2990
931fa60c
MS
2991 case DPLANE_OP_NEIGH_INSTALL:
2992 case DPLANE_OP_NEIGH_UPDATE:
2993 case DPLANE_OP_NEIGH_DELETE:
0bbd4ff4
MS
2994 case DPLANE_OP_VTEP_ADD:
2995 case DPLANE_OP_VTEP_DELETE:
931fa60c
MS
2996 res = kernel_dplane_neigh_update(ctx);
2997 break;
2998
104e3ad9 2999 /* Ignore 'notifications' - no-op */
cf363e1b
MS
3000 case DPLANE_OP_SYS_ROUTE_ADD:
3001 case DPLANE_OP_SYS_ROUTE_DELETE:
54818e3b 3002 case DPLANE_OP_ROUTE_NOTIFY:
104e3ad9 3003 case DPLANE_OP_LSP_NOTIFY:
cf363e1b
MS
3004 res = ZEBRA_DPLANE_REQUEST_SUCCESS;
3005 break;
3006
16c628de 3007 default:
c831033f 3008 atomic_fetch_add_explicit(
16c628de 3009 &zdplane_info.dg_other_errors, 1,
c831033f 3010 memory_order_relaxed);
d8c16a95 3011
16c628de
MS
3012 res = ZEBRA_DPLANE_REQUEST_FAILURE;
3013 break;
3014 }
3015
9677961e 3016skip_one:
c831033f
MS
3017 dplane_ctx_set_status(ctx, res);
3018
3019 dplane_provider_enqueue_out_ctx(prov, ctx);
3020 }
3021
3022 /* Ensure that we'll run the work loop again if there's still
3023 * more work to do.
3024 */
3025 if (counter >= limit) {
3026 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3027 zlog_debug("dplane provider '%s' reached max updates %d",
3028 dplane_provider_get_name(prov), counter);
3029
3030 atomic_fetch_add_explicit(&zdplane_info.dg_update_yields,
3031 1, memory_order_relaxed);
3032
3033 dplane_provider_work_ready();
3034 }
3035
3036 return 0;
3037}
3038
e5a60d82
MS
3039#if DPLANE_TEST_PROVIDER
3040
c831033f
MS
3041/*
3042 * Test dataplane provider plugin
3043 */
3044
3045/*
3046 * Test provider process callback
3047 */
3048static int test_dplane_process_func(struct zebra_dplane_provider *prov)
3049{
3050 struct zebra_dplane_ctx *ctx;
3051 int counter, limit;
3052
3053 /* Just moving from 'in' queue to 'out' queue */
3054
3055 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3056 zlog_debug("dplane provider '%s': processing",
3057 dplane_provider_get_name(prov));
3058
3059 limit = dplane_provider_get_work_limit(prov);
3060
3061 for (counter = 0; counter < limit; counter++) {
3062
3063 ctx = dplane_provider_dequeue_in_ctx(prov);
3064 if (ctx == NULL)
3065 break;
3066
cf363e1b
MS
3067 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3068 zlog_debug("dplane provider '%s': op %s",
3069 dplane_provider_get_name(prov),
3070 dplane_op2str(dplane_ctx_get_op(ctx)));
3071
c831033f
MS
3072 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
3073
3074 dplane_provider_enqueue_out_ctx(prov, ctx);
3075 }
3076
c9d17fe8
MS
3077 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3078 zlog_debug("dplane provider '%s': processed %d",
3079 dplane_provider_get_name(prov), counter);
3080
c831033f
MS
3081 /* Ensure that we'll run the work loop again if there's still
3082 * more work to do.
3083 */
3084 if (counter >= limit)
3085 dplane_provider_work_ready();
3086
3087 return 0;
3088}
3089
3090/*
3091 * Test provider shutdown/fini callback
3092 */
3093static int test_dplane_shutdown_func(struct zebra_dplane_provider *prov,
3094 bool early)
3095{
3096 if (IS_ZEBRA_DEBUG_DPLANE)
3097 zlog_debug("dplane provider '%s': %sshutdown",
3098 dplane_provider_get_name(prov),
3099 early ? "early " : "");
3100
3101 return 0;
3102}
e5a60d82 3103#endif /* DPLANE_TEST_PROVIDER */
c831033f
MS
3104
3105/*
3106 * Register default kernel provider
3107 */
3108static void dplane_provider_init(void)
3109{
3110 int ret;
3111
3112 ret = dplane_provider_register("Kernel",
3113 DPLANE_PRIO_KERNEL,
1dd4ea8a 3114 DPLANE_PROV_FLAGS_DEFAULT, NULL,
c831033f
MS
3115 kernel_dplane_process_func,
3116 NULL,
1ff8a248 3117 NULL, NULL);
c831033f
MS
3118
3119 if (ret != AOK)
3120 zlog_err("Unable to register kernel dplane provider: %d",
3121 ret);
3122
e5a60d82
MS
3123#if DPLANE_TEST_PROVIDER
3124 /* Optional test provider ... */
c831033f
MS
3125 ret = dplane_provider_register("Test",
3126 DPLANE_PRIO_PRE_KERNEL,
1dd4ea8a 3127 DPLANE_PROV_FLAGS_DEFAULT, NULL,
c831033f
MS
3128 test_dplane_process_func,
3129 test_dplane_shutdown_func,
1ff8a248 3130 NULL /* data */, NULL);
c831033f
MS
3131
3132 if (ret != AOK)
3133 zlog_err("Unable to register test dplane provider: %d",
3134 ret);
e5a60d82 3135#endif /* DPLANE_TEST_PROVIDER */
7cdb1a84
MS
3136}
3137
4dfd7a02
MS
3138/* Indicates zebra shutdown/exit is in progress. Some operations may be
3139 * simplified or skipped during shutdown processing.
3140 */
3141bool dplane_is_in_shutdown(void)
3142{
25779064 3143 return zdplane_info.dg_is_shutdown;
4dfd7a02
MS
3144}
3145
3146/*
3147 * Early or pre-shutdown, de-init notification api. This runs pretty
3148 * early during zebra shutdown, as a signal to stop new work and prepare
3149 * for updates generated by shutdown/cleanup activity, as zebra tries to
3150 * remove everything it's responsible for.
c9d17fe8 3151 * NB: This runs in the main zebra pthread context.
4dfd7a02
MS
3152 */
3153void zebra_dplane_pre_finish(void)
3154{
3155 if (IS_ZEBRA_DEBUG_DPLANE)
3156 zlog_debug("Zebra dataplane pre-fini called");
3157
25779064 3158 zdplane_info.dg_is_shutdown = true;
4dfd7a02 3159
c9d17fe8 3160 /* TODO -- Notify provider(s) of pending shutdown */
4dfd7a02
MS
3161}
3162
3163/*
3164 * Utility to determine whether work remains enqueued within the dplane;
3165 * used during system shutdown processing.
3166 */
3167static bool dplane_work_pending(void)
3168{
c9d17fe8 3169 bool ret = false;
25779064 3170 struct zebra_dplane_ctx *ctx;
c9d17fe8 3171 struct zebra_dplane_provider *prov;
4dfd7a02 3172
c831033f
MS
3173 /* TODO -- just checking incoming/pending work for now, must check
3174 * providers
3175 */
4dfd7a02
MS
3176 DPLANE_LOCK();
3177 {
3fe4ccc4 3178 ctx = TAILQ_FIRST(&zdplane_info.dg_update_ctx_q);
c9d17fe8 3179 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
4dfd7a02
MS
3180 }
3181 DPLANE_UNLOCK();
3182
c9d17fe8
MS
3183 if (ctx != NULL) {
3184 ret = true;
3185 goto done;
3186 }
3187
3188 while (prov) {
3189
ad6aad4d 3190 dplane_provider_lock(prov);
c9d17fe8
MS
3191
3192 ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
3193 if (ctx == NULL)
3194 ctx = TAILQ_FIRST(&(prov->dp_ctx_out_q));
3195
ad6aad4d 3196 dplane_provider_unlock(prov);
c9d17fe8
MS
3197
3198 if (ctx != NULL)
3199 break;
3200
3201 DPLANE_LOCK();
3202 prov = TAILQ_NEXT(prov, dp_prov_link);
3203 DPLANE_UNLOCK();
3204 }
3205
3206 if (ctx != NULL)
3207 ret = true;
3208
3209done:
3210 return ret;
4dfd7a02
MS
3211}
3212
3213/*
3214 * Shutdown-time intermediate callback, used to determine when all pending
3215 * in-flight updates are done. If there's still work to do, reschedules itself.
3216 * If all work is done, schedules an event to the main zebra thread for
3217 * final zebra shutdown.
3218 * This runs in the dplane pthread context.
3219 */
3220static int dplane_check_shutdown_status(struct thread *event)
3221{
3222 if (IS_ZEBRA_DEBUG_DPLANE)
3223 zlog_debug("Zebra dataplane shutdown status check called");
3224
3225 if (dplane_work_pending()) {
3226 /* Reschedule dplane check on a short timer */
25779064 3227 thread_add_timer_msec(zdplane_info.dg_master,
4dfd7a02
MS
3228 dplane_check_shutdown_status,
3229 NULL, 100,
25779064 3230 &zdplane_info.dg_t_shutdown_check);
4dfd7a02
MS
3231
3232 /* TODO - give up and stop waiting after a short time? */
3233
3234 } else {
3235 /* We appear to be done - schedule a final callback event
3236 * for the zebra main pthread.
3237 */
3801e764 3238 thread_add_event(zrouter.master, zebra_finalize, NULL, 0, NULL);
4dfd7a02
MS
3239 }
3240
3241 return 0;
3242}
3243
18c37974 3244/*
1d11b21f 3245 * Shutdown, de-init api. This runs pretty late during shutdown,
4dfd7a02
MS
3246 * after zebra has tried to free/remove/uninstall all routes during shutdown.
3247 * At this point, dplane work may still remain to be done, so we can't just
3248 * blindly terminate. If there's still work to do, we'll periodically check
3249 * and when done, we'll enqueue a task to the zebra main thread for final
3250 * termination processing.
3251 *
1d11b21f 3252 * NB: This runs in the main zebra thread context.
18c37974 3253 */
1d11b21f 3254void zebra_dplane_finish(void)
18c37974 3255{
4dfd7a02
MS
3256 if (IS_ZEBRA_DEBUG_DPLANE)
3257 zlog_debug("Zebra dataplane fini called");
3258
25779064 3259 thread_add_event(zdplane_info.dg_master,
4dfd7a02 3260 dplane_check_shutdown_status, NULL, 0,
25779064 3261 &zdplane_info.dg_t_shutdown_check);
4dfd7a02
MS
3262}
3263
c831033f
MS
3264/*
3265 * Main dataplane pthread event loop. The thread takes new incoming work
3266 * and offers it to the first provider. It then iterates through the
3267 * providers, taking complete work from each one and offering it
3268 * to the next in order. At each step, a limited number of updates are
3269 * processed during a cycle in order to provide some fairness.
14b0bc8e
MS
3270 *
3271 * This loop through the providers is only run once, so that the dataplane
3272 * pthread can look for other pending work - such as i/o work on behalf of
3273 * providers.
c831033f
MS
3274 */
3275static int dplane_thread_loop(struct thread *event)
3276{
3277 struct dplane_ctx_q work_list;
3278 struct dplane_ctx_q error_list;
3279 struct zebra_dplane_provider *prov;
3280 struct zebra_dplane_ctx *ctx, *tctx;
3281 int limit, counter, error_counter;
c9d17fe8 3282 uint64_t curr, high;
c831033f
MS
3283
3284 /* Capture work limit per cycle */
3285 limit = zdplane_info.dg_updates_per_cycle;
3286
14b0bc8e 3287 /* Init temporary lists used to move contexts among providers */
c831033f 3288 TAILQ_INIT(&work_list);
14b0bc8e
MS
3289 TAILQ_INIT(&error_list);
3290 error_counter = 0;
c831033f
MS
3291
3292 /* Check for zebra shutdown */
3293 if (!zdplane_info.dg_run)
3294 goto done;
3295
3296 /* Dequeue some incoming work from zebra (if any) onto the temporary
3297 * working list.
3298 */
3299 DPLANE_LOCK();
3300
3301 /* Locate initial registered provider */
3302 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
3303
14b0bc8e 3304 /* Move new work from incoming list to temp list */
c831033f 3305 for (counter = 0; counter < limit; counter++) {
3fe4ccc4 3306 ctx = TAILQ_FIRST(&zdplane_info.dg_update_ctx_q);
c831033f 3307 if (ctx) {
3fe4ccc4 3308 TAILQ_REMOVE(&zdplane_info.dg_update_ctx_q, ctx,
c831033f
MS
3309 zd_q_entries);
3310
c831033f
MS
3311 ctx->zd_provider = prov->dp_id;
3312
3313 TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
3314 } else {
3315 break;
3316 }
3317 }
3318
3319 DPLANE_UNLOCK();
3320
14b0bc8e
MS
3321 atomic_fetch_sub_explicit(&zdplane_info.dg_routes_queued, counter,
3322 memory_order_relaxed);
3323
c831033f
MS
3324 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3325 zlog_debug("dplane: incoming new work counter: %d", counter);
3326
3327 /* Iterate through the registered providers, offering new incoming
3328 * work. If the provider has outgoing work in its queue, take that
3329 * work for the next provider
3330 */
3331 while (prov) {
3332
14b0bc8e
MS
3333 /* At each iteration, the temporary work list has 'counter'
3334 * items.
3335 */
c831033f
MS
3336 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3337 zlog_debug("dplane enqueues %d new work to provider '%s'",
3338 counter, dplane_provider_get_name(prov));
3339
3340 /* Capture current provider id in each context; check for
3341 * error status.
3342 */
3343 TAILQ_FOREACH_SAFE(ctx, &work_list, zd_q_entries, tctx) {
3344 if (dplane_ctx_get_status(ctx) ==
3345 ZEBRA_DPLANE_REQUEST_SUCCESS) {
3346 ctx->zd_provider = prov->dp_id;
3347 } else {
3348 /*
3349 * TODO -- improve error-handling: recirc
3350 * errors backwards so that providers can
3351 * 'undo' their work (if they want to)
3352 */
3353
3354 /* Move to error list; will be returned
3355 * zebra main.
3356 */
3357 TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
3358 TAILQ_INSERT_TAIL(&error_list,
3359 ctx, zd_q_entries);
3360 error_counter++;
3361 }
3362 }
3363
3364 /* Enqueue new work to the provider */
ad6aad4d 3365 dplane_provider_lock(prov);
c831033f
MS
3366
3367 if (TAILQ_FIRST(&work_list))
3368 TAILQ_CONCAT(&(prov->dp_ctx_in_q), &work_list,
3369 zd_q_entries);
3370
c9d17fe8
MS
3371 atomic_fetch_add_explicit(&prov->dp_in_counter, counter,
3372 memory_order_relaxed);
3373 atomic_fetch_add_explicit(&prov->dp_in_queued, counter,
3374 memory_order_relaxed);
3375 curr = atomic_load_explicit(&prov->dp_in_queued,
3376 memory_order_relaxed);
3377 high = atomic_load_explicit(&prov->dp_in_max,
3378 memory_order_relaxed);
3379 if (curr > high)
3380 atomic_store_explicit(&prov->dp_in_max, curr,
c831033f
MS
3381 memory_order_relaxed);
3382
ad6aad4d 3383 dplane_provider_unlock(prov);
c831033f 3384
14b0bc8e
MS
3385 /* Reset the temp list (though the 'concat' may have done this
3386 * already), and the counter
3387 */
c831033f
MS
3388 TAILQ_INIT(&work_list);
3389 counter = 0;
3390
14b0bc8e
MS
3391 /* Call into the provider code. Note that this is
3392 * unconditional: we offer to do work even if we don't enqueue
3393 * any _new_ work.
3394 */
c831033f
MS
3395 (*prov->dp_fp)(prov);
3396
3397 /* Check for zebra shutdown */
3398 if (!zdplane_info.dg_run)
3399 break;
3400
3401 /* Dequeue completed work from the provider */
ad6aad4d 3402 dplane_provider_lock(prov);
c831033f
MS
3403
3404 while (counter < limit) {
3405 ctx = TAILQ_FIRST(&(prov->dp_ctx_out_q));
3406 if (ctx) {
3407 TAILQ_REMOVE(&(prov->dp_ctx_out_q), ctx,
3408 zd_q_entries);
3409
3410 TAILQ_INSERT_TAIL(&work_list,
3411 ctx, zd_q_entries);
3412 counter++;
3413 } else
3414 break;
3415 }
3416
ad6aad4d 3417 dplane_provider_unlock(prov);
c831033f
MS
3418
3419 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3420 zlog_debug("dplane dequeues %d completed work from provider %s",
3421 counter, dplane_provider_get_name(prov));
3422
3423 /* Locate next provider */
3424 DPLANE_LOCK();
3425 prov = TAILQ_NEXT(prov, dp_prov_link);
3426 DPLANE_UNLOCK();
c831033f
MS
3427 }
3428
3429 /* After all providers have been serviced, enqueue any completed
14b0bc8e 3430 * work and any errors back to zebra so it can process the results.
c831033f 3431 */
c831033f 3432 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
14b0bc8e
MS
3433 zlog_debug("dplane has %d completed, %d errors, for zebra main",
3434 counter, error_counter);
c831033f
MS
3435
3436 /*
4c206c8f 3437 * Hand lists through the api to zebra main,
c831033f
MS
3438 * to reduce the number of lock/unlock cycles
3439 */
14b0bc8e 3440
4c206c8f
MS
3441 /* Call through to zebra main */
3442 (zdplane_info.dg_results_cb)(&error_list);
14b0bc8e 3443
4c206c8f 3444 TAILQ_INIT(&error_list);
14b0bc8e 3445
4c206c8f
MS
3446 /* Call through to zebra main */
3447 (zdplane_info.dg_results_cb)(&work_list);
c831033f 3448
4c206c8f 3449 TAILQ_INIT(&work_list);
c831033f
MS
3450
3451done:
3452 return 0;
3453}
3454
4dfd7a02
MS
3455/*
3456 * Final phase of shutdown, after all work enqueued to dplane has been
3457 * processed. This is called from the zebra main pthread context.
3458 */
3459void zebra_dplane_shutdown(void)
3460{
3461 if (IS_ZEBRA_DEBUG_DPLANE)
3462 zlog_debug("Zebra dataplane shutdown called");
1d11b21f
MS
3463
3464 /* Stop dplane thread, if it's running */
3465
25779064 3466 zdplane_info.dg_run = false;
1d11b21f 3467
25779064 3468 THREAD_OFF(zdplane_info.dg_t_update);
1d11b21f 3469
d8c16a95
MS
3470 frr_pthread_stop(zdplane_info.dg_pthread, NULL);
3471
3472 /* Destroy pthread */
3473 frr_pthread_destroy(zdplane_info.dg_pthread);
3474 zdplane_info.dg_pthread = NULL;
3475 zdplane_info.dg_master = NULL;
4dfd7a02 3476
c831033f
MS
3477 /* TODO -- Notify provider(s) of final shutdown */
3478
3479 /* TODO -- Clean-up provider objects */
3480
3481 /* TODO -- Clean queue(s), free memory */
3482}
3483
3484/*
3485 * Initialize the dataplane module during startup, internal/private version
3486 */
2561d12e 3487static void zebra_dplane_init_internal(void)
c831033f
MS
3488{
3489 memset(&zdplane_info, 0, sizeof(zdplane_info));
3490
3491 pthread_mutex_init(&zdplane_info.dg_mutex, NULL);
1d11b21f 3492
3fe4ccc4 3493 TAILQ_INIT(&zdplane_info.dg_update_ctx_q);
c831033f 3494 TAILQ_INIT(&zdplane_info.dg_providers_q);
1d11b21f 3495
c831033f
MS
3496 zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK;
3497
3498 zdplane_info.dg_max_queued_updates = DPLANE_DEFAULT_MAX_QUEUED;
3499
3500 /* Register default kernel 'provider' during init */
3501 dplane_provider_init();
e5a60d82 3502}
c831033f 3503
e5a60d82
MS
3504/*
3505 * Start the dataplane pthread. This step needs to be run later than the
3506 * 'init' step, in case zebra has fork-ed.
3507 */
3508void zebra_dplane_start(void)
3509{
1dd4ea8a 3510 struct zebra_dplane_provider *prov;
c831033f
MS
3511 struct frr_pthread_attr pattr = {
3512 .start = frr_pthread_attr_default.start,
3513 .stop = frr_pthread_attr_default.stop
3514 };
3515
1dd4ea8a
MS
3516 /* Start dataplane pthread */
3517
c831033f 3518 zdplane_info.dg_pthread = frr_pthread_new(&pattr, "Zebra dplane thread",
0eca319c 3519 "zebra_dplane");
c831033f
MS
3520
3521 zdplane_info.dg_master = zdplane_info.dg_pthread->master;
3522
e5a60d82
MS
3523 zdplane_info.dg_run = true;
3524
c831033f
MS
3525 /* Enqueue an initial event for the dataplane pthread */
3526 thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0,
3527 &zdplane_info.dg_t_update);
3528
1dd4ea8a
MS
3529 /* Call start callbacks for registered providers */
3530
3531 DPLANE_LOCK();
3532 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
3533 DPLANE_UNLOCK();
3534
3535 while (prov) {
3536
3537 if (prov->dp_start)
3538 (prov->dp_start)(prov);
3539
3540 /* Locate next provider */
3541 DPLANE_LOCK();
3542 prov = TAILQ_NEXT(prov, dp_prov_link);
3543 DPLANE_UNLOCK();
3544 }
3545
c831033f 3546 frr_pthread_run(zdplane_info.dg_pthread, NULL);
18c37974
MS
3547}
3548
7cdb1a84 3549/*
b8e0423d 3550 * Initialize the dataplane module at startup; called by zebra rib_init()
7cdb1a84 3551 */
4c206c8f 3552void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_q *))
7cdb1a84 3553{
2561d12e 3554 zebra_dplane_init_internal();
4c206c8f 3555 zdplane_info.dg_results_cb = results_fp;
7cdb1a84 3556}