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