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