Merge pull request #9766 from opensourcerouting/typesafe-member-nhrp-zap

lib: add typesafe membership-test functions
This commit is contained in:
Mark Stapp 2021-10-20 08:13:17 -04:00 committed by GitHub
commit 52e458d922
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 423 additions and 364 deletions

View File

@ -106,19 +106,25 @@ Functions provided:
| _init, _fini | yes | yes | yes | yes | yes |
+------------------------------------+------+------+------+---------+------------+
| _first, _next, _next_safe, | yes | yes | yes | yes | yes |
| | | | | | |
| _const_first, _const_next | | | | | |
+------------------------------------+------+------+------+---------+------------+
| _swap_all | yes | yes | yes | yes | yes |
+------------------------------------+------+------+------+---------+------------+
| _anywhere | yes | -- | -- | -- | -- |
+------------------------------------+------+------+------+---------+------------+
| _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- |
+------------------------------------+------+------+------+---------+------------+
| _add | -- | yes | yes | yes | yes |
+------------------------------------+------+------+------+---------+------------+
| _member | yes | yes | yes | yes | yes |
+------------------------------------+------+------+------+---------+------------+
| _del, _pop | yes | yes | yes | yes | yes |
+------------------------------------+------+------+------+---------+------------+
| _find, _const_find | -- | -- | yes | yes | -- |
+------------------------------------+------+------+------+---------+------------+
| _find_lt, _find_gteq, | -- | -- | -- | yes | yes |
| | | | | | |
| _const_find_lt, _const_find_gteq | | | | | |
+------------------------------------+------+------+------+---------+------------+
| use with frr_each() macros | yes | yes | yes | yes | yes |
@ -268,6 +274,16 @@ The following documentation assumes that a list has been defined using
outdated by the time this function returns and can therefore only be
used as an estimate.
.. c:function:: bool Z_member(const struct Z_head *, const itemtype *)
Determines whether some item is a member of the given container. The
item must either be valid on some container, or set to all zeroes.
On some containers, if no faster way to determine membership is possible,
this is simply ``item == Z_find(head, item)``.
Not currently available for atomic containers.
.. c:function:: const itemtype *Z_const_first(const struct Z_head *)
.. c:function:: itemtype *Z_first(struct Z_head *)
@ -396,6 +412,17 @@ are several functions exposed to insert data:
maybe flip the order of ``item`` & ``after``?
``Z_add_after(head, item, after)``
.. c:function:: bool Z_anywhere(const itemtype *)
Returns whether an item is a member of *any* container of this type.
The item must either be valid on some container, or set to all zeroes.
Guaranteed to be fast (pointer compare or similar.)
Not currently available for sorted and atomic containers. Might be added
for sorted containers at some point (when needed.)
API for sorted structures
-------------------------

View File

@ -45,6 +45,7 @@
#include "config.h"
#endif
#include <string.h>
#include "typerb.h"
#define RB_BLACK 0
@ -330,6 +331,7 @@ color:
rbe_remove_color(rbt, parent, child);
rbt->count--;
memset(old, 0, sizeof(*old));
return (old);
}
@ -478,3 +480,11 @@ struct rb_entry *typed_rb_min(const struct rbt_tree *rbt)
return parent;
}
bool typed_rb_member(const struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe)
{
while (rbe->rbt_parent)
rbe = rbe->rbt_parent;
return rbe == rbt->rbt_root;
}

View File

@ -62,6 +62,8 @@ const struct typed_rb_entry *typed_rb_find_lt(const struct typed_rb_root *rbt,
const struct typed_rb_entry *b));
struct typed_rb_entry *typed_rb_min(const struct typed_rb_root *rbt);
struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe);
bool typed_rb_member(const struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe);
#define _PREDECL_RBTREE(prefix) \
struct prefix ## _head { struct typed_rb_root rr; }; \
@ -142,6 +144,11 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->rr.count; \
} \
macro_pure bool prefix ## _member(const struct prefix##_head *h, \
const type *item) \
{ \
return typed_rb_member(&h->rr, &item->field.re); \
} \
MACRO_REQUIRE_SEMICOLON() /* end */
#define PREDECL_RBTREE_UNIQ(prefix) \

View File

