]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_tx_queue.c
Merge pull request #12698 from Orange-OpenSource/isisd
[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 event *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 EVENT_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_and_free(&queue->hash, tx_queue_element_free);
90 XFREE(MTYPE_TX_QUEUE, queue);
91 }
92
93 static struct isis_tx_queue_entry *tx_queue_find(struct isis_tx_queue *queue,
94 struct isis_lsp *lsp)
95 {
96 struct isis_tx_queue_entry e = {
97 .lsp = lsp
98 };
99
100 return hash_lookup(queue->hash, &e);
101 }
102
103 static void tx_queue_send_event(struct event *thread)
104 {
105 struct isis_tx_queue_entry *e = EVENT_ARG(thread);
106 struct isis_tx_queue *queue = e->queue;
107
108 event_add_timer(master, tx_queue_send_event, e, 5, &e->retry);
109
110 if (e->is_retry)
111 queue->circuit->area->lsp_rxmt_count++;
112 else
113 e->is_retry = true;
114
115 queue->send_event(queue->circuit, e->lsp, e->type);
116 /* Don't access e here anymore, send_event might have destroyed it */
117 }
118
119 void _isis_tx_queue_add(struct isis_tx_queue *queue,
120 struct isis_lsp *lsp,
121 enum isis_tx_type type,
122 const char *func, const char *file,
123 int line)
124 {
125 if (!queue)
126 return;
127
128 if (IS_DEBUG_TX_QUEUE) {
129 zlog_debug(
130 "Add LSP %pLS to %s queue as %s LSP. (From %s %s:%d)",
131 lsp->hdr.lsp_id, queue->circuit->interface->name,
132 (type == TX_LSP_CIRCUIT_SCOPED) ? "circuit scoped"
133 : "regular",
134 func, file, line);
135 }
136
137 struct isis_tx_queue_entry *e = tx_queue_find(queue, lsp);
138 if (!e) {
139 e = XCALLOC(MTYPE_TX_QUEUE_ENTRY, sizeof(*e));
140 e->lsp = lsp;
141 e->queue = queue;
142
143 struct isis_tx_queue_entry *inserted;
144 inserted = hash_get(queue->hash, e, hash_alloc_intern);
145 assert(inserted == e);
146 }
147
148 e->type = type;
149
150 EVENT_OFF(e->retry);
151 event_add_event(master, tx_queue_send_event, e, 0, &e->retry);
152
153 e->is_retry = false;
154 }
155
156 void _isis_tx_queue_del(struct isis_tx_queue *queue, struct isis_lsp *lsp,
157 const char *func, const char *file, int line)
158 {
159 if (!queue)
160 return;
161
162 struct isis_tx_queue_entry *e = tx_queue_find(queue, lsp);
163 if (!e)
164 return;
165
166 if (IS_DEBUG_TX_QUEUE) {
167 zlog_debug("Remove LSP %pLS from %s queue. (From %s %s:%d)",
168 lsp->hdr.lsp_id, queue->circuit->interface->name,
169 func, file, line);
170 }
171
172 EVENT_OFF(e->retry);
173
174 hash_release(queue->hash, e);
175 XFREE(MTYPE_TX_QUEUE_ENTRY, e);
176 }
177
178 unsigned long isis_tx_queue_len(struct isis_tx_queue *queue)
179 {
180 if (!queue)
181 return 0;
182
183 return hashcount(queue->hash);
184 }
185
186 void isis_tx_queue_clean(struct isis_tx_queue *queue)
187 {
188 hash_clean(queue->hash, tx_queue_element_free);
189 }