diff options
Diffstat (limited to 'proto/ospf/topology.c')
-rw-r--r-- | proto/ospf/topology.c | 114 |
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; |