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