]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_tx_queue.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / isisd / isis_tx_queue.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * IS-IS Rout(e)ing protocol - LSP TX Queuing logic
4 *
5 * Copyright (C) 2018 Christian Franke
6 *
7 * This file is part of FRRouting (FRR)
8 */
9 #include <zebra.h>
10
11 #include "hash.h"
12 #include "jhash.h"
13
14 #include "isisd/isisd.h"
15 #include "isisd/isis_flags.h"
16 #include "isisd/isis_circuit.h"
17 #include "isisd/isis_lsp.h"
18 #include "isisd/isis_misc.h"
19 #include "isisd/isis_tx_queue.h"
20
21 DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE, "ISIS TX Queue");
22 DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE_ENTRY, "ISIS TX Queue Entry");
23
24 struct isis_tx_queue {
25 struct isis_circuit *circuit;
26 void (*send_event)(struct isis_circuit *circuit,
27 struct isis_lsp *, enum isis_tx_type);
28 struct hash *hash;
29 };
30
31 struct isis_tx_queue_entry {
32 struct isis_lsp *lsp;
33 enum isis_tx_type type;
34 bool is_retry;
35 struct thread *retry;
36 struct isis_tx_queue *queue;
37 };
38
39 static unsigned tx_queue_hash_key(const void *p)
40 {
41 const struct isis_tx_queue_entry *e = p;
42
43 uint32_t id_key = jhash(e->lsp->hdr.lsp_id,
44 ISIS_SYS_ID_LEN + 2, 0x55aa5a5a);
45
46 return jhash_1word(e->lsp->level, id_key);
47 }
48
49 static bool tx_queue_hash_cmp(const void *a, const void *b)
50 {
51 const struct isis_tx_queue_entry *ea = a, *eb = b;
52
53 if (ea->lsp->level != eb->lsp->level)
54 return false;
55
56 if (memcmp(ea->lsp->hdr.lsp_id, eb->lsp->hdr.lsp_id,
57 ISIS_SYS_ID_LEN + 2))
58 return false;
59
60 return true;
61 }
62
63 struct isis_tx_queue *isis_tx_queue_new(
64 struct isis_circuit *circuit,
65 void(*send_event)(struct isis_circuit *circuit,
66 struct isis_lsp *,
67 enum isis_tx_type))
68 {
69 struct isis_tx_queue *rv = XCALLOC(MTYPE_TX_QUEUE, sizeof(*rv));
70
71 rv->circuit = circuit;
72 rv->send_event = send_event;
73
74 rv->hash = hash_create(tx_queue_hash_key, tx_queue_hash_cmp, NULL);
75 return rv;
76 }
77
78 static void tx_queue_element_free(void *element)
79 {
80 struct isis_tx_queue_entry *e = element;
81
82 THREAD_OFF(e->retry);
83
84 XFREE(MTYPE_TX_QUEUE_ENTRY, e);
85 }
86
87 void isis_tx_queue_free(struct isis_tx_queue *queue)
88 {
89 hash_clean(queue->hash, tx_queue_element_free);
90 hash_free(queue->hash);
91 XFREE(MTYPE_TX_QUEUE, queue);
92 }
93
94 static struct isis_tx_queue_entry *tx_queue_find(struct isis_tx_queue *queue,
95 struct isis_lsp *lsp)
96 {
97 struct isis_tx_queue_entry e = {
98 .lsp = lsp
99 };
100
101 return hash_lookup(queue->hash, &e);
102 }
103
104 static void tx_queue_send_event(struct thread *thread)
105 {
106 struct isis_tx_queue_entry *e = THREAD_ARG(thread);
107 struct isis_tx_queue *queue = e->queue;
108
109 thread_add_timer(master, tx_queue_send_event, e, 5, &e->retry);
110
111 if (e->is_retry)
112 queue->circuit->area->lsp_rxmt_count++;
113 else
114 e->is_retry = true;
115
116 queue->send_event(queue->circuit, e->lsp, e->type);
117 /* Don't access e here anymore, send_event might have destroyed it */
118 }
119
120 void _isis_tx_queue_add(struct isis_tx_queue *queue,
121 struct isis_lsp *lsp,
122 enum isis_tx_type type,
123 const char *func, const char *file,
124 int line)
125 {
126 if (!queue)
127 return;
128
129 if (IS_DEBUG_TX_QUEUE) {
130 zlog_debug("Add LSP %s to %s queue as %s LSP. (From %s %s:%d)",
131 rawlspid_print(lsp->hdr.lsp_id),
132 queue->circuit->interface->name,
133 (type == TX_LSP_CIRCUIT_SCOPED) ?
134 "circuit scoped" : "regular",
135 func, file, line);
136 }
137
138 struct isis_tx_queue_entry *e = tx_queue_find(queue, lsp);
139 if (!e) {
140 e = XCALLOC(MTYPE_TX_QUEUE_ENTRY, sizeof(*e));
141 e->lsp = lsp;
142 e->queue = queue;
143
144 struct isis_tx_queue_entry *inserted;
145 inserted = hash_get(queue->hash, e, hash_alloc_intern);
146 assert(inserted == e);
147 }
148
149 e->type = type;
150
151 THREAD_OFF(e->retry);
152 thread_add_event(master, tx_queue_send_event, e, 0, &e->retry);
153
154 e->is_retry = false;
155 }
156
157 void _isis_tx_queue_del(struct isis_tx_queue *queue, struct isis_lsp *lsp,
158 const char *func, const char *file, int line)
159 {
160 if (!queue)
161 return;
162
163 struct isis_tx_queue_entry *e = tx_queue_find(queue, lsp);
164 if (!e)
165 return;
166
167 if (IS_DEBUG_TX_QUEUE) {
168 zlog_debug("Remove LSP %s from %s queue. (From %s %s:%d)",
169 rawlspid_print(lsp->hdr.lsp_id),
170 queue->circuit->interface->name,
171 func, file, line);
172 }
173
174 THREAD_OFF(e->retry);
175
176 hash_release(queue->hash, e);
177 XFREE(MTYPE_TX_QUEUE_ENTRY, e);
178 }
179
180 unsigned long isis_tx_queue_len(struct isis_tx_queue *queue)
181 {
182 if (!queue)
183 return 0;
184
185 return hashcount(queue->hash);
186 }
187
188 void isis_tx_queue_clean(struct isis_tx_queue *queue)
189 {
190 hash_clean(queue->hash, tx_queue_element_free);
191 }