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