@ -29,6 +29,46 @@ DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket");
DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow");
DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array");
struct slist_item typesafe_slist_sentinel = { NULL };
bool typesafe_list_member(const struct slist_head *head,
const struct slist_item *item)
{
struct slist_item *fromhead = head->first;
struct slist_item **fromnext = (struct slist_item **)&item->next;
while (fromhead != _SLIST_LAST) {
if (fromhead == item || fromnext == head->last_next)
return true;
fromhead = fromhead->next;
if (!*fromnext || *fromnext == _SLIST_LAST)
break;
fromnext = &(*fromnext)->next;
}
return false;
}
bool typesafe_dlist_member(const struct dlist_head *head,
const struct dlist_item *item)
{
const struct dlist_item *fromhead = head->hitem.next;
const struct dlist_item *fromitem = item->next;
if (!item->prev || !item->next)
return false;
while (fromhead != &head->hitem && fromitem != item) {
if (fromitem == &head->hitem || fromhead == item)
return true;
fromhead = fromhead->next;
fromitem = fromitem->next;
}
return false;
}
#if 0
static void hash_consistency_check(struct thash_head *head)
{

View File

@ -78,8 +78,34 @@ macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
} \
/* ... */
/* *_member via find - when there is no better membership check than find() */
#define TYPESAFE_MEMBER_VIA_FIND(prefix, type) \
macro_inline bool prefix ## _member(struct prefix##_head *h, \
const type *item) \
{ \
return item == prefix ## _const_find(h, item); \
} \
/* ... */
/* *_member via find_gteq - same for non-unique containers */
#define TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \
macro_inline bool prefix ## _member(struct prefix##_head *h, \
const type *item) \
{ \
const type *iter; \
for (iter = prefix ## _const_find_gteq(h, item); iter; \
iter = prefix ## _const_next(h, iter)) { \
if (iter == item) \
return true; \
if (cmpfn(iter, item) > 0) \
break; \
} \
return false; \
} \
/* ... */
/* SWAP_ALL_SIMPLE = for containers where the items don't point back to the
* head *AND* the head doesn'T points to itself (= everything except LIST,
* head *AND* the head doesn't point to itself (= everything except LIST,
* DLIST and SKIPLIST), just switch out the entire head
*/
#define TYPESAFE_SWAP_ALL_SIMPLE(prefix) \
@ -106,6 +132,10 @@ struct slist_head {
size_t count;
};
/* this replaces NULL as the value for ->next on the last item. */
extern struct slist_item typesafe_slist_sentinel;
#define _SLIST_LAST &typesafe_slist_sentinel
static inline void typesafe_list_add(struct slist_head *head,
struct slist_item **pos, struct slist_item *item)
{
@ -116,6 +146,9 @@ static inline void typesafe_list_add(struct slist_head *head,
head->count++;
}
extern bool typesafe_list_member(const struct slist_head *head,
const struct slist_item *item);
/* use as:
*
* PREDECL_LIST(namelist);
@ -136,6 +169,7 @@ MACRO_REQUIRE_SEMICOLON() /* end */
macro_inline void prefix ## _init(struct prefix##_head *h) \
{ \
memset(h, 0, sizeof(*h)); \
h->sh.first = _SLIST_LAST; \
h->sh.last_next = &h->sh.first; \
} \
macro_inline void prefix ## _fini(struct prefix##_head *h) \
@ -161,25 +195,27 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct slist_item **iter = &h->sh.first; \
while (*iter && *iter != &item->field.si) \
while (*iter != _SLIST_LAST && *iter != &item->field.si) \
iter = &(*iter)->next; \
if (!*iter) \
if (*iter == _SLIST_LAST) \
return NULL; \
h->sh.count--; \
*iter = item->field.si.next; \
if (!item->field.si.next) \
if (item->field.si.next == _SLIST_LAST) \
h->sh.last_next = iter; \
item->field.si.next = NULL; \
return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
struct slist_item *sitem = h->sh.first; \
if (!sitem) \
if (sitem == _SLIST_LAST) \
return NULL; \
h->sh.count--; \
h->sh.first = sitem->next; \
if (h->sh.first == NULL) \
if (h->sh.first == _SLIST_LAST) \
h->sh.last_next = &h->sh.first; \
sitem->next = NULL; \
return container_of(sitem, type, field.si); \
} \
macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
@ -195,13 +231,17 @@ macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
} \
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
return container_of_null(h->sh.first, type, field.si); \
if (h->sh.first != _SLIST_LAST) \
return container_of(h->sh.first, type, field.si); \
return NULL; \
} \
macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
const type *item) \
{ \
const struct slist_item *sitem = &item->field.si; \
return container_of_null(sitem->next, type, field.si); \
if (sitem->next != _SLIST_LAST) \
return container_of(sitem->next, type, field.si); \
return NULL; \
} \
TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
@ -210,12 +250,23 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
if (!item) \
return NULL; \
sitem = &item->field.si; \
return container_of_null(sitem->next, type, field.si); \
if (sitem->next != _SLIST_LAST) \
return container_of(sitem->next, type, field.si); \
return NULL; \
} \
macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->sh.count; \
} \
macro_pure bool prefix ## _anywhere(const type *item) \
{ \
return item->field.si.next != NULL; \
} \
macro_pure bool prefix ## _member(const struct prefix##_head *h, \
const type *item) \
{ \
return typesafe_list_member(&h->sh, &item->field.si); \
} \
MACRO_REQUIRE_SEMICOLON() /* end */
/* don't use these structs directly */
@ -267,6 +318,9 @@ static inline void typesafe_dlist_swap_all(struct dlist_head *a,
}
}
extern bool typesafe_dlist_member(const struct dlist_head *head,
const struct dlist_item *item);
/* double-linked list, for fast item deletion
*/
#define PREDECL_DLIST(prefix) \
@ -321,6 +375,7 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
ditem->prev->next = ditem->next; \
ditem->next->prev = ditem->prev; \
h->dh.count--; \
ditem->prev = ditem->next = NULL; \
return container_of(ditem, type, field.di); \
} \
macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
@ -354,6 +409,16 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->dh.count; \
} \
macro_pure bool prefix ## _anywhere(const type *item) \
{ \
const struct dlist_item *ditem = &item->field.di; \
return ditem->next && ditem->prev; \
} \
macro_pure bool prefix ## _member(const struct prefix##_head *h, \
const type *item) \
{ \
return typesafe_dlist_member(&h->dh, &item->field.di); \
} \
MACRO_REQUIRE_SEMICOLON() /* end */
/* note: heap currently caps out at 4G items */
@ -463,6 +528,14 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->hh.count; \
} \
macro_pure bool prefix ## _member(const struct prefix##_head *h, \
const type *item) \
{ \
uint32_t idx = item->field.hi.index; \
if (idx >= h->hh.count) \
return false; \
return h->hh.array[idx] == &item->field.hi; \
} \
MACRO_REQUIRE_SEMICOLON() /* end */
extern void typesafe_heap_resize(struct heap_head *head, bool grow);
@ -565,6 +638,7 @@ macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
return NULL; \
h->sh.count--; \
*iter = item->field.si.next; \
item->field.si.next = NULL; \
return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
@ -618,6 +692,7 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
return container_of(sitem, type, field.si); \
} \
TYPESAFE_FIND(prefix, type) \
TYPESAFE_MEMBER_VIA_FIND(prefix, type) \
MACRO_REQUIRE_SEMICOLON() /* end */
#define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn) \
@ -633,6 +708,7 @@ macro_inline int _ ## prefix ## _cmp(const type *a, const type *b) \
return 0; \
} \
_DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp); \
TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \
MACRO_REQUIRE_SEMICOLON() /* end */
@ -799,6 +875,19 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->hh.count; \
} \
macro_pure bool prefix ## _member(const struct prefix##_head *h, \
const type *item) \
{ \
uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \
const struct thash_item *hitem = h->hh.entries[hbits]; \
while (hitem && hitem->hashval < hval) \
hitem = hitem->next; \
for (hitem = h->hh.entries[hbits]; hitem && hitem->hashval <= hval; \
hitem = hitem->next) \
if (hitem == &item->field.hi) \
return true; \
return false; \
} \
MACRO_REQUIRE_SEMICOLON() /* end */
/* skiplist, sorted.
@ -937,6 +1026,7 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
return container_of_null(sitem, type, field.si); \
} \
TYPESAFE_FIND(prefix, type) \
TYPESAFE_MEMBER_VIA_FIND(prefix, type) \
\
_DECLARE_SKIPLIST(prefix, type, field, \
prefix ## __cmp, prefix ## __cmp); \
@ -968,6 +1058,7 @@ macro_inline int prefix ## __cmp_uq(const struct sskip_item *a, \
\
_DECLARE_SKIPLIST(prefix, type, field, \
prefix ## __cmp, prefix ## __cmp_uq); \
TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \
MACRO_REQUIRE_SEMICOLON() /* end */

