]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_event.c
Merge pull request #12837 from donaldsharp/unlikely_routemap
[mirror_frr.git] / nhrpd / nhrp_event.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* NHRP event manager
3 * Copyright (c) 2014-2015 Timo Teräs
4 */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <string.h>
11 #include <sys/socket.h>
12 #include <sys/un.h>
13
14 #include "frrevent.h"
15 #include "zbuf.h"
16 #include "log.h"
17 #include "nhrpd.h"
18
19 const char *nhrp_event_socket_path;
20 struct nhrp_reqid_pool nhrp_event_reqid;
21
22 struct event_manager {
23 struct event *t_reconnect, *t_read, *t_write;
24 struct zbuf ibuf;
25 struct zbuf_queue obuf;
26 int fd;
27 uint8_t ibuf_data[4 * 1024];
28 };
29
30 static void evmgr_reconnect(struct event *t);
31
32 static void evmgr_connection_error(struct event_manager *evmgr)
33 {
34 EVENT_OFF(evmgr->t_read);
35 EVENT_OFF(evmgr->t_write);
36 zbuf_reset(&evmgr->ibuf);
37 zbufq_reset(&evmgr->obuf);
38
39 if (evmgr->fd >= 0)
40 close(evmgr->fd);
41 evmgr->fd = -1;
42 if (nhrp_event_socket_path)
43 event_add_timer_msec(master, evmgr_reconnect, evmgr, 10,
44 &evmgr->t_reconnect);
45 }
46
47 static void evmgr_recv_message(struct event_manager *evmgr, struct zbuf *zb)
48 {
49 struct zbuf zl;
50 uint32_t eventid = 0;
51 size_t len;
52 char buf[256], result[64] = "";
53
54 while (zbuf_may_pull_until(zb, "\n", &zl)) {
55 len = zbuf_used(&zl) - 1;
56 if (len >= sizeof(buf) - 1)
57 continue;
58 memcpy(buf, zbuf_pulln(&zl, len), len);
59 buf[len] = 0;
60
61 debugf(NHRP_DEBUG_EVENT, "evmgr: msg: %s", buf);
62 if (sscanf(buf, "eventid=%" SCNu32, &eventid) == 1)
63 continue;
64 if (sscanf(buf, "result=%63s", result) == 1)
65 continue;
66 }
67 debugf(NHRP_DEBUG_EVENT, "evmgr: received: eventid=%d result=%s",
68 eventid, result);
69 if (eventid && result[0]) {
70 struct nhrp_reqid *r =
71 nhrp_reqid_lookup(&nhrp_event_reqid, eventid);
72 if (r)
73 r->cb(r, result);
74 }
75 }
76
77 static void evmgr_read(struct event *t)
78 {
79 struct event_manager *evmgr = EVENT_ARG(t);
80 struct zbuf *ibuf = &evmgr->ibuf;
81 struct zbuf msg;
82
83 if (zbuf_read(ibuf, evmgr->fd, (size_t)-1) < 0) {
84 evmgr_connection_error(evmgr);
85 return;
86 }
87
88 /* Process all messages in buffer */
89 while (zbuf_may_pull_until(ibuf, "\n\n", &msg))
90 evmgr_recv_message(evmgr, &msg);
91
92 event_add_read(master, evmgr_read, evmgr, evmgr->fd, &evmgr->t_read);
93 }
94
95 static void evmgr_write(struct event *t)
96 {
97 struct event_manager *evmgr = EVENT_ARG(t);
98 int r;
99
100 r = zbufq_write(&evmgr->obuf, evmgr->fd);
101 if (r > 0) {
102 event_add_write(master, evmgr_write, evmgr, evmgr->fd,
103 &evmgr->t_write);
104 } else if (r < 0) {
105 evmgr_connection_error(evmgr);
106 }
107 }
108
109 static void evmgr_hexdump(struct zbuf *zb, const uint8_t *val, size_t vallen)
110 {
111 static const char xd[] = "0123456789abcdef";
112 size_t i;
113 char *ptr;
114
115 ptr = zbuf_pushn(zb, 2 * vallen);
116 if (!ptr)
117 return;
118
119 for (i = 0; i < vallen; i++) {
120 uint8_t b = val[i];
121 *(ptr++) = xd[b >> 4];
122 *(ptr++) = xd[b & 0xf];
123 }
124 }
125
126 static void evmgr_put(struct zbuf *zb, const char *fmt, ...)
127 {
128 const char *pos, *nxt, *str;
129 const uint8_t *bin;
130 const union sockunion *su;
131 int len;
132 va_list va;
133
134 va_start(va, fmt);
135 for (pos = fmt; (nxt = strchr(pos, '%')) != NULL; pos = nxt + 2) {
136 zbuf_put(zb, pos, nxt - pos);
137 switch (nxt[1]) {
138 case '%':
139 zbuf_put8(zb, '%');
140 break;
141 case 'u':
142 zb->tail +=
143 snprintf((char *)zb->tail, zbuf_tailroom(zb),
144 "%u", va_arg(va, uint32_t));
145 break;
146 case 's':
147 str = va_arg(va, const char *);
148 zbuf_put(zb, str, strlen(str));
149 break;
150 case 'U':
151 su = va_arg(va, const union sockunion *);
152 if (sockunion2str(su, (char *)zb->tail,
153 zbuf_tailroom(zb)))
154 zb->tail += strlen((char *)zb->tail);
155 else
156 zbuf_set_werror(zb);
157 break;
158 case 'H':
159 bin = va_arg(va, const uint8_t *);
160 len = va_arg(va, int);
161 evmgr_hexdump(zb, bin, len);
162 break;
163 }
164 }
165 va_end(va);
166 zbuf_put(zb, pos, strlen(pos));
167 }
168
169 static void evmgr_submit(struct event_manager *evmgr, struct zbuf *obuf)
170 {
171 if (obuf->error) {
172 zbuf_free(obuf);
173 return;
174 }
175 zbuf_put(obuf, "\n", 1);
176 zbufq_queue(&evmgr->obuf, obuf);
177 if (evmgr->fd >= 0)
178 event_add_write(master, evmgr_write, evmgr, evmgr->fd,
179 &evmgr->t_write);
180 }
181
182 static void evmgr_reconnect(struct event *t)
183 {
184 struct event_manager *evmgr = EVENT_ARG(t);
185 int fd;
186
187 if (evmgr->fd >= 0 || !nhrp_event_socket_path)
188 return;
189
190 fd = sock_open_unix(nhrp_event_socket_path);
191 if (fd < 0) {
192 zlog_warn("%s: failure connecting nhrp-event socket: %s",
193 __func__, strerror(errno));
194 zbufq_reset(&evmgr->obuf);
195 event_add_timer(master, evmgr_reconnect, evmgr, 10,
196 &evmgr->t_reconnect);
197 return;
198 }
199
200 zlog_info("Connected to Event Manager");
201 evmgr->fd = fd;
202 event_add_read(master, evmgr_read, evmgr, evmgr->fd, &evmgr->t_read);
203 }
204
205 static struct event_manager evmgr_connection;
206
207 void evmgr_init(void)
208 {
209 struct event_manager *evmgr = &evmgr_connection;
210
211 evmgr->fd = -1;
212 zbuf_init(&evmgr->ibuf, evmgr->ibuf_data, sizeof(evmgr->ibuf_data), 0);
213 zbufq_init(&evmgr->obuf);
214 event_add_timer_msec(master, evmgr_reconnect, evmgr, 10,
215 &evmgr->t_reconnect);
216 }
217
218 void evmgr_set_socket(const char *socket)
219 {
220 if (nhrp_event_socket_path) {
221 free((char *)nhrp_event_socket_path);
222 nhrp_event_socket_path = NULL;
223 }
224 if (socket)
225 nhrp_event_socket_path = strdup(socket);
226 evmgr_connection_error(&evmgr_connection);
227 }
228
229 void evmgr_terminate(void)
230 {
231 }
232
233 void evmgr_notify(const char *name, struct nhrp_cache *c,
234 void (*cb)(struct nhrp_reqid *, void *))
235 {
236 struct event_manager *evmgr = &evmgr_connection;
237 struct nhrp_vc *vc;
238 struct nhrp_interface *nifp = c->ifp->info;
239 struct zbuf *zb;
240 afi_t afi = family2afi(sockunion_family(&c->remote_addr));
241
242 if (!nhrp_event_socket_path) {
243 cb(&c->eventid, (void *)"accept");
244 return;
245 }
246
247 debugf(NHRP_DEBUG_EVENT, "evmgr: sending event %s", name);
248
249 vc = c->new.peer ? c->new.peer->vc : NULL;
250 zb = zbuf_alloc(
251 1024 + (vc ? (vc->local.certlen + vc->remote.certlen) * 2 : 0));
252
253 if (cb) {
254 nhrp_reqid_free(&nhrp_event_reqid, &c->eventid);
255 evmgr_put(zb, "eventid=%u\n",
256 nhrp_reqid_alloc(&nhrp_event_reqid, &c->eventid, cb));
257 }
258
259 evmgr_put(zb,
260 "event=%s\n"
261 "type=%s\n"
262 "old_type=%s\n"
263 "num_nhs=%u\n"
264 "interface=%s\n"
265 "local_addr=%U\n",
266 name, nhrp_cache_type_str[c->new.type],
267 nhrp_cache_type_str[c->cur.type],
268 (unsigned int)nhrp_cache_counts[NHRP_CACHE_NHS], c->ifp->name,
269 &nifp->afi[afi].addr);
270
271 if (vc) {
272 evmgr_put(zb,
273 "vc_initiated=%s\n"
274 "local_nbma=%U\n"
275 "local_cert=%H\n"
276 "remote_addr=%U\n"
277 "remote_nbma=%U\n"
278 "remote_cert=%H\n",
279 c->new.peer->requested ? "yes" : "no",
280 &vc->local.nbma, vc->local.cert, vc->local.certlen,
281 &c->remote_addr, &vc->remote.nbma, vc->remote.cert,
282 vc->remote.certlen);
283 }
284
285 evmgr_submit(evmgr, zb);
286 }