]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/control.c
Merge pull request #5412 from opensourcerouting/bfdd-vrf-fix
[mirror_frr.git] / ldpd / control.c
CommitLineData
8429abe0
RW
1/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
eac6e3f0 19#include <zebra.h>
8429abe0 20#include <sys/un.h>
8429abe0
RW
21
22#include "ldpd.h"
23#include "ldpe.h"
24#include "log.h"
25#include "control.h"
26
27#define CONTROL_BACKLOG 5
28
eac6e3f0 29static int control_accept(struct thread *);
8429abe0
RW
30static struct ctl_conn *control_connbyfd(int);
31static struct ctl_conn *control_connbypid(pid_t);
32static void control_close(int);
eac6e3f0 33static int control_dispatch_imsg(struct thread *);
8429abe0
RW
34
35struct ctl_conns ctl_conns;
36
37static int control_fd;
38
39int
274f5abf 40control_init(char *path)
8429abe0 41{
e30090a6 42 struct sockaddr_un s_un;
8429abe0
RW
43 int fd;
44 mode_t old_umask;
45
eac6e3f0 46 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
8429abe0
RW
47 log_warn("%s: socket", __func__);
48 return (-1);
49 }
eac6e3f0 50 sock_set_nonblock(fd);
8429abe0 51
e30090a6
RW
52 memset(&s_un, 0, sizeof(s_un));
53 s_un.sun_family = AF_UNIX;
274f5abf 54 strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path));
8429abe0 55
274f5abf 56 if (unlink(path) == -1)
8429abe0 57 if (errno != ENOENT) {
274f5abf 58 log_warn("%s: unlink %s", __func__, path);
8429abe0
RW
59 close(fd);
60 return (-1);
61 }
62
63 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
e30090a6 64 if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
274f5abf 65 log_warn("%s: bind: %s", __func__, path);
8429abe0
RW
66 close(fd);
67 umask(old_umask);
68 return (-1);
69 }
70 umask(old_umask);
71
274f5abf 72 if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
8429abe0
RW
73 log_warn("%s: chmod", __func__);
74 close(fd);
274f5abf 75 (void)unlink(path);
8429abe0
RW
76 return (-1);
77 }
78
79 control_fd = fd;
80
81 return (0);
82}
83
84int
85control_listen(void)
86{
87 if (listen(control_fd, CONTROL_BACKLOG) == -1) {
88 log_warn("%s: listen", __func__);
89 return (-1);
90 }
91
92 return (accept_add(control_fd, control_accept, NULL));
93}
94
95void
274f5abf 96control_cleanup(char *path)
8429abe0
RW
97{
98 accept_del(control_fd);
99 close(control_fd);
274f5abf 100 unlink(path);
8429abe0
RW
101}
102
103/* ARGSUSED */
eac6e3f0
RW
104static int
105control_accept(struct thread *thread)
8429abe0
RW
106{
107 int connfd;
108 socklen_t len;
e30090a6 109 struct sockaddr_un s_un;
8429abe0
RW
110 struct ctl_conn *c;
111
e30090a6 112 len = sizeof(s_un);
eac6e3f0
RW
113 if ((connfd = accept(THREAD_FD(thread), (struct sockaddr *)&s_un,
114 &len)) == -1) {
8429abe0
RW
115 /*
116 * Pause accept if we are out of file descriptors, or
117 * libevent will haunt us here too.
118 */
119 if (errno == ENFILE || errno == EMFILE)
120 accept_pause();
121 else if (errno != EWOULDBLOCK && errno != EINTR &&
122 errno != ECONNABORTED)
eac6e3f0
RW
123 log_warn("%s: accept", __func__);
124 return (0);
8429abe0 125 }
eac6e3f0 126 sock_set_nonblock(connfd);
8429abe0
RW
127
128 if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
129 log_warn(__func__);
130 close(connfd);
eac6e3f0 131 return (0);
8429abe0
RW
132 }
133
134 imsg_init(&c->iev.ibuf, connfd);
eac6e3f0 135 c->iev.handler_read = control_dispatch_imsg;
66e78ae6
QY
136 c->iev.ev_read = NULL;
137 thread_add_read(master, c->iev.handler_read, &c->iev, c->iev.ibuf.fd,
138 &c->iev.ev_read);
eac6e3f0
RW
139 c->iev.handler_write = ldp_write_handler;
140 c->iev.ev_write = NULL;
8429abe0
RW
141
142 TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
eac6e3f0
RW
143
144 return (0);
8429abe0
RW
145}
146
147static struct ctl_conn *
148control_connbyfd(int fd)
149{
150 struct ctl_conn *c;
151
b53f7b86
RW
152 TAILQ_FOREACH(c, &ctl_conns, entry) {
153 if (c->iev.ibuf.fd == fd)
154 break;
155 }
8429abe0
RW
156
157 return (c);
158}
159
160static struct ctl_conn *
161control_connbypid(pid_t pid)
162{
163 struct ctl_conn *c;
164
b53f7b86
RW
165 TAILQ_FOREACH(c, &ctl_conns, entry) {
166 if (c->iev.ibuf.pid == pid)
167 break;
168 }
8429abe0
RW
169
170 return (c);
171}
172
173static void
174control_close(int fd)
175{
176 struct ctl_conn *c;
177
178 if ((c = control_connbyfd(fd)) == NULL) {
179 log_warnx("%s: fd %d: not found", __func__, fd);
180 return;
181 }
182
183 msgbuf_clear(&c->iev.ibuf.w);
184 TAILQ_REMOVE(&ctl_conns, c, entry);
185
eac6e3f0
RW
186 THREAD_READ_OFF(c->iev.ev_read);
187 THREAD_WRITE_OFF(c->iev.ev_write);
8429abe0
RW
188 close(c->iev.ibuf.fd);
189 accept_unpause();
190 free(c);
191}
192
193/* ARGSUSED */
eac6e3f0
RW
194static int
195control_dispatch_imsg(struct thread *thread)
8429abe0 196{
eac6e3f0 197 int fd = THREAD_FD(thread);
8429abe0
RW
198 struct ctl_conn *c;
199 struct imsg imsg;
200 ssize_t n;
201 unsigned int ifidx;
8429abe0
RW
202
203 if ((c = control_connbyfd(fd)) == NULL) {
204 log_warnx("%s: fd %d: not found", __func__, fd);
eac6e3f0 205 return (0);
8429abe0
RW
206 }
207
eac6e3f0
RW
208 c->iev.ev_read = NULL;
209
210 if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) ||
211 n == 0) {
212 control_close(fd);
213 return (0);
8429abe0
RW
214 }
215
216 for (;;) {
217 if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
218 control_close(fd);
eac6e3f0 219 return (0);
8429abe0
RW
220 }
221
222 if (n == 0)
223 break;
224
225 switch (imsg.hdr.type) {
226 case IMSG_CTL_FIB_COUPLE:
227 case IMSG_CTL_FIB_DECOUPLE:
228 case IMSG_CTL_RELOAD:
8429abe0
RW
229 case IMSG_CTL_KROUTE:
230 case IMSG_CTL_KROUTE_ADDR:
231 case IMSG_CTL_IFINFO:
eac6e3f0 232 /* ignore */
8429abe0
RW
233 break;
234 case IMSG_CTL_SHOW_INTERFACE:
235 if (imsg.hdr.len == IMSG_HEADER_SIZE +
236 sizeof(ifidx)) {
237 memcpy(&ifidx, imsg.data, sizeof(ifidx));
238 ldpe_iface_ctl(c, ifidx);
239 imsg_compose_event(&c->iev, IMSG_CTL_END, 0,
240 0, -1, NULL, 0);
241 }
242 break;
243 case IMSG_CTL_SHOW_DISCOVERY:
244 ldpe_adj_ctl(c);
245 break;
bc0eb287
RW
246 case IMSG_CTL_SHOW_DISCOVERY_DTL:
247 ldpe_adj_detail_ctl(c);
248 break;
8429abe0
RW
249 case IMSG_CTL_SHOW_LIB:
250 case IMSG_CTL_SHOW_L2VPN_PW:
251 case IMSG_CTL_SHOW_L2VPN_BINDING:
252 c->iev.ibuf.pid = imsg.hdr.pid;
253 ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid,
254 imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
255 break;
256 case IMSG_CTL_SHOW_NBR:
257 ldpe_nbr_ctl(c);
258 break;
259 case IMSG_CTL_CLEAR_NBR:
260 if (imsg.hdr.len != IMSG_HEADER_SIZE +
261 sizeof(struct ctl_nbr))
262 break;
263
264 nbr_clear_ctl(imsg.data);
265 break;
266 case IMSG_CTL_LOG_VERBOSE:
eac6e3f0 267 /* ignore */
8429abe0
RW
268 break;
269 default:
270 log_debug("%s: error handling imsg %d", __func__,
271 imsg.hdr.type);
272 break;
273 }
274 imsg_free(&imsg);
275 }
276
277 imsg_event_add(&c->iev);
eac6e3f0
RW
278
279 return (0);
8429abe0
RW
280}
281
282int
283control_imsg_relay(struct imsg *imsg)
284{
285 struct ctl_conn *c;
286
287 if ((c = control_connbypid(imsg->hdr.pid)) == NULL)
288 return (0);
289
290 return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid,
291 -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE));
292}