diff options
author | 2013-06-03 16:53:49 +0000 | |
---|---|---|
committer | 2013-06-03 16:53:49 +0000 | |
commit | 814e607d3f3f24d8b8efe894e32005cc63075d2c (patch) | |
tree | e03b54bf725c419c33211bca1c425f6a34734847 | |
parent | regen. reminded by miod (diff) | |
download | wireguard-openbsd-814e607d3f3f24d8b8efe894e32005cc63075d2c.tar.xz wireguard-openbsd-814e607d3f3f24d8b8efe894e32005cc63075d2c.zip |
Implement support for multiple addresses per interface.
This replaces the way addresses and interface are chained together.
In ospfd there was a 1 to 1 mapping (with iface clones) but LDP does
not have that limitation.
Diff from Renato Westphal
-rw-r--r-- | usr.sbin/ldpd/address.c | 34 | ||||
-rw-r--r-- | usr.sbin/ldpd/interface.c | 125 | ||||
-rw-r--r-- | usr.sbin/ldpd/kroute.c | 109 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.c | 5 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.h | 34 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.c | 127 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.h | 12 | ||||
-rw-r--r-- | usr.sbin/ldpd/packet.c | 48 | ||||
-rw-r--r-- | usr.sbin/ldpd/parse.y | 41 |
9 files changed, 341 insertions, 194 deletions
diff --git a/usr.sbin/ldpd/address.c b/usr.sbin/ldpd/address.c index 901b76c5c9f..e2e3ae5b4b9 100644 --- a/usr.sbin/ldpd/address.c +++ b/usr.sbin/ldpd/address.c @@ -1,4 +1,4 @@ -/* $OpenBSD: address.c,v 1.10 2013/06/01 19:42:07 claudio Exp $ */ +/* $OpenBSD: address.c,v 1.11 2013/06/03 16:53:49 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -39,13 +39,12 @@ extern struct ldpd_conf *leconf; -void gen_address_list_tlv(struct ibuf *, struct iface *, u_int16_t); +void gen_address_list_tlv(struct ibuf *, struct if_addr *, u_int16_t); void -send_address(struct nbr *nbr, struct iface *iface) +send_address(struct nbr *nbr, struct if_addr *if_addr) { struct ibuf *buf; - struct iface *niface; u_int16_t size, iface_count = 0; log_debug("send_address: neighbor ID %s", inet_ntoa(nbr->id)); @@ -53,9 +52,8 @@ send_address(struct nbr *nbr, struct iface *iface) if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL) fatal("send_address"); - /* XXX: multiple address on the same iface? */ - if (iface == NULL) - LIST_FOREACH(niface, &leconf->iface_list, entry) + if (if_addr == NULL) + LIST_FOREACH(if_addr, &leconf->addr_list, global_entry) iface_count++; else iface_count = 1; @@ -72,7 +70,7 @@ send_address(struct nbr *nbr, struct iface *iface) size -= sizeof(struct ldp_msg); - gen_address_list_tlv(buf, iface, size); + gen_address_list_tlv(buf, if_addr, size); evbuf_enqueue(&nbr->wbuf, buf); nbr_fsm(nbr, NBR_EVT_PDU_SENT); @@ -141,10 +139,10 @@ recv_address(struct nbr *nbr, char *buf, u_int16_t len) } void -gen_address_list_tlv(struct ibuf *buf, struct iface *iface, u_int16_t size) +gen_address_list_tlv(struct ibuf *buf, struct if_addr *if_addr, + u_int16_t size) { struct address_list_tlv alt; - struct iface *niface; /* We want just the size of the value */ size -= TLV_HDR_LEN; @@ -157,15 +155,15 @@ gen_address_list_tlv(struct ibuf *buf, struct iface *iface, u_int16_t size) ibuf_add(buf, &alt, sizeof(alt)); - if (iface == NULL) - LIST_FOREACH(niface, &leconf->iface_list, entry) - ibuf_add(buf, &niface->addr, sizeof(niface->addr)); + if (if_addr == NULL) + LIST_FOREACH(if_addr, &leconf->addr_list, global_entry) + ibuf_add(buf, &if_addr->addr, sizeof(if_addr->addr)); else - ibuf_add(buf, &iface->addr, sizeof(iface->addr)); + ibuf_add(buf, &if_addr->addr, sizeof(if_addr->addr)); } void -send_address_withdraw(struct nbr *nbr, struct iface *iface) +send_address_withdraw(struct nbr *nbr, struct if_addr *if_addr) { struct ibuf *buf; u_int16_t size; @@ -175,8 +173,8 @@ send_address_withdraw(struct nbr *nbr, struct iface *iface) if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL) fatal("send_address_withdraw"); - /* XXX: multiple address on the same iface? */ - size = LDP_HDR_SIZE + sizeof(struct ldp_msg) + sizeof(struct in_addr); + size = LDP_HDR_SIZE + sizeof(struct ldp_msg) + + sizeof(struct address_list_tlv) + sizeof(struct in_addr); gen_ldp_hdr(buf, size); @@ -186,7 +184,7 @@ send_address_withdraw(struct nbr *nbr, struct iface *iface) size -= sizeof(struct ldp_msg); - gen_address_list_tlv(buf, iface, size); + gen_address_list_tlv(buf, if_addr, size); evbuf_enqueue(&nbr->wbuf, buf); nbr_fsm(nbr, NBR_EVT_PDU_SENT); diff --git a/usr.sbin/ldpd/interface.c b/usr.sbin/ldpd/interface.c index fa875dd2082..1d84631158a 100644 --- a/usr.sbin/ldpd/interface.c +++ b/usr.sbin/ldpd/interface.c @@ -1,4 +1,4 @@ -/* $OpenBSD: interface.c,v 1.13 2013/06/01 18:35:02 claudio Exp $ */ +/* $OpenBSD: interface.c,v 1.14 2013/06/03 16:53:49 claudio Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -39,6 +39,11 @@ #include "log.h" #include "ldpe.h" +extern struct ldpd_conf *leconf; + +int if_act_start(struct iface *); +int if_act_reset(struct iface *); +int if_act_update(struct iface *); void if_hello_timer(int, short, void *); void if_start_hello_timer(struct iface *); void if_stop_hello_timer(struct iface *); @@ -51,20 +56,27 @@ struct { int new_state; } iface_fsm[] = { /* current state event that happened action to take resulting state */ - {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0}, - {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, + {IF_STA_DOWN, IF_EVT_DOWN, IF_ACT_NOTHING, 0}, + {IF_STA_DOWN, IF_EVT_UP, IF_ACT_UPDATE, 0}, + {IF_STA_DOWN, IF_EVT_NEWADDR, IF_ACT_UPDATE, 0}, + {IF_STA_DOWN, IF_EVT_DELADDR, IF_ACT_NOTHING, 0}, + {IF_STA_ACTIVE, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, + {IF_STA_ACTIVE, IF_EVT_NEWADDR, IF_ACT_NOTHING, 0}, + {IF_STA_ACTIVE, IF_EVT_DELADDR, IF_ACT_UPDATE, 0}, {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, }; const char * const if_event_names[] = { "NOTHING", "UP", - "DOWN" + "DOWN", + "NEWADDR", + "DELADDR" }; const char * const if_action_names[] = { "NOTHING", - "START", + "UPDATE", "RESET" }; @@ -93,8 +105,8 @@ if_fsm(struct iface *iface, enum iface_event event) } switch (iface_fsm[i].action) { - case IF_ACT_STRT: - ret = if_act_start(iface); + case IF_ACT_UPDATE: + ret = if_act_update(iface); break; case IF_ACT_RST: ret = if_act_reset(iface); @@ -123,7 +135,7 @@ if_fsm(struct iface *iface, enum iface_event event) } struct iface * -if_new(struct kif *kif, struct kif_addr *ka) +if_new(struct kif *kif) { struct iface *iface; @@ -151,23 +163,20 @@ if_new(struct kif *kif, struct kif_addr *ka) iface->media_type = kif->media_type; iface->baudrate = kif->baudrate; - /* set address, mask and p2p addr */ - iface->addr = ka->addr; - iface->mask = ka->mask; - if (kif->flags & IFF_POINTOPOINT) { - iface->dst = ka->dstbrd; - } - return (iface); } void if_del(struct iface *iface) { + struct if_addr *if_addr; + log_debug("if_del: interface %s", iface->name); - if (evtimer_pending(&iface->hello_timer, NULL)) - evtimer_del(&iface->hello_timer); + if_stop_hello_timer(iface); + + while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) + LIST_REMOVE(if_addr, iface_entry); free(iface); } @@ -181,6 +190,18 @@ if_init(struct ldpd_conf *xconf, struct iface *iface) iface->discovery_fd = xconf->ldp_discovery_socket; } +struct iface * +if_lookup(u_short ifindex) +{ + struct iface *iface; + + LIST_FOREACH(iface, &leconf->iface_list, entry) + if (iface->ifindex == ifindex) + return (iface); + + return (NULL); +} + /* timers */ /* ARGSUSED */ void @@ -212,7 +233,8 @@ if_start_hello_timer(struct iface *iface) void if_stop_hello_timer(struct iface *iface) { - if (evtimer_del(&iface->hello_timer) == -1) + if (evtimer_pending(&iface->hello_timer, NULL) && + evtimer_del(&iface->hello_timer) == -1) fatal("if_stop_hello_timer"); } @@ -250,14 +272,39 @@ if_act_reset(struct iface *iface) if_stop_hello_timer(iface); + /* try to cleanup */ inet_aton(AllRouters, &addr); - if (if_leave_group(iface, &addr)) { - log_warnx("if_act_reset: error leaving group %s, " - "interface %s", inet_ntoa(addr), iface->name); - } + if_leave_group(iface, &addr); + return (0); } +int +if_act_update(struct iface *iface) +{ + int ret; + + if (iface->state == IF_STA_DOWN) { + if (!((iface->flags & IFF_UP) && + LINK_STATE_IS_UP(iface->linkstate))) + return (0); + + if (LIST_EMPTY(&iface->addr_list)) + return (0); + + iface->state = IF_STA_ACTIVE; + ret = if_act_start(iface); + } else { + if (!LIST_EMPTY(&iface->addr_list)) + return (0); + + iface->state = IF_STA_DOWN; + ret = if_act_reset(iface); + } + + return (ret); +} + struct ctl_iface * if_to_ctl(struct iface *iface) { @@ -265,8 +312,6 @@ if_to_ctl(struct iface *iface) struct timeval tv, now, res; memcpy(ictl.name, iface->name, sizeof(ictl.name)); - memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); - memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); ictl.rtr_id.s_addr = ldpe_router_id(); ictl.ifindex = iface->ifindex; ictl.state = iface->state; @@ -373,6 +418,7 @@ if_join_group(struct iface *iface, struct in_addr *addr) { struct ip_mreq mreq; struct if_group_count *ifg; + struct if_addr *if_addr; LIST_FOREACH(ifg, &ifglist, entry) if (iface->ifindex == ifg->ifindex && @@ -390,14 +436,17 @@ if_join_group(struct iface *iface, struct in_addr *addr) /* already joined */ return (0); + if_addr = LIST_FIRST(&iface->addr_list); mreq.imr_multiaddr.s_addr = addr->s_addr; - mreq.imr_interface.s_addr = iface->addr.s_addr; + mreq.imr_interface.s_addr = if_addr->addr.s_addr; if (setsockopt(iface->discovery_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { log_warn("if_join_group: error IP_ADD_MEMBERSHIP, " "interface %s address %s", iface->name, inet_ntoa(*addr)); + LIST_REMOVE(ifg, entry); + free(ifg); return (-1); } return (0); @@ -408,6 +457,7 @@ if_leave_group(struct iface *iface, struct in_addr *addr) { struct ip_mreq mreq; struct if_group_count *ifg; + struct if_addr *if_addr; LIST_FOREACH(ifg, &ifglist, entry) if (iface->ifindex == ifg->ifindex && @@ -415,12 +465,21 @@ if_leave_group(struct iface *iface, struct in_addr *addr) break; /* if interface is not found just try to drop membership */ - if (ifg && --ifg->count != 0) - /* others still joined */ + if (ifg) { + if (--ifg->count != 0) + /* others still joined */ + return (0); + + LIST_REMOVE(ifg, entry); + free(ifg); + } + + if_addr = LIST_FIRST(&iface->addr_list); + if (!if_addr) return (0); mreq.imr_multiaddr.s_addr = addr->s_addr; - mreq.imr_interface.s_addr = iface->addr.s_addr; + mreq.imr_interface.s_addr = if_addr->addr.s_addr; if (setsockopt(iface->discovery_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { @@ -430,18 +489,18 @@ if_leave_group(struct iface *iface, struct in_addr *addr) return (-1); } - if (ifg) { - LIST_REMOVE(ifg, entry); - free(ifg); - } return (0); } int if_set_mcast(struct iface *iface) { + struct if_addr *if_addr; + + if_addr = LIST_FIRST(&iface->addr_list); + if (setsockopt(iface->discovery_fd, IPPROTO_IP, IP_MULTICAST_IF, - &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) { + &if_addr->addr.s_addr, sizeof(if_addr->addr.s_addr)) < 0) { log_debug("if_set_mcast: error setting " "IP_MULTICAST_IF, interface %s", iface->name); return (-1); diff --git a/usr.sbin/ldpd/kroute.c b/usr.sbin/ldpd/kroute.c index 031ce4111ed..9aecd61e587 100644 --- a/usr.sbin/ldpd/kroute.c +++ b/usr.sbin/ldpd/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.26 2013/06/01 20:13:04 claudio Exp $ */ +/* $OpenBSD: kroute.c,v 1.27 2013/06/03 16:53:49 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -56,6 +56,11 @@ struct kroute_node { struct kroute_node *next; }; +struct kif_addr { + TAILQ_ENTRY(kif_addr) entry; + struct kaddr addr; +}; + struct kif_node { RB_ENTRY(kif_node) entry; TAILQ_HEAD(, kif_addr) addrs; @@ -79,8 +84,8 @@ struct kif_node *kif_find(u_short); struct kif_node *kif_insert(u_short); int kif_remove(struct kif_node *); void kif_clear(void); -struct kif *kif_update(u_short, int, struct if_data *, - struct sockaddr_dl *); +struct kif_node *kif_update(u_short, int, struct if_data *, + struct sockaddr_dl *, int *); struct kroute_node *kroute_match(in_addr_t); @@ -124,6 +129,22 @@ kif_init(void) return (0); } +void +kif_redistribute(void) +{ + struct kif_node *kif; + struct kif_addr *ka; + + RB_FOREACH(kif, kif_tree, &kit) { + main_imsg_compose_ldpe(IMSG_IFUP, 0, &kif->k, + sizeof(struct kif)); + + TAILQ_FOREACH(ka, &kif->addrs, entry) + main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka->addr, + sizeof(struct kaddr)); + } +} + int kr_init(int fs) { @@ -636,24 +657,13 @@ kif_find(u_short ifindex) } struct kif * -kif_findname(char *ifname, struct in_addr addr, struct kif_addr **kap) +kif_findname(char *ifname) { struct kif_node *kif; - struct kif_addr *ka; RB_FOREACH(kif, kif_tree, &kit) - if (!strcmp(ifname, kif->k.ifname)) { - ka = TAILQ_FIRST(&kif->addrs); - if (addr.s_addr != 0) { - TAILQ_FOREACH(ka, &kif->addrs, entry) { - if (addr.s_addr == ka->addr.s_addr) - break; - } - } - if (kap != NULL) - *kap = ka; + if (!strcmp(ifname, kif->k.ifname)) return (&kif->k); - } return (NULL); } @@ -702,16 +712,18 @@ kif_clear(void) kif_remove(kif); } -struct kif * +struct kif_node * kif_update(u_short ifindex, int flags, struct if_data *ifd, - struct sockaddr_dl *sdl) + struct sockaddr_dl *sdl, int *link_old) { struct kif_node *kif; if ((kif = kif_find(ifindex)) == NULL) { if ((kif = kif_insert(ifindex)) == NULL) return (NULL); - } + } else + *link_old = (kif->k.flags & IFF_UP) && + LINK_STATE_IS_UP(kif->k.link_state); kif->k.flags = flags; kif->k.link_state = ifd->ifi_link_state; @@ -729,7 +741,7 @@ kif_update(u_short ifindex, int flags, struct if_data *ifd, /* string already terminated via calloc() */ } - return (&kif->k); + return (kif); } struct kroute_node * @@ -829,15 +841,35 @@ void if_change(u_short ifindex, int flags, struct if_data *ifd, struct sockaddr_dl *sdl) { - struct kif *kif; + struct kif_node *kif; + struct kif_addr *ka; + int link_old = 0, link_new; - if ((kif = kif_update(ifindex, flags, ifd, sdl)) == NULL) { + kif = kif_update(ifindex, flags, ifd, sdl, &link_old); + if (!kif) { log_warn("if_change: kif_update(%u)", ifindex); return; } + link_new = (kif->k.flags & IFF_UP) && + LINK_STATE_IS_UP(kif->k.link_state); - /* notify ldpe about interface link state */ - main_imsg_compose_ldpe(IMSG_IFINFO, 0, kif, sizeof(struct kif)); + if (link_new == link_old) { + main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif->k, + sizeof(struct kif)); + return; + } else if (link_new) { + main_imsg_compose_ldpe(IMSG_IFUP, 0, &kif->k, + sizeof(struct kif)); + TAILQ_FOREACH(ka, &kif->addrs, entry) + main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka->addr, + sizeof(struct kaddr)); + } else { + main_imsg_compose_ldpe(IMSG_IFDOWN, 0, &kif->k, + sizeof(struct kif)); + TAILQ_FOREACH(ka, &kif->addrs, entry) + main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka->addr, + sizeof(struct kaddr)); + } } void @@ -846,6 +878,7 @@ if_newaddr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask, { struct kif_node *kif; struct kif_addr *ka; + u_int32_t a; if (ifa == NULL || ifa->sin_family != AF_INET) return; @@ -853,19 +886,29 @@ if_newaddr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask, log_warnx("if_newaddr: corresponding if %i not found", ifindex); return; } + a = ntohl(ifa->sin_addr.s_addr); + if (IN_MULTICAST(a) || IN_BADCLASS(a) || + (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) + return; + if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL) fatal("if_newaddr"); - ka->addr = ifa->sin_addr; + ka->addr.ifindex = ifindex; + ka->addr.addr = ifa->sin_addr; if (mask) - ka->mask = mask->sin_addr; + ka->addr.mask = mask->sin_addr; else - ka->mask.s_addr = INADDR_NONE; + ka->addr.mask.s_addr = INADDR_NONE; if (brd) - ka->dstbrd = brd->sin_addr; + ka->addr.dstbrd = brd->sin_addr; else - ka->dstbrd.s_addr = INADDR_NONE; + ka->addr.dstbrd.s_addr = INADDR_NONE; TAILQ_INSERT_TAIL(&kif->addrs, ka, entry); + + /* notify ldpe about new address */ + main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka->addr, + sizeof(struct kaddr)); } void @@ -885,9 +928,13 @@ if_deladdr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask, for (ka = TAILQ_FIRST(&kif->addrs); ka != NULL; ka = nka) { nka = TAILQ_NEXT(ka, entry); - if (ka->addr.s_addr == ifa->sin_addr.s_addr) { + if (ka->addr.addr.s_addr == ifa->sin_addr.s_addr) { TAILQ_REMOVE(&kif->addrs, ka, entry); - /* XXX inform engine about if change? */ + + /* notify ldpe about removed address */ + main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka->addr, + sizeof(struct kaddr)); + free(ka); return; } diff --git a/usr.sbin/ldpd/ldpd.c b/usr.sbin/ldpd/ldpd.c index 5d5113c39d1..c2f3b5d3517 100644 --- a/usr.sbin/ldpd/ldpd.c +++ b/usr.sbin/ldpd/ldpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpd.c,v 1.15 2013/06/01 20:13:04 claudio Exp $ */ +/* $OpenBSD: ldpd.c,v 1.16 2013/06/03 16:53:49 claudio Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -255,6 +255,9 @@ main(int argc, char *argv[]) iev_lde->handler, iev_lde); event_add(&iev_lde->ev, NULL); + /* notify ldpe about existing interfaces and addresses */ + kif_redistribute(); + if (kr_init(!(ldpd_conf->flags & LDPD_FLAG_NO_FIB_UPDATE)) == -1) fatalx("kr_init failed"); diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h index c111b209eea..d94da0a5626 100644 --- a/usr.sbin/ldpd/ldpd.h +++ b/usr.sbin/ldpd/ldpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpd.h,v 1.36 2013/06/01 19:42:07 claudio Exp $ */ +/* $OpenBSD: ldpd.h,v 1.37 2013/06/03 16:53:49 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -82,7 +82,11 @@ enum imsg_type { IMSG_CTL_LOG_VERBOSE, IMSG_KLABEL_CHANGE, IMSG_KLABEL_DELETE, - IMSG_IFINFO, + IMSG_IFSTATUS, + IMSG_IFUP, + IMSG_IFDOWN, + IMSG_NEWADDR, + IMSG_DELADDR, IMSG_LABEL_MAPPING, IMSG_LABEL_MAPPING_FULL, IMSG_LABEL_REQUEST, @@ -118,13 +122,15 @@ enum imsg_type { enum iface_event { IF_EVT_NOTHING, IF_EVT_UP, - IF_EVT_DOWN + IF_EVT_DOWN, + IF_EVT_NEWADDR, + IF_EVT_DELADDR }; /* interface actions */ enum iface_action { IF_ACT_NOTHING, - IF_ACT_STRT, + IF_ACT_UPDATE, IF_ACT_RST }; @@ -193,6 +199,14 @@ struct notify_msg { u_int32_t type; }; +struct if_addr { + LIST_ENTRY(if_addr) global_entry; + LIST_ENTRY(if_addr) iface_entry; + struct in_addr addr; + struct in_addr mask; + struct in_addr dstbrd; +}; + struct iface { LIST_ENTRY(iface) entry; struct event hello_timer; @@ -200,9 +214,7 @@ struct iface { LIST_HEAD(, lde_nbr) lde_nbr_list; char name[IF_NAMESIZE]; - struct in_addr addr; - struct in_addr dst; - struct in_addr mask; + LIST_HEAD(, if_addr) addr_list; u_int64_t baudrate; time_t uptime; @@ -243,6 +255,7 @@ struct ldpd_conf { struct event disc_ev; struct in_addr rtr_id; LIST_HEAD(, iface) iface_list; + LIST_HEAD(, if_addr) addr_list; u_int32_t opts; #define LDPD_OPT_VERBOSE 0x00000001 @@ -268,8 +281,8 @@ struct kroute { u_int8_t priority; }; -struct kif_addr { - TAILQ_ENTRY(kif_addr) entry; +struct kaddr { + u_short ifindex; struct in_addr addr; struct in_addr mask; struct in_addr dstbrd; @@ -350,6 +363,7 @@ void session_socket_blockmode(int, enum blockmodes); /* kroute.c */ int kif_init(void); +void kif_redistribute(void); int kr_init(int); int kr_change(struct kroute *); int kr_delete(struct kroute *); @@ -359,7 +373,7 @@ void kr_fib_decouple(void); void kr_dispatch_msg(int, short, void *); void kr_show_route(struct imsg *); void kr_ifinfo(char *, pid_t); -struct kif *kif_findname(char *, struct in_addr, struct kif_addr **); +struct kif *kif_findname(char *); void kr_reload(void); u_int8_t mask2prefixlen(in_addr_t); diff --git a/usr.sbin/ldpd/ldpe.c b/usr.sbin/ldpd/ldpe.c index 8a2d1716b86..7bf70b78250 100644 --- a/usr.sbin/ldpd/ldpe.c +++ b/usr.sbin/ldpd/ldpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.c,v 1.17 2013/06/01 19:01:32 claudio Exp $ */ +/* $OpenBSD: ldpe.c,v 1.18 2013/06/03 16:53:49 claudio Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -43,11 +43,12 @@ #include "control.h" #include "log.h" +extern struct nbr_id_head nbrs_by_id; +RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare) + void ldpe_sig_handler(int, short, void *); void ldpe_shutdown(void); -void recv_packet(int, short, void *); - struct ldpd_conf *leconf = NULL, *nconf; struct imsgev *iev_main; struct imsgev *iev_lde; @@ -207,14 +208,9 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2], if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL) fatal("ldpe"); - /* start interfaces */ - LIST_FOREACH(iface, &leconf->iface_list, entry) { + /* initialize interfaces */ + LIST_FOREACH(iface, &leconf->iface_list, entry) if_init(xconf, iface); - if (if_fsm(iface, IF_EVT_UP)) { - log_debug("error starting interface %s", - iface->name); - } - } event_dispatch(); @@ -229,11 +225,13 @@ ldpe_shutdown(void) struct iface *iface; /* stop all interfaces */ - LIST_FOREACH(iface, &leconf->iface_list, entry) { + while ((iface = LIST_FIRST(&leconf->iface_list)) != NULL) { if (if_fsm(iface, IF_EVT_DOWN)) { log_debug("error stopping interface %s", iface->name); } + LIST_REMOVE(iface, entry); + if_del(iface); } close(leconf->ldp_discovery_socket); @@ -275,8 +273,11 @@ ldpe_dispatch_main(int fd, short event, void *bula) struct imsgev *iev = bula; struct imsgbuf *ibuf = &iev->ibuf; struct iface *iface = NULL; + struct if_addr *if_addr = NULL, *a; struct kif *kif; - int n, link_new, link_old, shut = 0; + struct kaddr *kaddr; + int n, shut = 0; + struct nbr *nbr; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1) @@ -296,37 +297,87 @@ ldpe_dispatch_main(int fd, short event, void *bula) break; switch (imsg.hdr.type) { - case IMSG_IFINFO: + case IMSG_IFSTATUS: + case IMSG_IFUP: + case IMSG_IFDOWN: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct kif)) fatalx("IFINFO imsg with wrong len"); + kif = imsg.data; - link_new = (kif->flags & IFF_UP) && - LINK_STATE_IS_UP(kif->link_state); - - LIST_FOREACH(iface, &leconf->iface_list, entry) { - if (kif->ifindex == iface->ifindex) { - link_old = (iface->flags & IFF_UP) && - LINK_STATE_IS_UP(iface->linkstate); - iface->flags = kif->flags; - iface->linkstate = kif->link_state; - - if (link_new == link_old) - continue; - if (link_new) { - if_fsm(iface, IF_EVT_UP); - log_warnx("interface %s up", - iface->name); - /* XXX: send address msg */ - } else { - if_fsm(iface, IF_EVT_DOWN); - log_warnx("interface %s down", - iface->name); - /* XXX: send address withdraw - msg */ - } - } + iface = if_lookup(kif->ifindex); + if (!iface) + break; + + iface->flags = kif->flags; + iface->linkstate = kif->link_state; + switch (imsg.hdr.type) { + case IMSG_IFUP: + if_fsm(iface, IF_EVT_UP); + break; + case IMSG_IFDOWN: + if_fsm(iface, IF_EVT_DOWN); + break; + default: + break; + } + break; + case IMSG_NEWADDR: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct kaddr)) + fatalx("NEWADDR imsg with wrong len"); + kaddr = imsg.data; + + if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL) + fatal("ldpe_dispatch_main"); + + if_addr->addr = kaddr->addr; + if_addr->mask = kaddr->mask; + if_addr->dstbrd = kaddr->dstbrd; + + LIST_INSERT_HEAD(&leconf->addr_list, if_addr, + global_entry); + RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { + if (nbr->state != NBR_STA_OPER) + continue; + send_address(nbr, if_addr); + } + + iface = if_lookup(kaddr->ifindex); + if (iface) { + LIST_INSERT_HEAD(&iface->addr_list, if_addr, + iface_entry); + if_fsm(iface, IF_EVT_NEWADDR); + } + break; + case IMSG_DELADDR: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct kaddr)) + fatalx("DELADDR imsg with wrong len"); + kaddr = imsg.data; + + LIST_FOREACH(a, &leconf->addr_list, global_entry) + if (a->addr.s_addr == kaddr->addr.s_addr && + a->mask.s_addr == kaddr->mask.s_addr && + a->dstbrd.s_addr == kaddr->dstbrd.s_addr) + break; + if_addr = a; + if (!if_addr) + break; + + LIST_REMOVE(if_addr, global_entry); + RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { + if (nbr->state != NBR_STA_OPER) + continue; + send_address_withdraw(nbr, if_addr); + } + + iface = if_lookup(kaddr->ifindex); + if (iface) { + LIST_REMOVE(if_addr, iface_entry); + if_fsm(iface, IF_EVT_DELADDR); } + free(if_addr); break; case IMSG_RECONF_CONF: break; diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h index 6148c95d193..5b1b3858a2d 100644 --- a/usr.sbin/ldpd/ldpe.h +++ b/usr.sbin/ldpd/ldpe.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.h,v 1.21 2013/06/01 19:28:55 claudio Exp $ */ +/* $OpenBSD: ldpe.h,v 1.22 2013/06/03 16:53:49 claudio Exp $ */ /* * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> @@ -97,9 +97,9 @@ struct ibuf *send_notification(u_int32_t, u_int32_t, u_int32_t); int recv_notification(struct nbr *, char *, u_int16_t); /* address.c */ -void send_address(struct nbr *, struct iface *); +void send_address(struct nbr *, struct if_addr *); int recv_address(struct nbr *, char *, u_int16_t); -void send_address_withdraw(struct nbr *, struct iface *); +void send_address_withdraw(struct nbr *, struct if_addr *); /* labelmapping.c */ #define PREFIX_SIZE(x) (((x) + 7) / 8) @@ -128,12 +128,10 @@ void ldpe_iface_ctl(struct ctl_conn *, unsigned int); /* interface.c */ int if_fsm(struct iface *, enum iface_event); -struct iface *if_new(struct kif *, struct kif_addr *); +struct iface *if_new(struct kif *); void if_del(struct iface *); void if_init(struct ldpd_conf *, struct iface *); - -int if_act_start(struct iface *); -int if_act_reset(struct iface *); +struct iface *if_lookup(u_short); struct ctl_iface *if_to_ctl(struct iface *); diff --git a/usr.sbin/ldpd/packet.c b/usr.sbin/ldpd/packet.c index bd1be15fb29..87b6b4aa106 100644 --- a/usr.sbin/ldpd/packet.c +++ b/usr.sbin/ldpd/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.24 2013/06/01 19:01:32 claudio Exp $ */ +/* $OpenBSD: packet.c,v 1.25 2013/06/03 16:53:49 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -39,7 +39,9 @@ #include "log.h" #include "ldpe.h" -struct iface *find_iface(struct ldpd_conf *, unsigned int, struct in_addr); +extern struct ldpd_conf *leconf; + +struct iface *disc_find_iface(unsigned int, struct in_addr); ssize_t session_get_pdu(struct ibuf_read *, char **); static int msgcnt = 0; @@ -112,7 +114,6 @@ disc_recv_packet(int fd, short event, void *bula) struct sockaddr_in src; struct msghdr msg; struct iovec iov; - struct ldpd_conf *xconf = bula; struct ldp_hdr ldp_hdr; struct ldp_msg ldp_msg; struct iface *iface; @@ -155,7 +156,7 @@ disc_recv_packet(int fd, short event, void *bula) len = (u_int16_t)r; /* find a matching interface */ - if ((iface = find_iface(xconf, ifindex, src.sin_addr)) == NULL) { + if ((iface = disc_find_iface(ifindex, src.sin_addr)) == NULL) { log_debug("disc_recv_packet: cannot find a matching interface"); return; } @@ -207,26 +208,27 @@ disc_recv_packet(int fd, short event, void *bula) } struct iface * -find_iface(struct ldpd_conf *xconf, unsigned int ifindex, struct in_addr src) +disc_find_iface(unsigned int ifindex, struct in_addr src) { - struct iface *iface = NULL; - - /* returned interface needs to be active */ - LIST_FOREACH(iface, &xconf->iface_list, entry) { - switch (iface->type) { - case IF_TYPE_POINTOPOINT: - if (ifindex == iface->ifindex && - iface->dst.s_addr == src.s_addr) - return (iface); - break; - default: - if (ifindex == iface->ifindex && - (iface->addr.s_addr & iface->mask.s_addr) == - (src.s_addr & iface->mask.s_addr)) - return (iface); - break; - } - } + struct iface *iface; + struct if_addr *if_addr; + + LIST_FOREACH(iface, &leconf->iface_list, entry) + LIST_FOREACH(if_addr, &iface->addr_list, iface_entry) + switch (iface->type) { + case IF_TYPE_POINTOPOINT: + if (ifindex == iface->ifindex && + if_addr->dstbrd.s_addr == src.s_addr) + return (iface); + break; + default: + if (ifindex == iface->ifindex && + (if_addr->addr.s_addr & + if_addr->mask.s_addr) == + (src.s_addr & if_addr->mask.s_addr)) + return (iface); + break; + } return (NULL); } diff --git a/usr.sbin/ldpd/parse.y b/usr.sbin/ldpd/parse.y index 77e643c62a8..52eea17bed0 100644 --- a/usr.sbin/ldpd/parse.y +++ b/usr.sbin/ldpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.14 2013/06/01 19:28:55 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.15 2013/06/03 16:53:49 claudio Exp $ */ /* * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> @@ -94,7 +94,7 @@ struct config_defaults globaldefs; struct config_defaults ifacedefs; struct config_defaults *defs; -struct iface *conf_get_if(struct kif *, struct kif_addr *); +struct iface *conf_get_if(struct kif *); typedef struct { union { @@ -251,38 +251,14 @@ nl : '\n' optnl /* one newline or more */ interface : INTERFACE STRING { struct kif *kif; - struct kif_addr *ka = NULL; - char *s; - struct in_addr addr; - - s = strchr($2, ':'); - if (s) { - *s++ = '\0'; - if (inet_aton(s, &addr) == 0) { - yyerror( - "error parsing interface address"); - free($2); - YYERROR; - } - } else - addr.s_addr = 0; - - if ((kif = kif_findname($2, addr, &ka)) == NULL) { + + if ((kif = kif_findname($2)) == NULL) { yyerror("unknown interface %s", $2); free($2); YYERROR; } - if (ka == NULL) { - if (s) - yyerror("address %s not configured on " - "interface %s", s, $2); - else - yyerror("unnumbered interface %s", $2); - free($2); - YYERROR; - } free($2); - iface = conf_get_if(kif, ka); + iface = conf_get_if(kif); if (iface == NULL) YYERROR; if (iface->media_type == IFT_LOOP || @@ -804,20 +780,19 @@ symget(const char *nam) } struct iface * -conf_get_if(struct kif *kif, struct kif_addr *ka) +conf_get_if(struct kif *kif) { struct iface *i; LIST_FOREACH(i, &conf->iface_list, entry) { - if (i->ifindex == kif->ifindex && - i->addr.s_addr == ka->addr.s_addr) { + if (i->ifindex == kif->ifindex) { yyerror("interface %s already configured", kif->ifname); return (NULL); } } - i = if_new(kif, ka); + i = if_new(kif); return (i); } |