]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/control.c
Zebra: Data structures for RMAC processing in FPM
[mirror_frr.git] / ldpd / control.c
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
19 #include <zebra.h>
20 #include <sys/un.h>
21
22 #include "ldpd.h"
23 #include "ldpe.h"
24 #include "log.h"
25 #include "control.h"
26
27 #define CONTROL_BACKLOG 5
28
29 static int control_accept(struct thread *);
30 static struct ctl_conn *control_connbyfd(int);
31 static struct ctl_conn *control_connbypid(pid_t);
32 static void control_close(int);
33 static int control_dispatch_imsg(struct thread *);
34
35 struct ctl_conns ctl_conns;
36
37 static int control_fd;
38
39 int
40 control_init(char *path)
41 {
42 struct sockaddr_un s_un;
43 int fd;
44 mode_t old_umask;
45
46 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
47 log_warn("%s: socket", __func__);
48 return (-1);
49 }
50 sock_set_nonblock(fd);
51
52 memset(&s_un, 0, sizeof(s_un));
53 s_un.sun_family = AF_UNIX;
54 strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path));
55
56 if (unlink(path) == -1)
57 if (errno != ENOENT) {
58 log_warn("%s: unlink %s", __func__, path);
59 close(fd);
60 return (-1);
61 }
62
63 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
64 if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
65 log_warn("%s: bind: %s", __func__, path);
66 close(fd);
67 umask(old_umask);
68 return (-1);
69 }
70 umask(old_umask);
71
72 if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
73 log_warn("%s: chmod", __func__);
74 close(fd);
75 (void)unlink(path);
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
96 control_cleanup(char *path)
97 {
98 accept_del(control_fd);
99 close(control_fd);
100 unlink(path);
101 }
102
103 /* ARGSUSED */
104 static int
105 control_accept(struct thread *thread)
106 {
107 int connfd;
108 socklen_t len;
109 struct sockaddr_un s_un;
110 struct ctl_conn *c;
111
112 len = sizeof(s_un);
113 if ((connfd = accept(THREAD_FD(thread), (struct sockaddr *)&s_un,
114 &len)) == -1) {
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)
123 log_warn("%s: accept", __func__);
124 return (0);
125 }
126 sock_set_nonblock(connfd);
127
128 if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
129 log_warn(__func__);
130 close(connfd);
131 return (0);
132 }
133
134 imsg_init(&c->iev.ibuf, connfd);
135 c->iev.handler_read = control_dispatch_imsg;
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);
139 c->iev.handler_write = ldp_write_handler;
140 c->iev.ev_write = NULL;
141
142 TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
143
144 return (0);
145 }
146
147 static struct ctl_conn *
148 control_connbyfd(int fd)
149 {
150 struct ctl_conn *c;
151
152 TAILQ_FOREACH(c, &ctl_conns, entry) {
153 if (c->iev.ibuf.fd == fd)
154 break;
155 }
156
157 return (c);
158 }
159
160 static struct ctl_conn *
161 control_connbypid(pid_t pid)
162 {
163 struct ctl_conn *c;
164
165 TAILQ_FOREACH(c, &ctl_conns, entry) {
166 if (c->iev.ibuf.pid == pid)
167 break;
168 }
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
186 THREAD_READ_OFF(c->iev.ev_read);
187 THREAD_WRITE_OFF(c->iev.ev_write);
188 close(c->iev.ibuf.fd);
189 accept_unpause();
190 free(c);
191 }
192
193 /* ARGSUSED */
194 static int
195 control_dispatch_imsg(struct thread *thread)
196 {
197 int fd = THREAD_FD(thread);
198 struct ctl_conn *c;
199 struct imsg imsg;
200 ssize_t n;
201 unsigned int ifidx;
202
203 if ((c = control_connbyfd(fd)) == NULL) {
204 log_warnx("%s: fd %d: not found", __func__, fd);
205 return (0);
206 }
207
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);
214 }
215
216 for (;;) {
217 if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
218 control_close(fd);
219 return (0);
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:
229 case IMSG_CTL_KROUTE:
230 case IMSG_CTL_KROUTE_ADDR:
231 case IMSG_CTL_IFINFO:
232 /* ignore */
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;
246 case IMSG_CTL_SHOW_DISCOVERY_DTL:
247 ldpe_adj_detail_ctl(c);
248 break;
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:
267 /* ignore */
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);
278
279 return (0);
280 }
281
282 int
283 control_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 }