[ospfd] Add support for oversized LSAs.
2006-01-18 Juergen Kammer <j.kammer@eurodata.de>
* ospf_lsa.c: (ospf_router_lsa_new) dont take reference to the
stream data until it is constructed, data reference is
volatile due to the potential resize in link_info_set
2006-01-18 Paul Jakma <paul.jakma@sun.com>
* ospf_lsa.c: (link_info_set) Resize the stream if required and
possible. Return number of links added.
(lsa_link_*_set) use return value from previous.
* ospf_lsa.h: Add OSPF_ROUTER_LSA_LINK_SIZE define.
diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog
index a13ed6f..e5f8337 100644
--- a/ospfd/ChangeLog
+++ b/ospfd/ChangeLog
@@ -1,3 +1,16 @@
+2006-01-18 Juergen Kammer <j.kammer@eurodata.de>
+
+ * ospf_lsa.c: (ospf_router_lsa_new) dont take reference to the
+ stream data until it is constructed, data reference is
+ volatile due to the potential resize in link_info_set
+
+2006-01-18 Paul Jakma <paul.jakma@sun.com>
+
+ * ospf_lsa.c: (link_info_set) Resize the stream if required and
+ possible. Return number of links added.
+ (lsa_link_*_set) use return value from previous.
+ * ospf_lsa.h: Add OSPF_ROUTER_LSA_LINK_SIZE define.
+
2006-01-17 Paul Jakma <paul.jakma@sun.com>
* ospf_packet.c: (ospf_verify_header) print out the types
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index ff018fd..89e4d53 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -497,16 +497,49 @@
}
/* Set a link information. */
-static void
+static char
link_info_set (struct stream *s, struct in_addr id,
struct in_addr data, u_char type, u_char tos, u_int16_t cost)
{
+ /* LSA stream is initially allocated to OSPF_MAX_LSA_SIZE, suits
+ * vast majority of cases. Some rare routers with lots of links need more.
+ * we try accomodate those here.
+ */
+ if (STREAM_WRITEABLE(s) < OSPF_ROUTER_LSA_LINK_SIZE)
+ {
+ size_t ret = OSPF_MAX_LSA_SIZE;
+
+ /* Can we enlarge the stream still? */
+ if (STREAM_SIZE(s) == OSPF_MAX_LSA_SIZE)
+ {
+ /* we futz the size here for simplicity, really we need to account
+ * for just:
+ * IP Header - (sizeof (struct ip))
+ * OSPF Header - OSPF_HEADER_SIZE
+ * LSA Header - OSPF_LSA_HEADER_SIZE
+ * MD5 auth data, if MD5 is configured - OSPF_AUTH_MD5_SIZE.
+ *
+ * Simpler just to subtract OSPF_MAX_LSA_SIZE though.
+ */
+ ret = stream_resize (s, OSPF_MAX_PACKET_SIZE - OSPF_MAX_LSA_SIZE);
+ }
+
+ if (ret == OSPF_MAX_LSA_SIZE)
+ {
+ zlog_warn ("%s: Out of space in LSA stream, left %ld, size %ld",
+ __func__, STREAM_REMAIN (s), STREAM_SIZE (s));
+ return 0;
+ }
+ }
+
/* TOS based routing is not supported. */
stream_put_ipv4 (s, id.s_addr); /* Link ID. */
stream_put_ipv4 (s, data.s_addr); /* Link Data. */
stream_putc (s, type); /* Link Type. */
stream_putc (s, tos); /* TOS = 0. */
stream_putw (s, cost); /* Link Cost. */
+
+ return 1;
}
/* Describe Point-to-Point link. */
@@ -526,9 +559,8 @@
{
/* For unnumbered point-to-point networks, the Link Data field
should specify the interface's MIB-II ifIndex value. */
- link_info_set (s, nbr->router_id, oi->address->u.prefix4,
- LSA_LINK_TYPE_POINTOPOINT, 0, cost);
- links++;
+ links += link_info_set (s, nbr->router_id, oi->address->u.prefix4,
+ LSA_LINK_TYPE_POINTOPOINT, 0, cost);
}
if (CONNECTED_DEST_HOST(oi->connected))
@@ -541,7 +573,8 @@
id.s_addr = oi->connected->destination->u.prefix4.s_addr;
mask.s_addr = 0xffffffff;
- link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+ links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
+ oi->output_cost);
}
else
{
@@ -549,10 +582,9 @@
network regardless of the state of the neighbor */
masklen2ip (oi->address->prefixlen, &mask);
id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
- link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+ links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
+ oi->output_cost);
}
- links++;
-
return links;
}
@@ -569,8 +601,8 @@
{
masklen2ip (oi->address->prefixlen, &mask);
id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
- link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
- return 1;
+ return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
+ oi->output_cost);
}
dr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi));
@@ -579,17 +611,17 @@
IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) &&
ospf_nbr_count (oi, NSM_Full) > 0)
{
- link_info_set (s, DR (oi), oi->address->u.prefix4,
- LSA_LINK_TYPE_TRANSIT, 0, cost);
+ return link_info_set (s, DR (oi), oi->address->u.prefix4,
+ LSA_LINK_TYPE_TRANSIT, 0, cost);
}
/* Describe type 3 link. */
else
{
masklen2ip (oi->address->prefixlen, &mask);
id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
- link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+ return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
+ oi->output_cost);
}
- return 1;
}
static int
@@ -603,8 +635,7 @@
mask.s_addr = 0xffffffff;
id.s_addr = oi->address->u.prefix4.s_addr;
- link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
- return 1;
+ return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
}
/* Describe Virtual Link. */
@@ -618,9 +649,8 @@
if ((nbr = ospf_nbr_lookup_ptop (oi)))
if (nbr->state == NSM_Full)
{
- link_info_set (s, nbr->router_id, oi->address->u.prefix4,
- LSA_LINK_TYPE_VIRTUALLINK, 0, cost);
- return 1;
+ return link_info_set (s, nbr->router_id, oi->address->u.prefix4,
+ LSA_LINK_TYPE_VIRTUALLINK, 0, cost);
}
return 0;
@@ -643,8 +673,7 @@
mask.s_addr = 0xffffffff;
id.s_addr = oi->address->u.prefix4.s_addr;
- link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, 0);
- links++;
+ links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, 0);
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
zlog_debug ("PointToMultipoint: running ptomultip_set");
@@ -657,9 +686,8 @@
if (nbr->state == NSM_Full)
{
- link_info_set (s, nbr->router_id, oi->address->u.prefix4,
- LSA_LINK_TYPE_POINTOPOINT, 0, cost);
- links++;
+ links += link_info_set (s, nbr->router_id, oi->address->u.prefix4,
+ LSA_LINK_TYPE_POINTOPOINT, 0, cost);
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
zlog_debug ("PointToMultipoint: set link to %s",
inet_ntoa(oi->address->u.prefix4));
@@ -816,8 +844,6 @@
/* Create a stream for LSA. */
s = stream_new (OSPF_MAX_LSA_SIZE);
- lsah = (struct lsa_header *) STREAM_DATA (s);
-
/* Set LSA common header fields. */
lsa_header_set (s, LSA_OPTIONS_GET (area) | LSA_OPTIONS_NSSA_GET (area),
OSPF_ROUTER_LSA, ospf->router_id, ospf->router_id);
@@ -827,6 +853,7 @@
/* Set length. */
length = stream_get_endp (s);
+ lsah = (struct lsa_header *) STREAM_DATA (s);
lsah->length = htons (length);
/* Now, create OSPF LSA instance. */
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index 42c0882..9e480de 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -47,8 +47,9 @@
#define OSPF_OPAQUE_AREA_LSA 10
#define OSPF_OPAQUE_AS_LSA 11
-#define OSPF_LSA_HEADER_SIZE 20U
-#define OSPF_MAX_LSA_SIZE 1500U
+#define OSPF_LSA_HEADER_SIZE 20U
+#define OSPF_ROUTER_LSA_LINK_SIZE 12U
+#define OSPF_MAX_LSA_SIZE 1500U
/* AS-external-LSA refresh method. */
#define LSA_REFRESH_IF_CHANGED 0