]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/interface.c
ldpd: allow targeted neighbors over any interface
[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 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;
142 iface->flags = kif->flags;
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
212 iface = if_lookup(leconf, ka->ifindex);
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
232 iface = if_lookup(leconf, ka->ifindex);
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);
290
8429abe0
RW
291 if_start_hello_timer(ia);
292 return (0);
293}
294
295static int
296if_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
057d48bd 307 while ((adj = RB_ROOT(&ia->adj_tree)) != NULL)
8429abe0
RW
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
327static void
328if_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
eac6e3f0 360 if (ldp_rtr_id_get(leconf) != INADDR_ANY)
8429abe0
RW
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
381void
61cd1100 382ldp_if_update(struct iface *iface, int af)
8429abe0
RW
383{
384 int link_ok;
385
eac6e3f0 386 link_ok = (iface->flags & IFF_UP) && (iface->flags & IFF_RUNNING);
8429abe0
RW
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
394void
395if_update_all(int af)
396{
397 struct iface *iface;
398
7d3d7491 399 RB_FOREACH(iface, iface_head, &leconf->iface_tree)
61cd1100 400 ldp_if_update(iface, af);
8429abe0
RW
401}
402
eac6e3f0
RW
403uint16_t
404if_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
415uint16_t
416if_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
8429abe0
RW
427/* timers */
428/* ARGSUSED */
eac6e3f0
RW
429static int
430if_hello_timer(struct thread *thread)
8429abe0 431{
eac6e3f0 432 struct iface_af *ia = THREAD_ARG(thread);
8429abe0 433
eac6e3f0 434 ia->hello_timer = NULL;
8429abe0
RW
435 send_hello(HELLO_LINK, ia, NULL);
436 if_start_hello_timer(ia);
eac6e3f0
RW
437
438 return (0);
8429abe0
RW
439}
440
441static void
442if_start_hello_timer(struct iface_af *ia)
443{
eac6e3f0
RW
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));
8429abe0
RW
447}
448
449static void
450if_stop_hello_timer(struct iface_af *ia)
451{
eac6e3f0 452 THREAD_TIMER_OFF(ia->hello_timer);
8429abe0
RW
453}
454
455struct ctl_iface *
456if_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;
8429abe0 467 ictl.type = ia->iface->type;
eac6e3f0
RW
468 ictl.hello_holdtime = if_get_hello_holdtime(ia);
469 ictl.hello_interval = if_get_hello_interval(ia);
8429abe0
RW
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;
057d48bd 479 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
8429abe0
RW
480 ictl.adj_cnt++;
481
482 return (&ictl);
483}
484
485/* multicast membership sockopts */
486in_addr_t
487if_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
498static int
499if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
500{
eac6e3f0 501 struct in_addr if_addr;
8429abe0
RW
502
503 log_debug("%s: interface %s addr %s", __func__, iface->name,
504 inet_ntoa(*addr));
505
eac6e3f0 506 if_addr.s_addr = if_get_ipv4_addr(iface);
8429abe0 507
eac6e3f0
RW
508 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
509 IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
8429abe0
RW
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
517static int
518if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
519{
eac6e3f0 520 struct in_addr if_addr;
8429abe0
RW
521
522 log_debug("%s: interface %s addr %s", __func__, iface->name,
523 inet_ntoa(*addr));
524
eac6e3f0 525 if_addr.s_addr = if_get_ipv4_addr(iface);
8429abe0 526
eac6e3f0
RW
527 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
528 IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
8429abe0
RW
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
537static int
538if_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
558static int
559if_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}