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