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