summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2013-06-03 16:53:49 +0000
committerclaudio <claudio@openbsd.org>2013-06-03 16:53:49 +0000
commit814e607d3f3f24d8b8efe894e32005cc63075d2c (patch)
treee03b54bf725c419c33211bca1c425f6a34734847
parentregen. reminded by miod (diff)
downloadwireguard-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.c34
-rw-r--r--usr.sbin/ldpd/interface.c125
-rw-r--r--usr.sbin/ldpd/kroute.c109
-rw-r--r--usr.sbin/ldpd/ldpd.c5
-rw-r--r--usr.sbin/ldpd/ldpd.h34
-rw-r--r--usr.sbin/ldpd/ldpe.c127
-rw-r--r--usr.sbin/ldpd/ldpe.h12
-rw-r--r--usr.sbin/ldpd/packet.c48
-rw-r--r--usr.sbin/ldpd/parse.y41
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);
}