]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/interface.c
Merge pull request #711 ("Coverity munging")
[mirror_frr.git] / ldpd / interface.c
CommitLineData
8429abe0
RW
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
eac6e3f0 21#include <zebra.h>
8429abe0
RW
22
23#include "ldpd.h"
24#include "ldpe.h"
25#include "log.h"
26
eac6e3f0
RW
27#include "sockopt.h"
28
7d3d7491 29static __inline int iface_compare(struct iface *, struct iface *);
8429abe0
RW
30static struct if_addr *if_addr_new(struct kaddr *);
31static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
32static int if_start(struct iface *, int);
33static int if_reset(struct iface *, int);
988ded8d 34static void if_update_af(struct iface_af *);
eac6e3f0 35static int if_hello_timer(struct thread *);
8429abe0
RW
36static void if_start_hello_timer(struct iface_af *);
37static void if_stop_hello_timer(struct iface_af *);
38static int if_join_ipv4_group(struct iface *, struct in_addr *);
39static int if_leave_ipv4_group(struct iface *, struct in_addr *);
40static int if_join_ipv6_group(struct iface *, struct in6_addr *);
41static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
42
7d3d7491
RW
43RB_GENERATE(iface_head, iface, entry, iface_compare)
44
45static __inline int
46iface_compare(struct iface *a, struct iface *b)
47{
48 return (strcmp(a->name, b->name));
49}
50
8429abe0 51struct iface *
52b530fc 52if_new(const char *name)
8429abe0
RW
53{
54 struct iface *iface;
55
56 if ((iface = calloc(1, sizeof(*iface))) == NULL)
57 fatal("if_new: calloc");
58
52b530fc 59 strlcpy(iface->name, name, sizeof(iface->name));
8429abe0
RW
60
61 /* ipv4 */
62 iface->ipv4.af = AF_INET;
63 iface->ipv4.iface = iface;
64 iface->ipv4.enabled = 0;
8429abe0
RW
65
66 /* ipv6 */
67 iface->ipv6.af = AF_INET6;
68 iface->ipv6.iface = iface;
69 iface->ipv6.enabled = 0;
8429abe0
RW
70
71 return (iface);
72}
73
8429abe0 74void
1d75a89d
RW
75ldpe_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
92void
93ldpe_if_exit(struct iface *iface)
8429abe0
RW
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
eac6e3f0 110struct iface *
7d3d7491 111if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
eac6e3f0
RW
112{
113 struct iface *iface;
114
7d3d7491
RW
115 RB_FOREACH(iface, iface_head, &xconf->iface_tree)
116 if (iface->ifindex == ifindex)
eac6e3f0
RW
117 return (iface);
118
119 return (NULL);
120}
121
7d3d7491
RW
122struct iface *
123if_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
eac6e3f0
RW
130void
131if_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;
988ded8d 142 iface->operative = kif->operative;
eac6e3f0
RW
143}
144
8429abe0
RW
145struct iface_af *
146iface_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
158static struct if_addr *
159if_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
174static struct if_addr *
175if_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
189void
190if_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
9cf67225 212 iface = if_lookup_name(leconf, ka->ifname);
8429abe0
RW
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);
61cd1100 220 ldp_if_update(iface, if_addr->af);
8429abe0
RW
221 }
222 }
223}
224
225void
226if_addr_del(struct kaddr *ka)
227{
228 struct iface *iface;
229 struct if_addr *if_addr;
230 struct nbr *nbr;
231
9cf67225 232 iface = if_lookup_name(leconf, ka->ifname);
8429abe0
RW
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);
61cd1100 241 ldp_if_update(iface, if_addr->af);
8429abe0
RW
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
262static int
263if_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);
8429abe0 290 if_start_hello_timer(ia);
8a26d0cf
RW
291 ia->state = IF_STA_ACTIVE;
292
8429abe0
RW
293 return (0);
294}
295
296static int
297if_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
057d48bd 308 while ((adj = RB_ROOT(&ia->adj_tree)) != NULL)
8429abe0
RW
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:
8a26d0cf 322 fatalx("if_reset: unknown af");
8429abe0
RW
323 }
324
8a26d0cf
RW
325 ia->state = IF_STA_DOWN;
326
8429abe0
RW
327 return (0);
328}
329
330static void
988ded8d 331if_update_af(struct iface_af *ia)
8429abe0
RW
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
eac6e3f0 363 if (ldp_rtr_id_get(leconf) != INADDR_ANY)
8429abe0
RW
364 rtr_id_ok = 1;
365 else
366 rtr_id_ok = 0;
367
368 if (ia->state == IF_STA_DOWN) {
988ded8d
RW
369 if (!ia->enabled || !ia->iface->operative || !addr_ok ||
370 !socket_ok || !rtr_id_ok)
8429abe0
RW
371 return;
372
8429abe0
RW
373 if_start(ia->iface, ia->af);
374 } else if (ia->state == IF_STA_ACTIVE) {
988ded8d
RW
375 if (ia->enabled && ia->iface->operative && addr_ok &&
376 socket_ok && rtr_id_ok)
8429abe0
RW
377 return;
378
8429abe0
RW
379 if_reset(ia->iface, ia->af);
380 }
381}
382
383void
61cd1100 384ldp_if_update(struct iface *iface, int af)
8429abe0 385{
8429abe0 386 if (af == AF_INET || af == AF_UNSPEC)
988ded8d 387 if_update_af(&iface->ipv4);
8429abe0 388 if (af == AF_INET6 || af == AF_UNSPEC)
988ded8d 389 if_update_af(&iface->ipv6);
8429abe0
RW
390}
391
392void
393if_update_all(int af)
394{
395 struct iface *iface;
396
7d3d7491 397 RB_FOREACH(iface, iface_head, &leconf->iface_tree)
61cd1100 398 ldp_if_update(iface, af);
8429abe0
RW
399}
400
eac6e3f0
RW
401uint16_t
402if_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
413uint16_t
414if_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
8429abe0
RW
425/* timers */
426/* ARGSUSED */
eac6e3f0
RW
427static int
428if_hello_timer(struct thread *thread)
8429abe0 429{
eac6e3f0 430 struct iface_af *ia = THREAD_ARG(thread);
8429abe0 431
eac6e3f0 432 ia->hello_timer = NULL;
8429abe0
RW
433 send_hello(HELLO_LINK, ia, NULL);
434 if_start_hello_timer(ia);
eac6e3f0
RW
435
436 return (0);
8429abe0
RW
437}
438
439static void
440if_start_hello_timer(struct iface_af *ia)
441{
eac6e3f0 442 THREAD_TIMER_OFF(ia->hello_timer);
66e78ae6
QY
443 ia->hello_timer = NULL;
444 thread_add_timer(master, if_hello_timer, ia, if_get_hello_interval(ia),
445 &ia->hello_timer);
8429abe0
RW
446}
447
448static void
449if_stop_hello_timer(struct iface_af *ia)
450{
eac6e3f0 451 THREAD_TIMER_OFF(ia->hello_timer);
8429abe0
RW
452}
453
454struct ctl_iface *
455if_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;
8429abe0 465 ictl.type = ia->iface->type;
eac6e3f0
RW
466 ictl.hello_holdtime = if_get_hello_holdtime(ia);
467 ictl.hello_interval = if_get_hello_interval(ia);
8429abe0
RW
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;
057d48bd 477 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
8429abe0
RW
478 ictl.adj_cnt++;
479
480 return (&ictl);
481}
482
483/* multicast membership sockopts */
484in_addr_t
485if_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
496static int
497if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
498{
eac6e3f0 499 struct in_addr if_addr;
8429abe0
RW
500
501 log_debug("%s: interface %s addr %s", __func__, iface->name,
502 inet_ntoa(*addr));
503
eac6e3f0 504 if_addr.s_addr = if_get_ipv4_addr(iface);
8429abe0 505
eac6e3f0
RW
506 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
507 IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
8429abe0
RW
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
515static int
516if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
517{
eac6e3f0 518 struct in_addr if_addr;
8429abe0
RW
519
520 log_debug("%s: interface %s addr %s", __func__, iface->name,
521 inet_ntoa(*addr));
522
eac6e3f0 523 if_addr.s_addr = if_get_ipv4_addr(iface);
8429abe0 524
eac6e3f0
RW
525 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
526 IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
8429abe0
RW
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
535static int
536if_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
556static int
557if_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}