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