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