]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/interface.c
ldpd: fixes to handle interface renames properly
[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 *, int);
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->flags = kif->flags;
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
291 if_start_hello_timer(ia);
292 return (0);
293 }
294
295 static int
296 if_reset(struct iface *iface, int af)
297 {
298 struct iface_af *ia;
299 struct adj *adj;
300
301 log_debug("%s: %s address-family %s", __func__, iface->name,
302 af_name(af));
303
304 ia = iface_af_get(iface, af);
305 if_stop_hello_timer(ia);
306
307 while ((adj = RB_ROOT(&ia->adj_tree)) != NULL)
308 adj_del(adj, S_SHUTDOWN);
309
310 /* try to cleanup */
311 switch (af) {
312 case AF_INET:
313 if (global.ipv4.ldp_disc_socket != -1)
314 if_leave_ipv4_group(iface, &global.mcast_addr_v4);
315 break;
316 case AF_INET6:
317 if (global.ipv6.ldp_disc_socket != -1)
318 if_leave_ipv6_group(iface, &global.mcast_addr_v6);
319 break;
320 default:
321 fatalx("if_start: unknown af");
322 }
323
324 return (0);
325 }
326
327 static void
328 if_update_af(struct iface_af *ia, int link_ok)
329 {
330 int addr_ok = 0, socket_ok, rtr_id_ok;
331 struct if_addr *if_addr;
332
333 switch (ia->af) {
334 case AF_INET:
335 /*
336 * NOTE: for LDPv4, each interface should have at least one
337 * valid IP address otherwise they can not be enabled.
338 */
339 LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
340 if (if_addr->af == AF_INET) {
341 addr_ok = 1;
342 break;
343 }
344 }
345 break;
346 case AF_INET6:
347 /* for IPv6 the link-local address is enough. */
348 if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
349 addr_ok = 1;
350 break;
351 default:
352 fatalx("if_update_af: unknown af");
353 }
354
355 if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
356 socket_ok = 1;
357 else
358 socket_ok = 0;
359
360 if (ldp_rtr_id_get(leconf) != INADDR_ANY)
361 rtr_id_ok = 1;
362 else
363 rtr_id_ok = 0;
364
365 if (ia->state == IF_STA_DOWN) {
366 if (!ia->enabled || !link_ok || !addr_ok || !socket_ok ||
367 !rtr_id_ok)
368 return;
369
370 ia->state = IF_STA_ACTIVE;
371 if_start(ia->iface, ia->af);
372 } else if (ia->state == IF_STA_ACTIVE) {
373 if (ia->enabled && link_ok && addr_ok && socket_ok && rtr_id_ok)
374 return;
375
376 ia->state = IF_STA_DOWN;
377 if_reset(ia->iface, ia->af);
378 }
379 }
380
381 void
382 ldp_if_update(struct iface *iface, int af)
383 {
384 int link_ok;
385
386 link_ok = (iface->flags & IFF_UP) && (iface->flags & IFF_RUNNING);
387
388 if (af == AF_INET || af == AF_UNSPEC)
389 if_update_af(&iface->ipv4, link_ok);
390 if (af == AF_INET6 || af == AF_UNSPEC)
391 if_update_af(&iface->ipv6, link_ok);
392 }
393
394 void
395 if_update_all(int af)
396 {
397 struct iface *iface;
398
399 RB_FOREACH(iface, iface_head, &leconf->iface_tree)
400 ldp_if_update(iface, af);
401 }
402
403 uint16_t
404 if_get_hello_holdtime(struct iface_af *ia)
405 {
406 if (ia->hello_holdtime != 0)
407 return (ia->hello_holdtime);
408
409 if ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime != 0)
410 return ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime);
411
412 return (leconf->lhello_holdtime);
413 }
414
415 uint16_t
416 if_get_hello_interval(struct iface_af *ia)
417 {
418 if (ia->hello_interval != 0)
419 return (ia->hello_interval);
420
421 if ((ldp_af_conf_get(leconf, ia->af))->lhello_interval != 0)
422 return ((ldp_af_conf_get(leconf, ia->af))->lhello_interval);
423
424 return (leconf->lhello_interval);
425 }
426
427 /* timers */
428 /* ARGSUSED */
429 static int
430 if_hello_timer(struct thread *thread)
431 {
432 struct iface_af *ia = THREAD_ARG(thread);
433
434 ia->hello_timer = NULL;
435 send_hello(HELLO_LINK, ia, NULL);
436 if_start_hello_timer(ia);
437
438 return (0);
439 }
440
441 static void
442 if_start_hello_timer(struct iface_af *ia)
443 {
444 THREAD_TIMER_OFF(ia->hello_timer);
445 ia->hello_timer = thread_add_timer(master, if_hello_timer, ia,
446 if_get_hello_interval(ia));
447 }
448
449 static void
450 if_stop_hello_timer(struct iface_af *ia)
451 {
452 THREAD_TIMER_OFF(ia->hello_timer);
453 }
454
455 struct ctl_iface *
456 if_to_ctl(struct iface_af *ia)
457 {
458 static struct ctl_iface ictl;
459 struct timeval now;
460 struct adj *adj;
461
462 ictl.af = ia->af;
463 memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
464 ictl.ifindex = ia->iface->ifindex;
465 ictl.state = ia->state;
466 ictl.flags = ia->iface->flags;
467 ictl.type = ia->iface->type;
468 ictl.hello_holdtime = if_get_hello_holdtime(ia);
469 ictl.hello_interval = if_get_hello_interval(ia);
470
471 gettimeofday(&now, NULL);
472 if (ia->state != IF_STA_DOWN &&
473 ia->uptime != 0) {
474 ictl.uptime = now.tv_sec - ia->uptime;
475 } else
476 ictl.uptime = 0;
477
478 ictl.adj_cnt = 0;
479 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
480 ictl.adj_cnt++;
481
482 return (&ictl);
483 }
484
485 /* multicast membership sockopts */
486 in_addr_t
487 if_get_ipv4_addr(struct iface *iface)
488 {
489 struct if_addr *if_addr;
490
491 LIST_FOREACH(if_addr, &iface->addr_list, entry)
492 if (if_addr->af == AF_INET)
493 return (if_addr->addr.v4.s_addr);
494
495 return (INADDR_ANY);
496 }
497
498 static int
499 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
500 {
501 struct in_addr if_addr;
502
503 log_debug("%s: interface %s addr %s", __func__, iface->name,
504 inet_ntoa(*addr));
505
506 if_addr.s_addr = if_get_ipv4_addr(iface);
507
508 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
509 IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
510 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
511 __func__, iface->name, inet_ntoa(*addr));
512 return (-1);
513 }
514 return (0);
515 }
516
517 static int
518 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
519 {
520 struct in_addr if_addr;
521
522 log_debug("%s: interface %s addr %s", __func__, iface->name,
523 inet_ntoa(*addr));
524
525 if_addr.s_addr = if_get_ipv4_addr(iface);
526
527 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
528 IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
529 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
530 "address %s", __func__, iface->name, inet_ntoa(*addr));
531 return (-1);
532 }
533
534 return (0);
535 }
536
537 static int
538 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
539 {
540 struct ipv6_mreq mreq;
541
542 log_debug("%s: interface %s addr %s", __func__, iface->name,
543 log_in6addr(addr));
544
545 mreq.ipv6mr_multiaddr = *addr;
546 mreq.ipv6mr_interface = iface->ifindex;
547
548 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
549 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) {
550 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
551 __func__, iface->name, log_in6addr(addr));
552 return (-1);
553 }
554
555 return (0);
556 }
557
558 static int
559 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
560 {
561 struct ipv6_mreq mreq;
562
563 log_debug("%s: interface %s addr %s", __func__, iface->name,
564 log_in6addr(addr));
565
566 mreq.ipv6mr_multiaddr = *addr;
567 mreq.ipv6mr_interface = iface->ifindex;
568
569 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
570 IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) {
571 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
572 __func__, iface->name, log_in6addr(addr));
573 return (-1);
574 }
575
576 return (0);
577 }