]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/interface.c
debian: add pkg-config to build-depends
[mirror_frr.git] / ldpd / interface.c
1 /* $OpenBSD$ */
2
3 /*
4 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 #include <zebra.h>
22
23 #include "ldpd.h"
24 #include "ldpe.h"
25 #include "log.h"
26
27 #include "sockopt.h"
28
29 static __inline int iface_compare(struct iface *, struct iface *);
30 static struct if_addr *if_addr_new(struct kaddr *);
31 static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
32 static int if_start(struct iface *, int);
33 static int if_reset(struct iface *, int);
34 static void if_update_af(struct iface_af *);
35 static int if_hello_timer(struct thread *);
36 static void if_start_hello_timer(struct iface_af *);
37 static void if_stop_hello_timer(struct iface_af *);
38 static int if_join_ipv4_group(struct iface *, struct in_addr *);
39 static int if_leave_ipv4_group(struct iface *, struct in_addr *);
40 static int if_join_ipv6_group(struct iface *, struct in6_addr *);
41 static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
42
43 RB_GENERATE(iface_head, iface, entry, iface_compare)
44
45 static __inline int
46 iface_compare(struct iface *a, struct iface *b)
47 {
48 return (strcmp(a->name, b->name));
49 }
50
51 struct iface *
52 if_new(const char *name)
53 {
54 struct iface *iface;
55
56 if ((iface = calloc(1, sizeof(*iface))) == NULL)
57 fatal("if_new: calloc");
58
59 strlcpy(iface->name, name, sizeof(iface->name));
60
61 /* ipv4 */
62 iface->ipv4.af = AF_INET;
63 iface->ipv4.iface = iface;
64 iface->ipv4.enabled = 0;
65
66 /* ipv6 */
67 iface->ipv6.af = AF_INET6;
68 iface->ipv6.iface = iface;
69 iface->ipv6.enabled = 0;
70
71 return (iface);
72 }
73
74 void
75 ldpe_if_init(struct iface *iface)
76 {
77 log_debug("%s: interface %s", __func__, iface->name);
78
79 LIST_INIT(&iface->addr_list);
80
81 /* ipv4 */
82 iface->ipv4.iface = iface;
83 iface->ipv4.state = IF_STA_DOWN;
84 RB_INIT(&iface->ipv4.adj_tree);
85
86 /* ipv6 */
87 iface->ipv6.iface = iface;
88 iface->ipv6.state = IF_STA_DOWN;
89 RB_INIT(&iface->ipv6.adj_tree);
90 }
91
92 void
93 ldpe_if_exit(struct iface *iface)
94 {
95 struct if_addr *if_addr;
96
97 log_debug("%s: interface %s", __func__, iface->name);
98
99 if (iface->ipv4.state == IF_STA_ACTIVE)
100 if_reset(iface, AF_INET);
101 if (iface->ipv6.state == IF_STA_ACTIVE)
102 if_reset(iface, AF_INET6);
103
104 while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
105 LIST_REMOVE(if_addr, entry);
106 free(if_addr);
107 }
108 }
109
110 struct iface *
111 if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
112 {
113 struct iface *iface;
114
115 RB_FOREACH(iface, iface_head, &xconf->iface_tree)
116 if (iface->ifindex == ifindex)
117 return (iface);
118
119 return (NULL);
120 }
121
122 struct iface *
123 if_lookup_name(struct ldpd_conf *xconf, const char *ifname)
124 {
125 struct iface iface;
126 strlcpy(iface.name, ifname, sizeof(iface.name));
127 return (RB_FIND(iface_head, &xconf->iface_tree, &iface));
128 }
129
130 void
131 if_update_info(struct iface *iface, struct kif *kif)
132 {
133 /* get type */
134 if (kif->flags & IFF_POINTOPOINT)
135 iface->type = IF_TYPE_POINTOPOINT;
136 if (kif->flags & IFF_BROADCAST &&
137 kif->flags & IFF_MULTICAST)
138 iface->type = IF_TYPE_BROADCAST;
139
140 /* get index and flags */
141 iface->ifindex = kif->ifindex;
142 iface->operative = kif->operative;
143 }
144
145 struct iface_af *
146 iface_af_get(struct iface *iface, int af)
147 {
148 switch (af) {
149 case AF_INET:
150 return (&iface->ipv4);
151 case AF_INET6:
152 return (&iface->ipv6);
153 default:
154 fatalx("iface_af_get: unknown af");
155 }
156 }
157
158 static struct if_addr *
159 if_addr_new(struct kaddr *ka)
160 {
161 struct if_addr *if_addr;
162
163 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
164 fatal(__func__);
165
166 if_addr->af = ka->af;
167 if_addr->addr = ka->addr;
168 if_addr->prefixlen = ka->prefixlen;
169 if_addr->dstbrd = ka->dstbrd;
170
171 return (if_addr);
172 }
173
174 static struct if_addr *
175 if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
176 {
177 struct if_addr *if_addr;
178 int af = ka->af;
179
180 LIST_FOREACH(if_addr, addr_list, entry)
181 if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
182 if_addr->prefixlen == ka->prefixlen &&
183 !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
184 return (if_addr);
185
186 return (NULL);
187 }
188
189 void
190 if_addr_add(struct kaddr *ka)
191 {
192 struct iface *iface;
193 struct if_addr *if_addr;
194 struct nbr *nbr;
195
196 if (if_addr_lookup(&global.addr_list, ka) == NULL) {
197 if_addr = if_addr_new(ka);
198
199 LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
200 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
201 if (nbr->state != NBR_STA_OPER)
202 continue;
203 if (if_addr->af == AF_INET && !nbr->v4_enabled)
204 continue;
205 if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
206 continue;
207
208 send_address_single(nbr, if_addr, 0);
209 }
210 }
211
212 iface = if_lookup_name(leconf, ka->ifname);
213 if (iface) {
214 if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
215 iface->linklocal = ka->addr.v6;
216
217 if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
218 if_addr = if_addr_new(ka);
219 LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
220 ldp_if_update(iface, if_addr->af);
221 }
222 }
223 }
224
225 void
226 if_addr_del(struct kaddr *ka)
227 {
228 struct iface *iface;
229 struct if_addr *if_addr;
230 struct nbr *nbr;
231
232 iface = if_lookup_name(leconf, ka->ifname);
233 if (iface) {
234 if (ka->af == AF_INET6 &&
235 IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
236 memset(&iface->linklocal, 0, sizeof(iface->linklocal));
237
238 if_addr = if_addr_lookup(&iface->addr_list, ka);
239 if (if_addr) {
240 LIST_REMOVE(if_addr, entry);
241 ldp_if_update(iface, if_addr->af);
242 free(if_addr);
243 }
244 }
245
246 if_addr = if_addr_lookup(&global.addr_list, ka);
247 if (if_addr) {
248 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
249 if (nbr->state != NBR_STA_OPER)
250 continue;
251 if (if_addr->af == AF_INET && !nbr->v4_enabled)
252 continue;
253 if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
254 continue;
255 send_address_single(nbr, if_addr, 1);
256 }
257 LIST_REMOVE(if_addr, entry);
258 free(if_addr);
259 }
260 }
261
262 static int
263 if_start(struct iface *iface, int af)
264 {
265 struct iface_af *ia;
266 struct timeval now;
267
268 log_debug("%s: %s address-family %s", __func__, iface->name,
269 af_name(af));
270
271 ia = iface_af_get(iface, af);
272
273 gettimeofday(&now, NULL);
274 ia->uptime = now.tv_sec;
275
276 switch (af) {
277 case AF_INET:
278 if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
279 return (-1);
280 break;
281 case AF_INET6:
282 if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
283 return (-1);
284 break;
285 default:
286 fatalx("if_start: unknown af");
287 }
288
289 send_hello(HELLO_LINK, ia, NULL);
290 if_start_hello_timer(ia);
291 ia->state = IF_STA_ACTIVE;
292
293 return (0);
294 }
295
296 static int
297 if_reset(struct iface *iface, int af)
298 {
299 struct iface_af *ia;
300 struct adj *adj;
301
302 log_debug("%s: %s address-family %s", __func__, iface->name,
303 af_name(af));
304
305 ia = iface_af_get(iface, af);
306 if_stop_hello_timer(ia);
307
308 while ((adj = RB_ROOT(&ia->adj_tree)) != NULL)
309 adj_del(adj, S_SHUTDOWN);
310
311 /* try to cleanup */
312 switch (af) {
313 case AF_INET:
314 if (global.ipv4.ldp_disc_socket != -1)
315 if_leave_ipv4_group(iface, &global.mcast_addr_v4);
316 break;
317 case AF_INET6:
318 if (global.ipv6.ldp_disc_socket != -1)
319 if_leave_ipv6_group(iface, &global.mcast_addr_v6);
320 break;
321 default:
322 fatalx("if_reset: unknown af");
323 }
324
325 ia->state = IF_STA_DOWN;
326
327 return (0);
328 }
329
330 static void
331 if_update_af(struct iface_af *ia)
332 {
333 int addr_ok = 0, socket_ok, rtr_id_ok;
334 struct if_addr *if_addr;
335
336 switch (ia->af) {
337 case AF_INET:
338 /*
339 * NOTE: for LDPv4, each interface should have at least one
340 * valid IP address otherwise they can not be enabled.
341 */
342 LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
343 if (if_addr->af == AF_INET) {
344 addr_ok = 1;
345 break;
346 }
347 }
348 break;
349 case AF_INET6:
350 /* for IPv6 the link-local address is enough. */
351 if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
352 addr_ok = 1;
353 break;
354 default:
355 fatalx("if_update_af: unknown af");
356 }
357
358 if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
359 socket_ok = 1;
360 else
361 socket_ok = 0;
362
363 if (ldp_rtr_id_get(leconf) != INADDR_ANY)
364 rtr_id_ok = 1;
365 else
366 rtr_id_ok = 0;
367
368 if (ia->state == IF_STA_DOWN) {
369 if (!ia->enabled || !ia->iface->operative || !addr_ok ||
370 !socket_ok || !rtr_id_ok)
371 return;
372
373 if_start(ia->iface, ia->af);
374 } else if (ia->state == IF_STA_ACTIVE) {
375 if (ia->enabled && ia->iface->operative && addr_ok &&
376 socket_ok && rtr_id_ok)
377 return;
378
379 if_reset(ia->iface, ia->af);
380 }
381 }
382
383 void
384 ldp_if_update(struct iface *iface, int af)
385 {
386 if (af == AF_INET || af == AF_UNSPEC)
387 if_update_af(&iface->ipv4);
388 if (af == AF_INET6 || af == AF_UNSPEC)
389 if_update_af(&iface->ipv6);
390 }
391
392 void
393 if_update_all(int af)
394 {
395 struct iface *iface;
396
397 RB_FOREACH(iface, iface_head, &leconf->iface_tree)
398 ldp_if_update(iface, af);
399 }
400
401 uint16_t
402 if_get_hello_holdtime(struct iface_af *ia)
403 {
404 if (ia->hello_holdtime != 0)
405 return (ia->hello_holdtime);
406
407 if ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime != 0)
408 return ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime);
409
410 return (leconf->lhello_holdtime);
411 }
412
413 uint16_t
414 if_get_hello_interval(struct iface_af *ia)
415 {
416 if (ia->hello_interval != 0)
417 return (ia->hello_interval);
418
419 if ((ldp_af_conf_get(leconf, ia->af))->lhello_interval != 0)
420 return ((ldp_af_conf_get(leconf, ia->af))->lhello_interval);
421
422 return (leconf->lhello_interval);
423 }
424
425 /* timers */
426 /* ARGSUSED */
427 static int
428 if_hello_timer(struct thread *thread)
429 {
430 struct iface_af *ia = THREAD_ARG(thread);
431
432 ia->hello_timer = NULL;
433 send_hello(HELLO_LINK, ia, NULL);
434 if_start_hello_timer(ia);
435
436 return (0);
437 }
438
439 static void
440 if_start_hello_timer(struct iface_af *ia)
441 {
442 THREAD_TIMER_OFF(ia->hello_timer);
443 ia->hello_timer = thread_add_timer(master, if_hello_timer, ia,
444 if_get_hello_interval(ia));
445 }
446
447 static void
448 if_stop_hello_timer(struct iface_af *ia)
449 {
450 THREAD_TIMER_OFF(ia->hello_timer);
451 }
452
453 struct ctl_iface *
454 if_to_ctl(struct iface_af *ia)
455 {
456 static struct ctl_iface ictl;
457 struct timeval now;
458 struct adj *adj;
459
460 ictl.af = ia->af;
461 memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
462 ictl.ifindex = ia->iface->ifindex;
463 ictl.state = ia->state;
464 ictl.type = ia->iface->type;
465 ictl.hello_holdtime = if_get_hello_holdtime(ia);
466 ictl.hello_interval = if_get_hello_interval(ia);
467
468 gettimeofday(&now, NULL);
469 if (ia->state != IF_STA_DOWN &&
470 ia->uptime != 0) {
471 ictl.uptime = now.tv_sec - ia->uptime;
472 } else
473 ictl.uptime = 0;
474
475 ictl.adj_cnt = 0;
476 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
477 ictl.adj_cnt++;
478
479 return (&ictl);
480 }
481
482 /* multicast membership sockopts */
483 in_addr_t
484 if_get_ipv4_addr(struct iface *iface)
485 {
486 struct if_addr *if_addr;
487
488 LIST_FOREACH(if_addr, &iface->addr_list, entry)
489 if (if_addr->af == AF_INET)
490 return (if_addr->addr.v4.s_addr);
491
492 return (INADDR_ANY);
493 }
494
495 static int
496 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
497 {
498 struct in_addr if_addr;
499
500 log_debug("%s: interface %s addr %s", __func__, iface->name,
501 inet_ntoa(*addr));
502
503 if_addr.s_addr = if_get_ipv4_addr(iface);
504
505 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
506 IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
507 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
508 __func__, iface->name, inet_ntoa(*addr));
509 return (-1);
510 }
511 return (0);
512 }
513
514 static int
515 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
516 {
517 struct in_addr if_addr;
518
519 log_debug("%s: interface %s addr %s", __func__, iface->name,
520 inet_ntoa(*addr));
521
522 if_addr.s_addr = if_get_ipv4_addr(iface);
523
524 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
525 IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
526 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
527 "address %s", __func__, iface->name, inet_ntoa(*addr));
528 return (-1);
529 }
530
531 return (0);
532 }
533
534 static int
535 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
536 {
537 struct ipv6_mreq mreq;
538
539 log_debug("%s: interface %s addr %s", __func__, iface->name,
540 log_in6addr(addr));
541
542 mreq.ipv6mr_multiaddr = *addr;
543 mreq.ipv6mr_interface = iface->ifindex;
544
545 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
546 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) {
547 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
548 __func__, iface->name, log_in6addr(addr));
549 return (-1);
550 }
551
552 return (0);
553 }
554
555 static int
556 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
557 {
558 struct ipv6_mreq mreq;
559
560 log_debug("%s: interface %s addr %s", __func__, iface->name,
561 log_in6addr(addr));
562
563 mreq.ipv6mr_multiaddr = *addr;
564 mreq.ipv6mr_interface = iface->ifindex;
565
566 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
567 IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) {
568 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
569 __func__, iface->name, log_in6addr(addr));
570 return (-1);
571 }
572
573 return (0);
574 }