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