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