#include "lib/frratomic.h"
#include "lib/frr_pthread.h"
#include "lib/memory.h"
-#include "lib/queue.h"
#include "lib/zebra.h"
#include "zebra/netconf_netlink.h"
#include "zebra/zebra_router.h"
uint32_t flags;
uint32_t status;
- TAILQ_ENTRY(dplane_intf_extra) link;
+ struct dplane_intf_extra_list_item dlink;
};
/*
struct nexthop_group old_backup_ng;
/* Optional list of extra interface info */
- TAILQ_HEAD(dp_intf_extra_q, dplane_intf_extra) intf_extra_q;
+ struct dplane_intf_extra_list_head intf_extra_list;
};
/*
struct zebra_dplane_info zd_ns_info;
/* Embedded list linkage */
- TAILQ_ENTRY(zebra_dplane_ctx) zd_q_entries;
+ struct dplane_ctx_list_item zd_entries;
};
/* Flag that can be set by a pre-kernel provider as a signal that an update
*/
#define DPLANE_CTX_FLAG_NO_KERNEL 0x01
+/* List types declared now that the structs involved are defined. */
+DECLARE_DLIST(dplane_ctx_list, struct zebra_dplane_ctx, zd_entries);
+DECLARE_DLIST(dplane_intf_extra_list, struct dplane_intf_extra, dlink);
+
+/* List for dplane plugins/providers */
+PREDECL_DLIST(dplane_prov_list);
/*
* Registration block for one dataplane provider.
_Atomic uint32_t dp_error_counter;
/* Queue of contexts inbound to the provider */
- struct dplane_ctx_q dp_ctx_in_q;
+ struct dplane_ctx_list_head dp_ctx_in_list;
/* Queue of completed contexts outbound from the provider back
* towards the dataplane module.
*/
- struct dplane_ctx_q dp_ctx_out_q;
+ struct dplane_ctx_list_head dp_ctx_out_list;
/* Embedded list linkage for provider objects */
- TAILQ_ENTRY(zebra_dplane_provider) dp_prov_link;
+ struct dplane_prov_list_item dp_link;
};
+/* Declare list of providers/plugins */
+DECLARE_DLIST(dplane_prov_list, struct zebra_dplane_provider, dp_link);
+
/* Declare types for list of zns info objects */
PREDECL_DLIST(zns_info_list);
pthread_mutex_t dg_mutex;
/* Results callback registered by zebra 'core' */
- int (*dg_results_cb)(struct dplane_ctx_q *ctxlist);
+ int (*dg_results_cb)(struct dplane_ctx_list_head *ctxlist);
/* Sentinel for beginning of shutdown */
volatile bool dg_is_shutdown;
volatile bool dg_run;
/* Update context queue inbound to the dataplane */
- TAILQ_HEAD(zdg_ctx_q, zebra_dplane_ctx) dg_update_ctx_q;
+ struct dplane_ctx_list_head dg_update_list;
/* Ordered list of providers */
- TAILQ_HEAD(zdg_prov_q, zebra_dplane_provider) dg_providers_q;
+ struct dplane_prov_list_head dg_providers;
/* List of info about each zns */
struct zns_info_list_head dg_zns_list;
*/
static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
{
- struct dplane_intf_extra *if_extra, *if_tmp;
+ struct dplane_intf_extra *if_extra;
/*
* Some internal allocations may need to be freed, depending on
}
/* Optional extra interface info */
- TAILQ_FOREACH_SAFE(if_extra, &ctx->u.rinfo.intf_extra_q,
- link, if_tmp) {
- TAILQ_REMOVE(&ctx->u.rinfo.intf_extra_q, if_extra,
- link);
+ while ((if_extra = dplane_intf_extra_list_pop(
+ &ctx->u.rinfo.intf_extra_list)))
XFREE(MTYPE_DP_INTF, if_extra);
- }
break;
dplane_ctx_free(pctx);
}
+/* Init a list of contexts */
+void dplane_ctx_q_init(struct dplane_ctx_list_head *q)
+{
+ dplane_ctx_list_init(q);
+}
+
/* Enqueue a context block */
-void dplane_ctx_enqueue_tail(struct dplane_ctx_q *q,
+void dplane_ctx_enqueue_tail(struct dplane_ctx_list_head *list,
const struct zebra_dplane_ctx *ctx)
{
- TAILQ_INSERT_TAIL(q, (struct zebra_dplane_ctx *)ctx, zd_q_entries);
+ dplane_ctx_list_add_tail(list, (struct zebra_dplane_ctx *)ctx);
}
/* Append a list of context blocks to another list */
-void dplane_ctx_list_append(struct dplane_ctx_q *to_list,
- struct dplane_ctx_q *from_list)
+void dplane_ctx_list_append(struct dplane_ctx_list_head *to_list,
+ struct dplane_ctx_list_head *from_list)
{
- if (TAILQ_FIRST(from_list)) {
- TAILQ_CONCAT(to_list, from_list, zd_q_entries);
+ struct zebra_dplane_ctx *ctx;
- /* And clear 'from' list */
- TAILQ_INIT(from_list);
- }
+ while ((ctx = dplane_ctx_list_pop(from_list)) != NULL)
+ dplane_ctx_list_add_tail(to_list, ctx);
}
-struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_q *q)
+struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_list_head *q)
{
- struct zebra_dplane_ctx *ctx = TAILQ_FIRST(q);
+ struct zebra_dplane_ctx *ctx = dplane_ctx_list_first(q);
return ctx;
}
/* Dequeue a context block from the head of a list */
-struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_q *q)
+struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_list_head *q)
{
- struct zebra_dplane_ctx *ctx = TAILQ_FIRST(q);
-
- if (ctx)
- TAILQ_REMOVE(q, ctx, zd_q_entries);
+ struct zebra_dplane_ctx *ctx = dplane_ctx_list_pop(q);
return ctx;
}
const struct dplane_intf_extra *
dplane_ctx_get_intf_extra(const struct zebra_dplane_ctx *ctx)
{
- return TAILQ_FIRST(&ctx->u.rinfo.intf_extra_q);
+ return dplane_intf_extra_list_const_first(
+ &ctx->u.rinfo.intf_extra_list);
}
const struct dplane_intf_extra *
dplane_ctx_intf_extra_next(const struct zebra_dplane_ctx *ctx,
const struct dplane_intf_extra *ptr)
{
- return TAILQ_NEXT(ptr, link);
+ return dplane_intf_extra_list_const_next(&ctx->u.rinfo.intf_extra_list,
+ ptr);
}
vrf_id_t dplane_intf_extra_get_vrfid(const struct dplane_intf_extra *ptr)
if (!ctx || !re)
return ret;
- TAILQ_INIT(&ctx->u.rinfo.intf_extra_q);
+ dplane_intf_extra_list_init(&ctx->u.rinfo.intf_extra_list);
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
if_extra->flags = ifp->flags;
if_extra->status = ifp->status;
- TAILQ_INSERT_TAIL(&ctx->u.rinfo.intf_extra_q,
- if_extra, link);
+ dplane_intf_extra_list_add_tail(
+ &ctx->u.rinfo.intf_extra_list,
+ if_extra);
}
}
/* Enqueue for processing by the dataplane pthread */
DPLANE_LOCK();
{
- TAILQ_INSERT_TAIL(&zdplane_info.dg_update_ctx_q, ctx,
- zd_q_entries);
+ dplane_ctx_list_add_tail(&zdplane_info.dg_update_list, ctx);
}
DPLANE_UNLOCK();
vty_out(vty, "Zebra dataplane providers:\n");
DPLANE_LOCK();
- prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
+ prov = dplane_prov_list_first(&zdplane_info.dg_providers);
DPLANE_UNLOCK();
/* Show counters, useful info from each registered provider */
out, out_q, out_max);
DPLANE_LOCK();
- prov = TAILQ_NEXT(prov, dp_prov_link);
+ prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
DPLANE_UNLOCK();
}
p = XCALLOC(MTYPE_DP_PROV, sizeof(struct zebra_dplane_provider));
pthread_mutex_init(&(p->dp_mutex), NULL);
- TAILQ_INIT(&(p->dp_ctx_in_q));
- TAILQ_INIT(&(p->dp_ctx_out_q));
+ dplane_ctx_list_init(&p->dp_ctx_in_list);
+ dplane_ctx_list_init(&p->dp_ctx_out_list);
p->dp_flags = flags;
p->dp_priority = prio;
"provider-%u", p->dp_id);
/* Insert into list ordered by priority */
- TAILQ_FOREACH(last, &zdplane_info.dg_providers_q, dp_prov_link) {
+ frr_each (dplane_prov_list, &zdplane_info.dg_providers, last) {
if (last->dp_priority > p->dp_priority)
break;
}
if (last)
- TAILQ_INSERT_BEFORE(last, p, dp_prov_link);
+ dplane_prov_list_add_after(&zdplane_info.dg_providers, last, p);
else
- TAILQ_INSERT_TAIL(&zdplane_info.dg_providers_q, p,
- dp_prov_link);
+ dplane_prov_list_add_tail(&zdplane_info.dg_providers, p);
/* And unlock */
DPLANE_UNLOCK();
dplane_provider_lock(prov);
- ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
+ ctx = dplane_ctx_list_pop(&(prov->dp_ctx_in_list));
if (ctx) {
- TAILQ_REMOVE(&(prov->dp_ctx_in_q), ctx, zd_q_entries);
-
atomic_fetch_sub_explicit(&prov->dp_in_queued, 1,
memory_order_relaxed);
}
* Dequeue work to a list, return count
*/
int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov,
- struct dplane_ctx_q *listp)
+ struct dplane_ctx_list_head *listp)
{
int limit, ret;
struct zebra_dplane_ctx *ctx;
dplane_provider_lock(prov);
for (ret = 0; ret < limit; ret++) {
- ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
- if (ctx) {
- TAILQ_REMOVE(&(prov->dp_ctx_in_q), ctx, zd_q_entries);
-
- TAILQ_INSERT_TAIL(listp, ctx, zd_q_entries);
- } else {
+ ctx = dplane_ctx_list_pop(&(prov->dp_ctx_in_list));
+ if (ctx)
+ dplane_ctx_list_add_tail(listp, ctx);
+ else
break;
- }
}
if (ret > 0)
dplane_provider_lock(prov);
- TAILQ_INSERT_TAIL(&(prov->dp_ctx_out_q), ctx,
- zd_q_entries);
+ dplane_ctx_list_add_tail(&(prov->dp_ctx_out_list), ctx);
/* Maintain out-queue counters */
atomic_fetch_add_explicit(&(prov->dp_out_queued), 1,
*/
void dplane_provider_enqueue_to_zebra(struct zebra_dplane_ctx *ctx)
{
- struct dplane_ctx_q temp_list;
+ struct dplane_ctx_list_head temp_list;
/* Zebra's api takes a list, so we need to use a temporary list */
- TAILQ_INIT(&temp_list);
+ dplane_ctx_list_init(&temp_list);
- TAILQ_INSERT_TAIL(&temp_list, ctx, zd_q_entries);
+ dplane_ctx_list_add_tail(&temp_list, ctx);
(zdplane_info.dg_results_cb)(&temp_list);
}
*/
static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
{
- struct zebra_dplane_ctx *ctx, *tctx;
- struct dplane_ctx_q work_list;
+ struct zebra_dplane_ctx *ctx;
+ struct dplane_ctx_list_head work_list;
int counter, limit;
- TAILQ_INIT(&work_list);
+ dplane_ctx_list_init(&work_list);
limit = dplane_provider_get_work_limit(prov);
== DPLANE_OP_IPSET_ENTRY_DELETE))
kernel_dplane_process_ipset_entry(prov, ctx);
else
- TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
+ dplane_ctx_list_add_tail(&work_list, ctx);
}
kernel_update_multi(&work_list);
- TAILQ_FOREACH_SAFE (ctx, &work_list, zd_q_entries, tctx) {
+ while ((ctx = dplane_ctx_list_pop(&work_list)) != NULL) {
kernel_dplane_handle_result(ctx);
- TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
dplane_provider_enqueue_out_ctx(prov, ctx);
}
int dplane_clean_ctx_queue(bool (*context_cb)(struct zebra_dplane_ctx *ctx,
void *arg), void *val)
{
- struct zebra_dplane_ctx *ctx, *temp;
- struct dplane_ctx_q work_list;
+ struct zebra_dplane_ctx *ctx;
+ struct dplane_ctx_list_head work_list;
- TAILQ_INIT(&work_list);
+ dplane_ctx_list_init(&work_list);
if (context_cb == NULL)
return AOK;
/* Walk the pending context queue under the dplane lock. */
DPLANE_LOCK();
- TAILQ_FOREACH_SAFE(ctx, &zdplane_info.dg_update_ctx_q, zd_q_entries,
- temp) {
+ frr_each_safe (dplane_ctx_list, &zdplane_info.dg_update_list, ctx) {
if (context_cb(ctx, val)) {
- TAILQ_REMOVE(&zdplane_info.dg_update_ctx_q, ctx,
- zd_q_entries);
- TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
+ dplane_ctx_list_del(&zdplane_info.dg_update_list, ctx);
+ dplane_ctx_list_add_tail(&work_list, ctx);
}
}
/* Now free any contexts selected by the caller, without holding
* the lock.
*/
- TAILQ_FOREACH_SAFE(ctx, &work_list, zd_q_entries, temp) {
- TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
+ while ((ctx = dplane_ctx_list_pop(&work_list)) != NULL)
dplane_ctx_fini(&ctx);
- }
return AOK;
}
zdplane_info.dg_is_shutdown = true;
/* Notify provider(s) of pending shutdown. */
- TAILQ_FOREACH(prov, &zdplane_info.dg_providers_q, dp_prov_link) {
+ frr_each (dplane_prov_list, &zdplane_info.dg_providers, prov) {
if (prov->dp_fini == NULL)
continue;
*/
DPLANE_LOCK();
{
- ctx = TAILQ_FIRST(&zdplane_info.dg_update_ctx_q);
- prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
+ ctx = dplane_ctx_list_first(&zdplane_info.dg_update_list);
+ prov = dplane_prov_list_first(&zdplane_info.dg_providers);
}
DPLANE_UNLOCK();
dplane_provider_lock(prov);
- ctx = TAILQ_FIRST(&(prov->dp_ctx_in_q));
+ ctx = dplane_ctx_list_first(&(prov->dp_ctx_in_list));
if (ctx == NULL)
- ctx = TAILQ_FIRST(&(prov->dp_ctx_out_q));
+ ctx = dplane_ctx_list_first(&(prov->dp_ctx_out_list));
dplane_provider_unlock(prov);
break;
DPLANE_LOCK();
- prov = TAILQ_NEXT(prov, dp_prov_link);
+ prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
DPLANE_UNLOCK();
}
*/
static void dplane_thread_loop(struct thread *event)
{
- struct dplane_ctx_q work_list;
- struct dplane_ctx_q error_list;
+ struct dplane_ctx_list_head work_list;
+ struct dplane_ctx_list_head error_list;
struct zebra_dplane_provider *prov;
- struct zebra_dplane_ctx *ctx, *tctx;
+ struct zebra_dplane_ctx *ctx;
int limit, counter, error_counter;
uint64_t curr, high;
bool reschedule = false;
limit = zdplane_info.dg_updates_per_cycle;
/* Init temporary lists used to move contexts among providers */
- TAILQ_INIT(&work_list);
- TAILQ_INIT(&error_list);
+ dplane_ctx_list_init(&work_list);
+ dplane_ctx_list_init(&error_list);
+
error_counter = 0;
/* Check for zebra shutdown */
DPLANE_LOCK();
/* Locate initial registered provider */
- prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
+ prov = dplane_prov_list_first(&zdplane_info.dg_providers);
/* Move new work from incoming list to temp list */
for (counter = 0; counter < limit; counter++) {
- ctx = TAILQ_FIRST(&zdplane_info.dg_update_ctx_q);
+ ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list);
if (ctx) {
- TAILQ_REMOVE(&zdplane_info.dg_update_ctx_q, ctx,
- zd_q_entries);
-
ctx->zd_provider = prov->dp_id;
- TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
+ dplane_ctx_list_add_tail(&work_list, ctx);
} else {
break;
}
/* Capture current provider id in each context; check for
* error status.
*/
- TAILQ_FOREACH_SAFE(ctx, &work_list, zd_q_entries, tctx) {
+ frr_each_safe (dplane_ctx_list, &work_list, ctx) {
if (dplane_ctx_get_status(ctx) ==
ZEBRA_DPLANE_REQUEST_SUCCESS) {
ctx->zd_provider = prov->dp_id;
/* Move to error list; will be returned
* zebra main.
*/
- TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
- TAILQ_INSERT_TAIL(&error_list,
- ctx, zd_q_entries);
+ dplane_ctx_list_del(&work_list, ctx);
+ dplane_ctx_list_add_tail(&error_list, ctx);
error_counter++;
}
}
/* Enqueue new work to the provider */
dplane_provider_lock(prov);
- if (TAILQ_FIRST(&work_list))
- TAILQ_CONCAT(&(prov->dp_ctx_in_q), &work_list,
- zd_q_entries);
+ while ((ctx = dplane_ctx_list_pop(&work_list)) != NULL)
+ dplane_ctx_list_add_tail(&(prov->dp_ctx_in_list), ctx);
atomic_fetch_add_explicit(&prov->dp_in_counter, counter,
memory_order_relaxed);
/* Reset the temp list (though the 'concat' may have done this
* already), and the counter
*/
- TAILQ_INIT(&work_list);
+ dplane_ctx_list_init(&work_list);
counter = 0;
/* Call into the provider code. Note that this is
dplane_provider_lock(prov);
while (counter < limit) {
- ctx = TAILQ_FIRST(&(prov->dp_ctx_out_q));
+ ctx = dplane_ctx_list_pop(&(prov->dp_ctx_out_list));
if (ctx) {
- TAILQ_REMOVE(&(prov->dp_ctx_out_q), ctx,
- zd_q_entries);
-
- TAILQ_INSERT_TAIL(&work_list,
- ctx, zd_q_entries);
+ dplane_ctx_list_add_tail(&work_list, ctx);
counter++;
} else
break;
/* Locate next provider */
DPLANE_LOCK();
- prov = TAILQ_NEXT(prov, dp_prov_link);
+ prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
DPLANE_UNLOCK();
}
/* Call through to zebra main */
(zdplane_info.dg_results_cb)(&error_list);
- TAILQ_INIT(&error_list);
+ dplane_ctx_list_init(&error_list);
/* Call through to zebra main */
(zdplane_info.dg_results_cb)(&work_list);
- TAILQ_INIT(&work_list);
+ dplane_ctx_list_init(&work_list);
}
/*
* Note that this call is in the main pthread, so providers must
* be prepared for that.
*/
- TAILQ_FOREACH(dp, &zdplane_info.dg_providers_q, dp_prov_link) {
+ frr_each (dplane_prov_list, &zdplane_info.dg_providers, dp) {
if (dp->dp_fini == NULL)
continue;
pthread_mutex_init(&zdplane_info.dg_mutex, NULL);
- TAILQ_INIT(&zdplane_info.dg_update_ctx_q);
- TAILQ_INIT(&zdplane_info.dg_providers_q);
+ dplane_prov_list_init(&zdplane_info.dg_providers);
+
+ dplane_ctx_list_init(&zdplane_info.dg_update_list);
zns_info_list_init(&zdplane_info.dg_zns_list);
zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK;
/* Call start callbacks for registered providers */
DPLANE_LOCK();
- prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
+ prov = dplane_prov_list_first(&zdplane_info.dg_providers);
DPLANE_UNLOCK();
while (prov) {
/* Locate next provider */
DPLANE_LOCK();
- prov = TAILQ_NEXT(prov, dp_prov_link);
+ prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
DPLANE_UNLOCK();
}
/*
* Initialize the dataplane module at startup; called by zebra rib_init()
*/
-void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_q *))
+void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_list_head *))
{
zebra_dplane_init_internal();
zdplane_info.dg_results_cb = results_fp;