]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_dplane.c
zebra: fix flowspec ipset operations
[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"
3801e764 31#include "zebra/zebra_router.h"
7cdb1a84 32#include "zebra/zebra_dplane.h"
f2a0ba3a 33#include "zebra/zebra_vxlan_private.h"
ee70f629 34#include "zebra/zebra_mpls.h"
7cdb1a84
MS
35#include "zebra/rt.h"
36#include "zebra/debug.h"
f62e5480 37#include "zebra/zebra_pbr.h"
c60522f7 38#include "printfrr.h"
7cdb1a84 39
d166308b 40/* Memory types */
bf8d3d6a
DL
41DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx");
42DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf");
43DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider");
44DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object");
d166308b 45DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes");
7cdb1a84
MS
46
47#ifndef AOK
48# define AOK 0
49#endif
50
5917df09
MS
51/* Control for collection of extra interface info with route updates; a plugin
52 * can enable the extra info via a dplane api.
53 */
54static bool dplane_collect_extra_intf_info;
55
e5a60d82
MS
56/* Enable test dataplane provider */
57/*#define DPLANE_TEST_PROVIDER 1 */
58
91f16812
MS
59/* Default value for max queued incoming updates */
60const uint32_t DPLANE_DEFAULT_MAX_QUEUED = 200;
61
c831033f
MS
62/* Default value for new work per cycle */
63const uint32_t DPLANE_DEFAULT_NEW_WORK = 100;
64
7cdb1a84
MS
65/* Validation check macro for context blocks */
66/* #define DPLANE_DEBUG 1 */
67
68#ifdef DPLANE_DEBUG
69
25779064
MS
70# define DPLANE_CTX_VALID(p) \
71 assert((p) != NULL)
7cdb1a84
MS
72
73#else
74
5709131c 75# define DPLANE_CTX_VALID(p)
7cdb1a84
MS
76
77#endif /* DPLANE_DEBUG */
78
0c8215cb
SW
79/*
80 * Nexthop information captured for nexthop/nexthop group updates
81 */
82struct dplane_nexthop_info {
83 uint32_t id;
df3cef24 84 uint32_t old_id;
0c8215cb
SW
85 afi_t afi;
86 vrf_id_t vrf_id;
38e40db1 87 int type;
0c8215cb
SW
88
89 struct nexthop_group ng;
e22e8001
SW
90 struct nh_grp nh_grp[MULTIPATH_NUM];
91 uint8_t nh_grp_count;
0c8215cb
SW
92};
93
5917df09
MS
94/*
95 * Optional extra info about interfaces used in route updates' nexthops.
96 */
97struct dplane_intf_extra {
98 vrf_id_t vrf_id;
99 uint32_t ifindex;
100 uint32_t flags;
101 uint32_t status;
102
103 TAILQ_ENTRY(dplane_intf_extra) link;
104};
105
7cdb1a84 106/*
0f461727 107 * Route information captured for route updates.
7cdb1a84 108 */
0f461727 109struct dplane_route_info {
7cdb1a84
MS
110
111 /* Dest and (optional) source prefixes */
112 struct prefix zd_dest;
113 struct prefix zd_src;
114
0f461727
MS
115 afi_t zd_afi;
116 safi_t zd_safi;
7cdb1a84
MS
117
118 int zd_type;
119 int zd_old_type;
120
7cdb1a84
MS
121 route_tag_t zd_tag;
122 route_tag_t zd_old_tag;
123 uint32_t zd_metric;
01ce7cba 124 uint32_t zd_old_metric;
0f461727 125
7cdb1a84
MS
126 uint16_t zd_instance;
127 uint16_t zd_old_instance;
128
129 uint8_t zd_distance;
130 uint8_t zd_old_distance;
131
132 uint32_t zd_mtu;
133 uint32_t zd_nexthop_mtu;
134
0c8215cb
SW
135 /* Nexthop hash entry info */
136 struct dplane_nexthop_info nhe;
f820d025 137
7cdb1a84 138 /* Nexthops */
1d48702e 139 uint32_t zd_nhg_id;
7cdb1a84
MS
140 struct nexthop_group zd_ng;
141
1d48702e
MS
142 /* Backup nexthops (if present) */
143 struct nexthop_group backup_ng;
144
4dfd7a02 145 /* "Previous" nexthops, used only in route updates without netlink */
01ce7cba 146 struct nexthop_group zd_old_ng;
1d48702e 147 struct nexthop_group old_backup_ng;
01ce7cba 148
5917df09
MS
149 /* Optional list of extra interface info */
150 TAILQ_HEAD(dp_intf_extra_q, dplane_intf_extra) intf_extra_q;
0f461727
MS
151};
152
d613b8e1
MS
153/*
154 * Pseudowire info for the dataplane
155 */
156struct dplane_pw_info {
d613b8e1
MS
157 int type;
158 int af;
159 int status;
160 uint32_t flags;
072b487b 161 uint32_t nhg_id;
16d69787 162 union g_addr dest;
d613b8e1
MS
163 mpls_label_t local_label;
164 mpls_label_t remote_label;
165
072b487b
MS
166 /* Nexthops that are valid and installed */
167 struct nexthop_group fib_nhg;
168
169 /* Primary and backup nexthop sets, copied from the resolving route. */
170 struct nexthop_group primary_nhg;
171 struct nexthop_group backup_nhg;
16d69787 172
d613b8e1
MS
173 union pw_protocol_fields fields;
174};
175
c60522f7
AK
176/*
177 * Bridge port info for the dataplane
178 */
179struct dplane_br_port_info {
180 uint32_t sph_filter_cnt;
181 struct in_addr sph_filters[ES_VTEP_MAX_CNT];
182 /* DPLANE_BR_PORT_XXX - see zebra_dplane.h*/
183 uint32_t flags;
184 uint32_t backup_nhg_id;
185};
186
a4a4802a
MS
187/*
188 * Interface/prefix info for the dataplane
189 */
190struct dplane_intf_info {
191
a4a4802a
MS
192 uint32_t metric;
193 uint32_t flags;
194
195#define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */
196#define DPLANE_INTF_SECONDARY (1 << 1)
64168803 197#define DPLANE_INTF_BROADCAST (1 << 2)
0f3af738 198#define DPLANE_INTF_HAS_DEST DPLANE_INTF_CONNECTED
64168803 199#define DPLANE_INTF_HAS_LABEL (1 << 4)
a4a4802a
MS
200
201 /* Interface address/prefix */
202 struct prefix prefix;
203
204 /* Dest address, for p2p, or broadcast prefix */
205 struct prefix dest_prefix;
206
207 char *label;
208 char label_buf[32];
209};
210
7597ac7b 211/*
0bbd4ff4 212 * EVPN MAC address info for the dataplane.
7597ac7b
MS
213 */
214struct dplane_mac_info {
215 vlanid_t vid;
478566d6 216 ifindex_t br_ifindex;
7597ac7b
MS
217 struct ethaddr mac;
218 struct in_addr vtep_ip;
219 bool is_sticky;
506efd37 220 uint32_t nhg_id;
f188e68e 221 uint32_t update_flags;
7597ac7b
MS
222};
223
931fa60c 224/*
d68e74b4 225 * Neighbor info for the dataplane
931fa60c
MS
226 */
227struct dplane_neigh_info {
228 struct ipaddr ip_addr;
0a27a2fe
PG
229 union {
230 struct ethaddr mac;
231 struct ipaddr ip_addr;
232 } link;
931fa60c
MS
233 uint32_t flags;
234 uint16_t state;
f188e68e 235 uint32_t update_flags;
931fa60c
MS
236};
237
e18747a9
PG
238/*
239 * Neighbor Table
240 */
241struct dplane_neigh_table {
242 uint8_t family;
243 uint32_t app_probes;
244 uint32_t ucast_probes;
245 uint32_t mcast_probes;
246};
247
60d8d43b
JU
248/*
249 * Policy based routing rule info for the dataplane
250 */
251struct dplane_ctx_rule {
252 uint32_t priority;
253
254 /* The route table pointed by this rule */
255 uint32_t table;
256
257 /* Filter criteria */
258 uint32_t filter_bm;
259 uint32_t fwmark;
01f23aff 260 uint8_t dsfield;
60d8d43b
JU
261 struct prefix src_ip;
262 struct prefix dst_ip;
8ccbc778 263 uint8_t ip_proto;
d70a31a3
EB
264
265 uint8_t action_pcp;
266 uint16_t action_vlan_id;
267 uint16_t action_vlan_flags;
268
269 uint32_t action_queue_id;
270
58a1d249 271 char ifname[INTERFACE_NAMSIZ + 1];
60d8d43b
JU
272};
273
274struct dplane_rule_info {
275 /*
276 * Originating zclient sock fd, so we can know who to send
277 * back to.
278 */
279 int sock;
280
281 int unique;
282 int seq;
283
284 struct dplane_ctx_rule new;
285 struct dplane_ctx_rule old;
286};
287
62b4b7e4
PG
288struct dplane_gre_ctx {
289 uint32_t link_ifindex;
db51f0cd 290 unsigned int mtu;
e3d3fa06 291 struct zebra_l2info_gre info;
62b4b7e4 292};
0f461727
MS
293/*
294 * The context block used to exchange info about route updates across
295 * the boundary between the zebra main context (and pthread) and the
296 * dataplane layer (and pthread).
297 */
298struct zebra_dplane_ctx {
299
300 /* Operation code */
301 enum dplane_op_e zd_op;
302
303 /* Status on return */
304 enum zebra_dplane_result zd_status;
305
306 /* Dplane provider id */
307 uint32_t zd_provider;
308
309 /* Flags - used by providers, e.g. */
310 int zd_flags;
311
312 bool zd_is_update;
313
314 uint32_t zd_seq;
315 uint32_t zd_old_seq;
316
0024a559
MS
317 /* Some updates may be generated by notifications: allow the
318 * plugin to notice and ignore results from its own notifications.
319 */
320 uint32_t zd_notif_provider;
321
0f461727
MS
322 /* TODO -- internal/sub-operation status? */
323 enum zebra_dplane_result zd_remote_status;
324 enum zebra_dplane_result zd_kernel_status;
325
326 vrf_id_t zd_vrf_id;
327 uint32_t zd_table_id;
328
7c7ef4a8
MS
329 char zd_ifname[INTERFACE_NAMSIZ];
330 ifindex_t zd_ifindex;
331
a4a4802a 332 /* Support info for different kinds of updates */
0f461727
MS
333 union {
334 struct dplane_route_info rinfo;
8f74a383 335 struct zebra_lsp lsp;
d613b8e1 336 struct dplane_pw_info pw;
c60522f7 337 struct dplane_br_port_info br_port;
a4a4802a 338 struct dplane_intf_info intf;
7597ac7b 339 struct dplane_mac_info macinfo;
931fa60c 340 struct dplane_neigh_info neigh;
60d8d43b 341 struct dplane_rule_info rule;
5162e000 342 struct zebra_pbr_iptable iptable;
ef524230 343 struct zebra_pbr_ipset ipset;
8f065cd3 344 struct {
ef524230
PG
345 struct zebra_pbr_ipset_entry entry;
346 struct zebra_pbr_ipset_info info;
347 } ipset_entry;
e18747a9 348 struct dplane_neigh_table neightable;
62b4b7e4 349 struct dplane_gre_ctx gre;
0f461727
MS
350 } u;
351
352 /* Namespace info, used especially for netlink kernel communication */
353 struct zebra_dplane_info zd_ns_info;
354
7cdb1a84 355 /* Embedded list linkage */
25779064 356 TAILQ_ENTRY(zebra_dplane_ctx) zd_q_entries;
7cdb1a84
MS
357};
358
c831033f
MS
359/* Flag that can be set by a pre-kernel provider as a signal that an update
360 * should bypass the kernel.
361 */
362#define DPLANE_CTX_FLAG_NO_KERNEL 0x01
363
364
7cdb1a84
MS
365/*
366 * Registration block for one dataplane provider.
367 */
25779064 368struct zebra_dplane_provider {
7cdb1a84
MS
369 /* Name */
370 char dp_name[DPLANE_PROVIDER_NAMELEN + 1];
371
372 /* Priority, for ordering among providers */
373 uint8_t dp_priority;
374
375 /* Id value */
376 uint32_t dp_id;
377
c831033f
MS
378 /* Mutex */
379 pthread_mutex_t dp_mutex;
380
381 /* Plugin-provided extra data */
382 void *dp_data;
383
384 /* Flags */
385 int dp_flags;
386
1dd4ea8a
MS
387 int (*dp_start)(struct zebra_dplane_provider *prov);
388
4c206c8f 389 int (*dp_fp)(struct zebra_dplane_provider *prov);
7cdb1a84 390
4c206c8f 391 int (*dp_fini)(struct zebra_dplane_provider *prov, bool early_p);
18c37974 392
0545c373 393 _Atomic uint32_t dp_in_counter;
c9d17fe8 394 _Atomic uint32_t dp_in_queued;
c831033f
MS
395 _Atomic uint32_t dp_in_max;
396 _Atomic uint32_t dp_out_counter;
c9d17fe8 397 _Atomic uint32_t dp_out_queued;
c831033f 398 _Atomic uint32_t dp_out_max;
0545c373 399 _Atomic uint32_t dp_error_counter;
1d11b21f 400
c831033f
MS
401 /* Queue of contexts inbound to the provider */
402 struct dplane_ctx_q dp_ctx_in_q;
403
404 /* Queue of completed contexts outbound from the provider back
405 * towards the dataplane module.
406 */
407 struct dplane_ctx_q dp_ctx_out_q;
7cdb1a84 408
c831033f
MS
409 /* Embedded list linkage for provider objects */
410 TAILQ_ENTRY(zebra_dplane_provider) dp_prov_link;
7cdb1a84
MS
411};
412
d166308b
MS
413/* Declare types for list of zns info objects */
414PREDECL_DLIST(zns_info_list);
415
416struct dplane_zns_info {
417 struct zebra_dplane_info info;
418
419 /* Read event */
420 struct thread *t_read;
421
422 /* List linkage */
423 struct zns_info_list_item link;
424};
425
7cdb1a84
MS
426/*
427 * Globals
428 */
25779064 429static struct zebra_dplane_globals {
7cdb1a84
MS
430 /* Mutex to control access to dataplane components */
431 pthread_mutex_t dg_mutex;
432
433 /* Results callback registered by zebra 'core' */
4c206c8f 434 int (*dg_results_cb)(struct dplane_ctx_q *ctxlist);
7cdb1a84 435
4dfd7a02
MS
436 /* Sentinel for beginning of shutdown */
437 volatile bool dg_is_shutdown;
438
439 /* Sentinel for end of shutdown */
1d11b21f
MS
440 volatile bool dg_run;
441
3fe4ccc4
MS
442 /* Update context queue inbound to the dataplane */
443 TAILQ_HEAD(zdg_ctx_q, zebra_dplane_ctx) dg_update_ctx_q;
7cdb1a84
MS
444
445 /* Ordered list of providers */
25779064 446 TAILQ_HEAD(zdg_prov_q, zebra_dplane_provider) dg_providers_q;
7cdb1a84 447
d166308b
MS
448 /* List of info about each zns */
449 struct zns_info_list_head dg_zns_list;
450
1d11b21f 451 /* Counter used to assign internal ids to providers */
b8e0423d
MS
452 uint32_t dg_provider_id;
453
91f16812
MS
454 /* Limit number of pending, unprocessed updates */
455 _Atomic uint32_t dg_max_queued_updates;
456
cf363e1b
MS
457 /* Control whether system route notifications should be produced. */
458 bool dg_sys_route_notifs;
459
c831033f
MS
460 /* Limit number of new updates dequeued at once, to pace an
461 * incoming burst.
462 */
463 uint32_t dg_updates_per_cycle;
464
0545c373 465 _Atomic uint32_t dg_routes_in;
1d11b21f 466 _Atomic uint32_t dg_routes_queued;
4dfd7a02 467 _Atomic uint32_t dg_routes_queued_max;
0545c373 468 _Atomic uint32_t dg_route_errors;
16c628de
MS
469 _Atomic uint32_t dg_other_errors;
470
f820d025
SW
471 _Atomic uint32_t dg_nexthops_in;
472 _Atomic uint32_t dg_nexthop_errors;
473
16c628de 474 _Atomic uint32_t dg_lsps_in;
16c628de
MS
475 _Atomic uint32_t dg_lsp_errors;
476
97d8d05a
MS
477 _Atomic uint32_t dg_pws_in;
478 _Atomic uint32_t dg_pw_errors;
479
c60522f7
AK
480 _Atomic uint32_t dg_br_port_in;
481 _Atomic uint32_t dg_br_port_errors;
482
64168803
MS
483 _Atomic uint32_t dg_intf_addrs_in;
484 _Atomic uint32_t dg_intf_addr_errors;
485
7597ac7b
MS
486 _Atomic uint32_t dg_macs_in;
487 _Atomic uint32_t dg_mac_errors;
488
931fa60c
MS
489 _Atomic uint32_t dg_neighs_in;
490 _Atomic uint32_t dg_neigh_errors;
491
60d8d43b
JU
492 _Atomic uint32_t dg_rules_in;
493 _Atomic uint32_t dg_rule_errors;
494
c831033f 495 _Atomic uint32_t dg_update_yields;
1d11b21f 496
5162e000
PG
497 _Atomic uint32_t dg_iptable_in;
498 _Atomic uint32_t dg_iptable_errors;
ef524230
PG
499
500 _Atomic uint32_t dg_ipset_in;
501 _Atomic uint32_t dg_ipset_errors;
502 _Atomic uint32_t dg_ipset_entry_in;
503 _Atomic uint32_t dg_ipset_entry_errors;
504
e18747a9
PG
505 _Atomic uint32_t dg_neightable_in;
506 _Atomic uint32_t dg_neightable_errors;
507
62b4b7e4
PG
508 _Atomic uint32_t dg_gre_set_in;
509 _Atomic uint32_t dg_gre_set_errors;
510
d8c16a95
MS
511 /* Dataplane pthread */
512 struct frr_pthread *dg_pthread;
513
7cdb1a84
MS
514 /* Event-delivery context 'master' for the dplane */
515 struct thread_master *dg_master;
516
517 /* Event/'thread' pointer for queued updates */
518 struct thread *dg_t_update;
519
4dfd7a02
MS
520 /* Event pointer for pending shutdown check loop */
521 struct thread *dg_t_shutdown_check;
522
25779064 523} zdplane_info;
7cdb1a84 524
d166308b
MS
525/* Instantiate zns list type */
526DECLARE_DLIST(zns_info_list, struct dplane_zns_info, link);
527
7cdb1a84 528/*
c831033f 529 * Lock and unlock for interactions with the zebra 'core' pthread
7cdb1a84 530 */
25779064 531#define DPLANE_LOCK() pthread_mutex_lock(&zdplane_info.dg_mutex)
25779064 532#define DPLANE_UNLOCK() pthread_mutex_unlock(&zdplane_info.dg_mutex)
7cdb1a84 533
c831033f
MS
534
535/*
536 * Lock and unlock for individual providers
537 */
538#define DPLANE_PROV_LOCK(p) pthread_mutex_lock(&((p)->dp_mutex))
539#define DPLANE_PROV_UNLOCK(p) pthread_mutex_unlock(&((p)->dp_mutex))
540
7cdb1a84 541/* Prototypes */
c831033f 542static int dplane_thread_loop(struct thread *event);
62b8bb7a
MS
543static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
544 struct zebra_ns *zns);
8f74a383 545static enum zebra_dplane_result lsp_update_internal(struct zebra_lsp *lsp,
16c628de 546 enum dplane_op_e op);
97d8d05a
MS
547static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
548 enum dplane_op_e op);
64168803
MS
549static enum zebra_dplane_result intf_addr_update_internal(
550 const struct interface *ifp, const struct connected *ifc,
551 enum dplane_op_e op);
f73a8467 552static enum zebra_dplane_result mac_update_common(
7597ac7b 553 enum dplane_op_e op, const struct interface *ifp,
478566d6 554 const struct interface *br_ifp,
7597ac7b 555 vlanid_t vid, const struct ethaddr *mac,
f188e68e
AK
556 struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
557 uint32_t update_flags);
0a27a2fe
PG
558static enum zebra_dplane_result
559neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
560 const void *link, int link_family,
561 const struct ipaddr *ip, uint32_t flags, uint16_t state,
562 uint32_t update_flags, int protocol);
7cdb1a84
MS
563
564/*
565 * Public APIs
566 */
567
ad6aad4d
MS
568/* Obtain thread_master for dataplane thread */
569struct thread_master *dplane_get_thread_master(void)
570{
571 return zdplane_info.dg_master;
572}
573
7cdb1a84 574/*
b8e0423d 575 * Allocate a dataplane update context
7cdb1a84 576 */
593e4eb1 577struct zebra_dplane_ctx *dplane_ctx_alloc(void)
7cdb1a84 578{
25779064 579 struct zebra_dplane_ctx *p;
7cdb1a84 580
b8e0423d
MS
581 /* TODO -- just alloc'ing memory, but would like to maintain
582 * a pool
583 */
25779064 584 p = XCALLOC(MTYPE_DP_CTX, sizeof(struct zebra_dplane_ctx));
7cdb1a84 585
5709131c 586 return p;
7cdb1a84
MS
587}
588
cf363e1b
MS
589/* Enable system route notifications */
590void dplane_enable_sys_route_notifs(void)
591{
592 zdplane_info.dg_sys_route_notifs = true;
593}
594
7cdb1a84 595/*
f73a8467 596 * Clean up dependent/internal allocations inside a context object
7cdb1a84 597 */
f73a8467 598static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
7cdb1a84 599{
5917df09
MS
600 struct dplane_intf_extra *if_extra, *if_tmp;
601
f73a8467
MS
602 /*
603 * Some internal allocations may need to be freed, depending on
16c628de
MS
604 * the type of info captured in the ctx.
605 */
f73a8467 606 switch (ctx->zd_op) {
16c628de
MS
607 case DPLANE_OP_ROUTE_INSTALL:
608 case DPLANE_OP_ROUTE_UPDATE:
609 case DPLANE_OP_ROUTE_DELETE:
cf363e1b
MS
610 case DPLANE_OP_SYS_ROUTE_ADD:
611 case DPLANE_OP_SYS_ROUTE_DELETE:
54818e3b 612 case DPLANE_OP_ROUTE_NOTIFY:
b8e0423d 613
16c628de 614 /* Free allocated nexthops */
f73a8467 615 if (ctx->u.rinfo.zd_ng.nexthop) {
7cdb1a84 616 /* This deals with recursive nexthops too */
f73a8467 617 nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
16c628de 618
f73a8467 619 ctx->u.rinfo.zd_ng.nexthop = NULL;
7cdb1a84
MS
620 }
621
1d48702e 622 /* Free backup info also (if present) */
f73a8467 623 if (ctx->u.rinfo.backup_ng.nexthop) {
1d48702e 624 /* This deals with recursive nexthops too */
f73a8467 625 nexthops_free(ctx->u.rinfo.backup_ng.nexthop);
1d48702e 626
f73a8467 627 ctx->u.rinfo.backup_ng.nexthop = NULL;
1d48702e
MS
628 }
629
f73a8467 630 if (ctx->u.rinfo.zd_old_ng.nexthop) {
4dfd7a02 631 /* This deals with recursive nexthops too */
f73a8467 632 nexthops_free(ctx->u.rinfo.zd_old_ng.nexthop);
16c628de 633
f73a8467 634 ctx->u.rinfo.zd_old_ng.nexthop = NULL;
16c628de
MS
635 }
636
f73a8467 637 if (ctx->u.rinfo.old_backup_ng.nexthop) {
1d48702e 638 /* This deals with recursive nexthops too */
f73a8467 639 nexthops_free(ctx->u.rinfo.old_backup_ng.nexthop);
1d48702e 640
f73a8467 641 ctx->u.rinfo.old_backup_ng.nexthop = NULL;
1d48702e
MS
642 }
643
5917df09
MS
644 /* Optional extra interface info */
645 TAILQ_FOREACH_SAFE(if_extra, &ctx->u.rinfo.intf_extra_q,
646 link, if_tmp) {
647 TAILQ_REMOVE(&ctx->u.rinfo.intf_extra_q, if_extra,
648 link);
649 XFREE(MTYPE_DP_INTF, if_extra);
650 }
651
16c628de
MS
652 break;
653
f820d025
SW
654 case DPLANE_OP_NH_INSTALL:
655 case DPLANE_OP_NH_UPDATE:
656 case DPLANE_OP_NH_DELETE: {
f73a8467 657 if (ctx->u.rinfo.nhe.ng.nexthop) {
0c8215cb 658 /* This deals with recursive nexthops too */
f73a8467 659 nexthops_free(ctx->u.rinfo.nhe.ng.nexthop);
0c8215cb 660
f73a8467 661 ctx->u.rinfo.nhe.ng.nexthop = NULL;
0c8215cb 662 }
f820d025
SW
663 break;
664 }
665
16c628de
MS
666 case DPLANE_OP_LSP_INSTALL:
667 case DPLANE_OP_LSP_UPDATE:
668 case DPLANE_OP_LSP_DELETE:
104e3ad9 669 case DPLANE_OP_LSP_NOTIFY:
16c628de 670 {
f2595bd5 671 struct zebra_nhlfe *nhlfe;
16c628de 672
cd4bb96f
MS
673 /* Unlink and free allocated NHLFEs */
674 frr_each_safe(nhlfe_list, &ctx->u.lsp.nhlfe_list, nhlfe) {
675 nhlfe_list_del(&ctx->u.lsp.nhlfe_list, nhlfe);
676 zebra_mpls_nhlfe_free(nhlfe);
677 }
678
679 /* Unlink and free allocated backup NHLFEs, if present */
680 frr_each_safe(nhlfe_list,
681 &(ctx->u.lsp.backup_nhlfe_list), nhlfe) {
682 nhlfe_list_del(&ctx->u.lsp.backup_nhlfe_list,
683 nhlfe);
684 zebra_mpls_nhlfe_free(nhlfe);
685 }
01ce7cba 686
cd4bb96f 687 /* Clear pointers in lsp struct, in case we're caching
16c628de
MS
688 * free context structs.
689 */
ee70f629 690 nhlfe_list_init(&ctx->u.lsp.nhlfe_list);
f73a8467 691 ctx->u.lsp.best_nhlfe = NULL;
cd4bb96f 692 nhlfe_list_init(&ctx->u.lsp.backup_nhlfe_list);
16c628de
MS
693
694 break;
695 }
696
97d8d05a
MS
697 case DPLANE_OP_PW_INSTALL:
698 case DPLANE_OP_PW_UNINSTALL:
16d69787 699 /* Free allocated nexthops */
072b487b 700 if (ctx->u.pw.fib_nhg.nexthop) {
16d69787 701 /* This deals with recursive nexthops too */
072b487b
MS
702 nexthops_free(ctx->u.pw.fib_nhg.nexthop);
703
704 ctx->u.pw.fib_nhg.nexthop = NULL;
705 }
706 if (ctx->u.pw.primary_nhg.nexthop) {
707 nexthops_free(ctx->u.pw.primary_nhg.nexthop);
16d69787 708
072b487b
MS
709 ctx->u.pw.primary_nhg.nexthop = NULL;
710 }
711 if (ctx->u.pw.backup_nhg.nexthop) {
712 nexthops_free(ctx->u.pw.backup_nhg.nexthop);
713
714 ctx->u.pw.backup_nhg.nexthop = NULL;
16d69787
MS
715 }
716 break;
717
a4a4802a
MS
718 case DPLANE_OP_ADDR_INSTALL:
719 case DPLANE_OP_ADDR_UNINSTALL:
9d59df63
MS
720 case DPLANE_OP_INTF_ADDR_ADD:
721 case DPLANE_OP_INTF_ADDR_DEL:
64168803 722 /* Maybe free label string, if allocated */
f73a8467
MS
723 if (ctx->u.intf.label != NULL &&
724 ctx->u.intf.label != ctx->u.intf.label_buf) {
725 free(ctx->u.intf.label);
726 ctx->u.intf.label = NULL;
64168803
MS
727 }
728 break;
729
7597ac7b
MS
730 case DPLANE_OP_MAC_INSTALL:
731 case DPLANE_OP_MAC_DELETE:
f2412b2d 732 case DPLANE_OP_NEIGH_INSTALL:
931fa60c 733 case DPLANE_OP_NEIGH_UPDATE:
f2412b2d 734 case DPLANE_OP_NEIGH_DELETE:
0bbd4ff4
MS
735 case DPLANE_OP_VTEP_ADD:
736 case DPLANE_OP_VTEP_DELETE:
60d8d43b
JU
737 case DPLANE_OP_RULE_ADD:
738 case DPLANE_OP_RULE_DELETE:
739 case DPLANE_OP_RULE_UPDATE:
d68e74b4 740 case DPLANE_OP_NEIGH_DISCOVER:
c60522f7 741 case DPLANE_OP_BR_PORT_UPDATE:
0a27a2fe
PG
742 case DPLANE_OP_NEIGH_IP_INSTALL:
743 case DPLANE_OP_NEIGH_IP_DELETE:
16c628de 744 case DPLANE_OP_NONE:
ef524230
PG
745 case DPLANE_OP_IPSET_ADD:
746 case DPLANE_OP_IPSET_DELETE:
16c628de 747 break;
5162e000 748
ef524230
PG
749 case DPLANE_OP_IPSET_ENTRY_ADD:
750 case DPLANE_OP_IPSET_ENTRY_DELETE:
751 break;
e18747a9
PG
752 case DPLANE_OP_NEIGH_TABLE_UPDATE:
753 break;
5162e000
PG
754 case DPLANE_OP_IPTABLE_ADD:
755 case DPLANE_OP_IPTABLE_DELETE:
756 if (ctx->u.iptable.interface_name_list) {
757 struct listnode *node, *nnode;
758 char *ifname;
759
760 for (ALL_LIST_ELEMENTS(
761 ctx->u.iptable.interface_name_list, node,
762 nnode, ifname)) {
763 LISTNODE_DETACH(
764 ctx->u.iptable.interface_name_list,
765 node);
ef524230 766 XFREE(MTYPE_DP_NETFILTER, ifname);
5162e000
PG
767 }
768 list_delete(&ctx->u.iptable.interface_name_list);
769 }
62b4b7e4
PG
770 break;
771 case DPLANE_OP_GRE_SET:
772 break;
7cdb1a84 773 }
f73a8467
MS
774}
775
776/*
777 * Free a dataplane results context.
778 */
779static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
780{
781 if (pctx == NULL)
782 return;
783
784 DPLANE_CTX_VALID(*pctx);
785
786 /* TODO -- just freeing memory, but would like to maintain
787 * a pool
788 */
789
790 /* Some internal allocations may need to be freed, depending on
791 * the type of info captured in the ctx.
792 */
793 dplane_ctx_free_internal(*pctx);
16c628de
MS
794
795 XFREE(MTYPE_DP_CTX, *pctx);
7cdb1a84
MS
796}
797
f73a8467
MS
798/*
799 * Reset an allocated context object for re-use. All internal allocations are
800 * freed and the context is memset.
801 */
802void dplane_ctx_reset(struct zebra_dplane_ctx *ctx)
803{
804 dplane_ctx_free_internal(ctx);
805 memset(ctx, 0, sizeof(*ctx));
806}
807
7cdb1a84
MS
808/*
809 * Return a context block to the dplane module after processing
810 */
25779064 811void dplane_ctx_fini(struct zebra_dplane_ctx **pctx)
7cdb1a84 812{
14b0bc8e 813 /* TODO -- maintain pool; for now, just free */
7cdb1a84
MS
814 dplane_ctx_free(pctx);
815}
816
817/* Enqueue a context block */
25779064
MS
818void dplane_ctx_enqueue_tail(struct dplane_ctx_q *q,
819 const struct zebra_dplane_ctx *ctx)
7cdb1a84 820{
25779064 821 TAILQ_INSERT_TAIL(q, (struct zebra_dplane_ctx *)ctx, zd_q_entries);
7cdb1a84
MS
822}
823
14b0bc8e
MS
824/* Append a list of context blocks to another list */
825void dplane_ctx_list_append(struct dplane_ctx_q *to_list,
826 struct dplane_ctx_q *from_list)
827{
828 if (TAILQ_FIRST(from_list)) {
829 TAILQ_CONCAT(to_list, from_list, zd_q_entries);
830
831 /* And clear 'from' list */
832 TAILQ_INIT(from_list);
833 }
834}
835
7cdb1a84 836/* Dequeue a context block from the head of a list */
68b375e0 837struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_q *q)
7cdb1a84 838{
25779064 839 struct zebra_dplane_ctx *ctx = TAILQ_FIRST(q);
5709131c
MS
840
841 if (ctx)
7cdb1a84 842 TAILQ_REMOVE(q, ctx, zd_q_entries);
7cdb1a84 843
68b375e0 844 return ctx;
7cdb1a84
MS
845}
846
847/*
848 * Accessors for information from the context object
849 */
25779064
MS
850enum zebra_dplane_result dplane_ctx_get_status(
851 const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
852{
853 DPLANE_CTX_VALID(ctx);
854
5709131c 855 return ctx->zd_status;
7cdb1a84
MS
856}
857
c831033f
MS
858void dplane_ctx_set_status(struct zebra_dplane_ctx *ctx,
859 enum zebra_dplane_result status)
860{
861 DPLANE_CTX_VALID(ctx);
862
863 ctx->zd_status = status;
864}
865
866/* Retrieve last/current provider id */
867uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx)
868{
869 DPLANE_CTX_VALID(ctx);
870 return ctx->zd_provider;
871}
872
873/* Providers run before the kernel can control whether a kernel
874 * update should be done.
875 */
876void dplane_ctx_set_skip_kernel(struct zebra_dplane_ctx *ctx)
877{
878 DPLANE_CTX_VALID(ctx);
879
880 SET_FLAG(ctx->zd_flags, DPLANE_CTX_FLAG_NO_KERNEL);
881}
882
883bool dplane_ctx_is_skip_kernel(const struct zebra_dplane_ctx *ctx)
884{
885 DPLANE_CTX_VALID(ctx);
886
887 return CHECK_FLAG(ctx->zd_flags, DPLANE_CTX_FLAG_NO_KERNEL);
888}
889
593e4eb1
MS
890void dplane_ctx_set_op(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
891{
892 DPLANE_CTX_VALID(ctx);
893 ctx->zd_op = op;
894}
895
25779064 896enum dplane_op_e dplane_ctx_get_op(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
897{
898 DPLANE_CTX_VALID(ctx);
899
5709131c 900 return ctx->zd_op;
7cdb1a84
MS
901}
902
5709131c 903const char *dplane_op2str(enum dplane_op_e op)
7cdb1a84
MS
904{
905 const char *ret = "UNKNOWN";
906
5709131c 907 switch (op) {
7cdb1a84
MS
908 case DPLANE_OP_NONE:
909 ret = "NONE";
910 break;
911
912 /* Route update */
913 case DPLANE_OP_ROUTE_INSTALL:
914 ret = "ROUTE_INSTALL";
915 break;
916 case DPLANE_OP_ROUTE_UPDATE:
917 ret = "ROUTE_UPDATE";
918 break;
919 case DPLANE_OP_ROUTE_DELETE:
920 ret = "ROUTE_DELETE";
921 break;
54818e3b
MS
922 case DPLANE_OP_ROUTE_NOTIFY:
923 ret = "ROUTE_NOTIFY";
924 break;
7cdb1a84 925
f820d025
SW
926 /* Nexthop update */
927 case DPLANE_OP_NH_INSTALL:
928 ret = "NH_INSTALL";
929 break;
930 case DPLANE_OP_NH_UPDATE:
931 ret = "NH_UPDATE";
932 break;
933 case DPLANE_OP_NH_DELETE:
934 ret = "NH_DELETE";
935 break;
936
16c628de
MS
937 case DPLANE_OP_LSP_INSTALL:
938 ret = "LSP_INSTALL";
939 break;
940 case DPLANE_OP_LSP_UPDATE:
941 ret = "LSP_UPDATE";
942 break;
943 case DPLANE_OP_LSP_DELETE:
944 ret = "LSP_DELETE";
945 break;
104e3ad9
MS
946 case DPLANE_OP_LSP_NOTIFY:
947 ret = "LSP_NOTIFY";
948 break;
16c628de 949
97d8d05a
MS
950 case DPLANE_OP_PW_INSTALL:
951 ret = "PW_INSTALL";
952 break;
953 case DPLANE_OP_PW_UNINSTALL:
954 ret = "PW_UNINSTALL";
955 break;
956
cf363e1b
MS
957 case DPLANE_OP_SYS_ROUTE_ADD:
958 ret = "SYS_ROUTE_ADD";
959 break;
960 case DPLANE_OP_SYS_ROUTE_DELETE:
961 ret = "SYS_ROUTE_DEL";
962 break;
a4a4802a 963
c60522f7
AK
964 case DPLANE_OP_BR_PORT_UPDATE:
965 ret = "BR_PORT_UPDATE";
966 break;
967
a4a4802a
MS
968 case DPLANE_OP_ADDR_INSTALL:
969 ret = "ADDR_INSTALL";
970 break;
971 case DPLANE_OP_ADDR_UNINSTALL:
972 ret = "ADDR_UNINSTALL";
973 break;
974
7597ac7b
MS
975 case DPLANE_OP_MAC_INSTALL:
976 ret = "MAC_INSTALL";
977 break;
978 case DPLANE_OP_MAC_DELETE:
979 ret = "MAC_DELETE";
980 break;
f2412b2d
MS
981
982 case DPLANE_OP_NEIGH_INSTALL:
983 ret = "NEIGH_INSTALL";
984 break;
931fa60c
MS
985 case DPLANE_OP_NEIGH_UPDATE:
986 ret = "NEIGH_UPDATE";
987 break;
f2412b2d
MS
988 case DPLANE_OP_NEIGH_DELETE:
989 ret = "NEIGH_DELETE";
990 break;
0bbd4ff4
MS
991 case DPLANE_OP_VTEP_ADD:
992 ret = "VTEP_ADD";
993 break;
994 case DPLANE_OP_VTEP_DELETE:
995 ret = "VTEP_DELETE";
996 break;
60d8d43b
JU
997
998 case DPLANE_OP_RULE_ADD:
999 ret = "RULE_ADD";
1000 break;
1001 case DPLANE_OP_RULE_DELETE:
1002 ret = "RULE_DELETE";
1003 break;
1004 case DPLANE_OP_RULE_UPDATE:
1005 ret = "RULE_UPDATE";
1006 break;
d68e74b4
JU
1007
1008 case DPLANE_OP_NEIGH_DISCOVER:
1009 ret = "NEIGH_DISCOVER";
1010 break;
5162e000
PG
1011
1012 case DPLANE_OP_IPTABLE_ADD:
1013 ret = "IPTABLE_ADD";
1014 break;
1015 case DPLANE_OP_IPTABLE_DELETE:
1016 ret = "IPTABLE_DELETE";
1017 break;
ef524230
PG
1018 case DPLANE_OP_IPSET_ADD:
1019 ret = "IPSET_ADD";
1020 break;
1021 case DPLANE_OP_IPSET_DELETE:
1022 ret = "IPSET_DELETE";
1023 break;
1024 case DPLANE_OP_IPSET_ENTRY_ADD:
1025 ret = "IPSET_ENTRY_ADD";
1026 break;
1027 case DPLANE_OP_IPSET_ENTRY_DELETE:
1028 ret = "IPSET_ENTRY_DELETE";
1029 break;
0a27a2fe
PG
1030 case DPLANE_OP_NEIGH_IP_INSTALL:
1031 ret = "NEIGH_IP_INSTALL";
1032 break;
1033 case DPLANE_OP_NEIGH_IP_DELETE:
1034 ret = "NEIGH_IP_DELETE";
1035 break;
e18747a9
PG
1036 case DPLANE_OP_NEIGH_TABLE_UPDATE:
1037 ret = "NEIGH_TABLE_UPDATE";
1038 break;
62b4b7e4
PG
1039
1040 case DPLANE_OP_GRE_SET:
1041 ret = "GRE_SET";
1042 break;
9d59df63
MS
1043
1044 case DPLANE_OP_INTF_ADDR_ADD:
1045 return "INTF_ADDR_ADD";
1046
1047 case DPLANE_OP_INTF_ADDR_DEL:
1048 return "INTF_ADDR_DEL";
5b94ec50 1049 }
7cdb1a84 1050
5709131c 1051 return ret;
7cdb1a84
MS
1052}
1053
f183e380
MS
1054const char *dplane_res2str(enum zebra_dplane_result res)
1055{
1056 const char *ret = "<Unknown>";
1057
1058 switch (res) {
1059 case ZEBRA_DPLANE_REQUEST_FAILURE:
1060 ret = "FAILURE";
1061 break;
1062 case ZEBRA_DPLANE_REQUEST_QUEUED:
1063 ret = "QUEUED";
1064 break;
1065 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1066 ret = "SUCCESS";
1067 break;
5b94ec50 1068 }
f183e380
MS
1069
1070 return ret;
1071}
1072
593e4eb1
MS
1073void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx,
1074 const struct prefix *dest)
1075{
1076 DPLANE_CTX_VALID(ctx);
1077
1078 prefix_copy(&(ctx->u.rinfo.zd_dest), dest);
1079}
1080
25779064 1081const struct prefix *dplane_ctx_get_dest(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1082{
1083 DPLANE_CTX_VALID(ctx);
1084
0f461727 1085 return &(ctx->u.rinfo.zd_dest);
7cdb1a84
MS
1086}
1087
593e4eb1
MS
1088void dplane_ctx_set_src(struct zebra_dplane_ctx *ctx, const struct prefix *src)
1089{
1090 DPLANE_CTX_VALID(ctx);
1091
1092 if (src)
1093 prefix_copy(&(ctx->u.rinfo.zd_src), src);
1094 else
1095 memset(&(ctx->u.rinfo.zd_src), 0, sizeof(struct prefix));
1096}
1097
5709131c 1098/* Source prefix is a little special - return NULL for "no src prefix" */
25779064 1099const struct prefix *dplane_ctx_get_src(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1100{
1101 DPLANE_CTX_VALID(ctx);
1102
0f461727
MS
1103 if (ctx->u.rinfo.zd_src.prefixlen == 0 &&
1104 IN6_IS_ADDR_UNSPECIFIED(&(ctx->u.rinfo.zd_src.u.prefix6))) {
5709131c 1105 return NULL;
7cdb1a84 1106 } else {
0f461727 1107 return &(ctx->u.rinfo.zd_src);
7cdb1a84
MS
1108 }
1109}
1110
25779064 1111bool dplane_ctx_is_update(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1112{
1113 DPLANE_CTX_VALID(ctx);
1114
5709131c 1115 return ctx->zd_is_update;
7cdb1a84
MS
1116}
1117
25779064 1118uint32_t dplane_ctx_get_seq(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1119{
1120 DPLANE_CTX_VALID(ctx);
1121
5709131c 1122 return ctx->zd_seq;
7cdb1a84
MS
1123}
1124
25779064 1125uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1126{
1127 DPLANE_CTX_VALID(ctx);
1128
5709131c 1129 return ctx->zd_old_seq;
7cdb1a84
MS
1130}
1131
593e4eb1
MS
1132void dplane_ctx_set_vrf(struct zebra_dplane_ctx *ctx, vrf_id_t vrf)
1133{
1134 DPLANE_CTX_VALID(ctx);
1135
1136 ctx->zd_vrf_id = vrf;
1137}
1138
25779064 1139vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1140{
1141 DPLANE_CTX_VALID(ctx);
1142
5709131c 1143 return ctx->zd_vrf_id;
7cdb1a84
MS
1144}
1145
971bad84
MS
1146/* In some paths we have only a namespace id */
1147void dplane_ctx_set_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t nsid)
1148{
1149 DPLANE_CTX_VALID(ctx);
1150
1151 ctx->zd_ns_info.ns_id = nsid;
1152}
1153
1154ns_id_t dplane_ctx_get_ns_id(const struct zebra_dplane_ctx *ctx)
1155{
1156 DPLANE_CTX_VALID(ctx);
1157
1158 return ctx->zd_ns_info.ns_id;
1159}
1160
0024a559
MS
1161bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx)
1162{
1163 DPLANE_CTX_VALID(ctx);
1164
1165 return (ctx->zd_notif_provider != 0);
1166}
1167
1168uint32_t dplane_ctx_get_notif_provider(const struct zebra_dplane_ctx *ctx)
1169{
1170 DPLANE_CTX_VALID(ctx);
1171
1172 return ctx->zd_notif_provider;
1173}
1174
9651af61
MS
1175void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx,
1176 uint32_t id)
1177{
1178 DPLANE_CTX_VALID(ctx);
1179
1180 ctx->zd_notif_provider = id;
1181}
fd563cc7 1182
7c7ef4a8
MS
1183const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx)
1184{
1185 DPLANE_CTX_VALID(ctx);
1186
1187 return ctx->zd_ifname;
1188}
1189
fd563cc7
KS
1190void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname)
1191{
1192 DPLANE_CTX_VALID(ctx);
1193
1194 if (!ifname)
1195 return;
1196
1197 strlcpy(ctx->zd_ifname, ifname, sizeof(ctx->zd_ifname));
1198}
1199
7c7ef4a8
MS
1200ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx)
1201{
1202 DPLANE_CTX_VALID(ctx);
1203
1204 return ctx->zd_ifindex;
1205}
9651af61 1206
971bad84
MS
1207void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex)
1208{
1209 DPLANE_CTX_VALID(ctx);
1210
1211 ctx->zd_ifindex = ifindex;
1212}
1213
593e4eb1
MS
1214void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type)
1215{
1216 DPLANE_CTX_VALID(ctx);
1217
1218 ctx->u.rinfo.zd_type = type;
1219}
1220
25779064 1221int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1222{
1223 DPLANE_CTX_VALID(ctx);
1224
0f461727 1225 return ctx->u.rinfo.zd_type;
7cdb1a84
MS
1226}
1227
25779064 1228int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1229{
1230 DPLANE_CTX_VALID(ctx);
1231
0f461727 1232 return ctx->u.rinfo.zd_old_type;
7cdb1a84
MS
1233}
1234
593e4eb1
MS
1235void dplane_ctx_set_afi(struct zebra_dplane_ctx *ctx, afi_t afi)
1236{
1237 DPLANE_CTX_VALID(ctx);
1238
1239 ctx->u.rinfo.zd_afi = afi;
1240}
1241
25779064 1242afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1243{
1244 DPLANE_CTX_VALID(ctx);
1245
0f461727 1246 return ctx->u.rinfo.zd_afi;
7cdb1a84
MS
1247}
1248
593e4eb1
MS
1249void dplane_ctx_set_safi(struct zebra_dplane_ctx *ctx, safi_t safi)
1250{
1251 DPLANE_CTX_VALID(ctx);
1252
1253 ctx->u.rinfo.zd_safi = safi;
1254}
1255
25779064 1256safi_t dplane_ctx_get_safi(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1257{
1258 DPLANE_CTX_VALID(ctx);
1259
0f461727 1260 return ctx->u.rinfo.zd_safi;
7cdb1a84
MS
1261}
1262
593e4eb1
MS
1263void dplane_ctx_set_table(struct zebra_dplane_ctx *ctx, uint32_t table)
1264{
1265 DPLANE_CTX_VALID(ctx);
1266
1267 ctx->zd_table_id = table;
1268}
1269
25779064 1270uint32_t dplane_ctx_get_table(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1271{
1272 DPLANE_CTX_VALID(ctx);
1273
5709131c 1274 return ctx->zd_table_id;
7cdb1a84
MS
1275}
1276
25779064 1277route_tag_t dplane_ctx_get_tag(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1278{
1279 DPLANE_CTX_VALID(ctx);
1280
0f461727 1281 return ctx->u.rinfo.zd_tag;
7cdb1a84
MS
1282}
1283
6a91ae98
MS
1284void dplane_ctx_set_tag(struct zebra_dplane_ctx *ctx, route_tag_t tag)
1285{
1286 DPLANE_CTX_VALID(ctx);
1287
1288 ctx->u.rinfo.zd_tag = tag;
1289}
1290
25779064 1291route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1292{
1293 DPLANE_CTX_VALID(ctx);
1294
0f461727 1295 return ctx->u.rinfo.zd_old_tag;
7cdb1a84
MS
1296}
1297
25779064 1298uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1299{
1300 DPLANE_CTX_VALID(ctx);
1301
0f461727 1302 return ctx->u.rinfo.zd_instance;
7cdb1a84
MS
1303}
1304
6a91ae98
MS
1305void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance)
1306{
1307 DPLANE_CTX_VALID(ctx);
1308
1309 ctx->u.rinfo.zd_instance = instance;
1310}
1311
25779064 1312uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1313{
1314 DPLANE_CTX_VALID(ctx);
1315
0f461727 1316 return ctx->u.rinfo.zd_old_instance;
7cdb1a84
MS
1317}
1318
25779064 1319uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1320{
1321 DPLANE_CTX_VALID(ctx);
1322
0f461727 1323 return ctx->u.rinfo.zd_metric;
7cdb1a84
MS
1324}
1325
25779064 1326uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx)
01ce7cba
MS
1327{
1328 DPLANE_CTX_VALID(ctx);
1329
0f461727 1330 return ctx->u.rinfo.zd_old_metric;
01ce7cba
MS
1331}
1332
25779064 1333uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1334{
1335 DPLANE_CTX_VALID(ctx);
1336
0f461727 1337 return ctx->u.rinfo.zd_mtu;
7cdb1a84
MS
1338}
1339
25779064 1340uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1341{
1342 DPLANE_CTX_VALID(ctx);
1343
0f461727 1344 return ctx->u.rinfo.zd_nexthop_mtu;
7cdb1a84
MS
1345}
1346
25779064 1347uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1348{
1349 DPLANE_CTX_VALID(ctx);
1350
0f461727 1351 return ctx->u.rinfo.zd_distance;
7cdb1a84
MS
1352}
1353
6a91ae98
MS
1354void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance)
1355{
1356 DPLANE_CTX_VALID(ctx);
1357
1358 ctx->u.rinfo.zd_distance = distance;
1359}
1360
25779064 1361uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1362{
1363 DPLANE_CTX_VALID(ctx);
1364
0f461727 1365 return ctx->u.rinfo.zd_old_distance;
7cdb1a84
MS
1366}
1367
e1f3a8eb
MS
1368/*
1369 * Set the nexthops associated with a context: note that processing code
1370 * may well expect that nexthops are in canonical (sorted) order, so we
1371 * will enforce that here.
1372 */
593e4eb1
MS
1373void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
1374{
1375 DPLANE_CTX_VALID(ctx);
1376
1377 if (ctx->u.rinfo.zd_ng.nexthop) {
1378 nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
1379 ctx->u.rinfo.zd_ng.nexthop = NULL;
1380 }
e1f3a8eb 1381 nexthop_group_copy_nh_sorted(&(ctx->u.rinfo.zd_ng), nh);
593e4eb1
MS
1382}
1383
928f94a9
MS
1384/*
1385 * Set the list of backup nexthops; their ordering is preserved (they're not
1386 * re-sorted.)
1387 */
1388void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx,
1389 const struct nexthop_group *nhg)
1390{
1391 struct nexthop *nh, *last_nh, *nexthop;
1392
1393 DPLANE_CTX_VALID(ctx);
1394
1395 if (ctx->u.rinfo.backup_ng.nexthop) {
1396 nexthops_free(ctx->u.rinfo.backup_ng.nexthop);
1397 ctx->u.rinfo.backup_ng.nexthop = NULL;
1398 }
1399
1400 last_nh = NULL;
1401
1402 /* Be careful to preserve the order of the backup list */
1403 for (nh = nhg->nexthop; nh; nh = nh->next) {
1404 nexthop = nexthop_dup(nh, NULL);
1405
1406 if (last_nh)
1407 NEXTHOP_APPEND(last_nh, nexthop);
1408 else
1409 ctx->u.rinfo.backup_ng.nexthop = nexthop;
1410
1411 last_nh = nexthop;
1412 }
1413}
1414
1d48702e
MS
1415uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx)
1416{
1417 DPLANE_CTX_VALID(ctx);
1418 return ctx->u.rinfo.zd_nhg_id;
1419}
1420
25779064
MS
1421const struct nexthop_group *dplane_ctx_get_ng(
1422 const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1423{
1424 DPLANE_CTX_VALID(ctx);
1425
0f461727 1426 return &(ctx->u.rinfo.zd_ng);
7cdb1a84
MS
1427}
1428
1d48702e
MS
1429const struct nexthop_group *
1430dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx)
1431{
1432 DPLANE_CTX_VALID(ctx);
1433
1434 return &(ctx->u.rinfo.backup_ng);
1435}
1436
1437const struct nexthop_group *
1438dplane_ctx_get_old_ng(const struct zebra_dplane_ctx *ctx)
01ce7cba
MS
1439{
1440 DPLANE_CTX_VALID(ctx);
1441
0f461727 1442 return &(ctx->u.rinfo.zd_old_ng);
01ce7cba
MS
1443}
1444
1d48702e
MS
1445const struct nexthop_group *
1446dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx)
1447{
1448 DPLANE_CTX_VALID(ctx);
1449
1450 return &(ctx->u.rinfo.old_backup_ng);
1451}
1452
25779064
MS
1453const struct zebra_dplane_info *dplane_ctx_get_ns(
1454 const struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
1455{
1456 DPLANE_CTX_VALID(ctx);
1457
5709131c 1458 return &(ctx->zd_ns_info);
7cdb1a84
MS
1459}
1460
f820d025 1461/* Accessors for nexthop information */
0c8215cb
SW
1462uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx)
1463{
1464 DPLANE_CTX_VALID(ctx);
1465 return ctx->u.rinfo.nhe.id;
1466}
1467
df3cef24
DS
1468uint32_t dplane_ctx_get_old_nhe_id(const struct zebra_dplane_ctx *ctx)
1469{
1470 DPLANE_CTX_VALID(ctx);
1471 return ctx->u.rinfo.nhe.old_id;
1472}
1473
0c8215cb
SW
1474afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx)
1475{
1476 DPLANE_CTX_VALID(ctx);
1477 return ctx->u.rinfo.nhe.afi;
1478}
1479
1480vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx)
f820d025
SW
1481{
1482 DPLANE_CTX_VALID(ctx);
0c8215cb
SW
1483 return ctx->u.rinfo.nhe.vrf_id;
1484}
1485
38e40db1 1486int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx)
0c8215cb
SW
1487{
1488 DPLANE_CTX_VALID(ctx);
38e40db1 1489 return ctx->u.rinfo.nhe.type;
0c8215cb
SW
1490}
1491
1492const struct nexthop_group *
1493dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx)
1494{
1495 DPLANE_CTX_VALID(ctx);
1496 return &(ctx->u.rinfo.nhe.ng);
1497}
1498
e22e8001
SW
1499const struct nh_grp *
1500dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx)
0c8215cb
SW
1501{
1502 DPLANE_CTX_VALID(ctx);
e22e8001 1503 return ctx->u.rinfo.nhe.nh_grp;
0c8215cb
SW
1504}
1505
e22e8001 1506uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx)
0c8215cb
SW
1507{
1508 DPLANE_CTX_VALID(ctx);
e22e8001 1509 return ctx->u.rinfo.nhe.nh_grp_count;
f820d025
SW
1510}
1511
0f461727
MS
1512/* Accessors for LSP information */
1513
1514mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx)
1515{
1516 DPLANE_CTX_VALID(ctx);
1517
1518 return ctx->u.lsp.ile.in_label;
1519}
1520
3ab54059
MS
1521void dplane_ctx_set_in_label(struct zebra_dplane_ctx *ctx, mpls_label_t label)
1522{
1523 DPLANE_CTX_VALID(ctx);
1524
1525 ctx->u.lsp.ile.in_label = label;
1526}
1527
0f461727
MS
1528uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx)
1529{
1530 DPLANE_CTX_VALID(ctx);
1531
1532 return ctx->u.lsp.addr_family;
1533}
1534
3ab54059
MS
1535void dplane_ctx_set_addr_family(struct zebra_dplane_ctx *ctx,
1536 uint8_t family)
1537{
1538 DPLANE_CTX_VALID(ctx);
1539
1540 ctx->u.lsp.addr_family = family;
1541}
1542
0f461727
MS
1543uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx)
1544{
1545 DPLANE_CTX_VALID(ctx);
1546
1547 return ctx->u.lsp.flags;
1548}
1549
3ab54059
MS
1550void dplane_ctx_set_lsp_flags(struct zebra_dplane_ctx *ctx,
1551 uint32_t flags)
1552{
1553 DPLANE_CTX_VALID(ctx);
1554
1555 ctx->u.lsp.flags = flags;
1556}
1557
ee70f629
MS
1558const struct nhlfe_list_head *dplane_ctx_get_nhlfe_list(
1559 const struct zebra_dplane_ctx *ctx)
0f461727
MS
1560{
1561 DPLANE_CTX_VALID(ctx);
ee70f629 1562 return &(ctx->u.lsp.nhlfe_list);
0f461727
MS
1563}
1564
cd4bb96f
MS
1565const struct nhlfe_list_head *dplane_ctx_get_backup_nhlfe_list(
1566 const struct zebra_dplane_ctx *ctx)
1567{
1568 DPLANE_CTX_VALID(ctx);
1569 return &(ctx->u.lsp.backup_nhlfe_list);
1570}
1571
f2595bd5
DS
1572struct zebra_nhlfe *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
1573 enum lsp_types_t lsp_type,
1574 enum nexthop_types_t nh_type,
1575 const union g_addr *gate,
1576 ifindex_t ifindex, uint8_t num_labels,
1577 mpls_label_t *out_labels)
3ab54059 1578{
f2595bd5 1579 struct zebra_nhlfe *nhlfe;
3ab54059
MS
1580
1581 DPLANE_CTX_VALID(ctx);
1582
1583 nhlfe = zebra_mpls_lsp_add_nhlfe(&(ctx->u.lsp),
1584 lsp_type, nh_type, gate,
5065db0a 1585 ifindex, num_labels, out_labels);
3ab54059
MS
1586
1587 return nhlfe;
1588}
1589
f2595bd5
DS
1590struct zebra_nhlfe *dplane_ctx_add_backup_nhlfe(
1591 struct zebra_dplane_ctx *ctx, enum lsp_types_t lsp_type,
1592 enum nexthop_types_t nh_type, const union g_addr *gate,
1593 ifindex_t ifindex, uint8_t num_labels, mpls_label_t *out_labels)
cd4bb96f 1594{
f2595bd5 1595 struct zebra_nhlfe *nhlfe;
cd4bb96f
MS
1596
1597 DPLANE_CTX_VALID(ctx);
1598
1599 nhlfe = zebra_mpls_lsp_add_backup_nhlfe(&(ctx->u.lsp),
1600 lsp_type, nh_type, gate,
1601 ifindex, num_labels,
1602 out_labels);
1603
1604 return nhlfe;
1605}
1606
f2595bd5 1607const struct zebra_nhlfe *
81793ac1 1608dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx)
0f461727
MS
1609{
1610 DPLANE_CTX_VALID(ctx);
1611
1612 return ctx->u.lsp.best_nhlfe;
1613}
1614
f2595bd5 1615const struct zebra_nhlfe *
3ab54059 1616dplane_ctx_set_best_nhlfe(struct zebra_dplane_ctx *ctx,
f2595bd5 1617 struct zebra_nhlfe *nhlfe)
3ab54059
MS
1618{
1619 DPLANE_CTX_VALID(ctx);
1620
1621 ctx->u.lsp.best_nhlfe = nhlfe;
1622 return ctx->u.lsp.best_nhlfe;
1623}
1624
0f461727
MS
1625uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx)
1626{
1627 DPLANE_CTX_VALID(ctx);
1628
1629 return ctx->u.lsp.num_ecmp;
1630}
1631
d613b8e1
MS
1632mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx)
1633{
1634 DPLANE_CTX_VALID(ctx);
1635
1636 return ctx->u.pw.local_label;
1637}
1638
1639mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx)
1640{
1641 DPLANE_CTX_VALID(ctx);
1642
1643 return ctx->u.pw.remote_label;
1644}
1645
1646int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx)
1647{
1648 DPLANE_CTX_VALID(ctx);
1649
1650 return ctx->u.pw.type;
1651}
1652
1653int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx)
1654{
1655 DPLANE_CTX_VALID(ctx);
1656
1657 return ctx->u.pw.af;
1658}
1659
1660uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx)
1661{
1662 DPLANE_CTX_VALID(ctx);
1663
1664 return ctx->u.pw.flags;
1665}
1666
1667int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx)
1668{
1669 DPLANE_CTX_VALID(ctx);
1670
1671 return ctx->u.pw.status;
1672}
1673
fd563cc7
KS
1674void dplane_ctx_set_pw_status(struct zebra_dplane_ctx *ctx, int status)
1675{
1676 DPLANE_CTX_VALID(ctx);
1677
1678 ctx->u.pw.status = status;
1679}
1680
16d69787 1681const union g_addr *dplane_ctx_get_pw_dest(
d613b8e1
MS
1682 const struct zebra_dplane_ctx *ctx)
1683{
1684 DPLANE_CTX_VALID(ctx);
1685
16d69787 1686 return &(ctx->u.pw.dest);
d613b8e1
MS
1687}
1688
1689const union pw_protocol_fields *dplane_ctx_get_pw_proto(
1690 const struct zebra_dplane_ctx *ctx)
1691{
1692 DPLANE_CTX_VALID(ctx);
1693
1694 return &(ctx->u.pw.fields);
1695}
1696
09cd307c
MS
1697const struct nexthop_group *
1698dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx)
1699{
1700 DPLANE_CTX_VALID(ctx);
1701
072b487b
MS
1702 return &(ctx->u.pw.fib_nhg);
1703}
1704
1705const struct nexthop_group *
1706dplane_ctx_get_pw_primary_nhg(const struct zebra_dplane_ctx *ctx)
1707{
1708 DPLANE_CTX_VALID(ctx);
1709
1710 return &(ctx->u.pw.primary_nhg);
1711}
1712
1713const struct nexthop_group *
1714dplane_ctx_get_pw_backup_nhg(const struct zebra_dplane_ctx *ctx)
1715{
1716 DPLANE_CTX_VALID(ctx);
1717
1718 return &(ctx->u.pw.backup_nhg);
09cd307c
MS
1719}
1720
a4a4802a 1721/* Accessors for interface information */
a4a4802a
MS
1722uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx)
1723{
1724 DPLANE_CTX_VALID(ctx);
1725
1726 return ctx->u.intf.metric;
1727}
1728
971bad84
MS
1729void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric)
1730{
1731 DPLANE_CTX_VALID(ctx);
1732
1733 ctx->u.intf.metric = metric;
1734}
1735
a4a4802a
MS
1736/* Is interface addr p2p? */
1737bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
1738{
1739 DPLANE_CTX_VALID(ctx);
1740
1741 return (ctx->u.intf.flags & DPLANE_INTF_CONNECTED);
1742}
1743
1744bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx)
1745{
1746 DPLANE_CTX_VALID(ctx);
1747
1748 return (ctx->u.intf.flags & DPLANE_INTF_SECONDARY);
1749}
1750
64168803
MS
1751bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx)
1752{
1753 DPLANE_CTX_VALID(ctx);
1754
1755 return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST);
1756}
1757
971bad84
MS
1758void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx)
1759{
1760 DPLANE_CTX_VALID(ctx);
1761
1762 ctx->u.intf.flags |= DPLANE_INTF_CONNECTED;
1763}
1764
1765void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx)
1766{
1767 DPLANE_CTX_VALID(ctx);
1768
1769 ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
1770}
1771
1772void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx)
1773{
1774 DPLANE_CTX_VALID(ctx);
1775
1776 ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
1777}
1778
a4a4802a
MS
1779const struct prefix *dplane_ctx_get_intf_addr(
1780 const struct zebra_dplane_ctx *ctx)
1781{
1782 DPLANE_CTX_VALID(ctx);
1783
1784 return &(ctx->u.intf.prefix);
1785}
1786
971bad84
MS
1787void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx,
1788 const struct prefix *p)
1789{
1790 DPLANE_CTX_VALID(ctx);
1791
1792 prefix_copy(&(ctx->u.intf.prefix), p);
1793}
1794
a4a4802a
MS
1795bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx)
1796{
1797 DPLANE_CTX_VALID(ctx);
1798
1799 return (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST);
1800}
1801
1802const struct prefix *dplane_ctx_get_intf_dest(
1803 const struct zebra_dplane_ctx *ctx)
1804{
1805 DPLANE_CTX_VALID(ctx);
1806
971bad84
MS
1807 return &(ctx->u.intf.dest_prefix);
1808}
1809
1810void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx,
1811 const struct prefix *p)
1812{
1813 DPLANE_CTX_VALID(ctx);
1814
1815 prefix_copy(&(ctx->u.intf.dest_prefix), p);
a4a4802a
MS
1816}
1817
1818bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx)
1819{
1820 DPLANE_CTX_VALID(ctx);
1821
1822 return (ctx->u.intf.flags & DPLANE_INTF_HAS_LABEL);
1823}
1824
1825const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx)
1826{
1827 DPLANE_CTX_VALID(ctx);
1828
1829 return ctx->u.intf.label;
1830}
1831
971bad84
MS
1832void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label)
1833{
1834 size_t len;
1835
1836 DPLANE_CTX_VALID(ctx);
1837
1838 if (ctx->u.intf.label && ctx->u.intf.label != ctx->u.intf.label_buf)
1839 free(ctx->u.intf.label);
1840
1841 ctx->u.intf.label = NULL;
1842
1843 if (label) {
1844 ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
1845
1846 /* Use embedded buffer if it's adequate; else allocate. */
1847 len = strlen(label);
1848
1849 if (len < sizeof(ctx->u.intf.label_buf)) {
1850 strlcpy(ctx->u.intf.label_buf, label,
1851 sizeof(ctx->u.intf.label_buf));
1852 ctx->u.intf.label = ctx->u.intf.label_buf;
1853 } else {
1854 ctx->u.intf.label = strdup(label);
1855 }
1856 } else {
1857 ctx->u.intf.flags &= ~DPLANE_INTF_HAS_LABEL;
1858 }
1859}
1860
7597ac7b
MS
1861/* Accessors for MAC information */
1862vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx)
1863{
1864 DPLANE_CTX_VALID(ctx);
1865 return ctx->u.macinfo.vid;
1866}
1867
1868bool dplane_ctx_mac_is_sticky(const struct zebra_dplane_ctx *ctx)
1869{
1870 DPLANE_CTX_VALID(ctx);
1871 return ctx->u.macinfo.is_sticky;
1872}
1873
506efd37
AK
1874uint32_t dplane_ctx_mac_get_nhg_id(const struct zebra_dplane_ctx *ctx)
1875{
1876 DPLANE_CTX_VALID(ctx);
1877 return ctx->u.macinfo.nhg_id;
1878}
1879
f188e68e
AK
1880uint32_t dplane_ctx_mac_get_update_flags(const struct zebra_dplane_ctx *ctx)
1881{
1882 DPLANE_CTX_VALID(ctx);
1883 return ctx->u.macinfo.update_flags;
1884}
1885
7597ac7b
MS
1886const struct ethaddr *dplane_ctx_mac_get_addr(
1887 const struct zebra_dplane_ctx *ctx)
1888{
1889 DPLANE_CTX_VALID(ctx);
1890 return &(ctx->u.macinfo.mac);
1891}
1892
1893const struct in_addr *dplane_ctx_mac_get_vtep_ip(
1894 const struct zebra_dplane_ctx *ctx)
1895{
1896 DPLANE_CTX_VALID(ctx);
1897 return &(ctx->u.macinfo.vtep_ip);
1898}
1899
478566d6
MS
1900ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx)
1901{
1902 DPLANE_CTX_VALID(ctx);
1903 return ctx->u.macinfo.br_ifindex;
1904}
1905
931fa60c
MS
1906/* Accessors for neighbor information */
1907const struct ipaddr *dplane_ctx_neigh_get_ipaddr(
1908 const struct zebra_dplane_ctx *ctx)
1909{
1910 DPLANE_CTX_VALID(ctx);
1911 return &(ctx->u.neigh.ip_addr);
1912}
1913
0a27a2fe
PG
1914const struct ipaddr *
1915dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx)
1916{
1917 DPLANE_CTX_VALID(ctx);
1918 return &(ctx->u.neigh.link.ip_addr);
1919}
1920
931fa60c
MS
1921const struct ethaddr *dplane_ctx_neigh_get_mac(
1922 const struct zebra_dplane_ctx *ctx)
1923{
1924 DPLANE_CTX_VALID(ctx);
0a27a2fe 1925 return &(ctx->u.neigh.link.mac);
931fa60c
MS
1926}
1927
1928uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx)
1929{
1930 DPLANE_CTX_VALID(ctx);
1931 return ctx->u.neigh.flags;
1932}
1933
1934uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx)
1935{
1936 DPLANE_CTX_VALID(ctx);
1937 return ctx->u.neigh.state;
1938}
1939
f188e68e
AK
1940uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx)
1941{
1942 DPLANE_CTX_VALID(ctx);
1943 return ctx->u.neigh.update_flags;
1944}
1945
62b4b7e4
PG
1946/* Accessor for GRE set */
1947uint32_t
1948dplane_ctx_gre_get_link_ifindex(const struct zebra_dplane_ctx *ctx)
1949{
1950 DPLANE_CTX_VALID(ctx);
1951
1952 return ctx->u.gre.link_ifindex;
1953}
1954
db51f0cd
PG
1955unsigned int
1956dplane_ctx_gre_get_mtu(const struct zebra_dplane_ctx *ctx)
1957{
1958 DPLANE_CTX_VALID(ctx);
1959
1960 return ctx->u.gre.mtu;
1961}
1962
e3d3fa06
PG
1963const struct zebra_l2info_gre *
1964dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx)
1965{
1966 DPLANE_CTX_VALID(ctx);
1967
1968 return &ctx->u.gre.info;
1969}
1970
60d8d43b
JU
1971/* Accessors for PBR rule information */
1972int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx)
1973{
1974 DPLANE_CTX_VALID(ctx);
1975
1976 return ctx->u.rule.sock;
1977}
1978
58a1d249
DS
1979const char *dplane_ctx_rule_get_ifname(const struct zebra_dplane_ctx *ctx)
1980{
1981 DPLANE_CTX_VALID(ctx);
1982
1983 return ctx->u.rule.new.ifname;
1984}
1985
60d8d43b
JU
1986int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx)
1987{
1988 DPLANE_CTX_VALID(ctx);
1989
1990 return ctx->u.rule.unique;
1991}
1992
1993int dplane_ctx_rule_get_seq(const struct zebra_dplane_ctx *ctx)
1994{
1995 DPLANE_CTX_VALID(ctx);
1996
1997 return ctx->u.rule.seq;
1998}
1999
2000uint32_t dplane_ctx_rule_get_priority(const struct zebra_dplane_ctx *ctx)
2001{
2002 DPLANE_CTX_VALID(ctx);
2003
2004 return ctx->u.rule.new.priority;
2005}
2006
2007uint32_t dplane_ctx_rule_get_old_priority(const struct zebra_dplane_ctx *ctx)
2008{
2009 DPLANE_CTX_VALID(ctx);
2010
2011 return ctx->u.rule.old.priority;
2012}
2013
2014uint32_t dplane_ctx_rule_get_table(const struct zebra_dplane_ctx *ctx)
2015{
2016 DPLANE_CTX_VALID(ctx);
2017
2018 return ctx->u.rule.new.table;
2019}
2020
2021uint32_t dplane_ctx_rule_get_old_table(const struct zebra_dplane_ctx *ctx)
2022{
2023 DPLANE_CTX_VALID(ctx);
2024
2025 return ctx->u.rule.old.table;
2026}
2027
2028uint32_t dplane_ctx_rule_get_filter_bm(const struct zebra_dplane_ctx *ctx)
2029{
2030 DPLANE_CTX_VALID(ctx);
2031
2032 return ctx->u.rule.new.filter_bm;
2033}
2034
2035uint32_t dplane_ctx_rule_get_old_filter_bm(const struct zebra_dplane_ctx *ctx)
2036{
2037 DPLANE_CTX_VALID(ctx);
2038
2039 return ctx->u.rule.old.filter_bm;
2040}
2041
2042uint32_t dplane_ctx_rule_get_fwmark(const struct zebra_dplane_ctx *ctx)
2043{
2044 DPLANE_CTX_VALID(ctx);
2045
2046 return ctx->u.rule.new.fwmark;
2047}
2048
2049uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx)
2050{
2051 DPLANE_CTX_VALID(ctx);
2052
2053 return ctx->u.rule.old.fwmark;
2054}
2055
8ccbc778
DS
2056uint8_t dplane_ctx_rule_get_ipproto(const struct zebra_dplane_ctx *ctx)
2057{
2058 DPLANE_CTX_VALID(ctx);
2059
2060 return ctx->u.rule.new.ip_proto;
2061}
2062
2063uint8_t dplane_ctx_rule_get_old_ipproto(const struct zebra_dplane_ctx *ctx)
2064{
2065 DPLANE_CTX_VALID(ctx);
2066
2067 return ctx->u.rule.old.ip_proto;
2068}
2069
01f23aff
WC
2070uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx)
2071{
2072 DPLANE_CTX_VALID(ctx);
2073
2074 return ctx->u.rule.new.dsfield;
2075}
2076
2077uint8_t dplane_ctx_rule_get_old_dsfield(const struct zebra_dplane_ctx *ctx)
2078{
2079 DPLANE_CTX_VALID(ctx);
2080
2081 return ctx->u.rule.old.dsfield;
2082}
2083
60d8d43b
JU
2084const struct prefix *
2085dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx)
2086{
2087 DPLANE_CTX_VALID(ctx);
2088
2089 return &(ctx->u.rule.new.src_ip);
2090}
2091
2092const struct prefix *
2093dplane_ctx_rule_get_old_src_ip(const struct zebra_dplane_ctx *ctx)
2094{
2095 DPLANE_CTX_VALID(ctx);
2096
2097 return &(ctx->u.rule.old.src_ip);
2098}
2099
2100const struct prefix *
2101dplane_ctx_rule_get_dst_ip(const struct zebra_dplane_ctx *ctx)
2102{
2103 DPLANE_CTX_VALID(ctx);
2104
2105 return &(ctx->u.rule.new.dst_ip);
2106}
2107
2108const struct prefix *
2109dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx)
2110{
2111 DPLANE_CTX_VALID(ctx);
2112
2113 return &(ctx->u.rule.old.dst_ip);
2114}
2115
c60522f7
AK
2116uint32_t dplane_ctx_get_br_port_flags(const struct zebra_dplane_ctx *ctx)
2117{
2118 DPLANE_CTX_VALID(ctx);
2119
2120 return ctx->u.br_port.flags;
2121}
2122
2123uint32_t
2124dplane_ctx_get_br_port_sph_filter_cnt(const struct zebra_dplane_ctx *ctx)
2125{
2126 DPLANE_CTX_VALID(ctx);
2127
2128 return ctx->u.br_port.sph_filter_cnt;
2129}
2130
2131const struct in_addr *
2132dplane_ctx_get_br_port_sph_filters(const struct zebra_dplane_ctx *ctx)
2133{
2134 DPLANE_CTX_VALID(ctx);
2135
2136 return ctx->u.br_port.sph_filters;
2137}
2138
2139uint32_t
2140dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx)
2141{
2142 DPLANE_CTX_VALID(ctx);
2143
2144 return ctx->u.br_port.backup_nhg_id;
2145}
2146
5162e000
PG
2147/* Accessors for PBR iptable information */
2148bool
2149dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx,
2150 struct zebra_pbr_iptable *table)
2151{
2152 DPLANE_CTX_VALID(ctx);
2153
2154 memcpy(table, &ctx->u.iptable, sizeof(struct zebra_pbr_iptable));
2155 return true;
2156}
2157
ef524230
PG
2158bool dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx,
2159 struct zebra_pbr_ipset *ipset)
2160{
2161 DPLANE_CTX_VALID(ctx);
2162
2163 if (!ipset)
2164 return false;
2165 if (ctx->zd_op == DPLANE_OP_IPSET_ENTRY_ADD ||
2166 ctx->zd_op == DPLANE_OP_IPSET_ENTRY_DELETE) {
2167 memset(ipset, 0, sizeof(struct zebra_pbr_ipset));
2168 ipset->type = ctx->u.ipset_entry.info.type;
2169 memcpy(&ipset->ipset_name, &ctx->u.ipset_entry.info.ipset_name,
2170 ZEBRA_IPSET_NAME_SIZE);
2171 } else
2172 memcpy(ipset, &ctx->u.ipset, sizeof(struct zebra_pbr_ipset));
2173 return true;
2174}
2175
2176bool dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx,
2177 struct zebra_pbr_ipset_entry *entry)
2178{
2179 DPLANE_CTX_VALID(ctx);
2180
2181 if (!entry)
2182 return false;
2183 memcpy(entry, &ctx->u.ipset_entry.entry, sizeof(struct zebra_pbr_ipset_entry));
2184 return true;
2185}
2186
7cdb1a84
MS
2187/*
2188 * End of dplane context accessors
2189 */
2190
5917df09
MS
2191/* Optional extra info about interfaces in nexthops - a plugin must enable
2192 * this extra info.
2193 */
2194const struct dplane_intf_extra *
2195dplane_ctx_get_intf_extra(const struct zebra_dplane_ctx *ctx)
2196{
2197 return TAILQ_FIRST(&ctx->u.rinfo.intf_extra_q);
2198}
2199
2200const struct dplane_intf_extra *
2201dplane_ctx_intf_extra_next(const struct zebra_dplane_ctx *ctx,
2202 const struct dplane_intf_extra *ptr)
2203{
2204 return TAILQ_NEXT(ptr, link);
2205}
2206
2207vrf_id_t dplane_intf_extra_get_vrfid(const struct dplane_intf_extra *ptr)
2208{
2209 return ptr->vrf_id;
2210}
2211
2212uint32_t dplane_intf_extra_get_ifindex(const struct dplane_intf_extra *ptr)
2213{
2214 return ptr->ifindex;
2215}
2216
2217uint32_t dplane_intf_extra_get_flags(const struct dplane_intf_extra *ptr)
2218{
2219 return ptr->flags;
2220}
2221
2222uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr)
2223{
2224 return ptr->status;
2225}
2226
e18747a9
PG
2227uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx)
2228{
2229 DPLANE_CTX_VALID(ctx);
2230
2231 return ctx->u.neightable.family;
2232}
2233
2234uint32_t
2235dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx)
2236{
2237 DPLANE_CTX_VALID(ctx);
2238
2239 return ctx->u.neightable.app_probes;
2240}
2241
2242uint32_t
2243dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx)
2244{
2245 DPLANE_CTX_VALID(ctx);
2246
2247 return ctx->u.neightable.ucast_probes;
2248}
2249
2250uint32_t
2251dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx)
2252{
2253 DPLANE_CTX_VALID(ctx);
2254
2255 return ctx->u.neightable.mcast_probes;
2256}
2257
5917df09
MS
2258/*
2259 * End of interface extra info accessors
2260 */
c831033f 2261
91f16812
MS
2262/*
2263 * Retrieve the limit on the number of pending, unprocessed updates.
2264 */
2265uint32_t dplane_get_in_queue_limit(void)
2266{
2267 return atomic_load_explicit(&zdplane_info.dg_max_queued_updates,
2268 memory_order_relaxed);
2269}
2270
2271/*
2272 * Configure limit on the number of pending, queued updates.
2273 */
2274void dplane_set_in_queue_limit(uint32_t limit, bool set)
2275{
2276 /* Reset to default on 'unset' */
2277 if (!set)
2278 limit = DPLANE_DEFAULT_MAX_QUEUED;
2279
2280 atomic_store_explicit(&zdplane_info.dg_max_queued_updates, limit,
2281 memory_order_relaxed);
2282}
2283
2284/*
2285 * Retrieve the current queue depth of incoming, unprocessed updates
2286 */
2287uint32_t dplane_get_in_queue_len(void)
2288{
2289 return atomic_load_explicit(&zdplane_info.dg_routes_queued,
2290 memory_order_seq_cst);
2291}
2292
16c628de
MS
2293/*
2294 * Common dataplane context init with zebra namespace info.
2295 */
2296static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
2297 struct zebra_ns *zns,
2298 bool is_update)
2299{
2300 dplane_info_from_zns(&(ctx->zd_ns_info), zns);
2301
2302#if defined(HAVE_NETLINK)
2303 /* Increment message counter after copying to context struct - may need
2304 * two messages in some 'update' cases.
2305 */
2306 if (is_update)
80dcc388 2307 zns->netlink_dplane_out.seq += 2;
16c628de 2308 else
80dcc388 2309 zns->netlink_dplane_out.seq++;
16c628de
MS
2310#endif /* HAVE_NETLINK */
2311
2312 return AOK;
2313}
2314
7cdb1a84
MS
2315/*
2316 * Initialize a context block for a route update from zebra data structs.
2317 */
018e77bc
RZ
2318int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
2319 struct route_node *rn, struct route_entry *re)
7cdb1a84
MS
2320{
2321 int ret = EINVAL;
2322 const struct route_table *table = NULL;
630d5962 2323 const struct rib_table_info *info;
7cdb1a84
MS
2324 const struct prefix *p, *src_p;
2325 struct zebra_ns *zns;
2326 struct zebra_vrf *zvrf;
f183e380 2327 struct nexthop *nexthop;
05843a27 2328 struct zebra_l3vni *zl3vni;
5917df09
MS
2329 const struct interface *ifp;
2330 struct dplane_intf_extra *if_extra;
7cdb1a84 2331
5709131c 2332 if (!ctx || !rn || !re)
7cdb1a84 2333 goto done;
7cdb1a84 2334
5917df09
MS
2335 TAILQ_INIT(&ctx->u.rinfo.intf_extra_q);
2336
7cdb1a84 2337 ctx->zd_op = op;
14b0bc8e 2338 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
7cdb1a84 2339
0f461727
MS
2340 ctx->u.rinfo.zd_type = re->type;
2341 ctx->u.rinfo.zd_old_type = re->type;
7cdb1a84
MS
2342
2343 /* Prefixes: dest, and optional source */
2344 srcdest_rnode_prefixes(rn, &p, &src_p);
2345
0f461727 2346 prefix_copy(&(ctx->u.rinfo.zd_dest), p);
7cdb1a84 2347
5709131c 2348 if (src_p)
0f461727 2349 prefix_copy(&(ctx->u.rinfo.zd_src), src_p);
5709131c 2350 else
0f461727 2351 memset(&(ctx->u.rinfo.zd_src), 0, sizeof(ctx->u.rinfo.zd_src));
7cdb1a84
MS
2352
2353 ctx->zd_table_id = re->table;
2354
0f461727
MS
2355 ctx->u.rinfo.zd_metric = re->metric;
2356 ctx->u.rinfo.zd_old_metric = re->metric;
7cdb1a84 2357 ctx->zd_vrf_id = re->vrf_id;
0f461727
MS
2358 ctx->u.rinfo.zd_mtu = re->mtu;
2359 ctx->u.rinfo.zd_nexthop_mtu = re->nexthop_mtu;
2360 ctx->u.rinfo.zd_instance = re->instance;
2361 ctx->u.rinfo.zd_tag = re->tag;
2362 ctx->u.rinfo.zd_old_tag = re->tag;
2363 ctx->u.rinfo.zd_distance = re->distance;
7cdb1a84
MS
2364
2365 table = srcdest_rnode_table(rn);
2366 info = table->info;
2367
0f461727
MS
2368 ctx->u.rinfo.zd_afi = info->afi;
2369 ctx->u.rinfo.zd_safi = info->safi;
7cdb1a84 2370
7cdb1a84 2371 /* Copy nexthops; recursive info is included too */
0eb97b86 2372 copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop),
c415d895 2373 re->nhe->nhg.nexthop, NULL);
1d48702e
MS
2374 ctx->u.rinfo.zd_nhg_id = re->nhe->id;
2375
2376 /* Copy backup nexthop info, if present */
2377 if (re->nhe->backup_info && re->nhe->backup_info->nhe) {
2378 copy_nexthops(&(ctx->u.rinfo.backup_ng.nexthop),
2379 re->nhe->backup_info->nhe->nhg.nexthop, NULL);
2380 }
7cdb1a84 2381
f2a0ba3a
RZ
2382 /*
2383 * Ensure that the dplane nexthops' flags are clear and copy
2384 * encapsulation information.
2385 */
2386 for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) {
f183e380 2387 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
f183e380 2388
5917df09
MS
2389 /* Optionally capture extra interface info while we're in the
2390 * main zebra pthread - a plugin has to ask for this info.
2391 */
2392 if (dplane_collect_extra_intf_info) {
2393 ifp = if_lookup_by_index(nexthop->ifindex,
2394 nexthop->vrf_id);
2395
2396 if (ifp) {
2397 if_extra = XCALLOC(
2398 MTYPE_DP_INTF,
2399 sizeof(struct dplane_intf_extra));
2400 if_extra->vrf_id = nexthop->vrf_id;
2401 if_extra->ifindex = nexthop->ifindex;
2402 if_extra->flags = ifp->flags;
2403 if_extra->status = ifp->status;
2404
2405 TAILQ_INSERT_TAIL(&ctx->u.rinfo.intf_extra_q,
2406 if_extra, link);
2407 }
2408 }
b364e87d
MS
2409
2410 /* Check for available evpn encapsulations. */
2411 if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
2412 continue;
2413
2414 zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
2415 if (zl3vni && is_l3vni_oper_up(zl3vni)) {
2416 nexthop->nh_encap_type = NET_VXLAN;
2417 nexthop->nh_encap.vni = zl3vni->vni;
2418 }
f2a0ba3a
RZ
2419 }
2420
cf363e1b
MS
2421 /* Don't need some info when capturing a system notification */
2422 if (op == DPLANE_OP_SYS_ROUTE_ADD ||
2423 op == DPLANE_OP_SYS_ROUTE_DELETE) {
2424 ret = AOK;
2425 goto done;
2426 }
2427
2428 /* Extract ns info - can't use pointers to 'core' structs */
2429 zvrf = vrf_info_lookup(re->vrf_id);
2430 zns = zvrf->zns;
2431 dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
2432
6df59152 2433#ifdef HAVE_NETLINK
f924db49 2434 {
1d48702e 2435 struct nhg_hash_entry *nhe = zebra_nhg_resolve(re->nhe);
6df59152 2436
ae9bfa06 2437 ctx->u.rinfo.nhe.id = nhe->id;
df3cef24 2438 ctx->u.rinfo.nhe.old_id = 0;
6df59152 2439 /*
ae9bfa06
SW
2440 * Check if the nhe is installed/queued before doing anything
2441 * with this route.
08c51a38
SW
2442 *
2443 * If its a delete we only use the prefix anyway, so this only
2444 * matters for INSTALL/UPDATE.
6df59152 2445 */
1a39fdc2
DS
2446 if (zebra_nhg_kernel_nexthops_enabled()
2447 && (((op == DPLANE_OP_ROUTE_INSTALL)
2448 || (op == DPLANE_OP_ROUTE_UPDATE))
2449 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
2450 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED))) {
6df59152
SW
2451 ret = ENOENT;
2452 goto done;
2453 }
98cda54a 2454 }
6df59152 2455#endif /* HAVE_NETLINK */
de3f5488 2456
7cdb1a84
MS
2457 /* Trying out the sequence number idea, so we can try to detect
2458 * when a result is stale.
2459 */
1485bbe7 2460 re->dplane_sequence = zebra_router_get_next_sequence();
7cdb1a84
MS
2461 ctx->zd_seq = re->dplane_sequence;
2462
2463 ret = AOK;
2464
2465done:
2466 return ret;
2467}
2468
f820d025
SW
2469/**
2470 * dplane_ctx_nexthop_init() - Initialize a context block for a nexthop update
2471 *
2472 * @ctx: Dataplane context to init
2473 * @op: Operation being performed
2474 * @nhe: Nexthop group hash entry
2475 *
2476 * Return: Result status
2477 */
a2072e71 2478int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
981ca597 2479 struct nhg_hash_entry *nhe)
f820d025 2480{
a7df21c4 2481 struct zebra_vrf *zvrf = NULL;
8e401b25 2482 struct zebra_ns *zns = NULL;
f820d025
SW
2483 int ret = EINVAL;
2484
2485 if (!ctx || !nhe)
2486 goto done;
2487
2488 ctx->zd_op = op;
2489 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2490
2491 /* Copy over nhe info */
0c8215cb
SW
2492 ctx->u.rinfo.nhe.id = nhe->id;
2493 ctx->u.rinfo.nhe.afi = nhe->afi;
2494 ctx->u.rinfo.nhe.vrf_id = nhe->vrf_id;
38e40db1 2495 ctx->u.rinfo.nhe.type = nhe->type;
0c8215cb 2496
c415d895 2497 nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), &(nhe->nhg));
0c8215cb 2498
c415d895 2499 /* If this is a group, convert it to a grp array of ids */
98cda54a
SW
2500 if (!zebra_nhg_depends_is_empty(nhe)
2501 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE))
8dbc800f
SW
2502 ctx->u.rinfo.nhe.nh_grp_count = zebra_nhg_nhe2grp(
2503 ctx->u.rinfo.nhe.nh_grp, nhe, MULTIPATH_NUM);
f820d025 2504
a7df21c4
SW
2505 zvrf = vrf_info_lookup(nhe->vrf_id);
2506
2507 /*
2508 * Fallback to default namespace if the vrf got ripped out from under
2509 * us.
2510 */
2511 zns = zvrf ? zvrf->zns : zebra_ns_lookup(NS_DEFAULT);
1909e63a 2512
2d3c57e6
SW
2513 /*
2514 * TODO: Might not need to mark this as an update, since
2515 * it probably won't require two messages
2516 */
1909e63a 2517 dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE));
f6feb48b 2518 ctx->zd_is_update = (op == DPLANE_OP_NH_UPDATE);
1909e63a 2519
f820d025
SW
2520 ret = AOK;
2521
2522done:
2523 return ret;
2524}
2525
16c628de
MS
2526/*
2527 * Capture information for an LSP update in a dplane context.
2528 */
65f264cf 2529int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
8f74a383 2530 struct zebra_lsp *lsp)
16c628de
MS
2531{
2532 int ret = AOK;
f2595bd5 2533 struct zebra_nhlfe *nhlfe, *new_nhlfe;
16c628de 2534
16c628de
MS
2535 ctx->zd_op = op;
2536 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2537
2538 /* Capture namespace info */
2539 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
2540 (op == DPLANE_OP_LSP_UPDATE));
f6feb48b 2541 ctx->zd_is_update = (op == DPLANE_OP_LSP_UPDATE);
16c628de
MS
2542
2543 memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp));
2544
ee70f629 2545 nhlfe_list_init(&(ctx->u.lsp.nhlfe_list));
cd4bb96f 2546 nhlfe_list_init(&(ctx->u.lsp.backup_nhlfe_list));
65f264cf
MS
2547
2548 /* This may be called to create/init a dplane context, not necessarily
2549 * to copy an lsp object.
2550 */
2551 if (lsp == NULL) {
2552 ret = AOK;
2553 goto done;
2554 }
2555
2556 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
2557 zlog_debug("init dplane ctx %s: in-label %u ecmp# %d",
2558 dplane_op2str(op), lsp->ile.in_label,
2559 lsp->num_ecmp);
2560
16c628de
MS
2561 ctx->u.lsp.ile = lsp->ile;
2562 ctx->u.lsp.addr_family = lsp->addr_family;
2563 ctx->u.lsp.num_ecmp = lsp->num_ecmp;
2564 ctx->u.lsp.flags = lsp->flags;
2565
2566 /* Copy source LSP's nhlfes, and capture 'best' nhlfe */
ee70f629 2567 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
16c628de
MS
2568 /* Not sure if this is meaningful... */
2569 if (nhlfe->nexthop == NULL)
2570 continue;
2571
cd4bb96f
MS
2572 new_nhlfe = zebra_mpls_lsp_add_nh(&(ctx->u.lsp), nhlfe->type,
2573 nhlfe->nexthop);
16c628de
MS
2574 if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) {
2575 ret = ENOMEM;
2576 break;
2577 }
2578
3c0e1622 2579 /* Need to copy flags and backup info too */
16c628de
MS
2580 new_nhlfe->flags = nhlfe->flags;
2581 new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
2582
3c0e1622
MS
2583 if (CHECK_FLAG(new_nhlfe->nexthop->flags,
2584 NEXTHOP_FLAG_HAS_BACKUP)) {
2585 new_nhlfe->nexthop->backup_num =
2586 nhlfe->nexthop->backup_num;
2587 memcpy(new_nhlfe->nexthop->backup_idx,
2588 nhlfe->nexthop->backup_idx,
2589 new_nhlfe->nexthop->backup_num);
2590 }
2591
16c628de
MS
2592 if (nhlfe == lsp->best_nhlfe)
2593 ctx->u.lsp.best_nhlfe = new_nhlfe;
2594 }
2595
cd4bb96f
MS
2596 if (ret != AOK)
2597 goto done;
2598
2599 /* Capture backup nhlfes/nexthops */
2600 frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
2601 /* Not sure if this is meaningful... */
2602 if (nhlfe->nexthop == NULL)
2603 continue;
2604
2605 new_nhlfe = zebra_mpls_lsp_add_backup_nh(&(ctx->u.lsp),
2606 nhlfe->type,
2607 nhlfe->nexthop);
2608 if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) {
2609 ret = ENOMEM;
2610 break;
2611 }
2612
2613 /* Need to copy flags too */
2614 new_nhlfe->flags = nhlfe->flags;
2615 new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
2616 }
2617
16c628de
MS
2618 /* On error the ctx will be cleaned-up, so we don't need to
2619 * deal with any allocated nhlfe or nexthop structs here.
2620 */
cd4bb96f 2621done:
16c628de
MS
2622
2623 return ret;
2624}
2625
97d8d05a
MS
2626/*
2627 * Capture information for an LSP update in a dplane context.
2628 */
2629static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
2630 enum dplane_op_e op,
2631 struct zebra_pw *pw)
2632{
072b487b 2633 int ret = EINVAL;
09cd307c
MS
2634 struct prefix p;
2635 afi_t afi;
2636 struct route_table *table;
2637 struct route_node *rn;
2638 struct route_entry *re;
0024ea8e 2639 const struct nexthop_group *nhg;
072b487b 2640 struct nexthop *nh, *newnh, *last_nh;
09cd307c 2641
97d8d05a
MS
2642 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
2643 zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
2644 dplane_op2str(op), pw->ifname, pw->local_label,
2645 pw->remote_label);
2646
2647 ctx->zd_op = op;
2648 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2649
2650 /* Capture namespace info: no netlink support as of 12/18,
2651 * but just in case...
2652 */
2653 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
2654
2655 memset(&ctx->u.pw, 0, sizeof(ctx->u.pw));
2656
2657 /* This name appears to be c-string, so we use string copy. */
7c7ef4a8 2658 strlcpy(ctx->zd_ifname, pw->ifname, sizeof(ctx->zd_ifname));
16d69787 2659
9bd9717b 2660 ctx->zd_vrf_id = pw->vrf_id;
7c7ef4a8 2661 ctx->zd_ifindex = pw->ifindex;
97d8d05a
MS
2662 ctx->u.pw.type = pw->type;
2663 ctx->u.pw.af = pw->af;
2664 ctx->u.pw.local_label = pw->local_label;
2665 ctx->u.pw.remote_label = pw->remote_label;
2666 ctx->u.pw.flags = pw->flags;
2667
16d69787 2668 ctx->u.pw.dest = pw->nexthop;
97d8d05a
MS
2669
2670 ctx->u.pw.fields = pw->data;
2671
09cd307c
MS
2672 /* Capture nexthop info for the pw destination. We need to look
2673 * up and use zebra datastructs, but we're running in the zebra
2674 * pthread here so that should be ok.
2675 */
2676 memcpy(&p.u, &pw->nexthop, sizeof(pw->nexthop));
2677 p.family = pw->af;
936fbaef 2678 p.prefixlen = ((pw->af == AF_INET) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN);
09cd307c
MS
2679
2680 afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6;
2681 table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id);
072b487b
MS
2682 if (table == NULL)
2683 goto done;
2684
2685 rn = route_node_match(table, &p);
2686 if (rn == NULL)
2687 goto done;
2688
2689 re = NULL;
2690 RNODE_FOREACH_RE(rn, re) {
2691 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
2692 break;
2693 }
2694
2695 if (re) {
2696 /* We'll capture a 'fib' list of nexthops that meet our
2697 * criteria: installed, and labelled.
2698 */
2699 nhg = rib_get_fib_nhg(re);
2700 last_nh = NULL;
2701
2702 if (nhg && nhg->nexthop) {
2703 for (ALL_NEXTHOPS_PTR(nhg, nh)) {
2704 if (!CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)
2705 || CHECK_FLAG(nh->flags,
2706 NEXTHOP_FLAG_RECURSIVE)
2707 || nh->nh_label == NULL)
2708 continue;
2709
2710 newnh = nexthop_dup(nh, NULL);
2711
2712 if (last_nh)
2713 NEXTHOP_APPEND(last_nh, newnh);
2714 else
2715 ctx->u.pw.fib_nhg.nexthop = newnh;
2716 last_nh = newnh;
09cd307c 2717 }
072b487b 2718 }
09cd307c 2719
072b487b
MS
2720 /* Include any installed backup nexthops also. */
2721 nhg = rib_get_fib_backup_nhg(re);
2722 if (nhg && nhg->nexthop) {
2723 for (ALL_NEXTHOPS_PTR(nhg, nh)) {
2724 if (!CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)
2725 || CHECK_FLAG(nh->flags,
2726 NEXTHOP_FLAG_RECURSIVE)
2727 || nh->nh_label == NULL)
2728 continue;
2729
2730 newnh = nexthop_dup(nh, NULL);
2731
2732 if (last_nh)
2733 NEXTHOP_APPEND(last_nh, newnh);
2734 else
2735 ctx->u.pw.fib_nhg.nexthop = newnh;
2736 last_nh = newnh;
0024ea8e 2737 }
072b487b
MS
2738 }
2739
2740 /* Copy primary nexthops; recursive info is included too */
2741 assert(re->nhe != NULL); /* SA warning */
2742 copy_nexthops(&(ctx->u.pw.primary_nhg.nexthop),
2743 re->nhe->nhg.nexthop, NULL);
2744 ctx->u.pw.nhg_id = re->nhe->id;
2745
2746 /* Copy backup nexthop info, if present */
2747 if (re->nhe->backup_info && re->nhe->backup_info->nhe) {
2748 copy_nexthops(&(ctx->u.pw.backup_nhg.nexthop),
2749 re->nhe->backup_info->nhe->nhg.nexthop,
2750 NULL);
09cd307c
MS
2751 }
2752 }
072b487b 2753 route_unlock_node(rn);
09cd307c 2754
072b487b
MS
2755 ret = AOK;
2756
2757done:
2758 return ret;
97d8d05a
MS
2759}
2760
f62e5480
JU
2761/**
2762 * dplane_ctx_rule_init_single() - Initialize a dataplane representation of a
2763 * PBR rule.
2764 *
2765 * @dplane_rule: Dataplane internal representation of a rule
2766 * @rule: PBR rule
2767 */
2768static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
2769 struct zebra_pbr_rule *rule)
2770{
2771 dplane_rule->priority = rule->rule.priority;
2772 dplane_rule->table = rule->rule.action.table;
2773
2774 dplane_rule->filter_bm = rule->rule.filter.filter_bm;
2775 dplane_rule->fwmark = rule->rule.filter.fwmark;
01f23aff 2776 dplane_rule->dsfield = rule->rule.filter.dsfield;
8ccbc778 2777 dplane_rule->ip_proto = rule->rule.filter.ip_proto;
f62e5480
JU
2778 prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip);
2779 prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip);
d70a31a3
EB
2780
2781 dplane_rule->action_pcp = rule->rule.action.pcp;
2782 dplane_rule->action_vlan_flags = rule->rule.action.vlan_flags;
2783 dplane_rule->action_vlan_id = rule->rule.action.vlan_id;
2784 dplane_rule->action_queue_id = rule->rule.action.queue_id;
2785
58a1d249 2786 strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ);
f62e5480
JU
2787}
2788
2789/**
2790 * dplane_ctx_rule_init() - Initialize a context block for a PBR rule update.
2791 *
2792 * @ctx: Dataplane context to init
2793 * @op: Operation being performed
2794 * @new_rule: PBR rule
2795 *
2796 * Return: Result status
2797 */
2798static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx,
2799 enum dplane_op_e op,
2800 struct zebra_pbr_rule *new_rule,
2801 struct zebra_pbr_rule *old_rule)
2802{
2dbe669b 2803 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
f62e5480 2804 zlog_debug(
2dbe669b 2805 "init dplane ctx %s: IF %s Prio %u Fwmark %u Src %pFX Dst %pFX Table %u",
f62e5480 2806 dplane_op2str(op), new_rule->ifname,
58a1d249 2807 new_rule->rule.priority, new_rule->rule.filter.fwmark,
2dbe669b
DA
2808 &new_rule->rule.filter.src_ip,
2809 &new_rule->rule.filter.dst_ip,
f62e5480 2810 new_rule->rule.action.table);
f62e5480
JU
2811
2812 ctx->zd_op = op;
2813 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2814
2815 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
2816 op == DPLANE_OP_RULE_UPDATE);
f6feb48b 2817 ctx->zd_is_update = (op == DPLANE_OP_RULE_UPDATE);
f62e5480
JU
2818
2819 ctx->zd_vrf_id = new_rule->vrf_id;
bc86b347 2820 strlcpy(ctx->zd_ifname, new_rule->ifname, sizeof(ctx->zd_ifname));
f62e5480
JU
2821
2822 ctx->u.rule.sock = new_rule->sock;
2823 ctx->u.rule.unique = new_rule->rule.unique;
2824 ctx->u.rule.seq = new_rule->rule.seq;
2825
2826 dplane_ctx_rule_init_single(&ctx->u.rule.new, new_rule);
2827 if (op == DPLANE_OP_RULE_UPDATE)
2828 dplane_ctx_rule_init_single(&ctx->u.rule.old, old_rule);
2829
2830 return AOK;
2831}
2832
5162e000
PG
2833/**
2834 * dplane_ctx_iptable_init() - Initialize a context block for a PBR iptable
2835 * update.
2836 *
2837 * @ctx: Dataplane context to init
2838 * @op: Operation being performed
2839 * @new_rule: PBR iptable
2840 *
2841 * Return: Result status
2842 */
2843static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx,
2844 enum dplane_op_e op,
2845 struct zebra_pbr_iptable *iptable)
2846{
2847 char *ifname;
2848 struct listnode *node;
2849
2850 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2851 zlog_debug(
2852 "init dplane ctx %s: Unique %u Fwmark %u Family %s Action %s",
2853 dplane_op2str(op), iptable->unique, iptable->fwmark,
2854 family2str(iptable->family),
2855 iptable->action == ZEBRA_IPTABLES_DROP ? "Drop"
2856 : "Forward");
2857 }
2858
2859 ctx->zd_op = op;
2860 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2861
2862 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
2863 ctx->zd_is_update = false;
2864
2865 ctx->zd_vrf_id = iptable->vrf_id;
2866 memcpy(&ctx->u.iptable, iptable, sizeof(struct zebra_pbr_iptable));
2867 ctx->u.iptable.interface_name_list = NULL;
2868 if (iptable->nb_interface > 0) {
2869 ctx->u.iptable.interface_name_list = list_new();
2870 for (ALL_LIST_ELEMENTS_RO(iptable->interface_name_list, node,
2871 ifname)) {
2872 listnode_add(ctx->u.iptable.interface_name_list,
ef524230 2873 XSTRDUP(MTYPE_DP_NETFILTER, ifname));
5162e000
PG
2874 }
2875 }
2876 return AOK;
2877}
2878
ef524230
PG
2879/**
2880 * dplane_ctx_ipset_init() - Initialize a context block for a PBR ipset update.
2881 *
2882 * @ctx: Dataplane context to init
2883 * @op: Operation being performed
2884 * @new_rule: PBR ipset
2885 *
2886 * Return: Result status
2887 */
2888static int dplane_ctx_ipset_init(struct zebra_dplane_ctx *ctx,
2889 enum dplane_op_e op,
2890 struct zebra_pbr_ipset *ipset)
2891{
2892 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2893 zlog_debug("init dplane ctx %s: %s Unique %u Family %s Type %s",
2894 dplane_op2str(op), ipset->ipset_name, ipset->unique,
2895 family2str(ipset->family),
2896 zebra_pbr_ipset_type2str(ipset->type));
2897 }
2898
2899 ctx->zd_op = op;
2900 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2901
2902 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
2903 ctx->zd_is_update = false;
2904
2905 ctx->zd_vrf_id = ipset->vrf_id;
2906
2907 memcpy(&ctx->u.ipset, ipset, sizeof(struct zebra_pbr_ipset));
2908 return AOK;
2909}
2910
2911/**
2912 * dplane_ctx_ipset_entry_init() - Initialize a context block for a PBR ipset
2913 * update.
2914 *
2915 * @ctx: Dataplane context to init
2916 * @op: Operation being performed
2917 * @new_rule: PBR ipset
2918 *
2919 * Return: Result status
2920 */
2921static int
2922dplane_ctx_ipset_entry_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
2923 struct zebra_pbr_ipset_entry *ipset_entry)
2924{
2925 struct zebra_pbr_ipset *ipset;
2926
2927 ipset = ipset_entry->backpointer;
2928 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
2929 zlog_debug("init dplane ctx %s: %s Unique %u filter %u",
2930 dplane_op2str(op), ipset->ipset_name,
2931 ipset_entry->unique, ipset_entry->filter_bm);
2932 }
2933
2934 ctx->zd_op = op;
2935 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2936
2937 dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
2938 ctx->zd_is_update = false;
2939
2940 ctx->zd_vrf_id = ipset->vrf_id;
2941
2942 memcpy(&ctx->u.ipset_entry.entry, ipset_entry,
2943 sizeof(struct zebra_pbr_ipset_entry));
2944 ctx->u.ipset_entry.entry.backpointer = NULL;
2945 ctx->u.ipset_entry.info.type = ipset->type;
2946 memcpy(&ctx->u.ipset_entry.info.ipset_name, &ipset->ipset_name,
2947 ZEBRA_IPSET_NAME_SIZE);
2948
2949 return AOK;
2950}
2951
2952
7cdb1a84 2953/*
3fe4ccc4 2954 * Enqueue a new update,
16c628de 2955 * and ensure an event is active for the dataplane pthread.
7cdb1a84 2956 */
3fe4ccc4 2957static int dplane_update_enqueue(struct zebra_dplane_ctx *ctx)
7cdb1a84
MS
2958{
2959 int ret = EINVAL;
91f16812 2960 uint32_t high, curr;
7cdb1a84 2961
16c628de 2962 /* Enqueue for processing by the dataplane pthread */
7cdb1a84
MS
2963 DPLANE_LOCK();
2964 {
3fe4ccc4 2965 TAILQ_INSERT_TAIL(&zdplane_info.dg_update_ctx_q, ctx,
25779064 2966 zd_q_entries);
7cdb1a84
MS
2967 }
2968 DPLANE_UNLOCK();
2969
e3d9208a 2970 curr = atomic_fetch_add_explicit(
e07e9549 2971 &(zdplane_info.dg_routes_queued),
e07e9549 2972 1, memory_order_seq_cst);
91f16812 2973
e3d9208a
MS
2974 curr++; /* We got the pre-incremented value */
2975
91f16812
MS
2976 /* Maybe update high-water counter also */
2977 high = atomic_load_explicit(&zdplane_info.dg_routes_queued_max,
2978 memory_order_seq_cst);
2979 while (high < curr) {
2980 if (atomic_compare_exchange_weak_explicit(
2981 &zdplane_info.dg_routes_queued_max,
2982 &high, curr,
2983 memory_order_seq_cst,
2984 memory_order_seq_cst))
2985 break;
2986 }
2987
7cdb1a84 2988 /* Ensure that an event for the dataplane thread is active */
c831033f 2989 ret = dplane_provider_work_ready();
7cdb1a84 2990
5709131c 2991 return ret;
7cdb1a84
MS
2992}
2993
7cdb1a84
MS
2994/*
2995 * Utility that prepares a route update and enqueues it for processing
2996 */
655d681a
MS
2997static enum zebra_dplane_result
2998dplane_route_update_internal(struct route_node *rn,
2999 struct route_entry *re,
3000 struct route_entry *old_re,
5709131c 3001 enum dplane_op_e op)
7cdb1a84 3002{
655d681a 3003 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
7cdb1a84 3004 int ret = EINVAL;
25779064 3005 struct zebra_dplane_ctx *ctx = NULL;
7cdb1a84
MS
3006
3007 /* Obtain context block */
3008 ctx = dplane_ctx_alloc();
7cdb1a84
MS
3009
3010 /* Init context with info from zebra data structs */
3011 ret = dplane_ctx_route_init(ctx, op, rn, re);
3012 if (ret == AOK) {
3013 /* Capture some extra info for update case
3014 * where there's a different 'old' route.
3015 */
b8e0423d
MS
3016 if ((op == DPLANE_OP_ROUTE_UPDATE) &&
3017 old_re && (old_re != re)) {
7cdb1a84
MS
3018 ctx->zd_is_update = true;
3019
1485bbe7
DS
3020 old_re->dplane_sequence =
3021 zebra_router_get_next_sequence();
7cdb1a84
MS
3022 ctx->zd_old_seq = old_re->dplane_sequence;
3023
0f461727
MS
3024 ctx->u.rinfo.zd_old_tag = old_re->tag;
3025 ctx->u.rinfo.zd_old_type = old_re->type;
3026 ctx->u.rinfo.zd_old_instance = old_re->instance;
3027 ctx->u.rinfo.zd_old_distance = old_re->distance;
3028 ctx->u.rinfo.zd_old_metric = old_re->metric;
df3cef24 3029 ctx->u.rinfo.nhe.old_id = old_re->nhe->id;
01ce7cba
MS
3030
3031#ifndef HAVE_NETLINK
f183e380
MS
3032 /* For bsd, capture previous re's nexthops too, sigh.
3033 * We'll need these to do per-nexthop deletes.
3034 */
0f461727 3035 copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
c415d895 3036 old_re->nhe->nhg.nexthop, NULL);
1d48702e
MS
3037
3038 if (zebra_nhg_get_backup_nhg(old_re->nhe) != NULL) {
3039 struct nexthop_group *nhg;
3040 struct nexthop **nh;
3041
3042 nhg = zebra_nhg_get_backup_nhg(old_re->nhe);
3043 nh = &(ctx->u.rinfo.old_backup_ng.nexthop);
3044
3045 if (nhg->nexthop)
3046 copy_nexthops(nh, nhg->nexthop, NULL);
3047 }
01ce7cba 3048#endif /* !HAVE_NETLINK */
7cdb1a84
MS
3049 }
3050
df3cef24
DS
3051 /*
3052 * If the old and new context type, and nexthop group id
3053 * are the same there is no need to send down a route replace
3054 * as that we know we have sent a nexthop group replace
3055 * or an upper level protocol has sent us the exact
3056 * same route again.
3057 */
3058 if ((dplane_ctx_get_type(ctx) == dplane_ctx_get_old_type(ctx))
3059 && (dplane_ctx_get_nhe_id(ctx)
3d3a9dc8
SW
3060 == dplane_ctx_get_old_nhe_id(ctx))
3061 && (dplane_ctx_get_nhe_id(ctx) >= ZEBRA_NHG_PROTO_LOWER)) {
27805e74
DS
3062 struct nexthop *nexthop;
3063
df3cef24
DS
3064 if (IS_ZEBRA_DEBUG_DPLANE)
3065 zlog_debug(
3066 "%s: Ignoring Route exactly the same",
3067 __func__);
3068
27805e74
DS
3069 for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
3070 nexthop)) {
3071 if (CHECK_FLAG(nexthop->flags,
3072 NEXTHOP_FLAG_RECURSIVE))
3073 continue;
3074
3075 if (CHECK_FLAG(nexthop->flags,
3076 NEXTHOP_FLAG_ACTIVE))
3077 SET_FLAG(nexthop->flags,
3078 NEXTHOP_FLAG_FIB);
3079 }
3080
841f77ff 3081 dplane_ctx_free(&ctx);
df3cef24
DS
3082 return ZEBRA_DPLANE_REQUEST_SUCCESS;
3083 }
3084
7cdb1a84 3085 /* Enqueue context for processing */
3fe4ccc4 3086 ret = dplane_update_enqueue(ctx);
7cdb1a84
MS
3087 }
3088
91f16812 3089 /* Update counter */
25779064 3090 atomic_fetch_add_explicit(&zdplane_info.dg_routes_in, 1,
1d11b21f
MS
3091 memory_order_relaxed);
3092
91f16812 3093 if (ret == AOK)
655d681a 3094 result = ZEBRA_DPLANE_REQUEST_QUEUED;
16c628de 3095 else {
b96f64f7
DS
3096 atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, 1,
3097 memory_order_relaxed);
16c628de
MS
3098 if (ctx)
3099 dplane_ctx_free(&ctx);
1d11b21f 3100 }
7cdb1a84 3101
5709131c 3102 return result;
7cdb1a84
MS
3103}
3104
f820d025
SW
3105/**
3106 * dplane_nexthop_update_internal() - Helper for enqueuing nexthop changes
3107 *
3108 * @nhe: Nexthop group hash entry where the change occured
3109 * @op: The operation to be enqued
3110 *
3111 * Return: Result of the change
3112 */
3113static enum zebra_dplane_result
3114dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op)
3115{
3116 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3117 int ret = EINVAL;
3118 struct zebra_dplane_ctx *ctx = NULL;
3119
3120 /* Obtain context block */
3121 ctx = dplane_ctx_alloc();
3122 if (!ctx) {
3123 ret = ENOMEM;
3124 goto done;
3125 }
3126
3127 ret = dplane_ctx_nexthop_init(ctx, op, nhe);
2d3c57e6 3128 if (ret == AOK)
f820d025 3129 ret = dplane_update_enqueue(ctx);
2d3c57e6 3130
f820d025
SW
3131done:
3132 /* Update counter */
3133 atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, 1,
3134 memory_order_relaxed);
3135
3136 if (ret == AOK)
3137 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3138 else {
81505946
SW
3139 atomic_fetch_add_explicit(&zdplane_info.dg_nexthop_errors, 1,
3140 memory_order_relaxed);
f820d025
SW
3141 if (ctx)
3142 dplane_ctx_free(&ctx);
3143 }
3144
3145 return result;
3146}
3147
7cdb1a84
MS
3148/*
3149 * Enqueue a route 'add' for the dataplane.
3150 */
655d681a
MS
3151enum zebra_dplane_result dplane_route_add(struct route_node *rn,
3152 struct route_entry *re)
7cdb1a84 3153{
655d681a 3154 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
7cdb1a84 3155
5709131c 3156 if (rn == NULL || re == NULL)
7cdb1a84 3157 goto done;
7cdb1a84
MS
3158
3159 ret = dplane_route_update_internal(rn, re, NULL,
3160 DPLANE_OP_ROUTE_INSTALL);
3161
3162done:
5709131c 3163 return ret;
7cdb1a84
MS
3164}
3165
3166/*
3167 * Enqueue a route update for the dataplane.
3168 */
655d681a
MS
3169enum zebra_dplane_result dplane_route_update(struct route_node *rn,
3170 struct route_entry *re,
3171 struct route_entry *old_re)
7cdb1a84 3172{
655d681a 3173 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
7cdb1a84 3174
5709131c 3175 if (rn == NULL || re == NULL)
7cdb1a84 3176 goto done;
7cdb1a84
MS
3177
3178 ret = dplane_route_update_internal(rn, re, old_re,
3179 DPLANE_OP_ROUTE_UPDATE);
7cdb1a84 3180done:
5709131c 3181 return ret;
7cdb1a84
MS
3182}
3183
3184/*
3185 * Enqueue a route removal for the dataplane.
3186 */
655d681a
MS
3187enum zebra_dplane_result dplane_route_delete(struct route_node *rn,
3188 struct route_entry *re)
7cdb1a84 3189{
655d681a 3190 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
7cdb1a84 3191
5709131c 3192 if (rn == NULL || re == NULL)
7cdb1a84 3193 goto done;
7cdb1a84
MS
3194
3195 ret = dplane_route_update_internal(rn, re, NULL,
3196 DPLANE_OP_ROUTE_DELETE);
3197
3198done:
5709131c 3199 return ret;
7cdb1a84
MS
3200}
3201
cf363e1b
MS
3202/*
3203 * Notify the dplane when system/connected routes change.
3204 */
3205enum zebra_dplane_result dplane_sys_route_add(struct route_node *rn,
3206 struct route_entry *re)
3207{
3208 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
3209
3210 /* Ignore this event unless a provider plugin has requested it. */
3211 if (!zdplane_info.dg_sys_route_notifs) {
3212 ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
3213 goto done;
3214 }
3215
3216 if (rn == NULL || re == NULL)
3217 goto done;
3218
3219 ret = dplane_route_update_internal(rn, re, NULL,
3220 DPLANE_OP_SYS_ROUTE_ADD);
3221
3222done:
3223 return ret;
3224}
3225
3226/*
3227 * Notify the dplane when system/connected routes are deleted.
3228 */
3229enum zebra_dplane_result dplane_sys_route_del(struct route_node *rn,
3230 struct route_entry *re)
3231{
3232 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
3233
3234 /* Ignore this event unless a provider plugin has requested it. */
3235 if (!zdplane_info.dg_sys_route_notifs) {
3236 ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
3237 goto done;
3238 }
3239
3240 if (rn == NULL || re == NULL)
3241 goto done;
3242
3243 ret = dplane_route_update_internal(rn, re, NULL,
3244 DPLANE_OP_SYS_ROUTE_DELETE);
3245
3246done:
3247 return ret;
3248}
3249
188a00e0
MS
3250/*
3251 * Update from an async notification, to bring other fibs up-to-date.
3252 */
3253enum zebra_dplane_result
3254dplane_route_notif_update(struct route_node *rn,
3255 struct route_entry *re,
3256 enum dplane_op_e op,
3257 struct zebra_dplane_ctx *ctx)
3258{
54d321aa
MS
3259 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3260 int ret = EINVAL;
188a00e0
MS
3261 struct zebra_dplane_ctx *new_ctx = NULL;
3262 struct nexthop *nexthop;
3c0e1622 3263 struct nexthop_group *nhg;
188a00e0
MS
3264
3265 if (rn == NULL || re == NULL)
3266 goto done;
3267
3268 new_ctx = dplane_ctx_alloc();
3269 if (new_ctx == NULL)
3270 goto done;
3271
3272 /* Init context with info from zebra data structs */
3273 dplane_ctx_route_init(new_ctx, op, rn, re);
3274
3275 /* For add/update, need to adjust the nexthops so that we match
3276 * the notification state, which may not be the route-entry/RIB
3277 * state.
3278 */
3279 if (op == DPLANE_OP_ROUTE_UPDATE ||
3280 op == DPLANE_OP_ROUTE_INSTALL) {
3281
3282 nexthops_free(new_ctx->u.rinfo.zd_ng.nexthop);
3283 new_ctx->u.rinfo.zd_ng.nexthop = NULL;
3284
3c0e1622
MS
3285 nhg = rib_get_fib_nhg(re);
3286 if (nhg && nhg->nexthop)
3287 copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
3288 nhg->nexthop, NULL);
188a00e0 3289
3c0e1622
MS
3290 /* Check for installed backup nexthops also */
3291 nhg = rib_get_fib_backup_nhg(re);
3292 if (nhg && nhg->nexthop) {
00a9b150 3293 copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
3c0e1622 3294 nhg->nexthop, NULL);
00a9b150 3295 }
188a00e0
MS
3296
3297 for (ALL_NEXTHOPS(new_ctx->u.rinfo.zd_ng, nexthop))
3298 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
3299
3300 }
3301
3302 /* Capture info about the source of the notification, in 'ctx' */
3303 dplane_ctx_set_notif_provider(new_ctx,
3304 dplane_ctx_get_notif_provider(ctx));
3305
54d321aa 3306 ret = dplane_update_enqueue(new_ctx);
188a00e0
MS
3307
3308done:
54d321aa
MS
3309 if (ret == AOK)
3310 result = ZEBRA_DPLANE_REQUEST_QUEUED;
dd3b6cb5
MS
3311 else if (new_ctx)
3312 dplane_ctx_free(&new_ctx);
54d321aa
MS
3313
3314 return result;
188a00e0
MS
3315}
3316
f820d025
SW
3317/*
3318 * Enqueue a nexthop add for the dataplane.
3319 */
3320enum zebra_dplane_result dplane_nexthop_add(struct nhg_hash_entry *nhe)
3321{
3322 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
3323
3324 if (nhe)
3325 ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_INSTALL);
3326 return ret;
3327}
3328
3329/*
3330 * Enqueue a nexthop update for the dataplane.
81505946
SW
3331 *
3332 * Might not need this func since zebra's nexthop objects should be immutable?
f820d025
SW
3333 */
3334enum zebra_dplane_result dplane_nexthop_update(struct nhg_hash_entry *nhe)
3335{
3336 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
3337
3338 if (nhe)
3339 ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_UPDATE);
3340 return ret;
3341}
3342
3343/*
3344 * Enqueue a nexthop removal for the dataplane.
3345 */
3346enum zebra_dplane_result dplane_nexthop_delete(struct nhg_hash_entry *nhe)
3347{
3348 enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
3349
3350 if (nhe)
3351 ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_DELETE);
3352
3353 return ret;
3354}
3355
16c628de
MS
3356/*
3357 * Enqueue LSP add for the dataplane.
3358 */
8f74a383 3359enum zebra_dplane_result dplane_lsp_add(struct zebra_lsp *lsp)
16c628de
MS
3360{
3361 enum zebra_dplane_result ret =
3362 lsp_update_internal(lsp, DPLANE_OP_LSP_INSTALL);
3363
3364 return ret;
3365}
3366
3367/*
3368 * Enqueue LSP update for the dataplane.
3369 */
8f74a383 3370enum zebra_dplane_result dplane_lsp_update(struct zebra_lsp *lsp)
16c628de
MS
3371{
3372 enum zebra_dplane_result ret =
3373 lsp_update_internal(lsp, DPLANE_OP_LSP_UPDATE);
3374
3375 return ret;
3376}
3377
3378/*
3379 * Enqueue LSP delete for the dataplane.
3380 */
8f74a383 3381enum zebra_dplane_result dplane_lsp_delete(struct zebra_lsp *lsp)
16c628de
MS
3382{
3383 enum zebra_dplane_result ret =
3384 lsp_update_internal(lsp, DPLANE_OP_LSP_DELETE);
3385
3386 return ret;
3387}
3388
188a00e0
MS
3389/* Update or un-install resulting from an async notification */
3390enum zebra_dplane_result
8f74a383 3391dplane_lsp_notif_update(struct zebra_lsp *lsp, enum dplane_op_e op,
188a00e0
MS
3392 struct zebra_dplane_ctx *notif_ctx)
3393{
3394 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3395 int ret = EINVAL;
3396 struct zebra_dplane_ctx *ctx = NULL;
00a9b150 3397 struct nhlfe_list_head *head;
f2595bd5 3398 struct zebra_nhlfe *nhlfe, *new_nhlfe;
188a00e0
MS
3399
3400 /* Obtain context block */
3401 ctx = dplane_ctx_alloc();
3402 if (ctx == NULL) {
3403 ret = ENOMEM;
3404 goto done;
3405 }
3406
00a9b150 3407 /* Copy info from zebra LSP */
188a00e0
MS
3408 ret = dplane_ctx_lsp_init(ctx, op, lsp);
3409 if (ret != AOK)
3410 goto done;
3411
00a9b150
MS
3412 /* Add any installed backup nhlfes */
3413 head = &(ctx->u.lsp.backup_nhlfe_list);
3414 frr_each(nhlfe_list, head, nhlfe) {
3415
3416 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) &&
3417 CHECK_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_FIB)) {
3418 new_nhlfe = zebra_mpls_lsp_add_nh(&(ctx->u.lsp),
3419 nhlfe->type,
3420 nhlfe->nexthop);
3421
3422 /* Need to copy flags too */
3423 new_nhlfe->flags = nhlfe->flags;
3424 new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
3425 }
3426 }
3427
188a00e0
MS
3428 /* Capture info about the source of the notification */
3429 dplane_ctx_set_notif_provider(
3430 ctx,
3431 dplane_ctx_get_notif_provider(notif_ctx));
3432
3fe4ccc4 3433 ret = dplane_update_enqueue(ctx);
188a00e0
MS
3434
3435done:
3436 /* Update counter */
3437 atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
3438 memory_order_relaxed);
3439
3440 if (ret == AOK)
3441 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3442 else {
3443 atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
3444 memory_order_relaxed);
3445 if (ctx)
3446 dplane_ctx_free(&ctx);
3447 }
3448 return result;
3449}
3450
97d8d05a
MS
3451/*
3452 * Enqueue pseudowire install for the dataplane.
3453 */
3454enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw)
3455{
3456 return pw_update_internal(pw, DPLANE_OP_PW_INSTALL);
3457}
3458
3459/*
3460 * Enqueue pseudowire un-install for the dataplane.
3461 */
3462enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw)
3463{
3464 return pw_update_internal(pw, DPLANE_OP_PW_UNINSTALL);
3465}
3466
16c628de
MS
3467/*
3468 * Common internal LSP update utility
3469 */
8f74a383 3470static enum zebra_dplane_result lsp_update_internal(struct zebra_lsp *lsp,
16c628de
MS
3471 enum dplane_op_e op)
3472{
3473 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3474 int ret = EINVAL;
3475 struct zebra_dplane_ctx *ctx = NULL;
3476
3477 /* Obtain context block */
3478 ctx = dplane_ctx_alloc();
16c628de
MS
3479
3480 ret = dplane_ctx_lsp_init(ctx, op, lsp);
3481 if (ret != AOK)
3482 goto done;
3483
3fe4ccc4 3484 ret = dplane_update_enqueue(ctx);
16c628de
MS
3485
3486done:
3487 /* Update counter */
3488 atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
3489 memory_order_relaxed);
3490
3491 if (ret == AOK)
3492 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3493 else {
3494 atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
3495 memory_order_relaxed);
d8e479a3 3496 dplane_ctx_free(&ctx);
16c628de
MS
3497 }
3498
3499 return result;
3500}
3501
97d8d05a
MS
3502/*
3503 * Internal, common handler for pseudowire updates.
3504 */
3505static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
3506 enum dplane_op_e op)
3507{
3508 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3509 int ret;
3510 struct zebra_dplane_ctx *ctx = NULL;
3511
3512 ctx = dplane_ctx_alloc();
97d8d05a
MS
3513
3514 ret = dplane_ctx_pw_init(ctx, op, pw);
3515 if (ret != AOK)
3516 goto done;
3517
3fe4ccc4 3518 ret = dplane_update_enqueue(ctx);
97d8d05a
MS
3519
3520done:
3521 /* Update counter */
3522 atomic_fetch_add_explicit(&zdplane_info.dg_pws_in, 1,
3523 memory_order_relaxed);
3524
3525 if (ret == AOK)
3526 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3527 else {
3528 atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
3529 memory_order_relaxed);
d8e479a3 3530 dplane_ctx_free(&ctx);
97d8d05a
MS
3531 }
3532
3533 return result;
3534}
3535
c60522f7
AK
3536/*
3537 * Enqueue access br_port update.
3538 */
3539enum zebra_dplane_result
3540dplane_br_port_update(const struct interface *ifp, bool non_df,
3541 uint32_t sph_filter_cnt,
3542 const struct in_addr *sph_filters, uint32_t backup_nhg_id)
3543{
3544 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3545 uint32_t flags = 0;
3546 int ret;
3547 struct zebra_dplane_ctx *ctx = NULL;
3548 struct zebra_ns *zns;
3549 enum dplane_op_e op = DPLANE_OP_BR_PORT_UPDATE;
3550
3551 if (non_df)
3552 flags |= DPLANE_BR_PORT_NON_DF;
3553
28e80a03 3554 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_EVPN_MH_ES) {
c60522f7
AK
3555 uint32_t i;
3556 char vtep_str[ES_VTEP_LIST_STR_SZ];
3557
3558 vtep_str[0] = '\0';
3559 for (i = 0; i < sph_filter_cnt; ++i) {
3560 snprintfrr(vtep_str + strlen(vtep_str),
3561 sizeof(vtep_str) - strlen(vtep_str), "%pI4 ",
3562 &sph_filters[i]);
3563 }
3564 zlog_debug(
3565 "init br_port ctx %s: ifp %s, flags 0x%x backup_nhg 0x%x sph %s",
3566 dplane_op2str(op), ifp->name, flags, backup_nhg_id,
3567 vtep_str);
3568 }
3569
3570 ctx = dplane_ctx_alloc();
3571
3572 ctx->zd_op = op;
3573 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3574 ctx->zd_vrf_id = ifp->vrf_id;
3575
3576 zns = zebra_ns_lookup(ifp->vrf_id);
3577 dplane_ctx_ns_init(ctx, zns, false);
3578
3579 ctx->zd_ifindex = ifp->ifindex;
3580 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
3581
3582 /* Init the br-port-specific data area */
3583 memset(&ctx->u.br_port, 0, sizeof(ctx->u.br_port));
3584
3585 ctx->u.br_port.flags = flags;
3586 ctx->u.br_port.backup_nhg_id = backup_nhg_id;
3587 ctx->u.br_port.sph_filter_cnt = sph_filter_cnt;
3588 memcpy(ctx->u.br_port.sph_filters, sph_filters,
3589 sizeof(ctx->u.br_port.sph_filters[0]) * sph_filter_cnt);
3590
3591 /* Enqueue for processing on the dplane pthread */
3592 ret = dplane_update_enqueue(ctx);
3593
3594 /* Increment counter */
3595 atomic_fetch_add_explicit(&zdplane_info.dg_br_port_in, 1,
3596 memory_order_relaxed);
3597
3598 if (ret == AOK) {
3599 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3600 } else {
3601 /* Error counter */
3602 atomic_fetch_add_explicit(&zdplane_info.dg_br_port_errors, 1,
3603 memory_order_relaxed);
3604 dplane_ctx_free(&ctx);
3605 }
3606
3607 return result;
3608}
3609
a4a4802a
MS
3610/*
3611 * Enqueue interface address add for the dataplane.
3612 */
3613enum zebra_dplane_result dplane_intf_addr_set(const struct interface *ifp,
3614 const struct connected *ifc)
3615{
64168803
MS
3616#if !defined(HAVE_NETLINK) && defined(HAVE_STRUCT_IFALIASREQ)
3617 /* Extra checks for this OS path. */
3618
3619 /* Don't configure PtP addresses on broadcast ifs or reverse */
3620 if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) {
3621 if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_DPLANE)
3622 zlog_debug("Failed to set intf addr: mismatch p2p and connected");
3623
3624 return ZEBRA_DPLANE_REQUEST_FAILURE;
3625 }
64168803
MS
3626#endif
3627
3628 return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_INSTALL);
a4a4802a
MS
3629}
3630
3631/*
3632 * Enqueue interface address remove/uninstall for the dataplane.
3633 */
3634enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
3635 const struct connected *ifc)
3636{
64168803
MS
3637 return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_UNINSTALL);
3638}
3639
3640static enum zebra_dplane_result intf_addr_update_internal(
3641 const struct interface *ifp, const struct connected *ifc,
3642 enum dplane_op_e op)
3643{
3644 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3645 int ret = EINVAL;
3646 struct zebra_dplane_ctx *ctx = NULL;
3647 struct zebra_ns *zns;
3648
2dbe669b
DA
3649 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3650 zlog_debug("init intf ctx %s: idx %d, addr %u:%pFX",
a36898e7 3651 dplane_op2str(op), ifp->ifindex, ifp->vrf_id,
2dbe669b 3652 ifc->address);
64168803
MS
3653
3654 ctx = dplane_ctx_alloc();
64168803
MS
3655
3656 ctx->zd_op = op;
3657 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
a36898e7 3658 ctx->zd_vrf_id = ifp->vrf_id;
64168803 3659
a36898e7 3660 zns = zebra_ns_lookup(ifp->vrf_id);
64168803
MS
3661 dplane_ctx_ns_init(ctx, zns, false);
3662
3663 /* Init the interface-addr-specific area */
3664 memset(&ctx->u.intf, 0, sizeof(ctx->u.intf));
3665
7c7ef4a8
MS
3666 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
3667 ctx->zd_ifindex = ifp->ifindex;
64168803
MS
3668 ctx->u.intf.prefix = *(ifc->address);
3669
3670 if (if_is_broadcast(ifp))
3671 ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
3672
3673 if (CONNECTED_PEER(ifc)) {
3674 ctx->u.intf.dest_prefix = *(ifc->destination);
3675 ctx->u.intf.flags |=
3676 (DPLANE_INTF_CONNECTED | DPLANE_INTF_HAS_DEST);
64168803
MS
3677 }
3678
3679 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
3680 ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
3681
3682 if (ifc->label) {
3683 size_t len;
3684
3685 ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
3686
3687 /* Use embedded buffer if it's adequate; else allocate. */
3688 len = strlen(ifc->label);
3689
3690 if (len < sizeof(ctx->u.intf.label_buf)) {
b7b7bf31 3691 strlcpy(ctx->u.intf.label_buf, ifc->label,
64168803
MS
3692 sizeof(ctx->u.intf.label_buf));
3693 ctx->u.intf.label = ctx->u.intf.label_buf;
3694 } else {
3695 ctx->u.intf.label = strdup(ifc->label);
3696 }
3697 }
3698
3fe4ccc4 3699 ret = dplane_update_enqueue(ctx);
64168803 3700
64168803
MS
3701 /* Increment counter */
3702 atomic_fetch_add_explicit(&zdplane_info.dg_intf_addrs_in, 1,
3703 memory_order_relaxed);
3704
3705 if (ret == AOK)
3706 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3707 else {
3708 /* Error counter */
3709 atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors,
3710 1, memory_order_relaxed);
d8e479a3 3711 dplane_ctx_free(&ctx);
64168803
MS
3712 }
3713
3714 return result;
a4a4802a
MS
3715}
3716
7597ac7b
MS
3717/*
3718 * Enqueue vxlan/evpn mac add (or update).
3719 */
f188e68e 3720enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
478566d6 3721 const struct interface *bridge_ifp,
7597ac7b
MS
3722 vlanid_t vid,
3723 const struct ethaddr *mac,
3724 struct in_addr vtep_ip,
506efd37 3725 bool sticky,
f188e68e
AK
3726 uint32_t nhg_id,
3727 bool was_static)
7597ac7b
MS
3728{
3729 enum zebra_dplane_result result;
f188e68e
AK
3730 uint32_t update_flags = 0;
3731
3732 update_flags |= DPLANE_MAC_REMOTE;
3733 if (was_static)
3734 update_flags |= DPLANE_MAC_WAS_STATIC;
7597ac7b
MS
3735
3736 /* Use common helper api */
f73a8467 3737 result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
f188e68e 3738 vid, mac, vtep_ip, sticky, nhg_id, update_flags);
7597ac7b
MS
3739 return result;
3740}
3741
3742/*
3743 * Enqueue vxlan/evpn mac delete.
3744 */
f188e68e 3745enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
478566d6 3746 const struct interface *bridge_ifp,
7597ac7b
MS
3747 vlanid_t vid,
3748 const struct ethaddr *mac,
3749 struct in_addr vtep_ip)
3750{
3751 enum zebra_dplane_result result;
f188e68e
AK
3752 uint32_t update_flags = 0;
3753
3754 update_flags |= DPLANE_MAC_REMOTE;
7597ac7b
MS
3755
3756 /* Use common helper api */
f73a8467 3757 result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
f188e68e
AK
3758 vid, mac, vtep_ip, false, 0, update_flags);
3759 return result;
3760}
3761
0a27a2fe
PG
3762/*
3763 * API to configure link local with either MAC address or IP information
3764 */
3765enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
3766 const struct interface *ifp,
3767 struct ipaddr *link_ip,
3768 struct ipaddr *ip,
d603c077 3769 uint32_t ndm_state, int protocol)
0a27a2fe
PG
3770{
3771 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3772 uint16_t state = 0;
3773 uint32_t update_flags;
3774
80ff3f05
MS
3775 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3776 zlog_debug("%s: init link ctx %s: ifp %s, link_ip %pIA ip %pIA",
3777 __func__, dplane_op2str(op), ifp->name, link_ip, ip);
0a27a2fe 3778
d603c077
PG
3779 if (ndm_state == ZEBRA_NEIGH_STATE_REACHABLE)
3780 state = DPLANE_NUD_REACHABLE;
3781 else if (ndm_state == ZEBRA_NEIGH_STATE_FAILED)
0a27a2fe
PG
3782 state = DPLANE_NUD_FAILED;
3783
3784 update_flags = DPLANE_NEIGH_NO_EXTENSION;
3785
3786 result = neigh_update_internal(op, ifp, (const void *)link_ip,
3787 ipaddr_family(link_ip), ip, 0, state,
3788 update_flags, protocol);
3789
3790 return result;
3791}
3792
f188e68e
AK
3793/*
3794 * Enqueue local mac add (or update).
3795 */
3796enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp,
3797 const struct interface *bridge_ifp,
3798 vlanid_t vid,
3799 const struct ethaddr *mac,
3800 bool sticky,
3801 uint32_t set_static,
3802 uint32_t set_inactive)
3803{
3804 enum zebra_dplane_result result;
3805 uint32_t update_flags = 0;
3806 struct in_addr vtep_ip;
3807
3808 if (set_static)
3809 update_flags |= DPLANE_MAC_SET_STATIC;
3810
3811 if (set_inactive)
3812 update_flags |= DPLANE_MAC_SET_INACTIVE;
3813
3814 vtep_ip.s_addr = 0;
3815
3816 /* Use common helper api */
3817 result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
3818 vid, mac, vtep_ip, sticky, 0,
3819 update_flags);
7597ac7b
MS
3820 return result;
3821}
3822
00a7710c
AK
3823/*
3824 * Enqueue local mac del
3825 */
3826enum zebra_dplane_result
3827dplane_local_mac_del(const struct interface *ifp,
3828 const struct interface *bridge_ifp, vlanid_t vid,
3829 const struct ethaddr *mac)
3830{
3831 enum zebra_dplane_result result;
3832 struct in_addr vtep_ip;
3833
3834 vtep_ip.s_addr = 0;
3835
3836 /* Use common helper api */
3837 result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, vid,
3838 mac, vtep_ip, false, 0, 0);
3839 return result;
3840}
7597ac7b 3841/*
f73a8467
MS
3842 * Public api to init an empty context - either newly-allocated or
3843 * reset/cleared - for a MAC update.
7597ac7b 3844 */
f73a8467
MS
3845void dplane_mac_init(struct zebra_dplane_ctx *ctx,
3846 const struct interface *ifp,
3847 const struct interface *br_ifp,
3848 vlanid_t vid,
3849 const struct ethaddr *mac,
3850 struct in_addr vtep_ip,
506efd37 3851 bool sticky,
f188e68e
AK
3852 uint32_t nhg_id,
3853 uint32_t update_flags)
7597ac7b 3854{
7597ac7b
MS
3855 struct zebra_ns *zns;
3856
7597ac7b
MS
3857 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3858 ctx->zd_vrf_id = ifp->vrf_id;
3859
3860 zns = zebra_ns_lookup(ifp->vrf_id);
3861 dplane_ctx_ns_init(ctx, zns, false);
3862
3863 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
3864 ctx->zd_ifindex = ifp->ifindex;
3865
3866 /* Init the mac-specific data area */
3867 memset(&ctx->u.macinfo, 0, sizeof(ctx->u.macinfo));
3868
478566d6 3869 ctx->u.macinfo.br_ifindex = br_ifp->ifindex;
7597ac7b
MS
3870 ctx->u.macinfo.vtep_ip = vtep_ip;
3871 ctx->u.macinfo.mac = *mac;
3872 ctx->u.macinfo.vid = vid;
3873 ctx->u.macinfo.is_sticky = sticky;
506efd37 3874 ctx->u.macinfo.nhg_id = nhg_id;
f188e68e 3875 ctx->u.macinfo.update_flags = update_flags;
f73a8467
MS
3876}
3877
3878/*
3879 * Common helper api for MAC address/vxlan updates
3880 */
3881static enum zebra_dplane_result
3882mac_update_common(enum dplane_op_e op,
3883 const struct interface *ifp,
3884 const struct interface *br_ifp,
3885 vlanid_t vid,
3886 const struct ethaddr *mac,
3887 struct in_addr vtep_ip,
506efd37 3888 bool sticky,
f188e68e
AK
3889 uint32_t nhg_id,
3890 uint32_t update_flags)
f73a8467
MS
3891{
3892 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3893 int ret;
3894 struct zebra_dplane_ctx *ctx = NULL;
3895
ef7b8be4
DL
3896 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3897 zlog_debug("init mac ctx %s: mac %pEA, ifp %s, vtep %pI4",
3898 dplane_op2str(op), mac, ifp->name, &vtep_ip);
f73a8467
MS
3899
3900 ctx = dplane_ctx_alloc();
3901 ctx->zd_op = op;
3902
3903 /* Common init for the ctx */
f188e68e
AK
3904 dplane_mac_init(ctx, ifp, br_ifp, vid, mac, vtep_ip, sticky,
3905 nhg_id, update_flags);
7597ac7b
MS
3906
3907 /* Enqueue for processing on the dplane pthread */
3908 ret = dplane_update_enqueue(ctx);
3909
3910 /* Increment counter */
3911 atomic_fetch_add_explicit(&zdplane_info.dg_macs_in, 1,
3912 memory_order_relaxed);
3913
3914 if (ret == AOK)
3915 result = ZEBRA_DPLANE_REQUEST_QUEUED;
3916 else {
3917 /* Error counter */
3918 atomic_fetch_add_explicit(&zdplane_info.dg_mac_errors, 1,
3919 memory_order_relaxed);
3920 dplane_ctx_free(&ctx);
3921 }
3922
3923 return result;
3924}
3925
931fa60c
MS
3926/*
3927 * Enqueue evpn neighbor add for the dataplane.
3928 */
f188e68e 3929enum zebra_dplane_result dplane_rem_neigh_add(const struct interface *ifp,
931fa60c
MS
3930 const struct ipaddr *ip,
3931 const struct ethaddr *mac,
f188e68e 3932 uint32_t flags, bool was_static)
931fa60c
MS
3933{
3934 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
f188e68e
AK
3935 uint32_t update_flags = 0;
3936
3937 update_flags |= DPLANE_NEIGH_REMOTE;
3938
3939 if (was_static)
3940 update_flags |= DPLANE_NEIGH_WAS_STATIC;
931fa60c 3941
0a27a2fe
PG
3942 result = neigh_update_internal(
3943 DPLANE_OP_NEIGH_INSTALL, ifp, (const void *)mac, AF_ETHERNET,
88217099 3944 ip, flags, DPLANE_NUD_NOARP, update_flags, 0);
f188e68e
AK
3945
3946 return result;
3947}
3948
3949/*
3950 * Enqueue local neighbor add for the dataplane.
3951 */
3952enum zebra_dplane_result dplane_local_neigh_add(const struct interface *ifp,
931fa60c
MS
3953 const struct ipaddr *ip,
3954 const struct ethaddr *mac,
f188e68e
AK
3955 bool set_router, bool set_static,
3956 bool set_inactive)
931fa60c
MS
3957{
3958 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
f188e68e
AK
3959 uint32_t update_flags = 0;
3960 uint32_t ntf = 0;
3961 uint16_t state;
3962
3963 if (set_static)
3964 update_flags |= DPLANE_NEIGH_SET_STATIC;
3965
3966 if (set_inactive) {
3967 update_flags |= DPLANE_NEIGH_SET_INACTIVE;
3968 state = DPLANE_NUD_STALE;
3969 } else {
3970 state = DPLANE_NUD_REACHABLE;
3971 }
3972
3973 if (set_router)
3974 ntf |= DPLANE_NTF_ROUTER;
931fa60c 3975
0a27a2fe
PG
3976 result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL, ifp,
3977 (const void *)mac, AF_ETHERNET, ip, ntf,
88217099 3978 state, update_flags, 0);
931fa60c
MS
3979
3980 return result;
3981}
3982
931fa60c
MS
3983/*
3984 * Enqueue evpn neighbor delete for the dataplane.
3985 */
f188e68e 3986enum zebra_dplane_result dplane_rem_neigh_delete(const struct interface *ifp,
931fa60c
MS
3987 const struct ipaddr *ip)
3988{
0bbd4ff4 3989 enum zebra_dplane_result result;
f188e68e
AK
3990 uint32_t update_flags = 0;
3991
3992 update_flags |= DPLANE_NEIGH_REMOTE;
931fa60c 3993
0a27a2fe 3994 result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE, ifp, NULL,
88217099 3995 AF_ETHERNET, ip, 0, 0, update_flags, 0);
931fa60c
MS
3996
3997 return result;
3998}
3999
0bbd4ff4
MS
4000/*
4001 * Enqueue evpn VTEP add for the dataplane.
4002 */
4003enum zebra_dplane_result dplane_vtep_add(const struct interface *ifp,
4004 const struct in_addr *ip,
4005 vni_t vni)
4006{
4007 enum zebra_dplane_result result;
4008 struct ethaddr mac = { {0, 0, 0, 0, 0, 0} };
4009 struct ipaddr addr;
4010
4011 if (IS_ZEBRA_DEBUG_VXLAN)
9bcef951
MS
4012 zlog_debug("Install %pI4 into flood list for VNI %u intf %s(%u)",
4013 ip, vni, ifp->name, ifp->ifindex);
0bbd4ff4
MS
4014
4015 SET_IPADDR_V4(&addr);
4016 addr.ipaddr_v4 = *ip;
4017
0a27a2fe 4018 result = neigh_update_internal(DPLANE_OP_VTEP_ADD, ifp, &mac,
88217099 4019 AF_ETHERNET, &addr, 0, 0, 0, 0);
0bbd4ff4
MS
4020
4021 return result;
4022}
4023
4024/*
4025 * Enqueue evpn VTEP add for the dataplane.
4026 */
4027enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
4028 const struct in_addr *ip,
4029 vni_t vni)
4030{
4031 enum zebra_dplane_result result;
4032 struct ethaddr mac = { {0, 0, 0, 0, 0, 0} };
4033 struct ipaddr addr;
4034
4035 if (IS_ZEBRA_DEBUG_VXLAN)
4036 zlog_debug(
9bcef951
MS
4037 "Uninstall %pI4 from flood list for VNI %u intf %s(%u)",
4038 ip, vni, ifp->name, ifp->ifindex);
0bbd4ff4
MS
4039
4040 SET_IPADDR_V4(&addr);
4041 addr.ipaddr_v4 = *ip;
4042
0a27a2fe
PG
4043 result = neigh_update_internal(DPLANE_OP_VTEP_DELETE, ifp,
4044 (const void *)&mac, AF_ETHERNET, &addr,
88217099 4045 0, 0, 0, 0);
0bbd4ff4
MS
4046
4047 return result;
4048}
4049
d68e74b4
JU
4050enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
4051 const struct ipaddr *ip)
4052{
4053 enum zebra_dplane_result result;
4054
0a27a2fe
PG
4055 result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL,
4056 AF_ETHERNET, ip, DPLANE_NTF_USE,
88217099 4057 DPLANE_NUD_INCOMPLETE, 0, 0);
d68e74b4
JU
4058
4059 return result;
4060}
4061
e18747a9
PG
4062enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp,
4063 const uint8_t family,
4064 const uint32_t app_probes,
4065 const uint32_t ucast_probes,
4066 const uint32_t mcast_probes)
4067{
4068 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4069 int ret;
4070 struct zebra_dplane_ctx *ctx = NULL;
4071 struct zebra_ns *zns;
4072 enum dplane_op_e op = DPLANE_OP_NEIGH_TABLE_UPDATE;
4073
4074 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
4075 zlog_debug("set neigh ctx %s: ifp %s, family %s",
4076 dplane_op2str(op), ifp->name, family2str(family));
4077 }
4078
4079 ctx = dplane_ctx_alloc();
4080
4081 ctx->zd_op = op;
4082 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
4083 ctx->zd_vrf_id = ifp->vrf_id;
4084
4085 zns = zebra_ns_lookup(ifp->vrf_id);
4086 dplane_ctx_ns_init(ctx, zns, false);
4087
4088 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
4089 ctx->zd_ifindex = ifp->ifindex;
4090
4091 /* Init the neighbor-specific data area */
4092 memset(&ctx->u.neightable, 0, sizeof(ctx->u.neightable));
4093
4094 ctx->u.neightable.family = family;
4095 ctx->u.neightable.app_probes = app_probes;
4096 ctx->u.neightable.ucast_probes = ucast_probes;
4097 ctx->u.neightable.mcast_probes = mcast_probes;
4098
4099 /* Enqueue for processing on the dplane pthread */
4100 ret = dplane_update_enqueue(ctx);
4101
4102 /* Increment counter */
4103 atomic_fetch_add_explicit(&zdplane_info.dg_neightable_in, 1,
4104 memory_order_relaxed);
4105
4106 if (ret == AOK)
4107 result = ZEBRA_DPLANE_REQUEST_QUEUED;
4108 else {
4109 /* Error counter */
4110 atomic_fetch_add_explicit(&zdplane_info.dg_neightable_errors, 1,
4111 memory_order_relaxed);
4112 dplane_ctx_free(&ctx);
4113 }
4114
4115 return result;
4116}
4117
931fa60c 4118/*
d68e74b4 4119 * Common helper api for neighbor updates
931fa60c
MS
4120 */
4121static enum zebra_dplane_result
0a27a2fe
PG
4122neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
4123 const void *link, const int link_family,
4124 const struct ipaddr *ip, uint32_t flags, uint16_t state,
4125 uint32_t update_flags, int protocol)
931fa60c
MS
4126{
4127 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4128 int ret;
4129 struct zebra_dplane_ctx *ctx = NULL;
4130 struct zebra_ns *zns;
0a27a2fe
PG
4131 const struct ethaddr *mac = NULL;
4132 const struct ipaddr *link_ip = NULL;
931fa60c 4133
0a27a2fe
PG
4134 if (link_family == AF_ETHERNET)
4135 mac = (const struct ethaddr *)link;
4136 else
4137 link_ip = (const struct ipaddr *)link;
4138
4139 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
4140 char buf1[PREFIX_STRLEN];
4141
4142 buf1[0] = '\0';
4143 if (link_family == AF_ETHERNET)
4144 prefix_mac2str(mac, buf1, sizeof(buf1));
4145 else
4146 ipaddr2str(link_ip, buf1, sizeof(buf1));
4147 zlog_debug("init neigh ctx %s: ifp %s, %s %s, ip %pIA",
4148 dplane_op2str(op), ifp->name,
4149 link_family == AF_ETHERNET ? "mac " : "link ",
4150 buf1, ip);
4151 }
931fa60c
MS
4152
4153 ctx = dplane_ctx_alloc();
4154
4155 ctx->zd_op = op;
4156 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
4157 ctx->zd_vrf_id = ifp->vrf_id;
0a27a2fe 4158 dplane_ctx_set_type(ctx, protocol);
931fa60c
MS
4159
4160 zns = zebra_ns_lookup(ifp->vrf_id);
4161 dplane_ctx_ns_init(ctx, zns, false);
4162
4163 strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
4164 ctx->zd_ifindex = ifp->ifindex;
4165
4166 /* Init the neighbor-specific data area */
4167 memset(&ctx->u.neigh, 0, sizeof(ctx->u.neigh));
4168
4169 ctx->u.neigh.ip_addr = *ip;
4170 if (mac)
0a27a2fe
PG
4171 ctx->u.neigh.link.mac = *mac;
4172 else if (link_ip)
4173 ctx->u.neigh.link.ip_addr = *link_ip;
4174
931fa60c
MS
4175 ctx->u.neigh.flags = flags;
4176 ctx->u.neigh.state = state;
f188e68e 4177 ctx->u.neigh.update_flags = update_flags;
931fa60c
MS
4178
4179 /* Enqueue for processing on the dplane pthread */
4180 ret = dplane_update_enqueue(ctx);
4181
4182 /* Increment counter */
4183 atomic_fetch_add_explicit(&zdplane_info.dg_neighs_in, 1,
4184 memory_order_relaxed);
4185
4186 if (ret == AOK)
4187 result = ZEBRA_DPLANE_REQUEST_QUEUED;
4188 else {
4189 /* Error counter */
4190 atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors, 1,
4191 memory_order_relaxed);
4192 dplane_ctx_free(&ctx);
4193 }
4194
4195 return result;
4196}
4197
f62e5480
JU
4198/*
4199 * Common helper api for PBR rule updates
4200 */
4201static enum zebra_dplane_result
4202rule_update_internal(enum dplane_op_e op, struct zebra_pbr_rule *new_rule,
4203 struct zebra_pbr_rule *old_rule)
4204{
4205 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4206 struct zebra_dplane_ctx *ctx;
4207 int ret;
4208
4209 ctx = dplane_ctx_alloc();
4210
4211 ret = dplane_ctx_rule_init(ctx, op, new_rule, old_rule);
4212 if (ret != AOK)
4213 goto done;
4214
4215 ret = dplane_update_enqueue(ctx);
4216
4217done:
4218 atomic_fetch_add_explicit(&zdplane_info.dg_rules_in, 1,
4219 memory_order_relaxed);
4220
4221 if (ret == AOK)
4222 result = ZEBRA_DPLANE_REQUEST_QUEUED;
4223 else {
4224 atomic_fetch_add_explicit(&zdplane_info.dg_rule_errors, 1,
4225 memory_order_relaxed);
4226 dplane_ctx_free(&ctx);
4227 }
4228
4229 return result;
4230}
4231
4232enum zebra_dplane_result dplane_pbr_rule_add(struct zebra_pbr_rule *rule)
4233{
4234 return rule_update_internal(DPLANE_OP_RULE_ADD, rule, NULL);
4235}
4236
4237enum zebra_dplane_result dplane_pbr_rule_delete(struct zebra_pbr_rule *rule)
4238{
4239 return rule_update_internal(DPLANE_OP_RULE_DELETE, rule, NULL);
4240}
4241
4242enum zebra_dplane_result dplane_pbr_rule_update(struct zebra_pbr_rule *old_rule,
4243 struct zebra_pbr_rule *new_rule)
4244{
4245 return rule_update_internal(DPLANE_OP_RULE_UPDATE, new_rule, old_rule);
4246}
5162e000
PG
4247/*
4248 * Common helper api for iptable updates
4249 */
4250static enum zebra_dplane_result
4251iptable_update_internal(enum dplane_op_e op, struct zebra_pbr_iptable *iptable)
4252{
4253 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4254 struct zebra_dplane_ctx *ctx;
4255 int ret;
4256
4257 ctx = dplane_ctx_alloc();
4258
4259 ret = dplane_ctx_iptable_init(ctx, op, iptable);
4260 if (ret != AOK)
4261 goto done;
4262
4263 ret = dplane_update_enqueue(ctx);
4264
4265done:
4266 atomic_fetch_add_explicit(&zdplane_info.dg_iptable_in, 1,
4267 memory_order_relaxed);
4268
4269 if (ret == AOK)
4270 result = ZEBRA_DPLANE_REQUEST_QUEUED;
4271 else {
4272 atomic_fetch_add_explicit(&zdplane_info.dg_iptable_errors, 1,
4273 memory_order_relaxed);
4274 dplane_ctx_free(&ctx);
4275 }
4276
4277 return result;
4278}
4279
4280enum zebra_dplane_result
4281dplane_pbr_iptable_add(struct zebra_pbr_iptable *iptable)
4282{
4283 return iptable_update_internal(DPLANE_OP_IPTABLE_ADD, iptable);
4284}
4285
4286enum zebra_dplane_result
4287dplane_pbr_iptable_delete(struct zebra_pbr_iptable *iptable)
4288{
4289 return iptable_update_internal(DPLANE_OP_IPTABLE_DELETE, iptable);
4290}
f62e5480 4291
ef524230
PG
4292/*
4293 * Common helper api for ipset updates
4294 */
4295static enum zebra_dplane_result
4296ipset_update_internal(enum dplane_op_e op, struct zebra_pbr_ipset *ipset)
4297{
4298 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4299 struct zebra_dplane_ctx *ctx;
4300 int ret;
4301
4302 ctx = dplane_ctx_alloc();
4303
4304 ret = dplane_ctx_ipset_init(ctx, op, ipset);
4305 if (ret != AOK)
4306 goto done;
4307
4308 ret = dplane_update_enqueue(ctx);
4309
4310done:
4311 atomic_fetch_add_explicit(&zdplane_info.dg_ipset_in, 1,
4312 memory_order_relaxed);
4313
4314 if (ret == AOK)
4315 result = ZEBRA_DPLANE_REQUEST_QUEUED;
4316 else {
4317 atomic_fetch_add_explicit(&zdplane_info.dg_ipset_errors, 1,
4318 memory_order_relaxed);
4319 dplane_ctx_free(&ctx);
4320 }
4321
4322 return result;
4323}
4324
4325enum zebra_dplane_result dplane_pbr_ipset_add(struct zebra_pbr_ipset *ipset)
4326{
4327 return ipset_update_internal(DPLANE_OP_IPSET_ADD, ipset);
4328}
4329
4330enum zebra_dplane_result dplane_pbr_ipset_delete(struct zebra_pbr_ipset *ipset)
4331{
4332 return ipset_update_internal(DPLANE_OP_IPSET_DELETE, ipset);
4333}
4334
4335/*
4336 * Common helper api for ipset updates
4337 */
4338static enum zebra_dplane_result
4339ipset_entry_update_internal(enum dplane_op_e op,
4340 struct zebra_pbr_ipset_entry *ipset_entry)
4341{
4342 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4343 struct zebra_dplane_ctx *ctx;
4344 int ret;
4345
4346 ctx = dplane_ctx_alloc();
4347
4348 ret = dplane_ctx_ipset_entry_init(ctx, op, ipset_entry);
4349 if (ret != AOK)
4350 goto done;
4351
4352 ret = dplane_update_enqueue(ctx);
4353
4354done:
4355 atomic_fetch_add_explicit(&zdplane_info.dg_ipset_entry_in, 1,
4356 memory_order_relaxed);
4357
4358 if (ret == AOK)
4359 result = ZEBRA_DPLANE_REQUEST_QUEUED;
4360 else {
4361 atomic_fetch_add_explicit(&zdplane_info.dg_ipset_entry_errors,
4362 1, memory_order_relaxed);
4363 dplane_ctx_free(&ctx);
4364 }
4365
4366 return result;
4367}
4368
4369enum zebra_dplane_result
4370dplane_pbr_ipset_entry_add(struct zebra_pbr_ipset_entry *ipset)
4371{
4372 return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_ADD, ipset);
4373}
4374
4375enum zebra_dplane_result
4376dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset)
4377{
4378 return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_DELETE, ipset);
4379}
4380
62b4b7e4
PG
4381/*
4382 * Common helper api for GRE set
4383 */
4384enum zebra_dplane_result
e3d3fa06
PG
4385dplane_gre_set(struct interface *ifp, struct interface *ifp_link,
4386 unsigned int mtu, const struct zebra_l2info_gre *gre_info)
62b4b7e4
PG
4387{
4388 enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4389 struct zebra_dplane_ctx *ctx;
4390 enum dplane_op_e op = DPLANE_OP_GRE_SET;
4391 int ret;
4392 struct zebra_ns *zns;
4393
4394 ctx = dplane_ctx_alloc();
4395
4396 if (!ifp)
4397 return result;
4398
4399 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
4400 zlog_debug("init dplane ctx %s: if %s link %s%s",
4401 dplane_op2str(op), ifp->name,
4402 ifp_link ? "set" : "unset", ifp_link ?
4403 ifp_link->name : "");
4404 }
4405
4406 ctx->zd_op = op;
4407 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
4408 zns = zebra_ns_lookup(ifp->vrf_id);
4409 if (!zns)
4410 return result;
4411 dplane_ctx_ns_init(ctx, zns, false);
4412
4413 dplane_ctx_set_ifname(ctx, ifp->name);
4414 ctx->zd_vrf_id = ifp->vrf_id;
4415 ctx->zd_ifindex = ifp->ifindex;
4416 if (ifp_link)
4417 ctx->u.gre.link_ifindex = ifp_link->ifindex;
4418 else
4419 ctx->u.gre.link_ifindex = 0;
e3d3fa06
PG
4420 if (gre_info)
4421 memcpy(&ctx->u.gre.info, gre_info, sizeof(ctx->u.gre.info));
db51f0cd
PG
4422 ctx->u.gre.mtu = mtu;
4423
62b4b7e4
PG
4424 ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
4425
4426 /* Enqueue context for processing */
4427 ret = dplane_update_enqueue(ctx);
4428
4429 /* Update counter */
4430 atomic_fetch_add_explicit(&zdplane_info.dg_gre_set_in, 1,
4431 memory_order_relaxed);
4432
4433 if (ret == AOK)
4434 result = ZEBRA_DPLANE_REQUEST_QUEUED;
4435 else {
4436 atomic_fetch_add_explicit(
4437 &zdplane_info.dg_gre_set_errors, 1,
4438 memory_order_relaxed);
4439 if (ctx)
4440 dplane_ctx_free(&ctx);
4441 result = ZEBRA_DPLANE_REQUEST_FAILURE;
4442 }
4443 return result;
4444}
4445
1d11b21f
MS
4446/*
4447 * Handler for 'show dplane'
4448 */
4449int dplane_show_helper(struct vty *vty, bool detailed)
4450{
16c628de
MS
4451 uint64_t queued, queue_max, limit, errs, incoming, yields,
4452 other_errs;
1d11b21f 4453
4dfd7a02 4454 /* Using atomics because counters are being changed in different
c831033f 4455 * pthread contexts.
4dfd7a02 4456 */
25779064 4457 incoming = atomic_load_explicit(&zdplane_info.dg_routes_in,
1d11b21f 4458 memory_order_relaxed);
91f16812
MS
4459 limit = atomic_load_explicit(&zdplane_info.dg_max_queued_updates,
4460 memory_order_relaxed);
25779064 4461 queued = atomic_load_explicit(&zdplane_info.dg_routes_queued,
1d11b21f 4462 memory_order_relaxed);
25779064 4463 queue_max = atomic_load_explicit(&zdplane_info.dg_routes_queued_max,
4dfd7a02 4464 memory_order_relaxed);
25779064 4465 errs = atomic_load_explicit(&zdplane_info.dg_route_errors,
1d11b21f 4466 memory_order_relaxed);
c831033f
MS
4467 yields = atomic_load_explicit(&zdplane_info.dg_update_yields,
4468 memory_order_relaxed);
16c628de
MS
4469 other_errs = atomic_load_explicit(&zdplane_info.dg_other_errors,
4470 memory_order_relaxed);
1d11b21f 4471
c831033f
MS
4472 vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n",
4473 incoming);
1d11b21f 4474 vty_out(vty, "Route update errors: %"PRIu64"\n", errs);
16c628de 4475 vty_out(vty, "Other errors : %"PRIu64"\n", other_errs);
91f16812 4476 vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit);
1d11b21f 4477 vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued);
4dfd7a02 4478 vty_out(vty, "Route update queue max: %"PRIu64"\n", queue_max);
4280d91c
MS
4479 vty_out(vty, "Dplane update yields: %"PRIu64"\n", yields);
4480
4481 incoming = atomic_load_explicit(&zdplane_info.dg_lsps_in,
4482 memory_order_relaxed);
4483 errs = atomic_load_explicit(&zdplane_info.dg_lsp_errors,
4484 memory_order_relaxed);
4485 vty_out(vty, "LSP updates: %"PRIu64"\n", incoming);
4486 vty_out(vty, "LSP update errors: %"PRIu64"\n", errs);
4487
4488 incoming = atomic_load_explicit(&zdplane_info.dg_pws_in,
4489 memory_order_relaxed);
4490 errs = atomic_load_explicit(&zdplane_info.dg_pw_errors,
4491 memory_order_relaxed);
4492 vty_out(vty, "PW updates: %"PRIu64"\n", incoming);
4493 vty_out(vty, "PW update errors: %"PRIu64"\n", errs);
4494
4495 incoming = atomic_load_explicit(&zdplane_info.dg_intf_addrs_in,
4496 memory_order_relaxed);
4497 errs = atomic_load_explicit(&zdplane_info.dg_intf_addr_errors,
4498 memory_order_relaxed);
4499 vty_out(vty, "Intf addr updates: %"PRIu64"\n", incoming);
4500 vty_out(vty, "Intf addr errors: %"PRIu64"\n", errs);
4501
4502 incoming = atomic_load_explicit(&zdplane_info.dg_macs_in,
4503 memory_order_relaxed);
4504 errs = atomic_load_explicit(&zdplane_info.dg_mac_errors,
4505 memory_order_relaxed);
4506 vty_out(vty, "EVPN MAC updates: %"PRIu64"\n", incoming);
4507 vty_out(vty, "EVPN MAC errors: %"PRIu64"\n", errs);
1d11b21f 4508
931fa60c
MS
4509 incoming = atomic_load_explicit(&zdplane_info.dg_neighs_in,
4510 memory_order_relaxed);
4511 errs = atomic_load_explicit(&zdplane_info.dg_neigh_errors,
4512 memory_order_relaxed);
4513 vty_out(vty, "EVPN neigh updates: %"PRIu64"\n", incoming);
4514 vty_out(vty, "EVPN neigh errors: %"PRIu64"\n", errs);
4515
60d8d43b
JU
4516 incoming = atomic_load_explicit(&zdplane_info.dg_rules_in,
4517 memory_order_relaxed);
4518 errs = atomic_load_explicit(&zdplane_info.dg_rule_errors,
4519 memory_order_relaxed);
4520 vty_out(vty, "Rule updates: %" PRIu64 "\n", incoming);
4521 vty_out(vty, "Rule errors: %" PRIu64 "\n", errs);
4522
c60522f7
AK
4523 incoming = atomic_load_explicit(&zdplane_info.dg_br_port_in,
4524 memory_order_relaxed);
4525 errs = atomic_load_explicit(&zdplane_info.dg_br_port_errors,
4526 memory_order_relaxed);
4527 vty_out(vty, "Bridge port updates: %" PRIu64 "\n", incoming);
4528 vty_out(vty, "Bridge port errors: %" PRIu64 "\n", errs);
4529
5162e000
PG
4530 incoming = atomic_load_explicit(&zdplane_info.dg_iptable_in,
4531 memory_order_relaxed);
4532 errs = atomic_load_explicit(&zdplane_info.dg_iptable_errors,
4533 memory_order_relaxed);
4534 vty_out(vty, "IPtable updates: %" PRIu64 "\n", incoming);
4535 vty_out(vty, "IPtable errors: %" PRIu64 "\n", errs);
ef524230
PG
4536 incoming = atomic_load_explicit(&zdplane_info.dg_ipset_in,
4537 memory_order_relaxed);
4538 errs = atomic_load_explicit(&zdplane_info.dg_ipset_errors,
4539 memory_order_relaxed);
4540 vty_out(vty, "IPset updates: %" PRIu64 "\n", incoming);
4541 vty_out(vty, "IPset errors: %" PRIu64 "\n", errs);
4542 incoming = atomic_load_explicit(&zdplane_info.dg_ipset_entry_in,
4543 memory_order_relaxed);
4544 errs = atomic_load_explicit(&zdplane_info.dg_ipset_entry_errors,
4545 memory_order_relaxed);
4546 vty_out(vty, "IPset entry updates: %" PRIu64 "\n", incoming);
4547 vty_out(vty, "IPset entry errors: %" PRIu64 "\n", errs);
e18747a9
PG
4548
4549 incoming = atomic_load_explicit(&zdplane_info.dg_neightable_in,
4550 memory_order_relaxed);
4551 errs = atomic_load_explicit(&zdplane_info.dg_neightable_errors,
4552 memory_order_relaxed);
4553 vty_out(vty, "Neighbor Table updates: %"PRIu64"\n", incoming);
4554 vty_out(vty, "Neighbor Table errors: %"PRIu64"\n", errs);
62b4b7e4
PG
4555
4556 incoming = atomic_load_explicit(&zdplane_info.dg_gre_set_in,
4557 memory_order_relaxed);
4558 errs = atomic_load_explicit(&zdplane_info.dg_gre_set_errors,
4559 memory_order_relaxed);
4560 vty_out(vty, "GRE set updates: %"PRIu64"\n", incoming);
4561 vty_out(vty, "GRE set errors: %"PRIu64"\n", errs);
1d11b21f
MS
4562 return CMD_SUCCESS;
4563}
4564
4565/*
4566 * Handler for 'show dplane providers'
4567 */
4568int dplane_show_provs_helper(struct vty *vty, bool detailed)
4569{
c831033f 4570 struct zebra_dplane_provider *prov;
a88a7c8d 4571 uint64_t in, in_q, in_max, out, out_q, out_max;
c831033f
MS
4572
4573 vty_out(vty, "Zebra dataplane providers:\n");
4574
4575 DPLANE_LOCK();
4576 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
4577 DPLANE_UNLOCK();
4578
4579 /* Show counters, useful info from each registered provider */
4580 while (prov) {
4581
4582 in = atomic_load_explicit(&prov->dp_in_counter,
4583 memory_order_relaxed);
a88a7c8d
MS
4584 in_q = atomic_load_explicit(&prov->dp_in_queued,
4585 memory_order_relaxed);
c831033f
MS
4586 in_max = atomic_load_explicit(&prov->dp_in_max,
4587 memory_order_relaxed);
4588 out = atomic_load_explicit(&prov->dp_out_counter,
4589 memory_order_relaxed);
a88a7c8d
MS
4590 out_q = atomic_load_explicit(&prov->dp_out_queued,
4591 memory_order_relaxed);
c831033f
MS
4592 out_max = atomic_load_explicit(&prov->dp_out_max,
4593 memory_order_relaxed);
4594
a88a7c8d
MS
4595 vty_out(vty, "%s (%u): in: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64", out: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64"\n",
4596 prov->dp_name, prov->dp_id, in, in_q, in_max,
4597 out, out_q, out_max);
c831033f
MS
4598
4599 DPLANE_LOCK();
4600 prov = TAILQ_NEXT(prov, dp_prov_link);
4601 DPLANE_UNLOCK();
4602 }
1d11b21f
MS
4603
4604 return CMD_SUCCESS;
4605}
4606
f26730e1
MS
4607/*
4608 * Helper for 'show run' etc.
4609 */
4610int dplane_config_write_helper(struct vty *vty)
4611{
4612 if (zdplane_info.dg_max_queued_updates != DPLANE_DEFAULT_MAX_QUEUED)
4613 vty_out(vty, "zebra dplane limit %u\n",
4614 zdplane_info.dg_max_queued_updates);
4615
4616 return 0;
4617}
4618
b8e0423d
MS
4619/*
4620 * Provider registration
4621 */
4622int dplane_provider_register(const char *name,
c831033f
MS
4623 enum dplane_provider_prio prio,
4624 int flags,
1dd4ea8a 4625 int (*start_fp)(struct zebra_dplane_provider *),
4c206c8f
MS
4626 int (*fp)(struct zebra_dplane_provider *),
4627 int (*fini_fp)(struct zebra_dplane_provider *,
4628 bool early),
1ff8a248
MS
4629 void *data,
4630 struct zebra_dplane_provider **prov_p)
b8e0423d
MS
4631{
4632 int ret = 0;
6fb51ccb 4633 struct zebra_dplane_provider *p = NULL, *last;
b8e0423d
MS
4634
4635 /* Validate */
4636 if (fp == NULL) {
4637 ret = EINVAL;
4638 goto done;
4639 }
4640
4641 if (prio <= DPLANE_PRIO_NONE ||
1bcea841 4642 prio > DPLANE_PRIO_LAST) {
b8e0423d
MS
4643 ret = EINVAL;
4644 goto done;
4645 }
4646
4647 /* Allocate and init new provider struct */
25779064 4648 p = XCALLOC(MTYPE_DP_PROV, sizeof(struct zebra_dplane_provider));
b8e0423d 4649
c831033f
MS
4650 pthread_mutex_init(&(p->dp_mutex), NULL);
4651 TAILQ_INIT(&(p->dp_ctx_in_q));
4652 TAILQ_INIT(&(p->dp_ctx_out_q));
b8e0423d 4653
932dbb4d 4654 p->dp_flags = flags;
b8e0423d
MS
4655 p->dp_priority = prio;
4656 p->dp_fp = fp;
1dd4ea8a 4657 p->dp_start = start_fp;
18c37974 4658 p->dp_fini = fini_fp;
c831033f 4659 p->dp_data = data;
18c37974 4660
c831033f 4661 /* Lock - the dplane pthread may be running */
18c37974 4662 DPLANE_LOCK();
b8e0423d 4663
25779064 4664 p->dp_id = ++zdplane_info.dg_provider_id;
b8e0423d 4665
c831033f
MS
4666 if (name)
4667 strlcpy(p->dp_name, name, DPLANE_PROVIDER_NAMELEN);
4668 else
4669 snprintf(p->dp_name, DPLANE_PROVIDER_NAMELEN,
4670 "provider-%u", p->dp_id);
4671
b8e0423d 4672 /* Insert into list ordered by priority */
c831033f 4673 TAILQ_FOREACH(last, &zdplane_info.dg_providers_q, dp_prov_link) {
5709131c 4674 if (last->dp_priority > p->dp_priority)
b8e0423d 4675 break;
b8e0423d
MS
4676 }
4677
5709131c 4678 if (last)
c831033f 4679 TAILQ_INSERT_BEFORE(last, p, dp_prov_link);
5709131c 4680 else
25779064 4681 TAILQ_INSERT_TAIL(&zdplane_info.dg_providers_q, p,
c831033f 4682 dp_prov_link);
b8e0423d 4683
18c37974
MS
4684 /* And unlock */
4685 DPLANE_UNLOCK();
4686
c831033f
MS
4687 if (IS_ZEBRA_DEBUG_DPLANE)
4688 zlog_debug("dplane: registered new provider '%s' (%u), prio %d",
4689 p->dp_name, p->dp_id, p->dp_priority);
4690
b8e0423d 4691done:
1ff8a248
MS
4692 if (prov_p)
4693 *prov_p = p;
4694
5709131c 4695 return ret;
b8e0423d
MS
4696}
4697
c831033f
MS
4698/* Accessors for provider attributes */
4699const char *dplane_provider_get_name(const struct zebra_dplane_provider *prov)
4700{
4701 return prov->dp_name;
4702}
4703
4704uint32_t dplane_provider_get_id(const struct zebra_dplane_provider *prov)
4705{
4706 return prov->dp_id;
4707}
4708
4709void *dplane_provider_get_data(const struct zebra_dplane_provider *prov)
4710{
4711 return prov->dp_data;
4712}
4713
4714int dplane_provider_get_work_limit(const struct zebra_dplane_provider *prov)
4715{
4716 return zdplane_info.dg_updates_per_cycle;
4717}
4718
ad6aad4d
MS
4719/* Lock/unlock a provider's mutex - iff the provider was registered with
4720 * the THREADED flag.
4721 */
4722void dplane_provider_lock(struct zebra_dplane_provider *prov)
4723{
4724 if (dplane_provider_is_threaded(prov))
4725 DPLANE_PROV_LOCK(prov);
4726}
4727
4728void dplane_provider_unlock(struct zebra_dplane_provider *prov)
4729{
4730 if (dplane_provider_is_threaded(prov))
4731 DPLANE_PROV_UNLOCK(prov);
4732}
4733
c831033f
MS
4734/*
4735 * Dequeue and maintain associated counter
4736 */
4737struct zebra_dplane_ctx *dplane_provider_dequeue_in_ctx(
4738 struct zebra_dplane_provider *prov)
4739{
4740 struct zebra_dplane_ctx *ctx = NULL;
4741
ad6aad4d 4742 dplane_provider_lock(prov);
c831033f
MS
4743
4744 ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
4745 if (ctx) {
4746 TAILQ_REMOVE(&(prov->dp_ctx_in_q), ctx, zd_q_entries);
c9d17fe8
MS
4747
4748 atomic_fetch_sub_explicit(&prov->dp_in_queued, 1,
4749 memory_order_relaxed);
c831033f
MS
4750 }
4751
ad6aad4d 4752 dplane_provider_unlock(prov);
c831033f
MS
4753
4754 return ctx;
4755}
4756
4757/*
4758 * Dequeue work to a list, return count
4759 */
4760int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov,
4761 struct dplane_ctx_q *listp)
4762{
4763 int limit, ret;
4764 struct zebra_dplane_ctx *ctx;
4765
4766 limit = zdplane_info.dg_updates_per_cycle;
4767
ad6aad4d 4768 dplane_provider_lock(prov);
c831033f
MS
4769
4770 for (ret = 0; ret < limit; ret++) {
4771 ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
4772 if (ctx) {
4773 TAILQ_REMOVE(&(prov->dp_ctx_in_q), ctx, zd_q_entries);
4774
4775 TAILQ_INSERT_TAIL(listp, ctx, zd_q_entries);
4776 } else {
4777 break;
4778 }
4779 }
4780
c9d17fe8
MS
4781 if (ret > 0)
4782 atomic_fetch_sub_explicit(&prov->dp_in_queued, ret,
4783 memory_order_relaxed);
4784
ad6aad4d 4785 dplane_provider_unlock(prov);
c831033f
MS
4786
4787 return ret;
4788}
4789
53706b4e
DE
4790uint32_t dplane_provider_out_ctx_queue_len(struct zebra_dplane_provider *prov)
4791{
4792 return atomic_load_explicit(&(prov->dp_out_counter),
4793 memory_order_relaxed);
4794}
4795
c831033f
MS
4796/*
4797 * Enqueue and maintain associated counter
4798 */
4799void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
4800 struct zebra_dplane_ctx *ctx)
4801{
a88a7c8d
MS
4802 uint64_t curr, high;
4803
ad6aad4d 4804 dplane_provider_lock(prov);
c831033f
MS
4805
4806 TAILQ_INSERT_TAIL(&(prov->dp_ctx_out_q), ctx,
4807 zd_q_entries);
4808
a88a7c8d
MS
4809 /* Maintain out-queue counters */
4810 atomic_fetch_add_explicit(&(prov->dp_out_queued), 1,
4811 memory_order_relaxed);
4812 curr = atomic_load_explicit(&prov->dp_out_queued,
4813 memory_order_relaxed);
4814 high = atomic_load_explicit(&prov->dp_out_max,
4815 memory_order_relaxed);
4816 if (curr > high)
4817 atomic_store_explicit(&prov->dp_out_max, curr,
4818 memory_order_relaxed);
4819
ad6aad4d 4820 dplane_provider_unlock(prov);
c831033f
MS
4821
4822 atomic_fetch_add_explicit(&(prov->dp_out_counter), 1,
4823 memory_order_relaxed);
4824}
4825
62b8bb7a
MS
4826/*
4827 * Accessor for provider object
4828 */
c831033f
MS
4829bool dplane_provider_is_threaded(const struct zebra_dplane_provider *prov)
4830{
4831 return (prov->dp_flags & DPLANE_PROV_FLAG_THREADED);
4832}
4833
62b8bb7a
MS
4834/*
4835 * Internal helper that copies information from a zebra ns object; this is
4836 * called in the zebra main pthread context as part of dplane ctx init.
4837 */
4838static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
4839 struct zebra_ns *zns)
4840{
4841 ns_info->ns_id = zns->ns_id;
4842
4843#if defined(HAVE_NETLINK)
4844 ns_info->is_cmd = true;
80dcc388 4845 ns_info->nls = zns->netlink_dplane_out;
62b8bb7a
MS
4846#endif /* NETLINK */
4847}
4848
d166308b
MS
4849#ifdef HAVE_NETLINK
4850/*
4851 * Callback when an OS (netlink) incoming event read is ready. This runs
4852 * in the dplane pthread.
4853 */
4854static int dplane_incoming_read(struct thread *event)
4855{
4856 struct dplane_zns_info *zi = THREAD_ARG(event);
4857
4858 kernel_dplane_read(&zi->info);
4859
4860 /* Re-start read task */
4861 thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi,
4862 zi->info.nls.sock, &zi->t_read);
4863
4864 return 0;
4865}
4866#endif /* HAVE_NETLINK */
4867
4868/*
4869 * Notify dplane when namespaces are enabled and disabled. The dplane
4870 * needs to start and stop reading incoming events from the zns. In the
4871 * common case where vrfs are _not_ namespaces, there will only be one
4872 * of these.
4873 *
4874 * This is called in the main pthread.
4875 */
4876void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled)
4877{
4878 struct dplane_zns_info *zi;
4879
4880 if (IS_ZEBRA_DEBUG_DPLANE)
4881 zlog_debug("%s: %s for nsid %u", __func__,
4882 (enabled ? "ENABLED" : "DISABLED"), zns->ns_id);
4883
4884 /* Search for an existing zns info entry */
4885 frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
4886 if (zi->info.ns_id == zns->ns_id)
4887 break;
4888 }
4889
4890 if (enabled) {
4891 /* Create a new entry if necessary; start reading. */
4892 if (zi == NULL) {
4893 zi = XCALLOC(MTYPE_DP_NS, sizeof(*zi));
4894
4895 zi->info.ns_id = zns->ns_id;
4896
4897 zns_info_list_add_tail(&zdplane_info.dg_zns_list, zi);
4898
4899 if (IS_ZEBRA_DEBUG_DPLANE)
4900 zlog_debug("%s: nsid %u, new zi %p", __func__,
4901 zns->ns_id, zi);
4902 }
4903
4904 /* Make sure we're up-to-date with the zns object */
4905#if defined(HAVE_NETLINK)
4906 zi->info.is_cmd = false;
4907 zi->info.nls = zns->netlink_dplane_in;
4908
4909 /* Start read task for the dplane pthread. */
4910 if (zdplane_info.dg_master)
4911 thread_add_read(zdplane_info.dg_master,
4912 dplane_incoming_read, zi,
4913 zi->info.nls.sock, &zi->t_read);
4914#endif
4915 } else if (zi) {
4916 if (IS_ZEBRA_DEBUG_DPLANE)
4917 zlog_debug("%s: nsid %u, deleting zi %p", __func__,
4918 zns->ns_id, zi);
4919
4920 /* Stop reading, free memory */
4921 zns_info_list_del(&zdplane_info.dg_zns_list, zi);
4922
4923 if (zdplane_info.dg_master)
4924 thread_cancel_async(zdplane_info.dg_master, &zi->t_read,
4925 NULL);
4926
4927 XFREE(MTYPE_DP_NS, zi);
4928 }
4929}
4930
c831033f
MS
4931/*
4932 * Provider api to signal that work/events are available
4933 * for the dataplane pthread.
4934 */
4935int dplane_provider_work_ready(void)
4936{
e5a60d82
MS
4937 /* Note that during zebra startup, we may be offered work before
4938 * the dataplane pthread (and thread-master) are ready. We want to
4939 * enqueue the work, but the event-scheduling machinery may not be
4940 * available.
4941 */
4942 if (zdplane_info.dg_run) {
4943 thread_add_event(zdplane_info.dg_master,
4944 dplane_thread_loop, NULL, 0,
4945 &zdplane_info.dg_t_update);
4946 }
c831033f
MS
4947
4948 return AOK;
4949}
4950
593e4eb1
MS
4951/*
4952 * Enqueue a context directly to zebra main.
4953 */
4954void dplane_provider_enqueue_to_zebra(struct zebra_dplane_ctx *ctx)
4955{
4956 struct dplane_ctx_q temp_list;
4957
4958 /* Zebra's api takes a list, so we need to use a temporary list */
4959 TAILQ_INIT(&temp_list);
4960
4961 TAILQ_INSERT_TAIL(&temp_list, ctx, zd_q_entries);
4962 (zdplane_info.dg_results_cb)(&temp_list);
4963}
4964
7cdb1a84 4965/*
c831033f 4966 * Kernel dataplane provider
7cdb1a84 4967 */
c831033f 4968
fef24b03 4969static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
c10a646d 4970{
fef24b03 4971 char buf[PREFIX_STRLEN];
c10a646d 4972
fef24b03 4973 switch (dplane_ctx_get_op(ctx)) {
16c628de 4974
fef24b03
JU
4975 case DPLANE_OP_ROUTE_INSTALL:
4976 case DPLANE_OP_ROUTE_UPDATE:
4977 case DPLANE_OP_ROUTE_DELETE:
2dbe669b
DA
4978 zlog_debug("%u:%pFX Dplane route update ctx %p op %s",
4979 dplane_ctx_get_vrf(ctx), dplane_ctx_get_dest(ctx),
4980 ctx, dplane_op2str(dplane_ctx_get_op(ctx)));
fef24b03 4981 break;
64168803 4982
fef24b03
JU
4983 case DPLANE_OP_NH_INSTALL:
4984 case DPLANE_OP_NH_UPDATE:
4985 case DPLANE_OP_NH_DELETE:
f820d025 4986 zlog_debug("ID (%u) Dplane nexthop update ctx %p op %s",
0c8215cb 4987 dplane_ctx_get_nhe_id(ctx), ctx,
f820d025 4988 dplane_op2str(dplane_ctx_get_op(ctx)));
fef24b03 4989 break;
f820d025 4990
fef24b03
JU
4991 case DPLANE_OP_LSP_INSTALL:
4992 case DPLANE_OP_LSP_UPDATE:
4993 case DPLANE_OP_LSP_DELETE:
4994 break;
f820d025 4995
fef24b03
JU
4996 case DPLANE_OP_PW_INSTALL:
4997 case DPLANE_OP_PW_UNINSTALL:
4998 zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u",
4999 dplane_ctx_get_ifname(ctx),
5000 dplane_op2str(ctx->zd_op), dplane_ctx_get_pw_af(ctx),
5001 dplane_ctx_get_pw_local_label(ctx),
5002 dplane_ctx_get_pw_remote_label(ctx));
5003 break;
5004
5005 case DPLANE_OP_ADDR_INSTALL:
5006 case DPLANE_OP_ADDR_UNINSTALL:
2dbe669b 5007 zlog_debug("Dplane intf %s, idx %u, addr %pFX",
fef24b03 5008 dplane_op2str(dplane_ctx_get_op(ctx)),
2dbe669b
DA
5009 dplane_ctx_get_ifindex(ctx),
5010 dplane_ctx_get_intf_addr(ctx));
fef24b03 5011 break;
036d93c0 5012
fef24b03
JU
5013 case DPLANE_OP_MAC_INSTALL:
5014 case DPLANE_OP_MAC_DELETE:
036d93c0
MS
5015 prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf,
5016 sizeof(buf));
5017
5018 zlog_debug("Dplane %s, mac %s, ifindex %u",
5019 dplane_op2str(dplane_ctx_get_op(ctx)),
5020 buf, dplane_ctx_get_ifindex(ctx));
fef24b03 5021 break;
931fa60c 5022
fef24b03
JU
5023 case DPLANE_OP_NEIGH_INSTALL:
5024 case DPLANE_OP_NEIGH_UPDATE:
5025 case DPLANE_OP_NEIGH_DELETE:
5026 case DPLANE_OP_VTEP_ADD:
5027 case DPLANE_OP_VTEP_DELETE:
d68e74b4 5028 case DPLANE_OP_NEIGH_DISCOVER:
0a27a2fe
PG
5029 case DPLANE_OP_NEIGH_IP_INSTALL:
5030 case DPLANE_OP_NEIGH_IP_DELETE:
931fa60c
MS
5031 ipaddr2str(dplane_ctx_neigh_get_ipaddr(ctx), buf,
5032 sizeof(buf));
5033
5034 zlog_debug("Dplane %s, ip %s, ifindex %u",
5035 dplane_op2str(dplane_ctx_get_op(ctx)),
5036 buf, dplane_ctx_get_ifindex(ctx));
fef24b03 5037 break;
931fa60c 5038
fef24b03
JU
5039 case DPLANE_OP_RULE_ADD:
5040 case DPLANE_OP_RULE_DELETE:
5041 case DPLANE_OP_RULE_UPDATE:
f62e5480
JU
5042 zlog_debug("Dplane rule update op %s, if %s(%u), ctx %p",
5043 dplane_op2str(dplane_ctx_get_op(ctx)),
5044 dplane_ctx_get_ifname(ctx),
5045 dplane_ctx_get_ifindex(ctx), ctx);
fef24b03 5046 break;
f62e5480 5047
fef24b03
JU
5048 case DPLANE_OP_SYS_ROUTE_ADD:
5049 case DPLANE_OP_SYS_ROUTE_DELETE:
5050 case DPLANE_OP_ROUTE_NOTIFY:
5051 case DPLANE_OP_LSP_NOTIFY:
c60522f7 5052 case DPLANE_OP_BR_PORT_UPDATE:
fef24b03
JU
5053
5054 case DPLANE_OP_NONE:
5055 break;
5162e000
PG
5056
5057 case DPLANE_OP_IPTABLE_ADD:
5058 case DPLANE_OP_IPTABLE_DELETE: {
5059 struct zebra_pbr_iptable ipt;
5060
5061 if (dplane_ctx_get_pbr_iptable(ctx, &ipt))
5062 zlog_debug("Dplane iptable update op %s, unique(%u), ctx %p",
5063 dplane_op2str(dplane_ctx_get_op(ctx)), ipt.unique, ctx);
5064 } break;
ef524230
PG
5065 case DPLANE_OP_IPSET_ADD:
5066 case DPLANE_OP_IPSET_DELETE: {
5067 struct zebra_pbr_ipset ipset;
5068
5069 if (dplane_ctx_get_pbr_ipset(ctx, &ipset))
5070 zlog_debug("Dplane ipset update op %s, unique(%u), ctx %p",
5071 dplane_op2str(dplane_ctx_get_op(ctx)),
5072 ipset.unique, ctx);
5073 } break;
5074 case DPLANE_OP_IPSET_ENTRY_ADD:
5075 case DPLANE_OP_IPSET_ENTRY_DELETE: {
5076 struct zebra_pbr_ipset_entry ipent;
5077
5078 if (dplane_ctx_get_pbr_ipset_entry(ctx, &ipent))
5079 zlog_debug("Dplane ipset entry update op %s, unique(%u), ctx %p",
5080 dplane_op2str(dplane_ctx_get_op(ctx)),
5081 ipent.unique, ctx);
5082 } break;
e18747a9
PG
5083
5084 case DPLANE_OP_NEIGH_TABLE_UPDATE:
5085 zlog_debug("Dplane neigh table op %s, ifp %s, family %s",
5086 dplane_op2str(dplane_ctx_get_op(ctx)),
5087 dplane_ctx_get_ifname(ctx),
5088 family2str(dplane_ctx_neightable_get_family(ctx)));
5089 break;
62b4b7e4
PG
5090 case DPLANE_OP_GRE_SET:
5091 zlog_debug("Dplane gre set op %s, ifp %s, link %u",
5092 dplane_op2str(dplane_ctx_get_op(ctx)),
5093 dplane_ctx_get_ifname(ctx),
5094 ctx->u.gre.link_ifindex);
5095 break;
9d59df63
MS
5096
5097 case DPLANE_OP_INTF_ADDR_ADD:
5098 case DPLANE_OP_INTF_ADDR_DEL:
5099 zlog_debug("Dplane incoming op %s, intf %s, addr %pFX",
5100 dplane_op2str(dplane_ctx_get_op(ctx)),
5101 dplane_ctx_get_ifname(ctx),
5102 dplane_ctx_get_intf_addr(ctx));
5103 break;
fef24b03 5104 }
2f74a82a 5105}
f62e5480 5106
fef24b03 5107static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
2f74a82a 5108{
fef24b03
JU
5109 enum zebra_dplane_result res = dplane_ctx_get_status(ctx);
5110
2f74a82a
JU
5111 switch (dplane_ctx_get_op(ctx)) {
5112
5113 case DPLANE_OP_ROUTE_INSTALL:
5114 case DPLANE_OP_ROUTE_UPDATE:
5115 case DPLANE_OP_ROUTE_DELETE:
5116 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5117 atomic_fetch_add_explicit(&zdplane_info.dg_route_errors,
5118 1, memory_order_relaxed);
fef24b03
JU
5119
5120 if ((dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE)
5121 && (res == ZEBRA_DPLANE_REQUEST_SUCCESS)) {
5122 struct nexthop *nexthop;
5123
5124 /* Update installed nexthops to signal which have been
5125 * installed.
5126 */
5127 for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
5128 nexthop)) {
5129 if (CHECK_FLAG(nexthop->flags,
5130 NEXTHOP_FLAG_RECURSIVE))
5131 continue;
5132
5133 if (CHECK_FLAG(nexthop->flags,
5134 NEXTHOP_FLAG_ACTIVE)) {
5135 SET_FLAG(nexthop->flags,
5136 NEXTHOP_FLAG_FIB);
5137 }
5138 }
5139 }
2f74a82a
JU
5140 break;
5141
5142 case DPLANE_OP_NH_INSTALL:
5143 case DPLANE_OP_NH_UPDATE:
5144 case DPLANE_OP_NH_DELETE:
5145 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5146 atomic_fetch_add_explicit(
5147 &zdplane_info.dg_nexthop_errors, 1,
5148 memory_order_relaxed);
5149 break;
5150
5151 case DPLANE_OP_LSP_INSTALL:
5152 case DPLANE_OP_LSP_UPDATE:
5153 case DPLANE_OP_LSP_DELETE:
5154 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5155 atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors,
5156 1, memory_order_relaxed);
5157 break;
5158
5159 case DPLANE_OP_PW_INSTALL:
5160 case DPLANE_OP_PW_UNINSTALL:
5161 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5162 atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
5163 memory_order_relaxed);
5164 break;
f62e5480 5165
2f74a82a
JU
5166 case DPLANE_OP_ADDR_INSTALL:
5167 case DPLANE_OP_ADDR_UNINSTALL:
5168 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5169 atomic_fetch_add_explicit(
5170 &zdplane_info.dg_intf_addr_errors, 1,
5171 memory_order_relaxed);
5172 break;
5173
5174 case DPLANE_OP_MAC_INSTALL:
5175 case DPLANE_OP_MAC_DELETE:
5176 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5177 atomic_fetch_add_explicit(&zdplane_info.dg_mac_errors,
5178 1, memory_order_relaxed);
5179 break;
5180
5181 case DPLANE_OP_NEIGH_INSTALL:
5182 case DPLANE_OP_NEIGH_UPDATE:
5183 case DPLANE_OP_NEIGH_DELETE:
5184 case DPLANE_OP_VTEP_ADD:
5185 case DPLANE_OP_VTEP_DELETE:
d68e74b4 5186 case DPLANE_OP_NEIGH_DISCOVER:
0a27a2fe
PG
5187 case DPLANE_OP_NEIGH_IP_INSTALL:
5188 case DPLANE_OP_NEIGH_IP_DELETE:
2f74a82a
JU
5189 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5190 atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors,
5191 1, memory_order_relaxed);
5192 break;
5193
5194 case DPLANE_OP_RULE_ADD:
5195 case DPLANE_OP_RULE_DELETE:
5196 case DPLANE_OP_RULE_UPDATE:
5197 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5198 atomic_fetch_add_explicit(&zdplane_info.dg_rule_errors,
5199 1, memory_order_relaxed);
5200 break;
5201
5162e000
PG
5202 case DPLANE_OP_IPTABLE_ADD:
5203 case DPLANE_OP_IPTABLE_DELETE:
5204 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5205 atomic_fetch_add_explicit(
5206 &zdplane_info.dg_iptable_errors, 1,
5207 memory_order_relaxed);
5208 break;
5209
ef524230
PG
5210 case DPLANE_OP_IPSET_ADD:
5211 case DPLANE_OP_IPSET_DELETE:
5212 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5213 atomic_fetch_add_explicit(&zdplane_info.dg_ipset_errors,
5214 1, memory_order_relaxed);
5215 break;
5216
5217 case DPLANE_OP_IPSET_ENTRY_ADD:
5218 case DPLANE_OP_IPSET_ENTRY_DELETE:
5219 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5220 atomic_fetch_add_explicit(
5221 &zdplane_info.dg_ipset_entry_errors, 1,
5222 memory_order_relaxed);
5223 break;
5224
e18747a9
PG
5225 case DPLANE_OP_NEIGH_TABLE_UPDATE:
5226 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5227 atomic_fetch_add_explicit(
5228 &zdplane_info.dg_neightable_errors, 1,
5229 memory_order_relaxed);
5230 break;
5231
62b4b7e4
PG
5232 case DPLANE_OP_GRE_SET:
5233 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5234 atomic_fetch_add_explicit(
5235 &zdplane_info.dg_gre_set_errors, 1,
5236 memory_order_relaxed);
5237 break;
2f74a82a
JU
5238 /* Ignore 'notifications' - no-op */
5239 case DPLANE_OP_SYS_ROUTE_ADD:
5240 case DPLANE_OP_SYS_ROUTE_DELETE:
5241 case DPLANE_OP_ROUTE_NOTIFY:
5242 case DPLANE_OP_LSP_NOTIFY:
c60522f7 5243 case DPLANE_OP_BR_PORT_UPDATE:
fef24b03
JU
5244 break;
5245
9d59df63
MS
5246 /* TODO -- error counters for incoming events? */
5247 case DPLANE_OP_INTF_ADDR_ADD:
5248 case DPLANE_OP_INTF_ADDR_DEL:
5249 break;
5250
2f74a82a 5251 case DPLANE_OP_NONE:
fef24b03
JU
5252 if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
5253 atomic_fetch_add_explicit(&zdplane_info.dg_other_errors,
5254 1, memory_order_relaxed);
2f74a82a
JU
5255 break;
5256 }
f62e5480
JU
5257}
5258
5162e000
PG
5259static void kernel_dplane_process_iptable(struct zebra_dplane_provider *prov,
5260 struct zebra_dplane_ctx *ctx)
5261{
5262 zebra_pbr_process_iptable(ctx);
5263 dplane_provider_enqueue_out_ctx(prov, ctx);
5264}
5265
ef524230
PG
5266static void kernel_dplane_process_ipset(struct zebra_dplane_provider *prov,
5267 struct zebra_dplane_ctx *ctx)
5268{
5269 zebra_pbr_process_ipset(ctx);
5270 dplane_provider_enqueue_out_ctx(prov, ctx);
5271}
5272
5273static void
5274kernel_dplane_process_ipset_entry(struct zebra_dplane_provider *prov,
5275 struct zebra_dplane_ctx *ctx)
5276{
5277 zebra_pbr_process_ipset_entry(ctx);
5278 dplane_provider_enqueue_out_ctx(prov, ctx);
5279}
5280
fef24b03
JU
5281/*
5282 * Kernel provider callback
5283 */
5284static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
5285{
5286 struct zebra_dplane_ctx *ctx, *tctx;
5287 struct dplane_ctx_q work_list;
5288 int counter, limit;
5289
5290 TAILQ_INIT(&work_list);
5291
5292 limit = dplane_provider_get_work_limit(prov);
5293
5294 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5295 zlog_debug("dplane provider '%s': processing",
5296 dplane_provider_get_name(prov));
5297
5298 for (counter = 0; counter < limit; counter++) {
5299 ctx = dplane_provider_dequeue_in_ctx(prov);
5300 if (ctx == NULL)
5301 break;
fef24b03
JU
5302 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5303 kernel_dplane_log_detail(ctx);
2f74a82a 5304
ef524230
PG
5305 if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD
5306 || dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_DELETE))
5162e000 5307 kernel_dplane_process_iptable(prov, ctx);
ef524230
PG
5308 else if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD
5309 || dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_DELETE))
5310 kernel_dplane_process_ipset(prov, ctx);
5311 else if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD
5312 || dplane_ctx_get_op(ctx)
5313 == DPLANE_OP_IPSET_ENTRY_DELETE))
5314 kernel_dplane_process_ipset_entry(prov, ctx);
5162e000
PG
5315 else
5316 TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
2f74a82a 5317 }
c831033f 5318
18f60fe9 5319 kernel_update_multi(&work_list);
fef24b03 5320
2f74a82a 5321 TAILQ_FOREACH_SAFE (ctx, &work_list, zd_q_entries, tctx) {
fef24b03
JU
5322 kernel_dplane_handle_result(ctx);
5323
2f74a82a 5324 TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
c831033f
MS
5325 dplane_provider_enqueue_out_ctx(prov, ctx);
5326 }
5327
5328 /* Ensure that we'll run the work loop again if there's still
5329 * more work to do.
5330 */
5331 if (counter >= limit) {
5332 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5333 zlog_debug("dplane provider '%s' reached max updates %d",
5334 dplane_provider_get_name(prov), counter);
5335
5336 atomic_fetch_add_explicit(&zdplane_info.dg_update_yields,
5337 1, memory_order_relaxed);
5338
5339 dplane_provider_work_ready();
5340 }
5341
5342 return 0;
5343}
5344
1e20238a 5345#ifdef DPLANE_TEST_PROVIDER
e5a60d82 5346
c831033f
MS
5347/*
5348 * Test dataplane provider plugin
5349 */
5350
5351/*
5352 * Test provider process callback
5353 */
5354static int test_dplane_process_func(struct zebra_dplane_provider *prov)
5355{
5356 struct zebra_dplane_ctx *ctx;
5357 int counter, limit;
5358
5359 /* Just moving from 'in' queue to 'out' queue */
5360
5361 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5362 zlog_debug("dplane provider '%s': processing",
5363 dplane_provider_get_name(prov));
5364
5365 limit = dplane_provider_get_work_limit(prov);
5366
5367 for (counter = 0; counter < limit; counter++) {
c831033f
MS
5368 ctx = dplane_provider_dequeue_in_ctx(prov);
5369 if (ctx == NULL)
5370 break;
5371
cf363e1b
MS
5372 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5373 zlog_debug("dplane provider '%s': op %s",
5374 dplane_provider_get_name(prov),
5375 dplane_op2str(dplane_ctx_get_op(ctx)));
5376
c831033f
MS
5377 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
5378
5379 dplane_provider_enqueue_out_ctx(prov, ctx);
5380 }
5381
c9d17fe8
MS
5382 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5383 zlog_debug("dplane provider '%s': processed %d",
5384 dplane_provider_get_name(prov), counter);
5385
c831033f
MS
5386 /* Ensure that we'll run the work loop again if there's still
5387 * more work to do.
5388 */
5389 if (counter >= limit)
5390 dplane_provider_work_ready();
5391
5392 return 0;
5393}
5394
5395/*
5396 * Test provider shutdown/fini callback
5397 */
5398static int test_dplane_shutdown_func(struct zebra_dplane_provider *prov,
5399 bool early)
5400{
5401 if (IS_ZEBRA_DEBUG_DPLANE)
5402 zlog_debug("dplane provider '%s': %sshutdown",
5403 dplane_provider_get_name(prov),
5404 early ? "early " : "");
5405
5406 return 0;
5407}
e5a60d82 5408#endif /* DPLANE_TEST_PROVIDER */
c831033f
MS
5409
5410/*
5411 * Register default kernel provider
5412 */
5413static void dplane_provider_init(void)
5414{
5415 int ret;
5416
5417 ret = dplane_provider_register("Kernel",
5418 DPLANE_PRIO_KERNEL,
1dd4ea8a 5419 DPLANE_PROV_FLAGS_DEFAULT, NULL,
c831033f
MS
5420 kernel_dplane_process_func,
5421 NULL,
1ff8a248 5422 NULL, NULL);
c831033f
MS
5423
5424 if (ret != AOK)
5425 zlog_err("Unable to register kernel dplane provider: %d",
5426 ret);
5427
1e20238a 5428#ifdef DPLANE_TEST_PROVIDER
e5a60d82 5429 /* Optional test provider ... */
c831033f
MS
5430 ret = dplane_provider_register("Test",
5431 DPLANE_PRIO_PRE_KERNEL,
1dd4ea8a 5432 DPLANE_PROV_FLAGS_DEFAULT, NULL,
c831033f
MS
5433 test_dplane_process_func,
5434 test_dplane_shutdown_func,
1ff8a248 5435 NULL /* data */, NULL);
c831033f
MS
5436
5437 if (ret != AOK)
5438 zlog_err("Unable to register test dplane provider: %d",
5439 ret);
e5a60d82 5440#endif /* DPLANE_TEST_PROVIDER */
7cdb1a84
MS
5441}
5442
aa21da07
MS
5443/*
5444 * Allow zebra code to walk the queue of pending contexts, evaluate each one
5445 * using a callback function. If the function returns 'true', the context
5446 * will be dequeued and freed without being processed.
5447 */
5448int dplane_clean_ctx_queue(bool (*context_cb)(struct zebra_dplane_ctx *ctx,
5449 void *arg), void *val)
5450{
5451 struct zebra_dplane_ctx *ctx, *temp;
5452 struct dplane_ctx_q work_list;
5453
5454 TAILQ_INIT(&work_list);
5455
5456 if (context_cb == NULL)
5457 goto done;
5458
5459 /* Walk the pending context queue under the dplane lock. */
5460 DPLANE_LOCK();
5461
5462 TAILQ_FOREACH_SAFE(ctx, &zdplane_info.dg_update_ctx_q, zd_q_entries,
5463 temp) {
5464 if (context_cb(ctx, val)) {
5465 TAILQ_REMOVE(&zdplane_info.dg_update_ctx_q, ctx,
5466 zd_q_entries);
5467 TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
5468 }
5469 }
5470
5471 DPLANE_UNLOCK();
5472
5473 /* Now free any contexts selected by the caller, without holding
5474 * the lock.
5475 */
5476 TAILQ_FOREACH_SAFE(ctx, &work_list, zd_q_entries, temp) {
5477 TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
5478 dplane_ctx_fini(&ctx);
5479 }
5480
5481done:
5482
5483 return 0;
5484}
5485
4dfd7a02
MS
5486/* Indicates zebra shutdown/exit is in progress. Some operations may be
5487 * simplified or skipped during shutdown processing.
5488 */
5489bool dplane_is_in_shutdown(void)
5490{
25779064 5491 return zdplane_info.dg_is_shutdown;
4dfd7a02
MS
5492}
5493
5917df09
MS
5494/*
5495 * Enable collection of extra info about interfaces in route updates.
5496 */
5497void dplane_enable_intf_extra_info(void)
5498{
5499 dplane_collect_extra_intf_info = true;
5500}
5501
4dfd7a02
MS
5502/*
5503 * Early or pre-shutdown, de-init notification api. This runs pretty
5504 * early during zebra shutdown, as a signal to stop new work and prepare
5505 * for updates generated by shutdown/cleanup activity, as zebra tries to
5506 * remove everything it's responsible for.
c9d17fe8 5507 * NB: This runs in the main zebra pthread context.
4dfd7a02
MS
5508 */
5509void zebra_dplane_pre_finish(void)
5510{
3c0e1622 5511 struct zebra_dplane_provider *prov;
6ba8db21 5512
4dfd7a02 5513 if (IS_ZEBRA_DEBUG_DPLANE)
3c0e1622 5514 zlog_debug("Zebra dataplane pre-finish called");
4dfd7a02 5515
25779064 5516 zdplane_info.dg_is_shutdown = true;
4dfd7a02 5517
6ba8db21 5518 /* Notify provider(s) of pending shutdown. */
3c0e1622
MS
5519 TAILQ_FOREACH(prov, &zdplane_info.dg_providers_q, dp_prov_link) {
5520 if (prov->dp_fini == NULL)
6ba8db21
RZ
5521 continue;
5522
3c0e1622 5523 prov->dp_fini(prov, true /* early */);
6ba8db21 5524 }
4dfd7a02
MS
5525}
5526
5527/*
5528 * Utility to determine whether work remains enqueued within the dplane;
5529 * used during system shutdown processing.
5530 */
5531static bool dplane_work_pending(void)
5532{
c9d17fe8 5533 bool ret = false;
25779064 5534 struct zebra_dplane_ctx *ctx;
c9d17fe8 5535 struct zebra_dplane_provider *prov;
4dfd7a02 5536
c831033f
MS
5537 /* TODO -- just checking incoming/pending work for now, must check
5538 * providers
5539 */
4dfd7a02
MS
5540 DPLANE_LOCK();
5541 {
3fe4ccc4 5542 ctx = TAILQ_FIRST(&zdplane_info.dg_update_ctx_q);
c9d17fe8 5543 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
4dfd7a02
MS
5544 }
5545 DPLANE_UNLOCK();
5546
c9d17fe8
MS
5547 if (ctx != NULL) {
5548 ret = true;
5549 goto done;
5550 }
5551
5552 while (prov) {
5553
ad6aad4d 5554 dplane_provider_lock(prov);
c9d17fe8
MS
5555
5556 ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
5557 if (ctx == NULL)
5558 ctx = TAILQ_FIRST(&(prov->dp_ctx_out_q));
5559
ad6aad4d 5560 dplane_provider_unlock(prov);
c9d17fe8
MS
5561
5562 if (ctx != NULL)
5563 break;
5564
5565 DPLANE_LOCK();
5566 prov = TAILQ_NEXT(prov, dp_prov_link);
5567 DPLANE_UNLOCK();
5568 }
5569
5570 if (ctx != NULL)
5571 ret = true;
5572
5573done:
5574 return ret;
4dfd7a02
MS
5575}
5576
5577/*
5578 * Shutdown-time intermediate callback, used to determine when all pending
5579 * in-flight updates are done. If there's still work to do, reschedules itself.
5580 * If all work is done, schedules an event to the main zebra thread for
5581 * final zebra shutdown.
5582 * This runs in the dplane pthread context.
5583 */
5584static int dplane_check_shutdown_status(struct thread *event)
5585{
d166308b
MS
5586 struct dplane_zns_info *zi;
5587
4dfd7a02
MS
5588 if (IS_ZEBRA_DEBUG_DPLANE)
5589 zlog_debug("Zebra dataplane shutdown status check called");
5590
d166308b
MS
5591 /* Remove any zns info entries as we stop the dplane pthread. */
5592 frr_each_safe (zns_info_list, &zdplane_info.dg_zns_list, zi) {
5593 zns_info_list_del(&zdplane_info.dg_zns_list, zi);
5594
5595 if (zdplane_info.dg_master)
5596 thread_cancel(&zi->t_read);
5597
5598 XFREE(MTYPE_DP_NS, zi);
5599 }
5600
4dfd7a02
MS
5601 if (dplane_work_pending()) {
5602 /* Reschedule dplane check on a short timer */
25779064 5603 thread_add_timer_msec(zdplane_info.dg_master,
4dfd7a02
MS
5604 dplane_check_shutdown_status,
5605 NULL, 100,
25779064 5606 &zdplane_info.dg_t_shutdown_check);
4dfd7a02
MS
5607
5608 /* TODO - give up and stop waiting after a short time? */
5609
5610 } else {
5611 /* We appear to be done - schedule a final callback event
5612 * for the zebra main pthread.
5613 */
3801e764 5614 thread_add_event(zrouter.master, zebra_finalize, NULL, 0, NULL);
4dfd7a02
MS
5615 }
5616
5617 return 0;
5618}
5619
18c37974 5620/*
1d11b21f 5621 * Shutdown, de-init api. This runs pretty late during shutdown,
4dfd7a02
MS
5622 * after zebra has tried to free/remove/uninstall all routes during shutdown.
5623 * At this point, dplane work may still remain to be done, so we can't just
5624 * blindly terminate. If there's still work to do, we'll periodically check
5625 * and when done, we'll enqueue a task to the zebra main thread for final
5626 * termination processing.
5627 *
1d11b21f 5628 * NB: This runs in the main zebra thread context.
18c37974 5629 */
1d11b21f 5630void zebra_dplane_finish(void)
18c37974 5631{
4dfd7a02
MS
5632 if (IS_ZEBRA_DEBUG_DPLANE)
5633 zlog_debug("Zebra dataplane fini called");
5634
25779064 5635 thread_add_event(zdplane_info.dg_master,
4dfd7a02 5636 dplane_check_shutdown_status, NULL, 0,
25779064 5637 &zdplane_info.dg_t_shutdown_check);
4dfd7a02
MS
5638}
5639
c831033f
MS
5640/*
5641 * Main dataplane pthread event loop. The thread takes new incoming work
5642 * and offers it to the first provider. It then iterates through the
5643 * providers, taking complete work from each one and offering it
5644 * to the next in order. At each step, a limited number of updates are
5645 * processed during a cycle in order to provide some fairness.
14b0bc8e
MS
5646 *
5647 * This loop through the providers is only run once, so that the dataplane
5648 * pthread can look for other pending work - such as i/o work on behalf of
5649 * providers.
c831033f
MS
5650 */
5651static int dplane_thread_loop(struct thread *event)
5652{
5653 struct dplane_ctx_q work_list;
5654 struct dplane_ctx_q error_list;
5655 struct zebra_dplane_provider *prov;
5656 struct zebra_dplane_ctx *ctx, *tctx;
5657 int limit, counter, error_counter;
c9d17fe8 5658 uint64_t curr, high;
f1595ce4 5659 bool reschedule = false;
c831033f
MS
5660
5661 /* Capture work limit per cycle */
5662 limit = zdplane_info.dg_updates_per_cycle;
5663
14b0bc8e 5664 /* Init temporary lists used to move contexts among providers */
c831033f 5665 TAILQ_INIT(&work_list);
14b0bc8e
MS
5666 TAILQ_INIT(&error_list);
5667 error_counter = 0;
c831033f
MS
5668
5669 /* Check for zebra shutdown */
5670 if (!zdplane_info.dg_run)
5671 goto done;
5672
5673 /* Dequeue some incoming work from zebra (if any) onto the temporary
5674 * working list.
5675 */
5676 DPLANE_LOCK();
5677
5678 /* Locate initial registered provider */
5679 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
5680
14b0bc8e 5681 /* Move new work from incoming list to temp list */
c831033f 5682 for (counter = 0; counter < limit; counter++) {
3fe4ccc4 5683 ctx = TAILQ_FIRST(&zdplane_info.dg_update_ctx_q);
c831033f 5684 if (ctx) {
3fe4ccc4 5685 TAILQ_REMOVE(&zdplane_info.dg_update_ctx_q, ctx,
c831033f
MS
5686 zd_q_entries);
5687
c831033f
MS
5688 ctx->zd_provider = prov->dp_id;
5689
5690 TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
5691 } else {
5692 break;
5693 }
5694 }
5695
5696 DPLANE_UNLOCK();
5697
14b0bc8e
MS
5698 atomic_fetch_sub_explicit(&zdplane_info.dg_routes_queued, counter,
5699 memory_order_relaxed);
5700
c831033f
MS
5701 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5702 zlog_debug("dplane: incoming new work counter: %d", counter);
5703
5704 /* Iterate through the registered providers, offering new incoming
5705 * work. If the provider has outgoing work in its queue, take that
5706 * work for the next provider
5707 */
5708 while (prov) {
5709
14b0bc8e
MS
5710 /* At each iteration, the temporary work list has 'counter'
5711 * items.
5712 */
c831033f
MS
5713 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5714 zlog_debug("dplane enqueues %d new work to provider '%s'",
5715 counter, dplane_provider_get_name(prov));
5716
5717 /* Capture current provider id in each context; check for
5718 * error status.
5719 */
5720 TAILQ_FOREACH_SAFE(ctx, &work_list, zd_q_entries, tctx) {
5721 if (dplane_ctx_get_status(ctx) ==
5722 ZEBRA_DPLANE_REQUEST_SUCCESS) {
5723 ctx->zd_provider = prov->dp_id;
5724 } else {
5725 /*
5726 * TODO -- improve error-handling: recirc
5727 * errors backwards so that providers can
5728 * 'undo' their work (if they want to)
5729 */
5730
5731 /* Move to error list; will be returned
5732 * zebra main.
5733 */
5734 TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
5735 TAILQ_INSERT_TAIL(&error_list,
5736 ctx, zd_q_entries);
5737 error_counter++;
5738 }
5739 }
5740
5741 /* Enqueue new work to the provider */
ad6aad4d 5742 dplane_provider_lock(prov);
c831033f
MS
5743
5744 if (TAILQ_FIRST(&work_list))
5745 TAILQ_CONCAT(&(prov->dp_ctx_in_q), &work_list,
5746 zd_q_entries);
5747
c9d17fe8
MS
5748 atomic_fetch_add_explicit(&prov->dp_in_counter, counter,
5749 memory_order_relaxed);
5750 atomic_fetch_add_explicit(&prov->dp_in_queued, counter,
5751 memory_order_relaxed);
5752 curr = atomic_load_explicit(&prov->dp_in_queued,
5753 memory_order_relaxed);
5754 high = atomic_load_explicit(&prov->dp_in_max,
5755 memory_order_relaxed);
5756 if (curr > high)
5757 atomic_store_explicit(&prov->dp_in_max, curr,
c831033f
MS
5758 memory_order_relaxed);
5759
ad6aad4d 5760 dplane_provider_unlock(prov);
c831033f 5761
14b0bc8e
MS
5762 /* Reset the temp list (though the 'concat' may have done this
5763 * already), and the counter
5764 */
c831033f
MS
5765 TAILQ_INIT(&work_list);
5766 counter = 0;
5767
14b0bc8e
MS
5768 /* Call into the provider code. Note that this is
5769 * unconditional: we offer to do work even if we don't enqueue
5770 * any _new_ work.
5771 */
c831033f
MS
5772 (*prov->dp_fp)(prov);
5773
5774 /* Check for zebra shutdown */
5775 if (!zdplane_info.dg_run)
5776 break;
5777
5778 /* Dequeue completed work from the provider */
ad6aad4d 5779 dplane_provider_lock(prov);
c831033f
MS
5780
5781 while (counter < limit) {
5782 ctx = TAILQ_FIRST(&(prov->dp_ctx_out_q));
5783 if (ctx) {
5784 TAILQ_REMOVE(&(prov->dp_ctx_out_q), ctx,
5785 zd_q_entries);
5786
5787 TAILQ_INSERT_TAIL(&work_list,
5788 ctx, zd_q_entries);
5789 counter++;
5790 } else
5791 break;
5792 }
5793
ad6aad4d 5794 dplane_provider_unlock(prov);
c831033f 5795
f1595ce4
DE
5796 if (counter >= limit)
5797 reschedule = true;
5798
c831033f
MS
5799 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5800 zlog_debug("dplane dequeues %d completed work from provider %s",
5801 counter, dplane_provider_get_name(prov));
5802
5803 /* Locate next provider */
5804 DPLANE_LOCK();
5805 prov = TAILQ_NEXT(prov, dp_prov_link);
5806 DPLANE_UNLOCK();
c831033f
MS
5807 }
5808
f1595ce4
DE
5809 /*
5810 * We hit the work limit while processing at least one provider's
5811 * output queue - ensure we come back and finish it.
5812 */
5813 if (reschedule)
5814 dplane_provider_work_ready();
5815
c831033f 5816 /* After all providers have been serviced, enqueue any completed
14b0bc8e 5817 * work and any errors back to zebra so it can process the results.
c831033f 5818 */
c831033f 5819 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
14b0bc8e
MS
5820 zlog_debug("dplane has %d completed, %d errors, for zebra main",
5821 counter, error_counter);
c831033f
MS
5822
5823 /*
4c206c8f 5824 * Hand lists through the api to zebra main,
c831033f
MS
5825 * to reduce the number of lock/unlock cycles
5826 */
14b0bc8e 5827
4c206c8f
MS
5828 /* Call through to zebra main */
5829 (zdplane_info.dg_results_cb)(&error_list);
14b0bc8e 5830
4c206c8f 5831 TAILQ_INIT(&error_list);
14b0bc8e 5832
4c206c8f
MS
5833 /* Call through to zebra main */
5834 (zdplane_info.dg_results_cb)(&work_list);
c831033f 5835
4c206c8f 5836 TAILQ_INIT(&work_list);
c831033f
MS
5837
5838done:
5839 return 0;
5840}
5841
4dfd7a02
MS
5842/*
5843 * Final phase of shutdown, after all work enqueued to dplane has been
5844 * processed. This is called from the zebra main pthread context.
5845 */
5846void zebra_dplane_shutdown(void)
5847{
6ba8db21
RZ
5848 struct zebra_dplane_provider *dp;
5849
4dfd7a02
MS
5850 if (IS_ZEBRA_DEBUG_DPLANE)
5851 zlog_debug("Zebra dataplane shutdown called");
1d11b21f
MS
5852
5853 /* Stop dplane thread, if it's running */
5854
25779064 5855 zdplane_info.dg_run = false;
1d11b21f 5856
9344d3fc
SW
5857 if (zdplane_info.dg_t_update)
5858 thread_cancel_async(zdplane_info.dg_t_update->master,
5859 &zdplane_info.dg_t_update, NULL);
1d11b21f 5860
d8c16a95
MS
5861 frr_pthread_stop(zdplane_info.dg_pthread, NULL);
5862
5863 /* Destroy pthread */
5864 frr_pthread_destroy(zdplane_info.dg_pthread);
5865 zdplane_info.dg_pthread = NULL;
5866 zdplane_info.dg_master = NULL;
4dfd7a02 5867
3c0e1622
MS
5868 /* Notify provider(s) of final shutdown.
5869 * Note that this call is in the main pthread, so providers must
5870 * be prepared for that.
5871 */
6ba8db21
RZ
5872 TAILQ_FOREACH(dp, &zdplane_info.dg_providers_q, dp_prov_link) {
5873 if (dp->dp_fini == NULL)
5874 continue;
5875
5876 dp->dp_fini(dp, false);
5877 }
c831033f
MS
5878
5879 /* TODO -- Clean-up provider objects */
5880
5881 /* TODO -- Clean queue(s), free memory */
5882}
5883
5884/*
5885 * Initialize the dataplane module during startup, internal/private version
5886 */
2561d12e 5887static void zebra_dplane_init_internal(void)
c831033f
MS
5888{
5889 memset(&zdplane_info, 0, sizeof(zdplane_info));
5890
5891 pthread_mutex_init(&zdplane_info.dg_mutex, NULL);
1d11b21f 5892
3fe4ccc4 5893 TAILQ_INIT(&zdplane_info.dg_update_ctx_q);
c831033f 5894 TAILQ_INIT(&zdplane_info.dg_providers_q);
d166308b 5895 zns_info_list_init(&zdplane_info.dg_zns_list);
1d11b21f 5896
c831033f
MS
5897 zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK;
5898
5899 zdplane_info.dg_max_queued_updates = DPLANE_DEFAULT_MAX_QUEUED;
5900
5901 /* Register default kernel 'provider' during init */
5902 dplane_provider_init();
e5a60d82 5903}
c831033f 5904
e5a60d82
MS
5905/*
5906 * Start the dataplane pthread. This step needs to be run later than the
5907 * 'init' step, in case zebra has fork-ed.
5908 */
5909void zebra_dplane_start(void)
5910{
d166308b 5911 struct dplane_zns_info *zi;
1dd4ea8a 5912 struct zebra_dplane_provider *prov;
c831033f
MS
5913 struct frr_pthread_attr pattr = {
5914 .start = frr_pthread_attr_default.start,
5915 .stop = frr_pthread_attr_default.stop
5916 };
5917
1dd4ea8a
MS
5918 /* Start dataplane pthread */
5919
c831033f 5920 zdplane_info.dg_pthread = frr_pthread_new(&pattr, "Zebra dplane thread",
0eca319c 5921 "zebra_dplane");
c831033f
MS
5922
5923 zdplane_info.dg_master = zdplane_info.dg_pthread->master;
5924
e5a60d82
MS
5925 zdplane_info.dg_run = true;
5926
c831033f
MS
5927 /* Enqueue an initial event for the dataplane pthread */
5928 thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0,
5929 &zdplane_info.dg_t_update);
5930
d166308b
MS
5931 /* Enqueue reads if necessary */
5932 frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
5933#if defined(HAVE_NETLINK)
5934 thread_add_read(zdplane_info.dg_master, dplane_incoming_read,
5935 zi, zi->info.nls.sock, &zi->t_read);
5936#endif
5937 }
5938
1dd4ea8a
MS
5939 /* Call start callbacks for registered providers */
5940
5941 DPLANE_LOCK();
5942 prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
5943 DPLANE_UNLOCK();
5944
5945 while (prov) {
5946
5947 if (prov->dp_start)
5948 (prov->dp_start)(prov);
5949
5950 /* Locate next provider */
5951 DPLANE_LOCK();
5952 prov = TAILQ_NEXT(prov, dp_prov_link);
5953 DPLANE_UNLOCK();
5954 }
5955
c831033f 5956 frr_pthread_run(zdplane_info.dg_pthread, NULL);
18c37974
MS
5957}
5958
7cdb1a84 5959/*
b8e0423d 5960 * Initialize the dataplane module at startup; called by zebra rib_init()
7cdb1a84 5961 */
4c206c8f 5962void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_q *))
7cdb1a84 5963{
2561d12e 5964 zebra_dplane_init_internal();
4c206c8f 5965 zdplane_info.dg_results_cb = results_fp;
7cdb1a84 5966}