View File

@ -1,209 +0,0 @@
/* Linux kernel style list handling function
*
* Written from scratch by Timo Teräs <timo.teras@iki.fi>, but modeled
* after the linux kernel code.
*
* This file is free software: you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef LIST_H
#define LIST_H
#ifndef NULL
#define NULL 0L
#endif
#ifndef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#endif
#ifndef container_of
#define container_of(ptr, type, member) \
({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); \
})
#endif
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next;
struct hlist_node **pprev;
};
static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;
}
static inline int hlist_hashed(const struct hlist_node *n)
{
return n->pprev != NULL;
}
static inline void hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
n->next = NULL;
n->pprev = NULL;
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
n->pprev = &h->first;
h->first = n;
}
static inline void hlist_add_after(struct hlist_node *n,
struct hlist_node *prev)
{
n->next = prev->next;
n->pprev = &prev->next;
prev->next = n;
}
static inline struct hlist_node **hlist_tail_ptr(struct hlist_head *h)
{
struct hlist_node *n = h->first;
if (n == NULL)
return &h->first;
while (n->next != NULL)
n = n->next;
return &n->next;
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos; pos = pos->next)
#define hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ \
n = pos->next; \
1; \
}); \
pos = n)
#define hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && ({ \
tpos = hlist_entry(pos, typeof(*tpos), member); \
1; \
}); \
pos = pos->next)
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ \
n = pos->next; \
1; \
}) \
&& ({ \
tpos = hlist_entry(pos, typeof(*tpos), member); \
1; \
}); \
pos = n)
struct list_head {
struct list_head *next, *prev;
};
#define LIST_INITIALIZER(l) { .next = &l, .prev = &l }
static inline void list_init(struct list_head *list)
{
list->next = list;
list->prev = list;
}
static inline void __list_add(struct list_head *new, struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = NULL;
entry->prev = NULL;
}
static inline int list_hashed(const struct list_head *n)
{
return n->next != n && n->next != NULL;
}
static inline int list_empty(const struct list_head *n)
{
return !list_hashed(n);
}
#define list_next(ptr, type, member) \
(list_hashed(ptr) ? container_of((ptr)->next, type, member) : NULL)
#define list_entry(ptr, type, member) container_of(ptr,type,member)
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = ((head)->next != head ? \
list_entry((head)->next, typeof(*pos), member) : \
NULL), \
n = (pos ? \
list_entry(pos->member.next, typeof(*pos), member) : NULL); \
pos && (&pos->member != (head)); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif

View File

@ -315,7 +315,7 @@ static void nhrp_cache_peer_notifier(struct notifier_block *n,
static void nhrp_cache_reset_new(struct nhrp_cache *c)
{
THREAD_OFF(c->t_auth);
if (list_hashed(&c->newpeer_notifier.notifier_entry))
if (notifier_list_anywhere(&c->newpeer_notifier))
nhrp_peer_notify_del(c->new.peer, &c->newpeer_notifier);
nhrp_peer_unref(c->new.peer);
memset(&c->new, 0, sizeof(c->new));
@ -574,5 +574,5 @@ void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *n,
void nhrp_cache_notify_del(struct nhrp_cache *c, struct notifier_block *n)
{
notifier_del(n);
notifier_del(n, &c->notifier_list);
}

View File

@ -79,8 +79,8 @@ static int nhrp_if_new_hook(struct interface *ifp)
for (afi = 0; afi < AFI_MAX; afi++) {
struct nhrp_afi_data *ad = &nifp->afi[afi];
ad->holdtime = NHRPD_DEFAULT_HOLDTIME;
list_init(&ad->nhslist_head);
list_init(&ad->mcastlist_head);
nhrp_nhslist_init(&ad->nhslist_head);
nhrp_mcastlist_init(&ad->mcastlist_head);
}
return 0;
@ -224,8 +224,12 @@ void nhrp_interface_update_nbma(struct interface *ifp,
nbmanifp = nbmaifp->info;
if (nbmaifp != nifp->nbmaifp) {
if (nifp->nbmaifp)
notifier_del(&nifp->nbmanifp_notifier);
if (nifp->nbmaifp) {
struct nhrp_interface *prev_nifp = nifp->nbmaifp->info;
notifier_del(&nifp->nbmanifp_notifier,
&prev_nifp->notifier_list);
}
nifp->nbmaifp = nbmaifp;
if (nbmaifp) {
notifier_add(&nifp->nbmanifp_notifier,
@ -509,12 +513,15 @@ void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n,
notifier_fn_t fn)
{
struct nhrp_interface *nifp = ifp->info;
notifier_add(n, &nifp->notifier_list, fn);
}
void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n)
{
notifier_del(n);
struct nhrp_interface *nifp = ifp->info;
notifier_del(n, &nifp->notifier_list);
}
void nhrp_interface_set_protection(struct interface *ifp, const char *profile,

View File

@ -219,7 +219,9 @@ void netlink_mcast_set_nflog_group(int nlgroup)
static int nhrp_multicast_free(struct interface *ifp,
struct nhrp_multicast *mcast)
{
list_del(&mcast->list_entry);
struct nhrp_interface *nifp = ifp->info;
nhrp_mcastlist_del(&nifp->afi[mcast->afi].mcastlist_head, mcast);
XFREE(MTYPE_NHRP_MULTICAST, mcast);
return 0;
}
@ -230,8 +232,7 @@ int nhrp_multicast_add(struct interface *ifp, afi_t afi,
struct nhrp_interface *nifp = ifp->info;
struct nhrp_multicast *mcast;
list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry)
{
frr_each (nhrp_mcastlist, &nifp->afi[afi].mcastlist_head, mcast) {
if (sockunion_same(&mcast->nbma_addr, nbma_addr))
return NHRP_ERR_ENTRY_EXISTS;
}
@ -241,7 +242,7 @@ int nhrp_multicast_add(struct interface *ifp, afi_t afi,
*mcast = (struct nhrp_multicast){
.afi = afi, .ifp = ifp, .nbma_addr = *nbma_addr,
};
list_add_tail(&mcast->list_entry, &nifp->afi[afi].mcastlist_head);
nhrp_mcastlist_add_tail(&nifp->afi[afi].mcastlist_head, mcast);
debugf(NHRP_DEBUG_COMMON, "Adding multicast entry (%pSU)", nbma_addr);
@ -252,11 +253,9 @@ int nhrp_multicast_del(struct interface *ifp, afi_t afi,
union sockunion *nbma_addr)
{
struct nhrp_interface *nifp = ifp->info;
struct nhrp_multicast *mcast, *tmp;
struct nhrp_multicast *mcast;
list_for_each_entry_safe(mcast, tmp, &nifp->afi[afi].mcastlist_head,
list_entry)
{
frr_each_safe (nhrp_mcastlist, &nifp->afi[afi].mcastlist_head, mcast) {
if (!sockunion_same(&mcast->nbma_addr, nbma_addr))
continue;
@ -274,17 +273,15 @@ int nhrp_multicast_del(struct interface *ifp, afi_t afi,
void nhrp_multicast_interface_del(struct interface *ifp)
{
struct nhrp_interface *nifp = ifp->info;
struct nhrp_multicast *mcast, *tmp;
struct nhrp_multicast *mcast;
afi_t afi;
for (afi = 0; afi < AFI_MAX; afi++) {
debugf(NHRP_DEBUG_COMMON,
"Cleaning up multicast entries (%d)",
!list_empty(&nifp->afi[afi].mcastlist_head));
debugf(NHRP_DEBUG_COMMON, "Cleaning up multicast entries (%zu)",
nhrp_mcastlist_count(&nifp->afi[afi].mcastlist_head));
list_for_each_entry_safe(
mcast, tmp, &nifp->afi[afi].mcastlist_head, list_entry)
{
frr_each_safe (nhrp_mcastlist, &nifp->afi[afi].mcastlist_head,
mcast) {
nhrp_multicast_free(ifp, mcast);
}
}
@ -297,8 +294,7 @@ void nhrp_multicast_foreach(struct interface *ifp, afi_t afi,
struct nhrp_interface *nifp = ifp->info;
struct nhrp_multicast *mcast;
list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry)
{
frr_each (nhrp_mcastlist, &nifp->afi[afi].mcastlist_head, mcast) {
cb(mcast, ctx);
}
}

View File

@ -254,7 +254,7 @@ static void nhrp_reg_delete(struct nhrp_registration *r)
{
nhrp_peer_notify_del(r->peer, &r->peer_notifier);
nhrp_peer_unref(r->peer);
list_del(&r->reglist_entry);
nhrp_reglist_del(&r->nhs->reglist_head, r);
THREAD_OFF(r->t_register);
XFREE(MTYPE_NHRP_REGISTRATION, r);
}
@ -264,10 +264,9 @@ nhrp_reg_by_nbma(struct nhrp_nhs *nhs, const union sockunion *nbma_addr)
{
struct nhrp_registration *r;
list_for_each_entry(
r, &nhs->reglist_head,
reglist_entry) if (sockunion_same(&r->peer->vc->remote.nbma,
nbma_addr)) return r;
frr_each (nhrp_reglist, &nhs->reglist_head, r)
if (sockunion_same(&r->peer->vc->remote.nbma, nbma_addr))
return r;
return NULL;
}
@ -276,7 +275,7 @@ static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr,
{
struct nhrp_nhs *nhs = container_of(q, struct nhrp_nhs, dns_resolve);
struct nhrp_interface *nifp = nhs->ifp->info;
struct nhrp_registration *reg, *regn;
struct nhrp_registration *reg;
int i;
if (n < 0) {
@ -289,8 +288,8 @@ static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr,
thread_add_timer(master, nhrp_nhs_resolve, nhs, 2 * 60 * 60,
&nhs->t_resolve);
list_for_each_entry(reg, &nhs->reglist_head, reglist_entry) reg->mark =
1;
frr_each (nhrp_reglist, &nhs->reglist_head, reg)
reg->mark = 1;
nhs->hub = 0;
for (i = 0; i < n; i++) {
@ -309,19 +308,16 @@ static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr,
reg->peer = nhrp_peer_get(nhs->ifp, &addrs[i]);
reg->nhs = nhs;
reg->timeout = 1;
list_init(&reg->reglist_entry);
list_add_tail(&reg->reglist_entry, &nhs->reglist_head);
nhrp_reglist_add_tail(&nhs->reglist_head, reg);
nhrp_peer_notify_add(reg->peer, &reg->peer_notifier,
nhrp_reg_peer_notify);
thread_add_timer_msec(master, nhrp_reg_send_req, reg, 50,
&reg->t_register);
}
list_for_each_entry_safe(reg, regn, &nhs->reglist_head, reglist_entry)
{
frr_each_safe (nhrp_reglist, &nhs->reglist_head, reg)
if (reg->mark)
nhrp_reg_delete(reg);
}
}
static int nhrp_nhs_resolve(struct thread *t)
@ -344,8 +340,7 @@ int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
&& sockunion_family(proto_addr) != afi2family(afi))
return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry)
{
frr_each (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) {
if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC
&& sockunion_family(proto_addr) != AF_UNSPEC
&& sockunion_same(&nhs->proto_addr, proto_addr))
@ -362,9 +357,9 @@ int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
.ifp = ifp,
.proto_addr = *proto_addr,
.nbma_fqdn = strdup(nbma_fqdn),
.reglist_head = LIST_INITIALIZER(nhs->reglist_head),
.reglist_head = INIT_DLIST(nhs->reglist_head),
};
list_add_tail(&nhs->nhslist_entry, &nifp->afi[afi].nhslist_head);
nhrp_nhslist_add_tail(&nifp->afi[afi].nhslist_head, nhs);
thread_add_timer_msec(master, nhrp_nhs_resolve, nhs, 1000,
&nhs->t_resolve);
@ -375,36 +370,34 @@ int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
const char *nbma_fqdn)
{
struct nhrp_interface *nifp = ifp->info;
struct nhrp_nhs *nhs, *nnhs;
struct nhrp_nhs *nhs;
int ret = NHRP_ERR_ENTRY_NOT_FOUND;
if (sockunion_family(proto_addr) != AF_UNSPEC
&& sockunion_family(proto_addr) != afi2family(afi))
return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
list_for_each_entry_safe(nhs, nnhs, &nifp->afi[afi].nhslist_head,
nhslist_entry)
{
frr_each_safe (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) {
if (!sockunion_same(&nhs->proto_addr, proto_addr))
continue;
if (strcmp(nhs->nbma_fqdn, nbma_fqdn) != 0)
continue;
nhrp_nhs_free(nhs);
nhrp_nhs_free(nifp, afi, nhs);
ret = NHRP_OK;
}
return ret;
}
int nhrp_nhs_free(struct nhrp_nhs *nhs)
int nhrp_nhs_free(struct nhrp_interface *nifp, afi_t afi, struct nhrp_nhs *nhs)
{
struct nhrp_registration *r, *rn;
struct nhrp_registration *r;
list_for_each_entry_safe(r, rn, &nhs->reglist_head, reglist_entry)
frr_each_safe (nhrp_reglist, &nhs->reglist_head, r)
nhrp_reg_delete(r);
THREAD_OFF(nhs->t_resolve);
list_del(&nhs->nhslist_entry);
nhrp_nhslist_del(&nifp->afi[afi].nhslist_head, nhs);
free((void *)nhs->nbma_fqdn);
XFREE(MTYPE_NHRP_NHS, nhs);
return 0;
@ -413,18 +406,15 @@ int nhrp_nhs_free(struct nhrp_nhs *nhs)
void nhrp_nhs_interface_del(struct interface *ifp)
{
struct nhrp_interface *nifp = ifp->info;
struct nhrp_nhs *nhs, *tmp;
struct nhrp_nhs *nhs;
afi_t afi;
for (afi = 0; afi < AFI_MAX; afi++) {
debugf(NHRP_DEBUG_COMMON, "Cleaning up nhs entries (%d)",
!list_empty(&nifp->afi[afi].nhslist_head));
debugf(NHRP_DEBUG_COMMON, "Cleaning up nhs entries (%zu)",
nhrp_nhslist_count(&nifp->afi[afi].nhslist_head));
list_for_each_entry_safe(nhs, tmp, &nifp->afi[afi].nhslist_head,
nhslist_entry)
{
nhrp_nhs_free(nhs);
}
frr_each_safe (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs)
nhrp_nhs_free(nifp, afi, nhs);
}
}
@ -433,15 +423,15 @@ void nhrp_nhs_terminate(void)
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct interface *ifp;
struct nhrp_interface *nifp;
struct nhrp_nhs *nhs, *tmp;
struct nhrp_nhs *nhs;
afi_t afi;
FOR_ALL_INTERFACES (vrf, ifp) {
nifp = ifp->info;
for (afi = 0; afi < AFI_MAX; afi++) {
list_for_each_entry_safe(
nhs, tmp, &nifp->afi[afi].nhslist_head,
nhslist_entry) nhrp_nhs_free(nhs);
frr_each_safe (nhrp_nhslist,
&nifp->afi[afi].nhslist_head, nhs)
nhrp_nhs_free(nifp, afi, nhs);
}
}
}
@ -455,11 +445,10 @@ void nhrp_nhs_foreach(struct interface *ifp, afi_t afi,
struct nhrp_nhs *nhs;
struct nhrp_registration *reg;
list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry)
{
if (!list_empty(&nhs->reglist_head)) {
list_for_each_entry(reg, &nhs->reglist_head,
reglist_entry) cb(nhs, reg, ctx);
frr_each (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) {
if (nhrp_reglist_count(&nhs->reglist_head)) {
frr_each (nhrp_reglist, &nhs->reglist_head, reg)
cb(nhs, reg, ctx);
} else
cb(nhs, 0, ctx);
}
@ -472,19 +461,14 @@ int nhrp_nhs_match_ip(union sockunion *in_ip, struct nhrp_interface *nifp)
struct nhrp_registration *reg;
for (i = 0; i < AFI_MAX; i++) {
list_for_each_entry(nhs, &nifp->afi[i].nhslist_head,
nhslist_entry)
{
if (!list_empty(&nhs->reglist_head)) {
list_for_each_entry(reg, &nhs->reglist_head,
reglist_entry)
{
if (!sockunion_cmp(
in_ip,
&reg->peer->vc->remote
.nbma))
return 1;
}
frr_each (nhrp_nhslist, &nifp->afi[i].nhslist_head, nhs) {
if (!nhrp_reglist_count(&nhs->reglist_head))
continue;
frr_each (nhrp_reglist, &nhs->reglist_head, reg) {
if (!sockunion_cmp(in_ip,
&reg->peer->vc->remote.nbma))
return 1;
}
}
}

View File

@ -359,7 +359,7 @@ void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *n,
void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *n)
{
notifier_del(n);
notifier_del(n, &p->notifier_list);
nhrp_peer_check_delete(p);
}

View File

@ -19,14 +19,18 @@
DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection");
PREDECL_DLIST(childlist);
struct child_sa {
uint32_t id;
struct nhrp_vc *vc;
struct list_head childlist_entry;
struct childlist_item childlist_entry;
};
DECLARE_DLIST(childlist, struct child_sa, childlist_entry);
static struct hash *nhrp_vc_hash;
static struct list_head childlist_head[512];
static struct childlist_head childlist_head[512];
static unsigned int nhrp_vc_key(const void *peer_data)
{
@ -104,8 +108,7 @@ int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc)
uint32_t child_hash = child_id % array_size(childlist_head);
int abort_migration = 0;
list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry)
{
frr_each (childlist, &childlist_head[child_hash], lsa) {
if (lsa->id == child_id) {
sa = lsa;
break;
@ -120,12 +123,9 @@ int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc)
*sa = (struct child_sa){
.id = child_id,
.childlist_entry =
LIST_INITIALIZER(sa->childlist_entry),
.vc = NULL,
};
list_add_tail(&sa->childlist_entry,
&childlist_head[child_hash]);
childlist_add_tail(&childlist_head[child_hash], sa);
}
if (sa->vc == vc)
@ -155,7 +155,7 @@ int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc)
/* Update */
sa->vc = vc;
if (!vc) {
list_del(&sa->childlist_entry);
childlist_del(&childlist_head[child_hash], sa);
XFREE(MTYPE_NHRP_VC, sa);
}
@ -170,7 +170,7 @@ void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n,
void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n)
{
notifier_del(n);
notifier_del(n, &vc->notifier_list);
nhrp_vc_check_delete(vc);
}
@ -200,17 +200,16 @@ void nhrp_vc_init(void)
nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp, "NHRP VC hash");
for (i = 0; i < array_size(childlist_head); i++)
list_init(&childlist_head[i]);
childlist_init(&childlist_head[i]);
}
void nhrp_vc_reset(void)
{
struct child_sa *sa, *n;
struct child_sa *sa;
size_t i;
for (i = 0; i < array_size(childlist_head); i++) {
list_for_each_entry_safe(sa, n, &childlist_head[i],
childlist_entry)
frr_each_safe (childlist, &childlist_head[i], sa)
nhrp_vc_ipsec_updown(sa->id, 0);
}
}

