Coverage Report

Created: 2025-07-14 06:48

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