]>
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 | ||
cc9f21da | 29 | static void 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); | |
cc9f21da | 33 | static void 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 */ | |
cc9f21da | 104 | static void control_accept(struct thread *thread) |
8429abe0 RW |
105 | { |
106 | int connfd; | |
107 | socklen_t len; | |
e30090a6 | 108 | struct sockaddr_un s_un; |
8429abe0 RW |
109 | struct ctl_conn *c; |
110 | ||
e30090a6 | 111 | len = sizeof(s_un); |
eac6e3f0 RW |
112 | if ((connfd = accept(THREAD_FD(thread), (struct sockaddr *)&s_un, |
113 | &len)) == -1) { | |
8429abe0 RW |
114 | /* |
115 | * Pause accept if we are out of file descriptors, or | |
116 | * libevent will haunt us here too. | |
117 | */ | |
118 | if (errno == ENFILE || errno == EMFILE) | |
119 | accept_pause(); | |
120 | else if (errno != EWOULDBLOCK && errno != EINTR && | |
121 | errno != ECONNABORTED) | |
eac6e3f0 | 122 | log_warn("%s: accept", __func__); |
cc9f21da | 123 | return; |
8429abe0 | 124 | } |
eac6e3f0 | 125 | sock_set_nonblock(connfd); |
8429abe0 RW |
126 | |
127 | if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { | |
128 | log_warn(__func__); | |
129 | close(connfd); | |
cc9f21da | 130 | return; |
8429abe0 RW |
131 | } |
132 | ||
133 | imsg_init(&c->iev.ibuf, connfd); | |
eac6e3f0 | 134 | c->iev.handler_read = control_dispatch_imsg; |
66e78ae6 QY |
135 | c->iev.ev_read = NULL; |
136 | thread_add_read(master, c->iev.handler_read, &c->iev, c->iev.ibuf.fd, | |
137 | &c->iev.ev_read); | |
eac6e3f0 RW |
138 | c->iev.handler_write = ldp_write_handler; |
139 | c->iev.ev_write = NULL; | |
8429abe0 RW |
140 | |
141 | TAILQ_INSERT_TAIL(&ctl_conns, c, entry); | |
142 | } | |
143 | ||
144 | static struct ctl_conn * | |
145 | control_connbyfd(int fd) | |
146 | { | |
147 | struct ctl_conn *c; | |
148 | ||
b53f7b86 RW |
149 | TAILQ_FOREACH(c, &ctl_conns, entry) { |
150 | if (c->iev.ibuf.fd == fd) | |
151 | break; | |
152 | } | |
8429abe0 RW |
153 | |
154 | return (c); | |
155 | } | |
156 | ||
157 | static struct ctl_conn * | |
158 | control_connbypid(pid_t pid) | |
159 | { | |
160 | struct ctl_conn *c; | |
161 | ||
b53f7b86 RW |
162 | TAILQ_FOREACH(c, &ctl_conns, entry) { |
163 | if (c->iev.ibuf.pid == pid) | |
164 | break; | |
165 | } | |
8429abe0 RW |
166 | |
167 | return (c); | |
168 | } | |
169 | ||
170 | static void | |
171 | control_close(int fd) | |
172 | { | |
173 | struct ctl_conn *c; | |
174 | ||
175 | if ((c = control_connbyfd(fd)) == NULL) { | |
176 | log_warnx("%s: fd %d: not found", __func__, fd); | |
177 | return; | |
178 | } | |
179 | ||
180 | msgbuf_clear(&c->iev.ibuf.w); | |
181 | TAILQ_REMOVE(&ctl_conns, c, entry); | |
182 | ||
2783a692 DS |
183 | THREAD_OFF(c->iev.ev_read); |
184 | THREAD_OFF(c->iev.ev_write); | |
8429abe0 RW |
185 | close(c->iev.ibuf.fd); |
186 | accept_unpause(); | |
187 | free(c); | |
188 | } | |
189 | ||
190 | /* ARGSUSED */ | |
cc9f21da | 191 | static void control_dispatch_imsg(struct thread *thread) |
8429abe0 | 192 | { |
eac6e3f0 | 193 | int fd = THREAD_FD(thread); |
8429abe0 RW |
194 | struct ctl_conn *c; |
195 | struct imsg imsg; | |
196 | ssize_t n; | |
197 | unsigned int ifidx; | |
8429abe0 RW |
198 | |
199 | if ((c = control_connbyfd(fd)) == NULL) { | |
200 | log_warnx("%s: fd %d: not found", __func__, fd); | |
cc9f21da | 201 | return; |
8429abe0 RW |
202 | } |
203 | ||
eac6e3f0 RW |
204 | c->iev.ev_read = NULL; |
205 | ||
206 | if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || | |
207 | n == 0) { | |
208 | control_close(fd); | |
cc9f21da | 209 | return; |
8429abe0 RW |
210 | } |
211 | ||
212 | for (;;) { | |
213 | if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { | |
214 | control_close(fd); | |
cc9f21da | 215 | return; |
8429abe0 RW |
216 | } |
217 | ||
218 | if (n == 0) | |
219 | break; | |
220 | ||
221 | switch (imsg.hdr.type) { | |
222 | case IMSG_CTL_FIB_COUPLE: | |
223 | case IMSG_CTL_FIB_DECOUPLE: | |
224 | case IMSG_CTL_RELOAD: | |
8429abe0 RW |
225 | case IMSG_CTL_KROUTE: |
226 | case IMSG_CTL_KROUTE_ADDR: | |
227 | case IMSG_CTL_IFINFO: | |
eac6e3f0 | 228 | /* ignore */ |
8429abe0 RW |
229 | break; |
230 | case IMSG_CTL_SHOW_INTERFACE: | |
231 | if (imsg.hdr.len == IMSG_HEADER_SIZE + | |
232 | sizeof(ifidx)) { | |
233 | memcpy(&ifidx, imsg.data, sizeof(ifidx)); | |
234 | ldpe_iface_ctl(c, ifidx); | |
235 | imsg_compose_event(&c->iev, IMSG_CTL_END, 0, | |
236 | 0, -1, NULL, 0); | |
237 | } | |
238 | break; | |
239 | case IMSG_CTL_SHOW_DISCOVERY: | |
240 | ldpe_adj_ctl(c); | |
241 | break; | |
bc0eb287 RW |
242 | case IMSG_CTL_SHOW_DISCOVERY_DTL: |
243 | ldpe_adj_detail_ctl(c); | |
244 | break; | |
8429abe0 RW |
245 | case IMSG_CTL_SHOW_LIB: |
246 | case IMSG_CTL_SHOW_L2VPN_PW: | |
247 | case IMSG_CTL_SHOW_L2VPN_BINDING: | |
248 | c->iev.ibuf.pid = imsg.hdr.pid; | |
249 | ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid, | |
250 | imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); | |
251 | break; | |
252 | case IMSG_CTL_SHOW_NBR: | |
253 | ldpe_nbr_ctl(c); | |
254 | break; | |
255 | case IMSG_CTL_CLEAR_NBR: | |
256 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
257 | sizeof(struct ctl_nbr)) | |
258 | break; | |
259 | ||
260 | nbr_clear_ctl(imsg.data); | |
261 | break; | |
e1894ff7 KS |
262 | case IMSG_CTL_SHOW_LDP_SYNC: |
263 | ldpe_ldp_sync_ctl(c); | |
264 | break; | |
8429abe0 | 265 | case IMSG_CTL_LOG_VERBOSE: |
eac6e3f0 | 266 | /* ignore */ |
8429abe0 RW |
267 | break; |
268 | default: | |
269 | log_debug("%s: error handling imsg %d", __func__, | |
270 | imsg.hdr.type); | |
271 | break; | |
272 | } | |
273 | imsg_free(&imsg); | |
274 | } | |
275 | ||
276 | imsg_event_add(&c->iev); | |
277 | } | |
278 | ||
279 | int | |
280 | control_imsg_relay(struct imsg *imsg) | |
281 | { | |
282 | struct ctl_conn *c; | |
283 | ||
284 | if ((c = control_connbypid(imsg->hdr.pid)) == NULL) | |
285 | return (0); | |
286 | ||
287 | return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, | |
288 | -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); | |
289 | } |