]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/interface.c
Merge remote-tracking branch 'origin/stable/3.0'
[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 = NULL;
444 thread_add_timer(master, if_hello_timer, ia, if_get_hello_interval(ia),
445 &ia->hello_timer);
446 }
447
448 static void
449 if_stop_hello_timer(struct iface_af *ia)
450 {
451 THREAD_TIMER_OFF(ia->hello_timer);
452 }
453
454 struct ctl_iface *
455 if_to_ctl(struct iface_af *ia)
456 {
457 static struct ctl_iface ictl;
458 struct timeval now;
459 struct adj *adj;
460
461 ictl.af = ia->af;
462 memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
463 ictl.ifindex = ia->iface->ifindex;
464 ictl.state = ia->state;
465 ictl.type = ia->iface->type;
466 ictl.hello_holdtime = if_get_hello_holdtime(ia);
467 ictl.hello_interval = if_get_hello_interval(ia);
468
469 gettimeofday(&now, NULL);
470 if (ia->state != IF_STA_DOWN &&
471 ia->uptime != 0) {
472 ictl.uptime = now.tv_sec - ia->uptime;
473 } else
474 ictl.uptime = 0;
475
476 ictl.adj_cnt = 0;
477 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
478 ictl.adj_cnt++;
479
480 return (&ictl);
481 }
482
483 /* multicast membership sockopts */
484 in_addr_t
485 if_get_ipv4_addr(struct iface *iface)
486 {
487 struct if_addr *if_addr;
488
489 LIST_FOREACH(if_addr, &iface->addr_list, entry)
490 if (if_addr->af == AF_INET)
491 return (if_addr->addr.v4.s_addr);
492
493 return (INADDR_ANY);
494 }
495
496 static int
497 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
498 {
499 struct in_addr if_addr;
500
501 log_debug("%s: interface %s addr %s", __func__, iface->name,
502 inet_ntoa(*addr));
503
504 if_addr.s_addr = if_get_ipv4_addr(iface);
505
506 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
507 IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
508 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
509 __func__, iface->name, inet_ntoa(*addr));
510 return (-1);
511 }
512 return (0);
513 }
514
515 static int
516 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
517 {
518 struct in_addr if_addr;
519
520 log_debug("%s: interface %s addr %s", __func__, iface->name,
521 inet_ntoa(*addr));
522
523 if_addr.s_addr = if_get_ipv4_addr(iface);
524
525 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
526 IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
527 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
528 "address %s", __func__, iface->name, inet_ntoa(*addr));
529 return (-1);
530 }
531
532 return (0);
533 }
534
535 static int
536 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
537 {
538 struct ipv6_mreq mreq;
539
540 log_debug("%s: interface %s addr %s", __func__, iface->name,
541 log_in6addr(addr));
542
543 mreq.ipv6mr_multiaddr = *addr;
544 mreq.ipv6mr_interface = iface->ifindex;
545
546 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
547 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) {
548 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
549 __func__, iface->name, log_in6addr(addr));
550 return (-1);
551 }
552
553 return (0);
554 }
555
556 static int
557 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
558 {
559 struct ipv6_mreq mreq;
560
561 log_debug("%s: interface %s addr %s", __func__, iface->name,
562 log_in6addr(addr));
563
564 mreq.ipv6mr_multiaddr = *addr;
565 mreq.ipv6mr_interface = iface->ifindex;
566
567 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
568 IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) {
569 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
570 __func__, iface->name, log_in6addr(addr));
571 return (-1);
572 }
573
574 return (0);
575 }