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