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