Currently ospfd has a problem when a single lsupdate is bigger then the
MTU. Normaly this is not a problem but Benjamin Papillon hit this limit on
a VPN hub.
This diff changes the way lsupdate.c handels buffers. The buffer is
changed from a MTU sized to a dynamic one that can grow up to 64k -
header. By default ospfd will try not to send out packets bigger then MTU
(e.g. not adding multiple updates into one message causing fragmentation)
but in case a single update is bigger then the MTU it will build a huge
packet with just that update in.
While there I also fixed a few other buffers (hello packet and the self
generated LSA) to have more correct upper bounds.
Last missing bit is now lsa_ack which is a separate diff.
Please test.
--
:wq Claudio
Index: hello.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/hello.c,v
retrieving revision 1.19
diff -u -p -r1.19 hello.c
--- hello.c 26 May 2010 13:56:08 -0000 1.19
+++ hello.c 17 Feb 2011 19:19:19 -0000
@@ -64,8 +64,8 @@ send_hello(struct iface *iface)
fatalx("send_hello: unknown interface type");
}
- /* XXX IBUF_READ_SIZE */
- if ((buf = ibuf_dynamic(PKG_DEF_SIZE, IBUF_READ_SIZE)) == NULL)
+ if ((buf = ibuf_dynamic(PKG_DEF_SIZE,
+ IP_MAXPACKET - sizeof(struct ip))) == NULL)
fatal("send_hello");
/* OSPF header */
Index: lsupdate.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/lsupdate.c,v
retrieving revision 1.39
diff -u -p -r1.39 lsupdate.c
--- lsupdate.c 26 May 2010 13:56:08 -0000 1.39
+++ lsupdate.c 17 Feb 2011 19:19:19 -0000
@@ -152,7 +152,8 @@ prepare_ls_update(struct iface *iface)
{
struct ibuf *buf;
- if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL)
+ if ((buf = ibuf_dynamic(iface->mtu - sizeof(struct ip),
+ IP_MAXPACKET - sizeof(struct ip))) == NULL)
fatal("prepare_ls_update");
/* OSPF header */
@@ -177,8 +178,13 @@ add_ls_update(struct ibuf *buf, struct i
void *lsage;
u_int16_t age;
- if (ibuf_left(buf) < (size_t)len + MD5_DIGEST_LENGTH)
- return (0);
+ if ((size_t)iface->mtu < sizeof(struct ip) + sizeof(struct ospf_hdr) +
+ sizeof(u_int32_t) + ibuf_size(buf) + len + MD5_DIGEST_LENGTH) {
+ /* start new packet unless this is the first LSA to pack */
+ if (ibuf_size(buf) > sizeof(struct ospf_hdr) +
+ sizeof(u_int32_t))
+ return (0);
+ }
lsage = ibuf_reserve(buf, 0);
if (ibuf_add(buf, data, len)) {
@@ -475,8 +481,19 @@ ls_retrans_timer(int fd, short event, vo
d = MAX_AGE;
if (add_ls_update(buf, nbr->iface, le->le_ref->data,
- le->le_ref->len, d) == 0)
+ le->le_ref->len, d) == 0) {
+ if (nlsa == 0) {
+ /* something bad happend retry later */
+ log_warnx("ls_retrans_timer: sending LS update "
+ "to neighbor ID %s failed",
+ inet_ntoa(nbr->id));
+ TAILQ_REMOVE(&nbr->ls_retrans_list, le, entry);
+ nbr->ls_ret_cnt--;
+ le->le_when = nbr->iface->rxmt_interval;
+ ls_retrans_list_insert(nbr, le);
+ }
break;
+ }
nlsa++;
if (le->le_oneshot)
ls_retrans_list_free(nbr, le);
@@ -487,7 +504,10 @@ ls_retrans_timer(int fd, short event, vo
ls_retrans_list_insert(nbr, le);
}
}
- send_ls_update(buf, nbr->iface, addr, nlsa);
+ if (nlsa)
+ send_ls_update(buf, nbr->iface, addr, nlsa);
+ else
+ ibuf_free(buf);
done:
if ((le = TAILQ_FIRST(&nbr->ls_retrans_list)) != NULL) {
Index: ospfe.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/ospfe.c,v
retrieving revision 1.77
diff -u -p -r1.77 ospfe.c
--- ospfe.c 1 Oct 2010 13:29:25 -0000 1.77
+++ ospfe.c 17 Feb 2011 19:19:19 -0000
@@ -183,7 +183,7 @@ ospfe(struct ospfd_conf *xconf, int pipe
TAILQ_INIT(&ctl_conns);
control_listen();
- if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
+ if ((pkt_ptr = calloc(1, READ_BUF_SIZE)) == NULL)
fatal("ospfe");
/* start interfaces */
@@ -756,8 +756,9 @@ orig_rtr_lsa(struct area *area)
log_debug("orig_rtr_lsa: area %s", inet_ntoa(area->id));
- /* XXX IBUF_READ_SIZE */
- if ((buf = ibuf_dynamic(sizeof(lsa_hdr), READ_BUF_SIZE)) == NULL)
+ if ((buf = ibuf_dynamic(sizeof(lsa_hdr),
+ IP_MAXPACKET - sizeof(struct ip) - sizeof(struct ospf_hdr) -
+ sizeof(u_int32_t) - MD5_DIGEST_LENGTH)) == NULL)
fatal("orig_rtr_lsa");
/* reserve space for LSA header and LSA Router header */
@@ -1024,8 +1025,9 @@ orig_net_lsa(struct iface *iface)
int num_rtr = 0;
u_int16_t chksum;
- /* XXX IBUF_READ_SIZE */
- if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL)
+ if ((buf = ibuf_dynamic(sizeof(lsa_hdr),
+ IP_MAXPACKET - sizeof(struct ip) - sizeof(struct ospf_hdr) -
+ sizeof(u_int32_t) - MD5_DIGEST_LENGTH)) == NULL)
fatal("orig_net_lsa");
/* reserve space for LSA header and LSA Router header */