summaryrefslogtreecommitdiff
path: root/usr.sbin/ldpd
diff options
context:
space:
mode:
authorRenato Westphal <renato@cvs.openbsd.org>2016-05-23 18:58:49 +0000
committerRenato Westphal <renato@cvs.openbsd.org>2016-05-23 18:58:49 +0000
commitcf7a670d9f872a58664dbcb1068aa3f90ee3a358 (patch)
tree5c5ac205ed68e30352e11e2307ed38d7076646cc /usr.sbin/ldpd
parent2a70268000d85df755837c9e48ee7423c839ee75 (diff)
Add support for IPv6 (RFC 7552).
This includes: * Full compliance to RFC 7552; * Support for MD5 on LDPov6 sessions; * Support for pseudowires over IPv6 LSPs (we're probably the world's first implementation doing this); * Support for the IPv6 explicit-null label; * Knob to specify the prefered address-family for TCP transport connections; * Knob to use cisco non-compliant format to send and interpret the Dual-Stack capability TLV.
Diffstat (limited to 'usr.sbin/ldpd')
-rw-r--r--usr.sbin/ldpd/address.c130
-rw-r--r--usr.sbin/ldpd/adjacency.c78
-rw-r--r--usr.sbin/ldpd/hello.c343
-rw-r--r--usr.sbin/ldpd/init.c6
-rw-r--r--usr.sbin/ldpd/interface.c354
-rw-r--r--usr.sbin/ldpd/kroute.c731
-rw-r--r--usr.sbin/ldpd/l2vpn.c40
-rw-r--r--usr.sbin/ldpd/labelmapping.c76
-rw-r--r--usr.sbin/ldpd/lde.c257
-rw-r--r--usr.sbin/ldpd/lde.h54
-rw-r--r--usr.sbin/ldpd/lde_lib.c93
-rw-r--r--usr.sbin/ldpd/ldp.h25
-rw-r--r--usr.sbin/ldpd/ldpd.813
-rw-r--r--usr.sbin/ldpd/ldpd.c166
-rw-r--r--usr.sbin/ldpd/ldpd.conf.583
-rw-r--r--usr.sbin/ldpd/ldpd.h178
-rw-r--r--usr.sbin/ldpd/ldpe.c178
-rw-r--r--usr.sbin/ldpd/ldpe.h98
-rw-r--r--usr.sbin/ldpd/log.c126
-rw-r--r--usr.sbin/ldpd/log.h11
-rw-r--r--usr.sbin/ldpd/neighbor.c113
-rw-r--r--usr.sbin/ldpd/packet.c163
-rw-r--r--usr.sbin/ldpd/parse.y300
-rw-r--r--usr.sbin/ldpd/pfkey.c72
-rw-r--r--usr.sbin/ldpd/printconf.c88
-rw-r--r--usr.sbin/ldpd/socket.c131
-rw-r--r--usr.sbin/ldpd/util.c303
27 files changed, 3060 insertions, 1150 deletions
diff --git a/usr.sbin/ldpd/address.c b/usr.sbin/ldpd/address.c
index 139393e928a..45e85e99b8f 100644
--- a/usr.sbin/ldpd/address.c
+++ b/usr.sbin/ldpd/address.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: address.c,v 1.22 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: address.c,v 1.23 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -32,16 +32,16 @@
#include <string.h>
#include "ldpd.h"
-#include "ldp.h"
-#include "log.h"
#include "ldpe.h"
+#include "lde.h"
+#include "log.h"
extern struct ldpd_conf *leconf;
-void gen_address_list_tlv(struct ibuf *, struct if_addr *, uint16_t);
+void gen_address_list_tlv(struct ibuf *, uint16_t, int, struct if_addr *);
void
-send_address(struct nbr *nbr, struct if_addr *if_addr, int withdraw)
+send_address(struct nbr *nbr, int af, struct if_addr *if_addr, int withdraw)
{
struct ibuf *buf;
uint32_t msg_type;
@@ -55,12 +55,22 @@ send_address(struct nbr *nbr, struct if_addr *if_addr, int withdraw)
if (if_addr == NULL) {
LIST_FOREACH(if_addr, &global.addr_list, entry)
- iface_count++;
+ if (if_addr->af == af)
+ iface_count++;
} else
iface_count = 1;
- size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct address_list_tlv) +
- iface_count * sizeof(struct in_addr);
+ size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct address_list_tlv);
+ switch (af) {
+ case AF_INET:
+ size += iface_count * sizeof(struct in_addr);
+ break;
+ case AF_INET6:
+ size += iface_count * sizeof(struct in6_addr);
+ break;
+ default:
+ fatalx("send_address: unknown af");
+ }
if ((buf = ibuf_open(size)) == NULL)
fatal(__func__);
@@ -69,7 +79,7 @@ send_address(struct nbr *nbr, struct if_addr *if_addr, int withdraw)
size -= LDP_HDR_SIZE;
gen_msg_hdr(buf, msg_type, size);
size -= LDP_MSG_SIZE;
- gen_address_list_tlv(buf, if_addr, size);
+ gen_address_list_tlv(buf, size, af, if_addr);
evbuf_enqueue(&nbr->tcp->wbuf, buf);
@@ -82,13 +92,9 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
struct ldp_msg addr;
struct address_list_tlv alt;
enum imsg_type type;
+ struct lde_addr lde_addr;
memcpy(&addr, buf, sizeof(addr));
- if (ntohs(addr.type) == MSG_TYPE_ADDR)
- type = IMSG_ADDRESS_ADD;
- else
- type = IMSG_ADDRESS_DEL;
-
buf += LDP_MSG_SIZE;
len -= LDP_MSG_SIZE;
@@ -107,48 +113,104 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
session_shutdown(nbr, S_UNKNOWN_TLV, addr.msgid, addr.type);
return (-1);
}
-
- /* For now we only support IPv4 */
- if (alt.family != htons(AF_IPV4)) {
+ switch (ntohs(alt.family)) {
+ case AF_IPV4:
+ if (!nbr->v4_enabled)
+ /* just ignore the message */
+ return (0);
+ break;
+ case AF_IPV6:
+ if (!nbr->v6_enabled)
+ /* just ignore the message */
+ return (0);
+ break;
+ default:
send_notification_nbr(nbr, S_UNSUP_ADDR, addr.msgid, addr.type);
return (-1);
}
buf += sizeof(alt);
len -= sizeof(alt);
- while (len >= sizeof(struct in_addr)) {
- ldpe_imsg_compose_lde(type, nbr->peerid, 0,
- buf, sizeof(struct in_addr));
-
- buf += sizeof(struct in_addr);
- len -= sizeof(struct in_addr);
- }
+ if (ntohs(addr.type) == MSG_TYPE_ADDR)
+ type = IMSG_ADDRESS_ADD;
+ else
+ type = IMSG_ADDRESS_DEL;
- if (len != 0) {
- session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid, addr.type);
- return (-1);
+ while (len > 0) {
+ switch (ntohs(alt.family)) {
+ case AF_IPV4:
+ if (len < sizeof(struct in_addr)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid,
+ addr.type);
+ return (-1);
+ }
+
+ memset(&lde_addr, 0, sizeof(lde_addr));
+ lde_addr.af = AF_INET;
+ memcpy(&lde_addr.addr, buf, sizeof(struct in_addr));
+
+ buf += sizeof(struct in_addr);
+ len -= sizeof(struct in_addr);
+ break;
+ case AF_IPV6:
+ if (len < sizeof(struct in6_addr)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid,
+ addr.type);
+ return (-1);
+ }
+
+ memset(&lde_addr, 0, sizeof(lde_addr));
+ lde_addr.af = AF_INET6;
+ memcpy(&lde_addr.addr, buf, sizeof(struct in6_addr));
+
+ buf += sizeof(struct in6_addr);
+ len -= sizeof(struct in6_addr);
+ break;
+ default:
+ fatalx("recv_address: unknown af");
+ }
+
+ log_debug("%s: neighbor ID %s address %s%s", __func__,
+ inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr),
+ ntohs(addr.type) == MSG_TYPE_ADDR ? "" : " (withdraw)");
+
+ ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
+ sizeof(lde_addr));
}
return (0);
}
void
-gen_address_list_tlv(struct ibuf *buf, struct if_addr *if_addr, uint16_t size)
+gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
+ struct if_addr *if_addr)
{
struct address_list_tlv alt;
-
+ uint16_t addr_size;
memset(&alt, 0, sizeof(alt));
alt.type = TLV_TYPE_ADDRLIST;
alt.length = htons(size - TLV_HDR_LEN);
- /* XXX: just ipv4 for now */
- alt.family = htons(AF_IPV4);
+ switch (af) {
+ case AF_INET:
+ alt.family = htons(AF_IPV4);
+ addr_size = sizeof(struct in_addr);
+ break;
+ case AF_INET6:
+ alt.family = htons(AF_IPV6);
+ addr_size = sizeof(struct in6_addr);
+ break;
+ default:
+ fatalx("gen_address_list_tlv: unknown af");
+ }
ibuf_add(buf, &alt, sizeof(alt));
if (if_addr == NULL) {
- LIST_FOREACH(if_addr, &global.addr_list, entry)
- ibuf_add(buf, &if_addr->addr, sizeof(if_addr->addr));
+ LIST_FOREACH(if_addr, &global.addr_list, entry) {
+ if (if_addr->af == af)
+ ibuf_add(buf, &if_addr->addr, addr_size);
+ }
} else
- ibuf_add(buf, &if_addr->addr, sizeof(if_addr->addr));
+ ibuf_add(buf, &if_addr->addr, addr_size);
}
diff --git a/usr.sbin/ldpd/adjacency.c b/usr.sbin/ldpd/adjacency.c
index 68066ff81bb..a116b4592b1 100644
--- a/usr.sbin/ldpd/adjacency.c
+++ b/usr.sbin/ldpd/adjacency.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: adjacency.c,v 1.18 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: adjacency.c,v 1.19 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -39,28 +39,29 @@ void tnbr_start_hello_timer(struct tnbr *);
void tnbr_stop_hello_timer(struct tnbr *);
struct adj *
-adj_new(struct nbr *nbr, struct hello_source *source, struct in_addr addr)
+adj_new(struct in_addr lsr_id, struct hello_source *source,
+ union ldpd_addr *addr)
{
struct adj *adj;
- log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(nbr->id),
+ log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(lsr_id),
log_hello_src(source));
if ((adj = calloc(1, sizeof(*adj))) == NULL)
fatal(__func__);
- adj->nbr = nbr;
+ adj->lsr_id = lsr_id;
+ adj->nbr = NULL;
adj->source = *source;
- adj->addr = addr;
+ adj->trans_addr = *addr;
evtimer_set(&adj->inactivity_timer, adj_itimer, adj);
- LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry);
+ LIST_INSERT_HEAD(&global.adj_list, adj, global_entry);
switch (source->type) {
case HELLO_LINK:
- LIST_INSERT_HEAD(&source->link.iface->adj_list, adj,
- iface_entry);
+ LIST_INSERT_HEAD(&source->link.ia->adj_list, adj, ia_entry);
break;
case HELLO_TARGETED:
source->target->adj = adj;
@@ -73,35 +74,38 @@ adj_new(struct nbr *nbr, struct hello_source *source, struct in_addr addr)
void
adj_del(struct adj *adj)
{
- log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(adj->nbr->id),
+ log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(adj->lsr_id),
log_hello_src(&adj->source));
adj_stop_itimer(adj);
- LIST_REMOVE(adj, nbr_entry);
+ LIST_REMOVE(adj, global_entry);
+ if (adj->nbr)
+ LIST_REMOVE(adj, nbr_entry);
if (adj->source.type == HELLO_LINK)
- LIST_REMOVE(adj, iface_entry);
+ LIST_REMOVE(adj, ia_entry);
/* last adjacency deleted */
- if (LIST_EMPTY(&adj->nbr->adj_list))
+ if (adj->nbr && LIST_EMPTY(&adj->nbr->adj_list))
nbr_del(adj->nbr);
free(adj);
}
struct adj *
-adj_find(struct nbr *nbr, struct hello_source *source)
+adj_find(struct hello_source *source)
{
struct adj *adj;
- LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) {
+ LIST_FOREACH(adj, &global.adj_list, global_entry) {
if (adj->source.type != source->type)
continue;
switch (source->type) {
case HELLO_LINK:
- if (adj->source.link.src_addr.s_addr ==
- source->link.src_addr.s_addr)
+ if (ldp_addrcmp(source->link.ia->af,
+ &adj->source.link.src_addr,
+ &source->link.src_addr) == 0)
return (adj);
break;
case HELLO_TARGETED:
@@ -114,6 +118,19 @@ adj_find(struct nbr *nbr, struct hello_source *source)
return (NULL);
}
+int
+adj_get_af(struct adj *adj)
+{
+ switch (adj->source.type) {
+ case HELLO_LINK:
+ return (adj->source.link.ia->af);
+ case HELLO_TARGETED:
+ return (adj->source.target->af);
+ default:
+ fatalx("adj_get_af: unknown hello type");
+ }
+}
+
/* adjacency timers */
/* ARGSUSED */
@@ -122,7 +139,7 @@ adj_itimer(int fd, short event, void *arg)
{
struct adj *adj = arg;
- log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->nbr->id));
+ log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id));
if (adj->source.type == HELLO_TARGETED) {
if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
@@ -159,17 +176,18 @@ adj_stop_itimer(struct adj *adj)
/* targeted neighbors */
struct tnbr *
-tnbr_new(struct ldpd_conf *xconf, struct in_addr addr)
+tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
{
struct tnbr *tnbr;
if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL)
fatal(__func__);
- tnbr->addr = addr;
+ tnbr->af = af;
+ tnbr->addr = *addr;
tnbr->state = TNBR_STA_DOWN;
- tnbr->hello_holdtime = xconf->thello_holdtime;
- tnbr->hello_interval = xconf->thello_interval;
+ tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime;
+ tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval;
return (tnbr);
}
@@ -185,12 +203,13 @@ tnbr_del(struct tnbr *tnbr)
}
struct tnbr *
-tnbr_find(struct ldpd_conf *xconf, struct in_addr addr)
+tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
{
struct tnbr *tnbr;
LIST_FOREACH(tnbr, &xconf->tnbr_list, entry)
- if (addr.s_addr == tnbr->addr.s_addr)
+ if (af == tnbr->af &&
+ ldp_addrcmp(af, addr, &tnbr->addr) == 0)
return (tnbr);
return (NULL);
@@ -213,7 +232,7 @@ tnbr_update(struct tnbr *tnbr)
{
int socket_ok, rtr_id_ok;
- if (global.ldp_edisc_socket != -1)
+ if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1)
socket_ok = 1;
else
socket_ok = 0;
@@ -242,13 +261,14 @@ tnbr_update(struct tnbr *tnbr)
}
void
-tnbr_update_all(void)
+tnbr_update_all(int af)
{
struct tnbr *tnbr;
/* update targeted neighbors */
LIST_FOREACH(tnbr, &leconf->tnbr_list, entry)
- tnbr_update(tnbr);
+ if (tnbr->af == af || af == AF_UNSPEC)
+ tnbr_update(tnbr);
}
/* target neighbors timers */
@@ -287,11 +307,12 @@ adj_to_ctl(struct adj *adj)
{
static struct ctl_adj actl;
- actl.id = adj->nbr->id;
+ actl.af = adj_get_af(adj);
+ actl.id = adj->lsr_id;
actl.type = adj->source.type;
switch (adj->source.type) {
case HELLO_LINK:
- memcpy(actl.ifname, adj->source.link.iface->name,
+ memcpy(actl.ifname, adj->source.link.ia->iface->name,
sizeof(actl.ifname));
break;
case HELLO_TARGETED:
@@ -299,6 +320,7 @@ adj_to_ctl(struct adj *adj)
break;
}
actl.holdtime = adj->holdtime;
+ actl.trans_addr = adj->trans_addr;
return (&actl);
}
diff --git a/usr.sbin/ldpd/hello.c b/usr.sbin/ldpd/hello.c
index be195e393ba..043eac8b7da 100644
--- a/usr.sbin/ldpd/hello.c
+++ b/usr.sbin/ldpd/hello.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hello.c,v 1.39 2016/05/23 18:33:56 renato Exp $ */
+/* $OpenBSD: hello.c,v 1.40 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -38,42 +38,70 @@
extern struct ldpd_conf *leconf;
int tlv_decode_hello_prms(char *, uint16_t, uint16_t *, uint16_t *);
-int tlv_decode_opt_hello_prms(char *, uint16_t, struct in_addr *,
- uint32_t *);
+int tlv_decode_opt_hello_prms(char *, uint16_t, int *, int,
+ union ldpd_addr *, uint32_t *, uint16_t *);
int gen_hello_prms_tlv(struct ibuf *buf, uint16_t, uint16_t);
int gen_opt4_hello_prms_tlv(struct ibuf *, uint16_t, uint32_t);
+int gen_opt16_hello_prms_tlv(struct ibuf *, uint16_t, uint8_t *);
+int gen_ds_hello_prms_tlv(struct ibuf *, uint32_t);
int
-send_hello(enum hello_type type, struct iface *iface, struct tnbr *tnbr)
+send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
{
- struct sockaddr_in dst;
- struct ibuf *buf;
+ int af;
+ union ldpd_addr dst;
uint16_t size, holdtime = 0, flags = 0;
int fd = 0;
-
- dst.sin_port = htons(LDP_PORT);
- dst.sin_family = AF_INET;
- dst.sin_len = sizeof(struct sockaddr_in);
+ struct ibuf *buf;
switch (type) {
case HELLO_LINK:
- inet_aton(AllRouters, &dst.sin_addr);
- holdtime = iface->hello_holdtime;
+ af = ia->af;
+ holdtime = ia->hello_holdtime;
flags = 0;
- fd = global.ldp_disc_socket;
+ fd = (ldp_af_global_get(&global, af))->ldp_disc_socket;
+
+ /* multicast destination address */
+ switch (af) {
+ case AF_INET:
+ dst.v4 = global.mcast_addr_v4;
+ break;
+ case AF_INET6:
+ dst.v6 = global.mcast_addr_v6;
+ break;
+ default:
+ fatalx("send_hello: unknown af");
+ }
break;
case HELLO_TARGETED:
- dst.sin_addr = tnbr->addr;
+ af = tnbr->af;
holdtime = tnbr->hello_holdtime;
flags = TARGETED_HELLO;
if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count)
flags |= REQUEST_TARG_HELLO;
- fd = global.ldp_edisc_socket;
+ fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket;
+
+ /* unicast destination address */
+ dst = tnbr->addr;
break;
+ default:
+ fatalx("send_hello: unknown hello type");
}
- size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct hello_prms_tlv) +
- sizeof(struct hello_prms_opt4_tlv);
+ /* calculate message size */
+ size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct hello_prms_tlv);
+ switch (af) {
+ case AF_INET:
+ size += sizeof(struct hello_prms_opt4_tlv);
+ break;
+ case AF_INET6:
+ size += sizeof(struct hello_prms_opt16_tlv);
+ break;
+ default:
+ fatalx("send_hello: unknown af");
+ }
+ if (ldp_is_dual_stack(leconf))
+ size += sizeof(struct hello_prms_opt4_tlv);
/* generate message */
if ((buf = ibuf_open(size)) == NULL)
@@ -83,26 +111,57 @@ send_hello(enum hello_type type, struct iface *iface, struct tnbr *tnbr)
size -= LDP_HDR_SIZE;
gen_msg_hdr(buf, MSG_TYPE_HELLO, size);
gen_hello_prms_tlv(buf, holdtime, flags);
- gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR,
- leconf->trans_addr.s_addr);
- send_packet(fd, iface, buf->buf, buf->wpos, &dst);
+ /*
+ * RFC 7552 - Section 6.1:
+ * "An LSR MUST include only the transport address whose address
+ * family is the same as that of the IP packet carrying the Hello
+ * message".
+ */
+ switch (af) {
+ case AF_INET:
+ gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR,
+ leconf->ipv4.trans_addr.v4.s_addr);
+ break;
+ case AF_INET6:
+ gen_opt16_hello_prms_tlv(buf, TLV_TYPE_IPV6TRANSADDR,
+ leconf->ipv6.trans_addr.v6.s6_addr);
+ break;
+ default:
+ fatalx("send_hello: unknown af");
+ }
+
+ /*
+ * RFC 7552 - Section 6.1.1:
+ * "A Dual-stack LSR (i.e., an LSR supporting Dual-stack LDP for a peer)
+ * MUST include the Dual-Stack capability TLV in all of its LDP Hellos".
+ */
+ if (ldp_is_dual_stack(leconf))
+ gen_ds_hello_prms_tlv(buf, leconf->trans_pref);
+
+ send_packet(fd, af, &dst, ia, buf->buf, buf->wpos);
ibuf_free(buf);
return (0);
}
void
-recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src,
- struct iface *iface, int multicast, char *buf, uint16_t len)
+recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, int af,
+ union ldpd_addr *src, struct iface *iface, int multicast, char *buf,
+ uint16_t len)
{
- struct adj *adj;
+ struct adj *adj = NULL;
struct nbr *nbr;
uint16_t holdtime, flags;
- struct in_addr transport_addr;
+ int tlvs_rcvd;
+ int ds_tlv;
+ union ldpd_addr trans_addr;
+ uint32_t scope_id = 0;
uint32_t conf_number;
+ uint16_t trans_pref;
int r;
struct hello_source source;
+ struct iface_af *ia = NULL;
struct tnbr *tnbr = NULL;
r = tlv_decode_hello_prms(buf, len, &holdtime, &flags);
@@ -133,7 +192,19 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src,
memset(&source, 0, sizeof(source));
if (flags & TARGETED_HELLO) {
- tnbr = tnbr_find(leconf, src);
+ /*
+ * RFC 7552 - Section 5.2:
+ * "The link-local IPv6 addresses MUST NOT be used as the
+ * targeted LDP Hello packet's source or destination addresses.
+ */
+ if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&src->v6)) {
+ log_debug("%s: lsr-id %s: targeted hello with "
+ "link-local source address", __func__,
+ inet_ntoa(lsr_id));
+ return;
+ }
+
+ tnbr = tnbr_find(leconf, af, src);
/* remove the dynamic tnbr if the 'R' bit was cleared */
if (tnbr && (tnbr->flags & F_TNBR_DYNAMIC) &&
@@ -144,10 +215,11 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src,
if (!tnbr) {
if (!((flags & REQUEST_TARG_HELLO) &&
- leconf->flags & F_LDPD_TH_ACCEPT))
+ ((ldp_af_conf_get(leconf, af))->flags &
+ F_LDPD_AF_THELLO_ACCEPT)))
return;
- tnbr = tnbr_new(leconf, src);
+ tnbr = tnbr_new(leconf, af, src);
tnbr->flags |= F_TNBR_DYNAMIC;
tnbr_update(tnbr);
LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
@@ -156,13 +228,14 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src,
source.type = HELLO_TARGETED;
source.target = tnbr;
} else {
+ ia = iface_af_get(iface, af);
source.type = HELLO_LINK;
- source.link.iface = iface;
- source.link.src_addr = src;
+ source.link.ia = ia;
+ source.link.src_addr = *src;
}
- r = tlv_decode_opt_hello_prms(buf, len, &transport_addr,
- &conf_number);
+ r = tlv_decode_opt_hello_prms(buf, len, &tlvs_rcvd, af, &trans_addr,
+ &conf_number, &trans_pref);
if (r == -1) {
log_debug("%s: lsr-id %s: failed to decode optional params",
__func__, inet_ntoa(lsr_id));
@@ -175,30 +248,118 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src,
}
/* implicit transport address */
- if (transport_addr.s_addr == INADDR_ANY)
- transport_addr = src;
- if (bad_ip_addr(transport_addr)) {
+ if (!(tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR))
+ trans_addr = *src;
+ if (bad_addr(af, &trans_addr)) {
log_debug("%s: lsr-id %s: invalid transport address %s",
- __func__, inet_ntoa(lsr_id), inet_ntoa(transport_addr));
+ __func__, inet_ntoa(lsr_id), log_addr(af, &trans_addr));
return;
}
+ if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&trans_addr.v6)) {
+ /*
+ * RFC 7552 - Section 6.1:
+ * An LSR MUST use a global unicast IPv6 address in an IPv6
+ * Transport Address optional object of outgoing targeted
+ * Hellos and check for the same in incoming targeted Hellos
+ * (i.e., MUST discard the targeted Hello if it failed the
+ * check)".
+ */
+ if (source.type == HELLO_TARGETED)
+ return;
+ scope_id = iface->ifindex;
+ }
+ adj = adj_find(&source);
nbr = nbr_find_ldpid(lsr_id.s_addr);
- if (!nbr) {
+
+ /* check dual-stack tlv */
+ ds_tlv = (tlvs_rcvd & F_HELLO_TLV_RCVD_DS) ? 1 : 0;
+ if (ds_tlv && trans_pref != leconf->trans_pref) {
+ /*
+ * RFC 7552 - Section 6.1.1:
+ * "If the Dual-Stack capability TLV is present and the remote
+ * preference does not match the local preference (or does not
+ * get recognized), then the LSR MUST discard the Hello message
+ * and log an error.
+ * If an LDP session was already in place, then the LSR MUST
+ * send a fatal Notification message with status code of
+ * 'Transport Connection Mismatch' and reset the session".
+ */
+ log_debug("%s: lsr-id %s: remote transport preference does not "
+ "match the local preference", __func__, inet_ntoa(lsr_id));
+ if (nbr)
+ session_shutdown(nbr, S_TRANS_MISMTCH, lm->msgid,
+ lm->type);
+ if (adj)
+ adj_del(adj);
+ return;
+ }
+
+ if (adj == NULL) {
+ adj = adj_new(lsr_id, &source, &trans_addr);
+ if (nbr) {
+ adj->nbr = nbr;
+ LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry);
+ }
+ }
+
+ if (nbr == NULL) {
+ /*
+ * The hello adjacency's address-family doesn't match the local
+ * preference.
+ */
+ if (ds_tlv &&
+ ((trans_pref == DUAL_STACK_LDPOV4 && af != AF_INET) ||
+ (trans_pref == DUAL_STACK_LDPOV6 && af != AF_INET6)))
+ return;
+
+ nbr = nbr_find_addr(af, &trans_addr);
+ if (nbr) {
+ log_debug("%s: transport address %s is already being "
+ "used by lsr-id %s", __func__, log_addr(af,
+ &trans_addr), inet_ntoa(nbr->id));
+ return;
+ }
+
/* create new adjacency and new neighbor */
- nbr = nbr_new(lsr_id, transport_addr);
- adj = adj_new(nbr, &source, transport_addr);
+ nbr = nbr_new(lsr_id, af, ds_tlv, &trans_addr, scope_id);
} else {
- adj = adj_find(nbr, &source);
- if (!adj) {
- /* create new adjacency for existing neighbor */
- adj = adj_new(nbr, &source, transport_addr);
-
- if (nbr->raddr.s_addr != transport_addr.s_addr)
- log_warnx("%s: lsr-id %s: multiple "
- "adjacencies advertising different "
- "transport addresses", __func__,
- inet_ntoa(lsr_id));
+ /*
+ * Check for noncompliant dual-stack neighbor according to
+ * RFC 7552 section 6.1.1.
+ */
+ if (!ds_tlv) {
+ switch (af) {
+ case AF_INET:
+ if (nbr_adj_count(nbr, AF_INET6) > 0) {
+ session_shutdown(nbr, S_DS_NONCMPLNCE,
+ lm->msgid, lm->type);
+ return;
+ }
+ break;
+ case AF_INET6:
+ if (nbr_adj_count(nbr, AF_INET) > 0) {
+ session_shutdown(nbr, S_DS_NONCMPLNCE,
+ lm->msgid, lm->type);
+ return;
+ }
+ break;
+ default:
+ fatalx("recv_hello: unknown af");
+ }
+ }
+
+ /*
+ * Protection against misconfigured networks and buggy
+ * implementations.
+ */
+ if (af == nbr->af &&
+ (ldp_addrcmp(af, &nbr->raddr, &trans_addr) ||
+ nbr->raddr_scope != scope_id)) {
+ log_warnx("%s: lsr-id %s: ignoring hello packet "
+ "advertising different transport address", __func__,
+ inet_ntoa(lsr_id));
+ return;
}
}
@@ -208,7 +369,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src,
if (holdtime == 0)
holdtime = LINK_DFLT_HOLDTIME;
- adj->holdtime = min(iface->hello_holdtime, holdtime);
+ adj->holdtime = min(ia->hello_holdtime, holdtime);
break;
case HELLO_TARGETED:
if (holdtime == 0)
@@ -247,13 +408,37 @@ gen_opt4_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint32_t value)
memset(&parms, 0, sizeof(parms));
parms.type = htons(type);
- parms.length = htons(4);
+ parms.length = htons(sizeof(parms.value));
parms.value = value;
return (ibuf_add(buf, &parms, sizeof(parms)));
}
int
+gen_opt16_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint8_t *value)
+{
+ struct hello_prms_opt16_tlv parms;
+
+ memset(&parms, 0, sizeof(parms));
+ parms.type = htons(type);
+ parms.length = htons(sizeof(parms.value));
+ memcpy(&parms.value, value, sizeof(parms.value));
+
+ return (ibuf_add(buf, &parms, sizeof(parms)));
+}
+
+int
+gen_ds_hello_prms_tlv(struct ibuf *buf, uint32_t value)
+{
+ if (leconf->flags & F_LDPD_DS_CISCO_INTEROP)
+ value = htonl(value);
+ else
+ value = htonl(value << 28);
+
+ return (gen_opt4_hello_prms_tlv(buf, TLV_TYPE_DUALSTACK, value));
+}
+
+int
tlv_decode_hello_prms(char *buf, uint16_t len, uint16_t *holdtime,
uint16_t *flags)
{
@@ -275,30 +460,78 @@ tlv_decode_hello_prms(char *buf, uint16_t len, uint16_t *holdtime,
}
int
-tlv_decode_opt_hello_prms(char *buf, uint16_t len, struct in_addr *addr,
- uint32_t *conf_number)
+tlv_decode_opt_hello_prms(char *buf, uint16_t len, int *tlvs_rcvd, int af,
+ union ldpd_addr *addr, uint32_t *conf_number, uint16_t *trans_pref)
{
struct tlv tlv;
uint16_t tlv_len;
int total = 0;
+ *tlvs_rcvd = 0;
memset(addr, 0, sizeof(*addr));
*conf_number = 0;
-
+ *trans_pref = 0;
+
+ /*
+ * RFC 7552 - Section 6.1:
+ * "An LSR SHOULD accept the Hello message that contains both IPv4 and
+ * IPv6 Transport Address optional objects but MUST use only the
+ * transport address whose address family is the same as that of the
+ * IP packet carrying the Hello message. An LSR SHOULD accept only
+ * the first Transport Address optional object for a given address
+ * family in the received Hello message and ignore the rest if the
+ * LSR receives more than one Transport Address optional object for a
+ * given address family".
+ */
while (len >= sizeof(tlv)) {
memcpy(&tlv, buf, sizeof(tlv));
tlv_len = ntohs(tlv.length);
switch (ntohs(tlv.type)) {
case TLV_TYPE_IPV4TRANSADDR:
- if (tlv_len != sizeof(uint32_t))
+ if (tlv_len != sizeof(addr->v4))
+ return (-1);
+ if (af != AF_INET || ldp_addrisset(AF_INET, addr))
+ break;
+ memcpy(&addr->v4, buf + TLV_HDR_LEN, sizeof(addr->v4));
+ *tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR;
+ break;
+ case TLV_TYPE_IPV6TRANSADDR:
+ if (tlv_len != sizeof(addr->v6))
return (-1);
- memcpy(addr, buf + TLV_HDR_LEN, sizeof(uint32_t));
+ if (af != AF_INET6 || ldp_addrisset(AF_INET6, addr))
+ break;
+ memcpy(&addr->v6, buf + TLV_HDR_LEN, sizeof(addr->v6));
+ *tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR;
break;
case TLV_TYPE_CONFIG:
if (tlv_len != sizeof(uint32_t))
return (-1);
memcpy(conf_number, buf + TLV_HDR_LEN,
sizeof(uint32_t));
+ *tlvs_rcvd |= F_HELLO_TLV_RCVD_CONF;
+ break;
+ case TLV_TYPE_DUALSTACK:
+ if (tlv_len != sizeof(uint32_t))
+ return (-1);
+ /*
+ * RFC 7552 - Section 6.1:
+ * "A Single-stack LSR does not need to use the
+ * Dual-Stack capability in Hello messages and SHOULD
+ * ignore this capability if received".
+ */
+ if (!ldp_is_dual_stack(leconf))
+ break;
+ /* Shame on you, Cisco! */
+ if (leconf->flags & F_LDPD_DS_CISCO_INTEROP) {
+ memcpy(trans_pref, buf + TLV_HDR_LEN +
+ sizeof(uint16_t), sizeof(uint16_t));
+ *trans_pref = ntohs(*trans_pref);
+ } else {
+ memcpy(trans_pref, buf + TLV_HDR_LEN,
+ sizeof(uint16_t));
+ *trans_pref = ntohs(*trans_pref) >> 12;
+ }
+ *tlvs_rcvd |= F_HELLO_TLV_RCVD_DS;
break;
default:
/* if unknown flag set, ignore TLV */
diff --git a/usr.sbin/ldpd/init.c b/usr.sbin/ldpd/init.c
index cad15769b03..4e162bc8788 100644
--- a/usr.sbin/ldpd/init.c
+++ b/usr.sbin/ldpd/init.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: init.c,v 1.24 2016/05/23 17:43:42 renato Exp $ */
+/* $OpenBSD: init.c,v 1.25 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -104,7 +104,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
return (-1);
}
- nbr->keepalive = min(nbr_get_keepalive(nbr->raddr),
+ nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id),
ntohs(sess.keepalive_time));
max_pdu_len = ntohs(sess.max_pdu_len);
@@ -131,7 +131,7 @@ gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr, uint16_t size)
parms.type = htons(TLV_TYPE_COMMONSESSION);
parms.length = htons(size - TLV_HDR_LEN);
parms.proto_version = htons(LDP_VERSION);
- parms.keepalive_time = htons(nbr_get_keepalive(nbr->raddr));
+ parms.keepalive_time = htons(nbr_get_keepalive(nbr->af, nbr->id));
parms.reserved = 0;
parms.pvlim = 0;
parms.max_pdu_len = 0;
diff --git a/usr.sbin/ldpd/interface.c b/usr.sbin/ldpd/interface.c
index 22a5ea17f84..fcaefed8c15 100644
--- a/usr.sbin/ldpd/interface.c
+++ b/usr.sbin/ldpd/interface.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: interface.c,v 1.40 2016/05/23 18:41:59 renato Exp $ */
+/* $OpenBSD: interface.c,v 1.41 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -42,8 +42,8 @@
extern struct ldpd_conf *leconf;
void if_hello_timer(int, short, void *);
-void if_start_hello_timer(struct iface *);
-void if_stop_hello_timer(struct iface *);
+void if_start_hello_timer(struct iface_af *);
+void if_stop_hello_timer(struct iface_af *);
struct iface *
if_new(struct kif *kif)
@@ -53,11 +53,6 @@ if_new(struct kif *kif)
if ((iface = calloc(1, sizeof(*iface))) == NULL)
fatal("if_new: calloc");
- iface->state = IF_STA_DOWN;
-
- LIST_INIT(&iface->addr_list);
- LIST_INIT(&iface->adj_list);
-
strlcpy(iface->name, kif->ifname, sizeof(iface->name));
/* get type */
@@ -68,11 +63,26 @@ if_new(struct kif *kif)
iface->type = IF_TYPE_BROADCAST;
/* get index and flags */
+ LIST_INIT(&iface->addr_list);
iface->ifindex = kif->ifindex;
iface->flags = kif->flags;
iface->linkstate = kif->link_state;
iface->if_type = kif->if_type;
+ /* ipv4 */
+ iface->ipv4.af = AF_INET;
+ iface->ipv4.iface = iface;
+ iface->ipv4.enabled = 0;
+ iface->ipv4.state = IF_STA_DOWN;
+ LIST_INIT(&iface->ipv4.adj_list);
+
+ /* ipv6 */
+ iface->ipv6.af = AF_INET6;
+ iface->ipv6.iface = iface;
+ iface->ipv6.enabled = 0;
+ iface->ipv6.state = IF_STA_DOWN;
+ LIST_INIT(&iface->ipv6.adj_list);
+
return (iface);
}
@@ -81,11 +91,13 @@ if_del(struct iface *iface)
{
struct if_addr *if_addr;
- if (iface->state == IF_STA_ACTIVE)
- if_reset(iface);
-
log_debug("%s: interface %s", __func__, iface->name);
+ if (iface->ipv4.state == IF_STA_ACTIVE)
+ if_reset(iface, AF_INET);
+ if (iface->ipv6.state == IF_STA_ACTIVE)
+ if_reset(iface, AF_INET6);
+
while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
LIST_REMOVE(if_addr, entry);
free(if_addr);
@@ -106,6 +118,19 @@ if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
return (NULL);
}
+struct iface_af *
+iface_af_get(struct iface *iface, int af)
+{
+ switch (af) {
+ case AF_INET:
+ return (&iface->ipv4);
+ case AF_INET6:
+ return (&iface->ipv6);
+ default:
+ fatalx("iface_af_get: unknown af");
+ }
+}
+
struct if_addr *
if_addr_new(struct kaddr *ka)
{
@@ -114,8 +139,9 @@ if_addr_new(struct kaddr *ka)
if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
fatal(__func__);
+ if_addr->af = ka->af;
if_addr->addr = ka->addr;
- if_addr->mask = ka->mask;
+ if_addr->prefixlen = ka->prefixlen;
if_addr->dstbrd = ka->dstbrd;
return (if_addr);
@@ -124,12 +150,13 @@ if_addr_new(struct kaddr *ka)
struct if_addr *
if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
{
- struct if_addr *if_addr;
+ struct if_addr *if_addr;
+ int af = ka->af;
LIST_FOREACH(if_addr, addr_list, entry)
- if (if_addr->addr.s_addr == ka->addr.s_addr &&
- if_addr->mask.s_addr == ka->mask.s_addr &&
- if_addr->dstbrd.s_addr == ka->dstbrd.s_addr)
+ if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
+ if_addr->prefixlen == ka->prefixlen &&
+ !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
return (if_addr);
return (NULL);
@@ -149,17 +176,25 @@ if_addr_add(struct kaddr *ka)
RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
if (nbr->state != NBR_STA_OPER)
continue;
+ if (if_addr->af == AF_INET && !nbr->v4_enabled)
+ continue;
+ if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
+ continue;
- send_address(nbr, if_addr, 0);
+ send_address(nbr, if_addr->af, if_addr, 0);
}
}
iface = if_lookup(leconf, ka->ifindex);
- if (iface &&
- if_addr_lookup(&iface->addr_list, ka) == NULL) {
- if_addr = if_addr_new(ka);
- LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
- if_update(iface);
+ if (iface) {
+ if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
+ iface->linklocal = ka->addr.v6;
+
+ if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
+ if_addr = if_addr_new(ka);
+ LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
+ if_update(iface, if_addr->af);
+ }
}
}
@@ -172,11 +207,15 @@ if_addr_del(struct kaddr *ka)
iface = if_lookup(leconf, ka->ifindex);
if (iface) {
+ if (ka->af == AF_INET6 &&
+ IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
+ memset(&iface->linklocal, 0, sizeof(iface->linklocal));
+
if_addr = if_addr_lookup(&iface->addr_list, ka);
if (if_addr) {
LIST_REMOVE(if_addr, entry);
+ if_update(iface, if_addr->af);
free(if_addr);
- if_update(iface);
}
}
@@ -185,7 +224,11 @@ if_addr_del(struct kaddr *ka)
RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
if (nbr->state != NBR_STA_OPER)
continue;
- send_address(nbr, if_addr, 1);
+ if (if_addr->af == AF_INET && !nbr->v4_enabled)
+ continue;
+ if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
+ continue;
+ send_address(nbr, if_addr->af, if_addr, 1);
}
LIST_REMOVE(if_addr, entry);
free(if_addr);
@@ -193,61 +236,100 @@ if_addr_del(struct kaddr *ka)
}
int
-if_start(struct iface *iface)
+if_start(struct iface *iface, int af)
{
- struct in_addr addr;
+ struct iface_af *ia;
struct timeval now;
- log_debug("%s: %s", __func__, iface->name);
+ log_debug("%s: %s address-family %s", __func__, iface->name,
+ af_name(af));
- gettimeofday(&now, NULL);
- iface->uptime = now.tv_sec;
+ ia = iface_af_get(iface, af);
- inet_aton(AllRouters, &addr);
- if (if_join_group(iface, &addr))
- return (-1);
+ gettimeofday(&now, NULL);
+ ia->uptime = now.tv_sec;
+
+ switch (af) {
+ case AF_INET:
+ if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
+ return (-1);
+ break;
+ case AF_INET6:
+ if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
+ return (-1);
+ break;
+ default:
+ fatalx("if_start: unknown af");
+ }
- send_hello(HELLO_LINK, iface, NULL);
+ send_hello(HELLO_LINK, ia, NULL);
- evtimer_set(&iface->hello_timer, if_hello_timer, iface);
- if_start_hello_timer(iface);
+ evtimer_set(&ia->hello_timer, if_hello_timer, ia);
+ if_start_hello_timer(ia);
return (0);
}
int
-if_reset(struct iface *iface)
+if_reset(struct iface *iface, int af)
{
- struct in_addr addr;
+ struct iface_af *ia;
struct adj *adj;
- log_debug("%s: %s", __func__, iface->name);
+ log_debug("%s: %s address-family %s", __func__, iface->name,
+ af_name(af));
- while ((adj = LIST_FIRST(&iface->adj_list)) != NULL)
- adj_del(adj);
+ ia = iface_af_get(iface, af);
+ if_stop_hello_timer(ia);
- if_stop_hello_timer(iface);
+ while ((adj = LIST_FIRST(&ia->adj_list)) != NULL)
+ adj_del(adj);
/* try to cleanup */
- if (global.ldp_disc_socket != -1) {
- inet_aton(AllRouters, &addr);
- if_leave_group(iface, &addr);
+ switch (af) {
+ case AF_INET:
+ if (global.ipv4.ldp_disc_socket != -1)
+ if_leave_ipv4_group(iface, &global.mcast_addr_v4);
+ break;
+ case AF_INET6:
+ if (global.ipv6.ldp_disc_socket != -1)
+ if_leave_ipv6_group(iface, &global.mcast_addr_v6);
+ break;
+ default:
+ fatalx("if_start: unknown af");
}
return (0);
}
-int
-if_update(struct iface *iface)
+void
+if_update_af(struct iface_af *ia, int link_ok)
{
- int link_ok, addr_ok = 0, socket_ok, rtr_id_ok;
- int ret;
-
- link_ok = (iface->flags & IFF_UP) &&
- LINK_STATE_IS_UP(iface->linkstate);
+ int addr_ok = 0, socket_ok, rtr_id_ok;
+ struct if_addr *if_addr;
- addr_ok = !LIST_EMPTY(&iface->addr_list);
+ switch (ia->af) {
+ case AF_INET:
+ /*
+ * NOTE: for LDPv4, each interface should have at least one
+ * valid IP address otherwise they can not be enabled.
+ */
+ LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
+ if (if_addr->af == AF_INET) {
+ addr_ok = 1;
+ break;
+ }
+ }
+ break;
+ case AF_INET6:
+ /* for IPv6 the link-local address is enough. */
+ if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
+ addr_ok = 1;
+ break;
+ default:
+ fatalx("if_update_af: unknown af");
+ }
- if (global.ldp_disc_socket != -1)
+ if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
socket_ok = 1;
else
socket_ok = 0;
@@ -257,31 +339,43 @@ if_update(struct iface *iface)
else
rtr_id_ok = 0;
- if (iface->state == IF_STA_DOWN) {
- if (!link_ok || !addr_ok || !socket_ok || !rtr_id_ok)
- return (0);
-
+ if (ia->state == IF_STA_DOWN) {
+ if (!ia->enabled || !link_ok || !addr_ok || !socket_ok ||
+ !rtr_id_ok)
+ return;
- iface->state = IF_STA_ACTIVE;
- ret = if_start(iface);
- } else {
- if (link_ok && addr_ok && socket_ok && rtr_id_ok)
- return (0);
+ ia->state = IF_STA_ACTIVE;
+ if_start(ia->iface, ia->af);
+ } else if (ia->state == IF_STA_ACTIVE) {
+ if (ia->enabled && link_ok && addr_ok && socket_ok && rtr_id_ok)
+ return;
- iface->state = IF_STA_DOWN;
- ret = if_reset(iface);
+ ia->state = IF_STA_DOWN;
+ if_reset(ia->iface, ia->af);
}
+}
- return (ret);
+void
+if_update(struct iface *iface, int af)
+{
+ int link_ok;
+
+ link_ok = (iface->flags & IFF_UP) &&
+ LINK_STATE_IS_UP(iface->linkstate);
+
+ if (af == AF_INET || af == AF_UNSPEC)
+ if_update_af(&iface->ipv4, link_ok);
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ if_update_af(&iface->ipv6, link_ok);
}
void
-if_update_all(void)
+if_update_all(int af)
{
struct iface *iface;
LIST_FOREACH(iface, &leconf->iface_list, entry)
- if_update(iface);
+ if_update(iface, af);
}
/* timers */
@@ -289,78 +383,89 @@ if_update_all(void)
void
if_hello_timer(int fd, short event, void *arg)
{
- struct iface *iface = arg;
+ struct iface_af *ia = arg;
- send_hello(HELLO_LINK, iface, NULL);
- if_start_hello_timer(iface);
+ send_hello(HELLO_LINK, ia, NULL);
+ if_start_hello_timer(ia);
}
void
-if_start_hello_timer(struct iface *iface)
+if_start_hello_timer(struct iface_af *ia)
{
struct timeval tv;
timerclear(&tv);
- tv.tv_sec = iface->hello_interval;
- if (evtimer_add(&iface->hello_timer, &tv) == -1)
+ tv.tv_sec = ia->hello_interval;
+ if (evtimer_add(&ia->hello_timer, &tv) == -1)
fatal(__func__);
}
void
-if_stop_hello_timer(struct iface *iface)
+if_stop_hello_timer(struct iface_af *ia)
{
- if (evtimer_pending(&iface->hello_timer, NULL) &&
- evtimer_del(&iface->hello_timer) == -1)
+ if (evtimer_pending(&ia->hello_timer, NULL) &&
+ evtimer_del(&ia->hello_timer) == -1)
fatal(__func__);
}
struct ctl_iface *
-if_to_ctl(struct iface *iface)
+if_to_ctl(struct iface_af *ia)
{
static struct ctl_iface ictl;
struct timeval now;
struct adj *adj;
- memcpy(ictl.name, iface->name, sizeof(ictl.name));
- ictl.ifindex = iface->ifindex;
- ictl.state = iface->state;
- ictl.hello_holdtime = iface->hello_holdtime;
- ictl.hello_interval = iface->hello_interval;
- ictl.flags = iface->flags;
- ictl.type = iface->type;
- ictl.linkstate = iface->linkstate;
- ictl.if_type = iface->if_type;
+ ictl.af = ia->af;
+ memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
+ ictl.ifindex = ia->iface->ifindex;
+ ictl.state = ia->state;
+ ictl.flags = ia->iface->flags;
+ ictl.linkstate = ia->iface->linkstate;
+ ictl.type = ia->iface->type;
+ ictl.if_type = ia->iface->if_type;
+ ictl.hello_holdtime = ia->hello_holdtime;
+ ictl.hello_interval = ia->hello_interval;
gettimeofday(&now, NULL);
- if (iface->state != IF_STA_DOWN &&
- iface->uptime != 0) {
- ictl.uptime = now.tv_sec - iface->uptime;
+ if (ia->state != IF_STA_DOWN &&
+ ia->uptime != 0) {
+ ictl.uptime = now.tv_sec - ia->uptime;
} else
ictl.uptime = 0;
ictl.adj_cnt = 0;
- LIST_FOREACH(adj, &iface->adj_list, iface_entry)
+ LIST_FOREACH(adj, &ia->adj_list, ia_entry)
ictl.adj_cnt++;
return (&ictl);
}
-/* misc */
+/* multicast membership sockopts */
+in_addr_t
+if_get_ipv4_addr(struct iface *iface)
+{
+ struct if_addr *if_addr;
+
+ LIST_FOREACH(if_addr, &iface->addr_list, entry)
+ if (if_addr->af == AF_INET)
+ return (if_addr->addr.v4.s_addr);
+
+ return (INADDR_ANY);
+}
+
int
-if_join_group(struct iface *iface, struct in_addr *addr)
+if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
{
struct ip_mreq mreq;
- struct if_addr *if_addr;
log_debug("%s: interface %s addr %s", __func__, iface->name,
inet_ntoa(*addr));
- if_addr = LIST_FIRST(&iface->addr_list);
mreq.imr_multiaddr = *addr;
- mreq.imr_interface = if_addr->addr;
+ mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
- if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
- (void *)&mreq, sizeof(mreq)) < 0) {
+ if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
+ IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
__func__, iface->name, inet_ntoa(*addr));
return (-1);
@@ -369,23 +474,18 @@ if_join_group(struct iface *iface, struct in_addr *addr)
}
int
-if_leave_group(struct iface *iface, struct in_addr *addr)
+if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
{
struct ip_mreq mreq;
- struct if_addr *if_addr;
log_debug("%s: interface %s addr %s", __func__, iface->name,
inet_ntoa(*addr));
- if_addr = LIST_FIRST(&iface->addr_list);
- if (!if_addr)
- return (0);
-
mreq.imr_multiaddr = *addr;
- mreq.imr_interface = if_addr->addr;
+ mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
- if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
- (void *)&mreq, sizeof(mreq)) < 0) {
+ if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
+ IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
"address %s", __func__, iface->name, inet_ntoa(*addr));
return (-1);
@@ -393,3 +493,45 @@ if_leave_group(struct iface *iface, struct in_addr *addr)
return (0);
}
+
+int
+if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
+{
+ struct ipv6_mreq mreq;
+
+ log_debug("%s: interface %s addr %s", __func__, iface->name,
+ log_in6addr(addr));
+
+ mreq.ipv6mr_multiaddr = *addr;
+ mreq.ipv6mr_interface = iface->ifindex;
+
+ if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
+ IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) {
+ log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
+ __func__, iface->name, log_in6addr(addr));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
+{
+ struct ipv6_mreq mreq;
+
+ log_debug("%s: interface %s addr %s", __func__, iface->name,
+ log_in6addr(addr));
+
+ mreq.ipv6mr_multiaddr = *addr;
+ mreq.ipv6mr_interface = iface->ifindex;
+
+ if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
+ IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) {
+ log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
+ __func__, iface->name, log_in6addr(addr));
+ return (-1);
+ }
+
+ return (0);
+}
diff --git a/usr.sbin/ldpd/kroute.c b/usr.sbin/ldpd/kroute.c
index e765ea0be14..bf4adb43415 100644
--- a/usr.sbin/ldpd/kroute.c
+++ b/usr.sbin/ldpd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.56 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: kroute.c,v 1.57 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -67,7 +67,8 @@ struct kroute_priority {
struct kroute_prefix {
RB_ENTRY(kroute_prefix) entry;
- struct in_addr prefix;
+ int af;
+ union ldpd_addr prefix;
uint8_t prefixlen;
TAILQ_HEAD(plist, kroute_priority) priorities;
};
@@ -84,15 +85,17 @@ struct kif_node {
struct kpw *kpw;
};
-void kr_redist_remove(struct kroute *);
-int kr_redist_eval(struct kroute *);
-void kr_redistribute(struct kroute_prefix *);
-int kroute_compare(struct kroute_prefix *, struct kroute_prefix *);
+void kr_redist_remove(struct kroute *);
+int kr_redist_eval(struct kroute *);
+void kr_redistribute(struct kroute_prefix *);
+int kroute_compare(struct kroute_prefix *,
+ struct kroute_prefix *);
+
+struct kroute_prefix *kroute_find_prefix(int, union ldpd_addr *, uint8_t);
+struct kroute_priority *kroute_find_prio(struct kroute_prefix *, uint8_t);
+struct kroute_node *kroute_find_gw(struct kroute_priority *,
+ union ldpd_addr *);
-struct kroute_prefix *kroute_find(in_addr_t, uint8_t);
-struct kroute_priority *kroute_find_prio(in_addr_t, uint8_t, uint8_t);
-struct kroute_node *kroute_find_gw(in_addr_t, uint8_t, uint8_t,
- struct in_addr);
int kroute_insert(struct kroute *);
int kroute_uninstall(struct kroute_node *);
int kroute_remove(struct kroute *);
@@ -105,23 +108,27 @@ int kif_remove(struct kif_node *);
struct kif_node *kif_update(unsigned short, int, struct if_data *,
struct sockaddr_dl *, int *);
-struct kroute_priority *kroute_match(in_addr_t);
+struct kroute_priority *kroute_match(int, union ldpd_addr *);
uint8_t prefixlen_classful(in_addr_t);
void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
void if_change(unsigned short, int, struct if_data *,
struct sockaddr_dl *);
-void if_newaddr(unsigned short, struct sockaddr_in *,
- struct sockaddr_in *, struct sockaddr_in *);
-void if_deladdr(unsigned short, struct sockaddr_in *,
- struct sockaddr_in *, struct sockaddr_in *);
+void if_newaddr(unsigned short, struct sockaddr *, struct sockaddr *,
+ struct sockaddr *);
+void if_deladdr(unsigned short, struct sockaddr *, struct sockaddr *,
+ struct sockaddr *);
void if_announce(void *);
-int send_rtmsg(int, int, struct kroute *, uint32_t);
+int send_rtmsg(int, int, struct kroute *, int);
+int send_rtmsg_v4(int, int, struct kroute *, int);
+int send_rtmsg_v6(int, int, struct kroute *, int);
int dispatch_rtmsg(void);
int fetchtable(void);
int fetchifs(void);
int rtmsg_process(char *, size_t);
+int rtmsg_process_route(struct rt_msghdr *,
+ struct sockaddr *[RTAX_MAX]);
RB_HEAD(kroute_tree, kroute_prefix) krt = RB_INITIALIZER(&krt);
RB_PROTOTYPE(kroute_tree, kroute_prefix, entry, kroute_compare)
@@ -219,55 +226,72 @@ kif_redistribute(const char *ifname)
}
int
-kr_change(struct kroute *kroute)
+kr_change(struct kroute *kr)
{
+ struct kroute_prefix *kp;
+ struct kroute_priority *kprio;
struct kroute_node *kn;
int action = RTM_ADD;
- char buf[16];
- kn = kroute_find_gw(kroute->prefix.s_addr, kroute->prefixlen,
- RTP_ANY, kroute->nexthop);
- if (kn == NULL) {
- log_warnx("%s: lost FEC %s/%d nexthop %s", __func__,
- inet_ntoa(kroute->prefix), kroute->prefixlen,
- inet_ntop(AF_INET, &kroute->nexthop, buf, sizeof(buf)));
- return (-1);
- }
+ kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen);
+ if (kp == NULL)
+ goto miss;
+
+ kprio = kroute_find_prio(kp, RTP_ANY);
+ if (kprio == NULL)
+ goto miss;
+
+ kn = kroute_find_gw(kprio, &kr->nexthop);
+ if (kn == NULL)
+ goto miss;
if (kn->r.flags & F_LDPD_INSERTED)
action = RTM_CHANGE;
- kn->r.local_label = kroute->local_label;
- kn->r.remote_label = kroute->remote_label;
+ kn->r.local_label = kr->local_label;
+ kn->r.remote_label = kr->remote_label;
kn->r.flags = kn->r.flags | F_LDPD_INSERTED;
/* send update */
if (send_rtmsg(kr_state.fd, action, &kn->r, AF_MPLS) == -1)
return (-1);
- if (kn->r.nexthop.s_addr != INADDR_ANY &&
+ if (ldp_addrisset(kn->r.af, &kn->r.nexthop) &&
kn->r.remote_label != NO_LABEL) {
if (send_rtmsg(kr_state.fd, RTM_CHANGE, &kn->r, AF_INET) == -1)
return (-1);
}
return (0);
+
+miss:
+ log_warnx("%s: lost FEC %s/%d nexthop %s", __func__,
+ log_addr(kr->af, &kr->prefix), kr->prefixlen,
+ log_addr(kr->af, &kr->nexthop));
+ return (-1);
}
int
-kr_delete(struct kroute *kroute)
+kr_delete(struct kroute *kr)
{
+ struct kroute_prefix *kp;
+ struct kroute_priority *kprio;
struct kroute_node *kn;
int update = 0;
- kn = kroute_find_gw(kroute->prefix.s_addr, kroute->prefixlen,
- RTP_ANY, kroute->nexthop);
+ kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen);
+ if (kp == NULL)
+ return (0);
+ kprio = kroute_find_prio(kp, RTP_ANY);
+ if (kprio == NULL)
+ return (0);
+ kn = kroute_find_gw(kprio, &kr->nexthop);
if (kn == NULL)
return (0);
if (!(kn->r.flags & F_LDPD_INSERTED))
return (0);
- if (kn->r.nexthop.s_addr != INADDR_ANY &&
+ if (ldp_addrisset(kn->r.af, &kn->r.nexthop) &&
kn->r.remote_label != NO_LABEL)
update = 1;
@@ -318,7 +342,7 @@ kr_fib_couple(void)
send_rtmsg(kr_state.fd, RTM_ADD, &kn->r, AF_MPLS);
- if (kn->r.nexthop.s_addr != INADDR_ANY &&
+ if (ldp_addrisset(kn->r.af, &kn->r.nexthop) &&
kn->r.remote_label != NO_LABEL) {
send_rtmsg(kr_state.fd, RTM_CHANGE,
&kn->r, AF_INET);
@@ -357,7 +381,7 @@ kr_fib_decouple(void)
send_rtmsg(kr_state.fd, RTM_DELETE,
&kn->r, AF_MPLS);
- if (kn->r.nexthop.s_addr != INADDR_ANY &&
+ if (ldp_addrisset(kn->r.af, &kn->r.nexthop) &&
kn->r.remote_label != NO_LABEL) {
rl = kn->r.remote_label;
kn->r.remote_label = NO_LABEL;
@@ -377,22 +401,36 @@ kr_fib_decouple(void)
}
void
-kr_change_egress_label(int was_implicit)
+kr_change_egress_label(int af, int was_implicit)
{
struct kroute_prefix *kp;
struct kroute_priority *kprio;
struct kroute_node *kn;
RB_FOREACH(kp, kroute_tree, &krt) {
+ if (kp->af != af)
+ continue;
+
TAILQ_FOREACH(kprio, &kp->priorities, entry) {
TAILQ_FOREACH(kn, &kprio->nexthops, entry) {
if (kn->r.local_label > MPLS_LABEL_RESERVED_MAX)
continue;
- if (!was_implicit)
+ if (!was_implicit) {
kn->r.local_label = MPLS_LABEL_IMPLNULL;
- else
+ continue;
+ }
+
+ switch (kn->r.af) {
+ case AF_INET:
kn->r.local_label = MPLS_LABEL_IPV4NULL;
+ break;
+ case AF_INET6:
+ kn->r.local_label = MPLS_LABEL_IPV6NULL;
+ break;
+ default:
+ break;
+ }
}
}
}
@@ -413,7 +451,7 @@ kr_show_route(struct imsg *imsg)
struct kroute_priority *kprio;
struct kroute_node *kn;
int flags;
- struct in_addr addr;
+ struct kroute kr;
switch (imsg->hdr.type) {
case IMSG_CTL_KROUTE:
@@ -426,22 +464,25 @@ kr_show_route(struct imsg *imsg)
RB_FOREACH(kp, kroute_tree, &krt)
TAILQ_FOREACH(kprio, &kp->priorities, entry)
TAILQ_FOREACH(kn, &kprio->nexthops, entry) {
- if (!flags || kn->r.flags & flags)
- main_imsg_compose_ldpe(
- IMSG_CTL_KROUTE,
- imsg->hdr.pid,
- &kn->r, sizeof(kn->r));
+ if (flags && !(kn->r.flags & flags))
+ continue;
+
+ main_imsg_compose_ldpe(IMSG_CTL_KROUTE,
+ imsg->hdr.pid, &kn->r,
+ sizeof(kn->r));
}
break;
case IMSG_CTL_KROUTE_ADDR:
- if (imsg->hdr.len != IMSG_HEADER_SIZE +
- sizeof(struct in_addr)) {
+ if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
log_warnx("%s: wrong imsg len", __func__);
return;
}
- memcpy(&addr, imsg->data, sizeof(addr));
+ memcpy(&kr, imsg->data, sizeof(kr));
+
+ kprio = kroute_match(kr.af, &kr.prefix);
+ if (kprio == NULL)
+ break;
- kprio = kroute_match(addr.s_addr);
TAILQ_FOREACH(kn, &kprio->nexthops, entry)
main_imsg_compose_ldpe(IMSG_CTL_KROUTE, imsg->hdr.pid,
&kn->r, sizeof(kn->r));
@@ -482,8 +523,6 @@ kr_redist_remove(struct kroute *kr)
int
kr_redist_eval(struct kroute *kr)
{
- uint32_t a;
-
/* was the route redistributed? */
if (kr->flags & F_REDISTRIBUTED)
goto dont_redistribute;
@@ -492,22 +531,34 @@ kr_redist_eval(struct kroute *kr)
if (kr->flags & F_DYNAMIC)
goto dont_redistribute;
- /*
- * We consider the loopback net, default route, multicast and
- * experimental addresses as not redistributable.
- */
- a = ntohl(kr->prefix.s_addr);
- if (IN_MULTICAST(a) || IN_BADCLASS(a) ||
- (kr->prefixlen == 0) ||
- (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
+ /* filter-out non-redistributable addresses */
+ if (bad_addr(kr->af, &kr->prefix) ||
+ (kr->af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr->prefix.v6)))
+ goto dont_redistribute;
+
+ /* do not redistribute the default route */
+ if (kr->prefixlen == 0)
goto dont_redistribute;
+
/*
* Consider networks with nexthop loopback as not redistributable
* unless it is a reject or blackhole route.
*/
- if (kr->nexthop.s_addr == htonl(INADDR_LOOPBACK) &&
- !(kr->flags & (F_BLACKHOLE|F_REJECT)))
- goto dont_redistribute;
+ switch (kr->af) {
+ case AF_INET:
+ if (kr->nexthop.v4.s_addr == htonl(INADDR_LOOPBACK) &&
+ !(kr->flags & (F_BLACKHOLE|F_REJECT)))
+ goto dont_redistribute;
+ break;
+ case AF_INET6:
+ if (IN6_IS_ADDR_LOOPBACK(&kr->nexthop.v6) &&
+ !(kr->flags & (F_BLACKHOLE|F_REJECT)))
+ goto dont_redistribute;
+ break;
+ default:
+ log_debug("%s: unexpected address-family", __func__);
+ break;
+ }
/* prefix should be redistributed */
kr->flags |= F_REDISTRIBUTED;
@@ -539,10 +590,17 @@ kr_redistribute(struct kroute_prefix *kp)
int
kroute_compare(struct kroute_prefix *a, struct kroute_prefix *b)
{
- if (ntohl(a->prefix.s_addr) < ntohl(b->prefix.s_addr))
+ int addrcmp;
+
+ if (a->af < b->af)
return (-1);
- if (ntohl(a->prefix.s_addr) > ntohl(b->prefix.s_addr))
+ if (a->af > b->af)
return (1);
+
+ addrcmp = ldp_addrcmp(a->af, &a->prefix, &b->prefix);
+ if (addrcmp != 0)
+ return (addrcmp);
+
if (a->prefixlen < b->prefixlen)
return (-1);
if (a->prefixlen > b->prefixlen)
@@ -553,25 +611,22 @@ kroute_compare(struct kroute_prefix *a, struct kroute_prefix *b)
/* tree management */
struct kroute_prefix *
-kroute_find(in_addr_t prefix, uint8_t prefixlen)
+kroute_find_prefix(int af, union ldpd_addr *prefix, uint8_t prefixlen)
{
struct kroute_prefix s;
- s.prefix.s_addr = prefix;
+ s.af = af;
+ s.prefix = *prefix;
s.prefixlen = prefixlen;
return (RB_FIND(kroute_tree, &krt, &s));
}
struct kroute_priority *
-kroute_find_prio(in_addr_t prefix, uint8_t prefixlen, uint8_t prio)
+kroute_find_prio(struct kroute_prefix *kp, uint8_t prio)
{
- struct kroute_prefix *kp;
struct kroute_priority *kprio;
- if ((kp = kroute_find(prefix, prefixlen)) == NULL)
- return (NULL);
-
/* RTP_ANY here picks the lowest priority node */
if (prio == RTP_ANY)
return (TAILQ_FIRST(&kp->priorities));
@@ -584,17 +639,12 @@ kroute_find_prio(in_addr_t prefix, uint8_t prefixlen, uint8_t prio)
}
struct kroute_node *
-kroute_find_gw(in_addr_t prefix, uint8_t prefixlen, uint8_t prio,
- struct in_addr nh)
+kroute_find_gw(struct kroute_priority *kprio, union ldpd_addr *nh)
{
- struct kroute_priority *kprio;
struct kroute_node *kn;
- if ((kprio = kroute_find_prio(prefix, prefixlen, prio)) == NULL)
- return (NULL);
-
TAILQ_FOREACH(kn, &kprio->nexthops, entry)
- if (kn->r.nexthop.s_addr == nh.s_addr)
+ if (ldp_addrcmp(kprio->kp->af, &kn->r.nexthop, nh) == 0)
return (kn);
return (NULL);
@@ -604,24 +654,24 @@ int
kroute_insert(struct kroute *kr)
{
struct kroute_prefix *kp;
- struct kroute_priority *kprio, *tmp = NULL;
+ struct kroute_priority *kprio, *tmp;
struct kroute_node *kn;
- kp = kroute_find(kr->prefix.s_addr, kr->prefixlen);
+ kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen);
if (kp == NULL) {
- kp = calloc(1, sizeof(struct kroute_prefix));
+ kp = calloc(1, sizeof((*kp)));
if (kp == NULL)
fatal(__func__);
+ kp->af = kr->af;
kp->prefix = kr->prefix;
kp->prefixlen = kr->prefixlen;
TAILQ_INIT(&kp->priorities);
RB_INSERT(kroute_tree, &krt, kp);
}
- kprio = kroute_find_prio(kr->prefix.s_addr, kr->prefixlen,
- kr->priority);
+ kprio = kroute_find_prio(kp, kr->priority);
if (kprio == NULL) {
- kprio = calloc(1, sizeof(struct kroute_priority));
+ kprio = calloc(1, sizeof(*kprio));
if (kprio == NULL)
fatal(__func__);
kprio->kp = kp;
@@ -629,20 +679,18 @@ kroute_insert(struct kroute *kr)
TAILQ_INIT(&kprio->nexthops);
/* lower priorities first */
- TAILQ_FOREACH(tmp, &kp->priorities, entry) {
- if (tmp->priority > kr->priority) {
- TAILQ_INSERT_BEFORE(tmp, kprio, entry);
- goto done;
- }
- }
- TAILQ_INSERT_TAIL(&kp->priorities, kprio, entry);
+ TAILQ_FOREACH(tmp, &kp->priorities, entry)
+ if (tmp->priority > kprio->priority)
+ break;
+ if (tmp)
+ TAILQ_INSERT_BEFORE(tmp, kprio, entry);
+ else
+ TAILQ_INSERT_TAIL(&kp->priorities, kprio, entry);
}
-done:
- kn = kroute_find_gw(kr->prefix.s_addr, kr->prefixlen, kr->priority,
- kr->nexthop);
+ kn = kroute_find_gw(kprio, &kr->nexthop);
if (kn == NULL) {
- kn = calloc(1, sizeof(struct kroute_node));
+ kn = calloc(1, sizeof(*kn));
if (kn == NULL)
fatal(__func__);
kn->kprio = kprio;
@@ -673,15 +721,15 @@ kroute_remove(struct kroute *kr)
struct kroute_priority *kprio;
struct kroute_node *kn;
- kn = kroute_find_gw(kr->prefix.s_addr, kr->prefixlen, kr->priority,
- kr->nexthop);
- if (kn == NULL) {
- log_warnx("%s failed to find %s/%u", __func__,
- inet_ntoa(kr->prefix), kr->prefixlen);
- return (-1);
- }
- kprio = kn->kprio;
- kp = kprio->kp;
+ kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen);
+ if (kp == NULL)
+ goto notfound;
+ kprio = kroute_find_prio(kp, kr->priority);
+ if (kprio == NULL)
+ goto notfound;
+ kn = kroute_find_gw(kprio, &kr->nexthop);
+ if (kn == NULL)
+ goto notfound;
kr_redist_remove(&kn->r);
kroute_uninstall(kn);
@@ -697,7 +745,7 @@ kroute_remove(struct kroute *kr)
if (TAILQ_EMPTY(&kp->priorities)) {
if (RB_REMOVE(kroute_tree, &krt, kp) == NULL) {
log_warnx("%s failed for %s/%u", __func__,
- inet_ntoa(kp->prefix), kp->prefixlen);
+ log_addr(kr->af, &kr->prefix), kp->prefixlen);
return (-1);
}
free(kp);
@@ -705,6 +753,11 @@ kroute_remove(struct kroute *kr)
kr_redistribute(kp);
return (0);
+
+notfound:
+ log_warnx("%s failed to find %s/%u", __func__,
+ log_addr(kr->af, &kr->prefix), kr->prefixlen);
+ return (-1);
}
void
@@ -838,20 +891,36 @@ kif_update(unsigned short ifindex, int flags, struct if_data *ifd,
}
struct kroute_priority *
-kroute_match(in_addr_t key)
+kroute_match(int af, union ldpd_addr *key)
{
- int i;
+ int i, maxprefixlen;
+ struct kroute_prefix *kp;
struct kroute_priority *kprio;
+ union ldpd_addr addr;
- /* we will never match the default route */
- for (i = 32; i > 0; i--)
- if ((kprio = kroute_find_prio(key & prefixlen2mask(i), i,
- RTP_ANY)) != NULL)
- return (kprio);
+ switch (af) {
+ case AF_INET:
+ maxprefixlen = 32;
+ break;
+ case AF_INET6:
+ maxprefixlen = 128;
+ break;
+ default:
+ log_warnx("%s: unknown af", __func__);
+ return (NULL);
+ }
+
+ for (i = maxprefixlen; i >= 0; i--) {
+ ldp_applymask(af, &addr, key, i);
+
+ kp = kroute_find_prefix(af, &addr, i);
+ if (kp == NULL)
+ continue;
- /* if we don't have a match yet, try to find a default route */
- if ((kprio = kroute_find_prio(0, 0, RTP_ANY)) != NULL)
- return (kprio);
+ kprio = kroute_find_prio(kp, RTP_ANY);
+ if (kprio != NULL)
+ return (kprio);
+ }
return (NULL);
}
@@ -924,38 +993,66 @@ if_change(unsigned short ifindex, int flags, struct if_data *ifd,
}
void
-if_newaddr(unsigned short ifindex, struct sockaddr_in *ifa,
- struct sockaddr_in *mask, struct sockaddr_in *brd)
+if_newaddr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask,
+ struct sockaddr *brd)
{
- struct kif_node *kif;
- struct kif_addr *ka;
- uint32_t a;
+ struct kif_node *kif;
+ struct sockaddr_in *ifa4, *mask4, *brd4;
+ struct sockaddr_in6 *ifa6, *mask6, *brd6;
+ struct kif_addr *ka;
- if (ifa == NULL || ifa->sin_family != AF_INET)
+ if (ifa == NULL)
return;
if ((kif = kif_find(ifindex)) == NULL) {
log_warnx("%s: corresponding if %d not found", __func__,
ifindex);
return;
}
- a = ntohl(ifa->sin_addr.s_addr);
- if (IN_MULTICAST(a) || IN_BADCLASS(a) ||
- (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
+
+ switch (ifa->sa_family) {
+ case AF_INET:
+ ifa4 = (struct sockaddr_in *) ifa;
+ mask4 = (struct sockaddr_in *) mask;
+ brd4 = (struct sockaddr_in *) brd;
+
+ /* filter out unwanted addresses */
+ if (bad_addr_v4(ifa4->sin_addr))
+ return;
+
+ if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
+ fatal("if_newaddr");
+ ka->a.addr.v4 = ifa4->sin_addr;
+ if (mask4)
+ ka->a.prefixlen =
+ mask2prefixlen(mask4->sin_addr.s_addr);
+ if (brd4)
+ ka->a.dstbrd.v4 = brd4->sin_addr;
+ break;
+ case AF_INET6:
+ ifa6 = (struct sockaddr_in6 *) ifa;
+ mask6 = (struct sockaddr_in6 *) mask;
+ brd6 = (struct sockaddr_in6 *) brd;
+
+ /* We only care about link-local and global-scope. */
+ if (bad_addr_v6(&ifa6->sin6_addr))
+ return;
+
+ clearscope(&ifa6->sin6_addr);
+
+ if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
+ fatal("if_newaddr");
+ ka->a.addr.v6 = ifa6->sin6_addr;
+ if (mask6)
+ ka->a.prefixlen = mask2prefixlen6(mask6);
+ if (brd6)
+ ka->a.dstbrd.v6 = brd6->sin6_addr;
+ break;
+ default:
return;
+ }
- if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
- fatal(__func__);
ka->a.ifindex = ifindex;
- ka->a.addr = ifa->sin_addr;
- if (mask)
- ka->a.mask = mask->sin_addr;
- else
- ka->a.mask.s_addr = INADDR_NONE;
- if (brd)
- ka->a.dstbrd = brd->sin_addr;
- else
- ka->a.dstbrd.s_addr = INADDR_NONE;
-
+ ka->a.af = ifa->sa_family;
TAILQ_INSERT_TAIL(&kif->addrs, ka, entry);
/* notify ldpe about new address */
@@ -963,13 +1060,16 @@ if_newaddr(unsigned short ifindex, struct sockaddr_in *ifa,
}
void
-if_deladdr(unsigned short ifindex, struct sockaddr_in *ifa,
- struct sockaddr_in *mask, struct sockaddr_in *brd)
+if_deladdr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask,
+ struct sockaddr *brd)
{
- struct kif_node *kif;
- struct kif_addr *ka, *nka;
+ struct kif_node *kif;
+ struct sockaddr_in *ifa4, *mask4, *brd4;
+ struct sockaddr_in6 *ifa6, *mask6, *brd6;
+ struct kaddr k;
+ struct kif_addr *ka, *nka;
- if (ifa == NULL || ifa->sin_family != AF_INET)
+ if (ifa == NULL)
return;
if ((kif = kif_find(ifindex)) == NULL) {
log_warnx("%s: corresponding if %d not found", __func__,
@@ -977,10 +1077,51 @@ if_deladdr(unsigned short ifindex, struct sockaddr_in *ifa,
return;
}
+ memset(&k, 0, sizeof(k));
+ k.af = ifa->sa_family;
+ switch (ifa->sa_family) {
+ case AF_INET:
+ ifa4 = (struct sockaddr_in *) ifa;
+ mask4 = (struct sockaddr_in *) mask;
+ brd4 = (struct sockaddr_in *) brd;
+
+ /* filter out unwanted addresses */
+ if (bad_addr_v4(ifa4->sin_addr))
+ return;
+
+ k.addr.v4 = ifa4->sin_addr;
+ if (mask4)
+ k.prefixlen = mask2prefixlen(mask4->sin_addr.s_addr);
+ if (brd4)
+ k.dstbrd.v4 = brd4->sin_addr;
+ break;
+ case AF_INET6:
+ ifa6 = (struct sockaddr_in6 *) ifa;
+ mask6 = (struct sockaddr_in6 *) mask;
+ brd6 = (struct sockaddr_in6 *) brd;
+
+ /* We only care about link-local and global-scope. */
+ if (bad_addr_v6(&ifa6->sin6_addr))
+ return;
+
+ clearscope(&ifa6->sin6_addr);
+
+ k.addr.v6 = ifa6->sin6_addr;
+ if (mask6)
+ k.prefixlen = mask2prefixlen6(mask6);
+ if (brd6)
+ k.dstbrd.v6 = brd6->sin6_addr;
+ break;
+ default:
+ return;
+ }
+
for (ka = TAILQ_FIRST(&kif->addrs); ka != NULL; ka = nka) {
nka = TAILQ_NEXT(ka, entry);
- if (ka->a.addr.s_addr != ifa->sin_addr.s_addr)
+ if (ka->a.af != k.af ||
+ ka->a.prefixlen != k.prefixlen ||
+ ldp_addrcmp(ka->a.af, &ka->a.addr, &k.addr))
continue;
/* notify ldpe about removed address */
@@ -1016,7 +1157,20 @@ if_announce(void *msg)
/* rtsock */
int
-send_rtmsg(int fd, int action, struct kroute *kr, uint32_t family)
+send_rtmsg(int fd, int action, struct kroute *kr, int family)
+{
+ switch (kr->af) {
+ case AF_INET:
+ return (send_rtmsg_v4(fd, action, kr, family));
+ case AF_INET6:
+ return (send_rtmsg_v6(fd, action, kr, family));
+ default:
+ fatalx("send_rtmsg: unknown af");
+ }
+}
+
+int
+send_rtmsg_v4(int fd, int action, struct kroute *kr, int family)
{
struct iovec iov[5];
struct rt_msghdr hdr;
@@ -1066,7 +1220,7 @@ send_rtmsg(int fd, int action, struct kroute *kr, uint32_t family)
memset(&dst, 0, sizeof(dst));
dst.sin_len = sizeof(dst);
dst.sin_family = AF_INET;
- dst.sin_addr = kr->prefix;
+ dst.sin_addr = kr->prefix.v4;
/* adjust header */
hdr.rtm_addrs |= RTA_DST;
hdr.rtm_msglen += sizeof(dst);
@@ -1078,7 +1232,7 @@ send_rtmsg(int fd, int action, struct kroute *kr, uint32_t family)
memset(&nexthop, 0, sizeof(nexthop));
nexthop.sin_len = sizeof(nexthop);
nexthop.sin_family = AF_INET;
- nexthop.sin_addr = kr->nexthop;
+ nexthop.sin_addr = kr->nexthop.v4;
/* adjust header */
hdr.rtm_flags |= RTF_GATEWAY;
hdr.rtm_addrs |= RTA_GATEWAY;
@@ -1136,12 +1290,13 @@ retry:
goto retry;
} else if (hdr.rtm_type == RTM_DELETE) {
log_info("route %s/%u vanished before delete",
- inet_ntoa(kr->prefix), kr->prefixlen);
+ inet_ntoa(kr->prefix.v4), kr->prefixlen);
return (-1);
}
}
- log_warn("%s action %u, AF %d, prefix %s/%u", __func__,
- hdr.rtm_type, family, inet_ntoa(kr->prefix), kr->prefixlen);
+ log_warn("%s action %u, af %s, prefix %s/%u", __func__,
+ hdr.rtm_type, af_name(family), inet_ntoa(kr->prefix.v4),
+ kr->prefixlen);
return (-1);
}
@@ -1149,6 +1304,12 @@ retry:
}
int
+send_rtmsg_v6(int fd, int action, struct kroute *kr, int family)
+{
+ return (0);
+}
+
+int
fetchtable(void)
{
size_t len;
@@ -1159,7 +1320,7 @@ fetchtable(void)
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
- mib[3] = AF_INET;
+ mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
mib[6] = 0; /* rtableid */
@@ -1195,7 +1356,7 @@ fetchifs(void)
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
- mib[3] = AF_INET;
+ mib[3] = 0; /* wildcard */
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
@@ -1247,14 +1408,6 @@ rtmsg_process(char *buf, size_t len)
struct if_msghdr ifm;
struct ifa_msghdr *ifam;
struct sockaddr *sa, *rti_info[RTAX_MAX];
- struct sockaddr_in *sa_in;
- struct kroute_priority *kprio;
- struct kroute_node *kn;
- struct kroute kr;
- struct in_addr prefix, nexthop;
- uint8_t prefixlen, prio;
- int flags;
- unsigned short ifindex = 0;
size_t offset;
char *next;
@@ -1268,12 +1421,6 @@ rtmsg_process(char *buf, size_t len)
continue;
log_rtmsg(rtm->rtm_type);
- prefix.s_addr = 0;
- prefixlen = 0;
- nexthop.s_addr = 0;
- prio = 0;
- flags = 0;
-
sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
@@ -1292,9 +1439,6 @@ rtmsg_process(char *buf, size_t len)
rtm->rtm_pid != kr_state.pid)
continue;
- if ((sa = rti_info[RTAX_DST]) == NULL)
- continue;
-
/* Skip ARP/ND cache and broadcast routes. */
if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
continue;
@@ -1302,118 +1446,12 @@ rtmsg_process(char *buf, size_t len)
/* LDP should follow the IGP and ignore BGP routes */
if (rtm->rtm_priority == RTP_BGP)
continue;
- prio = rtm->rtm_priority;
-
- switch (sa->sa_family) {
- case AF_INET:
- prefix = ((struct sockaddr_in *)sa)->sin_addr;
- sa_in = (struct sockaddr_in *)
- rti_info[RTAX_NETMASK];
- if (sa_in != NULL) {
- if (sa_in->sin_len != 0)
- prefixlen = mask2prefixlen(
- sa_in->sin_addr.s_addr);
- } else if (rtm->rtm_flags & RTF_HOST)
- prefixlen = 32;
- else
- prefixlen =
- prefixlen_classful(prefix.s_addr);
- if (rtm->rtm_flags & RTF_STATIC)
- flags |= F_STATIC;
- if (rtm->rtm_flags & RTF_BLACKHOLE)
- flags |= F_BLACKHOLE;
- if (rtm->rtm_flags & RTF_REJECT)
- flags |= F_REJECT;
- if (rtm->rtm_flags & RTF_DYNAMIC)
- flags |= F_DYNAMIC;
- break;
- default:
- continue;
- }
-
- ifindex = rtm->rtm_index;
- if ((sa = rti_info[RTAX_GATEWAY]) != NULL) {
- switch (sa->sa_family) {
- case AF_INET:
- if (rtm->rtm_flags & RTF_CONNECTED) {
- flags |= F_CONNECTED;
- break;
- }
- nexthop = ((struct
- sockaddr_in *)sa)->sin_addr;
- break;
- case AF_LINK:
- /*
- * Traditional BSD connected routes have
- * a gateway of type AF_LINK.
- */
- flags |= F_CONNECTED;
- break;
- }
- }
- }
- switch (rtm->rtm_type) {
- case RTM_CHANGE:
- /*
- * The kernel doesn't allow RTM_CHANGE for multipath
- * routes. If we got this message we know that the
- * route has only one nexthop and we should remove
- * it before installing the same route with a new
- * nexthop.
- */
- if ((kprio = kroute_find_prio(prefix.s_addr,
- prefixlen, prio)) == NULL) {
- log_warnx("%s: route not found", __func__);
- return (-1);
- }
- kn = TAILQ_FIRST(&kprio->nexthops);
- if (kn && kroute_remove(&kn->r) == -1)
+ if (rtmsg_process_route(rtm, rti_info) == -1)
return (-1);
- break;
- default:
- break;
}
switch (rtm->rtm_type) {
- case RTM_ADD:
- case RTM_GET:
- case RTM_CHANGE:
- if (nexthop.s_addr == 0 && !(flags & F_CONNECTED)) {
- log_warnx("no nexthop for %s/%u",
- inet_ntoa(prefix), prefixlen);
- continue;
- }
-
- /* routes attached to loopback interfaces */
- if (prefix.s_addr == nexthop.s_addr)
- flags |= F_CONNECTED;
-
- if (kroute_find_gw(prefix.s_addr, prefixlen, prio,
- nexthop) != NULL)
- break;
-
- memset(&kr, 0, sizeof(kr));
- kr.prefix = prefix;
- kr.prefixlen = prefixlen;
- kr.nexthop = nexthop;
- kr.flags = flags;
- kr.ifindex = ifindex;
- kr.priority = prio;
- kr.local_label = NO_LABEL;
- kr.remote_label = NO_LABEL;
- kroute_insert(&kr);
- break;
- case RTM_DELETE:
- /* get the correct route */
- if ((kn = kroute_find_gw(prefix.s_addr, prefixlen,
- prio, nexthop)) == NULL) {
- log_warnx("%s: route not found", __func__);
- return (-1);
- }
- if (kroute_remove(&kn->r) == -1)
- return (-1);
- break;
case RTM_IFINFO:
memcpy(&ifm, next, sizeof(ifm));
if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
@@ -1426,9 +1464,9 @@ rtmsg_process(char *buf, size_t len)
break;
if_newaddr(ifam->ifam_index,
- (struct sockaddr_in *)rti_info[RTAX_IFA],
- (struct sockaddr_in *)rti_info[RTAX_NETMASK],
- (struct sockaddr_in *)rti_info[RTAX_BRD]);
+ (struct sockaddr *)rti_info[RTAX_IFA],
+ (struct sockaddr *)rti_info[RTAX_NETMASK],
+ (struct sockaddr *)rti_info[RTAX_BRD]);
break;
case RTM_DELADDR:
ifam = (struct ifa_msghdr *)rtm;
@@ -1437,9 +1475,9 @@ rtmsg_process(char *buf, size_t len)
break;
if_deladdr(ifam->ifam_index,
- (struct sockaddr_in *)rti_info[RTAX_IFA],
- (struct sockaddr_in *)rti_info[RTAX_NETMASK],
- (struct sockaddr_in *)rti_info[RTAX_BRD]);
+ (struct sockaddr *)rti_info[RTAX_IFA],
+ (struct sockaddr *)rti_info[RTAX_NETMASK],
+ (struct sockaddr *)rti_info[RTAX_BRD]);
break;
case RTM_IFANNOUNCE:
if_announce(next);
@@ -1454,6 +1492,134 @@ rtmsg_process(char *buf, size_t len)
}
int
+rtmsg_process_route(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX])
+{
+ struct sockaddr *sa;
+ struct sockaddr_in *sa_in;
+ struct sockaddr_in6 *sa_in6;
+ struct kroute kr;
+ struct kroute_prefix *kp;
+ struct kroute_priority *kprio;
+ struct kroute_node *kn;
+
+ if ((sa = rti_info[RTAX_DST]) == NULL)
+ return (-1);
+
+ memset(&kr, 0, sizeof(kr));
+ kr.af = sa->sa_family;
+ switch (kr.af) {
+ case AF_INET:
+ kr.prefix.v4 = ((struct sockaddr_in *)sa)->sin_addr;
+ sa_in = (struct sockaddr_in *) rti_info[RTAX_NETMASK];
+ if (sa_in != NULL && sa_in->sin_len != 0)
+ kr.prefixlen = mask2prefixlen(sa_in->sin_addr.s_addr);
+ else if (rtm->rtm_flags & RTF_HOST)
+ kr.prefixlen = 32;
+ else if (kr.prefix.v4.s_addr == INADDR_ANY)
+ kr.prefixlen = 0;
+ else
+ kr.prefixlen = prefixlen_classful(kr.prefix.v4.s_addr);
+ break;
+ case AF_INET6:
+ kr.prefix.v6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
+ sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
+ if (sa_in6 != NULL && sa_in6->sin6_len != 0)
+ kr.prefixlen = mask2prefixlen6(sa_in6);
+ else if (rtm->rtm_flags & RTF_HOST)
+ kr.prefixlen = 128;
+ else if (IN6_IS_ADDR_UNSPECIFIED(&kr.prefix.v6))
+ kr.prefixlen = 0;
+ else
+ fatalx("in6 net addr without netmask");
+ break;
+ default:
+ return (0);
+ }
+ kr.ifindex = rtm->rtm_index;
+ if ((sa = rti_info[RTAX_GATEWAY]) != NULL) {
+ switch (sa->sa_family) {
+ case AF_INET:
+ kr.nexthop.v4 = ((struct sockaddr_in *)sa)->sin_addr;
+ break;
+ case AF_INET6:
+ sa_in6 = (struct sockaddr_in6 *)sa;
+ recoverscope(sa_in6);
+ kr.nexthop.v6 = sa_in6->sin6_addr;
+ if (sa_in6->sin6_scope_id)
+ kr.ifindex = sa_in6->sin6_scope_id;
+ break;
+ case AF_LINK:
+ kr.flags |= F_CONNECTED;
+ break;
+ }
+ }
+
+ if (rtm->rtm_flags & RTF_STATIC)
+ kr.flags |= F_STATIC;
+ if (rtm->rtm_flags & RTF_BLACKHOLE)
+ kr.flags |= F_BLACKHOLE;
+ if (rtm->rtm_flags & RTF_REJECT)
+ kr.flags |= F_REJECT;
+ if (rtm->rtm_flags & RTF_DYNAMIC)
+ kr.flags |= F_DYNAMIC;
+ /* routes attached to connected or loopback interfaces */
+ if (rtm->rtm_flags & RTF_CONNECTED ||
+ ldp_addrcmp(kr.af, &kr.prefix, &kr.nexthop) == 0)
+ kr.flags |= F_CONNECTED;
+ kr.priority = rtm->rtm_priority;
+
+ if (rtm->rtm_type == RTM_CHANGE) {
+ /*
+ * The kernel doesn't allow RTM_CHANGE for multipath routes.
+ * If we got this message we know that the route has only one
+ * nexthop and we should remove it before installing the same
+ * route with the new nexthop.
+ */
+ kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen);
+ if (kp) {
+ kprio = kroute_find_prio(kp, kr.priority);
+ if (kprio) {
+ kn = TAILQ_FIRST(&kprio->nexthops);
+ if (kn)
+ kroute_remove(&kn->r);
+ }
+ }
+ }
+
+ kn = NULL;
+ kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen);
+ if (kp) {
+ kprio = kroute_find_prio(kp, kr.priority);
+ if (kprio)
+ kn = kroute_find_gw(kprio, &kr.nexthop);
+ }
+
+ if (rtm->rtm_type == RTM_DELETE) {
+ if (kn == NULL)
+ return (0);
+ return (kroute_remove(&kr));
+ }
+
+ if (!ldp_addrisset(kr.af, &kr.nexthop) && !(kr.flags & F_CONNECTED)) {
+ log_warnx("%s: no nexthop for %s/%u", __func__,
+ log_addr(kr.af, &kr.prefix), kr.prefixlen);
+ return (-1);
+ }
+
+ if (kn != NULL) {
+ /* update route */
+ kn->r = kr;
+ kr_redistribute(kp);
+ } else {
+ kr.local_label = NO_LABEL;
+ kr.remote_label = NO_LABEL;
+ kroute_insert(&kr);
+ }
+
+ return (0);
+}
+
+int
kmpw_set(struct kpw *kpw)
{
struct kif_node *kif;
@@ -1497,7 +1663,6 @@ kmpw_unset(struct kpw *kpw)
int
kmpw_install(const char *ifname, struct kpw *kpw)
{
- struct sockaddr_in *sin;
struct ifreq ifr;
struct ifmpwreq imr;
@@ -1518,10 +1683,8 @@ kmpw_install(const char *ifname, struct kpw *kpw)
if (kpw->flags & F_PW_CWORD)
imr.imr_flags |= IMR_FLAG_CONTROLWORD;
- sin = (struct sockaddr_in *) &imr.imr_nexthop;
- sin->sin_family = AF_INET;
- sin->sin_addr = kpw->nexthop;
- sin->sin_len = sizeof(struct sockaddr_in);
+ memcpy(&imr.imr_nexthop, addr2sa(kpw->af, &kpw->nexthop, 0),
+ sizeof(imr.imr_nexthop));
imr.imr_lshim.shim_label = kpw->local_label;
imr.imr_rshim.shim_label = kpw->remote_label;
diff --git a/usr.sbin/ldpd/l2vpn.c b/usr.sbin/ldpd/l2vpn.c
index 91e60207be8..a1328f4cb4b 100644
--- a/usr.sbin/ldpd/l2vpn.c
+++ b/usr.sbin/ldpd/l2vpn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: l2vpn.c,v 1.13 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: l2vpn.c,v 1.14 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
@@ -164,7 +164,8 @@ l2vpn_pw_init(struct l2vpn_pw *pw)
l2vpn_pw_reset(pw);
l2vpn_pw_fec(pw, &fec);
- lde_kernel_insert(&fec, pw->lsr_id, 0, (void *)pw);
+ lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id,
+ 0, (void *)pw);
}
void
@@ -173,7 +174,7 @@ l2vpn_pw_exit(struct l2vpn_pw *pw)
struct fec fec;
l2vpn_pw_fec(pw, &fec);
- lde_kernel_remove(&fec, pw->lsr_id);
+ lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id);
}
void
@@ -225,9 +226,21 @@ l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
/* check for a working lsp to the nexthop */
memset(&fec, 0, sizeof(fec));
- fec.type = FEC_TYPE_IPV4;
- fec.u.ipv4.prefix = pw->lsr_id;
- fec.u.ipv4.prefixlen = 32;
+ switch (pw->af) {
+ case AF_INET:
+ fec.type = FEC_TYPE_IPV4;
+ fec.u.ipv4.prefix = pw->addr.v4;
+ fec.u.ipv4.prefixlen = 32;
+ break;
+ case AF_INET6:
+ fec.type = FEC_TYPE_IPV6;
+ fec.u.ipv6.prefix = pw->addr.v6;
+ fec.u.ipv6.prefixlen = 128;
+ break;
+ default:
+ fatalx("l2vpn_pw_ok: unknown af");
+ }
+
fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL || fn->local_label == NO_LABEL)
return (0);
@@ -328,7 +341,7 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
if (pw == NULL)
return;
- fnh = fec_nh_find(fn, ln->id);
+ fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id);
if (fnh == NULL)
return;
@@ -345,7 +358,7 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
}
void
-l2vpn_sync_pws(struct in_addr addr)
+l2vpn_sync_pws(int af, union ldpd_addr *addr)
{
struct l2vpn *l2vpn;
struct l2vpn_pw *pw;
@@ -355,14 +368,15 @@ l2vpn_sync_pws(struct in_addr addr)
LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) {
LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
- if (pw->lsr_id.s_addr != addr.s_addr)
+ if (af != pw->af || ldp_addrcmp(af, &pw->addr, addr))
continue;
l2vpn_pw_fec(pw, &fec);
fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL)
continue;
- fnh = fec_nh_find(fn, pw->lsr_id);
+ fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)
+ &pw->lsr_id);
if (fnh == NULL)
continue;
@@ -472,9 +486,9 @@ ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
{
struct tnbr *tnbr;
- tnbr = tnbr_find(leconf, pw->lsr_id);
+ tnbr = tnbr_find(leconf, pw->af, &pw->addr);
if (tnbr == NULL) {
- tnbr = tnbr_new(leconf, pw->lsr_id);
+ tnbr = tnbr_new(leconf, pw->af, &pw->addr);
tnbr_update(tnbr);
LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
}
@@ -487,7 +501,7 @@ ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
{
struct tnbr *tnbr;
- tnbr = tnbr_find(leconf, pw->lsr_id);
+ tnbr = tnbr_find(leconf, pw->af, &pw->addr);
if (tnbr) {
tnbr->pw_count--;
tnbr_check(tnbr);
diff --git a/usr.sbin/ldpd/labelmapping.c b/usr.sbin/ldpd/labelmapping.c
index 6706b4f4c0b..ed98c95c4bf 100644
--- a/usr.sbin/ldpd/labelmapping.c
+++ b/usr.sbin/ldpd/labelmapping.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: labelmapping.c,v 1.42 2016/05/23 18:51:52 renato Exp $ */
+/* $OpenBSD: labelmapping.c,v 1.43 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -90,7 +90,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
break;
case MAP_TYPE_PREFIX:
msg_size += FEC_ELM_PREFIX_MIN_LEN +
- PREFIX_SIZE(me->map.fec.ipv4.prefixlen);
+ PREFIX_SIZE(me->map.fec.prefix.prefixlen);
break;
case MAP_TYPE_PWID:
msg_size += FEC_PWID_ELM_MIN_LEN;
@@ -350,7 +350,32 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
int imsg_type = IMSG_NONE;
me->map.flags |= flags;
- if (me->map.type == MAP_TYPE_PWID) {
+ switch (me->map.type) {
+ case MAP_TYPE_PREFIX:
+ switch (me->map.fec.prefix.af) {
+ case AF_IPV4:
+ if (label == MPLS_LABEL_IPV6NULL) {
+ session_shutdown(nbr, S_BAD_TLV_VAL,
+ lm.msgid, lm.type);
+ goto err;
+ }
+ if (!nbr->v4_enabled)
+ goto next;
+ break;
+ case AF_IPV6:
+ if (label == MPLS_LABEL_IPV4NULL) {
+ session_shutdown(nbr, S_BAD_TLV_VAL,
+ lm.msgid, lm.type);
+ goto err;
+ }
+ if (!nbr->v6_enabled)
+ goto next;
+ break;
+ default:
+ fatalx("recv_labelmessage: unknown af");
+ }
+ break;
+ case MAP_TYPE_PWID:
if (label <= MPLS_LABEL_RESERVED_MAX) {
session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid,
lm.type);
@@ -358,6 +383,9 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
}
if (me->map.flags & F_MAP_PW_STATUS)
me->map.pw_status = pw_status;
+ break;
+ default:
+ break;
}
me->map.label = label;
if (me->map.flags & F_MAP_REQ_ID)
@@ -397,6 +425,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
sizeof(struct map));
+next:
TAILQ_REMOVE(&mh, me, entry);
free(me);
}
@@ -451,6 +480,7 @@ tlv_decode_label(struct nbr *nbr, struct ldp_msg *lm, char *buf,
if (*label > MPLS_LABEL_MAX ||
(*label <= MPLS_LABEL_RESERVED_MAX &&
*label != MPLS_LABEL_IPV4NULL &&
+ *label != MPLS_LABEL_IPV6NULL &&
*label != MPLS_LABEL_IMPLNULL)) {
session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid,
lm->type);
@@ -509,18 +539,18 @@ gen_fec_tlv(struct ibuf *buf, struct map *map)
ibuf_add(buf, &map->type, sizeof(map->type));
break;
case MAP_TYPE_PREFIX:
- len = PREFIX_SIZE(map->fec.ipv4.prefixlen);
+ len = PREFIX_SIZE(map->fec.prefix.prefixlen);
ft.length = htons(sizeof(map->type) + sizeof(family) +
- sizeof(map->fec.ipv4.prefixlen) + len);
+ sizeof(map->fec.prefix.prefixlen) + len);
ibuf_add(buf, &ft, sizeof(ft));
ibuf_add(buf, &map->type, sizeof(map->type));
- family = htons(AF_IPV4);
+ family = htons(map->fec.prefix.af);
ibuf_add(buf, &family, sizeof(family));
- ibuf_add(buf, &map->fec.ipv4.prefixlen,
- sizeof(map->fec.ipv4.prefixlen));
+ ibuf_add(buf, &map->fec.prefix.prefixlen,
+ sizeof(map->fec.prefix.prefixlen));
if (len)
- ibuf_add(buf, &map->fec.ipv4.prefix, len);
+ ibuf_add(buf, &map->fec.prefix.prefix, len);
break;
case MAP_TYPE_PWID:
if (map->flags & F_MAP_PW_ID)
@@ -566,7 +596,7 @@ int
tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf,
uint16_t len, struct map *map)
{
- uint16_t family, off = 0;
+ uint16_t off = 0;
uint8_t pw_len;
map->type = *buf;
@@ -590,31 +620,33 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf,
}
/* Address Family */
- memcpy(&family, buf + off, sizeof(family));
- off += sizeof(family);
-
- if (family != htons(AF_IPV4)) {
+ memcpy(&map->fec.prefix.af, buf + off,
+ sizeof(map->fec.prefix.af));
+ map->fec.prefix.af = ntohs(map->fec.prefix.af);
+ off += sizeof(map->fec.prefix.af);
+ if (map->fec.prefix.af != AF_IPV4 &&
+ map->fec.prefix.af != AF_IPV6) {
send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid,
lm->type);
return (-1);
}
- /* PreLen */
- map->fec.ipv4.prefixlen = buf[off];
+ /* Prefix Length */
+ map->fec.prefix.prefixlen = buf[off];
off += sizeof(uint8_t);
-
- if (len < off + PREFIX_SIZE(map->fec.ipv4.prefixlen)) {
+ if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) {
session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid,
lm->type);
return (-1);
}
/* Prefix */
- map->fec.ipv4.prefix.s_addr = 0;
- memcpy(&map->fec.ipv4.prefix, buf + off,
- PREFIX_SIZE(map->fec.ipv4.prefixlen));
+ memset(&map->fec.prefix.prefix, 0,
+ sizeof(map->fec.prefix.prefix));
+ memcpy(&map->fec.prefix.prefix, buf + off,
+ PREFIX_SIZE(map->fec.prefix.prefixlen));
- return (off + PREFIX_SIZE(map->fec.ipv4.prefixlen));
+ return (off + PREFIX_SIZE(map->fec.prefix.prefixlen));
case MAP_TYPE_PWID:
if (len < FEC_PWID_ELM_MIN_LEN) {
session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid,
diff --git a/usr.sbin/ldpd/lde.c b/usr.sbin/ldpd/lde.c
index 28eb38420cd..3e7afac9d89 100644
--- a/usr.sbin/ldpd/lde.c
+++ b/usr.sbin/ldpd/lde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lde.c,v 1.53 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: lde.c,v 1.54 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
@@ -45,7 +45,7 @@ void lde_dispatch_imsg(int, short, void *);
void lde_dispatch_parent(int, short, void *);
struct lde_nbr *lde_nbr_find(uint32_t);
-struct lde_nbr *lde_nbr_new(uint32_t, struct in_addr *);
+struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *);
void lde_nbr_del(struct lde_nbr *);
void lde_nbr_clear(void);
@@ -220,7 +220,7 @@ lde_dispatch_imsg(int fd, short event, void *bula)
struct imsg imsg;
struct lde_nbr *ln;
struct map map;
- struct in_addr addr;
+ struct lde_addr lde_addr;
struct notify_msg nm;
ssize_t n;
int shut = 0, verbose;
@@ -296,9 +296,9 @@ lde_dispatch_imsg(int fd, short event, void *bula)
}
break;
case IMSG_ADDRESS_ADD:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(addr))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
fatalx("lde_dispatch_imsg: wrong imsg len");
- memcpy(&addr, imsg.data, sizeof(addr));
+ memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
@@ -306,16 +306,16 @@ lde_dispatch_imsg(int fd, short event, void *bula)
__func__);
break;
}
- if (lde_address_add(ln, &addr) < 0) {
+ if (lde_address_add(ln, &lde_addr) < 0) {
log_debug("%s: cannot add address %s, it "
"already exists", __func__,
- inet_ntoa(addr));
+ log_addr(lde_addr.af, &lde_addr.addr));
}
break;
case IMSG_ADDRESS_DEL:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(addr))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
fatalx("lde_dispatch_imsg: wrong imsg len");
- memcpy(&addr, imsg.data, sizeof(addr));
+ memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
@@ -323,10 +323,10 @@ lde_dispatch_imsg(int fd, short event, void *bula)
__func__);
break;
}
- if (lde_address_del(ln, &addr) < 0) {
+ if (lde_address_del(ln, &lde_addr) < 0) {
log_debug("%s: cannot delete address %s, it "
"does not exist", __func__,
- inet_ntoa(addr));
+ log_addr(lde_addr.af, &lde_addr.addr));
}
break;
case IMSG_NOTIFICATION:
@@ -350,7 +350,8 @@ lde_dispatch_imsg(int fd, short event, void *bula)
}
break;
case IMSG_NEIGHBOR_UP:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(addr))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct lde_nbr))
fatalx("lde_dispatch_imsg: wrong imsg len");
if (lde_nbr_find(imsg.hdr.peerid))
@@ -439,29 +440,37 @@ lde_dispatch_parent(int fd, short event, void *bula)
switch (imsg.hdr.type) {
case IMSG_NETWORK_ADD:
+ case IMSG_NETWORK_DEL:
if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
log_warnx("%s: wrong imsg len", __func__);
break;
}
memcpy(&kr, imsg.data, sizeof(kr));
- fec.type = FEC_TYPE_IPV4;
- fec.u.ipv4.prefix = kr.prefix;
- fec.u.ipv4.prefixlen = kr.prefixlen;
- lde_kernel_insert(&fec, kr.nexthop,
- kr.flags & F_CONNECTED, NULL);
- break;
- case IMSG_NETWORK_DEL:
- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
- log_warnx("%s: wrong imsg len", __func__);
+ switch (kr.af) {
+ case AF_INET:
+ fec.type = FEC_TYPE_IPV4;
+ fec.u.ipv4.prefix = kr.prefix.v4;
+ fec.u.ipv4.prefixlen = kr.prefixlen;
break;
+ case AF_INET6:
+ fec.type = FEC_TYPE_IPV6;
+ fec.u.ipv6.prefix = kr.prefix.v6;
+ fec.u.ipv6.prefixlen = kr.prefixlen;
+ break;
+ default:
+ fatalx("lde_dispatch_parent: unknown af");
}
- memcpy(&kr, imsg.data, sizeof(kr));
- fec.type = FEC_TYPE_IPV4;
- fec.u.ipv4.prefix = kr.prefix;
- fec.u.ipv4.prefixlen = kr.prefixlen;
- lde_kernel_remove(&fec, kr.nexthop);
+ switch (imsg.hdr.type) {
+ case IMSG_NETWORK_ADD:
+ lde_kernel_insert(&fec, kr.af, &kr.nexthop,
+ kr.flags & F_CONNECTED, NULL);
+ break;
+ case IMSG_NETWORK_DEL:
+ lde_kernel_remove(&fec, kr.af, &kr.nexthop);
+ break;
+ }
break;
case IMSG_RECONF_CONF:
if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
@@ -480,7 +489,10 @@ lde_dispatch_parent(int fd, short event, void *bula)
memcpy(niface, imsg.data, sizeof(struct iface));
LIST_INIT(&niface->addr_list);
- LIST_INIT(&niface->adj_list);
+ LIST_INIT(&niface->ipv4.adj_list);
+ LIST_INIT(&niface->ipv6.adj_list);
+ niface->ipv4.iface = niface;
+ niface->ipv6.iface = niface;
LIST_INSERT_HEAD(&nconf->iface_list, niface, entry);
break;
@@ -564,18 +576,35 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
switch (fn->fec.type) {
case FEC_TYPE_IPV4:
memset(&kr, 0, sizeof(kr));
- kr.prefix = fn->fec.u.ipv4.prefix;
+ kr.af = AF_INET;
+ kr.prefix.v4 = fn->fec.u.ipv4.prefix;
kr.prefixlen = fn->fec.u.ipv4.prefixlen;
+ kr.nexthop.v4 = fnh->nexthop.v4;
kr.local_label = fn->local_label;
- kr.nexthop = fnh->nexthop;
kr.remote_label = fnh->remote_label;
lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
sizeof(kr));
- if (fnh->remote_label != NO_LABEL &&
- fn->fec.u.ipv4.prefixlen == 32)
- l2vpn_sync_pws(fn->fec.u.ipv4.prefix);
+ if (fn->fec.u.ipv4.prefixlen == 32)
+ l2vpn_sync_pws(AF_INET, (union ldpd_addr *)
+ &fn->fec.u.ipv4.prefix);
+ break;
+ case FEC_TYPE_IPV6:
+ memset(&kr, 0, sizeof(kr));
+ kr.af = AF_INET6;
+ kr.prefix.v6 = fn->fec.u.ipv6.prefix;
+ kr.prefixlen = fn->fec.u.ipv6.prefixlen;
+ kr.nexthop.v6 = fnh->nexthop.v6;
+ kr.local_label = fn->local_label;
+ kr.remote_label = fnh->remote_label;
+
+ lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
+ sizeof(kr));
+
+ if (fn->fec.u.ipv6.prefixlen == 128)
+ l2vpn_sync_pws(AF_INET6, (union ldpd_addr *)
+ &fn->fec.u.ipv6.prefix);
break;
case FEC_TYPE_PWID:
if (fn->local_label == NO_LABEL ||
@@ -588,7 +617,8 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
memset(&kpw, 0, sizeof(kpw));
kpw.ifindex = pw->ifindex;
kpw.pw_type = fn->fec.u.pwid.type;
- kpw.nexthop = fnh->nexthop;
+ kpw.af = pw->af;
+ kpw.nexthop = pw->addr;
kpw.local_label = fn->local_label;
kpw.remote_label = fnh->remote_label;
kpw.flags = pw->flags;
@@ -609,17 +639,35 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
switch (fn->fec.type) {
case FEC_TYPE_IPV4:
memset(&kr, 0, sizeof(kr));
- kr.prefix = fn->fec.u.ipv4.prefix;
+ kr.af = AF_INET;
+ kr.prefix.v4 = fn->fec.u.ipv4.prefix;
kr.prefixlen = fn->fec.u.ipv4.prefixlen;
+ kr.nexthop.v4 = fnh->nexthop.v4;
kr.local_label = fn->local_label;
- kr.nexthop = fnh->nexthop;
kr.remote_label = fnh->remote_label;
lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
sizeof(kr));
if (fn->fec.u.ipv4.prefixlen == 32)
- l2vpn_sync_pws(fn->fec.u.ipv4.prefix);
+ l2vpn_sync_pws(AF_INET, (union ldpd_addr *)
+ &fn->fec.u.ipv4.prefix);
+ break;
+ case FEC_TYPE_IPV6:
+ memset(&kr, 0, sizeof(kr));
+ kr.af = AF_INET6;
+ kr.prefix.v6 = fn->fec.u.ipv6.prefix;
+ kr.prefixlen = fn->fec.u.ipv6.prefixlen;
+ kr.nexthop.v6 = fnh->nexthop.v6;
+ kr.local_label = fn->local_label;
+ kr.remote_label = fnh->remote_label;
+
+ lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
+ sizeof(kr));
+
+ if (fn->fec.u.ipv6.prefixlen == 128)
+ l2vpn_sync_pws(AF_INET6, (union ldpd_addr *)
+ &fn->fec.u.ipv6.prefix);
break;
case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
@@ -630,7 +678,8 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
memset(&kpw, 0, sizeof(kpw));
kpw.ifindex = pw->ifindex;
kpw.pw_type = fn->fec.u.pwid.type;
- kpw.nexthop = fnh->nexthop;
+ kpw.af = pw->af;
+ kpw.nexthop = pw->addr;
kpw.local_label = fn->local_label;
kpw.remote_label = fnh->remote_label;
kpw.flags = pw->flags;
@@ -649,8 +698,15 @@ lde_fec2map(struct fec *fec, struct map *map)
switch (fec->type) {
case FEC_TYPE_IPV4:
map->type = MAP_TYPE_PREFIX;
- map->fec.ipv4.prefix = fec->u.ipv4.prefix;
- map->fec.ipv4.prefixlen = fec->u.ipv4.prefixlen;
+ map->fec.prefix.af = AF_IPV4;
+ map->fec.prefix.prefix.v4 = fec->u.ipv4.prefix;
+ map->fec.prefix.prefixlen = fec->u.ipv4.prefixlen;
+ break;
+ case FEC_TYPE_IPV6:
+ map->type = MAP_TYPE_PREFIX;
+ map->fec.prefix.af = AF_IPV6;
+ map->fec.prefix.prefix.v6 = fec->u.ipv6.prefix;
+ map->fec.prefix.prefixlen = fec->u.ipv6.prefixlen;
break;
case FEC_TYPE_PWID:
map->type = MAP_TYPE_PWID;
@@ -669,9 +725,21 @@ lde_map2fec(struct map *map, struct in_addr lsr_id, struct fec *fec)
switch (map->type) {
case MAP_TYPE_PREFIX:
- fec->type = FEC_TYPE_IPV4;
- fec->u.ipv4.prefix = map->fec.ipv4.prefix;
- fec->u.ipv4.prefixlen = map->fec.ipv4.prefixlen;
+ switch (map->fec.prefix.af) {
+ case AF_IPV4:
+ fec->type = FEC_TYPE_IPV4;
+ fec->u.ipv4.prefix = map->fec.prefix.prefix.v4;
+ fec->u.ipv4.prefixlen = map->fec.prefix.prefixlen;
+ break;
+ case AF_IPV6:
+ fec->type = FEC_TYPE_IPV6;
+ fec->u.ipv6.prefix = map->fec.prefix.prefix.v6;
+ fec->u.ipv6.prefixlen = map->fec.prefix.prefixlen;
+ break;
+ default:
+ fatalx("lde_map2fec: unknown af");
+ break;
+ }
break;
case MAP_TYPE_PWID:
fec->type = FEC_TYPE_PWID;
@@ -697,7 +765,16 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
*/
lde_fec2map(&fn->fec, &map);
- if (fn->fec.type == FEC_TYPE_PWID) {
+ switch (fn->fec.type) {
+ case FEC_TYPE_IPV4:
+ if (!ln->v4_enabled)
+ return;
+ break;
+ case FEC_TYPE_IPV6:
+ if (!ln->v6_enabled)
+ return;
+ break;
+ case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr)
/* not the remote end of the pseudowire */
@@ -712,6 +789,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
/* VPLS are always up */
map.pw_status = PW_FORWARDING;
}
+ break;
}
map.label = fn->local_label;
@@ -750,8 +828,16 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
if (fn) {
lde_fec2map(&fn->fec, &map);
- map.label = fn->local_label;
- if (fn->fec.type == FEC_TYPE_PWID) {
+ switch (fn->fec.type) {
+ case FEC_TYPE_IPV4:
+ if (!ln->v4_enabled)
+ return;
+ break;
+ case FEC_TYPE_IPV6:
+ if (!ln->v6_enabled)
+ return;
+ break;
+ case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr)
/* not the remote end of the pseudowire */
@@ -759,7 +845,9 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
if (pw->flags & F_PW_CWORD)
map.flags |= F_MAP_PW_CWORD;
+ break;
}
+ map.label = fn->local_label;
} else {
memset(&map, 0, sizeof(map));
map.type = MAP_TYPE_WILDCARD;
@@ -807,7 +895,16 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
if (fn) {
lde_fec2map(&fn->fec, &map);
- if (fn->fec.type == FEC_TYPE_PWID) {
+ switch (fn->fec.type) {
+ case FEC_TYPE_IPV4:
+ if (!ln->v4_enabled)
+ return;
+ break;
+ case FEC_TYPE_IPV6:
+ if (!ln->v6_enabled)
+ return;
+ break;
+ case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr)
/* not the remote end of the pseudowire */
@@ -815,6 +912,7 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
if (pw->flags & F_PW_CWORD)
map.flags |= F_MAP_PW_CWORD;
+ break;
}
} else {
memset(&map, 0, sizeof(map));
@@ -850,14 +948,16 @@ lde_nbr_compare(struct lde_nbr *a, struct lde_nbr *b)
}
struct lde_nbr *
-lde_nbr_new(uint32_t peerid, struct in_addr *id)
+lde_nbr_new(uint32_t peerid, struct lde_nbr *new)
{
struct lde_nbr *ln;
if ((ln = calloc(1, sizeof(*ln))) == NULL)
fatal(__func__);
- ln->id = *id;
+ ln->id = new->id;
+ ln->v4_enabled = new->v4_enabled;
+ ln->v6_enabled = new->v6_enabled;
ln->peerid = peerid;
fec_init(&ln->recv_map);
fec_init(&ln->sent_map);
@@ -891,7 +991,9 @@ lde_nbr_del(struct lde_nbr *ln)
LIST_FOREACH(fnh, &fn->nexthops, entry) {
switch (f->type) {
case FEC_TYPE_IPV4:
- if (!lde_address_find(ln, &fnh->nexthop))
+ case FEC_TYPE_IPV6:
+ if (!lde_address_find(ln, fnh->af,
+ &fnh->nexthop))
continue;
break;
case FEC_TYPE_PWID:
@@ -946,12 +1048,12 @@ lde_nbr_find_by_lsrid(struct in_addr addr)
}
struct lde_nbr *
-lde_nbr_find_by_addr(struct in_addr addr)
+lde_nbr_find_by_addr(int af, union ldpd_addr *addr)
{
struct lde_nbr *ln;
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
- if (lde_address_find(ln, &addr) != NULL)
+ if (lde_address_find(ln, af, addr) != NULL)
return (ln);
return (NULL);
@@ -1074,25 +1176,44 @@ lde_wdraw_del(struct lde_nbr *ln, struct lde_wdraw *lw)
}
void
-lde_change_egress_label(int was_implicit)
+lde_change_egress_label(int af, int was_implicit)
{
struct lde_nbr *ln;
struct fec *f;
struct fec_node *fn;
- /* explicit withdraw */
- if (was_implicit)
- lde_send_labelwithdraw_all(NULL, MPLS_LABEL_IMPLNULL);
- else
- lde_send_labelwithdraw_all(NULL, MPLS_LABEL_IPV4NULL);
-
- /* update label of connected prefixes */
RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
+ /* explicit withdraw */
+ if (was_implicit)
+ lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL);
+ else {
+ if (ln->v4_enabled)
+ lde_send_labelwithdraw(ln, NULL,
+ MPLS_LABEL_IPV4NULL);
+ if (ln->v6_enabled)
+ lde_send_labelwithdraw(ln, NULL,
+ MPLS_LABEL_IPV6NULL);
+ }
+
+ /* advertise new label of connected prefixes */
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
if (fn->local_label > MPLS_LABEL_RESERVED_MAX)
continue;
+ switch (af) {
+ case AF_INET:
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+ break;
+ case AF_INET6:
+ if (fn->fec.type != FEC_TYPE_IPV6)
+ continue;
+ break;
+ default:
+ fatalx("lde_change_egress_label: unknown af");
+ }
+
fn->local_label = egress_label(fn->fec.type);
lde_send_labelmapping(ln, fn, 0);
}
@@ -1103,28 +1224,27 @@ lde_change_egress_label(int was_implicit)
}
int
-lde_address_add(struct lde_nbr *ln, struct in_addr *addr)
+lde_address_add(struct lde_nbr *ln, struct lde_addr *lde_addr)
{
struct lde_addr *new;
- if (lde_address_find(ln, addr) != NULL)
+ if (lde_address_find(ln, lde_addr->af, &lde_addr->addr) != NULL)
return (-1);
if ((new = calloc(1, sizeof(*new))) == NULL)
fatal(__func__);
- new->addr = *addr;
+ new->af = lde_addr->af;
+ new->addr = lde_addr->addr;
TAILQ_INSERT_TAIL(&ln->addr_list, new, entry);
return (0);
}
int
-lde_address_del(struct lde_nbr *ln, struct in_addr *addr)
+lde_address_del(struct lde_nbr *ln, struct lde_addr *lde_addr)
{
- struct lde_addr *lde_addr;
-
- lde_addr = lde_address_find(ln, addr);
+ lde_addr = lde_address_find(ln, lde_addr->af, &lde_addr->addr);
if (lde_addr == NULL)
return (-1);
@@ -1135,12 +1255,13 @@ lde_address_del(struct lde_nbr *ln, struct in_addr *addr)
}
struct lde_addr *
-lde_address_find(struct lde_nbr *ln, struct in_addr *addr)
+lde_address_find(struct lde_nbr *ln, int af, union ldpd_addr *addr)
{
struct lde_addr *lde_addr;
TAILQ_FOREACH(lde_addr, &ln->addr_list, entry)
- if (lde_addr->addr.s_addr == addr->s_addr)
+ if (lde_addr->af == af &&
+ ldp_addrcmp(af, &lde_addr->addr, addr) == 0)
return (lde_addr);
return (NULL);
diff --git a/usr.sbin/ldpd/lde.h b/usr.sbin/ldpd/lde.h
index 9097715ebf7..92d9ab936c8 100644
--- a/usr.sbin/ldpd/lde.h
+++ b/usr.sbin/ldpd/lde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: lde.h,v 1.34 2016/05/23 18:46:13 renato Exp $ */
+/* $OpenBSD: lde.h,v 1.35 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -30,6 +30,7 @@ RB_HEAD(fec_tree, fec);
enum fec_type {
FEC_TYPE_IPV4,
+ FEC_TYPE_IPV6,
FEC_TYPE_PWID
};
@@ -42,6 +43,10 @@ struct fec {
uint8_t prefixlen;
} ipv4;
struct {
+ struct in6_addr prefix;
+ uint8_t prefixlen;
+ } ipv6;
+ struct {
uint16_t type;
uint32_t pwid;
struct in_addr lsr_id;
@@ -74,27 +79,29 @@ struct lde_wdraw {
/* Addresses belonging to neighbor */
struct lde_addr {
TAILQ_ENTRY(lde_addr) entry;
- struct in_addr addr;
+ int af;
+ union ldpd_addr addr;
};
/* just the info LDE needs */
struct lde_nbr {
- RB_ENTRY(lde_nbr) entry;
- struct in_addr id;
-
- struct fec_tree recv_req;
- struct fec_tree sent_req;
- struct fec_tree recv_map;
- struct fec_tree sent_map;
- struct fec_tree sent_wdraw;
- TAILQ_HEAD(, lde_addr) addr_list;
-
- uint32_t peerid;
+ RB_ENTRY(lde_nbr) entry;
+ uint32_t peerid;
+ struct in_addr id;
+ int v4_enabled; /* announce/process v4 msgs */
+ int v6_enabled; /* announce/process v6 msgs */
+ struct fec_tree recv_req;
+ struct fec_tree sent_req;
+ struct fec_tree recv_map;
+ struct fec_tree sent_map;
+ struct fec_tree sent_wdraw;
+ TAILQ_HEAD(, lde_addr) addr_list;
};
struct fec_nh {
LIST_ENTRY(fec_nh) entry;
- struct in_addr nexthop;
+ int af;
+ union ldpd_addr nexthop;
uint32_t remote_label;
};
@@ -125,18 +132,19 @@ void lde_send_labelwithdraw_all(struct fec_node *, uint32_t);
void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, uint32_t);
void lde_send_notification(uint32_t, uint32_t, uint32_t, uint16_t);
struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr);
-struct lde_nbr *lde_nbr_find_by_addr(struct in_addr);
+struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *);
struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int);
void lde_map_del(struct lde_nbr *, struct lde_map *, int);
struct lde_req *lde_req_add(struct lde_nbr *, struct fec *, int);
void lde_req_del(struct lde_nbr *, struct lde_req *, int);
struct lde_wdraw *lde_wdraw_add(struct lde_nbr *, struct fec_node *);
void lde_wdraw_del(struct lde_nbr *, struct lde_wdraw *);
-void lde_change_egress_label(int);
+void lde_change_egress_label(int, int);
-int lde_address_add(struct lde_nbr *, struct in_addr *);
-struct lde_addr *lde_address_find(struct lde_nbr *, struct in_addr *);
-int lde_address_del(struct lde_nbr *, struct in_addr *);
+int lde_address_add(struct lde_nbr *, struct lde_addr *);
+struct lde_addr *lde_address_find(struct lde_nbr *, int,
+ union ldpd_addr *);
+int lde_address_del(struct lde_nbr *, struct lde_addr *);
/* lde_lib.c */
void fec_init(struct fec_tree *);
@@ -149,10 +157,10 @@ void rt_dump(pid_t);
void fec_snap(struct lde_nbr *);
void fec_tree_clear(void);
-struct fec_nh *fec_nh_find(struct fec_node *, struct in_addr);
+struct fec_nh *fec_nh_find(struct fec_node *, int, union ldpd_addr *);
uint32_t egress_label(enum fec_type);
-void lde_kernel_insert(struct fec *, struct in_addr, int, void *);
-void lde_kernel_remove(struct fec *, struct in_addr);
+void lde_kernel_insert(struct fec *, int, union ldpd_addr *, int, void *);
+void lde_kernel_remove(struct fec *, int, union ldpd_addr *);
void lde_check_mapping(struct map *, struct lde_nbr *);
void lde_check_request(struct map *, struct lde_nbr *);
void lde_check_release(struct map *, struct lde_nbr *);
@@ -185,7 +193,7 @@ int l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *,
struct map *);
void l2vpn_send_pw_status(uint32_t, uint32_t, struct fec *);
void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *);
-void l2vpn_sync_pws(struct in_addr);
+void l2vpn_sync_pws(int, union ldpd_addr *);
void l2vpn_pw_ctl(pid_t);
void l2vpn_binding_ctl(pid_t);
diff --git a/usr.sbin/ldpd/lde_lib.c b/usr.sbin/ldpd/lde_lib.c
index e549c4086eb..f8099d086b9 100644
--- a/usr.sbin/ldpd/lde_lib.c
+++ b/usr.sbin/ldpd/lde_lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lde_lib.c,v 1.54 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: lde_lib.c,v 1.55 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -42,7 +42,7 @@ static int fec_compare(struct fec *, struct fec *);
void fec_free(void *);
struct fec_node *fec_add(struct fec *fec);
-struct fec_nh *fec_nh_add(struct fec_node *, struct in_addr);
+struct fec_nh *fec_nh_add(struct fec_node *, int, union ldpd_addr *);
void fec_nh_del(struct fec_nh *);
int lde_nbr_is_nexthop(struct fec_node *, struct lde_nbr *);
@@ -84,6 +84,18 @@ fec_compare(struct fec *a, struct fec *b)
if (a->u.ipv4.prefixlen > b->u.ipv4.prefixlen)
return (1);
return (0);
+ case FEC_TYPE_IPV6:
+ if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix,
+ sizeof(struct in6_addr)) < 0)
+ return (-1);
+ if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix,
+ sizeof(struct in6_addr)) > 0)
+ return (1);
+ if (a->u.ipv6.prefixlen < b->u.ipv6.prefixlen)
+ return (-1);
+ if (a->u.ipv6.prefixlen > b->u.ipv6.prefixlen)
+ return (1);
+ return (0);
case FEC_TYPE_PWID:
if (a->u.pwid.type < b->u.pwid.type)
return (-1);
@@ -147,7 +159,7 @@ lde_nbr_is_nexthop(struct fec_node *fn, struct lde_nbr *ln)
struct fec_nh *fnh;
LIST_FOREACH(fnh, &fn->nexthops, entry)
- if (lde_address_find(ln, &fnh->nexthop))
+ if (lde_address_find(ln, fnh->af, &fnh->nexthop))
return (1);
return (0);
@@ -163,17 +175,26 @@ rt_dump(pid_t pid)
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
- if (fn->fec.type != FEC_TYPE_IPV4)
- continue;
-
if (fn->local_label == NO_LABEL &&
LIST_EMPTY(&fn->downstream))
continue;
- rtctl.prefix = fn->fec.u.ipv4.prefix;
- rtctl.prefixlen = fn->fec.u.ipv4.prefixlen;
- rtctl.local_label = fn->local_label;
+ switch (fn->fec.type) {
+ case FEC_TYPE_IPV4:
+ rtctl.af = AF_INET;
+ rtctl.prefix.v4 = fn->fec.u.ipv4.prefix;
+ rtctl.prefixlen = fn->fec.u.ipv4.prefixlen;
+ break;
+ case FEC_TYPE_IPV6:
+ rtctl.af = AF_INET6;
+ rtctl.prefix.v6 = fn->fec.u.ipv6.prefix;
+ rtctl.prefixlen = fn->fec.u.ipv6.prefixlen;
+ break;
+ default:
+ continue;
+ }
+ rtctl.local_label = fn->local_label;
LIST_FOREACH(me, &fn->downstream, entry) {
rtctl.in_use = lde_nbr_is_nexthop(fn, me->nexthop);
rtctl.nexthop = me->nexthop->id;
@@ -257,19 +278,20 @@ fec_add(struct fec *fec)
}
struct fec_nh *
-fec_nh_find(struct fec_node *fn, struct in_addr nexthop)
+fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop)
{
struct fec_nh *fnh;
LIST_FOREACH(fnh, &fn->nexthops, entry)
- if (fnh->nexthop.s_addr == nexthop.s_addr)
+ if (fnh->af == af &&
+ ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0)
return (fnh);
return (NULL);
}
struct fec_nh *
-fec_nh_add(struct fec_node *fn, struct in_addr nexthop)
+fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop)
{
struct fec_nh *fnh;
@@ -277,7 +299,8 @@ fec_nh_add(struct fec_node *fn, struct in_addr nexthop)
if (fnh == NULL)
fatal(__func__);
- fnh->nexthop = nexthop;
+ fnh->af = af;
+ fnh->nexthop = *nexthop;
fnh->remote_label = NO_LABEL;
LIST_INSERT_HEAD(&fn->nexthops, fnh, entry);
@@ -294,12 +317,15 @@ fec_nh_del(struct fec_nh *fnh)
uint32_t
egress_label(enum fec_type fec_type)
{
- if (!(ldeconf->flags & F_LDPD_EXPNULL))
- return (MPLS_LABEL_IMPLNULL);
-
switch (fec_type) {
case FEC_TYPE_IPV4:
+ if (!(ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL))
+ return (MPLS_LABEL_IMPLNULL);
return (MPLS_LABEL_IPV4NULL);
+ case FEC_TYPE_IPV6:
+ if (!(ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL))
+ return (MPLS_LABEL_IMPLNULL);
+ return (MPLS_LABEL_IPV6NULL);
default:
log_warnx("%s: unexpected fec type", __func__);
}
@@ -308,8 +334,8 @@ egress_label(enum fec_type fec_type)
}
void
-lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected,
- void *data)
+lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
+ int connected, void *data)
{
struct fec_node *fn;
struct fec_nh *fnh;
@@ -319,11 +345,11 @@ lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected,
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
fn = fec_add(fec);
- if (fec_nh_find(fn, nexthop) != NULL)
+ if (fec_nh_find(fn, af, nexthop) != NULL)
return;
log_debug("lde add fec %s nexthop %s",
- log_fec(&fn->fec), inet_ntoa(nexthop));
+ log_fec(&fn->fec), log_addr(af, nexthop));
if (fn->fec.type == FEC_TYPE_PWID)
fn->data = data;
@@ -339,12 +365,13 @@ lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected,
lde_send_labelmapping(ln, fn, 1);
}
- fnh = fec_nh_add(fn, nexthop);
+ fnh = fec_nh_add(fn, af, nexthop);
lde_send_change_klabel(fn, fnh);
switch (fn->fec.type) {
case FEC_TYPE_IPV4:
- ln = lde_nbr_find_by_addr(fnh->nexthop);
+ case FEC_TYPE_IPV6:
+ ln = lde_nbr_find_by_addr(af, &fnh->nexthop);
break;
case FEC_TYPE_PWID:
ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id);
@@ -364,7 +391,7 @@ lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected,
}
void
-lde_kernel_remove(struct fec *fec, struct in_addr nexthop)
+lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop)
{
struct fec_node *fn;
struct fec_nh *fnh;
@@ -373,13 +400,13 @@ lde_kernel_remove(struct fec *fec, struct in_addr nexthop)
if (fn == NULL)
/* route lost */
return;
- fnh = fec_nh_find(fn, nexthop);
+ fnh = fec_nh_find(fn, af, nexthop);
if (fnh == NULL)
/* route lost */
return;
log_debug("lde remove fec %s nexthop %s",
- log_fec(&fn->fec), inet_ntoa(nexthop));
+ log_fec(&fn->fec), log_addr(af, nexthop));
lde_send_delete_klabel(fn, fnh);
fec_nh_del(fnh);
@@ -435,7 +462,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
* the possibility of multipath.
*/
LIST_FOREACH(fnh, &fn->nexthops, entry) {
- if (lde_address_find(ln, &fnh->nexthop) == NULL)
+ if (lde_address_find(ln, fnh->af,
+ &fnh->nexthop) == NULL)
continue;
lde_send_delete_klabel(fn, fnh);
@@ -452,7 +480,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
/* LMp.15: install FEC in FIB */
switch (fec.type) {
case FEC_TYPE_IPV4:
- if (!lde_address_find(ln, &fnh->nexthop))
+ case FEC_TYPE_IPV6:
+ if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
continue;
fnh->remote_label = map->label;
@@ -517,7 +546,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
LIST_FOREACH(fnh, &fn->nexthops, entry) {
switch (fec.type) {
case FEC_TYPE_IPV4:
- if (!lde_address_find(ln, &fnh->nexthop))
+ case FEC_TYPE_IPV6:
+ if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
continue;
lde_send_notification(ln->peerid, S_LOOP_DETECTED,
@@ -640,7 +670,8 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
LIST_FOREACH(fnh, &fn->nexthops, entry) {
switch (fec.type) {
case FEC_TYPE_IPV4:
- if (!lde_address_find(ln, &fnh->nexthop))
+ case FEC_TYPE_IPV6:
+ if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
continue;
break;
case FEC_TYPE_PWID:
@@ -683,7 +714,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
LIST_FOREACH(fnh, &fn->nexthops, entry) {
switch (f->type) {
case FEC_TYPE_IPV4:
- if (!lde_address_find(ln, &fnh->nexthop))
+ case FEC_TYPE_IPV6:
+ if (!lde_address_find(ln, fnh->af,
+ &fnh->nexthop))
continue;
break;
case FEC_TYPE_PWID:
diff --git a/usr.sbin/ldpd/ldp.h b/usr.sbin/ldpd/ldp.h
index 505e6952989..bbf12ca89ff 100644
--- a/usr.sbin/ldpd/ldp.h
+++ b/usr.sbin/ldpd/ldp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldp.h,v 1.26 2016/05/23 17:43:42 renato Exp $ */
+/* $OpenBSD: ldp.h,v 1.27 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -27,10 +27,12 @@
/* misc */
#define LDP_VERSION 1
#define LDP_PORT 646
-#define AllRouters "224.0.0.2"
-
#define LDP_MAX_LEN 4096
+/* All Routers on this Subnet group multicast addresses */
+#define AllRouters_v4 "224.0.0.2"
+#define AllRouters_v6 "ff02::2"
+
#define LINK_DFLT_HOLDTIME 15
#define TARGETED_DFLT_HOLDTIME 45
#define MIN_HOLDTIME 3
@@ -93,6 +95,8 @@
#define TLV_TYPE_PW_STATUS 0x096A
#define TLV_TYPE_PW_IF_PARAM 0x096B
#define TLV_TYPE_PW_GROUP_ID 0x096C
+/* RFC 7552 */
+#define TLV_TYPE_DUALSTACK 0x8701
/* LDP header */
struct ldp_hdr {
@@ -144,6 +148,18 @@ struct hello_prms_opt4_tlv {
uint32_t value;
};
+struct hello_prms_opt16_tlv {
+ uint16_t type;
+ uint16_t length;
+ uint8_t value[16];
+};
+
+#define DUAL_STACK_LDPOV4 4
+#define DUAL_STACK_LDPOV6 6
+
+#define F_HELLO_TLV_RCVD_ADDR 0x01
+#define F_HELLO_TLV_RCVD_CONF 0x02
+#define F_HELLO_TLV_RCVD_DS 0x04
#define S_SUCCESS 0x00000000
#define S_BAD_LDP_ID 0x80000001
@@ -180,6 +196,9 @@ struct hello_prms_opt4_tlv {
#define S_UNASSIGN_TAI 0x00000029
#define S_MISCONF_ERR 0x0000002A
#define S_WITHDRAW_MTHD 0x0000002B
+/* RFC 7552 */
+#define S_TRANS_MISMTCH 0x80000032
+#define S_DS_NONCMPLNCE 0x80000033
struct sess_prms_tlv {
uint16_t type;
diff --git a/usr.sbin/ldpd/ldpd.8 b/usr.sbin/ldpd/ldpd.8
index 501b933f955..c91d3753d6d 100644
--- a/usr.sbin/ldpd/ldpd.8
+++ b/usr.sbin/ldpd/ldpd.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ldpd.8,v 1.13 2016/05/23 17:43:42 renato Exp $
+.\" $OpenBSD: ldpd.8,v 1.14 2016/05/23 18:58:48 renato Exp $
.\"
.\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
.\" Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
@@ -126,6 +126,17 @@ socket used for communication with
.%R RFC 5036
.%T LDP Specification
.Re
+.Pp
+.Rs
+.%A R. Asati
+.%A C. Pignataro
+.%A K. Raza
+.%A V. Manral
+.%A R. Papneja
+.%D June 2015
+.%R RFC 7552
+.%T Updates to LDP for IPv6
+.Re
.Sh HISTORY
The
.Nm
diff --git a/usr.sbin/ldpd/ldpd.c b/usr.sbin/ldpd/ldpd.c
index 1cb72f02528..8d464b17c87 100644
--- a/usr.sbin/ldpd/ldpd.c
+++ b/usr.sbin/ldpd/ldpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpd.c,v 1.43 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: ldpd.c,v 1.44 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -54,11 +54,13 @@ int check_child(pid_t, const char *);
void main_dispatch_ldpe(int, short, void *);
void main_dispatch_lde(int, short, void *);
int main_imsg_compose_both(enum imsg_type, void *, uint16_t);
-void main_imsg_send_net_sockets(void);
-void main_imsg_send_net_socket(enum socket_type);
+void main_imsg_send_net_sockets(int);
+void main_imsg_send_net_socket(int, enum socket_type);
int ldp_reload(void);
void merge_global(struct ldpd_conf *, struct ldpd_conf *);
+void merge_af(int, struct ldpd_af_conf *, struct ldpd_af_conf *);
void merge_ifaces(struct ldpd_conf *, struct ldpd_conf *);
+void merge_iface_af(struct iface_af *, struct iface_af *);
void merge_tnbrs(struct ldpd_conf *, struct ldpd_conf *);
void merge_nbrps(struct ldpd_conf *, struct ldpd_conf *);
void merge_l2vpns(struct ldpd_conf *, struct ldpd_conf *);
@@ -263,7 +265,8 @@ main(int argc, char *argv[])
if (kr_init(!(ldpd_conf->flags & F_LDPD_NO_FIB_UPDATE)) == -1)
fatalx("kr_init failed");
- main_imsg_send_net_sockets();
+ main_imsg_send_net_sockets(AF_INET);
+ main_imsg_send_net_sockets(AF_INET6);
/* remove unneded stuff from config */
/* ... */
@@ -333,6 +336,7 @@ main_dispatch_ldpe(int fd, short event, void *bula)
struct imsgev *iev = bula;
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
+ int af;
ssize_t n;
int shut = 0, verbose;
@@ -358,7 +362,8 @@ main_dispatch_ldpe(int fd, short event, void *bula)
switch (imsg.hdr.type) {
case IMSG_REQUEST_SOCKETS:
- main_imsg_send_net_sockets();
+ af = imsg.hdr.peerid;
+ main_imsg_send_net_sockets(af);
break;
case IMSG_CTL_RELOAD:
if (ldp_reload() == -1)
@@ -562,30 +567,63 @@ evbuf_clear(struct evbuf *eb)
}
void
-main_imsg_send_net_sockets(void)
+main_imsg_send_net_sockets(int af)
{
- main_imsg_send_net_socket(LDP_SOCKET_DISC);
- main_imsg_send_net_socket(LDP_SOCKET_EDISC);
- main_imsg_send_net_socket(LDP_SOCKET_SESSION);
- main_imsg_compose_ldpe(IMSG_SETUP_SOCKETS, 0, NULL, 0);
+ main_imsg_send_net_socket(af, LDP_SOCKET_DISC);
+ main_imsg_send_net_socket(af, LDP_SOCKET_EDISC);
+ main_imsg_send_net_socket(af, LDP_SOCKET_SESSION);
+ imsg_compose_event(iev_ldpe, IMSG_SETUP_SOCKETS, af, 0, -1, NULL, 0);
}
void
-main_imsg_send_net_socket(enum socket_type type)
+main_imsg_send_net_socket(int af, enum socket_type type)
{
int fd;
- fd = ldp_create_socket(type);
+ fd = ldp_create_socket(af, type);
if (fd == -1) {
- log_warnx("%s: failed to create %s socket", __func__,
- socket_name(type));
+ log_warnx("%s: failed to create %s socket for address-family "
+ "%s", __func__, socket_name(type), af_name(af));
return;
}
- imsg_compose_event(iev_ldpe, IMSG_SOCKET_NET, 0, 0, fd, &type,
+ imsg_compose_event(iev_ldpe, IMSG_SOCKET_NET, af, 0, fd, &type,
sizeof(type));
}
+struct ldpd_af_conf *
+ldp_af_conf_get(struct ldpd_conf *xconf, int af)
+{
+ switch (af) {
+ case AF_INET:
+ return (&xconf->ipv4);
+ case AF_INET6:
+ return (&xconf->ipv6);
+ default:
+ fatalx("ldp_af_conf_get: unknown af");
+ }
+}
+
+struct ldpd_af_global *
+ldp_af_global_get(struct ldpd_global *xglobal, int af)
+{
+ switch (af) {
+ case AF_INET:
+ return (&xglobal->ipv4);
+ case AF_INET6:
+ return (&xglobal->ipv6);
+ default:
+ fatalx("ldp_af_global_get: unknown af");
+ }
+}
+
+int
+ldp_is_dual_stack(struct ldpd_conf *xconf)
+{
+ return ((xconf->ipv4.flags & F_LDPD_AF_ENABLED) &&
+ (xconf->ipv6.flags & F_LDPD_AF_ENABLED));
+}
+
int
ldp_reload(void)
{
@@ -651,6 +689,8 @@ void
merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
{
merge_global(conf, xconf);
+ merge_af(AF_INET, &conf->ipv4, &xconf->ipv4);
+ merge_af(AF_INET6, &conf->ipv6, &xconf->ipv6);
merge_ifaces(conf, xconf);
merge_tnbrs(conf, xconf);
merge_nbrps(conf, xconf);
@@ -661,68 +701,91 @@ merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
void
merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
{
- struct nbr *nbr;
- struct nbr_params *nbrp;
- int egress_label_changed = 0;
-
/* change of router-id requires resetting all neighborships */
if (conf->rtr_id.s_addr != xconf->rtr_id.s_addr) {
if (ldpd_process == PROC_LDP_ENGINE) {
- ldpe_reset_nbrs();
+ ldpe_reset_nbrs(AF_INET);
+ ldpe_reset_nbrs(AF_INET6);
if (conf->rtr_id.s_addr == INADDR_ANY ||
xconf->rtr_id.s_addr == INADDR_ANY) {
- if_update_all();
- tnbr_update_all();
+ if_update_all(AF_UNSPEC);
+ tnbr_update_all(AF_UNSPEC);
}
}
conf->rtr_id = xconf->rtr_id;
}
- if (conf->keepalive != xconf->keepalive) {
- conf->keepalive = xconf->keepalive;
+ if (conf->trans_pref != xconf->trans_pref) {
+ if (ldpd_process == PROC_LDP_ENGINE)
+ ldpe_reset_ds_nbrs();
+ conf->trans_pref = xconf->trans_pref;
+ }
+
+ if ((conf->flags & F_LDPD_DS_CISCO_INTEROP) !=
+ (xconf->flags & F_LDPD_DS_CISCO_INTEROP)) {
if (ldpd_process == PROC_LDP_ENGINE)
- ldpe_stop_init_backoff();
+ ldpe_reset_ds_nbrs();
}
- conf->thello_holdtime = xconf->thello_holdtime;
- conf->thello_interval = xconf->thello_interval;
+ conf->flags = xconf->flags;
+}
+
+void
+merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
+{
+ struct nbr *nbr;
+ struct nbr_params *nbrp;
+ int egress_label_changed = 0;
+
+ if (af_conf->keepalive != xa->keepalive) {
+ af_conf->keepalive = xa->keepalive;
+ if (ldpd_process == PROC_LDP_ENGINE)
+ ldpe_stop_init_backoff(af);
+ }
+ af_conf->thello_holdtime = xa->thello_holdtime;
+ af_conf->thello_interval = xa->thello_interval;
/* update flags */
if (ldpd_process == PROC_LDP_ENGINE &&
- (conf->flags & F_LDPD_TH_ACCEPT) &&
- !(xconf->flags & F_LDPD_TH_ACCEPT))
- ldpe_remove_dynamic_tnbrs();
+ (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) &&
+ !(xa->flags & F_LDPD_AF_THELLO_ACCEPT))
+ ldpe_remove_dynamic_tnbrs(af);
- if ((conf->flags & F_LDPD_EXPNULL) !=
- (xconf->flags & F_LDPD_EXPNULL))
+ if ((af_conf->flags & F_LDPD_AF_EXPNULL) !=
+ (xa->flags & F_LDPD_AF_EXPNULL))
egress_label_changed = 1;
- conf->flags = xconf->flags;
+ af_conf->flags = xa->flags;
if (egress_label_changed) {
switch (ldpd_process) {
case PROC_LDE_ENGINE:
- lde_change_egress_label(conf->flags & F_LDPD_EXPNULL);
+ lde_change_egress_label(af, af_conf->flags &
+ F_LDPD_AF_EXPNULL);
break;
case PROC_MAIN:
- kr_change_egress_label(conf->flags & F_LDPD_EXPNULL);
+ kr_change_egress_label(af, af_conf->flags &
+ F_LDPD_AF_EXPNULL);
break;
default:
break;
}
}
- if (conf->trans_addr.s_addr != xconf->trans_addr.s_addr) {
- conf->trans_addr = xconf->trans_addr;
+ if (ldp_addrcmp(af, &af_conf->trans_addr, &xa->trans_addr)) {
+ af_conf->trans_addr = xa->trans_addr;
if (ldpd_process == PROC_MAIN)
- imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, 0,
+ imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, af,
0, -1, NULL, 0);
if (ldpd_process == PROC_LDP_ENGINE) {
RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
+ if (nbr->af != af)
+ continue;
+
session_shutdown(nbr, S_SHUTDOWN, 0, 0);
pfkey_remove(nbr);
- nbr->laddr = conf->trans_addr;
+ nbr->laddr = af_conf->trans_addr;
nbrp = nbr_params_find(leconf, nbr->id);
if (nbrp && pfkey_establish(nbr, nbrp) == -1)
fatalx("pfkey setup failed");
@@ -759,14 +822,26 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
}
/* update existing interfaces */
- iface->hello_holdtime = xi->hello_holdtime;
- iface->hello_interval = xi->hello_interval;
+ merge_iface_af(&iface->ipv4, &xi->ipv4);
+ merge_iface_af(&iface->ipv6, &xi->ipv6);
LIST_REMOVE(xi, entry);
free(xi);
}
}
void
+merge_iface_af(struct iface_af *ia, struct iface_af *xi)
+{
+ if (ia->enabled != xi->enabled) {
+ ia->enabled = xi->enabled;
+ if (ldpd_process == PROC_LDP_ENGINE)
+ if_update(ia->iface, ia->af);
+ }
+ ia->hello_holdtime = xi->hello_holdtime;
+ ia->hello_interval = xi->hello_interval;
+}
+
+void
merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
{
struct tnbr *tnbr, *ttmp, *xt;
@@ -776,7 +851,7 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
continue;
/* find deleted tnbrs */
- if ((xt = tnbr_find(xconf, tnbr->addr)) == NULL) {
+ if ((xt = tnbr_find(xconf, tnbr->af, &tnbr->addr)) == NULL) {
if (ldpd_process == PROC_LDP_ENGINE) {
tnbr->flags &= ~F_TNBR_CONFIGURED;
tnbr_check(tnbr);
@@ -788,7 +863,7 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
}
LIST_FOREACH_SAFE(xt, &xconf->tnbr_list, entry, ttmp) {
/* find new tnbrs */
- if ((tnbr = tnbr_find(conf, xt->addr)) == NULL) {
+ if ((tnbr = tnbr_find(conf, xt->af, &xt->addr)) == NULL) {
LIST_REMOVE(xt, entry);
LIST_INSERT_HEAD(&conf->tnbr_list, xt, entry);
@@ -997,7 +1072,8 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
}
/* update existing pseudowire */
- if (pw->lsr_id.s_addr != xp->lsr_id.s_addr)
+ if (pw->af != xp->af ||
+ ldp_addrcmp(pw->af, &pw->addr, &xp->addr))
reinstall_tnbr = 1;
else
reinstall_tnbr = 0;
@@ -1029,6 +1105,8 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
!reset_nbr && reinstall_pwfec)
l2vpn_pw_exit(pw);
pw->lsr_id = xp->lsr_id;
+ pw->af = xp->af;
+ pw->addr = xp->addr;
pw->pwid = xp->pwid;
strlcpy(pw->ifname, xp->ifname, sizeof(pw->ifname));
pw->ifindex = xp->ifindex;
diff --git a/usr.sbin/ldpd/ldpd.conf.5 b/usr.sbin/ldpd/ldpd.conf.5
index 49de2c22dc6..050a2a9ff6e 100644
--- a/usr.sbin/ldpd/ldpd.conf.5
+++ b/usr.sbin/ldpd/ldpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ldpd.conf.5,v 1.26 2016/05/23 18:49:22 renato Exp $
+.\" $OpenBSD: ldpd.conf.5,v 1.27 2016/05/23 18:58:48 renato Exp $
.\"
.\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
.\" Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
@@ -31,7 +31,7 @@ daemon implements the Label Distribution Protocol as described in RFC 5036.
.Sh SECTIONS
The
.Nm
-config file is divided into six main sections.
+config file is divided into seven main sections.
.Bl -tag -width xxxx
.It Sy Macros
User-defined variables may be defined and used later, simplifying the
@@ -39,6 +39,8 @@ configuration file.
.It Sy Global Configuration
Global settings for
.Xr ldpd 8 .
+.It Sy Address-Family Configuration
+Address-family specific parameters.
.It Sy Interfaces Configuration
Interface-specific parameters.
.It Sy Targeted Neighbors Configuration
@@ -78,18 +80,19 @@ neighbor 10.0.1.5 {
}
.Ed
.Sh GLOBAL CONFIGURATION
-All interface related settings can be configured globally and per interface.
+Several settings can be configured globally or within a more restricted scope,
+like per address-family or per interface.
The only settings that can be set globally and not overruled are listed below.
.Pp
.Bl -tag -width Ds -compact
.It Xo
-.Ic explicit-null
+.Ic ds-cisco-interop
.Pq Ic yes Ns | Ns Ic no
.Xc
If set to
.Ic yes ,
-advertise explicit-null labels in place of implicit-null labels for directly
-connected prefixes.
+Cisco non-compliant format will be used to send and interpret the Dual-Stack
+capability TLV.
The default is
.Ic no .
.Pp
@@ -104,15 +107,48 @@ table.
The default is
.Ic yes .
.Pp
-.It Ic keepalive Ar seconds
-Set the keepalive timeout in seconds.
-The default value is 180; valid range is 1\-65535.
-.Pp
.It Ic router-id Ar address
Set the router ID; in combination with labelspace it forms the LSR-ID.
If not specified, the numerically lowest IP address of the router will be used.
.Pp
.It Xo
+.Ic transport-preference
+.Pq Ic ipv4 Ns | Ns Ic ipv6
+.Xc
+Specify the prefered address-family for TCP transport connections.
+If two dual-stack LSRs preferences does not match, no LDP session will
+be established.
+The default is
+.Ic ipv6 .
+.El
+.Sh ADDRESS-FAMILY CONFIGURATION
+Each address-family can have several parameters configured
+individually, otherwise they are inherited.
+.Bd -literal -offset indent
+address-family ipv6 {
+ explicit-null yes
+ transport-address 2001:db8::50
+ interface em0
+}
+.Ed
+.Pp
+.Bl -tag -width Ds -compact
+.It Xo
+.Ic explicit-null
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+If set to
+.Ic yes ,
+advertise explicit-null labels in place of implicit-null labels for directly
+connected prefixes.
+The default is
+.Ic no .
+.Pp
+.It Ic keepalive Ar seconds
+Set the keepalive timeout in seconds.
+The default value is 180; valid range is 3\-65535.
+.Pp
+.It Xo
.Ic targeted-hello-accept
.Pq Ic yes Ns | Ns Ic no
.Xc
@@ -125,13 +161,18 @@ The default is
.Pp
.It Ic transport-address Ar address
Set the local address to be used in the TCP sessions.
-If not specified, the router-id will be used.
+For the IPv4 address-family, the router-id will be used if this option is not specified.
+For the IPv6 address-family, this option must be specified.
.El
.Sh INTERFACES
Each interface can have several parameters configured individually, otherwise
they are inherited.
.Bd -literal -offset indent
-interface em0 {
+address-family ipv4 {
+ interface em0 {
+ link-hello-holdtime 9
+ link-hello-interval 3
+ }
}
.Ed
.Pp
@@ -152,7 +193,14 @@ The default value is 5; valid range is 1\-65535.
Each targeted neighbor can have several parameters configured individually,
otherwise they are inherited.
.Bd -literal -offset indent
-targeted-neighbor A.B.C.D {
+address-family ipv4 {
+ targeted-neighbor A.B.C.D {
+ targeted-hello-holdtime 90
+ targeted-hello-interval 10
+ }
+}
+address-family ipv6 {
+ targeted-neighbor 2001:db8::1
}
.Ed
.Pp
@@ -178,6 +226,7 @@ Note, however, that
uses the hello discovery mechanism to discover its neighbors.
Without an underlying adjacency these commands have no effect.
A neighbor is identified by its LSR-ID, not by its remote address.
+The neighbor-specific parameters apply for both LDPoIPv4 and LDPoIPv6 sessions.
.Bd -literal -offset indent
neighbor A.B.C.D {
}
@@ -264,9 +313,13 @@ preferred.
The default is
.Ic yes .
.Pp
-.It Ic neighbor Ar address
-Specify the endpoint of the pseudowire on the remote PE router.
+.It Ic neighbor-addr Ar address
+Specify the IPv4 or IPv6 address of the remote endpoint of the pseudowire.
A targeted neighbor will automatically be created for this address.
+By default, the LSR-ID of the remote endpoint of the pseudowire will be used.
+.Pp
+.It Ic neighbor-id Ar address
+Specify the LSR-ID of the remote endpoint of the pseudowire.
.Pp
.It Ic pw-id Ar number
Set the PW ID used to identify the pseudowire.
diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h
index 4962a09e678..ddd1ddcbd0c 100644
--- a/usr.sbin/ldpd/ldpd.h
+++ b/usr.sbin/ldpd/ldpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpd.h,v 1.70 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: ldpd.h,v 1.71 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -127,6 +127,16 @@ enum imsg_type {
IMSG_RECONF_END
};
+union ldpd_addr {
+ struct in_addr v4;
+ struct in6_addr v6;
+};
+
+#define IN6_IS_SCOPE_EMBED(a) \
+ ((IN6_IS_ADDR_LINKLOCAL(a)) || \
+ (IN6_IS_ADDR_MC_LINKLOCAL(a)) || \
+ (IN6_IS_ADDR_MC_INTFACELOCAL(a)))
+
/* interface states */
#define IF_STA_DOWN 0x01
#define IF_STA_ACTIVE 0x02
@@ -180,11 +190,12 @@ TAILQ_HEAD(mapping_head, mapping_entry);
struct map {
uint8_t type;
uint32_t messageid;
- union map_fec {
+ union {
struct {
- struct in_addr prefix;
+ uint16_t af;
+ union ldpd_addr prefix;
uint8_t prefixlen;
- } ipv4;
+ } prefix;
struct {
uint16_t type;
uint32_t pwid;
@@ -216,29 +227,37 @@ struct notify_msg {
struct if_addr {
LIST_ENTRY(if_addr) entry;
- struct in_addr addr;
- struct in_addr mask;
- struct in_addr dstbrd;
+ int af;
+ union ldpd_addr addr;
+ uint8_t prefixlen;
+ union ldpd_addr dstbrd;
};
LIST_HEAD(if_addr_head, if_addr);
-struct iface {
- LIST_ENTRY(iface) entry;
- struct event hello_timer;
-
- char name[IF_NAMESIZE];
- struct if_addr_head addr_list;
+struct iface_af {
+ struct iface *iface;
+ int af;
+ int enabled;
+ int state;
LIST_HEAD(, adj) adj_list;
-
time_t uptime;
- unsigned int ifindex;
- int state;
+ struct event hello_timer;
uint16_t hello_holdtime;
uint16_t hello_interval;
- uint16_t flags;
+};
+
+struct iface {
+ LIST_ENTRY(iface) entry;
+ char name[IF_NAMESIZE];
+ unsigned int ifindex;
+ struct if_addr_head addr_list;
+ struct in6_addr linklocal;
enum iface_type type;
uint8_t if_type;
+ uint16_t flags;
uint8_t linkstate;
+ struct iface_af ipv4;
+ struct iface_af ipv6;
};
/* source of targeted hellos */
@@ -246,8 +265,8 @@ struct tnbr {
LIST_ENTRY(tnbr) entry;
struct event hello_timer;
struct adj *adj;
- struct in_addr addr;
-
+ int af;
+ union ldpd_addr addr;
int state;
uint16_t hello_holdtime;
uint16_t hello_interval;
@@ -289,6 +308,8 @@ struct l2vpn_pw {
LIST_ENTRY(l2vpn_pw) entry;
struct l2vpn *l2vpn;
struct in_addr lsr_id;
+ int af;
+ union ldpd_addr addr;
uint32_t pwid;
char ifname[IF_NAMESIZE];
unsigned int ifindex;
@@ -335,30 +356,49 @@ enum hello_type {
HELLO_TARGETED
};
+struct ldpd_af_conf {
+ uint16_t keepalive;
+ uint16_t thello_holdtime;
+ uint16_t thello_interval;
+ union ldpd_addr trans_addr;
+ int flags;
+};
+#define F_LDPD_AF_ENABLED 0x0001
+#define F_LDPD_AF_THELLO_ACCEPT 0x0002
+#define F_LDPD_AF_EXPNULL 0x0004
+
struct ldpd_conf {
struct in_addr rtr_id;
- struct in_addr trans_addr;
+ struct ldpd_af_conf ipv4;
+ struct ldpd_af_conf ipv6;
LIST_HEAD(, iface) iface_list;
LIST_HEAD(, tnbr) tnbr_list;
LIST_HEAD(, nbr_params) nbrp_list;
LIST_HEAD(, l2vpn) l2vpn_list;
- uint16_t keepalive;
- uint16_t thello_holdtime;
- uint16_t thello_interval;
+ uint16_t trans_pref;
int flags;
};
#define F_LDPD_NO_FIB_UPDATE 0x0001
-#define F_LDPD_TH_ACCEPT 0x0002
-#define F_LDPD_EXPNULL 0x0004
+#define F_LDPD_DS_CISCO_INTEROP 0x0002
+
+struct ldpd_af_global {
+ struct event disc_ev;
+ struct event edisc_ev;
+ int ldp_disc_socket;
+ int ldp_edisc_socket;
+ int ldp_session_socket;
+};
struct ldpd_global {
int cmd_opts;
time_t uptime;
+ struct ldpd_af_global ipv4;
+ struct ldpd_af_global ipv6;
int pfkeysock;
- int ldp_disc_socket;
- int ldp_edisc_socket;
- int ldp_session_socket;
struct if_addr_head addr_list;
+ LIST_HEAD(, adj) adj_list;
+ struct in_addr mcast_addr_v4;
+ struct in6_addr mcast_addr_v6;
TAILQ_HEAD(, pending_conn) pending_conns;
};
@@ -366,20 +406,22 @@ extern struct ldpd_global global;
/* kroute */
struct kroute {
- struct in_addr prefix;
- struct in_addr nexthop;
+ int af;
+ union ldpd_addr prefix;
+ uint8_t prefixlen;
+ union ldpd_addr nexthop;
uint32_t local_label;
uint32_t remote_label;
- uint16_t flags;
unsigned short ifindex;
- uint8_t prefixlen;
uint8_t priority;
+ uint16_t flags;
};
struct kpw {
unsigned short ifindex;
int pw_type;
- struct in_addr nexthop;
+ int af;
+ union ldpd_addr nexthop;
uint32_t local_label;
uint32_t remote_label;
uint8_t flags;
@@ -387,55 +429,62 @@ struct kpw {
struct kaddr {
unsigned short ifindex;
- struct in_addr addr;
- struct in_addr mask;
- struct in_addr dstbrd;
+ int af;
+ union ldpd_addr addr;
+ uint8_t prefixlen;
+ union ldpd_addr dstbrd;
};
struct kif {
char ifname[IF_NAMESIZE];
- uint64_t baudrate;
+ unsigned short ifindex;
int flags;
+ uint8_t link_state;
int mtu;
- unsigned short ifindex;
uint8_t if_type;
- uint8_t link_state;
+ uint64_t baudrate;
};
/* control data structures */
struct ctl_iface {
+ int af;
char name[IF_NAMESIZE];
- time_t uptime;
unsigned int ifindex;
int state;
- uint16_t adj_cnt;
uint16_t flags;
- uint16_t hello_holdtime;
- uint16_t hello_interval;
- enum iface_type type;
uint8_t linkstate;
+ enum iface_type type;
uint8_t if_type;
+ uint16_t hello_holdtime;
+ uint16_t hello_interval;
+ time_t uptime;
+ uint16_t adj_cnt;
};
struct ctl_adj {
+ int af;
struct in_addr id;
enum hello_type type;
char ifname[IF_NAMESIZE];
- struct in_addr src_addr;
+ union ldpd_addr src_addr;
uint16_t holdtime;
+ union ldpd_addr trans_addr;
};
struct ctl_nbr {
+ int af;
struct in_addr id;
- struct in_addr addr;
+ union ldpd_addr laddr;
+ union ldpd_addr raddr;
time_t uptime;
int nbr_state;
};
struct ctl_rt {
- struct in_addr prefix;
+ int af;
+ union ldpd_addr prefix;
uint8_t prefixlen;
- struct in_addr nexthop;
+ struct in_addr nexthop; /* lsr-id */
uint32_t local_label;
uint32_t remote_label;
uint8_t flags;
@@ -470,13 +519,11 @@ void kif_clear(void);
void kr_shutdown(void);
void kr_fib_couple(void);
void kr_fib_decouple(void);
-void kr_change_egress_label(int);
+void kr_change_egress_label(int, int);
void kr_dispatch_msg(int, short, void *);
void kr_show_route(struct imsg *);
void kr_ifinfo(char *, pid_t);
struct kif *kif_findname(char *);
-uint8_t mask2prefixlen(in_addr_t);
-in_addr_t prefixlen2mask(uint8_t);
int kmpw_set(struct kpw *);
int kmpw_unset(struct kpw *);
int kmpw_install(const char *, struct kpw *);
@@ -490,8 +537,25 @@ const char *notification_name(uint32_t);
/* util.c */
uint8_t mask2prefixlen(in_addr_t);
+uint8_t mask2prefixlen6(struct sockaddr_in6 *);
in_addr_t prefixlen2mask(uint8_t);
-int bad_ip_addr(struct in_addr);
+struct in6_addr *prefixlen2mask6(uint8_t);
+void ldp_applymask(int, union ldpd_addr *,
+ const union ldpd_addr *, int);
+int ldp_addrcmp(int, const union ldpd_addr *,
+ const union ldpd_addr *);
+int ldp_addrisset(int, const union ldpd_addr *);
+int ldp_prefixcmp(int, const union ldpd_addr *,
+ const union ldpd_addr *, uint8_t);
+int bad_addr_v4(struct in_addr);
+int bad_addr_v6(struct in6_addr *);
+int bad_addr(int, union ldpd_addr *);
+void embedscope(struct sockaddr_in6 *);
+void recoverscope(struct sockaddr_in6 *);
+void addscope(struct sockaddr_in6 *, uint32_t);
+void clearscope(struct in6_addr *);
+struct sockaddr *addr2sa(int af, union ldpd_addr *, uint16_t);
+void sa2addr(struct sockaddr *, int *, union ldpd_addr *);
/* ldpd.c */
void main_imsg_compose_ldpe(int, pid_t, void *, uint16_t);
@@ -506,8 +570,12 @@ void evbuf_event_add(struct evbuf *);
void evbuf_init(struct evbuf *, int, void (*)(int, short, void *), void *);
void evbuf_clear(struct evbuf *);
+struct ldpd_af_conf *ldp_af_conf_get(struct ldpd_conf *, int);
+struct ldpd_af_global *ldp_af_global_get(struct ldpd_global *, int);
+int ldp_is_dual_stack(struct ldpd_conf *);
+
/* socket.c */
-int ldp_create_socket(enum socket_type);
+int ldp_create_socket(int, enum socket_type);
void sock_set_recvbuf(int);
int sock_set_reuse(int, int);
int sock_set_bindany(int, int);
@@ -516,6 +584,10 @@ int sock_set_ipv4_tos(int, int);
int sock_set_ipv4_recvif(int, int);
int sock_set_ipv4_mcast(struct iface *);
int sock_set_ipv4_mcast_loop(int);
+int sock_set_ipv6_dscp(int, int);
+int sock_set_ipv6_pktinfo(int, int);
+int sock_set_ipv6_mcast(struct iface *);
+int sock_set_ipv6_mcast_loop(int);
/* printconf.c */
void print_config(struct ldpd_conf *);
diff --git a/usr.sbin/ldpd/ldpe.c b/usr.sbin/ldpd/ldpe.c
index 228e1f9bc5e..a269298d55d 100644
--- a/usr.sbin/ldpd/ldpe.c
+++ b/usr.sbin/ldpd/ldpe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpe.c,v 1.56 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: ldpe.c,v 1.57 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -32,6 +32,7 @@
#include <pwd.h>
#include <unistd.h>
#include <event.h>
+#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
@@ -49,9 +50,7 @@ void ldpe_shutdown(void);
struct ldpd_conf *leconf = NULL, *nconf;
struct imsgev *iev_main;
struct imsgev *iev_lde;
-struct event disc_ev;
-struct event edisc_ev;
-struct event pfkey_ev;
+struct event pfkey_ev;
struct ldpd_sysdep sysdep;
/* ARGSUSED */
@@ -97,7 +96,12 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2],
fatalx("control socket setup failed");
LIST_INIT(&global.addr_list);
+ LIST_INIT(&global.adj_list);
TAILQ_INIT(&global.pending_conns);
+ if (inet_pton(AF_INET, AllRouters_v4, &global.mcast_addr_v4) != 1)
+ fatal("inet_pton");
+ if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1)
+ fatal("inet_pton");
global.pfkeysock = pfkey_init(&sysdep);
if ((pw = getpwnam(LDPD_USER)) == NULL)
@@ -159,9 +163,12 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2],
}
/* mark sockets as closed */
- global.ldp_disc_socket = -1;
- global.ldp_edisc_socket = -1;
- global.ldp_session_socket = -1;
+ global.ipv4.ldp_disc_socket = -1;
+ global.ipv4.ldp_edisc_socket = -1;
+ global.ipv4.ldp_session_socket = -1;
+ global.ipv6.ldp_disc_socket = -1;
+ global.ipv6.ldp_edisc_socket = -1;
+ global.ipv6.ldp_session_socket = -1;
/* listen on ldpd control socket */
TAILQ_INIT(&ctl_conns);
@@ -185,6 +192,7 @@ void
ldpe_shutdown(void)
{
struct if_addr *if_addr;
+ struct adj *adj;
control_cleanup();
config_clear(leconf);
@@ -193,13 +201,16 @@ ldpe_shutdown(void)
event_del(&pfkey_ev);
close(global.pfkeysock);
}
- ldpe_close_sockets();
+ ldpe_close_sockets(AF_INET);
+ ldpe_close_sockets(AF_INET6);
/* remove addresses from global list */
while ((if_addr = LIST_FIRST(&global.addr_list)) != NULL) {
LIST_REMOVE(if_addr, entry);
free(if_addr);
}
+ while ((adj = LIST_FIRST(&global.adj_list)) != NULL)
+ adj_del(adj);
/* clean up */
msgbuf_write(&iev_lde->ibuf.w);
@@ -244,6 +255,7 @@ ldpe_dispatch_main(int fd, short event, void *bula)
struct imsgbuf *ibuf = &iev->ibuf;
struct iface *iface = NULL;
struct kif *kif;
+ int af;
enum socket_type *socket_type;
static int disc_socket = -1;
static int edisc_socket = -1;
@@ -282,7 +294,7 @@ ldpe_dispatch_main(int fd, short event, void *bula)
iface->flags = kif->flags;
iface->linkstate = kif->link_state;
- if_update(iface);
+ if_update(iface, AF_UNSPEC);
break;
case IMSG_NEWADDR:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
@@ -299,9 +311,11 @@ ldpe_dispatch_main(int fd, short event, void *bula)
if_addr_del(imsg.data);
break;
case IMSG_CLOSE_SOCKETS:
- ldpe_close_sockets();
- if_update_all();
- tnbr_update_all();
+ af = imsg.hdr.peerid;
+
+ ldpe_close_sockets(af);
+ if_update_all(af);
+ tnbr_update_all(af);
disc_socket = -1;
edisc_socket = -1;
@@ -328,6 +342,7 @@ ldpe_dispatch_main(int fd, short event, void *bula)
}
break;
case IMSG_SETUP_SOCKETS:
+ af = imsg.hdr.peerid;
if (disc_socket == -1 || edisc_socket == -1 ||
session_socket == -1) {
if (disc_socket != -1)
@@ -339,10 +354,10 @@ ldpe_dispatch_main(int fd, short event, void *bula)
break;
}
- ldpe_setup_sockets(disc_socket, edisc_socket,
+ ldpe_setup_sockets(af, disc_socket, edisc_socket,
session_socket);
- if_update_all();
- tnbr_update_all();
+ if_update_all(af);
+ tnbr_update_all(af);
break;
case IMSG_RECONF_CONF:
if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
@@ -361,7 +376,10 @@ ldpe_dispatch_main(int fd, short event, void *bula)
memcpy(niface, imsg.data, sizeof(struct iface));
LIST_INIT(&niface->addr_list);
- LIST_INIT(&niface->adj_list);
+ LIST_INIT(&niface->ipv4.adj_list);
+ LIST_INIT(&niface->ipv6.adj_list);
+ niface->ipv4.iface = niface;
+ niface->ipv6.iface = niface;
LIST_INSERT_HEAD(&nconf->iface_list, niface, entry);
break;
@@ -577,79 +595,103 @@ ldpe_dispatch_pfkey(int fd, short event, void *bula)
}
void
-ldpe_setup_sockets(int disc_socket, int edisc_socket, int session_socket)
+ldpe_setup_sockets(int af, int disc_socket, int edisc_socket, int session_socket)
{
+ struct ldpd_af_global *af_global;
+
+ af_global = ldp_af_global_get(&global, af);
+
/* discovery socket */
- global.ldp_disc_socket = disc_socket;
- event_set(&disc_ev, global.ldp_disc_socket,
+ af_global->ldp_disc_socket = disc_socket;
+ event_set(&af_global->disc_ev, af_global->ldp_disc_socket,
EV_READ|EV_PERSIST, disc_recv_packet, NULL);
- event_add(&disc_ev, NULL);
+ event_add(&af_global->disc_ev, NULL);
/* extended discovery socket */
- global.ldp_edisc_socket = edisc_socket;
- event_set(&edisc_ev, global.ldp_edisc_socket,
+ af_global->ldp_edisc_socket = edisc_socket;
+ event_set(&af_global->edisc_ev, af_global->ldp_edisc_socket,
EV_READ|EV_PERSIST, disc_recv_packet, NULL);
- event_add(&edisc_ev, NULL);
+ event_add(&af_global->edisc_ev, NULL);
/* session socket */
- global.ldp_session_socket = session_socket;
- accept_add(global.ldp_session_socket, session_accept, NULL);
+ af_global->ldp_session_socket = session_socket;
+ accept_add(af_global->ldp_session_socket, session_accept, NULL);
}
void
-ldpe_close_sockets(void)
+ldpe_close_sockets(int af)
{
+ struct ldpd_af_global *af_global;
+
+ af_global = ldp_af_global_get(&global, af);
+
/* discovery socket */
- if (event_initialized(&disc_ev))
- event_del(&disc_ev);
- if (global.ldp_disc_socket != -1) {
- close(global.ldp_disc_socket);
- global.ldp_disc_socket = -1;
+ if (event_initialized(&af_global->disc_ev))
+ event_del(&af_global->disc_ev);
+ if (af_global->ldp_disc_socket != -1) {
+ close(af_global->ldp_disc_socket);
+ af_global->ldp_disc_socket = -1;
}
/* extended discovery socket */
- if (event_initialized(&edisc_ev))
- event_del(&edisc_ev);
- if (global.ldp_edisc_socket != -1) {
- close(global.ldp_edisc_socket);
- global.ldp_edisc_socket = -1;
+ if (event_initialized(&af_global->edisc_ev))
+ event_del(&af_global->edisc_ev);
+ if (af_global->ldp_edisc_socket != -1) {
+ close(af_global->ldp_edisc_socket);
+ af_global->ldp_edisc_socket = -1;
}
/* session socket */
- if (global.ldp_session_socket != -1) {
- accept_del(global.ldp_session_socket);
- close(global.ldp_session_socket);
- global.ldp_session_socket = -1;
+ if (af_global->ldp_session_socket != -1) {
+ accept_del(af_global->ldp_session_socket);
+ close(af_global->ldp_session_socket);
+ af_global->ldp_session_socket = -1;
+ }
+}
+
+void
+ldpe_reset_nbrs(int af)
+{
+ struct nbr *nbr;
+
+ RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
+ if (nbr->af == af)
+ session_shutdown(nbr, S_SHUTDOWN, 0, 0);
}
}
void
-ldpe_reset_nbrs(void)
+ldpe_reset_ds_nbrs(void)
{
struct nbr *nbr;
- RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id)
- session_shutdown(nbr, S_SHUTDOWN, 0, 0);
+ RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
+ if (nbr->ds_tlv)
+ session_shutdown(nbr, S_SHUTDOWN, 0, 0);
+ }
}
void
-ldpe_remove_dynamic_tnbrs(void)
+ldpe_remove_dynamic_tnbrs(int af)
{
struct tnbr *tnbr, *safe;
LIST_FOREACH_SAFE(tnbr, &leconf->tnbr_list, entry, safe) {
+ if (tnbr->af != af)
+ continue;
+
tnbr->flags &= ~F_TNBR_DYNAMIC;
tnbr_check(tnbr);
}
}
void
-ldpe_stop_init_backoff(void)
+ldpe_stop_init_backoff(int af)
{
struct nbr *nbr;
RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
- if (nbr_pending_idtimer(nbr)) {
+ if (nbr->af == af && nbr_pending_idtimer(nbr)) {
nbr_stop_idtimer(nbr);
nbr_establish_connection(nbr);
}
@@ -657,14 +699,19 @@ ldpe_stop_init_backoff(void)
}
void
-ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
+ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx)
{
struct iface *iface;
+ struct iface_af *ia;
struct ctl_iface *ictl;
LIST_FOREACH(iface, &leconf->iface_list, entry) {
if (idx == 0 || idx == iface->ifindex) {
- ictl = if_to_ctl(iface);
+ ia = iface_af_get(iface, af);
+ if (!ia->enabled)
+ continue;
+
+ ictl = if_to_ctl(ia);
imsg_compose_event(&c->iev,
IMSG_CTL_SHOW_INTERFACE,
0, 0, -1, ictl, sizeof(struct ctl_iface));
@@ -673,28 +720,35 @@ ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
}
void
+ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
+{
+ ldpe_iface_af_ctl(c, AF_INET, idx);
+ ldpe_iface_af_ctl(c, AF_INET6, idx);
+}
+
+void
ldpe_adj_ctl(struct ctl_conn *c)
{
+ struct nbr *nbr;
struct adj *adj;
- struct iface *iface;
- struct tnbr *tnbr;
struct ctl_adj *actl;
- /* basic discovery mechanism */
- LIST_FOREACH(iface, &leconf->iface_list, entry)
- LIST_FOREACH(adj, &iface->adj_list, iface_entry) {
+ RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) {
+ LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) {
actl = adj_to_ctl(adj);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY,
0, 0, -1, actl, sizeof(struct ctl_adj));
}
-
- /* extended discovery mechanism */
- LIST_FOREACH(tnbr, &leconf->tnbr_list, entry)
- if (tnbr->adj) {
- actl = adj_to_ctl(tnbr->adj);
- imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY,
- 0, 0, -1, actl, sizeof(struct ctl_adj));
- }
+ }
+ /* show adjacencies not associated with any neighbor */
+ LIST_FOREACH(adj, &global.adj_list, global_entry) {
+ if (adj->nbr != NULL)
+ continue;
+
+ actl = adj_to_ctl(adj);
+ imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0,
+ -1, actl, sizeof(struct ctl_adj));
+ }
imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
}
@@ -705,7 +759,7 @@ ldpe_nbr_ctl(struct ctl_conn *c)
struct nbr *nbr;
struct ctl_nbr *nctl;
- RB_FOREACH(nbr, nbr_pid_head, &nbrs_by_pid) {
+ RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) {
nctl = nbr_to_ctl(nbr);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl,
sizeof(struct ctl_nbr));
diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h
index 77cc98dff40..8caea614685 100644
--- a/usr.sbin/ldpd/ldpe.h
+++ b/usr.sbin/ldpd/ldpe.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpe.h,v 1.51 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: ldpe.h,v 1.52 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
@@ -31,23 +31,25 @@
struct hello_source {
enum hello_type type;
struct {
- struct iface *iface;
- struct in_addr src_addr;
- } link;
+ struct iface_af *ia;
+ union ldpd_addr src_addr;
+ } link;
struct tnbr *target;
};
struct adj {
+ LIST_ENTRY(adj) global_entry;
LIST_ENTRY(adj) nbr_entry;
- LIST_ENTRY(adj) iface_entry;
+ LIST_ENTRY(adj) ia_entry;
+ struct in_addr lsr_id;
struct nbr *nbr;
+ int ds_tlv;
struct hello_source source;
struct event inactivity_timer;
uint16_t holdtime;
- struct in_addr addr;
+ union ldpd_addr trans_addr;
};
-struct nbr;
struct tcp_conn {
struct nbr *nbr;
int fd;
@@ -71,13 +73,16 @@ struct nbr {
struct mapping_head release_list;
struct mapping_head abortreq_list;
- struct in_addr laddr; /* local address */
- struct in_addr raddr; /* remote address */
+ uint32_t peerid; /* unique ID in DB */
+ int af;
+ int ds_tlv;
+ int v4_enabled; /* announce/process v4 msgs */
+ int v6_enabled; /* announce/process v6 msgs */
struct in_addr id; /* lsr id */
-
+ union ldpd_addr laddr; /* local address */
+ union ldpd_addr raddr; /* remote address */
+ uint32_t raddr_scope; /* remote address scope (v6) */
time_t uptime;
- uint32_t peerid; /* unique ID in DB */
-
int fd;
int state;
int idtimer_cnt;
@@ -96,7 +101,8 @@ struct nbr {
struct pending_conn {
TAILQ_ENTRY(pending_conn) entry;
int fd;
- struct in_addr addr;
+ int af;
+ union ldpd_addr addr;
struct event ev_timeout;
};
#define PENDING_CONN_TIMEOUT 5
@@ -119,8 +125,8 @@ void accept_pause(void);
void accept_unpause(void);
/* hello.c */
-int send_hello(enum hello_type, struct iface *, struct tnbr *);
-void recv_hello(struct in_addr, struct ldp_msg *, struct in_addr,
+int send_hello(enum hello_type, struct iface_af *, struct tnbr *);
+void recv_hello(struct in_addr, struct ldp_msg *, int, union ldpd_addr *,
struct iface *, int, char *, uint16_t);
/* init.c */
@@ -139,7 +145,7 @@ void send_notification_full(struct tcp_conn *, struct notify_msg *);
int recv_notification(struct nbr *, char *, uint16_t);
/* address.c */
-void send_address(struct nbr *, struct if_addr *, int);
+void send_address(struct nbr *, int, struct if_addr *, int);
int recv_address(struct nbr *, char *, uint16_t);
/* labelmapping.c */
@@ -153,18 +159,21 @@ int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,
/* ldpe.c */
pid_t ldpe(struct ldpd_conf *, int[2], int[2], int[2]);
-int ldpe_imsg_compose_parent(int, pid_t, void *, uint16_t);
+int ldpe_imsg_compose_parent(int, pid_t, void *,
+ uint16_t);
int ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *,
uint16_t);
void ldpe_dispatch_main(int, short, void *);
void ldpe_dispatch_lde(int, short, void *);
void ldpe_dispatch_pfkey(int, short, void *);
-void ldpe_setup_sockets(int, int, int);
-void ldpe_close_sockets(void);
-void ldpe_reset_nbrs(void);
-void ldpe_remove_dynamic_tnbrs(void);
-void ldpe_stop_init_backoff(void);
+void ldpe_setup_sockets(int, int, int, int);
+void ldpe_close_sockets(int);
+void ldpe_reset_nbrs(int);
+void ldpe_reset_ds_nbrs(void);
+void ldpe_remove_dynamic_tnbrs(int);
+void ldpe_stop_init_backoff(int);
struct ctl_conn;
+void ldpe_iface_af_ctl(struct ctl_conn *, int, unsigned int);
void ldpe_iface_ctl(struct ctl_conn *, unsigned int);
void ldpe_adj_ctl(struct ctl_conn *);
void ldpe_nbr_ctl(struct ctl_conn *);
@@ -172,47 +181,55 @@ void mapping_list_add(struct mapping_head *, struct map *);
void mapping_list_clr(struct mapping_head *);
/* interface.c */
-int if_start(struct iface *);
-int if_reset(struct iface *);
-int if_update(struct iface *);
-void if_update_all(void);
+int if_start(struct iface *, int);
+int if_reset(struct iface *, int);
+void if_update_af(struct iface_af *, int);
+void if_update(struct iface *, int);
+void if_update_all(int);
struct iface *if_new(struct kif *);
void if_del(struct iface *);
struct iface *if_lookup(struct ldpd_conf *, unsigned short);
+struct iface_af *iface_af_get(struct iface *, int);
struct if_addr *if_addr_new(struct kaddr *);
struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
void if_addr_add(struct kaddr *);
void if_addr_del(struct kaddr *);
-struct ctl_iface *if_to_ctl(struct iface *);
+struct ctl_iface *if_to_ctl(struct iface_af *);
-int if_join_group(struct iface *, struct in_addr *);
-int if_leave_group(struct iface *, struct in_addr *);
+in_addr_t if_get_ipv4_addr(struct iface *);
+int if_join_ipv4_group(struct iface *, struct in_addr *);
+int if_leave_ipv4_group(struct iface *, struct in_addr *);
+int if_join_ipv6_group(struct iface *, struct in6_addr *);
+int if_leave_ipv6_group(struct iface *, struct in6_addr *);
/* adjacency.c */
-struct adj *adj_new(struct nbr *, struct hello_source *, struct in_addr);
+struct adj *adj_new(struct in_addr, struct hello_source *,
+ union ldpd_addr *);
void adj_del(struct adj *);
-struct adj *adj_find(struct nbr *, struct hello_source *);
+struct adj *adj_find(struct hello_source *);
+int adj_get_af(struct adj *adj);
void adj_start_itimer(struct adj *);
void adj_stop_itimer(struct adj *);
-struct tnbr *tnbr_new(struct ldpd_conf *, struct in_addr);
+struct tnbr *tnbr_new(struct ldpd_conf *, int, union ldpd_addr *);
void tnbr_del(struct tnbr *);
-struct tnbr *tnbr_find(struct ldpd_conf *, struct in_addr);
+struct tnbr *tnbr_find(struct ldpd_conf *, int, union ldpd_addr *);
struct tnbr *tnbr_check(struct tnbr *);
void tnbr_update(struct tnbr *);
-void tnbr_update_all(void);
+void tnbr_update_all(int);
struct ctl_adj *adj_to_ctl(struct adj *);
/* neighbor.c */
-struct nbr *nbr_new(struct in_addr, struct in_addr);
+struct nbr *nbr_new(struct in_addr, int, int, union ldpd_addr *, uint32_t);
void nbr_del(struct nbr *);
void nbr_update_peerid(struct nbr *);
struct nbr *nbr_find_ldpid(uint32_t);
-struct nbr *nbr_find_addr(struct in_addr);
+struct nbr *nbr_find_addr(int, union ldpd_addr *);
struct nbr *nbr_find_peerid(uint32_t);
+int nbr_adj_count(struct nbr *, int);
int nbr_fsm(struct nbr *, enum nbr_event);
int nbr_session_active_role(struct nbr *);
@@ -230,7 +247,7 @@ int nbr_pending_idtimer(struct nbr *);
int nbr_pending_connect(struct nbr *);
int nbr_establish_connection(struct nbr *);
-uint16_t nbr_get_keepalive(struct in_addr);
+uint16_t nbr_get_keepalive(int, struct in_addr);
struct nbr_params *nbr_params_new(struct in_addr);
struct nbr_params *nbr_params_find(struct ldpd_conf *, struct in_addr);
@@ -246,7 +263,8 @@ RB_PROTOTYPE(nbr_pid_head, nbr, pid_tree, nbr_pid_compare)
/* packet.c */
int gen_ldp_hdr(struct ibuf *, uint16_t);
int gen_msg_hdr(struct ibuf *, uint32_t, uint16_t);
-int send_packet(int, struct iface *, void *, size_t, struct sockaddr_in *);
+int send_packet(int, int, union ldpd_addr *, struct iface_af *, void *,
+ size_t);
void disc_recv_packet(int, short, void *);
void session_accept(int, short, void *);
void session_accept_nbr(struct nbr *, int);
@@ -257,9 +275,9 @@ void session_shutdown(struct nbr *, uint32_t, uint32_t, uint32_t);
struct tcp_conn *tcp_new(int, struct nbr *);
void tcp_close(struct tcp_conn *);
-struct pending_conn *pending_conn_new(int, struct in_addr);
+struct pending_conn *pending_conn_new(int, int, union ldpd_addr *);
void pending_conn_del(struct pending_conn *);
-struct pending_conn *pending_conn_find(struct in_addr);
+struct pending_conn *pending_conn_find(int, union ldpd_addr *);
void pending_conn_timeout(int, short, void *);
char *pkt_ptr; /* packet buffer */
diff --git a/usr.sbin/ldpd/log.c b/usr.sbin/ldpd/log.c
index 5f5374dea46..077189a8c17 100644
--- a/usr.sbin/ldpd/log.c
+++ b/usr.sbin/ldpd/log.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.c,v 1.24 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: log.c,v 1.25 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -28,6 +28,7 @@
#include <string.h>
#include <syslog.h>
#include <unistd.h>
+#include <netdb.h>
#include "ldpd.h"
#include "ldpe.h"
@@ -174,8 +175,92 @@ fatalx(const char *emsg)
fatal(emsg);
}
+#define NUM_LOGS 4
+const char *
+log_sockaddr(void *vp)
+{
+ static char buf[NUM_LOGS][NI_MAXHOST];
+ static int round = 0;
+ struct sockaddr *sa = vp;
+
+ round = (round + 1) % NUM_LOGS;
+
+ if (getnameinfo(sa, sa->sa_len, buf[round], NI_MAXHOST, NULL, 0,
+ NI_NUMERICHOST))
+ return ("(unknown)");
+ else
+ return (buf[round]);
+}
+
+const char *
+log_in6addr(const struct in6_addr *addr)
+{
+ struct sockaddr_in6 sa_in6;
+
+ memset(&sa_in6, 0, sizeof(sa_in6));
+ sa_in6.sin6_len = sizeof(sa_in6);
+ sa_in6.sin6_family = AF_INET6;
+ sa_in6.sin6_addr = *addr;
+
+ recoverscope(&sa_in6);
+
+ return (log_sockaddr(&sa_in6));
+}
+
+const char *
+log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex)
+{
+ struct sockaddr_in6 sa_in6;
+
+ memset(&sa_in6, 0, sizeof(sa_in6));
+ sa_in6.sin6_len = sizeof(sa_in6);
+ sa_in6.sin6_family = AF_INET6;
+ sa_in6.sin6_addr = *addr;
+
+ addscope(&sa_in6, ifindex);
+
+ return (log_sockaddr(&sa_in6));
+}
+
+const char *
+log_addr(int af, const union ldpd_addr *addr)
+{
+ static char buf[NUM_LOGS][INET6_ADDRSTRLEN];
+ static int round = 0;
+
+ switch (af) {
+ case AF_INET:
+ round = (round + 1) % NUM_LOGS;
+ if (inet_ntop(AF_INET, &addr->v4, buf[round],
+ sizeof(buf[round])) == NULL)
+ return ("???");
+ return (buf[round]);
+ case AF_INET6:
+ return (log_in6addr(&addr->v6));
+ default:
+ break;
+ }
+
+ return ("???");
+}
+
/* names */
const char *
+af_name(int af)
+{
+ switch (af) {
+ case AF_INET:
+ return ("ipv4");
+ case AF_INET6:
+ return ("ipv6");
+ case AF_MPLS:
+ return ("mpls");
+ default:
+ return ("UNKNOWN");
+ }
+}
+
+const char *
socket_name(int type)
{
switch (type) {
@@ -309,6 +394,10 @@ notification_name(uint32_t status)
return ("Generic Misconfiguration Error");
case S_WITHDRAW_MTHD:
return ("Label Withdraw PW Status Method");
+ case S_TRANS_MISMTCH:
+ return ("Transport Connection Mismatch");
+ case S_DS_NONCMPLNCE:
+ return ("Dual-Stack Noncompliance");
default:
snprintf(buf, sizeof(buf), "[%08x]", status);
return (buf);
@@ -339,11 +428,11 @@ log_hello_src(const struct hello_source *src)
switch (src->type) {
case HELLO_LINK:
snprintf(buffer, sizeof(buffer), "iface %s",
- src->link.iface->name);
+ src->link.ia->iface->name);
break;
case HELLO_TARGETED:
snprintf(buffer, sizeof(buffer), "source %s",
- inet_ntoa(src->target->addr));
+ log_addr(src->target->af, &src->target->addr));
break;
}
@@ -354,7 +443,7 @@ const char *
log_map(const struct map *map)
{
static char buf[64];
- char pstr[64];
+ int af;
switch (map->type) {
case MAP_TYPE_WILDCARD:
@@ -362,9 +451,20 @@ log_map(const struct map *map)
return ("???");
break;
case MAP_TYPE_PREFIX:
+ switch (map->fec.prefix.af) {
+ case AF_IPV4:
+ af = AF_INET;
+ break;
+ case AF_IPV6:
+ af = AF_INET6;
+ break;
+ default:
+ return ("???");
+ }
+
if (snprintf(buf, sizeof(buf), "%s/%u",
- inet_ntop(AF_INET, &map->fec.ipv4.prefix, pstr,
- sizeof(pstr)), map->fec.ipv4.prefixlen) == -1)
+ log_addr(af, &map->fec.prefix.prefix),
+ map->fec.prefix.prefixlen) == -1)
return ("???");
break;
case MAP_TYPE_PWID:
@@ -384,13 +484,19 @@ const char *
log_fec(const struct fec *fec)
{
static char buf[64];
- char pstr[32];
+ union ldpd_addr addr;
switch (fec->type) {
case FEC_TYPE_IPV4:
- if (snprintf(buf, sizeof(buf), "%s/%u",
- inet_ntop(AF_INET, &fec->u.ipv4.prefix, pstr,
- sizeof(pstr)), fec->u.ipv4.prefixlen) == -1)
+ addr.v4 = fec->u.ipv4.prefix;
+ if (snprintf(buf, sizeof(buf), "ipv4 %s/%u",
+ log_addr(AF_INET, &addr), fec->u.ipv4.prefixlen) == -1)
+ return ("???");
+ break;
+ case FEC_TYPE_IPV6:
+ addr.v6 = fec->u.ipv6.prefix;
+ if (snprintf(buf, sizeof(buf), "ipv6 %s/%u",
+ log_addr(AF_INET6, &addr), fec->u.ipv6.prefixlen) == -1)
return ("???");
break;
case FEC_TYPE_PWID:
diff --git a/usr.sbin/ldpd/log.h b/usr.sbin/ldpd/log.h
index 043cc2ffc2f..aedc26dccc1 100644
--- a/usr.sbin/ldpd/log.h
+++ b/usr.sbin/ldpd/log.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.h,v 1.9 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: log.h,v 1.10 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -21,6 +21,9 @@
#include <stdarg.h>
+struct in6_addr;
+union ldpd_addr;
+
void log_init(int);
void log_verbose(int);
void logit(int, const char *, ...);
@@ -31,6 +34,7 @@ void log_info(const char *, ...);
void log_debug(const char *, ...);
void fatal(const char *) __dead;
void fatalx(const char *) __dead;
+const char *af_name(int);
const char *socket_name(int);
const char *pw_type_name(uint16_t);
const char *log_map(const struct map *);
@@ -40,4 +44,9 @@ void log_rtmsg(unsigned char);
struct hello_source;
char *log_hello_src(const struct hello_source *);
+const char *log_in6addr(const struct in6_addr *);
+const char *log_in6addr_scope(const struct in6_addr *, unsigned int);
+const char *log_sockaddr(void *);
+const char *log_addr(int, const union ldpd_addr *);
+
#endif /* _LOG_H_ */
diff --git a/usr.sbin/ldpd/neighbor.c b/usr.sbin/ldpd/neighbor.c
index bee64588bb8..2d1c3dab295 100644
--- a/usr.sbin/ldpd/neighbor.c
+++ b/usr.sbin/ldpd/neighbor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: neighbor.c,v 1.67 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: neighbor.c,v 1.68 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -66,12 +66,12 @@ nbr_id_compare(struct nbr *a, struct nbr *b)
static __inline int
nbr_addr_compare(struct nbr *a, struct nbr *b)
{
- if (ntohl(a->raddr.s_addr) < ntohl(b->raddr.s_addr))
+ if (a->af < b->af)
return (-1);
- if (ntohl(a->raddr.s_addr) > ntohl(b->raddr.s_addr))
+ if (a->af > b->af)
return (1);
- return (0);
+ return (ldp_addrcmp(a->af, &a->raddr, &b->raddr));
}
static __inline int
@@ -188,7 +188,10 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event)
nbr_act_session_operational(nbr);
nbr_start_ktimer(nbr);
nbr_start_ktimeout(nbr);
- send_address(nbr, NULL, 0);
+ if (nbr->v4_enabled)
+ send_address(nbr, AF_INET, NULL, 0);
+ if (nbr->v6_enabled)
+ send_address(nbr, AF_INET6, NULL, 0);
nbr_send_labelmappings(nbr);
break;
case NBR_ACT_CONNECT_SETUP:
@@ -220,23 +223,40 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event)
}
struct nbr *
-nbr_new(struct in_addr id, struct in_addr addr)
+nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr,
+ uint32_t scope_id)
{
struct nbr *nbr;
struct nbr_params *nbrp;
+ struct adj *adj;
struct pending_conn *pconn;
- log_debug("%s: lsr-id %s", __func__, inet_ntoa(id));
+ log_debug("%s: lsr-id %s transport-address %s", __func__,
+ inet_ntoa(id), log_addr(af, addr));
if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
fatal(__func__);
LIST_INIT(&nbr->adj_list);
nbr->state = NBR_STA_PRESENT;
- nbr->id = id;
- nbr->laddr = leconf->trans_addr;
- nbr->raddr = addr;
nbr->peerid = 0;
+ nbr->af = af;
+ nbr->ds_tlv = ds_tlv;
+ if (af == AF_INET || ds_tlv)
+ nbr->v4_enabled = 1;
+ if (af == AF_INET6 || ds_tlv)
+ nbr->v6_enabled = 1;
+ nbr->id = id;
+ nbr->laddr = (ldp_af_conf_get(leconf, af))->trans_addr;
+ nbr->raddr = *addr;
+ nbr->raddr_scope = scope_id;
+
+ LIST_FOREACH(adj, &global.adj_list, global_entry) {
+ if (adj->lsr_id.s_addr == nbr->id.s_addr) {
+ adj->nbr = nbr;
+ LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry);
+ }
+ }
if (RB_INSERT(nbr_id_head, &nbrs_by_id, nbr) != NULL)
fatalx("nbr_new: RB_INSERT(nbrs_by_id) failed");
@@ -258,7 +278,7 @@ nbr_new(struct in_addr id, struct in_addr addr)
if (nbrp && pfkey_establish(nbr, nbrp) == -1)
fatalx("pfkey setup failed");
- pconn = pending_conn_find(nbr->raddr);
+ pconn = pending_conn_find(nbr->af, &nbr->raddr);
if (pconn) {
session_accept_nbr(nbr, pconn->fd);
pending_conn_del(pconn);
@@ -319,10 +339,11 @@ nbr_find_ldpid(uint32_t lsr_id)
}
struct nbr *
-nbr_find_addr(struct in_addr addr)
+nbr_find_addr(int af, union ldpd_addr *addr)
{
struct nbr n;
- n.raddr = addr;
+ n.af = af;
+ n.raddr = *addr;
return (RB_FIND(nbr_addr_head, &nbrs_by_addr, &n));
}
@@ -335,9 +356,22 @@ nbr_find_peerid(uint32_t peerid)
}
int
+nbr_adj_count(struct nbr *nbr, int af)
+{
+ struct adj *adj;
+ int total = 0;
+
+ LIST_FOREACH(adj, &nbr->adj_list, nbr_entry)
+ if (adj_get_af(adj) == af)
+ total++;
+
+ return (total);
+}
+
+int
nbr_session_active_role(struct nbr *nbr)
{
- if (ntohl(nbr->laddr.s_addr) > ntohl(nbr->raddr.s_addr))
+ if (ldp_addrcmp(nbr->af, &nbr->laddr, &nbr->raddr) > 0)
return (1);
return (0);
@@ -492,7 +526,7 @@ nbr_connect_cb(int fd, short event, void *arg)
close(nbr->fd);
errno = error;
log_debug("%s: error while connecting to %s: %s", __func__,
- inet_ntoa(nbr->raddr), strerror(errno));
+ log_addr(nbr->af, &nbr->raddr), strerror(errno));
return;
}
@@ -502,13 +536,14 @@ nbr_connect_cb(int fd, short event, void *arg)
int
nbr_establish_connection(struct nbr *nbr)
{
- struct sockaddr_in local_sa;
- struct sockaddr_in remote_sa;
+ struct sockaddr_storage local_sa;
+ struct sockaddr_storage remote_sa;
struct adj *adj;
struct nbr_params *nbrp;
int opt = 1;
- nbr->fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
+ nbr->fd = socket(nbr->af,
+ SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (nbr->fd == -1) {
log_warn("%s: error while creating socket", __func__);
return (-1);
@@ -529,34 +564,30 @@ nbr_establish_connection(struct nbr *nbr)
}
}
- memset(&local_sa, 0, sizeof(local_sa));
- local_sa.sin_family = AF_INET;
- local_sa.sin_port = htons(0);
- local_sa.sin_addr = nbr->laddr;
+ memcpy(&local_sa, addr2sa(nbr->af, &nbr->laddr, 0), sizeof(local_sa));
+ memcpy(&remote_sa, addr2sa(nbr->af, &nbr->raddr, LDP_PORT),
+ sizeof(local_sa));
+ if (nbr->af == AF_INET6 && nbr->raddr_scope)
+ addscope((struct sockaddr_in6 *)&remote_sa, nbr->raddr_scope);
- if (bind(nbr->fd, (struct sockaddr *) &local_sa,
- sizeof(struct sockaddr_in)) == -1) {
+ if (bind(nbr->fd, (struct sockaddr *)&local_sa,
+ local_sa.ss_len) == -1) {
log_warn("%s: error while binding socket to %s", __func__,
- inet_ntoa(local_sa.sin_addr));
+ log_sockaddr((struct sockaddr *)&local_sa));
close(nbr->fd);
return (-1);
}
- memset(&remote_sa, 0, sizeof(remote_sa));
- remote_sa.sin_family = AF_INET;
- remote_sa.sin_port = htons(LDP_PORT);
- remote_sa.sin_addr = nbr->raddr;
-
/*
* Send an extra hello to guarantee that the remote peer has formed
* an adjacency as well.
*/
LIST_FOREACH(adj, &nbr->adj_list, nbr_entry)
- send_hello(adj->source.type, adj->source.link.iface,
+ send_hello(adj->source.type, adj->source.link.ia,
adj->source.target);
if (connect(nbr->fd, (struct sockaddr *)&remote_sa,
- sizeof(remote_sa)) == -1) {
+ remote_sa.ss_len) == -1) {
if (errno == EINPROGRESS) {
event_set(&nbr->ev_connect, nbr->fd, EV_WRITE,
nbr_connect_cb, nbr);
@@ -564,7 +595,7 @@ nbr_establish_connection(struct nbr *nbr)
return (0);
}
log_warn("%s: error while connecting to %s", __func__,
- inet_ntoa(nbr->raddr));
+ log_sockaddr((struct sockaddr *)&remote_sa));
close(nbr->fd);
return (-1);
}
@@ -578,13 +609,19 @@ nbr_establish_connection(struct nbr *nbr)
int
nbr_act_session_operational(struct nbr *nbr)
{
+ struct lde_nbr lde_nbr;
+
nbr->idtimer_cnt = 0;
/* this is necessary to avoid ipc synchronization issues */
nbr_update_peerid(nbr);
+ memset(&lde_nbr, 0, sizeof(lde_nbr));
+ lde_nbr.id = nbr->id;
+ lde_nbr.v4_enabled = nbr->v4_enabled;
+ lde_nbr.v6_enabled = nbr->v6_enabled;
return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0,
- &nbr->id, sizeof(nbr->id)));
+ &lde_nbr, sizeof(lde_nbr)));
}
void
@@ -621,7 +658,7 @@ nbr_params_find(struct ldpd_conf *xconf, struct in_addr lsr_id)
}
uint16_t
-nbr_get_keepalive(struct in_addr lsr_id)
+nbr_get_keepalive(int af, struct in_addr lsr_id)
{
struct nbr_params *nbrp;
@@ -629,7 +666,7 @@ nbr_get_keepalive(struct in_addr lsr_id)
if (nbrp && (nbrp->flags & F_NBRP_KEEPALIVE))
return (nbrp->keepalive);
- return (leconf->keepalive);
+ return ((ldp_af_conf_get(leconf, af))->keepalive);
}
struct ctl_nbr *
@@ -638,8 +675,10 @@ nbr_to_ctl(struct nbr *nbr)
static struct ctl_nbr nctl;
struct timeval now;
+ nctl.af = nbr->af;
nctl.id = nbr->id;
- nctl.addr = nbr->raddr;
+ nctl.laddr = nbr->laddr;
+ nctl.raddr = nbr->raddr;
nctl.nbr_state = nbr->state;
gettimeofday(&now, NULL);
diff --git a/usr.sbin/ldpd/packet.c b/usr.sbin/ldpd/packet.c
index 878c59d4cd0..60e84b9bac9 100644
--- a/usr.sbin/ldpd/packet.c
+++ b/usr.sbin/ldpd/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.54 2016/05/23 17:43:42 renato Exp $ */
+/* $OpenBSD: packet.c,v 1.55 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -42,7 +42,7 @@
extern struct ldpd_conf *leconf;
extern struct ldpd_sysdep sysdep;
-struct iface *disc_find_iface(unsigned int, struct in_addr, int);
+struct iface *disc_find_iface(unsigned int, int, union ldpd_addr *, int);
ssize_t session_get_pdu(struct ibuf_read *, char **);
static int msgcnt = 0;
@@ -79,21 +79,40 @@ gen_msg_hdr(struct ibuf *buf, uint32_t type, uint16_t size)
/* send packets */
int
-send_packet(int fd, struct iface *iface, void *pkt, size_t len,
- struct sockaddr_in *dst)
+send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia,
+ void *pkt, size_t len)
{
- /* set outgoing interface for multicast traffic */
- if (iface && IN_MULTICAST(ntohl(dst->sin_addr.s_addr)))
- if (sock_set_ipv4_mcast(iface) == -1) {
- log_warn("%s: error setting multicast interface, %s",
- __func__, iface->name);
- return (-1);
+ struct sockaddr *sa;
+
+ switch (af) {
+ case AF_INET:
+ if (ia && IN_MULTICAST(ntohl(dst->v4.s_addr))) {
+ /* set outgoing interface for multicast traffic */
+ if (sock_set_ipv4_mcast(ia->iface) == -1) {
+ log_debug("%s: error setting multicast "
+ "interface, %s", __func__, ia->iface->name);
+ return (-1);
+ }
+ }
+ break;
+ case AF_INET6:
+ if (ia && IN6_IS_ADDR_MULTICAST(&dst->v6)) {
+ /* set outgoing interface for multicast traffic */
+ if (sock_set_ipv6_mcast(ia->iface) == -1) {
+ log_debug("%s: error setting multicast "
+ "interface, %s", __func__, ia->iface->name);
+ return (-1);
+ }
}
+ break;
+ default:
+ fatalx("send_packet: unknown af");
+ }
- if (sendto(fd, pkt, len, 0, (struct sockaddr *)dst,
- sizeof(*dst)) == -1) {
+ sa = addr2sa(af, dst, LDP_PORT);
+ if (sendto(fd, pkt, len, 0, sa, sa->sa_len) == -1) {
log_warn("%s: error sending packet to %s", __func__,
- inet_ntoa(dst->sin_addr));
+ log_sockaddr(sa));
return (-1);
}
@@ -101,20 +120,23 @@ send_packet(int fd, struct iface *iface, void *pkt, size_t len,
}
/* Discovery functions */
+#define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo))
void
disc_recv_packet(int fd, short event, void *bula)
{
union {
struct cmsghdr hdr;
- char buf[CMSG_SPACE(sizeof(struct sockaddr_dl))];
+ char buf[CMSG_SPACE(CMSG_MAXLEN)];
} cmsgbuf;
- struct sockaddr_in src;
struct msghdr msg;
+ struct sockaddr_storage from;
struct iovec iov;
char *buf;
struct cmsghdr *cmsg;
ssize_t r;
int multicast;
+ int af;
+ union ldpd_addr src;
unsigned int ifindex = 0;
struct iface *iface;
uint16_t len;
@@ -131,8 +153,8 @@ disc_recv_packet(int fd, short event, void *bula)
memset(&msg, 0, sizeof(msg));
iov.iov_base = buf = pkt_ptr;
iov.iov_len = IBUF_READ_SIZE;
- msg.msg_name = &src;
- msg.msg_namelen = sizeof(src);
+ msg.msg_name = &from;
+ msg.msg_namelen = sizeof(from);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &cmsgbuf.buf;
@@ -146,24 +168,31 @@ disc_recv_packet(int fd, short event, void *bula)
}
multicast = (msg.msg_flags & MSG_MCAST) ? 1 : 0;
- if (bad_ip_addr(src.sin_addr)) {
+ sa2addr((struct sockaddr *)&from, &af, &src);
+ if (bad_addr(af, &src)) {
log_debug("%s: invalid source address: %s", __func__,
- inet_ntoa(src.sin_addr));
+ log_addr(af, &src));
return;
}
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == IPPROTO_IP &&
+ if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP &&
cmsg->cmsg_type == IP_RECVIF) {
ifindex = ((struct sockaddr_dl *)
CMSG_DATA(cmsg))->sdl_index;
break;
}
+ if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 &&
+ cmsg->cmsg_type == IPV6_PKTINFO) {
+ ifindex = ((struct in6_pktinfo *)
+ CMSG_DATA(cmsg))->ipi6_ifindex;
+ break;
+ }
}
/* find a matching interface */
- iface = disc_find_iface(ifindex, src.sin_addr, multicast);
+ iface = disc_find_iface(ifindex, af, &src, multicast);
if (iface == NULL)
return;
@@ -171,7 +200,7 @@ disc_recv_packet(int fd, short event, void *bula)
len = (uint16_t)r;
if (len < (LDP_HDR_SIZE + LDP_MSG_SIZE) || len > LDP_MAX_LEN) {
log_debug("%s: bad packet size, source %s", __func__,
- inet_ntoa(src.sin_addr));
+ log_addr(af, &src));
return;
}
@@ -179,12 +208,12 @@ disc_recv_packet(int fd, short event, void *bula)
memcpy(&ldp_hdr, buf, sizeof(ldp_hdr));
if (ntohs(ldp_hdr.version) != LDP_VERSION) {
log_debug("%s: invalid LDP version %d, source %s", __func__,
- ntohs(ldp_hdr.version), inet_ntoa(src.sin_addr));
+ ntohs(ldp_hdr.version), log_addr(af, &src));
return;
}
if (ntohs(ldp_hdr.lspace_id) != 0) {
log_debug("%s: invalid label space %u, source %s", __func__,
- ntohs(ldp_hdr.lspace_id), inet_ntoa(src.sin_addr));
+ ntohs(ldp_hdr.lspace_id), log_addr(af, &src));
return;
}
/* check "PDU Length" field */
@@ -192,7 +221,7 @@ disc_recv_packet(int fd, short event, void *bula)
if ((pdu_len < (LDP_HDR_PDU_LEN + LDP_MSG_SIZE)) ||
(pdu_len > (len - LDP_HDR_DEAD_LEN))) {
log_debug("%s: invalid LDP packet length %u, source %s",
- __func__, ntohs(ldp_hdr.length), inet_ntoa(src.sin_addr));
+ __func__, ntohs(ldp_hdr.length), log_addr(af, &src));
return;
}
buf += LDP_HDR_SIZE;
@@ -211,7 +240,7 @@ disc_recv_packet(int fd, short event, void *bula)
msg_len = ntohs(ldp_msg.length);
if (msg_len < LDP_MSG_LEN || ((msg_len + LDP_MSG_DEAD_LEN) > pdu_len)) {
log_debug("%s: invalid LDP message length %u, source %s",
- __func__, ntohs(ldp_msg.length), inet_ntoa(src.sin_addr));
+ __func__, ntohs(ldp_msg.length), log_addr(af, &src));
return;
}
buf += LDP_MSG_SIZE;
@@ -220,43 +249,65 @@ disc_recv_packet(int fd, short event, void *bula)
/* switch LDP packet type */
switch (ntohs(ldp_msg.type)) {
case MSG_TYPE_HELLO:
- recv_hello(lsr_id, &ldp_msg, src.sin_addr, iface, multicast,
+ recv_hello(lsr_id, &ldp_msg, af, &src, iface, multicast,
buf, len);
break;
default:
log_debug("%s: unknown LDP packet type, source %s", __func__,
- inet_ntoa(src.sin_addr));
+ log_addr(af, &src));
}
}
struct iface *
-disc_find_iface(unsigned int ifindex, struct in_addr src,
+disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src,
int multicast)
{
struct iface *iface;
+ struct iface_af *ia;
struct if_addr *if_addr;
+ in_addr_t mask;
iface = if_lookup(leconf, ifindex);
if (iface == NULL)
return (NULL);
- if (!multicast)
- return (iface);
+ /*
+ * For unicast packets, we just need to make sure that the interface
+ * is enabled for the given address-family.
+ */
+ if (!multicast) {
+ ia = iface_af_get(iface, af);
+ if (ia->enabled)
+ return (iface);
+ return (NULL);
+ }
+
+ switch (af) {
+ case AF_INET:
+ LIST_FOREACH(if_addr, &iface->addr_list, entry) {
+ if (if_addr->af != AF_INET)
+ continue;
- LIST_FOREACH(if_addr, &iface->addr_list, 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;
+ switch (iface->type) {
+ case IF_TYPE_POINTOPOINT:
+ if (if_addr->dstbrd.v4.s_addr == src->v4.s_addr)
+ return (iface);
+ break;
+ default:
+ mask = prefixlen2mask(if_addr->prefixlen);
+ if ((if_addr->addr.v4.s_addr & mask) ==
+ (src->v4.s_addr & mask))
+ return (iface);
+ break;
+ }
}
+ break;
+ case AF_INET6:
+ if (IN6_IS_ADDR_LINKLOCAL(&src->v6))
+ return (iface);
+ break;
+ default:
+ fatalx("disc_find_iface: unknown af");
}
return (NULL);
@@ -265,9 +316,11 @@ disc_find_iface(unsigned int ifindex, struct in_addr src,
void
session_accept(int fd, short event, void *bula)
{
- struct sockaddr_in src;
+ struct sockaddr_storage src;
socklen_t len = sizeof(src);
int newfd;
+ int af;
+ union ldpd_addr addr;
struct nbr *nbr;
struct pending_conn *pconn;
@@ -290,12 +343,14 @@ session_accept(int fd, short event, void *bula)
return;
}
+ sa2addr((struct sockaddr *)&src, &af, &addr);
+
/*
* Since we don't support label spaces, we can identify this neighbor
* just by its source address. This way we don't need to wait for its
* Initialization message to know who we are talking to.
*/
- nbr = nbr_find_addr(src.sin_addr);
+ nbr = nbr_find_addr(af, &addr);
if (nbr == NULL) {
/*
* According to RFC 5036, we would need to send a No Hello
@@ -308,11 +363,11 @@ session_accept(int fd, short event, void *bula)
* message within this interval, so it's worth waiting before
* taking a more drastic measure.
*/
- pconn = pending_conn_find(src.sin_addr);
+ pconn = pending_conn_find(af, &addr);
if (pconn)
close(newfd);
else
- pending_conn_new(newfd, src.sin_addr);
+ pending_conn_new(newfd, af, &addr);
return;
}
/* protection against buggy implementations */
@@ -663,7 +718,7 @@ tcp_close(struct tcp_conn *tcp)
}
struct pending_conn *
-pending_conn_new(int fd, struct in_addr addr)
+pending_conn_new(int fd, int af, union ldpd_addr *addr)
{
struct pending_conn *pconn;
struct timeval tv;
@@ -672,7 +727,8 @@ pending_conn_new(int fd, struct in_addr addr)
fatal(__func__);
pconn->fd = fd;
- pconn->addr = addr;
+ pconn->af = af;
+ pconn->addr = *addr;
evtimer_set(&pconn->ev_timeout, pending_conn_timeout, pconn);
TAILQ_INSERT_TAIL(&global.pending_conns, pconn, entry);
@@ -696,12 +752,13 @@ pending_conn_del(struct pending_conn *pconn)
}
struct pending_conn *
-pending_conn_find(struct in_addr addr)
+pending_conn_find(int af, union ldpd_addr *addr)
{
struct pending_conn *pconn;
TAILQ_FOREACH(pconn, &global.pending_conns, entry)
- if (addr.s_addr == pconn->addr.s_addr)
+ if (af == pconn->af &&
+ ldp_addrcmp(af, addr, &pconn->addr) == 0)
return (pconn);
return (NULL);
@@ -714,7 +771,7 @@ pending_conn_timeout(int fd, short event, void *arg)
struct tcp_conn *tcp;
log_debug("%s: no adjacency with remote end: %s", __func__,
- inet_ntoa(pconn->addr));
+ log_addr(pconn->af, &pconn->addr));
/*
* Create a write buffer detached from any neighbor to send a
diff --git a/usr.sbin/ldpd/parse.y b/usr.sbin/ldpd/parse.y
index 193b1cb1f79..174bdd303fe 100644
--- a/usr.sbin/ldpd/parse.y
+++ b/usr.sbin/ldpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.49 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: parse.y,v 1.50 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
@@ -81,33 +81,41 @@ char *symget(const char *);
void clear_config(struct ldpd_conf *xconf);
uint32_t get_rtr_id(void);
-int host(const char *, struct in_addr *, struct in_addr *);
+int get_address(const char *, union ldpd_addr *);
+int get_af_address(const char *, int *, union ldpd_addr *);
static struct ldpd_conf *conf;
static int errors = 0;
+int af = AF_UNSPEC;
+struct ldpd_af_conf *af_conf = NULL;
struct iface *iface = NULL;
+struct iface_af *ia = NULL;
struct tnbr *tnbr = NULL;
struct nbr_params *nbrp = NULL;
struct l2vpn *l2vpn = NULL;
struct l2vpn_pw *pw = NULL;
struct config_defaults {
+ uint16_t keepalive;
uint16_t lhello_holdtime;
uint16_t lhello_interval;
uint16_t thello_holdtime;
uint16_t thello_interval;
+ union ldpd_addr trans_addr;
+ int afflags;
uint8_t pwflags;
};
struct config_defaults globaldefs;
+struct config_defaults afdefs;
struct config_defaults ifacedefs;
struct config_defaults tnbrdefs;
struct config_defaults pwdefs;
struct config_defaults *defs;
struct iface *conf_get_if(struct kif *);
-struct tnbr *conf_get_tnbr(struct in_addr);
+struct tnbr *conf_get_tnbr(union ldpd_addr *);
struct nbr_params *conf_get_nbrp(struct in_addr);
struct l2vpn *conf_get_l2vpn(char *);
struct l2vpn_if *conf_get_l2vpn_if(struct l2vpn *, struct kif *);
@@ -126,19 +134,19 @@ typedef struct {
%token INTERFACE TNEIGHBOR ROUTERID FIBUPDATE EXPNULL
%token LHELLOHOLDTIME LHELLOINTERVAL
%token THELLOHOLDTIME THELLOINTERVAL
-%token THELLOACCEPT
-%token KEEPALIVE TRANSADDRESS
+%token THELLOACCEPT AF IPV4 IPV6
+%token KEEPALIVE TRANSADDRESS TRANSPREFERENCE DSCISCOINTEROP
%token NEIGHBOR PASSWORD
%token L2VPN TYPE VPLS PWTYPE MTU BRIDGE
%token ETHERNET ETHERNETTAGGED STATUSTLV CONTROLWORD
-%token PSEUDOWIRE NEIGHBOR PWID
+%token PSEUDOWIRE NEIGHBORID NEIGHBORADDR PWID
%token EXTTAG
%token YES NO
%token INCLUDE
%token ERROR
%token <v.string> STRING
%token <v.number> NUMBER
-%type <v.number> yesno l2vpn_type pw_type
+%type <v.number> yesno ldp_af l2vpn_type pw_type
%type <v.string> string
%%
@@ -148,8 +156,7 @@ grammar : /* empty */
| grammar '\n'
| grammar conf_main '\n'
| grammar varset '\n'
- | grammar interface '\n'
- | grammar tneighbor '\n'
+ | grammar af '\n'
| grammar neighbor '\n'
| grammar l2vpn '\n'
| grammar error '\n' { file->errors++; }
@@ -187,6 +194,10 @@ yesno : YES { $$ = 1; }
| NO { $$ = 0; }
;
+ldp_af : IPV4 { $$ = AF_INET; }
+ | IPV6 { $$ = AF_INET6; }
+ ;
+
l2vpn_type : VPLS { $$ = L2VPN_TYPE_VPLS; }
;
@@ -211,7 +222,7 @@ conf_main : ROUTERID STRING {
YYERROR;
}
free($2);
- if (bad_ip_addr(conf->rtr_id)) {
+ if (bad_addr_v4(conf->rtr_id)) {
yyerror("invalid router-id");
YYERROR;
}
@@ -222,40 +233,114 @@ conf_main : ROUTERID STRING {
else
conf->flags &= ~F_LDPD_NO_FIB_UPDATE;
}
- | THELLOACCEPT yesno {
- if ($2 == 0)
- conf->flags &= ~F_LDPD_TH_ACCEPT;
- else
- conf->flags |= F_LDPD_TH_ACCEPT;
+ | TRANSPREFERENCE ldp_af {
+ conf->trans_pref = $2;
+
+ switch (conf->trans_pref) {
+ case AF_INET:
+ conf->trans_pref = DUAL_STACK_LDPOV4;
+ break;
+ case AF_INET6:
+ conf->trans_pref = DUAL_STACK_LDPOV6;
+ break;
+ default:
+ yyerror("invalid address-family");
+ YYERROR;
+ }
}
- | EXPNULL yesno {
- if ($2 == 0)
- conf->flags &= ~F_LDPD_EXPNULL;
+ | DSCISCOINTEROP yesno {
+ if ($2 == 1)
+ conf->flags |= F_LDPD_DS_CISCO_INTEROP;
else
- conf->flags |= F_LDPD_EXPNULL;
+ conf->flags &= ~F_LDPD_DS_CISCO_INTEROP;
}
- | KEEPALIVE NUMBER {
- if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) {
- yyerror("keepalive out of range (%d-%d)",
- MIN_KEEPALIVE, MAX_KEEPALIVE);
+ | af_defaults
+ | iface_defaults
+ | tnbr_defaults
+ ;
+
+af : AF ldp_af {
+ af = $2;
+ switch (af) {
+ case AF_INET:
+ af_conf = &conf->ipv4;
+ break;
+ case AF_INET6:
+ af_conf = &conf->ipv6;
+ break;
+ default:
+ yyerror("invalid address-family");
YYERROR;
}
- conf->keepalive = $2;
+
+ afdefs = *defs;
+ defs = &afdefs;
+ } af_block {
+ af_conf->keepalive = defs->keepalive;
+ af_conf->thello_holdtime = defs->thello_holdtime;
+ af_conf->thello_interval = defs->thello_interval;
+ af_conf->flags = defs->afflags;
+ af_conf->flags |= F_LDPD_AF_ENABLED;
+ af_conf = NULL;
+ af = AF_UNSPEC;
+ defs = &globaldefs;
}
- | TRANSADDRESS STRING {
- if (!inet_aton($2, &conf->trans_addr)) {
+ ;
+
+af_block : '{' optnl afopts_l '}'
+ | '{' optnl '}'
+ |
+ ;
+
+afopts_l : afopts_l afoptsl nl
+ | afoptsl optnl
+ ;
+
+afoptsl : TRANSADDRESS STRING {
+ if (get_address($2, &af_conf->trans_addr) == -1) {
yyerror("error parsing transport-address");
free($2);
YYERROR;
}
free($2);
- if (bad_ip_addr(conf->trans_addr)) {
+ if (bad_addr(af, &af_conf->trans_addr)) {
yyerror("invalid transport-address");
YYERROR;
}
+ if (af == AF_INET6 &&
+ IN6_IS_SCOPE_EMBED(&af_conf->trans_addr.v6)) {
+ yyerror("ipv6 transport-address can not be "
+ "link-local");
+ YYERROR;
+ }
}
+ | af_defaults
| iface_defaults
| tnbr_defaults
+ | interface
+ | tneighbor
+ ;
+
+af_defaults : THELLOACCEPT yesno {
+ if ($2 == 0)
+ defs->afflags &= ~F_LDPD_AF_THELLO_ACCEPT;
+ else
+ defs->afflags |= F_LDPD_AF_THELLO_ACCEPT;
+ }
+ | EXPNULL yesno {
+ if ($2 == 0)
+ defs->afflags &= ~F_LDPD_AF_EXPNULL;
+ else
+ defs->afflags |= F_LDPD_AF_EXPNULL;
+ }
+ | KEEPALIVE NUMBER {
+ if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) {
+ yyerror("keepalive out of range (%d-%d)",
+ MIN_KEEPALIVE, MAX_KEEPALIVE);
+ YYERROR;
+ }
+ defs->keepalive = $2;
+ }
;
iface_defaults : LHELLOHOLDTIME NUMBER {
@@ -344,22 +429,46 @@ pwopts : PWID NUMBER {
pw->pwid = $2;
}
- | NEIGHBOR STRING {
+ | NEIGHBORID STRING {
struct in_addr addr;
- if (inet_aton($2, &addr) == 0) {
- yyerror("error parsing neighbor address");
+ if (!inet_aton($2, &addr)) {
+ yyerror("error parsing neighbor-id");
free($2);
YYERROR;
}
free($2);
- if (bad_ip_addr(addr)) {
+ if (bad_addr_v4(addr)) {
yyerror("invalid neighbor-id");
YYERROR;
}
pw->lsr_id = addr;
}
+ | NEIGHBORADDR STRING {
+ int family;
+ union ldpd_addr addr;
+
+ if (get_af_address($2, &family, &addr) == -1) {
+ yyerror("error parsing neighbor address");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ if (bad_addr(family, &addr)) {
+ yyerror("invalid neighbor address");
+ YYERROR;
+ }
+ if (family == AF_INET6 &&
+ IN6_IS_SCOPE_EMBED(&addr.v6)) {
+ yyerror("neighbor address can not be "
+ "link-local");
+ YYERROR;
+ }
+
+ pw->af = family;
+ pw->addr = addr;
+ }
| pw_defaults
;
@@ -395,14 +504,16 @@ pseudowire : PSEUDOWIRE STRING {
YYERROR;
}
if (pw->lsr_id.s_addr == INADDR_ANY) {
- yyerror("missing pseudowire neighbor");
+ yyerror("missing pseudowire neighbor-id");
YYERROR;
}
LIST_FOREACH(l, &conf->l2vpn_list, entry) {
LIST_FOREACH(p, &l->pw_list, entry) {
if (pw != p &&
pw->pwid == p->pwid &&
- pw->lsr_id.s_addr == p->lsr_id.s_addr) {
+ pw->af == p->af &&
+ pw->lsr_id.s_addr ==
+ p->lsr_id.s_addr) {
yyerror("pseudowire already "
"configured");
YYERROR;
@@ -410,6 +521,15 @@ pseudowire : PSEUDOWIRE STRING {
}
}
+ /*
+ * If the neighbor address is not specified, use the
+ * neighbor id.
+ */
+ if (pw->af == AF_UNSPEC) {
+ pw->af = AF_INET;
+ pw->addr.v4 = pw->lsr_id;
+ }
+
pw->flags = defs->pwflags;
pw = NULL;
defs = &globaldefs;
@@ -521,13 +641,22 @@ interface : INTERFACE STRING {
if (iface == NULL)
YYERROR;
+ ia = iface_af_get(iface, af);
+ if (ia->enabled) {
+ yyerror("interface %s already configured for "
+ "address-family %s", kif->ifname,
+ af_name(af));
+ YYERROR;
+ }
+ ia->enabled = 1;
+
ifacedefs = *defs;
defs = &ifacedefs;
} interface_block {
- iface->hello_holdtime = defs->lhello_holdtime;
- iface->hello_interval = defs->lhello_interval;
+ ia->hello_holdtime = defs->lhello_holdtime;
+ ia->hello_interval = defs->lhello_interval;
iface = NULL;
- defs = &globaldefs;
+ defs = &afdefs;
}
;
@@ -541,21 +670,27 @@ interfaceopts_l : interfaceopts_l iface_defaults nl
;
tneighbor : TNEIGHBOR STRING {
- struct in_addr addr;
+ union ldpd_addr addr;
- if (inet_aton($2, &addr) == 0) {
+ if (get_address($2, &addr) == -1) {
yyerror("error parsing targeted-neighbor "
"address");
free($2);
YYERROR;
}
free($2);
- if (bad_ip_addr(addr)) {
+ if (bad_addr(af, &addr)) {
yyerror("invalid targeted-neighbor address");
YYERROR;
}
+ if (af == AF_INET6 &&
+ IN6_IS_SCOPE_EMBED(&addr.v6)) {
+ yyerror("targeted-neighbor address can not be "
+ "link-local");
+ YYERROR;
+ }
- tnbr = conf_get_tnbr(addr);
+ tnbr = conf_get_tnbr(&addr);
if (tnbr == NULL)
YYERROR;
@@ -565,7 +700,7 @@ tneighbor : TNEIGHBOR STRING {
tnbr->hello_holdtime = defs->thello_holdtime;
tnbr->hello_interval = defs->thello_interval;
tnbr = NULL;
- defs = &globaldefs;
+ defs = &afdefs;
}
;
@@ -582,13 +717,13 @@ neighbor : NEIGHBOR STRING {
struct in_addr addr;
if (inet_aton($2, &addr) == 0) {
- yyerror("error parsing neighbor address");
+ yyerror("error parsing neighbor-id");
free($2);
YYERROR;
}
free($2);
- if (bad_ip_addr(addr)) {
- yyerror("invalid neighbor address");
+ if (bad_addr_v4(addr)) {
+ yyerror("invalid neighbor-id");
YYERROR;
}
@@ -662,20 +797,26 @@ lookup(char *s)
{
/* this has to be sorted always */
static const struct keywords keywords[] = {
+ {"address-family", AF},
{"bridge", BRIDGE},
{"control-word", CONTROLWORD},
+ {"ds-cisco-interop", DSCISCOINTEROP},
{"ethernet", ETHERNET},
{"ethernet-tagged", ETHERNETTAGGED},
{"explicit-null", EXPNULL},
{"fib-update", FIBUPDATE},
{"include", INCLUDE},
{"interface", INTERFACE},
+ {"ipv4", IPV4},
+ {"ipv6", IPV6},
{"keepalive", KEEPALIVE},
{"l2vpn", L2VPN},
{"link-hello-holdtime", LHELLOHOLDTIME},
{"link-hello-interval", LHELLOINTERVAL},
{"mtu", MTU},
{"neighbor", NEIGHBOR},
+ {"neighbor-addr", NEIGHBORADDR},
+ {"neighbor-id", NEIGHBORID},
{"no", NO},
{"password", PASSWORD},
{"pseudowire", PSEUDOWIRE},
@@ -688,6 +829,7 @@ lookup(char *s)
{"targeted-hello-interval", THELLOINTERVAL},
{"targeted-neighbor", TNEIGHBOR},
{"transport-address", TRANSADDRESS},
+ {"transport-preference", TRANSPREFERENCE},
{"type", TYPE},
{"vpls", VPLS},
{"yes", YES}
@@ -1020,15 +1162,14 @@ parse_config(char *filename)
if ((conf = calloc(1, sizeof(struct ldpd_conf))) == NULL)
fatal(__func__);
- conf->keepalive = DEFAULT_KEEPALIVE;
+ conf->trans_pref = DUAL_STACK_LDPOV6;
defs = &globaldefs;
+ defs->keepalive = DEFAULT_KEEPALIVE;
defs->lhello_holdtime = LINK_DFLT_HOLDTIME;
defs->lhello_interval = DEFAULT_HELLO_INTERVAL;
defs->thello_holdtime = TARGETED_DFLT_HOLDTIME;
defs->thello_interval = DEFAULT_HELLO_INTERVAL;
- conf->thello_holdtime = TARGETED_DFLT_HOLDTIME;
- conf->thello_interval = DEFAULT_HELLO_INTERVAL;
defs->pwflags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF;
if ((file = pushfile(filename,
@@ -1069,8 +1210,11 @@ parse_config(char *filename)
if (conf->rtr_id.s_addr == INADDR_ANY)
conf->rtr_id.s_addr = get_rtr_id();
- if (conf->trans_addr.s_addr == 0)
- conf->trans_addr = conf->rtr_id;
+
+ /* if the ipv4 transport-address is not set, use the router-id */
+ if ((conf->ipv4.flags & F_LDPD_AF_ENABLED) &&
+ conf->ipv4.trans_addr.v4.s_addr == INADDR_ANY)
+ conf->ipv4.trans_addr.v4 = conf->rtr_id;
return (conf);
}
@@ -1154,13 +1298,9 @@ conf_get_if(struct kif *kif)
{
struct iface *i;
- LIST_FOREACH(i, &conf->iface_list, entry) {
- if (i->ifindex == kif->ifindex) {
- yyerror("interface %s already configured",
- kif->ifname);
- return (NULL);
- }
- }
+ LIST_FOREACH(i, &conf->iface_list, entry)
+ if (i->ifindex == kif->ifindex)
+ return (i);
if (kif->if_type == IFT_LOOP ||
kif->if_type == IFT_CARP ||
@@ -1176,18 +1316,18 @@ conf_get_if(struct kif *kif)
}
struct tnbr *
-conf_get_tnbr(struct in_addr addr)
+conf_get_tnbr(union ldpd_addr *addr)
{
struct tnbr *t;
- t = tnbr_find(conf, addr);
+ t = tnbr_find(conf, af, addr);
if (t) {
yyerror("targeted neighbor %s already configured",
- inet_ntoa(addr));
+ log_addr(af, addr));
return (NULL);
}
- t = tnbr_new(conf, addr);
+ t = tnbr_new(conf, af, addr);
t->flags |= F_TNBR_CONFIGURED;
LIST_INSERT_HEAD(&conf->tnbr_list, t, entry);
return (t);
@@ -1343,22 +1483,36 @@ get_rtr_id(void)
}
int
-host(const char *s, struct in_addr *addr, struct in_addr *mask)
+get_address(const char *s, union ldpd_addr *addr)
{
- struct in_addr ina;
- int bits = 32;
+ switch (af) {
+ case AF_INET:
+ if (inet_pton(AF_INET, s, &addr->v4) != 1)
+ return (-1);
+ break;
+ case AF_INET6:
+ if (inet_pton(AF_INET6, s, &addr->v6) != 1)
+ return (-1);
+ break;
+ default:
+ return (-1);
+ }
- memset(&ina, 0, sizeof(struct in_addr));
- if (strrchr(s, '/') != NULL) {
- if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
- return (0);
- } else {
- if (inet_pton(AF_INET, s, &ina) != 1)
- return (0);
+ return (0);
+}
+
+int
+get_af_address(const char *s, int *family, union ldpd_addr *addr)
+{
+ if (inet_pton(AF_INET, s, &addr->v4) == 1) {
+ *family = AF_INET;
+ return (0);
}
- *addr = ina;
- mask->s_addr = prefixlen2mask(bits);
+ if (inet_pton(AF_INET6, s, &addr->v6) == 1) {
+ *family = AF_INET6;
+ return (0);
+ }
- return (1);
+ return (-1);
}
diff --git a/usr.sbin/ldpd/pfkey.c b/usr.sbin/ldpd/pfkey.c
index e1d470b6afa..c1a412fb137 100644
--- a/usr.sbin/ldpd/pfkey.c
+++ b/usr.sbin/ldpd/pfkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfkey.c,v 1.7 2016/05/23 18:28:22 renato Exp $ */
+/* $OpenBSD: pfkey.c,v 1.8 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -43,34 +43,19 @@ static int fd;
int pfkey_reply(int, uint32_t *);
int pfkey_send(int, uint8_t, uint8_t, uint8_t,
- struct in_addr *, struct in_addr *,
+ int, union ldpd_addr *, union ldpd_addr *,
uint32_t, uint8_t, int, char *, uint8_t, int, char *,
uint16_t, uint16_t);
-int pfkey_sa_add(struct in_addr *, struct in_addr *, uint8_t, char *,
+int pfkey_sa_add(int, union ldpd_addr *, union ldpd_addr *, uint8_t, char *,
uint32_t *);
-int pfkey_sa_remove(struct in_addr *, struct in_addr *, uint32_t *);
+int pfkey_sa_remove(int, union ldpd_addr *, union ldpd_addr *, uint32_t *);
int pfkey_md5sig_establish(struct nbr *, struct nbr_params *nbrp);
int pfkey_md5sig_remove(struct nbr *);
-static struct sockaddr *
-addr2sa(struct in_addr *addr)
-{
- static struct sockaddr_storage ss;
- struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
-
- memset(&ss, 0, sizeof(ss));
- sa_in->sin_family = AF_INET;
- sa_in->sin_len = sizeof(struct sockaddr_in);
- sa_in->sin_addr = *addr;
- sa_in->sin_port = htons(0);
-
- return ((struct sockaddr *)&ss);
-}
-
int
pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
- struct in_addr *src, struct in_addr *dst, uint32_t spi,
+ int af, union ldpd_addr *src, union ldpd_addr *dst, uint32_t spi,
uint8_t aalg, int alen, char *akey, uint8_t ealg, int elen, char *ekey,
uint16_t sport, uint16_t dport)
{
@@ -92,17 +77,37 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
/* we need clean sockaddr... no ports set */
memset(&ssrc, 0, sizeof(ssrc));
memset(&smask, 0, sizeof(smask));
- if ((saptr = addr2sa(src)))
+ if ((saptr = addr2sa(af, src, 0)))
memcpy(&ssrc, saptr, sizeof(ssrc));
- memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8);
+ switch (af) {
+ case AF_INET:
+ memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8);
+ break;
+ case AF_INET6:
+ memset(&((struct sockaddr_in6 *)&smask)->sin6_addr, 0xff,
+ 128/8);
+ break;
+ default:
+ return (-1);
+ }
smask.ss_family = ssrc.ss_family;
smask.ss_len = ssrc.ss_len;
memset(&sdst, 0, sizeof(sdst));
memset(&dmask, 0, sizeof(dmask));
- if ((saptr = addr2sa(dst)))
+ if ((saptr = addr2sa(af, dst, 0)))
memcpy(&sdst, saptr, sizeof(sdst));
- memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8);
+ switch (af) {
+ case AF_INET:
+ memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8);
+ break;
+ case AF_INET6:
+ memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr, 0xff,
+ 128/8);
+ break;
+ default:
+ return (-1);
+ }
dmask.ss_family = sdst.ss_family;
dmask.ss_len = sdst.ss_len;
@@ -341,16 +346,16 @@ pfkey_reply(int sd, uint32_t *spip)
}
int
-pfkey_sa_add(struct in_addr *src, struct in_addr *dst, uint8_t keylen,
+pfkey_sa_add(int af, union ldpd_addr *src, union ldpd_addr *dst, uint8_t keylen,
char *key, uint32_t *spi)
{
if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_GETSPI, 0,
- src, dst, 0, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0)
+ af, src, dst, 0, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0)
return (-1);
if (pfkey_reply(fd, spi) < 0)
return (-1);
if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_UPDATE, 0,
- src, dst, *spi, 0, keylen, key, 0, 0, NULL, 0, 0) < 0)
+ af, src, dst, *spi, 0, keylen, key, 0, 0, NULL, 0, 0) < 0)
return (-1);
if (pfkey_reply(fd, NULL) < 0)
return (-1);
@@ -358,10 +363,11 @@ pfkey_sa_add(struct in_addr *src, struct in_addr *dst, uint8_t keylen,
}
int
-pfkey_sa_remove(struct in_addr *src, struct in_addr *dst, uint32_t *spi)
+pfkey_sa_remove(int af, union ldpd_addr *src, union ldpd_addr *dst,
+ uint32_t *spi)
{
if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_DELETE, 0,
- src, dst, *spi, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0)
+ af, src, dst, *spi, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0)
return (-1);
if (pfkey_reply(fd, NULL) < 0)
return (-1);
@@ -375,12 +381,12 @@ pfkey_md5sig_establish(struct nbr *nbr, struct nbr_params *nbrp)
sleep(1);
if (!nbr->auth.spi_out)
- if (pfkey_sa_add(&nbr->laddr, &nbr->raddr,
+ if (pfkey_sa_add(nbr->af, &nbr->laddr, &nbr->raddr,
nbrp->auth.md5key_len, nbrp->auth.md5key,
&nbr->auth.spi_out) == -1)
return (-1);
if (!nbr->auth.spi_in)
- if (pfkey_sa_add(&nbr->raddr, &nbr->laddr,
+ if (pfkey_sa_add(nbr->af, &nbr->raddr, &nbr->laddr,
nbrp->auth.md5key_len, nbrp->auth.md5key,
&nbr->auth.spi_in) == -1)
return (-1);
@@ -393,11 +399,11 @@ int
pfkey_md5sig_remove(struct nbr *nbr)
{
if (nbr->auth.spi_out)
- if (pfkey_sa_remove(&nbr->laddr, &nbr->raddr,
+ if (pfkey_sa_remove(nbr->af, &nbr->laddr, &nbr->raddr,
&nbr->auth.spi_out) == -1)
return (-1);
if (nbr->auth.spi_in)
- if (pfkey_sa_remove(&nbr->raddr, &nbr->laddr,
+ if (pfkey_sa_remove(nbr->af, &nbr->raddr, &nbr->laddr,
&nbr->auth.spi_in) == -1)
return (-1);
diff --git a/usr.sbin/ldpd/printconf.c b/usr.sbin/ldpd/printconf.c
index 383fb1c8813..f1adc0ec9e1 100644
--- a/usr.sbin/ldpd/printconf.c
+++ b/usr.sbin/ldpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.21 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: printconf.c,v 1.22 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
@@ -27,9 +27,11 @@
#include "ldp.h"
#include "ldpd.h"
#include "ldpe.h"
+#include "log.h"
void print_mainconf(struct ldpd_conf *);
-void print_iface(struct iface *);
+void print_af(int, struct ldpd_conf *, struct ldpd_af_conf *);
+void print_iface(struct iface *, struct iface_af *);
void print_tnbr(struct tnbr *);
void print_nbrp(struct nbr_params *);
void print_l2vpn(struct l2vpn *);
@@ -45,36 +47,68 @@ print_mainconf(struct ldpd_conf *conf)
else
printf("fib-update yes\n");
- if (conf->flags & F_LDPD_TH_ACCEPT)
- printf("targeted-hello-accept yes\n");
+ if (conf->trans_pref == DUAL_STACK_LDPOV4)
+ printf("transport-preference ipv4\n");
+ else if (conf->trans_pref == DUAL_STACK_LDPOV6)
+ printf("transport-preference ipv6\n");
+
+ if (conf->flags & F_LDPD_DS_CISCO_INTEROP)
+ printf("ds-cisco-interop yes\n");
else
- printf("targeted-hello-accept no\n");
+ printf("ds-cisco-interop no\n");
+}
+
+void
+print_af(int af, struct ldpd_conf *conf, struct ldpd_af_conf *af_conf)
+{
+ struct iface *iface;
+ struct iface_af *ia;
+ struct tnbr *tnbr;
- if (conf->flags & F_LDPD_EXPNULL)
- printf("explicit-null yes\n");
+ printf("\naddress-family %s {\n", af_name(af));
+
+ if (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT)
+ printf("\ttargeted-hello-accept yes\n");
+ else
+ printf("\ttargeted-hello-accept no\n");
+
+ if (af_conf->flags & F_LDPD_AF_EXPNULL)
+ printf("\texplicit-null yes\n");
else
- printf("explicit-null no\n");
+ printf("\texplicit-null no\n");
+
+ printf("\tkeepalive %u\n", af_conf->keepalive);
+ printf("\ttransport-address %s\n", log_addr(af, &af_conf->trans_addr));
+
+ LIST_FOREACH(iface, &conf->iface_list, entry) {
+ ia = iface_af_get(iface, af);
+ if (ia->enabled)
+ print_iface(iface, ia);
+ }
+
+ LIST_FOREACH(tnbr, &conf->tnbr_list, entry)
+ if (tnbr->af == af && tnbr->flags & F_TNBR_CONFIGURED)
+ print_tnbr(tnbr);
- printf("keepalive %u\n", conf->keepalive);
- printf("transport-address %s\n", inet_ntoa(conf->trans_addr));
+ printf("}\n");
}
void
-print_iface(struct iface *iface)
+print_iface(struct iface *iface, struct iface_af *ia)
{
- printf("\ninterface %s {\n", iface->name);
- printf("\tlink-hello-holdtime %u\n", iface->hello_holdtime);
- printf("\tlink-hello-interval %u\n", iface->hello_interval);
- printf("}\n");
+ printf("\tinterface %s {\n", iface->name);
+ printf("\t\tlink-hello-holdtime %u\n", ia->hello_holdtime);
+ printf("\t\tlink-hello-interval %u\n", ia->hello_interval);
+ printf("\t}\n");
}
void
print_tnbr(struct tnbr *tnbr)
{
- printf("\ntargeted-neighbor %s {\n", inet_ntoa(tnbr->addr));
- printf("\ttargeted-hello-holdtime %u\n", tnbr->hello_holdtime);
- printf("\ttargeted-hello-interval %u\n", tnbr->hello_interval);
- printf("}\n");
+ printf("\n\ttargeted-neighbor %s {\n", log_addr(tnbr->af, &tnbr->addr));
+ printf("\t\ttargeted-hello-holdtime %u\n", tnbr->hello_holdtime);
+ printf("\t\ttargeted-hello-interval %u\n", tnbr->hello_interval);
+ printf("\t}\n");
}
void
@@ -119,7 +153,9 @@ void
print_pw(struct l2vpn_pw *pw)
{
printf("\tpseudowire %s {\n", pw->ifname);
- printf("\t\tneighbor %s\n", inet_ntoa(pw->lsr_id));
+
+ printf("\t\tneighbor-id %s\n", inet_ntoa(pw->lsr_id));
+ printf("\t\tneighbor-addr %s\n", log_addr(pw->af, &pw->addr));
printf("\t\tpw-id %u\n", pw->pwid);
if (pw->flags & F_PW_STATUSTLV_CONF)
@@ -138,19 +174,15 @@ print_pw(struct l2vpn_pw *pw)
void
print_config(struct ldpd_conf *conf)
{
- struct iface *iface;
- struct tnbr *tnbr;
struct nbr_params *nbrp;
struct l2vpn *l2vpn;
print_mainconf(conf);
- LIST_FOREACH(iface, &conf->iface_list, entry)
- print_iface(iface);
-
- LIST_FOREACH(tnbr, &conf->tnbr_list, entry)
- if (tnbr->flags & F_TNBR_CONFIGURED)
- print_tnbr(tnbr);
+ if (conf->ipv4.flags & F_LDPD_AF_ENABLED)
+ print_af(AF_INET, conf, &conf->ipv4);
+ if (conf->ipv6.flags & F_LDPD_AF_ENABLED)
+ print_af(AF_INET6, conf, &conf->ipv6);
LIST_FOREACH(nbrp, &conf->nbrp_list, entry)
print_nbrp(nbrp);
diff --git a/usr.sbin/ldpd/socket.c b/usr.sbin/ldpd/socket.c
index f4e1120faab..89b94fd7b72 100644
--- a/usr.sbin/ldpd/socket.c
+++ b/usr.sbin/ldpd/socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: socket.c,v 1.5 2016/05/23 18:43:28 renato Exp $ */
+/* $OpenBSD: socket.c,v 1.6 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2016 Renato Westphal <renato@openbsd.org>
@@ -35,10 +35,11 @@ extern struct ldpd_conf *ldpd_conf;
extern struct ldpd_sysdep sysdep;
int
-ldp_create_socket(enum socket_type type)
+ldp_create_socket(int af, enum socket_type type)
{
int fd, domain, proto;
- struct sockaddr_in local_sa;
+ union ldpd_addr addr;
+ struct sockaddr_storage local_sa;
int opt;
/* create socket */
@@ -55,24 +56,25 @@ ldp_create_socket(enum socket_type type)
default:
fatalx("ldp_create_socket: unknown socket type");
}
- fd = socket(AF_INET, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto);
+ fd = socket(af, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto);
if (fd == -1) {
log_warn("%s: error creating socket", __func__);
return (-1);
}
/* bind to a local address/port */
- memset(&local_sa, 0, sizeof(local_sa));
- local_sa.sin_family = AF_INET;
- local_sa.sin_len = sizeof(struct sockaddr_in);
- local_sa.sin_port = htons(LDP_PORT);
switch (type) {
case LDP_SOCKET_DISC:
/* listen on all addresses */
+ memset(&addr, 0, sizeof(addr));
+ memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
+ sizeof(local_sa));
break;
case LDP_SOCKET_EDISC:
case LDP_SOCKET_SESSION:
- local_sa.sin_addr = ldpd_conf->trans_addr;
+ addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr;
+ memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
+ sizeof(local_sa));
if (sock_set_bindany(fd, 1) == -1) {
close(fd);
return (-1);
@@ -83,33 +85,55 @@ ldp_create_socket(enum socket_type type)
close(fd);
return (-1);
}
- if (bind(fd, (struct sockaddr *)&local_sa, local_sa.sin_len) == -1) {
+ if (bind(fd, (struct sockaddr *)&local_sa, local_sa.ss_len) == -1) {
log_warn("%s: error binding socket", __func__);
close(fd);
return (-1);
}
/* set options */
- if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
- close(fd);
- return (-1);
- }
- if (type == LDP_SOCKET_DISC) {
- if (sock_set_ipv4_mcast_ttl(fd,
- IP_DEFAULT_MULTICAST_TTL) == -1) {
+ switch (af) {
+ case AF_INET:
+ if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
close(fd);
return (-1);
}
- if (sock_set_ipv4_mcast_loop(fd) == -1) {
- close(fd);
- return (-1);
+ if (type == LDP_SOCKET_DISC) {
+ if (sock_set_ipv4_mcast_ttl(fd,
+ IP_DEFAULT_MULTICAST_TTL) == -1) {
+ close(fd);
+ return (-1);
+ }
+ if (sock_set_ipv4_mcast_loop(fd) == -1) {
+ close(fd);
+ return (-1);
+ }
}
- }
- if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
- if (sock_set_ipv4_recvif(fd, 1) == -1) {
+ if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
+ if (sock_set_ipv4_recvif(fd, 1) == -1) {
+ close(fd);
+ return (-1);
+ }
+ }
+ break;
+ case AF_INET6:
+ if (sock_set_ipv6_dscp(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
close(fd);
return (-1);
}
+ if (type == LDP_SOCKET_DISC) {
+ if (sock_set_ipv6_mcast_loop(fd) == -1) {
+ close(fd);
+ return (-1);
+ }
+ }
+ if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
+ if (sock_set_ipv6_pktinfo(fd, 1) == -1) {
+ close(fd);
+ return (-1);
+ }
+ }
+ break;
}
switch (type) {
case LDP_SOCKET_DISC:
@@ -210,14 +234,12 @@ sock_set_ipv4_recvif(int fd, int enable)
int
sock_set_ipv4_mcast(struct iface *iface)
{
- struct if_addr *if_addr;
+ in_addr_t addr;
- if_addr = LIST_FIRST(&iface->addr_list);
- if (!if_addr)
- return (0);
+ addr = if_get_ipv4_addr(iface);
- if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF,
- &if_addr->addr.s_addr, sizeof(if_addr->addr.s_addr)) < 0) {
+ if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF,
+ &addr, sizeof(addr)) < 0) {
log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
__func__, iface->name);
return (-1);
@@ -239,3 +261,54 @@ sock_set_ipv4_mcast_loop(int fd)
return (0);
}
+
+int
+sock_set_ipv6_dscp(int fd, int dscp)
+{
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
+ sizeof(dscp)) < 0) {
+ log_warn("%s: error setting IPV6_TCLASS", __func__);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+sock_set_ipv6_pktinfo(int fd, int enable)
+{
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
+ sizeof(enable)) < 0) {
+ log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+sock_set_ipv6_mcast(struct iface *iface)
+{
+ if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
+ IPV6_MULTICAST_IF, &iface->ifindex, sizeof(iface->ifindex)) < 0) {
+ log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
+ __func__, iface->name);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+sock_set_ipv6_mcast_loop(int fd)
+{
+ unsigned int loop = 0;
+
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
+ (unsigned int *)&loop, sizeof(loop)) < 0) {
+ log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
+ return (-1);
+ }
+
+ return (0);
+}
diff --git a/usr.sbin/ldpd/util.c b/usr.sbin/ldpd/util.c
index 92d51624ead..ba0cfa0a2f4 100644
--- a/usr.sbin/ldpd/util.c
+++ b/usr.sbin/ldpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.3 2016/05/23 18:55:21 renato Exp $ */
+/* $OpenBSD: util.c,v 1.4 2016/05/23 18:58:48 renato Exp $ */
/*
* Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
@@ -34,6 +34,54 @@ mask2prefixlen(in_addr_t ina)
return (33 - ffs(ntohl(ina)));
}
+uint8_t
+mask2prefixlen6(struct sockaddr_in6 *sa_in6)
+{
+ uint8_t l = 0, *ap, *ep;
+
+ /*
+ * sin6_len is the size of the sockaddr so substract the offset of
+ * the possibly truncated sin6_addr struct.
+ */
+ ap = (uint8_t *)&sa_in6->sin6_addr;
+ ep = (uint8_t *)sa_in6 + sa_in6->sin6_len;
+ for (; ap < ep; ap++) {
+ /* this "beauty" is adopted from sbin/route/show.c ... */
+ switch (*ap) {
+ case 0xff:
+ l += 8;
+ break;
+ case 0xfe:
+ l += 7;
+ return (l);
+ case 0xfc:
+ l += 6;
+ return (l);
+ case 0xf8:
+ l += 5;
+ return (l);
+ case 0xf0:
+ l += 4;
+ return (l);
+ case 0xe0:
+ l += 3;
+ return (l);
+ case 0xc0:
+ l += 2;
+ return (l);
+ case 0x80:
+ l += 1;
+ return (l);
+ case 0x00:
+ return (l);
+ default:
+ fatalx("non contiguous inet6 netmask");
+ }
+ }
+
+ return (l);
+}
+
in_addr_t
prefixlen2mask(uint8_t prefixlen)
{
@@ -43,8 +91,129 @@ prefixlen2mask(uint8_t prefixlen)
return (htonl(0xffffffff << (32 - prefixlen)));
}
+struct in6_addr *
+prefixlen2mask6(uint8_t prefixlen)
+{
+ static struct in6_addr mask;
+ int i;
+
+ memset(&mask, 0, sizeof(mask));
+ for (i = 0; i < prefixlen / 8; i++)
+ mask.s6_addr[i] = 0xff;
+ i = prefixlen % 8;
+ if (i)
+ mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
+
+ return (&mask);
+}
+
+void
+ldp_applymask(int af, union ldpd_addr *dest, const union ldpd_addr *src,
+ int prefixlen)
+{
+ struct in6_addr mask;
+ int i;
+
+ switch (af) {
+ case AF_INET:
+ dest->v4.s_addr = src->v4.s_addr & prefixlen2mask(prefixlen);
+ break;
+ case AF_INET6:
+ memset(&mask, 0, sizeof(mask));
+ for (i = 0; i < prefixlen / 8; i++)
+ mask.s6_addr[i] = 0xff;
+ i = prefixlen % 8;
+ if (i)
+ mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
+
+ for (i = 0; i < 16; i++)
+ dest->v6.s6_addr[i] = src->v6.s6_addr[i] &
+ mask.s6_addr[i];
+ break;
+ default:
+ fatalx("ldp_applymask: unknown af");
+ }
+}
+
int
-bad_ip_addr(struct in_addr addr)
+ldp_addrcmp(int af, const union ldpd_addr *a, const union ldpd_addr *b)
+{
+ switch (af) {
+ case AF_INET:
+ if (a->v4.s_addr == b->v4.s_addr)
+ return (0);
+ return ((ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr)) ? 1 : -1);
+ case AF_INET6:
+ return (memcmp(&a->v6, &b->v6, sizeof(struct in6_addr)));
+ default:
+ fatalx("ldp_addrcmp: unknown af");
+ }
+}
+
+int
+ldp_addrisset(int af, const union ldpd_addr *addr)
+{
+ switch (af) {
+ case AF_UNSPEC:
+ return (0);
+ case AF_INET:
+ if (addr->v4.s_addr != INADDR_ANY)
+ return (1);
+ break;
+ case AF_INET6:
+ if (!IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
+ return (1);
+ break;
+ default:
+ fatalx("ldp_addrisset: unknown af");
+ }
+
+ return (0);
+}
+
+int
+ldp_prefixcmp(int af, const union ldpd_addr *a, const union ldpd_addr *b,
+ uint8_t prefixlen)
+{
+ in_addr_t mask, aa, ba;
+ int i;
+ uint8_t m;
+
+ switch (af) {
+ case AF_INET:
+ if (prefixlen == 0)
+ return (0);
+ if (prefixlen > 32)
+ fatalx("ldp_prefixcmp: bad IPv4 prefixlen");
+ mask = htonl(prefixlen2mask(prefixlen));
+ aa = htonl(a->v4.s_addr) & mask;
+ ba = htonl(b->v4.s_addr) & mask;
+ return (aa - ba);
+ case AF_INET6:
+ if (prefixlen == 0)
+ return (0);
+ if (prefixlen > 128)
+ fatalx("ldp_prefixcmp: bad IPv6 prefixlen");
+ for (i = 0; i < prefixlen / 8; i++)
+ if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
+ return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
+ i = prefixlen % 8;
+ if (i) {
+ m = 0xff00 >> i;
+ if ((a->v6.s6_addr[prefixlen / 8] & m) !=
+ (b->v6.s6_addr[prefixlen / 8] & m))
+ return ((a->v6.s6_addr[prefixlen / 8] & m) -
+ (b->v6.s6_addr[prefixlen / 8] & m));
+ }
+ return (0);
+ default:
+ fatalx("ldp_prefixcmp: unknown af");
+ }
+ return (-1);
+}
+
+int
+bad_addr_v4(struct in_addr addr)
{
uint32_t a = ntohl(addr.s_addr);
@@ -55,3 +224,133 @@ bad_ip_addr(struct in_addr addr)
return (0);
}
+
+int
+bad_addr_v6(struct in6_addr *addr)
+{
+ if (IN6_IS_ADDR_UNSPECIFIED(addr) ||
+ IN6_IS_ADDR_LOOPBACK(addr) ||
+ IN6_IS_ADDR_MULTICAST(addr) ||
+ IN6_IS_ADDR_SITELOCAL(addr) ||
+ IN6_IS_ADDR_V4MAPPED(addr) ||
+ IN6_IS_ADDR_V4COMPAT(addr))
+ return (1);
+
+ return (0);
+}
+
+int
+bad_addr(int af, union ldpd_addr *addr)
+{
+ switch (af) {
+ case AF_INET:
+ return (bad_addr_v4(addr->v4));
+ case AF_INET6:
+ return (bad_addr_v6(&addr->v6));
+ default:
+ fatalx("bad_addr: unknown af");
+ }
+}
+
+void
+embedscope(struct sockaddr_in6 *sin6)
+{
+ uint16_t tmp16;
+
+ if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
+ memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
+ if (tmp16 != 0) {
+ log_warnx("%s: address %s already has embeded scope %u",
+ __func__, log_sockaddr(sin6), ntohs(tmp16));
+ }
+ tmp16 = htons(sin6->sin6_scope_id);
+ memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16));
+ sin6->sin6_scope_id = 0;
+ }
+}
+
+void
+recoverscope(struct sockaddr_in6 *sin6)
+{
+ uint16_t tmp16;
+
+ if (sin6->sin6_scope_id != 0)
+ log_warnx("%s: address %s already has scope id %u",
+ __func__, log_sockaddr(sin6), sin6->sin6_scope_id);
+
+ if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
+ memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
+ sin6->sin6_scope_id = ntohs(tmp16);
+ sin6->sin6_addr.s6_addr[2] = 0;
+ sin6->sin6_addr.s6_addr[3] = 0;
+ }
+}
+
+void
+addscope(struct sockaddr_in6 *sin6, uint32_t id)
+{
+ if (sin6->sin6_scope_id != 0)
+ log_warnx("%s: address %s already has scope id %u", __func__,
+ log_sockaddr(sin6), sin6->sin6_scope_id);
+
+ if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr))
+ sin6->sin6_scope_id = id;
+}
+
+void
+clearscope(struct in6_addr *in6)
+{
+ if (IN6_IS_SCOPE_EMBED(in6)) {
+ in6->s6_addr[2] = 0;
+ in6->s6_addr[3] = 0;
+ }
+}
+
+struct sockaddr *
+addr2sa(int af, union ldpd_addr *addr, uint16_t port)
+{
+ static struct sockaddr_storage ss;
+ struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
+ struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
+
+ memset(&ss, 0, sizeof(ss));
+ switch (af) {
+ case AF_INET:
+ sa_in->sin_family = AF_INET;
+ sa_in->sin_len = sizeof(struct sockaddr_in);
+ sa_in->sin_addr = addr->v4;
+ sa_in->sin_port = htons(port);
+ break;
+ case AF_INET6:
+ sa_in6->sin6_family = AF_INET6;
+ sa_in6->sin6_len = sizeof(struct sockaddr_in6);
+ sa_in6->sin6_addr = addr->v6;
+ sa_in6->sin6_port = htons(port);
+ break;
+ default:
+ fatalx("addr2sa: unknown af");
+ }
+
+ return ((struct sockaddr *)&ss);
+}
+
+void
+sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr)
+{
+ struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
+ struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
+
+ memset(addr, 0, sizeof(*addr));
+ switch (sa->sa_family) {
+ case AF_INET:
+ *af = AF_INET;
+ addr->v4 = sa_in->sin_addr;
+ break;
+ case AF_INET6:
+ *af = AF_INET6;
+ addr->v6 = sa_in6->sin6_addr;
+ break;
+ default:
+ fatalx("sa2addr: unknown af");
+ }
+}