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