Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc.
4 : *
5 : * This file is part of Quagga
6 : */
7 :
8 : #include <zebra.h>
9 :
10 : #include "frrevent.h"
11 : #include "memory.h"
12 : #include "hash.h"
13 : #include "log.h"
14 : #include "qobj.h"
15 : #include "jhash.h"
16 : #include "network.h"
17 :
18 80 : static uint32_t qobj_hash(const struct qobj_node *node)
19 : {
20 80 : return (uint32_t)node->nid;
21 : }
22 :
23 20 : static int qobj_cmp(const struct qobj_node *na, const struct qobj_node *nb)
24 : {
25 20 : if (na->nid < nb->nid)
26 : return -1;
27 20 : if (na->nid > nb->nid)
28 : return 1;
29 : return 0;
30 : }
31 :
32 364 : DECLARE_HASH(qobj_nodes, struct qobj_node, nodehash,
33 : qobj_cmp, qobj_hash);
34 :
35 : static pthread_rwlock_t nodes_lock;
36 : static struct qobj_nodes_head nodes = { };
37 :
38 :
39 32 : void qobj_reg(struct qobj_node *node, const struct qobj_nodetype *type)
40 : {
41 32 : node->type = type;
42 32 : pthread_rwlock_wrlock(&nodes_lock);
43 32 : do {
44 32 : node->nid = (uint64_t)frr_weak_random();
45 32 : node->nid ^= (uint64_t)frr_weak_random() << 32;
46 64 : } while (!node->nid || qobj_nodes_find(&nodes, node));
47 32 : qobj_nodes_add(&nodes, node);
48 32 : pthread_rwlock_unlock(&nodes_lock);
49 32 : }
50 :
51 26 : void qobj_unreg(struct qobj_node *node)
52 : {
53 26 : pthread_rwlock_wrlock(&nodes_lock);
54 26 : qobj_nodes_del(&nodes, node);
55 26 : pthread_rwlock_unlock(&nodes_lock);
56 26 : }
57 :
58 0 : struct qobj_node *qobj_get(uint64_t id)
59 : {
60 0 : struct qobj_node dummy = {.nid = id}, *rv;
61 0 : pthread_rwlock_rdlock(&nodes_lock);
62 0 : rv = qobj_nodes_find(&nodes, &dummy);
63 0 : pthread_rwlock_unlock(&nodes_lock);
64 0 : return rv;
65 : }
66 :
67 20 : void *qobj_get_typed(uint64_t id, const struct qobj_nodetype *type)
68 : {
69 20 : struct qobj_node dummy = {.nid = id};
70 20 : struct qobj_node *node;
71 20 : void *rv;
72 :
73 20 : pthread_rwlock_rdlock(&nodes_lock);
74 20 : node = qobj_nodes_find(&nodes, &dummy);
75 :
76 : /* note: we explicitly hold the lock until after we have checked the
77 : * type.
78 : * if the caller holds a lock that for example prevents the deletion of
79 : * route-maps, we can still race against a delete of something that
80 : * isn't
81 : * a route-map. */
82 20 : if (!node || node->type != type)
83 : rv = NULL;
84 : else
85 20 : rv = (char *)node - node->type->node_member_offset;
86 :
87 20 : pthread_rwlock_unlock(&nodes_lock);
88 20 : return rv;
89 : }
90 :
91 6 : void qobj_init(void)
92 : {
93 6 : pthread_rwlock_init(&nodes_lock, NULL);
94 6 : qobj_nodes_init(&nodes);
95 6 : }
96 :
97 4 : void qobj_finish(void)
98 : {
99 4 : struct qobj_node *node;
100 10 : while ((node = qobj_nodes_pop(&nodes)))
101 6 : qobj_nodes_del(&nodes, node);
102 4 : pthread_rwlock_destroy(&nodes_lock);
103 4 : }
|