diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2010-06-08 16:04:26 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2010-06-08 16:04:26 +0000 |
commit | 12f2e7a8a3344ddd415e5d1861c936e241286889 (patch) | |
tree | 7638e18dd2b05dbd50e83173535e7f1eaf581af1 /usr.sbin | |
parent | cbabf43b35f1c8b887c3da07209b4e6eb194c0ca (diff) |
Calculate size of update packet with IPv6 header and reserve space
for IPsec. Avoid IPv6 fragments where possible. If a single LSA
is too big, put it into a separate packet with up to IPV6_MAXPACKET
bytes. This packet may get fragmented by the kernel.
ok stsp@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/ospf6d/lsupdate.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/usr.sbin/ospf6d/lsupdate.c b/usr.sbin/ospf6d/lsupdate.c index 16c198d9455..dfc5d5213ed 100644 --- a/usr.sbin/ospf6d/lsupdate.c +++ b/usr.sbin/ospf6d/lsupdate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lsupdate.c,v 1.7 2010/06/03 10:00:34 bluhm Exp $ */ +/* $OpenBSD: lsupdate.c,v 1.8 2010/06/08 16:04:25 bluhm Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -21,6 +21,8 @@ #include <sys/hash.h> #include <sys/socket.h> #include <netinet/in.h> +#include <netinet/ip6.h> +#include <netinet/ip_ah.h> #include <arpa/inet.h> #include <stdlib.h> @@ -35,7 +37,7 @@ extern struct ospfd_conf *oeconf; extern struct imsgev *iev_rde; -struct ibuf *prepare_ls_update(struct iface *); +struct ibuf *prepare_ls_update(struct iface *, int); int add_ls_update(struct ibuf *, struct iface *, void *, int, u_int16_t); int send_ls_update(struct ibuf *, struct iface *, struct in6_addr, u_int32_t); @@ -147,11 +149,27 @@ lsa_flood(struct iface *iface, struct nbr *originator, struct lsa_hdr *lsa_hdr, } struct ibuf * -prepare_ls_update(struct iface *iface) +prepare_ls_update(struct iface *iface, int bigpkt) { struct ibuf *buf; + size_t size; - if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL) + size = bigpkt ? IPV6_MAXPACKET : iface->mtu; + if (size < IPV6_MMTU) + size = IPV6_MMTU; + size -= sizeof(struct ip6_hdr); + /* + * Reserve space for optional ah or esp encryption. The + * algorithm is taken from ah_output and esp_output, the + * values are the maxima of crypto/xform.c. + */ + size -= max( + /* base-ah-header replay authsize */ + AH_FLENGTH + sizeof(u_int32_t) + 32, + /* spi sequence ivlen blocksize pad-length next-header authsize */ + 2 * sizeof(u_int32_t) + 16 + 16 + 2 * sizeof(u_int8_t) + 32); + + if ((buf = ibuf_open(size)) == NULL) fatal("prepare_ls_update"); /* OSPF header */ @@ -418,7 +436,7 @@ ls_retrans_timer(int fd, short event, void *bula) struct lsa_entry *le; struct ibuf *buf; time_t now; - int d; + int bigpkt, d; u_int32_t nlsa = 0; if ((le = TAILQ_FIRST(&nbr->ls_retrans_list)) != NULL) @@ -452,7 +470,17 @@ ls_retrans_timer(int fd, short event, void *bula) } else memcpy(&addr, &nbr->addr, sizeof(addr)); - if ((buf = prepare_ls_update(nbr->iface)) == NULL) { + /* + * Allow big ipv6 packets that may get fragmented if a + * single lsa might be too big for an unfragmented packet. + * To avoid the exact algorithm duplicated here, just make + * a good guess. If the first lsa is bigger than 1024 + * bytes, reserve a separate big packet for it. The kernel + * will figure out if fragmentation is necessary. For + * smaller lsas, we avoid big packets and fragmentation. + */ + bigpkt = le->le_ref->len > 1024; + if ((buf = prepare_ls_update(nbr->iface, bigpkt)) == NULL) { le->le_when = 1; goto done; } @@ -489,6 +517,9 @@ ls_retrans_timer(int fd, short event, void *bula) le->le_when = nbr->iface->rxmt_interval; ls_retrans_list_insert(nbr, le); } + /* do not put additional lsa into fragmented big packet */ + if (bigpkt) + break; } send_ls_update(buf, nbr->iface, addr, nlsa); |