summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/ldpd/address.c167
-rw-r--r--usr.sbin/ldpd/interface.c6
-rw-r--r--usr.sbin/ldpd/ldp.h4
-rw-r--r--usr.sbin/ldpd/ldpe.h5
-rw-r--r--usr.sbin/ldpd/neighbor.c6
5 files changed, 138 insertions, 50 deletions
diff --git a/usr.sbin/ldpd/address.c b/usr.sbin/ldpd/address.c
index d09640af4ac..9ee4d4198df 100644
--- a/usr.sbin/ldpd/address.c
+++ b/usr.sbin/ldpd/address.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: address.c,v 1.29 2016/07/16 19:24:30 renato Exp $ */
+/* $OpenBSD: address.c,v 1.30 2016/09/03 16:07:08 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <arpa/inet.h>
+#include <stdlib.h>
#include <string.h>
#include "ldpd.h"
@@ -25,64 +26,124 @@
#include "lde.h"
#include "log.h"
-static int gen_address_list_tlv(struct ibuf *, uint16_t, int,
- struct if_addr *);
+static void send_address(struct nbr *, int, struct if_addr_head *,
+ unsigned int, int);
+static int gen_address_list_tlv(struct ibuf *, uint16_t, int,
+ struct if_addr_head *, unsigned int);
+static void address_list_add(struct if_addr_head *, struct if_addr *);
+static void address_list_clr(struct if_addr_head *);
-void
-send_address(struct nbr *nbr, int af, struct if_addr *if_addr, int withdraw)
+static void
+send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
+ unsigned int addr_count, int withdraw)
{
struct ibuf *buf;
uint16_t msg_type;
+ uint8_t addr_size;
+ struct if_addr *if_addr;
uint16_t size;
- int iface_count = 0;
+ unsigned int tlv_addr_count = 0;
int err = 0;
+ /* nothing to send */
+ if (LIST_EMPTY(addr_list))
+ return;
+
if (!withdraw)
msg_type = MSG_TYPE_ADDR;
else
msg_type = MSG_TYPE_ADDRWITHDRAW;
- if (if_addr == NULL) {
- LIST_FOREACH(if_addr, &global.addr_list, entry)
- if (if_addr->af == af)
- iface_count++;
- } else
- iface_count = 1;
-
- size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct address_list_tlv);
switch (af) {
case AF_INET:
- size += iface_count * sizeof(struct in_addr);
+ addr_size = sizeof(struct in_addr);
break;
case AF_INET6:
- size += iface_count * sizeof(struct in6_addr);
+ addr_size = sizeof(struct in6_addr);
break;
default:
fatalx("send_address: unknown af");
}
- if ((buf = ibuf_open(size)) == NULL)
- fatal(__func__);
+ while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
+ /*
+ * Send as many addresses as possible - respect the session's
+ * negotiated maximum pdu length.
+ */
+ size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE;
+ if (size + addr_count * addr_size <= nbr->max_pdu_len)
+ tlv_addr_count = addr_count;
+ else
+ tlv_addr_count = (nbr->max_pdu_len - size) / addr_size;
+ size += tlv_addr_count * addr_size;
+ addr_count -= tlv_addr_count;
- err |= gen_ldp_hdr(buf, size);
- size -= LDP_HDR_SIZE;
- err |= gen_msg_hdr(buf, msg_type, size);
- size -= LDP_MSG_SIZE;
- err |= gen_address_list_tlv(buf, size, af, if_addr);
- if (err) {
- ibuf_free(buf);
- return;
- }
+ if ((buf = ibuf_open(size)) == NULL)
+ fatal(__func__);
+
+ err |= gen_ldp_hdr(buf, size);
+ size -= LDP_HDR_SIZE;
+ err |= gen_msg_hdr(buf, msg_type, size);
+ size -= LDP_MSG_SIZE;
+ err |= gen_address_list_tlv(buf, size, af, addr_list,
+ tlv_addr_count);
+ if (err) {
+ address_list_clr(addr_list);
+ ibuf_free(buf);
+ return;
+ }
- evbuf_enqueue(&nbr->tcp->wbuf, buf);
+ while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
+ log_debug("msg-out: %s: lsr-id %s, address %s",
+ msg_name(msg_type), inet_ntoa(nbr->id),
+ log_addr(af, &if_addr->addr));
+
+ LIST_REMOVE(if_addr, entry);
+ free(if_addr);
+ if (--tlv_addr_count == 0)
+ break;
+ }
+
+ evbuf_enqueue(&nbr->tcp->wbuf, buf);
+ }
nbr_fsm(nbr, NBR_EVT_PDU_SENT);
}
+void
+send_address_single(struct nbr *nbr, struct if_addr *if_addr, int withdraw)
+{
+ struct if_addr_head addr_list;
+
+ LIST_INIT(&addr_list);
+ address_list_add(&addr_list, if_addr);
+ send_address(nbr, if_addr->af, &addr_list, 1, withdraw);
+}
+
+void
+send_address_all(struct nbr *nbr, int af)
+{
+ struct if_addr_head addr_list;
+ struct if_addr *if_addr;
+ unsigned int addr_count = 0;
+
+ LIST_INIT(&addr_list);
+ LIST_FOREACH(if_addr, &global.addr_list, entry) {
+ if (if_addr->af != af)
+ continue;
+
+ address_list_add(&addr_list, if_addr);
+ addr_count++;
+ }
+
+ send_address(nbr, af, &addr_list, addr_count, 0);
+}
+
int
recv_address(struct nbr *nbr, char *buf, uint16_t len)
{
struct ldp_msg msg;
+ uint16_t msg_type;
struct address_list_tlv alt;
enum imsg_type type;
struct lde_addr lde_addr;
@@ -92,7 +153,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
len -= LDP_MSG_SIZE;
/* Address List TLV */
- if (len < sizeof(alt)) {
+ if (len < ADDR_LIST_SIZE) {
session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
return (-1);
}
@@ -124,7 +185,8 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
buf += sizeof(alt);
len -= sizeof(alt);
- if (ntohs(msg.type) == MSG_TYPE_ADDR)
+ msg_type = ntohs(msg.type);
+ if (msg_type == MSG_TYPE_ADDR)
type = IMSG_ADDRESS_ADD;
else
type = IMSG_ADDRESS_DEL;
@@ -163,9 +225,9 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
fatalx("recv_address: unknown af");
}
- log_debug("%s: lsr-id %s address %s%s", __func__,
- inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr),
- ntohs(msg.type) == MSG_TYPE_ADDR ? "" : " (withdraw)");
+ log_debug("msg-in: %s: lsr-id %s, address %s",
+ msg_name(msg_type), inet_ntoa(nbr->id),
+ log_addr(lde_addr.af, &lde_addr.addr));
ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
sizeof(lde_addr));
@@ -176,15 +238,17 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
static int
gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
- struct if_addr *if_addr)
+ struct if_addr_head *addr_list, unsigned int tlv_addr_count)
{
struct address_list_tlv alt;
uint16_t addr_size;
+ struct if_addr *if_addr;
int err = 0;
memset(&alt, 0, sizeof(alt));
alt.type = TLV_TYPE_ADDRLIST;
alt.length = htons(size - TLV_HDR_SIZE);
+
switch (af) {
case AF_INET:
alt.family = htons(AF_IPV4);
@@ -199,14 +263,35 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
}
err |= ibuf_add(buf, &alt, sizeof(alt));
- if (if_addr == NULL) {
- LIST_FOREACH(if_addr, &global.addr_list, entry) {
- if (if_addr->af != af)
- continue;
- err |= ibuf_add(buf, &if_addr->addr, addr_size);
- }
- } else
+ LIST_FOREACH(if_addr, addr_list, entry) {
err |= ibuf_add(buf, &if_addr->addr, addr_size);
+ if (--tlv_addr_count == 0)
+ break;
+ }
return (err);
}
+
+static void
+address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr)
+{
+ struct if_addr *new;
+
+ new = malloc(sizeof(*new));
+ if (new == NULL)
+ fatal(__func__);
+ *new = *if_addr;
+
+ LIST_INSERT_HEAD(addr_list, new, entry);
+}
+
+static void
+address_list_clr(struct if_addr_head *addr_list)
+{
+ struct if_addr *if_addr;
+
+ while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
+ LIST_REMOVE(if_addr, entry);
+ free(if_addr);
+ }
+}
diff --git a/usr.sbin/ldpd/interface.c b/usr.sbin/ldpd/interface.c
index 8ce9598b4cc..7988448bd68 100644
--- a/usr.sbin/ldpd/interface.c
+++ b/usr.sbin/ldpd/interface.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: interface.c,v 1.47 2016/07/01 23:29:55 renato Exp $ */
+/* $OpenBSD: interface.c,v 1.48 2016/09/03 16:07:08 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
@@ -175,7 +175,7 @@ if_addr_add(struct kaddr *ka)
if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
continue;
- send_address(nbr, if_addr->af, if_addr, 0);
+ send_address_single(nbr, if_addr, 0);
}
}
@@ -222,7 +222,7 @@ if_addr_del(struct kaddr *ka)
continue;
if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
continue;
- send_address(nbr, if_addr->af, if_addr, 1);
+ send_address_single(nbr, if_addr, 1);
}
LIST_REMOVE(if_addr, entry);
free(if_addr);
diff --git a/usr.sbin/ldpd/ldp.h b/usr.sbin/ldpd/ldp.h
index 1a51bc4330b..d50a3d0ba15 100644
--- a/usr.sbin/ldpd/ldp.h
+++ b/usr.sbin/ldpd/ldp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldp.h,v 1.34 2016/07/15 17:09:25 renato Exp $ */
+/* $OpenBSD: ldp.h,v 1.35 2016/09/03 16:07:08 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
@@ -239,6 +239,8 @@ struct address_list_tlv {
/* address entries */
} __packed;
+#define ADDR_LIST_SIZE 6
+
#define FEC_ELM_WCARD_LEN 1
#define FEC_ELM_PREFIX_MIN_LEN 4
#define FEC_PWID_ELM_MIN_LEN 8
diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h
index bf62dc0bbee..e2acb6a3b4f 100644
--- a/usr.sbin/ldpd/ldpe.h
+++ b/usr.sbin/ldpd/ldpe.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpe.h,v 1.68 2016/09/02 17:10:34 renato Exp $ */
+/* $OpenBSD: ldpe.h,v 1.69 2016/09/03 16:07:08 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
@@ -166,7 +166,8 @@ int recv_notification(struct nbr *, char *, uint16_t);
int gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t);
/* address.c */
-void send_address(struct nbr *, int, struct if_addr *, int);
+void send_address_single(struct nbr *, struct if_addr *, int);
+void send_address_all(struct nbr *, int);
int recv_address(struct nbr *, char *, uint16_t);
/* labelmapping.c */
diff --git a/usr.sbin/ldpd/neighbor.c b/usr.sbin/ldpd/neighbor.c
index d58bf032bfa..361cf5660e2 100644
--- a/usr.sbin/ldpd/neighbor.c
+++ b/usr.sbin/ldpd/neighbor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: neighbor.c,v 1.77 2016/07/01 23:29:55 renato Exp $ */
+/* $OpenBSD: neighbor.c,v 1.78 2016/09/03 16:07:08 renato Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
@@ -185,9 +185,9 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event)
nbr_start_ktimer(nbr);
nbr_start_ktimeout(nbr);
if (nbr->v4_enabled)
- send_address(nbr, AF_INET, NULL, 0);
+ send_address_all(nbr, AF_INET);
if (nbr->v6_enabled)
- send_address(nbr, AF_INET6, NULL, 0);
+ send_address_all(nbr, AF_INET6);
nbr_send_labelmappings(nbr);
break;
case NBR_ACT_CONNECT_SETUP: