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