]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/interface.c
Merge pull request #2932 from donaldsharp/ferr_fix
[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(const struct iface *, const 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(const struct iface *a, const struct iface *b)
47 {
48 return (if_cmp_name_func((char *)a->name, (char *)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(ia_adj_head, &iface->ipv4.adj_tree);
85
86 /* ipv6 */
87 iface->ipv6.iface = iface;
88 iface->ipv6.state = IF_STA_DOWN;
89 RB_INIT(ia_adj_head, &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 assert(if_addr != LIST_FIRST(&iface->addr_list));
107 free(if_addr);
108 }
109 }
110
111 struct iface *
112 if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
113 {
114 struct iface *iface;
115
116 RB_FOREACH(iface, iface_head, &xconf->iface_tree)
117 if (iface->ifindex == ifindex)
118 return (iface);
119
120 return (NULL);
121 }
122
123 struct iface *
124 if_lookup_name(struct ldpd_conf *xconf, const char *ifname)
125 {
126 struct iface iface;
127 strlcpy(iface.name, ifname, sizeof(iface.name));
128 return (RB_FIND(iface_head, &xconf->iface_tree, &iface));
129 }
130
131 void
132 if_update_info(struct iface *iface, struct kif *kif)
133 {
134 /* get type */
135 if (kif->flags & IFF_POINTOPOINT)
136 iface->type = IF_TYPE_POINTOPOINT;
137 if (kif->flags & IFF_BROADCAST &&
138 kif->flags & IFF_MULTICAST)
139 iface->type = IF_TYPE_BROADCAST;
140
141 /* get index and flags */
142 iface->ifindex = kif->ifindex;
143 iface->operative = kif->operative;
144 }
145
146 struct iface_af *
147 iface_af_get(struct iface *iface, int af)
148 {
149 switch (af) {
150 case AF_INET:
151 return (&iface->ipv4);
152 case AF_INET6:
153 return (&iface->ipv6);
154 default:
155 fatalx("iface_af_get: unknown af");
156 }
157 }
158
159 static struct if_addr *
160 if_addr_new(struct kaddr *ka)
161 {
162 struct if_addr *if_addr;
163
164 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
165 fatal(__func__);
166
167 if_addr->af = ka->af;
168 if_addr->addr = ka->addr;
169 if_addr->prefixlen = ka->prefixlen;
170 if_addr->dstbrd = ka->dstbrd;
171
172 return (if_addr);
173 }
174
175 static struct if_addr *
176 if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
177 {
178 struct if_addr *if_addr;
179 int af = ka->af;
180
181 LIST_FOREACH(if_addr, addr_list, entry)
182 if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
183 if_addr->prefixlen == ka->prefixlen &&
184 !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
185 return (if_addr);
186
187 return (NULL);
188 }
189
190 void
191 if_addr_add(struct kaddr *ka)
192 {
193 struct iface *iface;
194 struct if_addr *if_addr;
195 struct nbr *nbr;
196
197 if (if_addr_lookup(&global.addr_list, ka) == NULL) {
198 if_addr = if_addr_new(ka);
199
200 LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
201 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
202 if (nbr->state != NBR_STA_OPER)
203 continue;
204 if (if_addr->af == AF_INET && !nbr->v4_enabled)
205 continue;
206 if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
207 continue;
208
209 send_address_single(nbr, if_addr, 0);
210 }
211 }
212
213 iface = if_lookup_name(leconf, ka->ifname);
214 if (iface) {
215 if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
216 iface->linklocal = ka->addr.v6;
217
218 if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
219 if_addr = if_addr_new(ka);
220 LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
221 ldp_if_update(iface, if_addr->af);
222 }
223 }
224 }
225
226 void
227 if_addr_del(struct kaddr *ka)
228 {
229 struct iface *iface;
230 struct if_addr *if_addr;
231 struct nbr *nbr;
232
233 iface = if_lookup_name(leconf, ka->ifname);
234 if (iface) {
235 if (ka->af == AF_INET6 &&
236 IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
237 memset(&iface->linklocal, 0, sizeof(iface->linklocal));
238
239 if_addr = if_addr_lookup(&iface->addr_list, ka);
240 if (if_addr) {
241 LIST_REMOVE(if_addr, entry);
242 ldp_if_update(iface, if_addr->af);
243 free(if_addr);
244 }
245 }
246
247 if_addr = if_addr_lookup(&global.addr_list, ka);
248 if (if_addr) {
249 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
250 if (nbr->state != NBR_STA_OPER)
251 continue;
252 if (if_addr->af == AF_INET && !nbr->v4_enabled)
253 continue;
254 if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
255 continue;
256 send_address_single(nbr, if_addr, 1);
257 }
258 LIST_REMOVE(if_addr, entry);
259 free(if_addr);
260 }
261 }
262
263 static int
264 if_start(struct iface *iface, int af)
265 {
266 struct iface_af *ia;
267 struct timeval now;
268
269 log_debug("%s: %s address-family %s", __func__, iface->name,
270 af_name(af));
271
272 ia = iface_af_get(iface, af);
273
274 gettimeofday(&now, NULL);
275 ia->uptime = now.tv_sec;
276
277 switch (af) {
278 case AF_INET:
279 if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
280 return (-1);
281 break;
282 case AF_INET6:
283 if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
284 return (-1);
285 break;
286 default:
287 fatalx("if_start: unknown af");
288 }
289
290 send_hello(HELLO_LINK, ia, NULL);
291 if_start_hello_timer(ia);
292 ia->state = IF_STA_ACTIVE;
293
294 return (0);
295 }
296
297 static int
298 if_reset(struct iface *iface, int af)
299 {
300 struct iface_af *ia;
301 struct adj *adj;
302
303 log_debug("%s: %s address-family %s", __func__, iface->name,
304 af_name(af));
305
306 ia = iface_af_get(iface, af);
307 if_stop_hello_timer(ia);
308
309 while (!RB_EMPTY(ia_adj_head, &ia->adj_tree)) {
310 adj = RB_ROOT(ia_adj_head, &ia->adj_tree);
311
312 adj_del(adj, S_SHUTDOWN);
313 }
314
315 /* try to cleanup */
316 switch (af) {
317 case AF_INET:
318 if (global.ipv4.ldp_disc_socket != -1)
319 if_leave_ipv4_group(iface, &global.mcast_addr_v4);
320 break;
321 case AF_INET6:
322 if (global.ipv6.ldp_disc_socket != -1)
323 if_leave_ipv6_group(iface, &global.mcast_addr_v6);
324 break;
325 default:
326 fatalx("if_reset: unknown af");
327 }
328
329 ia->state = IF_STA_DOWN;
330
331 return (0);
332 }
333
334 static void
335 if_update_af(struct iface_af *ia)
336 {
337 int addr_ok = 0, socket_ok, rtr_id_ok;
338 struct if_addr *if_addr;
339
340 switch (ia->af) {
341 case AF_INET:
342 /*
343 * NOTE: for LDPv4, each interface should have at least one
344 * valid IP address otherwise they can not be enabled.
345 */
346 LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
347 if (if_addr->af == AF_INET) {
348 addr_ok = 1;
349 break;
350 }
351 }
352 break;
353 case AF_INET6:
354 /* for IPv6 the link-local address is enough. */
355 if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
356 addr_ok = 1;
357 break;
358 default:
359 fatalx("if_update_af: unknown af");
360 }
361
362 if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
363 socket_ok = 1;
364 else
365 socket_ok = 0;
366
367 if (ldp_rtr_id_get(leconf) != INADDR_ANY)
368 rtr_id_ok = 1;
369 else
370 rtr_id_ok = 0;
371
372 if (ia->state == IF_STA_DOWN) {
373 if (!ia->enabled || !ia->iface->operative || !addr_ok ||
374 !socket_ok || !rtr_id_ok)
375 return;
376
377 if_start(ia->iface, ia->af);
378 } else if (ia->state == IF_STA_ACTIVE) {
379 if (ia->enabled && ia->iface->operative && addr_ok &&
380 socket_ok && rtr_id_ok)
381 return;
382
383 if_reset(ia->iface, ia->af);
384 }
385 }
386
387 void
388 ldp_if_update(struct iface *iface, int af)
389 {
390 if (af == AF_INET || af == AF_UNSPEC)
391 if_update_af(&iface->ipv4);
392 if (af == AF_INET6 || af == AF_UNSPEC)
393 if_update_af(&iface->ipv6);
394 }
395
396 void
397 if_update_all(int af)
398 {
399 struct iface *iface;
400
401 RB_FOREACH(iface, iface_head, &leconf->iface_tree)
402 ldp_if_update(iface, af);
403 }
404
405 uint16_t
406 if_get_hello_holdtime(struct iface_af *ia)
407 {
408 if (ia->hello_holdtime != 0)
409 return (ia->hello_holdtime);
410
411 if ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime != 0)
412 return ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime);
413
414 return (leconf->lhello_holdtime);
415 }
416
417 uint16_t
418 if_get_hello_interval(struct iface_af *ia)
419 {
420 if (ia->hello_interval != 0)
421 return (ia->hello_interval);
422
423 if ((ldp_af_conf_get(leconf, ia->af))->lhello_interval != 0)
424 return ((ldp_af_conf_get(leconf, ia->af))->lhello_interval);
425
426 return (leconf->lhello_interval);
427 }
428
429 /* timers */
430 /* ARGSUSED */
431 static int
432 if_hello_timer(struct thread *thread)
433 {
434 struct iface_af *ia = THREAD_ARG(thread);
435
436 ia->hello_timer = NULL;
437 send_hello(HELLO_LINK, ia, NULL);
438 if_start_hello_timer(ia);
439
440 return (0);
441 }
442
443 static void
444 if_start_hello_timer(struct iface_af *ia)
445 {
446 THREAD_TIMER_OFF(ia->hello_timer);
447 ia->hello_timer = NULL;
448 thread_add_timer(master, if_hello_timer, ia, if_get_hello_interval(ia),
449 &ia->hello_timer);
450 }
451
452 static void
453 if_stop_hello_timer(struct iface_af *ia)
454 {
455 THREAD_TIMER_OFF(ia->hello_timer);
456 }
457
458 struct ctl_iface *
459 if_to_ctl(struct iface_af *ia)
460 {
461 static struct ctl_iface ictl;
462 struct timeval now;
463 struct adj *adj;
464
465 ictl.af = ia->af;
466 memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
467 ictl.ifindex = ia->iface->ifindex;
468 ictl.state = ia->state;
469 ictl.type = ia->iface->type;
470 ictl.hello_holdtime = if_get_hello_holdtime(ia);
471 ictl.hello_interval = if_get_hello_interval(ia);
472
473 gettimeofday(&now, NULL);
474 if (ia->state != IF_STA_DOWN &&
475 ia->uptime != 0) {
476 ictl.uptime = now.tv_sec - ia->uptime;
477 } else
478 ictl.uptime = 0;
479
480 ictl.adj_cnt = 0;
481 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
482 ictl.adj_cnt++;
483
484 return (&ictl);
485 }
486
487 /* multicast membership sockopts */
488 in_addr_t
489 if_get_ipv4_addr(struct iface *iface)
490 {
491 struct if_addr *if_addr;
492
493 LIST_FOREACH(if_addr, &iface->addr_list, entry)
494 if (if_addr->af == AF_INET)
495 return (if_addr->addr.v4.s_addr);
496
497 return (INADDR_ANY);
498 }
499
500 static int
501 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
502 {
503 struct in_addr if_addr;
504
505 log_debug("%s: interface %s addr %s", __func__, iface->name,
506 inet_ntoa(*addr));
507
508 if_addr.s_addr = if_get_ipv4_addr(iface);
509
510 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
511 IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
512 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
513 __func__, iface->name, inet_ntoa(*addr));
514 return (-1);
515 }
516 return (0);
517 }
518
519 static int
520 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
521 {
522 struct in_addr if_addr;
523
524 log_debug("%s: interface %s addr %s", __func__, iface->name,
525 inet_ntoa(*addr));
526
527 if_addr.s_addr = if_get_ipv4_addr(iface);
528
529 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
530 IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
531 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
532 "address %s", __func__, iface->name, inet_ntoa(*addr));
533 return (-1);
534 }
535
536 return (0);
537 }
538
539 static int
540 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
541 {
542 struct ipv6_mreq mreq;
543
544 log_debug("%s: interface %s addr %s", __func__, iface->name,
545 log_in6addr(addr));
546
547 mreq.ipv6mr_multiaddr = *addr;
548 mreq.ipv6mr_interface = iface->ifindex;
549
550 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
551 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) {
552 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
553 __func__, iface->name, log_in6addr(addr));
554 return (-1);
555 }
556
557 return (0);
558 }
559
560 static int
561 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
562 {
563 struct ipv6_mreq mreq;
564
565 log_debug("%s: interface %s addr %s", __func__, iface->name,
566 log_in6addr(addr));
567
568 mreq.ipv6mr_multiaddr = *addr;
569 mreq.ipv6mr_interface = iface->ifindex;
570
571 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
572 IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) {
573 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
574 __func__, iface->name, log_in6addr(addr));
575 return (-1);
576 }
577
578 return (0);
579 }