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