]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_event.c
Merge pull request #571 from donaldsharp/nhrp
[mirror_frr.git] / nhrpd / nhrp_event.c
1 /* NHRP event manager
2 * Copyright (c) 2014-2015 Timo Teräs
3 *
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10 #include <string.h>
11 #include <sys/socket.h>
12 #include <sys/un.h>
13
14 #include "thread.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 thread *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 int evmgr_reconnect(struct thread *t);
31
32 static void evmgr_connection_error(struct event_manager *evmgr)
33 {
34 THREAD_OFF(evmgr->t_read);
35 THREAD_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 thread_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 sscanf(buf, "eventid=%d", &eventid);
63 sscanf(buf, "result=%63s", result);
64 }
65 debugf(NHRP_DEBUG_EVENT, "evmgr: received: eventid=%d result=%s", eventid, result);
66 if (eventid && result[0]) {
67 struct nhrp_reqid *r = nhrp_reqid_lookup(&nhrp_event_reqid, eventid);
68 if (r) r->cb(r, result);
69 }
70 }
71
72 static int evmgr_read(struct thread *t)
73 {
74 struct event_manager *evmgr = THREAD_ARG(t);
75 struct zbuf *ibuf = &evmgr->ibuf;
76 struct zbuf msg;
77
78 evmgr->t_read = NULL;
79 if (zbuf_read(ibuf, evmgr->fd, (size_t) -1) < 0) {
80 evmgr_connection_error(evmgr);
81 return 0;
82 }
83
84 /* Process all messages in buffer */
85 while (zbuf_may_pull_until(ibuf, "\n\n", &msg))
86 evmgr_recv_message(evmgr, &msg);
87
88 thread_add_read(master, evmgr_read, evmgr, evmgr->fd, &evmgr->t_read);
89 return 0;
90 }
91
92 static int evmgr_write(struct thread *t)
93 {
94 struct event_manager *evmgr = THREAD_ARG(t);
95 int r;
96
97 evmgr->t_write = NULL;
98 r = zbufq_write(&evmgr->obuf, evmgr->fd);
99 if (r > 0) {
100 thread_add_write(master, evmgr_write, evmgr, evmgr->fd,
101 &evmgr->t_write);
102 } else if (r < 0) {
103 evmgr_connection_error(evmgr);
104 }
105
106 return 0;
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) return;
117
118 for (i = 0; i < vallen; i++) {
119 uint8_t b = val[i];
120 *(ptr++) = xd[b >> 4];
121 *(ptr++) = xd[b & 0xf];
122 }
123 }
124
125 static void evmgr_put(struct zbuf *zb, const char *fmt, ...)
126 {
127 const char *pos, *nxt, *str;
128 const uint8_t *bin;
129 const union sockunion *su;
130 int len;
131 va_list va;
132
133 va_start(va, fmt);
134 for (pos = fmt; (nxt = strchr(pos, '%')) != NULL; pos = nxt + 2) {
135 zbuf_put(zb, pos, nxt-pos);
136 switch (nxt[1]) {
137 case '%':
138 zbuf_put8(zb, '%');
139 break;
140 case 'u':
141 zb->tail += snprintf((char *) zb->tail, zbuf_tailroom(zb), "%u", va_arg(va, uint32_t));
142 break;
143 case 's':
144 str = va_arg(va, const char *);
145 zbuf_put(zb, str, strlen(str));
146 break;
147 case 'U':
148 su = va_arg(va, const union sockunion *);
149 if (sockunion2str(su, (char *) zb->tail, zbuf_tailroom(zb)))
150 zb->tail += strlen((char *) zb->tail);
151 else
152 zbuf_set_werror(zb);
153 break;
154 case 'H':
155 bin = va_arg(va, const uint8_t *);
156 len = va_arg(va, int);
157 evmgr_hexdump(zb, bin, len);
158 break;
159 }
160 }
161 va_end(va);
162 zbuf_put(zb, pos, strlen(pos));
163 }
164
165 static void evmgr_submit(struct event_manager *evmgr, struct zbuf *obuf)
166 {
167 if (obuf->error) {
168 zbuf_free(obuf);
169 return;
170 }
171 zbuf_put(obuf, "\n", 1);
172 zbufq_queue(&evmgr->obuf, obuf);
173 if (evmgr->fd >= 0)
174 thread_add_write(master, evmgr_write, evmgr, evmgr->fd,
175 &evmgr->t_write);
176 }
177
178 static int evmgr_reconnect(struct thread *t)
179 {
180 struct event_manager *evmgr = THREAD_ARG(t);
181 int fd;
182
183 evmgr->t_reconnect = NULL;
184 if (evmgr->fd >= 0 || !nhrp_event_socket_path) return 0;
185
186 fd = sock_open_unix(nhrp_event_socket_path);
187 if (fd < 0) {
188 zlog_warn("%s: failure connecting nhrp-event socket: %s",
189 __PRETTY_FUNCTION__, strerror(errno));
190 zbufq_reset(&evmgr->obuf);
191 thread_add_timer(master, evmgr_reconnect, evmgr, 10,
192 &evmgr->t_reconnect);
193 return 0;
194 }
195
196 zlog_info("Connected to Event Manager");
197 evmgr->fd = fd;
198 thread_add_read(master, evmgr_read, evmgr, evmgr->fd, &evmgr->t_read);
199
200 return 0;
201 }
202
203 static struct event_manager evmgr_connection;
204
205 void evmgr_init(void)
206 {
207 struct event_manager *evmgr = &evmgr_connection;
208
209 evmgr->fd = -1;
210 zbuf_init(&evmgr->ibuf, evmgr->ibuf_data, sizeof(evmgr->ibuf_data), 0);
211 zbufq_init(&evmgr->obuf);
212 thread_add_timer_msec(master, evmgr_reconnect, evmgr, 10,
213 &evmgr->t_reconnect);
214 }
215
216 void evmgr_set_socket(const char *socket)
217 {
218 if (nhrp_event_socket_path) {
219 free((char *) nhrp_event_socket_path);
220 nhrp_event_socket_path = NULL;
221 }
222 if (socket)
223 nhrp_event_socket_path = strdup(socket);
224 evmgr_connection_error(&evmgr_connection);
225 }
226
227 void evmgr_terminate(void)
228 {
229 }
230
231 void evmgr_notify(const char *name, struct nhrp_cache *c, void (*cb)(struct nhrp_reqid *, void *))
232 {
233 struct event_manager *evmgr = &evmgr_connection;
234 struct nhrp_vc *vc;
235 struct nhrp_interface *nifp = c->ifp->info;
236 struct zbuf *zb;
237 afi_t afi = family2afi(sockunion_family(&c->remote_addr));
238
239 if (!nhrp_event_socket_path) {
240 cb(&c->eventid, (void*) "accept");
241 return;
242 }
243
244 debugf(NHRP_DEBUG_EVENT, "evmgr: sending event %s", name);
245
246 vc = c->new.peer ? c->new.peer->vc : NULL;
247 zb = zbuf_alloc(1024 + (vc ? (vc->local.certlen + vc->remote.certlen) * 2 : 0));
248
249 if (cb) {
250 nhrp_reqid_free(&nhrp_event_reqid, &c->eventid);
251 evmgr_put(zb,
252 "eventid=%u\n",
253 nhrp_reqid_alloc(&nhrp_event_reqid, &c->eventid, cb));
254 }
255
256 evmgr_put(zb,
257 "event=%s\n"
258 "type=%s\n"
259 "old_type=%s\n"
260 "num_nhs=%u\n"
261 "interface=%s\n"
262 "local_addr=%U\n",
263 name,
264 nhrp_cache_type_str[c->new.type],
265 nhrp_cache_type_str[c->cur.type],
266 (unsigned int) nhrp_cache_counts[NHRP_CACHE_NHS],
267 c->ifp->name,
268 &nifp->afi[afi].addr);
269
270 if (vc) {
271 evmgr_put(zb,
272 "vc_initiated=%s\n"
273 "local_nbma=%U\n"
274 "local_cert=%H\n"
275 "remote_addr=%U\n"
276 "remote_nbma=%U\n"
277 "remote_cert=%H\n",
278 c->new.peer->requested ? "yes" : "no",
279 &vc->local.nbma,
280 vc->local.cert, vc->local.certlen,
281 &c->remote_addr, &vc->remote.nbma,
282 vc->remote.cert, vc->remote.certlen);
283 }
284
285 evmgr_submit(evmgr, zb);
286 }
287