interface.c revision 1.42
1/* $OpenBSD: interface.c,v 1.42 2016/05/23 19:09:25 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/ioctl.h> 22#include <sys/time.h> 23#include <sys/socket.h> 24#include <netinet/in.h> 25#include <arpa/inet.h> 26#include <net/if.h> 27#include <net/if_types.h> 28#include <fcntl.h> 29#include <ctype.h> 30#include <err.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <unistd.h> 34#include <string.h> 35#include <event.h> 36 37#include "ldpd.h" 38#include "ldp.h" 39#include "log.h" 40#include "ldpe.h" 41 42static struct if_addr *if_addr_new(struct kaddr *); 43static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *); 44static int if_start(struct iface *, int); 45static int if_reset(struct iface *, int); 46static void if_update_af(struct iface_af *, int); 47static void if_hello_timer(int, short, void *); 48static void if_start_hello_timer(struct iface_af *); 49static void if_stop_hello_timer(struct iface_af *); 50static int if_join_ipv4_group(struct iface *, struct in_addr *); 51static int if_leave_ipv4_group(struct iface *, struct in_addr *); 52static int if_join_ipv6_group(struct iface *, struct in6_addr *); 53static int if_leave_ipv6_group(struct iface *, struct in6_addr *); 54 55struct iface * 56if_new(struct kif *kif) 57{ 58 struct iface *iface; 59 60 if ((iface = calloc(1, sizeof(*iface))) == NULL) 61 fatal("if_new: calloc"); 62 63 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 64 65 /* get type */ 66 if (kif->flags & IFF_POINTOPOINT) 67 iface->type = IF_TYPE_POINTOPOINT; 68 if (kif->flags & IFF_BROADCAST && 69 kif->flags & IFF_MULTICAST) 70 iface->type = IF_TYPE_BROADCAST; 71 72 /* get index and flags */ 73 LIST_INIT(&iface->addr_list); 74 iface->ifindex = kif->ifindex; 75 iface->flags = kif->flags; 76 iface->linkstate = kif->link_state; 77 iface->if_type = kif->if_type; 78 79 /* ipv4 */ 80 iface->ipv4.af = AF_INET; 81 iface->ipv4.iface = iface; 82 iface->ipv4.enabled = 0; 83 iface->ipv4.state = IF_STA_DOWN; 84 LIST_INIT(&iface->ipv4.adj_list); 85 86 /* ipv6 */ 87 iface->ipv6.af = AF_INET6; 88 iface->ipv6.iface = iface; 89 iface->ipv6.enabled = 0; 90 iface->ipv6.state = IF_STA_DOWN; 91 LIST_INIT(&iface->ipv6.adj_list); 92 93 return (iface); 94} 95 96void 97if_del(struct iface *iface) 98{ 99 struct if_addr *if_addr; 100 101 log_debug("%s: interface %s", __func__, iface->name); 102 103 if (iface->ipv4.state == IF_STA_ACTIVE) 104 if_reset(iface, AF_INET); 105 if (iface->ipv6.state == IF_STA_ACTIVE) 106 if_reset(iface, AF_INET6); 107 108 while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) { 109 LIST_REMOVE(if_addr, entry); 110 free(if_addr); 111 } 112 113 free(iface); 114} 115 116struct iface * 117if_lookup(struct ldpd_conf *xconf, unsigned short ifindex) 118{ 119 struct iface *iface; 120 121 LIST_FOREACH(iface, &xconf->iface_list, entry) 122 if (iface->ifindex == ifindex) 123 return (iface); 124 125 return (NULL); 126} 127 128struct iface_af * 129iface_af_get(struct iface *iface, int af) 130{ 131 switch (af) { 132 case AF_INET: 133 return (&iface->ipv4); 134 case AF_INET6: 135 return (&iface->ipv6); 136 default: 137 fatalx("iface_af_get: unknown af"); 138 } 139} 140 141static struct if_addr * 142if_addr_new(struct kaddr *ka) 143{ 144 struct if_addr *if_addr; 145 146 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL) 147 fatal(__func__); 148 149 if_addr->af = ka->af; 150 if_addr->addr = ka->addr; 151 if_addr->prefixlen = ka->prefixlen; 152 if_addr->dstbrd = ka->dstbrd; 153 154 return (if_addr); 155} 156 157static struct if_addr * 158if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka) 159{ 160 struct if_addr *if_addr; 161 int af = ka->af; 162 163 LIST_FOREACH(if_addr, addr_list, entry) 164 if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) && 165 if_addr->prefixlen == ka->prefixlen && 166 !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd)) 167 return (if_addr); 168 169 return (NULL); 170} 171 172void 173if_addr_add(struct kaddr *ka) 174{ 175 struct iface *iface; 176 struct if_addr *if_addr; 177 struct nbr *nbr; 178 179 if (if_addr_lookup(&global.addr_list, ka) == NULL) { 180 if_addr = if_addr_new(ka); 181 182 LIST_INSERT_HEAD(&global.addr_list, if_addr, entry); 183 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { 184 if (nbr->state != NBR_STA_OPER) 185 continue; 186 if (if_addr->af == AF_INET && !nbr->v4_enabled) 187 continue; 188 if (if_addr->af == AF_INET6 && !nbr->v6_enabled) 189 continue; 190 191 send_address(nbr, if_addr->af, if_addr, 0); 192 } 193 } 194 195 iface = if_lookup(leconf, ka->ifindex); 196 if (iface) { 197 if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6)) 198 iface->linklocal = ka->addr.v6; 199 200 if (if_addr_lookup(&iface->addr_list, ka) == NULL) { 201 if_addr = if_addr_new(ka); 202 LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry); 203 if_update(iface, if_addr->af); 204 } 205 } 206} 207 208void 209if_addr_del(struct kaddr *ka) 210{ 211 struct iface *iface; 212 struct if_addr *if_addr; 213 struct nbr *nbr; 214 215 iface = if_lookup(leconf, ka->ifindex); 216 if (iface) { 217 if (ka->af == AF_INET6 && 218 IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6)) 219 memset(&iface->linklocal, 0, sizeof(iface->linklocal)); 220 221 if_addr = if_addr_lookup(&iface->addr_list, ka); 222 if (if_addr) { 223 LIST_REMOVE(if_addr, entry); 224 if_update(iface, if_addr->af); 225 free(if_addr); 226 } 227 } 228 229 if_addr = if_addr_lookup(&global.addr_list, ka); 230 if (if_addr) { 231 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { 232 if (nbr->state != NBR_STA_OPER) 233 continue; 234 if (if_addr->af == AF_INET && !nbr->v4_enabled) 235 continue; 236 if (if_addr->af == AF_INET6 && !nbr->v6_enabled) 237 continue; 238 send_address(nbr, if_addr->af, if_addr, 1); 239 } 240 LIST_REMOVE(if_addr, entry); 241 free(if_addr); 242 } 243} 244 245static int 246if_start(struct iface *iface, int af) 247{ 248 struct iface_af *ia; 249 struct timeval now; 250 251 log_debug("%s: %s address-family %s", __func__, iface->name, 252 af_name(af)); 253 254 ia = iface_af_get(iface, af); 255 256 gettimeofday(&now, NULL); 257 ia->uptime = now.tv_sec; 258 259 switch (af) { 260 case AF_INET: 261 if (if_join_ipv4_group(iface, &global.mcast_addr_v4)) 262 return (-1); 263 break; 264 case AF_INET6: 265 if (if_join_ipv6_group(iface, &global.mcast_addr_v6)) 266 return (-1); 267 break; 268 default: 269 fatalx("if_start: unknown af"); 270 } 271 272 send_hello(HELLO_LINK, ia, NULL); 273 274 evtimer_set(&ia->hello_timer, if_hello_timer, ia); 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); 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 344 if (leconf->rtr_id.s_addr != INADDR_ANY) 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 370 link_ok = (iface->flags & IFF_UP) && 371 LINK_STATE_IS_UP(iface->linkstate); 372 373 if (af == AF_INET || af == AF_UNSPEC) 374 if_update_af(&iface->ipv4, link_ok); 375 if (af == AF_INET6 || af == AF_UNSPEC) 376 if_update_af(&iface->ipv6, link_ok); 377} 378 379void 380if_update_all(int af) 381{ 382 struct iface *iface; 383 384 LIST_FOREACH(iface, &leconf->iface_list, entry) 385 if_update(iface, af); 386} 387 388/* timers */ 389/* ARGSUSED */ 390static void 391if_hello_timer(int fd, short event, void *arg) 392{ 393 struct iface_af *ia = arg; 394 395 send_hello(HELLO_LINK, ia, NULL); 396 if_start_hello_timer(ia); 397} 398 399static void 400if_start_hello_timer(struct iface_af *ia) 401{ 402 struct timeval tv; 403 404 timerclear(&tv); 405 tv.tv_sec = ia->hello_interval; 406 if (evtimer_add(&ia->hello_timer, &tv) == -1) 407 fatal(__func__); 408} 409 410static void 411if_stop_hello_timer(struct iface_af *ia) 412{ 413 if (evtimer_pending(&ia->hello_timer, NULL) && 414 evtimer_del(&ia->hello_timer) == -1) 415 fatal(__func__); 416} 417 418struct ctl_iface * 419if_to_ctl(struct iface_af *ia) 420{ 421 static struct ctl_iface ictl; 422 struct timeval now; 423 struct adj *adj; 424 425 ictl.af = ia->af; 426 memcpy(ictl.name, ia->iface->name, sizeof(ictl.name)); 427 ictl.ifindex = ia->iface->ifindex; 428 ictl.state = ia->state; 429 ictl.flags = ia->iface->flags; 430 ictl.linkstate = ia->iface->linkstate; 431 ictl.type = ia->iface->type; 432 ictl.if_type = ia->iface->if_type; 433 ictl.hello_holdtime = ia->hello_holdtime; 434 ictl.hello_interval = ia->hello_interval; 435 436 gettimeofday(&now, NULL); 437 if (ia->state != IF_STA_DOWN && 438 ia->uptime != 0) { 439 ictl.uptime = now.tv_sec - ia->uptime; 440 } else 441 ictl.uptime = 0; 442 443 ictl.adj_cnt = 0; 444 LIST_FOREACH(adj, &ia->adj_list, ia_entry) 445 ictl.adj_cnt++; 446 447 return (&ictl); 448} 449 450/* multicast membership sockopts */ 451in_addr_t 452if_get_ipv4_addr(struct iface *iface) 453{ 454 struct if_addr *if_addr; 455 456 LIST_FOREACH(if_addr, &iface->addr_list, entry) 457 if (if_addr->af == AF_INET) 458 return (if_addr->addr.v4.s_addr); 459 460 return (INADDR_ANY); 461} 462 463static int 464if_join_ipv4_group(struct iface *iface, struct in_addr *addr) 465{ 466 struct ip_mreq mreq; 467 468 log_debug("%s: interface %s addr %s", __func__, iface->name, 469 inet_ntoa(*addr)); 470 471 mreq.imr_multiaddr = *addr; 472 mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); 473 474 if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, 475 IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 476 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s", 477 __func__, iface->name, inet_ntoa(*addr)); 478 return (-1); 479 } 480 return (0); 481} 482 483static int 484if_leave_ipv4_group(struct iface *iface, struct in_addr *addr) 485{ 486 struct ip_mreq mreq; 487 488 log_debug("%s: interface %s addr %s", __func__, iface->name, 489 inet_ntoa(*addr)); 490 491 mreq.imr_multiaddr = *addr; 492 mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); 493 494 if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, 495 IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 496 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s " 497 "address %s", __func__, iface->name, inet_ntoa(*addr)); 498 return (-1); 499 } 500 501 return (0); 502} 503 504static int 505if_join_ipv6_group(struct iface *iface, struct in6_addr *addr) 506{ 507 struct ipv6_mreq mreq; 508 509 log_debug("%s: interface %s addr %s", __func__, iface->name, 510 log_in6addr(addr)); 511 512 mreq.ipv6mr_multiaddr = *addr; 513 mreq.ipv6mr_interface = iface->ifindex; 514 515 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6, 516 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { 517 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s", 518 __func__, iface->name, log_in6addr(addr)); 519 return (-1); 520 } 521 522 return (0); 523} 524 525static int 526if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr) 527{ 528 struct ipv6_mreq mreq; 529 530 log_debug("%s: interface %s addr %s", __func__, iface->name, 531 log_in6addr(addr)); 532 533 mreq.ipv6mr_multiaddr = *addr; 534 mreq.ipv6mr_interface = iface->ifindex; 535 536 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6, 537 IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) { 538 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s", 539 __func__, iface->name, log_in6addr(addr)); 540 return (-1); 541 } 542 543 return (0); 544} 545