summaryrefslogtreecommitdiff
path: root/proto/ospf/topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/topology.c')
-rw-r--r--proto/ospf/topology.c114
1 files changed, 73 insertions, 41 deletions
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index ec012b22..f25db9a7 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -103,7 +103,8 @@ lsab_alloc(struct proto_ospf *po, unsigned size)
if (po->lsab_used > po->lsab_size)
{
po->lsab_size = MAX(po->lsab_used, 2 * po->lsab_size);
- po->lsab = mb_realloc(po->proto.pool, po->lsab, po->lsab_size);
+ po->lsab = po->lsab ? mb_realloc(po->lsab, po->lsab_size):
+ mb_alloc(po->proto.pool, po->lsab_size);
}
return ((byte *) po->lsab) + offset;
}
@@ -233,6 +234,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
WALK_LIST(ifa, po->iface_list)
{
int net_lsa = 0;
+ u32 link_cost = po->stub_router ? 0xffff : ifa->cost;
if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) &&
(!EMPTY_LIST(ifa->neigh_list)))
@@ -258,9 +260,17 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
ln->type = LSART_PTP;
ln->id = neigh->rid;
- ln->data = (ifa->addr->flags & IA_PEER) ?
- ifa->iface->index : ipa_to_u32(ifa->addr->ip);
- ln->metric = ifa->cost;
+
+ /*
+ * ln->data should be ifa->iface_id in case of no/ptp
+ * address (ifa->addr->flags & IA_PEER) on PTP link (see
+ * RFC 2328 12.4.1.1.), but the iface ID value has no use,
+ * while using IP address even in this case is here for
+ * compatibility with some broken implementations that use
+ * this address as a next-hop.
+ */
+ ln->data = ipa_to_u32(ifa->addr->ip);
+ ln->metric = link_cost;
ln->padding = 0;
i++;
}
@@ -274,7 +284,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
ln->type = LSART_NET;
ln->id = ipa_to_u32(ifa->drip);
ln->data = ipa_to_u32(ifa->addr->ip);
- ln->metric = ifa->cost;
+ ln->metric = link_cost;
ln->padding = 0;
i++;
net_lsa = 1;
@@ -289,7 +299,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
ln->type = LSART_VLNK;
ln->id = neigh->rid;
ln->data = ipa_to_u32(ifa->addr->ip);
- ln->metric = ifa->cost;
+ ln->metric = link_cost;
ln->padding = 0;
i++;
}
@@ -305,7 +315,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
/* Now we will originate stub area if there is no primary */
if (net_lsa ||
(ifa->type == OSPF_IT_VLINK) ||
- (ifa->addr->flags & IA_PEER) ||
+ ((ifa->addr->flags & IA_PEER) && ! ifa->cf->stub) ||
configured_stubnet(oa, ifa->addr))
continue;
@@ -368,7 +378,7 @@ add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif,
ln->type = type;
ln->padding = 0;
ln->metric = ifa->cost;
- ln->lif = ifa->iface->index;
+ ln->lif = ifa->iface_id;
ln->nif = nif;
ln->id = id;
}
@@ -546,7 +556,7 @@ originate_net_lsa_body(struct ospf_iface *ifa, u16 *length,
if (n->state == NEIGHBOR_FULL)
{
#ifdef OSPFv3
- en = ospf_hash_find(po->gr, ifa->iface->index, n->iface_id, n->rid, LSA_T_LINK);
+ en = ospf_hash_find(po->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK);
if (en)
options |= ((struct ospf_lsa_link *) en->lsa_body)->options;
#endif
@@ -596,7 +606,7 @@ originate_net_lsa(struct ospf_iface *ifa)
lsa.options = ifa->oa->options;
lsa.id = ipa_to_u32(ifa->addr->ip);
#else /* OSPFv3 */
- lsa.id = ifa->iface->index;
+ lsa.id = ifa->iface_id;
#endif
lsa.rt = po->router_id;
@@ -1207,10 +1217,10 @@ originate_link_lsa(struct ospf_iface *ifa)
lsa.age = 0;
lsa.type = LSA_T_LINK;
- lsa.id = ifa->iface->index;
+ lsa.id = ifa->iface_id;
lsa.rt = po->router_id;
lsa.sn = get_seqnum(ifa->link_lsa);
- u32 dom = ifa->iface->index;
+ u32 dom = ifa->iface_id;
body = originate_link_lsa_body(ifa, &lsa.length);
lsasum_calculate(&lsa, body);
@@ -1249,7 +1259,6 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
struct ospf_config *cf = (struct ospf_config *) (po->proto.cf);
struct ospf_iface *ifa;
struct ospf_lsa_prefix *lp;
- struct ifa *vlink_addr = NULL;
int host_addr = 0;
int net_lsa;
int i = 0;
@@ -1263,7 +1272,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
WALK_LIST(ifa, po->iface_list)
{
- if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
+ if ((ifa->oa != oa) || (ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN))
continue;
ifa->px_pos_beg = i;
@@ -1282,9 +1291,6 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
(a->scope <= SCOPE_LINK))
continue;
- if (!vlink_addr)
- vlink_addr = a;
-
if (((a->pxlen < MAX_PREFIX_LENGTH) && net_lsa) ||
configured_stubnet(oa, a))
continue;
@@ -1304,23 +1310,41 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
ifa->px_pos_end = i;
}
- /* If there are some configured vlinks, add some global address,
- which will be used as a vlink endpoint. */
- if (!EMPTY_LIST(cf->vlink_list) && !host_addr && vlink_addr)
- {
- lsa_put_prefix(po, vlink_addr->ip, MAX_PREFIX_LENGTH, 0);
- i++;
- }
-
struct ospf_stubnet_config *sn;
if (oa->ac)
WALK_LIST(sn, oa->ac->stubnet_list)
if (!sn->hidden)
{
lsa_put_prefix(po, sn->px.addr, sn->px.len, sn->cost);
+ if (sn->px.len == MAX_PREFIX_LENGTH)
+ host_addr = 1;
+ i++;
+ }
+
+ /* If there are some configured vlinks, find some global address
+ (even from another area), which will be used as a vlink endpoint. */
+ if (!EMPTY_LIST(cf->vlink_list) && !host_addr)
+ {
+ WALK_LIST(ifa, po->iface_list)
+ {
+ if ((ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN))
+ continue;
+
+ struct ifa *a;
+ WALK_LIST(a, ifa->iface->addrs)
+ {
+ if ((a->flags & IA_SECONDARY) || (a->scope <= SCOPE_LINK))
+ continue;
+
+ /* Found some IP */
+ lsa_put_prefix(po, a->ip, MAX_PREFIX_LENGTH, 0);
i++;
+ goto done;
}
+ }
+ }
+ done:
lp = po->lsab;
lp->pxcount = i;
*length = po->lsab_used + sizeof(struct ospf_lsa_header);
@@ -1389,15 +1413,12 @@ add_prefix(struct proto_ospf *po, u32 *px, int offset, int *pxc)
{
u32 *pxl = lsab_offset(po, offset);
int i;
- for (i = 0; i < *pxc; i++)
+ for (i = 0; i < *pxc; pxl = prefix_advance(pxl), i++)
+ if (prefix_same(px, pxl))
{
- if (prefix_same(px, pxl))
- {
- /* Options should be logically OR'ed together */
- *pxl |= *px;
- return;
- }
- pxl = prefix_advance(pxl);
+ /* Options should be logically OR'ed together */
+ *pxl |= (*px & 0x00FF0000);
+ return;
}
ASSERT(pxl == lsab_end(po));
@@ -1405,6 +1426,7 @@ add_prefix(struct proto_ospf *po, u32 *px, int offset, int *pxc)
int pxspace = prefix_space(px);
pxl = lsab_alloc(po, pxspace);
memcpy(pxl, px, pxspace);
+ *pxl &= 0xFFFF0000; /* Set metric to zero */
(*pxc)++;
}
@@ -1415,11 +1437,21 @@ add_link_lsa(struct proto_ospf *po, struct top_hash_entry *en, int offset, int *
u32 *pxb = ll->rest;
int j;
- for (j = 0; j < ll->pxcount; j++)
- {
- add_prefix(po, pxb, offset, pxc);
- pxb = prefix_advance(pxb);
- }
+ for (j = 0; j < ll->pxcount; pxb = prefix_advance(pxb), j++)
+ {
+ u8 pxlen = (pxb[0] >> 24);
+ u8 pxopts = (pxb[0] >> 16);
+
+ /* Skip NU or LA prefixes */
+ if (pxopts & (OPT_PX_NU | OPT_PX_LA))
+ continue;
+
+ /* Skip link-local prefixes */
+ if ((pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
+ continue;
+
+ add_prefix(po, pxb, offset, pxc);
+ }
}
@@ -1449,7 +1481,7 @@ originate_prefix_net_lsa_body(struct ospf_iface *ifa, u16 *length)
WALK_LIST(n, ifa->neigh_list)
if ((n->state == NEIGHBOR_FULL) &&
- (en = ospf_hash_find(po->gr, ifa->iface->index, n->iface_id, n->rid, LSA_T_LINK)))
+ (en = ospf_hash_find(po->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK)))
add_link_lsa(po, en, offset, &pxc);
lp = po->lsab;
@@ -1471,7 +1503,7 @@ originate_prefix_net_lsa(struct ospf_iface *ifa)
lsa.age = 0;
lsa.type = LSA_T_PREFIX;
- lsa.id = ifa->iface->index;
+ lsa.id = ifa->iface_id;
lsa.rt = po->router_id;
lsa.sn = get_seqnum(ifa->pxn_lsa);
u32 dom = ifa->oa->areaid;
@@ -1642,7 +1674,7 @@ ospf_lsa_domain(u32 type, struct ospf_iface *ifa)
switch (type & LSA_SCOPE_MASK)
{
case LSA_SCOPE_LINK:
- return ifa->iface->index;
+ return ifa->iface_id;
case LSA_SCOPE_AREA:
return ifa->oa->areaid;