interface.c revision 1.43
1/* $OpenBSD: interface.c,v 1.43 2016/05/23 19:11:42 renato Exp $ */ 2 3/* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20#include <sys/types.h> 21#include <sys/time.h> 22#include <arpa/inet.h> 23#include <stdlib.h> 24#include <string.h> 25 26#include "ldpd.h" 27#include "ldpe.h" 28#include "log.h" 29 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); 35static void if_hello_timer(int, short, void *); 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 43struct iface * 44if_new(struct kif *kif) 45{ 46 struct iface *iface; 47 48 if ((iface = calloc(1, sizeof(*iface))) == NULL) 49 fatal("if_new: calloc"); 50 51 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 52 53 /* get type */ 54 if (kif->flags & IFF_POINTOPOINT) 55 iface->type = IF_TYPE_POINTOPOINT; 56 if (kif->flags & IFF_BROADCAST && 57 kif->flags & IFF_MULTICAST) 58 iface->type = IF_TYPE_BROADCAST; 59 60 /* get index and flags */ 61 LIST_INIT(&iface->addr_list); 62 iface->ifindex = kif->ifindex; 63 iface->flags = kif->flags; 64 iface->linkstate = kif->link_state; 65 iface->if_type = kif->if_type; 66 67 /* ipv4 */ 68 iface->ipv4.af = AF_INET; 69 iface->ipv4.iface = iface; 70 iface->ipv4.enabled = 0; 71 iface->ipv4.state = IF_STA_DOWN; 72 LIST_INIT(&iface->ipv4.adj_list); 73 74 /* ipv6 */ 75 iface->ipv6.af = AF_INET6; 76 iface->ipv6.iface = iface; 77 iface->ipv6.enabled = 0; 78 iface->ipv6.state = IF_STA_DOWN; 79 LIST_INIT(&iface->ipv6.adj_list); 80 81 return (iface); 82} 83 84void 85if_del(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 free(iface); 102} 103 104struct iface * 105if_lookup(struct ldpd_conf *xconf, unsigned short ifindex) 106{ 107 struct iface *iface; 108 109 LIST_FOREACH(iface, &xconf->iface_list, entry) 110 if (iface->ifindex == ifindex) 111 return (iface); 112 113 return (NULL); 114} 115 116struct iface_af * 117iface_af_get(struct iface *iface, int af) 118{ 119 switch (af) { 120 case AF_INET: 121 return (&iface->ipv4); 122 case AF_INET6: 123 return (&iface->ipv6); 124 default: 125 fatalx("iface_af_get: unknown af"); 126 } 127} 128 129static struct if_addr * 130if_addr_new(struct kaddr *ka) 131{ 132 struct if_addr *if_addr; 133 134 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL) 135 fatal(__func__); 136 137 if_addr->af = ka->af; 138 if_addr->addr = ka->addr; 139 if_addr->prefixlen = ka->prefixlen; 140 if_addr->dstbrd = ka->dstbrd; 141 142 return (if_addr); 143} 144 145static struct if_addr * 146if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka) 147{ 148 struct if_addr *if_addr; 149 int af = ka->af; 150 151 LIST_FOREACH(if_addr, addr_list, entry) 152 if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) && 153 if_addr->prefixlen == ka->prefixlen && 154 !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd)) 155 return (if_addr); 156 157 return (NULL); 158} 159 160void 161if_addr_add(struct kaddr *ka) 162{ 163 struct iface *iface; 164 struct if_addr *if_addr; 165 struct nbr *nbr; 166 167 if (if_addr_lookup(&global.addr_list, ka) == NULL) { 168 if_addr = if_addr_new(ka); 169 170 LIST_INSERT_HEAD(&global.addr_list, if_addr, entry); 171 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { 172 if (nbr->state != NBR_STA_OPER) 173 continue; 174 if (if_addr->af == AF_INET && !nbr->v4_enabled) 175 continue; 176 if (if_addr->af == AF_INET6 && !nbr->v6_enabled) 177 continue; 178 179 send_address(nbr, if_addr->af, if_addr, 0); 180 } 181 } 182 183 iface = if_lookup(leconf, ka->ifindex); 184 if (iface) { 185 if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6)) 186 iface->linklocal = ka->addr.v6; 187 188 if (if_addr_lookup(&iface->addr_list, ka) == NULL) { 189 if_addr = if_addr_new(ka); 190 LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry); 191 if_update(iface, if_addr->af); 192 } 193 } 194} 195 196void 197if_addr_del(struct kaddr *ka) 198{ 199 struct iface *iface; 200 struct if_addr *if_addr; 201 struct nbr *nbr; 202 203 iface = if_lookup(leconf, ka->ifindex); 204 if (iface) { 205 if (ka->af == AF_INET6 && 206 IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6)) 207 memset(&iface->linklocal, 0, sizeof(iface->linklocal)); 208 209 if_addr = if_addr_lookup(&iface->addr_list, ka); 210 if (if_addr) { 211 LIST_REMOVE(if_addr, entry); 212 if_update(iface, if_addr->af); 213 free(if_addr); 214 } 215 } 216 217 if_addr = if_addr_lookup(&global.addr_list, ka); 218 if (if_addr) { 219 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { 220 if (nbr->state != NBR_STA_OPER) 221 continue; 222 if (if_addr->af == AF_INET && !nbr->v4_enabled) 223 continue; 224 if (if_addr->af == AF_INET6 && !nbr->v6_enabled) 225 continue; 226 send_address(nbr, if_addr->af, if_addr, 1); 227 } 228 LIST_REMOVE(if_addr, entry); 229 free(if_addr); 230 } 231} 232 233static int 234if_start(struct iface *iface, int af) 235{ 236 struct iface_af *ia; 237 struct timeval now; 238 239 log_debug("%s: %s address-family %s", __func__, iface->name, 240 af_name(af)); 241 242 ia = iface_af_get(iface, af); 243 244 gettimeofday(&now, NULL); 245 ia->uptime = now.tv_sec; 246 247 switch (af) { 248 case AF_INET: 249 if (if_join_ipv4_group(iface, &global.mcast_addr_v4)) 250 return (-1); 251 break; 252 case AF_INET6: 253 if (if_join_ipv6_group(iface, &global.mcast_addr_v6)) 254 return (-1); 255 break; 256 default: 257 fatalx("if_start: unknown af"); 258 } 259 260 send_hello(HELLO_LINK, ia, NULL); 261 262 evtimer_set(&ia->hello_timer, if_hello_timer, ia); 263 if_start_hello_timer(ia); 264 return (0); 265} 266 267static int 268if_reset(struct iface *iface, int af) 269{ 270 struct iface_af *ia; 271 struct adj *adj; 272 273 log_debug("%s: %s address-family %s", __func__, iface->name, 274 af_name(af)); 275 276 ia = iface_af_get(iface, af); 277 if_stop_hello_timer(ia); 278 279 while ((adj = LIST_FIRST(&ia->adj_list)) != NULL) 280 adj_del(adj); 281 282 /* try to cleanup */ 283 switch (af) { 284 case AF_INET: 285 if (global.ipv4.ldp_disc_socket != -1) 286 if_leave_ipv4_group(iface, &global.mcast_addr_v4); 287 break; 288 case AF_INET6: 289 if (global.ipv6.ldp_disc_socket != -1) 290 if_leave_ipv6_group(iface, &global.mcast_addr_v6); 291 break; 292 default: 293 fatalx("if_start: unknown af"); 294 } 295 296 return (0); 297} 298 299static void 300if_update_af(struct iface_af *ia, int link_ok) 301{ 302 int addr_ok = 0, socket_ok, rtr_id_ok; 303 struct if_addr *if_addr; 304 305 switch (ia->af) { 306 case AF_INET: 307 /* 308 * NOTE: for LDPv4, each interface should have at least one 309 * valid IP address otherwise they can not be enabled. 310 */ 311 LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) { 312 if (if_addr->af == AF_INET) { 313 addr_ok = 1; 314 break; 315 } 316 } 317 break; 318 case AF_INET6: 319 /* for IPv6 the link-local address is enough. */ 320 if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal)) 321 addr_ok = 1; 322 break; 323 default: 324 fatalx("if_update_af: unknown af"); 325 } 326 327 if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1) 328 socket_ok = 1; 329 else 330 socket_ok = 0; 331 332 if (leconf->rtr_id.s_addr != INADDR_ANY) 333 rtr_id_ok = 1; 334 else 335 rtr_id_ok = 0; 336 337 if (ia->state == IF_STA_DOWN) { 338 if (!ia->enabled || !link_ok || !addr_ok || !socket_ok || 339 !rtr_id_ok) 340 return; 341 342 ia->state = IF_STA_ACTIVE; 343 if_start(ia->iface, ia->af); 344 } else if (ia->state == IF_STA_ACTIVE) { 345 if (ia->enabled && link_ok && addr_ok && socket_ok && rtr_id_ok) 346 return; 347 348 ia->state = IF_STA_DOWN; 349 if_reset(ia->iface, ia->af); 350 } 351} 352 353void 354if_update(struct iface *iface, int af) 355{ 356 int link_ok; 357 358 link_ok = (iface->flags & IFF_UP) && 359 LINK_STATE_IS_UP(iface->linkstate); 360 361 if (af == AF_INET || af == AF_UNSPEC) 362 if_update_af(&iface->ipv4, link_ok); 363 if (af == AF_INET6 || af == AF_UNSPEC) 364 if_update_af(&iface->ipv6, link_ok); 365} 366 367void 368if_update_all(int af) 369{ 370 struct iface *iface; 371 372 LIST_FOREACH(iface, &leconf->iface_list, entry) 373 if_update(iface, af); 374} 375 376/* timers */ 377/* ARGSUSED */ 378static void 379if_hello_timer(int fd, short event, void *arg) 380{ 381 struct iface_af *ia = arg; 382 383 send_hello(HELLO_LINK, ia, NULL); 384 if_start_hello_timer(ia); 385} 386 387static void 388if_start_hello_timer(struct iface_af *ia) 389{ 390 struct timeval tv; 391 392 timerclear(&tv); 393 tv.tv_sec = ia->hello_interval; 394 if (evtimer_add(&ia->hello_timer, &tv) == -1) 395 fatal(__func__); 396} 397 398static void 399if_stop_hello_timer(struct iface_af *ia) 400{ 401 if (evtimer_pending(&ia->hello_timer, NULL) && 402 evtimer_del(&ia->hello_timer) == -1) 403 fatal(__func__); 404} 405 406struct ctl_iface * 407if_to_ctl(struct iface_af *ia) 408{ 409 static struct ctl_iface ictl; 410 struct timeval now; 411 struct adj *adj; 412 413 ictl.af = ia->af; 414 memcpy(ictl.name, ia->iface->name, sizeof(ictl.name)); 415 ictl.ifindex = ia->iface->ifindex; 416 ictl.state = ia->state; 417 ictl.flags = ia->iface->flags; 418 ictl.linkstate = ia->iface->linkstate; 419 ictl.type = ia->iface->type; 420 ictl.if_type = ia->iface->if_type; 421 ictl.hello_holdtime = ia->hello_holdtime; 422 ictl.hello_interval = ia->hello_interval; 423 424 gettimeofday(&now, NULL); 425 if (ia->state != IF_STA_DOWN && 426 ia->uptime != 0) { 427 ictl.uptime = now.tv_sec - ia->uptime; 428 } else 429 ictl.uptime = 0; 430 431 ictl.adj_cnt = 0; 432 LIST_FOREACH(adj, &ia->adj_list, ia_entry) 433 ictl.adj_cnt++; 434 435 return (&ictl); 436} 437 438/* multicast membership sockopts */ 439in_addr_t 440if_get_ipv4_addr(struct iface *iface) 441{ 442 struct if_addr *if_addr; 443 444 LIST_FOREACH(if_addr, &iface->addr_list, entry) 445 if (if_addr->af == AF_INET) 446 return (if_addr->addr.v4.s_addr); 447 448 return (INADDR_ANY); 449} 450 451static int 452if_join_ipv4_group(struct iface *iface, struct in_addr *addr) 453{ 454 struct ip_mreq mreq; 455 456 log_debug("%s: interface %s addr %s", __func__, iface->name, 457 inet_ntoa(*addr)); 458 459 mreq.imr_multiaddr = *addr; 460 mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); 461 462 if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, 463 IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 464 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s", 465 __func__, iface->name, inet_ntoa(*addr)); 466 return (-1); 467 } 468 return (0); 469} 470 471static int 472if_leave_ipv4_group(struct iface *iface, struct in_addr *addr) 473{ 474 struct ip_mreq mreq; 475 476 log_debug("%s: interface %s addr %s", __func__, iface->name, 477 inet_ntoa(*addr)); 478 479 mreq.imr_multiaddr = *addr; 480 mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); 481 482 if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, 483 IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 484 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s " 485 "address %s", __func__, iface->name, inet_ntoa(*addr)); 486 return (-1); 487 } 488 489 return (0); 490} 491 492static int 493if_join_ipv6_group(struct iface *iface, struct in6_addr *addr) 494{ 495 struct ipv6_mreq mreq; 496 497 log_debug("%s: interface %s addr %s", __func__, iface->name, 498 log_in6addr(addr)); 499 500 mreq.ipv6mr_multiaddr = *addr; 501 mreq.ipv6mr_interface = iface->ifindex; 502 503 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6, 504 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { 505 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s", 506 __func__, iface->name, log_in6addr(addr)); 507 return (-1); 508 } 509 510 return (0); 511} 512 513static int 514if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr) 515{ 516 struct ipv6_mreq mreq; 517 518 log_debug("%s: interface %s addr %s", __func__, iface->name, 519 log_in6addr(addr)); 520 521 mreq.ipv6mr_multiaddr = *addr; 522 mreq.ipv6mr_interface = iface->ifindex; 523 524 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6, 525 IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) { 526 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s", 527 __func__, iface->name, log_in6addr(addr)); 528 return (-1); 529 } 530 531 return (0); 532} 533