View File

@ -1200,9 +1200,7 @@ static int interface_config_write(struct vty *vty)
nhrp_cache_config_foreach(
ifp, interface_config_write_nhrp_map, &mapctx);
list_for_each_entry(nhs, &ad->nhslist_head,
nhslist_entry)
{
frr_each (nhrp_nhslist, &ad->nhslist_head, nhs) {
vty_out(vty, " %s nhrp nhs ", aficmd);
if (sockunion_family(&nhs->proto_addr)
== AF_UNSPEC)
@ -1212,9 +1210,7 @@ static int interface_config_write(struct vty *vty)
vty_out(vty, " nbma %s\n", nhs->nbma_fqdn);
}
list_for_each_entry(mcast, &ad->mcastlist_head,
list_entry)
{
frr_each (nhrp_mcastlist, &ad->mcastlist_head, mcast) {
vty_out(vty, " %s nhrp map multicast ", aficmd);
if (sockunion_family(&mcast->nbma_addr)
== AF_UNSPEC)

View File

@ -10,8 +10,6 @@
#ifndef NHRPD_H
#define NHRPD_H
#include "list.h"
#include "zbuf.h"
#include "zclient.h"
#include "debug.h"
@ -42,48 +40,53 @@ struct notifier_block;
typedef void (*notifier_fn_t)(struct notifier_block *, unsigned long);
PREDECL_DLIST(notifier_list);
struct notifier_block {
struct list_head notifier_entry;
struct notifier_list_item notifier_entry;
notifier_fn_t action;
};
DECLARE_DLIST(notifier_list, struct notifier_block, notifier_entry);
struct notifier_list {
struct list_head notifier_head;
struct notifier_list_head head;
};
#define NOTIFIER_LIST_INITIALIZER(l) \
{ \
.notifier_head = LIST_INITIALIZER((l)->notifier_head) \
.head = INIT_DLIST((l)->head) \
}
static inline void notifier_init(struct notifier_list *l)
{
list_init(&l->notifier_head);
notifier_list_init(&l->head);
}
static inline void notifier_add(struct notifier_block *n,
struct notifier_list *l, notifier_fn_t action)
{
n->action = action;
list_add_tail(&n->notifier_entry, &l->notifier_head);
notifier_list_add_tail(&l->head, n);
}
static inline void notifier_del(struct notifier_block *n)
static inline void notifier_del(struct notifier_block *n,
struct notifier_list *l)
{
list_del(&n->notifier_entry);
notifier_list_del(&l->head, n);
}
static inline void notifier_call(struct notifier_list *l, int cmd)
{
struct notifier_block *n, *nn;
list_for_each_entry_safe(n, nn, &l->notifier_head, notifier_entry) {
struct notifier_block *n;
frr_each_safe (notifier_list, &l->head, n)
n->action(n, cmd);
}
}
static inline int notifier_active(struct notifier_list *l)
{
return !list_empty(&l->notifier_head);
return notifier_list_count(&l->head) > 0;
}
extern struct hash *nhrp_gre_list;
@ -263,9 +266,13 @@ struct nhrp_shortcut {
struct notifier_block cache_notifier;
};
PREDECL_DLIST(nhrp_nhslist);
PREDECL_DLIST(nhrp_mcastlist);
PREDECL_DLIST(nhrp_reglist);
struct nhrp_nhs {
struct interface *ifp;
struct list_head nhslist_entry;
struct nhrp_nhslist_item nhslist_entry;
unsigned hub : 1;
afi_t afi;
@ -274,18 +281,22 @@ struct nhrp_nhs {
struct thread *t_resolve;
struct resolver_query dns_resolve;
struct list_head reglist_head;
struct nhrp_reglist_head reglist_head;
};
DECLARE_DLIST(nhrp_nhslist, struct nhrp_nhs, nhslist_entry);
struct nhrp_multicast {
struct interface *ifp;
struct list_head list_entry;
struct nhrp_mcastlist_item mcastlist_entry;
afi_t afi;
union sockunion nbma_addr; /* IP-address */
};
DECLARE_DLIST(nhrp_mcastlist, struct nhrp_multicast, mcastlist_entry);
struct nhrp_registration {
struct list_head reglist_entry;
struct nhrp_reglist_item reglist_entry;
struct thread *t_register;
struct nhrp_nhs *nhs;
struct nhrp_reqid reqid;
@ -296,6 +307,8 @@ struct nhrp_registration {
struct notifier_block peer_notifier;
};
DECLARE_DLIST(nhrp_reglist, struct nhrp_registration, reglist_entry);
#define NHRP_IFF_SHORTCUT 0x0001
#define NHRP_IFF_REDIRECT 0x0002
#define NHRP_IFF_REG_NO_UNIQUE 0x0100
@ -330,8 +343,8 @@ struct nhrp_interface {
short configured_mtu;
unsigned short mtu;
unsigned int holdtime;
struct list_head nhslist_head;
struct list_head mcastlist_head;
struct nhrp_nhslist_head nhslist_head;
struct nhrp_mcastlist_head mcastlist_head;
} afi[AFI_MAX];
};
@ -381,7 +394,7 @@ int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
const char *nbma_fqdn);
int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
const char *nbma_fqdn);
int nhrp_nhs_free(struct nhrp_nhs *nhs);
int nhrp_nhs_free(struct nhrp_interface *nifp, afi_t afi, struct nhrp_nhs *nhs);
void nhrp_nhs_terminate(void);
void nhrp_nhs_foreach(struct interface *ifp, afi_t afi,
void (*cb)(struct nhrp_nhs *, struct nhrp_registration *,

View File

@ -34,7 +34,6 @@ nhrpd_nhrpd_SOURCES = \
noinst_HEADERS += \
nhrpd/debug.h \
nhrpd/list.h \
nhrpd/netlink.h \
nhrpd/nhrp_errors.h \
nhrpd/nhrp_protocol.h \

View File

@ -164,35 +164,33 @@ void *zbuf_may_pull_until(struct zbuf *zb, const char *sep, struct zbuf *msg)
void zbufq_init(struct zbuf_queue *zbq)
{
*zbq = (struct zbuf_queue){
.queue_head = LIST_INITIALIZER(zbq->queue_head),
.queue_head = INIT_DLIST(zbq->queue_head),
};
}
void zbufq_reset(struct zbuf_queue *zbq)
{
struct zbuf *buf, *bufn;
struct zbuf *buf;
list_for_each_entry_safe(buf, bufn, &zbq->queue_head, queue_list)
{
list_del(&buf->queue_list);
frr_each_safe (zbuf_queue, &zbq->queue_head, buf) {
zbuf_queue_del(&zbq->queue_head, buf);
zbuf_free(buf);
}
}
void zbufq_queue(struct zbuf_queue *zbq, struct zbuf *zb)
{
list_add_tail(&zb->queue_list, &zbq->queue_head);
zbuf_queue_add_tail(&zbq->queue_head, zb);
}
int zbufq_write(struct zbuf_queue *zbq, int fd)
{
struct iovec iov[16];
struct zbuf *zb, *zbn;
struct zbuf *zb;
ssize_t r;
size_t iovcnt = 0;
list_for_each_entry_safe(zb, zbn, &zbq->queue_head, queue_list)
{
frr_each_safe (zbuf_queue, &zbq->queue_head, zb) {
iov[iovcnt++] = (struct iovec){
.iov_base = zb->head, .iov_len = zbuf_used(zb),
};
@ -204,15 +202,14 @@ int zbufq_write(struct zbuf_queue *zbq, int fd)
if (r < 0)
return r;
list_for_each_entry_safe(zb, zbn, &zbq->queue_head, queue_list)
{
frr_each_safe (zbuf_queue, &zbq->queue_head, zb) {
if (r < (ssize_t)zbuf_used(zb)) {
zb->head += r;
return 1;
}
r -= zbuf_used(zb);
list_del(&zb->queue_list);
zbuf_queue_del(&zbq->queue_head, zb);
zbuf_free(zb);
}

View File

@ -15,18 +15,22 @@
#include <endian.h>
#include <sys/types.h>
#include "list.h"
#include "typesafe.h"
PREDECL_DLIST(zbuf_queue);
struct zbuf {
struct list_head queue_list;
struct zbuf_queue_item queue_entry;
unsigned allocated : 1;
unsigned error : 1;
uint8_t *buf, *end;
uint8_t *head, *tail;
};
DECLARE_DLIST(zbuf_queue, struct zbuf, queue_entry);
struct zbuf_queue {
struct list_head queue_head;
struct zbuf_queue_head queue_head;
};
struct zbuf *zbuf_alloc(size_t size);

2
tests/.gitignore vendored
View File

@ -28,6 +28,7 @@
/lib/test_frrscript
/lib/test_frrlua
/lib/test_graph
/lib/test_grpc
/lib/test_heavy
/lib/test_heavy_thread
/lib/test_heavy_wq
@ -44,6 +45,7 @@
/lib/test_segv
/lib/test_seqlock
/lib/test_sig
/lib/test_skiplist
/lib/test_srcdest_table
/lib/test_stream
/lib/test_table

View File

@ -39,6 +39,8 @@
#define list_find concat(TYPE, _find)
#define list_find_lt concat(TYPE, _find_lt)
#define list_find_gteq concat(TYPE, _find_gteq)
#define list_member concat(TYPE, _member)
#define list_anywhere concat(TYPE, _anywhere)
#define list_del concat(TYPE, _del)
#define list_pop concat(TYPE, _pop)
#define list_swap_all concat(TYPE, _swap_all)
@ -239,6 +241,13 @@ static void concat(test_, TYPE)(void)
ts_hash_headx(
&head, "swap2b",
"a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
while (list_pop(&other))
;
list_fini(&other);
prng_free(prng_swap);
ts_ref("swap-cleanup");
#endif /* !IS_ATOMIC */
k = 0;
@ -294,7 +303,7 @@ static void concat(test_, TYPE)(void)
#elif IS_HEAP(REALTYPE)
/* heap - partially sorted. */
prev = NULL;
l = k / 2;
l = k / 4;
for (i = 0; i < l; i++) {
item = list_pop(&head);
if (prev)
@ -303,7 +312,24 @@ static void concat(test_, TYPE)(void)
k--;
prev = item;
}
ts_hash("pop", NULL);
ts_hash("pop#1", NULL);
for (i = 0; i < NITEM; i++)
assertf(list_member(&head, &itm[i]) == itm[i].scratchpad,
"%zu should:%d is:%d", i, itm[i].scratchpad,
list_member(&head, &itm[i]));
ts_hash("member", NULL);
l = k / 2;
for (; i < l; i++) {
item = list_pop(&head);
if (prev)
assert(prev->val < item->val);
item->scratchpad = 0;
k--;
prev = item;
}
ts_hash("pop#2", NULL);
#else /* !IS_UNIQ(REALTYPE) && !IS_HEAP(REALTYPE) */
for (i = 0; i < NITEM; i++) {
@ -380,6 +406,14 @@ static void concat(test_, TYPE)(void)
assert(l + list_count(&head) == k);
ts_hashx("del", "cb2e5d80f08a803ef7b56c15e981b681adcea214bebc2f55e12e0bfb242b07ca");
#if !IS_ATOMIC(REALTYPE)
for (i = 0; i < NITEM; i++)
assertf(list_member(&head, &itm[i]) == itm[i].scratchpad,
"%zu should:%d is:%d", i, itm[i].scratchpad,
list_member(&head, &itm[i]));
ts_hashx("member", "cb2e5d80f08a803ef7b56c15e981b681adcea214bebc2f55e12e0bfb242b07ca");
#endif
frr_each_safe(list, &head, item) {
assert(item->scratchpad != 0);
@ -449,6 +483,13 @@ static void concat(test_, TYPE)(void)
ts_hash_head(
&head, "swap2b",
"eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19");
while (list_pop(&other))
;
list_fini(&other);
prng_free(prng_swap);
ts_ref("swap-cleanup");
#endif
for (i = 0; i < NITEM / 2; i++) {
@ -461,7 +502,39 @@ static void concat(test_, TYPE)(void)
}
ts_hash("del-prng", "86d568a95eb429dab3162976c5a5f3f75aabc835932cd682aa280b6923549564");
#if !IS_ATOMIC(REALTYPE)
for (i = 0; i < NITEM; i++) {
assertf(list_member(&head, &itm[i]) == itm[i].scratchpad,
"%zu should:%d is:%d", i, itm[i].scratchpad,
list_member(&head, &itm[i]));
assertf(list_anywhere(&itm[i]) == itm[i].scratchpad,
"%zu should:%d is:%d", i, itm[i].scratchpad,
list_anywhere(&itm[i]));
}
ts_hash("member", "86d568a95eb429dab3162976c5a5f3f75aabc835932cd682aa280b6923549564");
#endif
l = 0;
while (l < (k / 4) && (prev = list_pop(&head))) {
assert(prev->scratchpad != 0);
prev->scratchpad = 0;
l++;
}
ts_hash("pop#1", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d");
#if !IS_ATOMIC(REALTYPE)
for (i = 0; i < NITEM; i++) {
assertf(list_member(&head, &itm[i]) == itm[i].scratchpad,
"%zu should:%d is:%d", i, itm[i].scratchpad,
list_member(&head, &itm[i]));
assertf(list_anywhere(&itm[i]) == itm[i].scratchpad,
"%zu should:%d is:%d", i, itm[i].scratchpad,
list_anywhere(&itm[i]));
}
ts_hash("member", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d");
#endif
while ((item = list_pop(&head))) {
assert(item->scratchpad != 0);
@ -471,7 +544,7 @@ static void concat(test_, TYPE)(void)
assert(l == k);
assert(list_count(&head) == 0);
assert(list_first(&head) == NULL);
ts_hash("pop", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119");
ts_hash("pop#2", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119");
prng_free(prng);
prng = prng_new(0x1e5a2d69);
@ -650,6 +723,7 @@ static void concat(test_, TYPE)(void)
list_fini(&head);
ts_ref("fini");
ts_end();
prng_free(prng);
printfrr("%s end\n", str(TYPE));
}
@ -680,6 +754,8 @@ static void concat(test_, TYPE)(void)
#undef list_find
#undef list_find_lt
#undef list_find_gteq
#undef list_member
#undef list_anywhere
#undef list_del
#undef list_pop
#undef list_swap_all

View File

@ -409,6 +409,25 @@ our $Operators = qr{
}x;
our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x;
our $Iterators = qr{
frr_each|frr_each_safe|frr_each_from|
frr_with_mutex|frr_with_privs|
LIST_FOREACH|LIST_FOREACH_SAFE|
SLIST_FOREACH|SLIST_FOREACH_SAFE|SLIST_FOREACH_PREVPTR|
STAILQ_FOREACH|STAILQ_FOREACH_SAFE|
TAILQ_FOREACH|TAILQ_FOREACH_SAFE|TAILQ_FOREACH_REVERSE|TAILQ_FOREACH_REVERSE_SAFE|
RB_FOREACH|RB_FOREACH_SAFE|RB_FOREACH_REVERSE|RB_FOREACH_REVERSE_SAFE|
SPLAY_FOREACH|
FOR_ALL_INTERFACES|FOR_ALL_INTERFACES_ADDRESSES|JSON_FOREACH|
LY_FOR_KEYS|LY_LIST_FOR|LY_TREE_FOR|LY_TREE_DFS_BEGIN|LYD_TREE_DFS_BEGIN|
RE_DEST_FOREACH_ROUTE|RE_DEST_FOREACH_ROUTE_SAFE|
RNODE_FOREACH_RE|RNODE_FOREACH_RE_SAFE|
UPDGRP_FOREACH_SUBGRP|UPDGRP_FOREACH_SUBGRP_SAFE|
SUBGRP_FOREACH_PEER|SUBGRP_FOREACH_PEER_SAFE|
SUBGRP_FOREACH_ADJ|SUBGRP_FOREACH_ADJ_SAFE|
AF_FOREACH|FOREACH_AFI_SAFI|FOREACH_SAFI|
LSDB_LOOP
}x;
our $BasicType;
our $NonptrType;
@ -1009,9 +1028,9 @@ sub top_of_kernel_tree {
my ($root) = @_;
my @tree_check = (
"COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile",
"README", "Documentation", "arch", "include", "drivers",
"fs", "init", "ipc", "kernel", "lib", "scripts",
"COPYING", "configure.ac", "Makefile.am",
"README.md", "doc", "lib", "vtysh", "watchfrr", "tests",
"zebra", "bgpd", "ospfd", "ospf6d", "isisd", "staticd",
);
foreach my $check (@tree_check) {
@ -2655,8 +2674,8 @@ sub process {
(defined($1) || defined($2))))) {
$is_patch = 1;
$reported_maintainer_file = 1;
WARN("FILE_PATH_CHANGES",
"added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
#WARN("FILE_PATH_CHANGES",
# "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
}
# Check for wrappage within a valid hunk of the file
@ -4028,7 +4047,8 @@ sub process {
if|for|while|switch|return|case|
volatile|__volatile__|
__attribute__|format|__extension__|
asm|__asm__)$/x)
asm|__asm__|
$Iterators)$/x)
{
# cpp #define statements have non-optional spaces, ie
# if there is a space between the name and the open