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