]>
Commit | Line | Data |
---|---|---|
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 | 29 | static int control_accept(struct thread *); |
8429abe0 RW |
30 | static struct ctl_conn *control_connbyfd(int); |
31 | static struct ctl_conn *control_connbypid(pid_t); | |
32 | static void control_close(int); | |
eac6e3f0 | 33 | static int control_dispatch_imsg(struct thread *); |
8429abe0 RW |
34 | |
35 | struct ctl_conns ctl_conns; | |
36 | ||
37 | static int control_fd; | |
38 | ||
39 | int | |
274f5abf | 40 | control_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 | ||
84 | int | |
85 | control_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 | ||
95 | void | |
274f5abf | 96 | control_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 |
104 | static int |
105 | control_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 | ||
147 | static struct ctl_conn * | |
148 | control_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 | ||
160 | static struct ctl_conn * | |
161 | control_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 | ||
173 | static void | |
174 | control_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 | ||
50478845 MS |
186 | thread_cancel(&c->iev.ev_read); |
187 | thread_cancel(&c->iev.ev_write); | |
8429abe0 RW |
188 | close(c->iev.ibuf.fd); |
189 | accept_unpause(); | |
190 | free(c); | |
191 | } | |
192 | ||
193 | /* ARGSUSED */ | |
eac6e3f0 RW |
194 | static int |
195 | control_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; | |
e1894ff7 KS |
266 | case IMSG_CTL_SHOW_LDP_SYNC: |
267 | ldpe_ldp_sync_ctl(c); | |
268 | break; | |
8429abe0 | 269 | case IMSG_CTL_LOG_VERBOSE: |
eac6e3f0 | 270 | /* ignore */ |
8429abe0 RW |
271 | break; |
272 | default: | |
273 | log_debug("%s: error handling imsg %d", __func__, | |
274 | imsg.hdr.type); | |
275 | break; | |
276 | } | |
277 | imsg_free(&imsg); | |
278 | } | |
279 | ||
280 | imsg_event_add(&c->iev); | |
eac6e3f0 RW |
281 | |
282 | return (0); | |
8429abe0 RW |
283 | } |
284 | ||
285 | int | |
286 | control_imsg_relay(struct imsg *imsg) | |
287 | { | |
288 | struct ctl_conn *c; | |
289 | ||
290 | if ((c = control_connbypid(imsg->hdr.pid)) == NULL) | |
291 | return (0); | |
292 | ||
293 | return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, | |
294 | -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); | |
295 | } |