From 70945cb645402a4bb1d3dc46a07928caeb954c1f Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 26 Jun 2014 11:58:57 +0200 Subject: Temporary integrated OSPF commit. --- proto/ospf/rt.c | 1007 ++++++++++++++++++++++++------------------------------- 1 file changed, 437 insertions(+), 570 deletions(-) (limited to 'proto/ospf/rt.c') diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 2a879c05..c4340ee5 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -1,9 +1,11 @@ /* - * BIRD -- OSPF + * BIRD -- OSPF * - * (c) 2000--2004 Ondrej Filip + * (c) 2000--2004 Ondrej Filip + * (c) 2009--2014 Ondrej Zajicek + * (c) 2009--2014 CZ.NIC z.s.p.o. * - * Can be freely distributed and used under the terms of the GNU GPL. + * Can be freely distributed and used under the terms of the GNU GPL. */ #include "ospf.h" @@ -11,15 +13,7 @@ static void add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, u32 dist, struct ospf_area *oa, int i); -static void rt_sync(struct proto_ospf *po); - -/* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address) - as index, so we need to encapsulate RID to IP address */ -#ifdef OSPFv2 -#define ipa_from_rid(x) _MI(x) -#else /* OSPFv3 */ -#define ipa_from_rid(x) _MI(0,0,0,x) -#endif +static void rt_sync(struct ospf_proto *p); static inline void reset_ri(ort *ort) @@ -33,7 +27,7 @@ ospf_rt_initort(struct fib_node *fn) ort *ri = (ort *) fn; reset_ri(ri); ri->old_rta = NULL; - ri->fn.x0 = ri->fn.x1 = 0; + ri->fn.flags = 0; } static inline int @@ -49,9 +43,9 @@ unresolved_vlink(ort *ort) } static inline struct mpnh * -new_nexthop(struct proto_ospf *po, ip_addr gw, struct iface *iface, unsigned char weight) +new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, unsigned char weight) { - struct mpnh *nh = lp_alloc(po->nhpool, sizeof(struct mpnh)); + struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh)); nh->gw = gw; nh->iface = iface; nh->next = NULL; @@ -60,9 +54,9 @@ new_nexthop(struct proto_ospf *po, ip_addr gw, struct iface *iface, unsigned cha } static inline struct mpnh * -copy_nexthop(struct proto_ospf *po, const struct mpnh *src) +copy_nexthop(struct ospf_proto *p, const struct mpnh *src) { - struct mpnh *nh = lp_alloc(po->nhpool, sizeof(struct mpnh)); + struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh)); nh->gw = src->gw; nh->iface = src->iface; nh->next = NULL; @@ -95,11 +89,11 @@ cmp_nhs(struct mpnh *s1, struct mpnh *s2) } static struct mpnh * -merge_nexthops(struct proto_ospf *po, struct mpnh *s1, struct mpnh *s2, int r1, int r2) +merge_nexthops(struct ospf_proto *p, struct mpnh *s1, struct mpnh *s2, int r1, int r2) { struct mpnh *root = NULL; struct mpnh **n = &root; - int count = po->ecmp; + int count = p->ecmp; /* * r1, r2 signalize whether we can reuse nexthops from s1, s2. @@ -118,17 +112,17 @@ merge_nexthops(struct proto_ospf *po, struct mpnh *s1, struct mpnh *s2, int r1, int cmp = cmp_nhs(s1, s2); if (cmp < 0) { - *n = r1 ? s1 : copy_nexthop(po, s1); + *n = r1 ? s1 : copy_nexthop(p, s1); s1 = s1->next; } else if (cmp > 0) { - *n = r2 ? s2 : copy_nexthop(po, s2); + *n = r2 ? s2 : copy_nexthop(p, s2); s2 = s2->next; } else { - *n = r1 ? s1 : (r2 ? s2 : copy_nexthop(po, s1)); + *n = r1 ? s1 : (r2 ? s2 : copy_nexthop(p, s1)); s1 = s1->next; s2 = s2->next; } @@ -152,7 +146,7 @@ has_device_nexthops(const struct mpnh *n) /* Replace device nexthops with nexthops to gw */ static struct mpnh * -fix_device_nexthops(struct proto_ospf *po, const struct mpnh *n, ip_addr gw) +fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw) { struct mpnh *root1 = NULL; struct mpnh *root2 = NULL; @@ -165,7 +159,7 @@ fix_device_nexthops(struct proto_ospf *po, const struct mpnh *n, ip_addr gw) for (; n; n = n->next) { - struct mpnh *nn = new_nexthop(po, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight); + struct mpnh *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight); if (ipa_zero(n->gw)) { @@ -179,7 +173,7 @@ fix_device_nexthops(struct proto_ospf *po, const struct mpnh *n, ip_addr gw) } } - return merge_nexthops(po, root1, root2, 1, 1); + return merge_nexthops(p, root1, root2, 1, 1); } @@ -235,7 +229,7 @@ orta_prefer_lsa(const orta *new, const orta *old) * the old orta. */ static int -orta_compare(const struct proto_ospf *po, const orta *new, const orta *old) +orta_compare(const struct ospf_proto *p, const orta *new, const orta *old) { int r; @@ -270,7 +264,7 @@ orta_compare(const struct proto_ospf *po, const orta *new, const orta *old) return 1; - if (po->ecmp) + if (p->ecmp) return 0; /* Prefer routes with higher Router ID, just to be more deterministic */ @@ -286,14 +280,14 @@ orta_compare(const struct proto_ospf *po, const orta *new, const orta *old) * than 0 if the new ASBR is less or more preferred than the old ASBR. */ static int -orta_compare_asbr(const struct proto_ospf *po, const orta *new, const orta *old) +orta_compare_asbr(const struct ospf_proto *p, const orta *new, const orta *old) { int r; if (old->type == RTS_DUMMY) return 1; - if (!po->rfc1583) + if (!p->rfc1583) { r = epath_preferred(new) - epath_preferred(old); if (r) return r; @@ -316,7 +310,7 @@ orta_compare_asbr(const struct proto_ospf *po, const orta *new, const orta *old) * than 0 if the new orta is less, equal or more preferred than the old orta. */ static int -orta_compare_ext(const struct proto_ospf *po, const orta *new, const orta *old) +orta_compare_ext(const struct ospf_proto *p, const orta *new, const orta *old) { int r; @@ -335,7 +329,7 @@ orta_compare_ext(const struct proto_ospf *po, const orta *new, const orta *old) } /* 16.4 (6c) - if not RFC1583, prefer routes with preferred ASBR/next_hop */ - if (!po->rfc1583) + if (!p->rfc1583) { r = orta_pref(new) - orta_pref(old); if (r) return r; @@ -346,7 +340,7 @@ orta_compare_ext(const struct proto_ospf *po, const orta *new, const orta *old) if (r) return r; - if (po->ecmp && po->merge_external) + if (p->ecmp && p->merge_external) return 0; /* @@ -369,13 +363,13 @@ ort_replace(ort *o, const orta *new) } static void -ort_merge(struct proto_ospf *po, ort *o, const orta *new) +ort_merge(struct ospf_proto *p, ort *o, const orta *new) { orta *old = &o->n; if (old->nhs != new->nhs) { - old->nhs = merge_nexthops(po, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse); + old->nhs = merge_nexthops(p, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse); old->nhs_reuse = 1; } @@ -384,13 +378,13 @@ ort_merge(struct proto_ospf *po, ort *o, const orta *new) } static void -ort_merge_ext(struct proto_ospf *po, ort *o, const orta *new) +ort_merge_ext(struct ospf_proto *p, ort *o, const orta *new) { orta *old = &o->n; if (old->nhs != new->nhs) { - old->nhs = merge_nexthops(po, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse); + old->nhs = merge_nexthops(p, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse); old->nhs_reuse = 1; } @@ -415,15 +409,15 @@ ort_merge_ext(struct proto_ospf *po, ort *o, const orta *new) static inline void -ri_install_net(struct proto_ospf *po, ip_addr prefix, int pxlen, const orta *new) +ri_install_net(struct ospf_proto *p, ip_addr prefix, int pxlen, const orta *new) { - ort *old = (ort *) fib_get(&po->rtf, &prefix, pxlen); - int cmp = orta_compare(po, new, &old->n); + ort *old = (ort *) fib_get(&p->rtf, &prefix, pxlen); + int cmp = orta_compare(p, new, &old->n); if (cmp > 0) ort_replace(old, new); else if (cmp == 0) - ort_merge(po, old, new); + ort_merge(p, old, new); } static inline void @@ -440,51 +434,55 @@ ri_install_rt(struct ospf_area *oa, u32 rid, const orta *new) } static inline void -ri_install_asbr(struct proto_ospf *po, ip_addr *addr, const orta *new) +ri_install_asbr(struct ospf_proto *p, ip_addr *addr, const orta *new) { - ort *old = (ort *) fib_get(&po->backbone->rtr, addr, MAX_PREFIX_LENGTH); - if (orta_compare_asbr(po, new, &old->n) > 0) + ort *old = (ort *) fib_get(&p->backbone->rtr, addr, MAX_PREFIX_LENGTH); + if (orta_compare_asbr(p, new, &old->n) > 0) ort_replace(old, new); } static inline void -ri_install_ext(struct proto_ospf *po, ip_addr prefix, int pxlen, const orta *new) +ri_install_ext(struct ospf_proto *p, ip_addr prefix, int pxlen, const orta *new) { - ort *old = (ort *) fib_get(&po->rtf, &prefix, pxlen); - int cmp = orta_compare_ext(po, new, &old->n); + ort *old = (ort *) fib_get(&p->rtf, &prefix, pxlen); + int cmp = orta_compare_ext(p, new, &old->n); if (cmp > 0) ort_replace(old, new); else if (cmp == 0) - ort_merge_ext(po, old, new); + ort_merge_ext(p, old, new); } static inline struct ospf_iface * rt_pos_to_ifa(struct ospf_area *oa, int pos) { struct ospf_iface *ifa; + WALK_LIST(ifa, oa->po->iface_list) if (ifa->oa == oa && pos >= ifa->rt_pos_beg && pos < ifa->rt_pos_end) return ifa; + return NULL; } -#ifdef OSPFv3 static inline struct ospf_iface * px_pos_to_ifa(struct ospf_area *oa, int pos) { struct ospf_iface *ifa; + WALK_LIST(ifa, oa->po->iface_list) if (ifa->oa == oa && pos >= ifa->px_pos_beg && pos < ifa->px_pos_end) return ifa; + return NULL; } -#endif static void add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en, int pos) { + struct ospf_proto *p = oa->po; + orta nf = { .type = RTS_OSPF, .options = 0, @@ -499,7 +497,7 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_ if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) { log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", - oa->po->proto.name, en->lsa.type, en->lsa.id, en->lsa.rt); + p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt); return; } @@ -514,24 +512,117 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_ */ struct ospf_iface *ifa; -#ifdef OSPFv2 - ifa = rt_pos_to_ifa(oa, pos); -#else /* OSPFv3 */ - ifa = px_pos_to_ifa(oa, pos); -#endif + ifa = ospf_is_v2(p) ? rt_pos_to_ifa(oa, pos) : px_pos_to_ifa(oa, pos); + nf.nhs = ifa ? new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL; + } + + ri_install_net(p, px, pxlen, &nf); +} + - nf.nhs = ifa ? new_nexthop(oa->po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL; + +static inline void +spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entry *act) +{ + struct ospf_lsa_rt *rt = act->lsa_body; + struct ospf_lsa_rt_walk rtl; + struct top_hash_entry *tmp; + ip_addr prefix; + int pxlen, i; + + if (rt->options & OPT_RT_V) + oa->trcap = 1; + + /* + * In OSPFv3, all routers are added to per-area routing + * tables. But we use it just for ASBRs and ABRs. For the + * purpose of the last step in SPF - prefix-LSA processing in + * spfa_process_prefixes(), we use information stored in LSA db. + */ + if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B)) + && (act->lsa.rt != p->router_id)) + { + orta nf = { + .type = RTS_OSPF, + .options = rt->options, + .metric1 = act->dist, + .metric2 = LSINFINITY, + .tag = 0, + .rid = act->lsa.rt, + .oa = oa, + .nhs = act->nhs + }; + ri_install_rt(oa, act->lsa.rt, &nf); } - ri_install_net(oa->po, px, pxlen, &nf); + /* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */ + if (ospf_is_v3(p) && (act != oa->rt) && !(rt->options & OPT_R)) + break; + + /* Now process Rt links */ + for (lsa_walk_rt_init(p, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++) + { + tmp = NULL; + + switch (rtl.type) + { + case LSART_STUB: + + /* Should not happen, LSART_STUB is not defined in OSPFv3 */ + if (ospf_is_v3(p)) + break; + + /* + * RFC 2328 in 16.1. (2a) says to handle stub networks in an + * second phase after the SPF for an area is calculated. We get + * the same result by handing them here because add_network() + * will keep the best (not the first) found route. + */ + prefix = ipa_from_u32(rtl.id & rtl.data); + pxlen = u32_masklen(rtl.data); + add_network(oa, prefix, pxlen, act->dist + rtl.metric, act, i); + break; + + case LSART_NET: + tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif); + break; + + case LSART_VLNK: + case LSART_PTP: + tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id); + break; + } + + add_cand(&oa->cand, tmp, act, act->dist + rtl.metric, oa, i); + } } -#ifdef OSPFv3 -static void -process_prefixes(struct ospf_area *oa) +static inline void +spfa_process_net(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entry *act) +{ + struct ospf_lsa_net *ln = act->lsa_body; + struct top_hash_entry *tmp; + ip_addr prefix; + int pxlen, i, cnt; + + if (ospf_is_v2(p)) + { + prefix = ipa_from_u32(act->lsa.id & ln->optx); + pxlen = u32_masklen(ln->optx); + add_network(oa, prefix, pxlen, act->dist, act, -1); + } + + cnt = lsa_net_count(&act->lsa); + for (i = 0; i < cnt; i++) + { + tmp = ospf_hash_find_rt(p->gr, oa->areaid, ln->routers[i]); + add_cand(&oa->cand, tmp, act, act->dist, oa, -1); + } +} + +static inline void +spfa_process_prefixes(struct ospf_proto *p, struct ospf_area *oa) { - struct proto_ospf *po = oa->po; - // struct proto *p = &po->proto; struct top_hash_entry *en, *src; struct ospf_lsa_prefix *px; ip_addr pxa; @@ -541,9 +632,9 @@ process_prefixes(struct ospf_area *oa) u32 *buf; int i; - WALK_SLIST(en, po->lsal) + WALK_SLIST(en, p->lsal) { - if (en->lsa.type != LSA_T_PREFIX) + if (en->lsa_type != LSA_T_PREFIX) continue; if (en->domain != oa->areaid) @@ -556,9 +647,9 @@ process_prefixes(struct ospf_area *oa) /* For router prefix-LSA, we would like to find the first router-LSA */ if (px->ref_type == LSA_T_RT) - src = ospf_hash_find_rt(po->gr, oa->areaid, px->ref_rt); + src = ospf_hash_find_rt(p->gr, oa->areaid, px->ref_rt); else - src = ospf_hash_find(po->gr, oa->areaid, px->ref_id, px->ref_rt, px->ref_type); + src = ospf_hash_find(p->gr, oa->areaid, px->ref_id, px->ref_rt, px->ref_type); if (!src) continue; @@ -567,7 +658,7 @@ process_prefixes(struct ospf_area *oa) if (src->color != INSPF) continue; - if ((src->lsa.type != LSA_T_RT) && (src->lsa.type != LSA_T_NET)) + if ((src->lsa_type != LSA_T_RT) && (src->lsa_type != LSA_T_NET)) continue; buf = px->rest; @@ -586,80 +677,13 @@ process_prefixes(struct ospf_area *oa) } } } -#endif - - -static void -ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct top_hash_entry *en) -{ - // struct proto *p = &oa->po->proto; - struct proto_ospf *po = oa->po; - ip_addr prefix UNUSED; - int pxlen UNUSED, i; - - struct ospf_lsa_rt *rt = en->lsa_body; - struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1); - - for (i = 0; i < lsa_rt_count(&en->lsa); i++) - { - struct ospf_lsa_rt_link *rtl = rr + i; - struct top_hash_entry *tmp = NULL; - - DBG(" Working on link: %R (type: %u) ", rtl->id, rtl->type); - switch (rtl->type) - { -#ifdef OSPFv2 - case LSART_STUB: - /* - * RFC 2328 in 16.1. (2a) says to handle stub networks in an - * second phase after the SPF for an area is calculated. We get - * the same result by handing them here because add_network() - * will keep the best (not the first) found route. - */ - prefix = ipa_from_u32(rtl->id & rtl->data); - pxlen = ipa_mklen(ipa_from_u32(rtl->data)); - add_network(oa, prefix, pxlen, act->dist + rtl->metric, act, i); - break; -#endif - - case LSART_NET: -#ifdef OSPFv2 - /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */ - tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id); -#else /* OSPFv3 */ - tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET); -#endif - break; - - case LSART_VLNK: - case LSART_PTP: - tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id); - break; - - default: - log("Unknown link type in router lsa. (rid = %R)", act->lsa.id); - break; - } - - if (tmp) - DBG("Going to add cand, Mydist: %u, Req: %u\n", - tmp->dist, act->dist + rtl->metric); - add_cand(&oa->cand, tmp, act, act->dist + rtl->metric, oa, i); - } -} /* RFC 2328 16.1. calculating shortest paths for an area */ static void ospf_rt_spfa(struct ospf_area *oa) { - struct proto *p = &oa->po->proto; - struct proto_ospf *po = oa->po; - struct ospf_lsa_rt *rt; - struct ospf_lsa_net *ln; - struct top_hash_entry *act, *tmp; - ip_addr prefix UNUSED; - int pxlen UNUSED; - u32 i, *rts; + struct ospf_proto *p = oa->po; + struct top_hash_entry *act; node *n; if (oa->rt == NULL) @@ -677,7 +701,7 @@ ospf_rt_spfa(struct ospf_area *oa) oa->rt->color = CANDIDATE; add_head(&oa->cand, &oa->rt->cn); DBG("RT LSA: rt: %R, id: %R, type: %u\n", - oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa.type); + oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa_type); while (!EMPTY_LIST(oa->cand)) { @@ -686,89 +710,36 @@ ospf_rt_spfa(struct ospf_area *oa) rem_node(n); DBG("Working on LSA: rt: %R, id: %R, type: %u\n", - act->lsa.rt, act->lsa.id, act->lsa.type); + act->lsa.rt, act->lsa.id, act->lsa_type); act->color = INSPF; - switch (act->lsa.type) + switch (act->lsa_type) { case LSA_T_RT: - rt = (struct ospf_lsa_rt *) act->lsa_body; - if (rt->options & OPT_RT_V) - oa->trcap = 1; - - /* - * In OSPFv3, all routers are added to per-area routing - * tables. But we use it just for ASBRs and ABRs. For the - * purpose of the last step in SPF - prefix-LSA processing in - * process_prefixes(), we use information stored in LSA db. - */ - if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B)) - && (act->lsa.rt != po->router_id)) - { - orta nf = { - .type = RTS_OSPF, - .options = rt->options, - .metric1 = act->dist, - .metric2 = LSINFINITY, - .tag = 0, - .rid = act->lsa.rt, - .oa = oa, - .nhs = act->nhs - }; - ri_install_rt(oa, act->lsa.rt, &nf); - } - -#ifdef OSPFv2 - ospf_rt_spfa_rtlinks(oa, act, act); -#else /* OSPFv3 */ - /* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */ - if ((act != oa->rt) && !(rt->options & OPT_R)) - break; - - for (tmp = ospf_hash_find_rt_first(po->gr, act->domain, act->lsa.rt); - tmp; tmp = ospf_hash_find_rt_next(tmp)) - ospf_rt_spfa_rtlinks(oa, act, tmp); -#endif - + spfa_process_rt(p, oa, act); break; - case LSA_T_NET: - ln = act->lsa_body; -#ifdef OSPFv2 - prefix = ipa_and(ipa_from_u32(act->lsa.id), ln->netmask); - pxlen = ipa_mklen(ln->netmask); - add_network(oa, prefix, pxlen, act->dist, act, -1); -#endif - - rts = (u32 *) (ln + 1); - for (i = 0; i < lsa_net_count(&act->lsa); i++) - { - DBG(" Working on router %R ", rts[i]); - tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]); - if (tmp != NULL) - DBG("Found :-)\n"); - else - DBG("Not found!\n"); - add_cand(&oa->cand, tmp, act, act->dist, oa, -1); - } + case LSA_T_NET: + spfa_process_net(p, oa, act); break; + + default: + log(L_WARN "%s: Unknown LSA type in SPF: %d", p->p.name, act->lsa_type); } } -#ifdef OSPFv3 - process_prefixes(oa); -#endif + if (ospf_is_v3(p)) + spfa_process_prefixes(p, oa); } static int link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par) { - u32 i, *rts; - struct ospf_lsa_net *ln; - struct ospf_lsa_rt *rt; - struct ospf_lsa_rt_link *rtl, *rr; + struct ospf_proto *p = oa->po; + struct ospf_lsa_rt_walk rtl; struct top_hash_entry *tmp; - struct proto_ospf *po = oa->po; + struct ospf_lsa_net *ln; + u32 i, cnt; if (!en || !par) return 0; @@ -783,65 +754,56 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry it is set in process_prefixes() to any global addres in the area */ en->lb = IPA_NONE; -#ifdef OSPFv3 en->lb_id = 0; -#endif - switch (en->lsa.type) + + switch (en->lsa_type) { - case LSA_T_RT: - rt = (struct ospf_lsa_rt *) en->lsa_body; - rr = (struct ospf_lsa_rt_link *) (rt + 1); - for (i = 0; i < lsa_rt_count(&en->lsa); i++) + case LSA_T_RT: + lsa_walk_rt_init(p, en, &rtl); + while (lsa_walk_rt(&rtl)) + { + switch (rtl.type) { - rtl = (rr + i); - switch (rtl->type) + case LSART_STUB: + break; + + case LSART_NET: + tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif); + if (tmp == par) { - case LSART_STUB: - break; - case LSART_NET: -#ifdef OSPFv2 - /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */ - tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id); -#else /* OSPFv3 */ - tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET); -#endif - if (tmp == par) - { -#ifdef OSPFv2 - en->lb = ipa_from_u32(rtl->data); -#else /* OSPFv3 */ - en->lb_id = rtl->lif; -#endif - return 1; - } - - break; - case LSART_VLNK: - case LSART_PTP: - /* Not necessary the same link, see RFC 2328 [23] */ - tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id); - if (tmp == par) - return 1; - - break; - default: - log(L_WARN "Unknown link type in router lsa. (rid = %R)", en->lsa.rt); - break; + if (ospf_is_v2(p)) + en->lb = ipa_from_u32(rtl.data); + else + en->lb_id = rtl.lif; + + return 1; } - } - break; - case LSA_T_NET: - ln = en->lsa_body; - rts = (u32 *) (ln + 1); - for (i = 0; i < lsa_net_count(&en->lsa); i++) - { - tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]); + break; + + case LSART_VLNK: + case LSART_PTP: + /* Not necessary the same link, see RFC 2328 [23] */ + tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id); if (tmp == par) - return 1; + return 1; + break; } - break; - default: - bug("Unknown lsa type %x.", en->lsa.type); + } + break; + + case LSA_T_NET: + ln = en->lsa_body; + cnt = lsa_net_count(&en->lsa); + for (i = 0; i < cnt; i++) + { + tmp = ospf_hash_find_rt(p->gr, oa->areaid, ln->routers[i]); + if (tmp == par) + return 1; + } + break; + + default: + log(L_WARN "%s: Unknown LSA type in SPF: %d", p->p.name, en->lsa_type); } return 0; } @@ -851,20 +813,20 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry static void ospf_rt_sum(struct ospf_area *oa) { - struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; + struct ospf_proto *p = oa->po; struct top_hash_entry *en; - ip_addr ip = IPA_NONE; - u32 dst_rid = 0; - u32 metric, options; + ip_addr ip, abrip; + u32 dst_rid, metric, options; ort *abr; int pxlen = -1, type = -1; + u8 pxopts; + OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid); - WALK_SLIST(en, po->lsal) + WALK_SLIST(en, p->lsal) { - if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) + if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET)) continue; if (en->domain != oa->areaid) @@ -875,55 +837,36 @@ ospf_rt_sum(struct ospf_area *oa) continue; /* 16.2. (2) */ - if (en->lsa.rt == po->router_id) + if (en->lsa.rt == p->router_id) continue; /* 16.2. (3) is handled later in ospf_rt_abr() by resetting such rt entry */ - if (en->lsa.type == LSA_T_SUM_NET) + if (en->lsa_type == LSA_T_SUM_NET) { -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = en->lsa_body; - ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask); - pxlen = ipa_mklen(ls->netmask); -#else /* OSPFv3 */ - u8 pxopts; - u16 rest; - struct ospf_lsa_sum_net *ls = en->lsa_body; - lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest); + lsa_parse_sum_net(en, ospf_is_v2(p), &ip, &pxlen, &pxopts, &metric); if (pxopts & OPT_PX_NU) continue; -#endif if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) { log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", - p->name, en->lsa.type, en->lsa.id, en->lsa.rt); + p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt); continue; } - metric = ls->metric & METRIC_MASK; options = 0; type = ORT_NET; } else /* LSA_T_SUM_RT */ { -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = en->lsa_body; - dst_rid = en->lsa.id; - options = 0; -#else /* OSPFv3 */ - struct ospf_lsa_sum_rt *ls = en->lsa_body; - dst_rid = ls->drid; - options = ls->options & OPTIONS_MASK; -#endif + lsa_parse_sum_rt(en, ospf_is_v2(p), &dst_rid, &metric, &options); /* We don't want local router in ASBR routing table */ - if (dst_rid == po->router_id) + if (dst_rid == p->router_id) continue; - metric = ls->metric & METRIC_MASK; options |= ORTA_ASBR; type = ORT_ROUTER; } @@ -933,7 +876,7 @@ ospf_rt_sum(struct ospf_area *oa) continue; /* 16.2. (4) */ - ip_addr abrip = ipa_from_rid(en->lsa.rt); + abrip = ipa_from_rid(en->lsa.rt); abr = (ort *) fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH); if (!abr || !abr->n.type) continue; @@ -958,7 +901,7 @@ ospf_rt_sum(struct ospf_area *oa) }; if (type == ORT_NET) - ri_install_net(po, ip, pxlen, &nf); + ri_install_net(p, ip, pxlen, &nf); else ri_install_rt(oa, dst_rid, &nf); } @@ -968,20 +911,22 @@ ospf_rt_sum(struct ospf_area *oa) static void ospf_rt_sum_tr(struct ospf_area *oa) { - struct proto *p = &oa->po->proto; - struct proto_ospf *po = oa->po; - struct ospf_area *bb = po->backbone; - ip_addr abrip; + struct ospf_proto *p = oa->po; + struct ospf_area *bb = p->backbone; struct top_hash_entry *en; - u32 dst_rid, metric; - ort *re = NULL, *abr; + ort *re, *abr; + ip_addr ip, abrip; + u32 dst_rid, metric, options; + int pxlen; + u8 pxopts; - if (!bb) return; + if (!bb) + return; - WALK_SLIST(en, po->lsal) + WALK_SLIST(en, p->lsal) { - if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) + if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET)) continue; if (en->domain != oa->areaid) @@ -992,49 +937,30 @@ ospf_rt_sum_tr(struct ospf_area *oa) continue; /* 16.3 (2) */ - if (en->lsa.rt == po->router_id) + if (en->lsa.rt == p->router_id) continue; - if (en->lsa.type == LSA_T_SUM_NET) + if (en->lsa_type == LSA_T_SUM_NET) { - ip_addr ip; - int pxlen; -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = en->lsa_body; - ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask); - pxlen = ipa_mklen(ls->netmask); -#else /* OSPFv3 */ - u8 pxopts; - u16 rest; - struct ospf_lsa_sum_net *ls = en->lsa_body; - lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest); + lsa_parse_sum_net(en, ospf_is_v2(p), &ip, &pxlen, &pxopts, &metric); if (pxopts & OPT_PX_NU) continue; -#endif if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) { log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", - p->name, en->lsa.type, en->lsa.id, en->lsa.rt); + p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt); continue; } - metric = ls->metric & METRIC_MASK; - re = fib_find(&po->rtf, &ip, pxlen); + re = fib_find(&p->rtf, &ip, pxlen); } - else // en->lsa.type == LSA_T_SUM_RT + else // en->lsa_type == LSA_T_SUM_RT { -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = en->lsa_body; - dst_rid = en->lsa.id; -#else /* OSPFv3 */ - struct ospf_lsa_sum_rt *ls = en->lsa_body; - dst_rid = ls->drid; -#endif - - metric = ls->metric & METRIC_MASK; - ip_addr ip = ipa_from_rid(dst_rid); + lsa_parse_sum_rt(en, ospf_is_v2(p), &dst_rid, &metric, &options); + + ip = ipa_from_rid(dst_rid); re = fib_find(&bb->rtr, &ip, MAX_PREFIX_LENGTH); } @@ -1156,20 +1082,20 @@ decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest) /* RFC 2328 16.7. p1 - originate or flush summary LSAs */ static inline void -check_sum_net_lsa(struct proto_ospf *po, ort *nf) +check_sum_net_lsa(struct ospf_proto *p, ort *nf) { struct area_net *anet = NULL; struct ospf_area *anet_oa = NULL; /* RT entry marked as area network */ - if (nf->fn.x0) + if (nf->fn.flags & OSPF_RT_PERSISTENT) { /* It is a default route for stub areas, handled entirely in ospf_rt_abr() */ if (nf->fn.pxlen == 0) return; /* Find that area network */ - WALK_LIST(anet_oa, po->area_list) + WALK_LIST(anet_oa, p->area_list) { anet = (struct area_net *) fib_find(&anet_oa->net_fib, &nf->fn.prefix, nf->fn.pxlen); if (anet) @@ -1178,36 +1104,29 @@ check_sum_net_lsa(struct proto_ospf *po, ort *nf) } struct ospf_area *oa; - WALK_LIST(oa, po->area_list) + WALK_LIST(oa, p->area_list) { if (anet && decide_anet_lsa(oa, anet, anet_oa)) - originate_sum_net_lsa(oa, &nf->fn, anet->metric); + ospf_originate_sum_net_lsa(p, oa, nf, anet->metric); else if (decide_sum_lsa(oa, nf, ORT_NET)) - originate_sum_net_lsa(oa, &nf->fn, nf->n.metric1); - else - flush_sum_lsa(oa, &nf->fn, ORT_NET); + ospf_originate_sum_net_lsa(p, oa, nf, nf->n.metric1); } } static inline void -check_sum_rt_lsa(struct proto_ospf *po, ort *nf) +check_sum_rt_lsa(struct ospf_proto *p, ort *nf) { struct ospf_area *oa; - WALK_LIST(oa, po->area_list) - { + WALK_LIST(oa, p->area_list) if (decide_sum_lsa(oa, nf, ORT_ROUTER)) - originate_sum_rt_lsa(oa, &nf->fn, nf->n.metric1, nf->n.options); - else - flush_sum_lsa(oa, &nf->fn, ORT_ROUTER); - } + ospf_originate_sum_rt_lsa(p, oa, nf, nf->n.metric1, nf->n.options); } static inline int -decide_nssa_lsa(ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag) +decide_nssa_lsa(struct ospf_proto *p, ort *nf, struct ospf_lsa_ext_local *rt) { struct ospf_area *oa = nf->n.oa; struct top_hash_entry *en = nf->n.en; - int propagate; if (!rt_is_nssa(nf) || !oa->translate) return 0; @@ -1216,66 +1135,40 @@ decide_nssa_lsa(ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag) if (fib_route(&oa->enet_fib, nf->fn.prefix, nf->fn.pxlen)) return 0; - if (!en || (en->lsa.type != LSA_T_NSSA)) + if (!en || (en->lsa_type != LSA_T_NSSA)) return 0; /* We do not store needed data in struct orta, we have to parse the LSA */ - struct ospf_lsa_ext *le = en->lsa_body; - -#ifdef OSPFv2 - *rt_fwaddr = le->fwaddr; - *rt_tag = le->tag; - propagate = en->lsa.options & OPT_P; -#else /* OSPFv3 */ - u32 *buf = le->rest; - u8 pxlen = (*buf >> 24); - u8 pxopts = (*buf >> 16); - buf += IPV6_PREFIX_WORDS(pxlen); /* Skip the IP prefix */ - - if (pxopts & OPT_PX_NU) + lsa_parse_ext(en, ospf_is_v2(p), rt); + + if (rt->pxopts & OPT_PX_NU) return 0; - if (le->metric & LSA_EXT_FBIT) - buf = lsa_get_ipv6_addr(buf, rt_fwaddr); - else - *rt_fwaddr = IPA_NONE; - - if (le->metric & LSA_EXT_TBIT) - *rt_tag = *buf++; - else - *rt_tag = 0; - - propagate = pxopts & OPT_PX_P; -#endif - - if (!propagate || ipa_zero(*rt_fwaddr)) + if (!rt->propagate || ipa_zero(rt->fwaddr)) return 0; - *rt_metric = le->metric & (METRIC_MASK | LSA_EXT_EBIT); return 1; } /* RFC 3103 3.2 - translating Type-7 LSAs into Type-5 LSAs */ static inline void -check_nssa_lsa(struct proto_ospf *po, ort *nf) +check_nssa_lsa(struct ospf_proto *p, ort *nf) { - struct fib_node *fn = &nf->fn; struct area_net *anet = NULL; struct ospf_area *oa = NULL; - u32 rt_metric, rt_tag; - ip_addr rt_fwaddr; + struct ospf_lsa_ext_local rt; /* Do not translate LSA if there is already the external LSA from route export */ - if (fn->x1 == EXT_EXPORT) + if (nf->external_rte) return; /* RT entry marked as area network */ - if (fn->x0) + if (nf->fn.flags & OSPF_RT_PERSISTENT) { /* Find that area network */ - WALK_LIST(oa, po->area_list) + WALK_LIST(oa, p->area_list) { - anet = (struct area_net *) fib_find(&oa->enet_fib, &fn->prefix, fn->pxlen); + anet = (struct area_net *) fib_find(&oa->enet_fib, &nf->fn.prefix, nf->fn.pxlen); if (anet) break; } @@ -1283,33 +1176,29 @@ check_nssa_lsa(struct proto_ospf *po, ort *nf) /* RFC 3103 3.2 (3) - originate the aggregated address range */ if (anet && anet->active && !anet->hidden && oa->translate) - originate_ext_lsa(po->backbone, fn, EXT_NSSA, anet->metric, IPA_NONE, anet->tag, 0); + ospf_originate_ext_lsa(p, NULL, nf, LSA_RTCALC, anet->metric, + (anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0); /* RFC 3103 3.2 (2) - originate the same network */ - else if (decide_nssa_lsa(nf, &rt_metric, &rt_fwaddr, &rt_tag)) - originate_ext_lsa(po->backbone, fn, EXT_NSSA, rt_metric, rt_fwaddr, rt_tag, 0); - - else if (fn->x1 == EXT_NSSA) - flush_ext_lsa(po->backbone, fn, 0); + else if (decide_nssa_lsa(p, nf, &rt)) + ospf_originate_ext_lsa(p, NULL, nf, LSA_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0); } /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */ static void -ospf_check_vlinks(struct proto_ospf *po) +ospf_check_vlinks(struct ospf_proto *p) { - struct proto *p = &po->proto; - struct ospf_iface *ifa; - WALK_LIST(ifa, po->iface_list) + WALK_LIST(ifa, p->iface_list) { if (ifa->type == OSPF_IT_VLINK) { struct top_hash_entry *tmp; - tmp = ospf_hash_find_rt(po->gr, ifa->voa->areaid, ifa->vid); + tmp = ospf_hash_find_rt(p->gr, ifa->voa->areaid, ifa->vid); if (tmp && (tmp->color == INSPF) && ipa_nonzero(tmp->lb) && tmp->nhs) { - struct ospf_iface *nhi = ospf_iface_find(po, tmp->nhs->iface); + struct ospf_iface *nhi = ospf_iface_find(p, tmp->nhs->iface); if ((ifa->state != OSPF_IS_PTP) || (ifa->vifa != nhi) @@ -1326,7 +1215,9 @@ ospf_check_vlinks(struct proto_ospf *po) else if ((ifa->state == OSPF_IS_PTP) && (ifa->cost != tmp->dist)) { ifa->cost = tmp->dist; - schedule_rt_lsa(po->backbone); + + /* RFC 2328 12.4 Event 8 - vlink state change */ + ospf_notify_rt_lsa(ifa->oa); } } else @@ -1344,13 +1235,13 @@ ospf_check_vlinks(struct proto_ospf *po) /* Miscellaneous route processing that needs to be done by ABRs */ static void -ospf_rt_abr1(struct proto_ospf *po) +ospf_rt_abr1(struct ospf_proto *p) { struct area_net *anet; ort *nf, *default_nf; /* RFC 2328 G.3 - incomplete resolution of virtual next hops - routers */ - FIB_WALK(&po->backbone->rtr, nftmp) + FIB_WALK(&p->backbone->rtr, nftmp) { nf = (ort *) nftmp; @@ -1360,7 +1251,7 @@ ospf_rt_abr1(struct proto_ospf *po) FIB_WALK_END; - FIB_WALK(&po->rtf, nftmp) + FIB_WALK(&p->rtf, nftmp) { nf = (ort *) nftmp; @@ -1381,8 +1272,8 @@ ospf_rt_abr1(struct proto_ospf *po) anet->active = 1; /* Get a RT entry and mark it to know that it is an area network */ - ort *nfi = (ort *) fib_get(&po->rtf, &anet->fn.prefix, anet->fn.pxlen); - nfi->fn.x0 = 1; /* mark and keep persistent, to have stable UID */ + ort *nfi = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen); + nfi->fn.flags |= OSPF_RT_PERSISTENT; /* mark persistent, to have stable UID */ /* 16.2. (3) */ if (nfi->n.type == RTS_OSPF_IA) @@ -1397,18 +1288,16 @@ ospf_rt_abr1(struct proto_ospf *po) FIB_WALK_END; ip_addr addr = IPA_NONE; - default_nf = (ort *) fib_get(&po->rtf, &addr, 0); - default_nf->fn.x0 = 1; /* keep persistent */ + default_nf = (ort *) fib_get(&p->rtf, &addr, 0); + default_nf->fn.flags |= OSPF_RT_PERSISTENT; /* keep persistent */ struct ospf_area *oa; - WALK_LIST(oa, po->area_list) + WALK_LIST(oa, p->area_list) { /* 12.4.3.1. - originate or flush default route for stub/NSSA areas */ if (oa_is_stub(oa) || (oa_is_nssa(oa) && !oa->ac->summary)) - originate_sum_net_lsa(oa, &default_nf->fn, oa->ac->default_cost); - else - flush_sum_lsa(oa, &default_nf->fn, ORT_NET); + ospf_originate_sum_net_lsa(p, oa, default_nf, oa->ac->default_cost); /* * Originate type-7 default route for NSSA areas @@ -1420,10 +1309,8 @@ ospf_rt_abr1(struct proto_ospf *po) */ if (oa_is_nssa(oa) && oa->ac->default_nssa) - originate_ext_lsa(oa, &default_nf->fn, 0, oa->ac->default_cost, IPA_NONE, 0, 0); - else - flush_ext_lsa(oa, &default_nf->fn, 1); - + ospf_originate_ext_lsa(p, oa, default_nf, LSA_RTCALC, oa->ac->default_cost, + (oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0); /* RFC 2328 16.4. (3) - precompute preferred ASBR entries */ if (oa_is_ext(oa)) @@ -1432,7 +1319,7 @@ ospf_rt_abr1(struct proto_ospf *po) { nf = (ort *) nftmp; if (nf->n.options & ORTA_ASBR) - ri_install_asbr(po, &nf->fn.prefix, &nf->n); + ri_install_asbr(p, &nf->fn.prefix, &nf->n); } FIB_WALK_END; } @@ -1440,15 +1327,15 @@ ospf_rt_abr1(struct proto_ospf *po) /* Originate or flush ASBR summary LSAs */ - FIB_WALK(&po->backbone->rtr, nftmp) + FIB_WALK(&p->backbone->rtr, nftmp) { - check_sum_rt_lsa(po, (ort *) nftmp); + check_sum_rt_lsa(p, (ort *) nftmp); } FIB_WALK_END; /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */ - ospf_check_vlinks(po); + ospf_check_vlinks(p); } @@ -1465,7 +1352,7 @@ translator_timer_hook(timer *timer) } static void -ospf_rt_abr2(struct proto_ospf *po) +ospf_rt_abr2(struct ospf_proto *p) { struct ospf_area *oa; struct top_hash_entry *en; @@ -1473,8 +1360,8 @@ ospf_rt_abr2(struct proto_ospf *po) /* RFC 3103 3.1 - type-7 translator election */ - struct ospf_area *bb = po->backbone; - WALK_LIST(oa, po->area_list) + struct ospf_area *bb = p->backbone; + WALK_LIST(oa, p->area_list) if (oa_is_nssa(oa)) { int translate = 1; @@ -1492,13 +1379,13 @@ ospf_rt_abr2(struct proto_ospf *po) if (!nf2 || !nf2->n.type || !(nf2->n.options & ORTA_ABR)) continue; - en = ospf_hash_find_rt(po->gr, oa->areaid, nf->n.rid); + en = ospf_hash_find_rt(p->gr, oa->areaid, nf->n.rid); if (!en || (en->color != INSPF)) continue; struct ospf_lsa_rt *rt = en->lsa_body; /* There is better candidate - Nt-bit or higher Router ID */ - if ((rt->options & OPT_RT_NT) || (po->router_id < nf->n.rid)) + if ((rt->options & OPT_RT_NT) || (p->router_id < nf->n.rid)) { translate = 0; goto decided; @@ -1518,7 +1405,7 @@ ospf_rt_abr2(struct proto_ospf *po) if (!translate && (oa->translate == TRANS_ON)) { if (oa->translator_timer == NULL) - oa->translator_timer = tm_new_set(po->proto.pool, translator_timer_hook, oa, 0, 0); + oa->translator_timer = tm_new_set(p->p.pool, translator_timer_hook, oa, 0, 0); /* Schedule the end of translation */ tm_start(oa->translator_timer, oa->ac->transint); @@ -1528,7 +1415,7 @@ ospf_rt_abr2(struct proto_ospf *po) /* Compute condensed external networks */ - FIB_WALK(&po->rtf, nftmp) + FIB_WALK(&p->rtf, nftmp) { nf = (ort *) nftmp; if (rt_is_nssa(nf) && (nf->n.options & ORTA_PROP)) @@ -1543,12 +1430,12 @@ ospf_rt_abr2(struct proto_ospf *po) anet->active = 1; /* Get a RT entry and mark it to know that it is an area network */ - nf2 = (ort *) fib_get(&po->rtf, &anet->fn.prefix, anet->fn.pxlen); - nf2->fn.x0 = 1; + nf2 = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen); + nf2->fn.flags |= OSPF_RT_PERSISTENT; /* keep persistent */ } u32 metric = (nf->n.type == RTS_OSPF_EXT1) ? - nf->n.metric1 : ((nf->n.metric2 + 1) | LSA_EXT_EBIT); + nf->n.metric1 : ((nf->n.metric2 + 1) | LSA_EXT3_EBIT); if (anet->metric < metric) anet->metric = metric; @@ -1558,12 +1445,12 @@ ospf_rt_abr2(struct proto_ospf *po) FIB_WALK_END; - FIB_WALK(&po->rtf, nftmp) + FIB_WALK(&p->rtf, nftmp) { nf = (ort *) nftmp; - check_sum_net_lsa(po, nf); - check_nssa_lsa(po, nf); + check_sum_net_lsa(p, nf); + check_nssa_lsa(p, nf); } FIB_WALK_END; } @@ -1589,78 +1476,46 @@ ospf_fib_route(struct fib *f, ip_addr a, int len) /* RFC 2328 16.4. calculating external routes */ static void -ospf_ext_spf(struct proto_ospf *po) +ospf_ext_spf(struct ospf_proto *p) { + struct top_hash_entry *en; + struct ospf_lsa_ext_local rt; ort *nf1, *nf2; orta nfa = {}; - struct top_hash_entry *en; - struct proto *p = &po->proto; - struct ospf_lsa_ext *le; - int pxlen, ebit, rt_fwaddr_valid, rt_propagate; - ip_addr ip, rtid, rt_fwaddr; - u32 br_metric, rt_metric, rt_tag; + ip_addr rtid; + u32 br_metric; struct ospf_area *atmp; OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes"); - WALK_SLIST(en, po->lsal) + WALK_SLIST(en, p->lsal) { /* 16.4. (1) */ - if ((en->lsa.type != LSA_T_EXT) && (en->lsa.type != LSA_T_NSSA)) + if ((en->lsa_type != LSA_T_EXT) && (en->lsa_type != LSA_T_NSSA)) continue; if (en->lsa.age == LSA_MAXAGE) continue; /* 16.4. (2) */ - if (en->lsa.rt == po->router_id) + if (en->lsa.rt == p->router_id) continue; DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n", - p->name, en->lsa.id, en->lsa.rt, en->lsa.type); + p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type); - le = en->lsa_body; + lsa_parse_ext(en, ospf_is_v2(p), &rt); - rt_metric = le->metric & METRIC_MASK; - ebit = le->metric & LSA_EXT_EBIT; - - if (rt_metric == LSINFINITY) + if (rt.metric == LSINFINITY) continue; -#ifdef OSPFv2 - ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask); - pxlen = ipa_mklen(le->netmask); - rt_fwaddr = le->fwaddr; - rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE); - rt_tag = le->tag; - rt_propagate = en->lsa.options & OPT_P; -#else /* OSPFv3 */ - u8 pxopts; - u16 rest; - u32 *buf = le->rest; - buf = lsa_get_ipv6_prefix(buf, &ip, &pxlen, &pxopts, &rest); - - if (pxopts & OPT_PX_NU) + if (rt.pxopts & OPT_PX_NU) continue; - rt_fwaddr_valid = le->metric & LSA_EXT_FBIT; - if (rt_fwaddr_valid) - buf = lsa_get_ipv6_addr(buf, &rt_fwaddr); - else - rt_fwaddr = IPA_NONE; - - if (le->metric & LSA_EXT_TBIT) - rt_tag = *buf++; - else - rt_tag = 0; - - rt_propagate = pxopts & OPT_PX_P; -#endif - - if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) + if (rt.pxlen < 0 || rt.pxlen > MAX_PREFIX_LENGTH) { log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", - p->name, en->lsa.type, en->lsa.id, en->lsa.rt); + p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt); continue; } @@ -1669,10 +1524,10 @@ ospf_ext_spf(struct proto_ospf *po) /* If there are more areas, we already precomputed preferred ASBR entries in ospf_rt_abr1() and stored them in the backbone table. For NSSA, we examine the area to which the LSA is assigned */ - if (en->lsa.type == LSA_T_EXT) - atmp = ospf_main_area(po); + if (en->lsa_type == LSA_T_EXT) + atmp = ospf_main_area(p); else /* NSSA */ - atmp = ospf_find_area(po, en->domain); + atmp = ospf_find_area(p, en->domain); if (!atmp) continue; /* Should not happen */ @@ -1688,11 +1543,11 @@ ospf_ext_spf(struct proto_ospf *po) /* 16.4. (3) NSSA - special rule for default routes */ /* ABR should use default only if P-bit is set and summaries are active */ - if ((en->lsa.type == LSA_T_NSSA) && ipa_zero(ip) && (pxlen == 0) && - (po->areano > 1) && !(rt_propagate && atmp->ac->summary)) + if ((en->lsa_type == LSA_T_NSSA) && ipa_zero(rt.ip) && (rt.pxlen == 0) && + (p->areano > 1) && !(rt.propagate && atmp->ac->summary)) continue; - if (!rt_fwaddr_valid) + if (!rt.fbit) { nf2 = nf1; nfa.nhs = nf1->n.nhs; @@ -1700,11 +1555,11 @@ ospf_ext_spf(struct proto_ospf *po) } else { - nf2 = ospf_fib_route(&po->rtf, rt_fwaddr, MAX_PREFIX_LENGTH); + nf2 = ospf_fib_route(&p->rtf, rt.fwaddr, MAX_PREFIX_LENGTH); if (!nf2) continue; - if (en->lsa.type == LSA_T_EXT) + if (en->lsa_type == LSA_T_EXT) { /* For ext routes, we accept intra-area or inter-area routes */ if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA)) @@ -1727,21 +1582,21 @@ ospf_ext_spf(struct proto_ospf *po) /* Replace device nexthops with nexthops to forwarding address from LSA */ if (has_device_nexthops(nfa.nhs)) { - nfa.nhs = fix_device_nexthops(po, nfa.nhs, rt_fwaddr); + nfa.nhs = fix_device_nexthops(p, nfa.nhs, rt.fwaddr); nfa.nhs_reuse = 1; } } - if (ebit) + if (rt.ebit) { nfa.type = RTS_OSPF_EXT2; nfa.metric1 = br_metric; - nfa.metric2 = rt_metric; + nfa.metric2 = rt.metric; } else { nfa.type = RTS_OSPF_EXT1; - nfa.metric1 = br_metric + rt_metric; + nfa.metric1 = br_metric + rt.metric; nfa.metric2 = LSINFINITY; } @@ -1750,25 +1605,25 @@ ospf_ext_spf(struct proto_ospf *po) /* Whether the route is preferred in route selection according to 16.4.1 */ nfa.options = epath_preferred(&nf2->n) ? ORTA_PREF : 0; - if (en->lsa.type == LSA_T_NSSA) + if (en->lsa_type == LSA_T_NSSA) { nfa.options |= ORTA_NSSA; - if (rt_propagate) + if (rt.propagate) nfa.options |= ORTA_PROP; } - nfa.tag = rt_tag; + nfa.tag = rt.tag; nfa.rid = en->lsa.rt; nfa.oa = atmp; /* undefined in RFC 2328 */ nfa.en = en; /* store LSA for later (NSSA processing) */ - ri_install_ext(po, ip, pxlen, &nfa); + ri_install_ext(p, rt.ip, rt.pxlen, &nfa); } } /* Cleanup of routing tables and data */ void -ospf_rt_reset(struct proto_ospf *po) +ospf_rt_reset(struct ospf_proto *p) { struct ospf_area *oa; struct top_hash_entry *en; @@ -1776,24 +1631,27 @@ ospf_rt_reset(struct proto_ospf *po) ort *ri; /* Reset old routing table */ - FIB_WALK(&po->rtf, nftmp) + FIB_WALK(&p->rtf, nftmp) { ri = (ort *) nftmp; - ri->fn.x0 = 0; + ri->fn.flags &= ~OSPF_RT_PERSISTENT; reset_ri(ri); } FIB_WALK_END; /* Reset SPF data in LSA db */ - WALK_SLIST(en, po->lsal) + WALK_SLIST(en, p->lsal) { en->color = OUTSPF; en->dist = LSINFINITY; en->nhs = NULL; en->lb = IPA_NONE; + + if (en->rtcalc == LSA_RTCALC) + en->rtcalc = LSA_STALE; } - WALK_LIST(oa, po->area_list) + WALK_LIST(oa, p->area_list) { /* Reset ASBR routing tables */ FIB_WALK(&oa->rtr, nftmp) @@ -1804,7 +1662,7 @@ ospf_rt_reset(struct proto_ospf *po) FIB_WALK_END; /* Reset condensed area networks */ - if (po->areano > 1) + if (p->areano > 1) { FIB_WALK(&oa->net_fib, nftmp) { @@ -1825,53 +1683,57 @@ ospf_rt_reset(struct proto_ospf *po) } } +static void +ospf_flush_stale(struct ospf_proto *p) +{ +} + /** * ospf_rt_spf - calculate internal routes - * @po: OSPF protocol + * @p: OSPF protocol * * Calculation of internal paths in an area is described in 16.1 of RFC 2328. * It's based on Dijkstra's shortest path tree algorithms. * This function is invoked from ospf_disp(). */ void -ospf_rt_spf(struct proto_ospf *po) +ospf_rt_spf(struct ospf_proto *p) { - struct proto *p = &po->proto; struct ospf_area *oa; - if (po->areano == 0) + if (p->areano == 0) return; OSPF_TRACE(D_EVENTS, "Starting routing table calculation"); /* 16. (1) */ - ospf_rt_reset(po); + ospf_rt_reset(p); /* 16. (2) */ - WALK_LIST(oa, po->area_list) + WALK_LIST(oa, p->area_list) ospf_rt_spfa(oa); /* 16. (3) */ - ospf_rt_sum(ospf_main_area(po)); + ospf_rt_sum(ospf_main_area(p)); /* 16. (4) */ - WALK_LIST(oa, po->area_list) + WALK_LIST(oa, p->area_list) if (oa->trcap && (oa->areaid != 0)) ospf_rt_sum_tr(oa); - if (po->areano > 1) - ospf_rt_abr1(po); + if (p->areano > 1) + ospf_rt_abr1(p); /* 16. (5) */ - ospf_ext_spf(po); + ospf_ext_spf(p); - if (po->areano > 1) - ospf_rt_abr2(po); + if (p->areano > 1) + ospf_rt_abr2(p); - rt_sync(po); - lp_flush(po->nhpool); + rt_sync(p); + lp_flush(p->nhpool); - po->calcrt = 0; + p->calcrt = 0; } @@ -1886,15 +1748,14 @@ static struct mpnh * calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par, int pos) { - // struct proto *p = &oa->po->proto; - struct proto_ospf *po = oa->po; + struct ospf_proto *p = oa->po; struct mpnh *pn = par->nhs; struct ospf_iface *ifa; u32 rid = en->lsa.rt; /* 16.1.1. The next hop calculation */ DBG(" Next hop calculating for id: %R rt: %R type: %u\n", - en->lsa.id, en->lsa.rt, en->lsa.type); + en->lsa.id, en->lsa.rt, en->lsa_type); /* Usually, we inherit parent nexthops */ if (inherit_nexthops(pn)) @@ -1908,67 +1769,69 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, */ /* The first case - local network */ - if ((en->lsa.type == LSA_T_NET) && (par == oa->rt)) + if ((en->lsa_type == LSA_T_NET) && (par == oa->rt)) { ifa = rt_pos_to_ifa(oa, pos); if (!ifa) return NULL; - return new_nexthop(po, IPA_NONE, ifa->iface, ifa->ecmp_weight); + return new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight); } /* The second case - ptp or ptmp neighbor */ - if ((en->lsa.type == LSA_T_RT) && (par == oa->rt)) + if ((en->lsa_type == LSA_T_RT) && (par == oa->rt)) { ifa = rt_pos_to_ifa(oa, pos); if (!ifa) return NULL; if (ifa->type == OSPF_IT_VLINK) - return new_nexthop(po, IPA_NONE, NULL, 0); + return new_nexthop(p, IPA_NONE, NULL, 0); struct ospf_neighbor *m = find_neigh(ifa, rid); if (!m || (m->state != NEIGHBOR_FULL)) return NULL; - return new_nexthop(po, m->ip, ifa->iface, ifa->ecmp_weight); + return new_nexthop(p, m->ip, ifa->iface, ifa->ecmp_weight); } /* The third case - bcast or nbma neighbor */ - if ((en->lsa.type == LSA_T_RT) && (par->lsa.type == LSA_T_NET)) + if ((en->lsa_type == LSA_T_RT) && (par->lsa_type == LSA_T_NET)) { /* par->nhi should be defined from parent's calc_next_hop() */ if (!pn) goto bad; -#ifdef OSPFv2 - /* - * In this case, next-hop is the same as link-back, which is - * already computed in link_back(). - */ - if (ipa_zero(en->lb)) - goto bad; - - return new_nexthop(po, en->lb, pn->iface, pn->weight); + if (ospf_is_v2(p)) + { + /* + * In this case, next-hop is the same as link-back, which is + * already computed in link_back(). + */ + if (ipa_zero(en->lb)) + goto bad; -#else /* OSPFv3 */ - /* - * Next-hop is taken from lladdr field of Link-LSA, en->lb_id - * is computed in link_back(). - */ - struct top_hash_entry *lhe; - lhe = ospf_hash_find(po->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK); + return new_nexthop(p, en->lb, pn->iface, pn->weight); + } + else /* OSPFv3 */ + { + /* + * Next-hop is taken from lladdr field of Link-LSA, en->lb_id + * is computed in link_back(). + */ + struct top_hash_entry *lhe; + lhe = ospf_hash_find(p->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK); - if (!lhe) - return NULL; + if (!lhe) + return NULL; - struct ospf_lsa_link *llsa = lhe->lsa_body; + struct ospf_lsa_link *llsa = lhe->lsa_body; - if (ipa_zero(llsa->lladdr)) - return NULL; + if (ipa_zero(llsa->lladdr)) + return NULL; - return new_nexthop(po, llsa->lladdr, pn->iface, pn->weight); -#endif + return new_nexthop(p, llsa->lladdr, pn->iface, pn->weight); + } } bad: @@ -1983,7 +1846,7 @@ static void add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, u32 dist, struct ospf_area *oa, int pos) { - struct proto_ospf *po = oa->po; + struct ospf_proto *p = oa->po; node *prev, *n; int added = 0; struct top_hash_entry *act; @@ -1994,14 +1857,13 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, if (en->lsa.age == LSA_MAXAGE) return; -#ifdef OSPFv3 - if (en->lsa.type == LSA_T_RT) - { - struct ospf_lsa_rt *rt = en->lsa_body; - if (!(rt->options & OPT_V6)) - return; - } -#endif + if (ospf_is_v3(p) && (en->lsa_type == LSA_T_RT)) + { + /* In OSPFv3, check V6 flag */ + struct ospf_lsa_rt *rt = en->lsa_body; + if (!(rt->options & OPT_V6)) + return; + } /* 16.1. (2c) */ if (en->color == INSPF) @@ -2019,7 +1881,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, if (!nhs) { log(L_WARN "Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)", - en->lsa.type, en->lsa.id, en->lsa.rt); + en->lsa_type, en->lsa.id, en->lsa.rt); return; } @@ -2042,18 +1904,18 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, */ /* Keep old ones */ - if (!po->ecmp || nh_is_vlink(nhs) || (nhs == en->nhs)) + if (!p->ecmp || nh_is_vlink(nhs) || (nhs == en->nhs)) return; /* Merge old and new */ int new_reuse = (par->nhs != nhs); - en->nhs = merge_nexthops(po, en->nhs, nhs, en->nhs_reuse, new_reuse); + en->nhs = merge_nexthops(p, en->nhs, nhs, en->nhs_reuse, new_reuse); en->nhs_reuse = 1; return; } DBG(" Adding candidate: rt: %R, id: %R, type: %u\n", - en->lsa.rt, en->lsa.id, en->lsa.type); + en->lsa.rt, en->lsa.id, en->lsa_type); if (en->color == CANDIDATE) { /* We found a shorter path */ @@ -2076,7 +1938,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, { act = SKIP_BACK(struct top_hash_entry, cn, n); if ((act->dist > dist) || - ((act->dist == dist) && (act->lsa.type == LSA_T_RT))) + ((act->dist == dist) && (act->lsa_type == LSA_T_RT))) { if (prev == NULL) add_head(l, &en->cn); @@ -2108,16 +1970,16 @@ ort_changed(ort *nf, rta *nr) } static void -rt_sync(struct proto_ospf *po) +rt_sync(struct ospf_proto *p) { - struct proto *p = &po->proto; + struct top_hash_entry *en; struct fib_iterator fit; - struct fib *fib = &po->rtf; + struct fib *fib = &p->rtf; ort *nf; struct ospf_area *oa; /* This is used for forced reload of routes */ - int reload = (po->calcrt == 2); + int reload = (p->calcrt == 2); OSPF_TRACE(D_EVENTS, "Starting routing table synchronisation"); @@ -2135,7 +1997,7 @@ again1: for (nh = nf->n.nhs; nh; nh = nh->next) if (ipa_nonzero(nh->gw)) { - neighbor *ng = neigh_find2(p, &nh->gw, nh->iface, 0); + neighbor *ng = neigh_find2(&p->p, &nh->gw, nh->iface, 0); if (!ng || (ng->scope == SCOPE_HOST)) { reset_ri(nf); break; } } @@ -2148,7 +2010,7 @@ again1: if (nf->n.type) /* Add the route */ { rta a0 = { - .src = p->main_source, + .src = p->p.main_source, .source = nf->n.type, .scope = SCOPE_UNIVERSE, .cast = RTC_UNICAST @@ -2173,7 +2035,7 @@ again1: if (reload || ort_changed(nf, &a0)) { - net *ne = net_get(p->table, nf->fn.prefix, nf->fn.pxlen); + net *ne = net_get(p->p.table, nf->fn.prefix, nf->fn.pxlen); rta *a = rta_lookup(&a0); rte *e = rte_get_temp(a); @@ -2185,11 +2047,11 @@ again1: e->u.ospf.router_id = nf->old_rid = nf->n.rid; e->pflags = 0; e->net = ne; - e->pref = p->preference; + e->pref = p->p.preference; DBG("Mod rte type %d - %I/%d via %I on iface %s, met %d\n", a0.source, nf->fn.prefix, nf->fn.pxlen, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1); - rte_update(p, ne, e); + rte_update(&p->p, ne, e); } } else if (nf->old_rta) @@ -2198,12 +2060,12 @@ again1: rta_free(nf->old_rta); nf->old_rta = NULL; - net *ne = net_get(p->table, nf->fn.prefix, nf->fn.pxlen); - rte_update(p, ne, NULL); + net *ne = net_get(p->p.table, nf->fn.prefix, nf->fn.pxlen); + rte_update(&p->p, ne, NULL); } - /* Remove unused rt entry. Entries with fn.x0 == 1 are persistent. */ - if (!nf->n.type && !nf->fn.x0 && !nf->fn.x1) + /* Remove unused rt entry. Entries with any flags are persistent. */ + if (!nf->n.type && !nf->external_rte) // XXXX { FIB_ITERATE_PUT(&fit, nftmp); fib_delete(fib, nftmp); @@ -2213,7 +2075,7 @@ again1: FIB_ITERATE_END(nftmp); - WALK_LIST(oa, po->area_list) + WALK_LIST(oa, p->area_list) { /* Cleanup ASBR hash tables */ FIB_ITERATE_INIT(&fit, &oa->rtr); @@ -2231,4 +2093,9 @@ again2: } FIB_ITERATE_END(nftmp); } + + /* Cleanup stale LSAs */ + WALK_SLIST(en, p->lsal) + if (en->rtcalc == LSA_STALE) + ospf_flush_lsa(p, en); } -- cgit v1.2.3 From a7a7372aa7c527619ee527e3b37013f9fb87d618 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 18 Jul 2014 18:24:12 +0200 Subject: Temporary integrated OSPF commit. --- nest/locks.c | 10 +- nest/locks.h | 5 +- proto/ospf/dbdes.c | 19 +- proto/ospf/hello.c | 2 +- proto/ospf/iface.c | 17 +- proto/ospf/lsack.c | 10 +- proto/ospf/lsreq.c | 3 +- proto/ospf/lsupd.c | 88 ++++++--- proto/ospf/neighbor.c | 59 ++++-- proto/ospf/ospf.c | 170 ++++++++-------- proto/ospf/ospf.h | 533 ++++++++++++++++++++++++++------------------------ proto/ospf/rt.c | 43 ++-- proto/ospf/rt.h | 57 +++--- proto/ospf/topology.c | 340 ++++++++++++++------------------ proto/ospf/topology.h | 118 ++++++++++- 15 files changed, 781 insertions(+), 693 deletions(-) (limited to 'proto/ospf/rt.c') diff --git a/nest/locks.c b/nest/locks.c index 7044d6a9..c74f2f45 100644 --- a/nest/locks.c +++ b/nest/locks.c @@ -22,10 +22,11 @@ * or some other non-shareable resource, it asks the core to lock it and it doesn't * use the resource until it's notified that it has acquired the lock. * - * Object locks are represented by &object_lock structures which are in turn a kind of - * resource. Lockable resources are uniquely determined by resource type + * Object locks are represented by &object_lock structures which are in turn a + * kind of resource. Lockable resources are uniquely determined by resource type * (%OBJLOCK_UDP for a UDP port etc.), IP address (usually a broadcast or - * multicast address the port is bound to), port number and interface. + * multicast address the port is bound to), port number, interface and optional + * instance ID. */ #undef LOCAL_DEBUG @@ -45,6 +46,7 @@ olock_same(struct object_lock *x, struct object_lock *y) x->type == y->type && x->iface == y->iface && x->port == y->port && + x->inst == y->inst && ipa_equal(x->addr, y->addr); } @@ -88,7 +90,7 @@ olock_dump(resource *r) struct object_lock *l = (struct object_lock *) r; static char *olock_states[] = { "free", "locked", "waiting", "event" }; - debug("(%d:%s:%I:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->port, olock_states[l->state]); + debug("(%d:%s:%I:%d:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->port, l->inst, olock_states[l->state]); if (!EMPTY_LIST(l->waiters)) debug(" [wanted]\n"); } diff --git a/nest/locks.h b/nest/locks.h index 892d3c6b..3d58c8ed 100644 --- a/nest/locks.h +++ b/nest/locks.h @@ -26,9 +26,10 @@ struct object_lock { resource r; ip_addr addr; /* Identification of a object: IP address */ - unsigned int type; /* ... object type (OBJLOCK_xxx) */ + uint type; /* ... object type (OBJLOCK_xxx) */ + uint port; /* ... port number */ + uint inst; /* ... instance ID */ struct iface *iface; /* ... interface */ - unsigned int port; /* ... port number */ void (*hook)(struct object_lock *); /* Called when the lock succeeds */ void *data; /* User data */ /* ... internal to lock manager, don't touch ... */ diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index 1f37965c..62b330ed 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -200,15 +200,11 @@ ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) * of the buffer. */ void -ospf_send_dbdes(struct ospf_neighbor *n, int next) +ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int next) { - struct ospf_iface *ifa = n->ifa; - struct ospf_area *oa = ifa->oa; - struct ospf_proto *p = oa->po; - /* RFC 2328 10.8 */ - if (oa->rt == NULL) + if (n->ifa->oa->rt == NULL) return; switch (n->state) @@ -312,6 +308,7 @@ ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_ne s_add_tail(&n->lsrql, SNODE req); req->lsa = lsa; + req->lsa_body = LSA_BODY_DUMMY; } } @@ -394,7 +391,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, n->imms = rcv_imms; OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip); ospf_neigh_sm(n, INM_NEGDONE); - ospf_send_dbdes(n, 1); + ospf_send_dbdes(p, n, 1); break; } @@ -426,7 +423,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if (!(n->myimms & DBDES_MS)) { /* Slave should retransmit dbdes packet */ - ospf_send_dbdes(n, 0); + ospf_send_dbdes(p, n, 0); } return; } @@ -472,7 +469,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M)) ospf_neigh_sm(n, INM_EXDONE); else - ospf_send_dbdes(n, 1); + ospf_send_dbdes(p, n, 1); } else { @@ -489,7 +486,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if (ospf_process_dbdes(p, pkt, n) < 0) return; - ospf_send_dbdes(n, 1); + ospf_send_dbdes(p, n, 1); } break; @@ -504,7 +501,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if (!(n->myimms & DBDES_MS)) { /* Slave should retransmit dbdes packet */ - ospf_send_dbdes(n, 0); + ospf_send_dbdes(p, n, 0); } return; } diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index 376eac3c..50cd8609 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -275,7 +275,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, /* Check consistency of existing neighbor entry */ if (n) { - unsigned t = ifa->type; + uint t = ifa->type; if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP))) { /* Neighbor identified by IP address; Router ID may change */ diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 5e17371d..312e626a 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -620,18 +620,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i add_tail(&oa->po->iface_list, NODE ifa); - /* - * In some cases we allow more ospf_ifaces on one physical iface. - * In OSPFv2, if they use different IP address prefix. - * In OSPFv3, if they use different instance_id. - * Therefore, we store such info to lock->addr field. - */ - - // XXXX review struct object_lock *lock = olock_new(pool); - lock->addr = ospf_is_v2(p) ? ifa->addr->prefix : _MI6(0,0,0,ifa->instance_id); + lock->addr = ospf_is_v2(p) ? ifa->addr->prefix : IPA_NONE; lock->type = OBJLOCK_IP; lock->port = OSPF_PROTO; + lock->inst = ifa->instance_id; lock->iface = iface; lock->data = ifa; lock->hook = ospf_iface_add; @@ -997,7 +990,7 @@ ospf_walk_matching_iface_patts(struct ospf_proto *p, struct ospf_mip_walk *s) BIT32_SET(s->ignore, id); /* If we already found it in previous areas, ignore it and add warning */ - if (!BIT32_TEST(s->active, id)) + if (BIT32_TEST(s->active, id)) { s->warn = 1; continue; } BIT32_SET(s->active, id); @@ -1046,7 +1039,7 @@ ospf_ifa_notify2(struct proto *P, uint flags, struct ifa *a) { struct ospf_mip_walk s = { .iface = a->iface, .a = a }; while (ospf_walk_matching_iface_patts(p, &s)) - ospf_iface_new(s.oa, s.a, s.ip); + ospf_iface_new(s.oa, a, s.ip); } if (flags & IF_CHANGE_DOWN) @@ -1078,7 +1071,7 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a) { struct ospf_mip_walk s = { .iface = a->iface }; while (ospf_walk_matching_iface_patts(p, &s)) - ospf_iface_new(s.oa, s.a, s.ip); + ospf_iface_new(s.oa, a, s.ip); } if (flags & IF_CHANGE_DOWN) diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index aefddfb8..5cac3f69 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -79,10 +79,9 @@ ospf_reset_lsack_queue(struct ospf_neighbor *n) } static inline void -ospf_send_lsack(struct ospf_neighbor *n, int queue) +ospf_send_lsack_(struct ospf_proto *p, struct ospf_neighbor *n, int queue) { struct ospf_iface *ifa = n->ifa; - struct ospf_proto *p = ifa->oa->po; struct ospf_lsa_header *lsas; struct ospf_packet *pkt; struct lsa_node *no; @@ -121,10 +120,10 @@ ospf_send_lsack(struct ospf_neighbor *n, int queue) } void -ospf_lsack_send(struct ospf_neighbor *n, int queue) +ospf_send_lsack(struct ospf_proto *p, struct ospf_neighbor *n, int queue) { while (!EMPTY_LIST(n->ackl[queue])) - ospf_send_lsack(n, queue); + ospf_send_lsack_(p, n, queue); } void @@ -160,9 +159,6 @@ ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa, if (lsa_comp(&lsa, &ret->lsa) != CMP_SAME) { - if ((lsa.sn == LSA_MAXSEQNO) && (lsa.age == LSA_MAXAGE)) - continue; - OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip); OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R", lsa_type, lsa.id, lsa.rt); diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 8888f88e..1685ef13 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -71,7 +71,8 @@ ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n) ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P); ospf_lsreq_body(p, pkt, &lsrs, &lsr_max); - // for (i = 0; i < lsr_max; i++) + /* We send smaller LSREQ to prevent multiple LSACKs as answer */ + lsr_max = lsr_max / 4; i = 0; WALK_SLIST(en, n->lsrql) diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index b0bf21cd..37c89a24 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -115,7 +115,8 @@ ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n) s_add_tail(&n->lsrtl, SNODE ret); } - memcpy(&ret->lsa, &en->lsa, sizeof(struct ospf_lsa_header)); + ret->lsa = en->lsa; + ret->lsa_body = LSA_BODY_DUMMY; } static inline int @@ -134,25 +135,37 @@ ospf_lsa_lsrt_down(struct top_hash_entry *en, struct ospf_neighbor *n) return 0; } +void +ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n) +{ + struct top_hash_entry *en; + + WALK_SLIST(en, p->lsal) + if ((en->lsa.age == LSA_MAXAGE) && (en->lsa_body != NULL) && + lsa_flooding_allowed(en->lsa_type, en->domain, n->ifa)) + ospf_lsa_lsrt_up(en, n); +} + -static void ospf_lsupd_flood_ifa(struct ospf_proto *p, struct ospf_iface *ifa, struct top_hash_entry *en); +static void ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa); /** - * ospf_lsupd_flood - send received or generated LSA to the neighbors - * @p: OSPF protocol + * ospf_flood_lsa - send LSA to the neighbors + * @p: OSPF protocol instance * @en: LSA entry * @from: neighbor than sent this LSA (or NULL if LSA is local) * * return value - was the LSA flooded back? */ - int -ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from) +ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from) { struct ospf_iface *ifa; struct ospf_neighbor *n; + /* RFC 2328 13.3 */ + int back = 0; WALK_LIST(ifa, p->iface_list) { @@ -185,6 +198,8 @@ ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ne { s_rem_node(SNODE req); ospf_hash_delete(n->lsrqh, req); + n->want_lsreq = 1; + if ((EMPTY_SLIST(n->lsrql)) && (n->state == NEIGHBOR_LOADING)) ospf_neigh_sm(n, INM_LOADDONE); } @@ -227,7 +242,7 @@ ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ne } /* 13.3 (5) - finally flood the packet */ - ospf_lsupd_flood_ifa(p, ifa, en); + ospf_send_lsupd_to_ifa(p, en, ifa); } return back; @@ -288,7 +303,7 @@ ospf_prepare_lsupd(struct ospf_proto *p, struct ospf_iface *ifa, static void -ospf_lsupd_flood_ifa(struct ospf_proto *p, struct ospf_iface *ifa, struct top_hash_entry *en) +ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa) { uint c = ospf_prepare_lsupd(p, ifa, &en, 1); @@ -384,7 +399,8 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, /* RFC 2328 13. */ - int sendreq = 1; /* XXXX: review sendreq */ + int skip_lsreq = 0; + n->want_lsreq = 0; uint plen = ntohs(pkt->length); if (plen < (ospf_lsupd_hdrlen(p) + sizeof(struct ospf_lsa_header))) @@ -436,7 +452,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, u16 chsum = lsa_n->checksum; if (chsum != lsasum_check(lsa_n, NULL)) { - log(L_WARN "%s: Received LSA from %I with bad checskum: %x %x", + log(L_WARN "%s: Received LSA from %I with bad checksum: %x %x", p->p.name, n->ip, chsum, lsa_n->checksum); continue; } @@ -501,7 +517,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, if (en && ((now - en->inst_time) < MINLSARRIVAL)) { OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival"); - sendreq = 0; + skip_lsreq = 1; continue; } @@ -514,7 +530,6 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, { log(L_WARN "%s: Received invalid LSA from %I", p->p.name, n->ip); mb_free(body); - sendreq = 0; continue; } @@ -528,22 +543,27 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, } /* 13. (5c) - remove old LSA from all retransmission lists */ - /* Must be done before (5b), otherwise it also removes the new entries from (5b) */ - + /* + * We only need to remove it from the retransmission list of the neighbor + * that send us the new LSA. The old LSA is automatically replaced in + * retransmission lists by the new LSA. + */ if (en) ospf_lsa_lsrt_down(en, n); +#if 0 /* - { - struct ospf_iface *ifi; - struct ospf_neighbor *ni; - - WALK_LIST(ifi, p->iface_list) - WALK_LIST(ni, ifi->neigh_list) - if (ni->state > NEIGHBOR_EXSTART) - ospf_lsa_lsrt_down(en, ni); - } - */ + * Old code for removing LSA from all retransmission lists. Must be done + * before (5b), otherwise it also removes the new entries from (5b). + */ + struct ospf_iface *ifi; + struct ospf_neighbor *ni; + + WALK_LIST(ifi, p->iface_list) + WALK_LIST(ni, ifi->neigh_list) + if (ni->state > NEIGHBOR_EXSTART) + ospf_lsa_lsrt_down(en, ni); +#endif /* 13. (5d) - install new LSA into database */ en = ospf_install_lsa(p, &lsa, lsa_type, lsa_domain, body); @@ -553,7 +573,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, ospf_notify_net_lsa(ifa); /* 13. (5b) - flood new LSA */ - int flood_back = ospf_lsupd_flood(p, en, n); + int flood_back = ospf_flood_lsa(p, en, n); /* 13.5. - schedule ACKs (tbl 19, cases 1+2) */ if (! flood_back) @@ -582,7 +602,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, else ospf_enqueue_lsack(n, lsa_n, ACKL_DIRECT); - sendreq = 0; + skip_lsreq = 1; continue; } @@ -598,11 +618,17 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, } } - /* Send direct LSAs */ - ospf_lsack_send(n, ACKL_DIRECT); - - /* If loading, ask for another part of neighbor's database */ - if (sendreq && (n->state == NEIGHBOR_LOADING)) + /* Send direct LSACKs */ + ospf_send_lsack(p, n, ACKL_DIRECT); + + /* + * In loading state, we should ask for another batch of LSAs. This is only + * vaguely mentioned in RFC 2328. We send a new LSREQ only if the current + * LSUPD actually removed some entries from LSA request list (want_lsreq) and + * did not contain duplicate or early LSAs (skip_lsreq). The first condition + * prevents endless floods, the second condition helps with flow control. + */ + if ((n->state == NEIGHBOR_LOADING) && n->want_lsreq && !skip_lsreq) ospf_send_lsreq(p, n); } diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 392f1d64..c182f0d2 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -33,13 +33,26 @@ static void rxmt_timer_hook(timer * timer); static void ackd_timer_hook(timer * t); static void -init_lists(struct ospf_neighbor *n) +init_lists(struct ospf_proto *p, struct ospf_neighbor *n) { s_init_list(&(n->lsrql)); - n->lsrqh = ospf_top_new(n->pool); + n->lsrqh = ospf_top_new(p, n->pool); s_init_list(&(n->lsrtl)); - n->lsrth = ospf_top_new(n->pool); + n->lsrth = ospf_top_new(p, n->pool); +} + +static void +release_lsrtl(struct ospf_proto *p, struct ospf_neighbor *n) +{ + struct top_hash_entry *ret, *en; + + WALK_SLIST(ret, n->lsrtl) + { + en = ospf_hash_find_entry(p->gr, ret); + if (en) + en->ret_count--; + } } /* Resets LSA request and retransmit lists. @@ -47,11 +60,12 @@ init_lists(struct ospf_neighbor *n) * it is reset during entering EXCHANGE state. */ static void -reset_lists(struct ospf_neighbor *n) +reset_lists(struct ospf_proto *p, struct ospf_neighbor *n) { + release_lsrtl(p,n); ospf_top_free(n->lsrqh); ospf_top_free(n->lsrth); - init_lists(n); + init_lists(p, n); } struct ospf_neighbor * @@ -68,7 +82,7 @@ ospf_neighbor_new(struct ospf_iface *ifa) n->csn = 0; n->state = NEIGHBOR_DOWN; - init_lists(n); + init_lists(p, n); s_init(&(n->dbsi), &(p->lsal)); n->inactim = tm_new(pool); @@ -360,6 +374,10 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) s_get(&(n->dbsi)); s_init(&(n->dbsi), &p->lsal); + /* Add MaxAge LSA entries to retransmission list */ + ospf_add_flushed_to_lsrt(p, n); + + /* FIXME: Why is this here ? */ ospf_reset_lsack_queue(n); } else @@ -388,7 +406,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) if (n->state >= NEIGHBOR_EXSTART) if (!can_do_adj(n)) { - reset_lists(n); + reset_lists(p,n); neigh_chstate(n, NEIGHBOR_2WAY); } break; @@ -399,7 +417,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) case INM_BADLSREQ: if (n->state >= NEIGHBOR_EXCHANGE) { - reset_lists(n); + reset_lists(p, n); neigh_chstate(n, NEIGHBOR_EXSTART); } break; @@ -407,12 +425,12 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) case INM_KILLNBR: case INM_LLDOWN: case INM_INACTTIM: - reset_lists(n); + reset_lists(p, n); neigh_chstate(n, NEIGHBOR_DOWN); break; case INM_1WAYREC: - reset_lists(n); + reset_lists(p, n); neigh_chstate(n, NEIGHBOR_INIT); break; @@ -552,8 +570,10 @@ ospf_neigh_remove(struct ospf_neighbor *n) nn->found = 0; } - s_get(&(n->dbsi)); neigh_chstate(n, NEIGHBOR_DOWN); + + s_get(&(n->dbsi)); + release_lsrtl(p, n); rem_node(NODE n); rfree(n->pool); OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", n->rid); @@ -620,9 +640,9 @@ ospf_sh_neigh_info(struct ospf_neighbor *n) } static void -rxmt_timer_hook(timer * timer) +rxmt_timer_hook(timer *t) { - struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; + struct ospf_neighbor *n = t->data; struct ospf_proto *p = n->ifa->oa->po; DBG("%s: RXMT timer fired on interface %s for neigh %I\n", @@ -631,12 +651,12 @@ rxmt_timer_hook(timer * timer) switch (n->state) { case NEIGHBOR_EXSTART: - ospf_send_dbdes(n, 1); + ospf_send_dbdes(p, n, 1); return; case NEIGHBOR_EXCHANGE: if (n->myimms & DBDES_MS) - ospf_send_dbdes(n, 0); + ospf_send_dbdes(p, n, 0); case NEIGHBOR_LOADING: ospf_send_lsreq(p, n); return; @@ -653,8 +673,13 @@ rxmt_timer_hook(timer * timer) } static void -ackd_timer_hook(timer * t) +ackd_timer_hook(timer *t) { struct ospf_neighbor *n = t->data; - ospf_lsack_send(n, ACKL_DELAY); + struct ospf_proto *p = n->ifa->oa->po; + + DBG("%s: ACKD timer fired on interface %s for neigh %I\n", + p->p.name, n->ifa->ifname, n->ip); + + ospf_send_lsack(p, n, ACKL_DELAY); } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index abcd527a..df5fe472 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -11,93 +11,81 @@ /** * DOC: Open Shortest Path First (OSPF) * - * The OSPF protocol is quite complicated and its complex implemenation is - * split to many files. In |ospf.c|, you will find mainly the interface - * for communication with the core (e.g., reconfiguration hooks, shutdown - * and initialisation and so on). In |packet.c|, you will find various - * functions for sending and receiving generic OSPF packets. There are - * also routines for authentication and checksumming. File |iface.c| contains - * the interface state machine and functions for allocation and deallocation of OSPF's - * interface data structures. Source |neighbor.c| includes the neighbor state - * machine and functions for election of Designated Router and Backup - * Designated router. In |hello.c|, there are routines for sending - * and receiving of hello packets as well as functions for maintaining - * wait times and the inactivity timer. Files |lsreq.c|, |lsack.c|, |dbdes.c| - * contain functions for sending and receiving of link-state requests, - * link-state acknowledgements and database descriptions respectively. - * In |lsupd.c|, there are functions for sending and receiving - * of link-state updates and also the flooding algorithm. Source |topology.c| is - * a place where routines for searching LSAs in the link-state database, - * adding and deleting them reside, there also are functions for originating - * of various types of LSAs (router LSA, net LSA, external LSA). File |rt.c| - * contains routines for calculating the routing table. |lsalib.c| is a set - * of various functions for working with the LSAs (endianity conversions, - * calculation of checksum etc.). + * The OSPF protocol is quite complicated and its complex implemenation is split + * to many files. In |ospf.c|, you will find mainly the interface for + * communication with the core (e.g., reconfiguration hooks, shutdown and + * initialisation and so on). File |iface.c| contains the interface state + * machine and functions for allocation and deallocation of OSPF's interface + * data structures. Source |neighbor.c| includes the neighbor state machine and + * functions for election of Designated Router and Backup Designated router. In + * |packet.c|, you will find various functions for sending and receiving generic + * OSPF packets. There are also routines for authentication and checksumming. + * In |hello.c|, there are routines for sending and receiving of hello packets + * as well as functions for maintaining wait times and the inactivity timer. + * Files |lsreq.c|, |lsack.c|, |dbdes.c| contain functions for sending and + * receiving of link-state requests, link-state acknowledgements and database + * descriptions respectively. In |lsupd.c|, there are functions for sending and + * receiving of link-state updates and also the flooding algorithm. Source + * |topology.c| is a place where routines for searching LSAs in the link-state + * database, adding and deleting them reside, there also are functions for + * originating of various types of LSAs (router LSA, net LSA, external LSA). + * File |rt.c| contains routines for calculating the routing table. |lsalib.c| + * is a set of various functions for working with the LSAs (endianity + * conversions, calculation of checksum etc.). * - * One instance of the protocol is able to hold LSA databases for - * multiple OSPF areas, to exchange routing information between - * multiple neighbors and to calculate the routing tables. The core - * structure is &ospf_proto to which multiple &ospf_area and - * &ospf_iface structures are connected. &ospf_area is also connected to - * &top_hash_graph which is a dynamic hashing structure that - * describes the link-state database. It allows fast search, addition - * and deletion. Each LSA is kept in two pieces: header and body. Both of them are + * One instance of the protocol is able to hold LSA databases for multiple OSPF + * areas, to exchange routing information between multiple neighbors and to + * calculate the routing tables. The core structure is &ospf_proto to which + * multiple &ospf_area and &ospf_iface structures are connected. &ospf_proto is + * also connected to &top_hash_graph which is a dynamic hashing structure that + * describes the link-state database. It allows fast search, addition and + * deletion. Each LSA is kept in two pieces: header and body. Both of them are * kept in the endianity of the CPU. * - * In OSPFv2 specification, it is implied that there is one IP prefix - * for each physical network/interface (unless it is an ptp link). But - * in modern systems, there might be more independent IP prefixes - * associated with an interface. To handle this situation, we have - * one &ospf_iface for each active IP prefix (instead for each active - * iface); This behaves like virtual interface for the purpose of OSPF. - * If we receive packet, we associate it with a proper virtual interface - * mainly according to its source address. + * In OSPFv2 specification, it is implied that there is one IP prefix for each + * physical network/interface (unless it is an ptp link). But in modern systems, + * there might be more independent IP prefixes associated with an interface. To + * handle this situation, we have one &ospf_iface for each active IP prefix + * (instead for each active iface); This behaves like virtual interface for the + * purpose of OSPF. If we receive packet, we associate it with a proper virtual + * interface mainly according to its source address. * - * OSPF keeps one socket per &ospf_iface. This allows us (compared to - * one socket approach) to evade problems with a limit of multicast - * groups per socket and with sending multicast packets to appropriate - * interface in a portable way. The socket is associated with - * underlying physical iface and should not receive packets received - * on other ifaces (unfortunately, this is not true on - * BSD). Generally, one packet can be received by more sockets (for - * example, if there are more &ospf_iface on one physical iface), - * therefore we explicitly filter received packets according to - * src/dst IP address and received iface. + * OSPF keeps one socket per &ospf_iface. This allows us (compared to one socket + * approach) to evade problems with a limit of multicast groups per socket and + * with sending multicast packets to appropriate interface in a portable way. + * The socket is associated with underlying physical iface and should not + * receive packets received on other ifaces (unfortunately, this is not true on + * BSD). Generally, one packet can be received by more sockets (for example, if + * there are more &ospf_iface on one physical iface), therefore we explicitly + * filter received packets according to src/dst IP address and received iface. * - * Vlinks are implemented using particularly degenerate form of - * &ospf_iface, which has several exceptions: it does not have its - * iface or socket (it copies these from 'parent' &ospf_iface) and it - * is present in iface list even when down (it is not freed in - * ospf_iface_down()). + * Vlinks are implemented using particularly degenerate form of &ospf_iface, + * which has several exceptions: it does not have its iface or socket (it copies + * these from 'parent' &ospf_iface) and it is present in iface list even when + * down (it is not freed in ospf_iface_down()). * * The heart beat of ospf is ospf_disp(). It is called at regular intervals - * (&ospf_proto->tick). It is responsible for aging and flushing of LSAs in - * the database, for routing table calculaction and it call area_disp() of every - * ospf_area. + * (&ospf_proto->tick). It is responsible for aging and flushing of LSAs in the + * database, updating topology information in LSAs and for routing table + * calculation. * - * The function area_disp() is - * responsible for late originating of router LSA and network LSA - * and for cleanup before routing table calculation process in - * the area. - * To every &ospf_iface, we connect one or more - * &ospf_neighbor's -- a structure containing many timers and queues - * for building adjacency and for exchange of routing messages. + * To every &ospf_iface, we connect one or more &ospf_neighbor's -- a structure + * containing many timers and queues for building adjacency and for exchange of + * routing messages. * - * BIRD's OSPF implementation respects RFC2328 in every detail, but - * some of internal algorithms do differ. The RFC recommends making a snapshot - * of the link-state database when a new adjacency is forming and sending - * the database description packets based on the information in this - * snapshot. The database can be quite large in some networks, so - * rather we walk through a &slist structure which allows us to - * continue even if the actual LSA we were working with is deleted. New - * LSAs are added at the tail of this &slist. + * BIRD's OSPF implementation respects RFC2328 in every detail, but some of + * internal algorithms do differ. The RFC recommends making a snapshot of the + * link-state database when a new adjacency is forming and sending the database + * description packets based on the information in this snapshot. The database + * can be quite large in some networks, so rather we walk through a &slist + * structure which allows us to continue even if the actual LSA we were working + * with is deleted. New LSAs are added at the tail of this &slist. * - * We also don't keep a separate OSPF routing table, because the core - * helps us by being able to recognize when a route is updated - * to an identical one and it suppresses the update automatically. - * Due to this, we can flush all the routes we've recalculated and - * also those we've deleted to the core's routing table and the - * core will take care of the rest. This simplifies the process + * We also do not keep a separate OSPF routing table, because the core helps us + * by being able to recognize when a route is updated to an identical one and it + * suppresses the update automatically. Due to this, we can flush all the routes + * we have recalculated and also those we have deleted to the core's routing + * table and the core will take care of the rest. This simplifies the process * and conserves memory. */ @@ -145,7 +133,7 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac) } static void -ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac, int reconf) +ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac) { struct ospf_area *oa; @@ -169,6 +157,8 @@ ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac, int reconf) oa->options = ac->type; else oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R); + + ospf_notify_rt_lsa(oa); } static void @@ -252,11 +242,11 @@ ospf_start(struct proto *P) init_list(&(p->area_list)); fib_init(&p->rtf, P->pool, sizeof(ort), 0, ospf_rt_initort); p->areano = 0; - p->gr = ospf_top_new(P->pool); + p->gr = ospf_top_new(p, P->pool); s_init_list(&(p->lsal)); WALK_LIST(ac, c->area_list) - ospf_area_add(p, ac, 0); + ospf_area_add(p, ac); if (c->abr) ospf_open_vlink_sk(p); @@ -382,7 +372,7 @@ ospf_build_attrs(ea_list * next, struct linpool *pool, u32 m1, u32 m2, void -schedule_rtcalc(struct ospf_proto *p) +ospf_schedule_rtcalc(struct ospf_proto *p) { if (p->calcrt) return; @@ -418,7 +408,7 @@ ospf_disp(timer * timer) /* Originate or flush local topology LSAs */ ospf_update_topology(p); - /* Age LSA DB */ + /* Process LSA DB */ ospf_update_lsadb(p); /* Calculate routing table */ @@ -429,7 +419,7 @@ ospf_disp(timer * timer) /** * ospf_import_control - accept or reject new route from nest's routing table - * @p: current instance of protocol + * @P: OSPF protocol instance * @new: the new route * @attrs: list of attributes * @pool: pool for allocation of attributes @@ -475,7 +465,7 @@ ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs) /** * ospf_shutdown - Finish of OSPF instance - * @p: current instance of protocol + * @P: OSPF protocol instance * * RFC does not define any action that should be taken before router * shutdown. To make my neighbors react as fast as possible, I send @@ -619,7 +609,7 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) /** * ospf_reconfigure - reconfiguration hook - * @p: current instance of protocol (with old configuration) + * @P: current instance of protocol (with old configuration) * @c: new configuration requested by user * * This hook tries to be a little bit intelligent. Instance of OSPF @@ -669,7 +659,7 @@ ospf_reconfigure(struct proto *P, struct proto_config *c) if (oa) ospf_area_reconfigure(oa, nac); else - ospf_area_add(p, nac, 1); + ospf_area_add(p, nac); } /* Add and update interfaces */ @@ -697,7 +687,7 @@ ospf_reconfigure(struct proto *P, struct proto_config *c) if (oa->marked) ospf_area_remove(oa); - schedule_rtcalc(p); + ospf_schedule_rtcalc(p); return 1; } @@ -1009,7 +999,7 @@ show_lsa_router(struct ospf_proto *p, struct top_hash_entry *he, int verbose) /* In OSPFv2, we try to find network-LSA to get prefix/pxlen */ struct top_hash_entry *net_he = ospf_hash_find_net2(p->gr, he->domain, rtl.id); - if (net_he) + if (net_he && (net_he->lsa.age < LSA_MAXAGE)) { struct ospf_lsa_header *net_lsa = &(net_he->lsa); struct ospf_lsa_net *net_ln = net_he->lsa_body; @@ -1367,8 +1357,8 @@ void ospf_sh_lsadb(struct lsadb_show_data *ld) { struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf); - int num = p->gr->hash_entries; - unsigned int i, j; + uint num = p->gr->hash_entries; + uint i, j; int last_dscope = -1; u32 last_domain = 0; u16 type_mask = ospf_is_v2(p) ? 0x00ff : 0xffff; /* see lsa_etype() */ diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 34c26b47..e5713628 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -102,7 +102,7 @@ do { if ((p->p.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \ struct ospf_config { struct proto_config c; - unsigned tick; + uint tick; byte ospf2; byte rfc1583; byte stub_router; @@ -110,16 +110,26 @@ struct ospf_config byte abr; byte asbr; int ecmp; - list area_list; /* list of struct ospf_area_config */ - list vlink_list; /* list of struct ospf_iface_patt */ + list area_list; /* list of area configs (struct ospf_area_config) */ + list vlink_list; /* list of configured vlinks (struct ospf_iface_patt) */ }; -struct nbma_node +struct ospf_area_config { node n; - ip_addr ip; - byte eligible; - byte found; + u32 areaid; + u32 default_cost; /* Cost of default route for stub areas + (With possible LSA_EXT3_EBIT for NSSA areas) */ + u8 type; /* Area type (standard, stub, NSSA), represented + by option flags (OPT_E, OPT_N) */ + u8 summary; /* Import summaries to this stub/NSSA area, valid for ABR */ + u8 default_nssa; /* Generate default NSSA route for NSSA+summary area */ + u8 translator; /* Translator role, for NSSA ABR */ + u32 transint; /* Translator stability interval */ + list patt_list; /* List of iface configs (struct ospf_iface_patt) */ + list net_list; /* List of aggregate networks for that area */ + list enet_list; /* List of aggregate external (NSSA) networks */ + list stubnet_list; /* List of stub networks added to Router LSA */ }; struct area_net_config @@ -148,65 +158,54 @@ struct ospf_stubnet_config u8 summary; }; -struct ospf_area_config +struct nbma_node { node n; - u32 areaid; - u32 default_cost; /* Cost of default route for stub areas - (With possible LSA_EXT3_EBIT for NSSA areas) */ - u8 type; /* Area type (standard, stub, NSSA), represented - by option flags (OPT_E, OPT_N) */ - u8 summary; /* Import summaries to this stub/NSSA area, valid for ABR */ - u8 default_nssa; /* Generate default NSSA route for NSSA+summary area */ - u8 translator; /* Translator role, for NSSA ABR */ - u32 transint; /* Translator stability interval */ - list patt_list; - list net_list; /* List of aggregate networks for that area */ - list enet_list; /* List of aggregate external (NSSA) networks */ - list stubnet_list; /* List of stub networks added to Router LSA */ + ip_addr ip; + byte eligible; + byte found; }; +struct ospf_iface_patt +{ + struct iface_patt i; + u32 type; + u32 stub; + u32 cost; + u32 helloint; + u32 rxmtint; + u32 pollint; + u32 waitint; + u32 deadc; + u32 deadint; + u32 inftransdelay; + list nbma_list; + u32 priority; + u32 voa; + u32 vid; + int tx_tos; + int tx_priority; + u16 tx_length; + u16 rx_buffer; -/* Generic option flags */ -#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */ -#define OPT_E 0x02 /* Related to AS-external LSAs */ -#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */ -#define OPT_N 0x08 /* Related to NSSA */ -#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */ -#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */ -#define OPT_R 0x10 /* OSPFv3, originator is active router */ -#define OPT_DC 0x20 /* Related to demand circuits, not used */ - -/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */ -#define OPT_RT_B (0x01 << 24) -#define OPT_RT_E (0x02 << 24) -#define OPT_RT_V (0x04 << 24) -#define OPT_RT_NT (0x10 << 24) - -/* Prefix flags, specific for OSPFv3 */ -#define OPT_PX_NU 0x01 -#define OPT_PX_LA 0x02 -#define OPT_PX_P 0x08 -#define OPT_PX_DN 0x10 - - -/* OSPF interface types */ -#define OSPF_IT_BCAST 0 -#define OSPF_IT_NBMA 1 -#define OSPF_IT_PTP 2 -#define OSPF_IT_PTMP 3 -#define OSPF_IT_VLINK 4 -#define OSPF_IT_UNDEF 5 - -/* OSPF interface states */ -#define OSPF_IS_DOWN 0 /* Not active */ -#define OSPF_IS_LOOP 1 /* Iface with no link */ -#define OSPF_IS_WAITING 2 /* Waiting for Wait timer */ -#define OSPF_IS_PTP 3 /* PTP operational */ -#define OSPF_IS_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */ -#define OSPF_IS_BACKUP 5 /* I'm BDR */ -#define OSPF_IS_DR 6 /* I'm DR */ - +#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */ + u8 instance_id; + u8 autype; /* Not really used in OSPFv3 */ +#define OSPF_AUTH_NONE 0 +#define OSPF_AUTH_SIMPLE 1 +#define OSPF_AUTH_CRYPT 2 +#define OSPF_AUTH_CRYPT_SIZE 16 + u8 strictnbma; + u8 check_link; + u8 ecmp_weight; + u8 link_lsa_suppression; + u8 real_bcast; /* Not really used in OSPFv3 */ + u8 ptp_netmask; /* bool + 2 for unspecified */ + u8 ttl_security; /* bool + 2 for TX only */ + u8 bfd; + u8 bsd_secondary; + list *passwords; +}; /* Default values for interface parameters */ #define COST_D 10 @@ -220,6 +219,58 @@ struct ospf_area_config /* Value of Wait timer - not found it in RFC * - using 4*HELLO */ + +struct ospf_proto +{ + struct proto p; + timer *disp_timer; /* OSPF proto dispatcher */ + uint tick; + struct top_graph *gr; /* LSA graph */ + slist lsal; /* List of all LSA's */ + int calcrt; /* Routing table calculation scheduled? + 0=no, 1=normal, 2=forced reload */ + list iface_list; /* List of OSPF interfaces (struct ospf_iface) */ + list area_list; /* List of OSPF areas (struct ospf_area) */ + int areano; /* Number of area I belong to */ + int padj; /* Number of neighbors in Exchange or Loading state */ + struct fib rtf; /* Routing table */ + byte ospf2; /* OSPF v2 or v3 */ + byte rfc1583; /* RFC1583 compatibility */ + byte stub_router; /* Do not forward transit traffic */ + byte merge_external; /* Should i merge external routes? */ + byte asbr; /* May i originate any ext/NSSA lsa? */ + byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ + struct ospf_area *backbone; /* If exists */ + void *lsab; /* LSA buffer used when originating router LSAs */ + int lsab_size, lsab_used; + linpool *nhpool; /* Linpool used for next hops computed in SPF */ + sock *vlink_sk; /* IP socket used for vlink TX */ + u32 router_id; + u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */ +}; + +struct ospf_area +{ + node n; + u32 areaid; + struct ospf_area_config *ac; /* Related area config */ + struct top_hash_entry *rt; /* My own router LSA */ + struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */ + list cand; /* List of candidates for RT calc. */ + struct fib net_fib; /* Networks to advertise or not */ + struct fib enet_fib; /* External networks for NSSAs */ + u32 options; /* Optional features */ + u8 update_rt_lsa; /* Rt lsa origination scheduled? */ + u8 trcap; /* Transit capability? */ + u8 marked; /* Used in OSPF reconfigure */ + u8 translate; /* Translator state (TRANS_*), for NSSA ABR */ + timer *translator_timer; /* For NSSA translator switch */ + struct ospf_proto *po; + struct fib rtr; /* Routing tables for routers */ +}; + + + struct ospf_iface { node n; @@ -231,7 +282,7 @@ struct ospf_iface pool *pool; sock *sk; /* IP socket */ - list neigh_list; /* List of neigbours */ + list neigh_list; /* List of neigbours (struct ospf_neighbor) */ u32 cost; /* Cost of iface */ u32 waitint; /* number of sec before changing state from wait */ u32 rxmtint; /* number of seconds between LSA retransmissions */ @@ -295,6 +346,153 @@ struct ospf_iface u8 bfd; /* Use BFD on iface */ }; +struct ospf_neighbor +{ + node n; + pool *pool; + struct ospf_iface *ifa; + u8 state; + timer *inactim; /* Inactivity timer */ + u8 imms; /* I, M, Master/slave received */ + u8 myimms; /* I, M Master/slave */ + u32 dds; /* DD Sequence number being sent */ + u32 ddr; /* last Dat Des packet received */ + + u32 rid; /* Router ID */ + ip_addr ip; /* IP of it's interface */ + u8 priority; /* Priority */ + u8 adj; /* built adjacency? */ + u8 want_lsreq; /* Set to 1 when lsrql was shortened during LSUPD */ + u32 options; /* Options received */ + + /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in + OSPFv3, we use the same type to simplify handling */ + u32 dr; /* Neigbour's idea of DR */ + u32 bdr; /* Neigbour's idea of BDR */ + u32 iface_id; /* ID of Neighbour's iface connected to common network */ + + /* Database summary list iterator, controls initial dbdes exchange. + * Advances in the LSA list as dbdes packets are sent. + */ + siterator dbsi; /* iterator of po->lsal */ + + /* Link state request list, controls initial LSA exchange. + * Entries added when received in dbdes packets, removed as sent in lsreq packets. + */ + slist lsrql; /* slist of struct top_hash_entry from n->lsrqh */ + struct top_graph *lsrqh; + + /* Link state retransmission list, controls LSA retransmission during flood. + * Entries added as sent in lsupd packets, removed when received in lsack packets. + * These entries hold ret_count in appropriate LSA entries. + */ + slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */ + struct top_graph *lsrth; + timer *rxmt_timer; /* RXMT timer */ + list ackl[2]; +#define ACKL_DIRECT 0 +#define ACKL_DELAY 1 + timer *ackd_timer; /* Delayed ack timer */ + struct bfd_request *bfd_req; /* BFD request, if BFD is used */ + void *ldd_buffer; /* Last database description packet */ + u32 ldd_bsize; /* Buffer size for ldd_buffer */ + u32 csn; /* Last received crypt seq number (for MD5) */ +}; + + +/* OSPF interface types */ +#define OSPF_IT_BCAST 0 +#define OSPF_IT_NBMA 1 +#define OSPF_IT_PTP 2 +#define OSPF_IT_PTMP 3 +#define OSPF_IT_VLINK 4 +#define OSPF_IT_UNDEF 5 + +/* OSPF interface states */ +#define OSPF_IS_DOWN 0 /* Not active */ +#define OSPF_IS_LOOP 1 /* Iface with no link */ +#define OSPF_IS_WAITING 2 /* Waiting for Wait timer */ +#define OSPF_IS_PTP 3 /* PTP operational */ +#define OSPF_IS_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */ +#define OSPF_IS_BACKUP 5 /* I'm BDR */ +#define OSPF_IS_DR 6 /* I'm DR */ + +/* Definitions for interface state machine */ +#define ISM_UP 0 /* Interface Up */ +#define ISM_WAITF 1 /* Wait timer fired */ +#define ISM_BACKS 2 /* Backup seen */ +#define ISM_NEICH 3 /* Neighbor change */ +#define ISM_LOOP 4 /* Link down */ +#define ISM_UNLOOP 5 /* Link up */ +#define ISM_DOWN 6 /* Interface down */ + + +/* OSPF neighbor states */ +#define NEIGHBOR_DOWN 0 +#define NEIGHBOR_ATTEMPT 1 +#define NEIGHBOR_INIT 2 +#define NEIGHBOR_2WAY 3 +#define NEIGHBOR_EXSTART 4 +#define NEIGHBOR_EXCHANGE 5 +#define NEIGHBOR_LOADING 6 +#define NEIGHBOR_FULL 7 + +/* Definitions for neighbor state machine */ +#define INM_HELLOREC 0 /* Hello Received */ +#define INM_START 1 /* Neighbor start - for NBMA */ +#define INM_2WAYREC 2 /* 2-Way received */ +#define INM_NEGDONE 3 /* Negotiation done */ +#define INM_EXDONE 4 /* Exchange done */ +#define INM_BADLSREQ 5 /* Bad LS Request */ +#define INM_LOADDONE 6 /* Load done */ +#define INM_ADJOK 7 /* AdjOK? */ +#define INM_SEQMIS 8 /* Sequence number mismatch */ +#define INM_1WAYREC 9 /* 1-Way */ +#define INM_KILLNBR 10 /* Kill Neighbor */ +#define INM_INACTTIM 11 /* Inactivity timer */ +#define INM_LLDOWN 12 /* Line down */ + +#define TRANS_OFF 0 +#define TRANS_ON 1 +#define TRANS_WAIT 2 /* Waiting before the end of translation */ + + + +/* Generic option flags */ +#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */ +#define OPT_E 0x02 /* Related to AS-external LSAs */ +#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */ +#define OPT_N 0x08 /* Related to NSSA */ +#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */ +#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */ +#define OPT_R 0x10 /* OSPFv3, originator is active router */ +#define OPT_DC 0x20 /* Related to demand circuits, not used */ + +/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */ +#define OPT_RT_B (0x01 << 24) +#define OPT_RT_E (0x02 << 24) +#define OPT_RT_V (0x04 << 24) +#define OPT_RT_NT (0x10 << 24) + +/* Prefix flags, specific for OSPFv3 */ +#define OPT_PX_NU 0x01 +#define OPT_PX_LA 0x02 +#define OPT_PX_P 0x08 +#define OPT_PX_DN 0x10 + + +struct ospf_packet +{ + u8 version; + u8 type; + u16 length; + u32 routerid; + u32 areaid; + u16 checksum; + u8 instance_id; /* See RFC 6549 */ + u8 autype; /* Undefined for OSPFv3 */ +}; + struct ospf_md5 { u16 zero; @@ -309,7 +507,6 @@ union ospf_auth struct ospf_md5 md5; }; - /* Packet types */ #define HELLO_P 1 /* Hello */ #define DBDES_P 2 /* Database description */ @@ -317,8 +514,6 @@ union ospf_auth #define LSUPD_P 4 /* Link state update */ #define LSACK_P 5 /* Link state acknowledgement */ -/* Area IDs */ -#define BACKBONE 0 #define DBDES_I 4 /* Init bit */ #define DBDES_M 2 /* More bit */ @@ -326,19 +521,6 @@ union ospf_auth #define DBDES_IMMS (DBDES_I | DBDES_M | DBDES_MS) -struct ospf_packet -{ - u8 version; - u8 type; - u16 length; - u32 routerid; - u32 areaid; - u16 checksum; - u8 instance_id; /* See RFC 6549 */ - u8 autype; /* Undefined for OSPFv3 */ -}; - - #define LSA_T_RT 0x2001 #define LSA_T_NET 0x2002 #define LSA_T_SUM_NET 0x2003 @@ -530,7 +712,7 @@ struct ospf_lsa_prefix }; -static inline unsigned +static inline uint lsa_net_count(struct ospf_lsa_header *lsa) { return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net)) @@ -558,6 +740,7 @@ lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest) *addr = IPA_NONE; +#ifdef IPV6 if (pxl > 0) _I0(*addr) = *buf++; if (pxl > 32) @@ -570,6 +753,7 @@ lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest) /* Clean up remaining bits */ if (pxl < 128) addr->addr[pxl / 32] &= u32_mkmask(pxl % 32); +#endif return buf; } @@ -613,183 +797,6 @@ struct ospf_lsreq_header }; -struct ospf_neighbor -{ - node n; - pool *pool; - struct ospf_iface *ifa; - u8 state; -#define NEIGHBOR_DOWN 0 -#define NEIGHBOR_ATTEMPT 1 -#define NEIGHBOR_INIT 2 -#define NEIGHBOR_2WAY 3 -#define NEIGHBOR_EXSTART 4 -#define NEIGHBOR_EXCHANGE 5 -#define NEIGHBOR_LOADING 6 -#define NEIGHBOR_FULL 7 - timer *inactim; /* Inactivity timer */ - u8 imms; /* I, M, Master/slave received */ - u8 myimms; /* I, M Master/slave */ - u32 dds; /* DD Sequence number being sent */ - u32 ddr; /* last Dat Des packet received */ - - u32 rid; /* Router ID */ - ip_addr ip; /* IP of it's interface */ - u8 priority; /* Priority */ - u8 adj; /* built adjacency? */ - u32 options; /* Options received */ - - /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in - OSPFv3, we use the same type to simplify handling */ - u32 dr; /* Neigbour's idea of DR */ - u32 bdr; /* Neigbour's idea of BDR */ - u32 iface_id; /* ID of Neighbour's iface connected to common network */ - - /* Database summary list iterator, controls initial dbdes exchange. - * Advances in the LSA list as dbdes packets are sent. - */ - siterator dbsi; /* iterator of po->lsal */ - - /* Link state request list, controls initial LSA exchange. - * Entries added when received in dbdes packets, removed as sent in lsreq packets. - */ - slist lsrql; /* slist of struct top_hash_entry from n->lsrqh */ - struct top_graph *lsrqh; - - /* Link state retransmission list, controls LSA retransmission during flood. - * Entries added as sent in lsupd packets, removed when received in lsack packets. - */ - slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */ - struct top_graph *lsrth; - timer *rxmt_timer; /* RXMT timer */ - list ackl[2]; -#define ACKL_DIRECT 0 -#define ACKL_DELAY 1 - timer *ackd_timer; /* Delayed ack timer */ - struct bfd_request *bfd_req; /* BFD request, if BFD is used */ - void *ldd_buffer; /* Last database description packet */ - u32 ldd_bsize; /* Buffer size for ldd_buffer */ - u32 csn; /* Last received crypt seq number (for MD5) */ -}; - -/* Definitions for interface state machine */ -#define ISM_UP 0 /* Interface Up */ -#define ISM_WAITF 1 /* Wait timer fired */ -#define ISM_BACKS 2 /* Backup seen */ -#define ISM_NEICH 3 /* Neighbor change */ -#define ISM_LOOP 4 /* Link down */ -#define ISM_UNLOOP 5 /* Link up */ -#define ISM_DOWN 6 /* Interface down */ - -/* Definitions for neighbor state machine */ -#define INM_HELLOREC 0 /* Hello Received */ -#define INM_START 1 /* Neighbor start - for NBMA */ -#define INM_2WAYREC 2 /* 2-Way received */ -#define INM_NEGDONE 3 /* Negotiation done */ -#define INM_EXDONE 4 /* Exchange done */ -#define INM_BADLSREQ 5 /* Bad LS Request */ -#define INM_LOADDONE 6 /* Load done */ -#define INM_ADJOK 7 /* AdjOK? */ -#define INM_SEQMIS 8 /* Sequence number mismatch */ -#define INM_1WAYREC 9 /* 1-Way */ -#define INM_KILLNBR 10 /* Kill Neighbor */ -#define INM_INACTTIM 11 /* Inactivity timer */ -#define INM_LLDOWN 12 /* Line down */ - -struct ospf_area -{ - node n; - u32 areaid; - struct ospf_area_config *ac; /* Related area config */ - struct top_hash_entry *rt; /* My own router LSA */ - struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */ - list cand; /* List of candidates for RT calc. */ - struct fib net_fib; /* Networks to advertise or not */ - struct fib enet_fib; /* External networks for NSSAs */ - u32 options; /* Optional features */ - u8 update_rt_lsa; /* Rt lsa origination scheduled? */ - u8 trcap; /* Transit capability? */ - u8 marked; /* Used in OSPF reconfigure */ - u8 translate; /* Translator state (TRANS_*), for NSSA ABR */ - timer *translator_timer; /* For NSSA translator switch */ - struct ospf_proto *po; - struct fib rtr; /* Routing tables for routers */ -}; - -#define TRANS_OFF 0 -#define TRANS_ON 1 -#define TRANS_WAIT 2 /* Waiting before the end of translation */ - -struct ospf_proto -{ - struct proto p; - timer *disp_timer; /* OSPF proto dispatcher */ - unsigned tick; - struct top_graph *gr; /* LSA graph */ - slist lsal; /* List of all LSA's */ - int calcrt; /* Routing table calculation scheduled? - 0=no, 1=normal, 2=forced reload */ - list iface_list; /* Interfaces we really use */ - list area_list; - int areano; /* Number of area I belong to */ - int padj; /* Number of neighbors in Exchange or Loading state */ - struct fib rtf; /* Routing table */ - byte ospf2; /* OSPF v2 or v3 */ - byte rfc1583; /* RFC1583 compatibility */ - byte stub_router; /* Do not forward transit traffic */ - byte merge_external; /* Should i merge external routes? */ - byte asbr; /* May i originate any ext/NSSA lsa? */ - byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ - struct ospf_area *backbone; /* If exists */ - void *lsab; /* LSA buffer used when originating router LSAs */ - int lsab_size, lsab_used; - linpool *nhpool; /* Linpool used for next hops computed in SPF */ - sock *vlink_sk; /* IP socket used for vlink TX */ - u32 router_id; - u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */ -}; - -struct ospf_iface_patt -{ - struct iface_patt i; - u32 type; - u32 stub; - u32 cost; - u32 helloint; - u32 rxmtint; - u32 pollint; - u32 waitint; - u32 deadc; - u32 deadint; - u32 inftransdelay; - list nbma_list; - u32 priority; - u32 voa; - u32 vid; - int tx_tos; - int tx_priority; - u16 tx_length; - u16 rx_buffer; - -#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */ - u8 instance_id; - u8 autype; /* Not really used in OSPFv3 */ -#define OSPF_AUTH_NONE 0 -#define OSPF_AUTH_SIMPLE 1 -#define OSPF_AUTH_CRYPT 2 -#define OSPF_AUTH_CRYPT_SIZE 16 - u8 strictnbma; - u8 check_link; - u8 ecmp_weight; - u8 link_lsa_suppression; - u8 real_bcast; /* Not really used in OSPFv3 */ - u8 ptp_netmask; /* bool + 2 for unspecified */ - u8 ttl_security; /* bool + 2 for TX only */ - u8 bfd; - u8 bsd_secondary; - list *passwords; -}; - #define SH_ROUTER_SELF 0xffffffff @@ -810,7 +817,7 @@ struct lsadb_show_data { /* ospf.c */ -void schedule_rtcalc(struct ospf_proto *p); +void ospf_schedule_rtcalc(struct ospf_proto *p); static inline void ospf_notify_rt_lsa(struct ospf_area *oa) { oa->update_rt_lsa = 1; } @@ -822,12 +829,15 @@ static inline void ospf_notify_link_lsa(struct ospf_iface *ifa) { ifa->update_link_lsa = 1; } +#define ospf_is_v2(X) OSPF_IS_V2 +#define ospf_is_v3(X) (!OSPF_IS_V2) +/* static inline int ospf_is_v2(struct ospf_proto *p) { return p->ospf2; } static inline int ospf_is_v3(struct ospf_proto *p) { return ! p->ospf2; } - +*/ static inline int ospf_get_version(struct ospf_proto *p) { return ospf_is_v2(p) ? 2 : 3; } @@ -920,7 +930,7 @@ void ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dir void ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr); /* dbdes.c */ -void ospf_send_dbdes(struct ospf_neighbor *n, int next); +void ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int next); void ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n); /* lsreq.c */ @@ -930,7 +940,8 @@ void ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa, struct /* lsupd.c */ void ospf_dump_lsahdr(struct ospf_proto *p, struct ospf_lsa_header *lsa_n); void ospf_dump_common(struct ospf_proto *p, struct ospf_packet *pkt); -int ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from); +void ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n); +int ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from); int ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, struct ospf_neighbor *n); void ospf_rxmt_lsupd(struct ospf_proto *p, struct ospf_neighbor *n); void ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n); @@ -938,7 +949,7 @@ void ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, struct /* lsack.c */ void ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int queue); void ospf_reset_lsack_queue(struct ospf_neighbor *n); -void ospf_lsack_send(struct ospf_neighbor *n, int queue); +void ospf_send_lsack(struct ospf_proto *p, struct ospf_neighbor *n, int queue); void ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n); diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index c4340ee5..9d146ce2 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -557,7 +557,7 @@ spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entr /* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */ if (ospf_is_v3(p) && (act != oa->rt) && !(rt->options & OPT_R)) - break; + return; /* Now process Rt links */ for (lsa_walk_rt_init(p, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++) @@ -688,6 +688,8 @@ ospf_rt_spfa(struct ospf_area *oa) if (oa->rt == NULL) return; + if (oa->rt->lsa.age == LSA_MAXAGE) + return; OSPF_TRACE(D_EVENTS, "Starting routing table calculation for area %R", oa->areaid); @@ -1087,8 +1089,7 @@ check_sum_net_lsa(struct ospf_proto *p, ort *nf) struct area_net *anet = NULL; struct ospf_area *anet_oa = NULL; - /* RT entry marked as area network */ - if (nf->fn.flags & OSPF_RT_PERSISTENT) + if (nf->area_net) { /* It is a default route for stub areas, handled entirely in ospf_rt_abr() */ if (nf->fn.pxlen == 0) @@ -1162,8 +1163,7 @@ check_nssa_lsa(struct ospf_proto *p, ort *nf) if (nf->external_rte) return; - /* RT entry marked as area network */ - if (nf->fn.flags & OSPF_RT_PERSISTENT) + if (nf->area_net) { /* Find that area network */ WALK_LIST(oa, p->area_list) @@ -1176,12 +1176,12 @@ check_nssa_lsa(struct ospf_proto *p, ort *nf) /* RFC 3103 3.2 (3) - originate the aggregated address range */ if (anet && anet->active && !anet->hidden && oa->translate) - ospf_originate_ext_lsa(p, NULL, nf, LSA_RTCALC, anet->metric, + ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, anet->metric, (anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0); /* RFC 3103 3.2 (2) - originate the same network */ else if (decide_nssa_lsa(p, nf, &rt)) - ospf_originate_ext_lsa(p, NULL, nf, LSA_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0); + ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0); } /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */ @@ -1273,7 +1273,7 @@ ospf_rt_abr1(struct ospf_proto *p) /* Get a RT entry and mark it to know that it is an area network */ ort *nfi = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen); - nfi->fn.flags |= OSPF_RT_PERSISTENT; /* mark persistent, to have stable UID */ + nfi->area_net = 1; /* 16.2. (3) */ if (nfi->n.type == RTS_OSPF_IA) @@ -1289,7 +1289,7 @@ ospf_rt_abr1(struct ospf_proto *p) ip_addr addr = IPA_NONE; default_nf = (ort *) fib_get(&p->rtf, &addr, 0); - default_nf->fn.flags |= OSPF_RT_PERSISTENT; /* keep persistent */ + default_nf->area_net = 1; struct ospf_area *oa; WALK_LIST(oa, p->area_list) @@ -1309,7 +1309,7 @@ ospf_rt_abr1(struct ospf_proto *p) */ if (oa_is_nssa(oa) && oa->ac->default_nssa) - ospf_originate_ext_lsa(p, oa, default_nf, LSA_RTCALC, oa->ac->default_cost, + ospf_originate_ext_lsa(p, oa, default_nf, LSA_M_RTCALC, oa->ac->default_cost, (oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0); /* RFC 2328 16.4. (3) - precompute preferred ASBR entries */ @@ -1348,7 +1348,7 @@ translator_timer_hook(timer *timer) return; oa->translate = TRANS_OFF; - schedule_rtcalc(oa->po); + ospf_schedule_rtcalc(oa->po); } static void @@ -1431,7 +1431,7 @@ ospf_rt_abr2(struct ospf_proto *p) /* Get a RT entry and mark it to know that it is an area network */ nf2 = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen); - nf2->fn.flags |= OSPF_RT_PERSISTENT; /* keep persistent */ + nf2->area_net = 1; } u32 metric = (nf->n.type == RTS_OSPF_EXT1) ? @@ -1634,7 +1634,7 @@ ospf_rt_reset(struct ospf_proto *p) FIB_WALK(&p->rtf, nftmp) { ri = (ort *) nftmp; - ri->fn.flags &= ~OSPF_RT_PERSISTENT; + ri->area_net = 0; reset_ri(ri); } FIB_WALK_END; @@ -1647,8 +1647,8 @@ ospf_rt_reset(struct ospf_proto *p) en->nhs = NULL; en->lb = IPA_NONE; - if (en->rtcalc == LSA_RTCALC) - en->rtcalc = LSA_STALE; + if (en->mode == LSA_M_RTCALC) + en->mode = LSA_M_STALE; } WALK_LIST(oa, p->area_list) @@ -1683,14 +1683,9 @@ ospf_rt_reset(struct ospf_proto *p) } } -static void -ospf_flush_stale(struct ospf_proto *p) -{ -} - /** * ospf_rt_spf - calculate internal routes - * @p: OSPF protocol + * @p: OSPF protocol instance * * Calculation of internal paths in an area is described in 16.1 of RFC 2328. * It's based on Dijkstra's shortest path tree algorithms. @@ -2064,8 +2059,8 @@ again1: rte_update(&p->p, ne, NULL); } - /* Remove unused rt entry. Entries with any flags are persistent. */ - if (!nf->n.type && !nf->external_rte) // XXXX + /* Remove unused rt entry, some special entries are persistent */ + if (!nf->n.type && !nf->external_rte && !nf->area_net) { FIB_ITERATE_PUT(&fit, nftmp); fib_delete(fib, nftmp); @@ -2096,6 +2091,6 @@ again2: /* Cleanup stale LSAs */ WALK_SLIST(en, p->lsal) - if (en->rtcalc == LSA_STALE) + if (en->mode == LSA_M_STALE) ospf_flush_lsa(p, en); } diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h index 77d7080b..61936f3c 100644 --- a/proto/ospf/rt.h +++ b/proto/ospf/rt.h @@ -2,9 +2,10 @@ * BIRD -- OSPF * * (c) 2000--2004 Ondrej Filip + * (c) 2009--2014 Ondrej Zajicek + * (c) 2009--2014 CZ.NIC z.s.p.o. * * Can be freely distributed and used under the terms of the GNU GPL. - * */ #ifndef _BIRD_OSPF_RT_H_ @@ -28,12 +29,17 @@ typedef struct orta #define ORTA_ASBR OPT_RT_E #define ORTA_ABR OPT_RT_B /* - * For ORT_NET routes, the field is almost unused with one - * exception: ORTA_PREF for external routes means that the route is - * preferred in AS external route selection according to 16.4.1. - - * it is intra-area path using non-backbone area. In other words, - * the forwarding address (or ASBR if forwarding address is zero) is - * intra-area (type == RTS_OSPF) and its area is not a backbone. + * For ORT_NET routes, there are just several flags for external routes: + * + * ORTA_PREF for external routes means that the route is preferred in AS + * external route selection according to 16.4.1. - it is intra-area path using + * non-backbone area. In other words, the forwarding address (or ASBR if + * forwarding address is zero) is intra-area (type == RTS_OSPF) and its area + * is not a backbone. + * + * ORTA_NSSA means that the entry represents an NSSA route, and ORTA_PROP + * means that the NSSA route has propagate-bit set. These flags are used in + * NSSA translation. */ #define ORTA_PREF 0x80000000 #define ORTA_NSSA 0x40000000 @@ -51,41 +57,38 @@ typedef struct orta } orta; - -/* Values for fn.flags in struct ort */ -#define OSPF_RT_PERSISTENT 0x01 - typedef struct ort { /* - * We use OSPF_RT_PERSISTENT to mark persistent rt entries, that are - * needed for summary LSAs that don't have 'proper' rt entry (area - * networks + default to stubs) to keep uid stable (used for LSA ID - * in OSPFv3 - see fibnode_to_lsaid()). - * - * We use ORT_RT_EXPORT and ORT_RT_NSSA to note whether the - * external/NSSA route was originated from the route export (in - * ospf_rt_notify()) or from the NSSA route translation (in - * check_nssa_lsa()). + * Most OSPF routing table entries are for computed OSPF routes, these have + * defined n.type. There are also few other cases: entries for configured area + * networks (these have area_net field set) and entries for external routes + * exported to OSPF (these have external_rte field set). These entries are + * kept even if they do not contain 'proper' rt entry. That is needed to keep + * allocated stable UID numbers (fn.uid), which are used as LSA IDs in OSPFv3 + * (see fibnode_to_lsaid()) for related LSAs (network summary LSAs in the + * first case, external or NSSA LSAs in the second case). Entries for external + * routes also have a second purpose - to prevent NSSA translation of received + * NSSA routes if regular external routes were already originated for the same + * network (see check_nssa_lsa()). * - * old_* values are here to represent the last route update. old_rta - * is cached (we keep reference), mainly for multipath nexthops. - * old_rta == NULL means route was not in the last update, in that - * case other old_* values are not valid. + * old_* values are here to represent the last route update. old_rta is cached + * (we keep reference), mainly for multipath nexthops. old_rta == NULL means + * route was not in the last update, in that case other old_* values are not + * valid. */ struct fib_node fn; orta n; u32 old_metric1, old_metric2, old_tag, old_rid; rta *old_rta; u8 external_rte; + u8 area_net; } ort; static inline int rt_is_nssa(ort *nf) { return nf->n.options & ORTA_NSSA; } -#define EXT_EXPORT 1 -#define EXT_NSSA 2 /* * Invariants for structs top_hash_entry (nodes of LSA db) @@ -97,7 +100,7 @@ static inline int rt_is_nssa(ort *nf) * - beware, nhs is not valid after SPF calculation * * Invariants for structs orta nodes of fib tables po->rtf, oa->rtr: - * - nodes may be invalid (fn.type == 0), in that case other invariants don't hold + * - nodes may be invalid (n.type == 0), in that case other invariants don't hold * - n.metric1 may be at most a small multiple of LSINFINITY, * therefore sums do not overflow * - n.oa is always non-NULL diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 5ed3cf7a..bc2de79f 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -40,11 +40,13 @@ static inline void lsab_reset(struct ospf_proto *p); * new routing table calculation is necessary. This is described in 13.2 of RFC * 2328. This function is for received LSA only, locally originated LSAs are * installed by ospf_originate_lsa(). + * + * The LSA body in @body is expected to be mb_allocated by the caller and its + * ownership is transferred to the LSA entry structure. */ struct top_hash_entry * ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body) { - /* LSA can be temporary, but body must be mb_allocated. */ struct top_hash_entry *en; int change = 0; @@ -61,8 +63,8 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3 memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header))) change = 1; - DBG("Inst lsa: Id: %R, Rt: %R, Type: %u, Age: %u, Sum: %u, Sn: 0x%x\n", - lsa->id, lsa->rt, lsa->type, lsa->age, lsa->checksum, lsa->sn); + if ((en->lsa.age == LSA_MAXAGE) && (lsa->age == LSA_MAXAGE)) + change = 0; mb_free(en->lsa_body); en->lsa_body = body; @@ -70,16 +72,43 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3 en->init_age = en->lsa.age; en->inst_time = now; + /* + * We do not set en->mode. It is either default LSA_M_BASIC, or in a special + * case when en is local but flushed, there is postponed LSA, self-originated + * LSA is received and ospf_install_lsa() is called from ospf_advance_lse(), + * then we have en->mode from the postponed LSA origination. + */ + + OSPF_TRACE(D_EVENTS, "Installing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x, Age: %u", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age); + if (change) - schedule_rtcalc(p); + ospf_schedule_rtcalc(p); return en; } +/** + * ospf_advance_lsa - handle received unexpected self-originated LSA + * @p: OSPF protocol instance + * @en: current LSA entry or NULL + * @lsa: new LSA header + * @type: type of LSA + * @domain: domain of LSA + * @body: pointer to LSA body + * + * This function handles received unexpected self-originated LSA (@lsa, @body) + * by either advancing sequence number of the local LSA instance (@en) and + * propagating it, or installing the received LSA and immediately flushing it + * (if there is no local LSA; i.e., @en is NULL or MaxAge). + * + * The LSA body in @body is expected to be mb_allocated by the caller and its + * ownership is transferred to the LSA entry structure or it is freed. + */ void ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body) { - // OSPF_TRACE(D_EVENTS, "Reflooding new self-originated LSA with newer sequence number"); + /* RFC 2328 13.4 */ if (en && (en->lsa.age < LSA_MAXAGE)) { @@ -101,6 +130,9 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls en->init_age = 0; en->inst_time = now; lsasum_calculate(&en->lsa, en->lsa_body); + + OSPF_TRACE(D_EVENTS, "Advancing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); } else { @@ -129,6 +161,11 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls en->lsa.age = LSA_MAXAGE; en->init_age = lsa->age; en->inst_time = now; + + OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); + OSPF_TRACE(D_EVENTS, "Postponing LSA: Type: %04x, Id: %R, Rt: %R", + en->lsa_type, en->lsa.id, en->lsa.rt); } } else @@ -137,6 +174,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls * We do not have received LSA in the database. We have to flush the * received LSA. It has to be installed in the database to secure * retransmissions. Note that the received LSA may already be MaxAge. + * Also note that en->next_lsa_* may be defined. */ lsa->age = LSA_MAXAGE; @@ -150,7 +188,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls * the neighbor we received it from), we cheat a bit here. */ - ospf_lsupd_flood(p, en, NULL); + ospf_flood_lsa(p, en, NULL); } @@ -167,11 +205,11 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa /* Prepare to flush old LSA */ if (en->lsa.age != LSA_MAXAGE) { - OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R", - en->lsa_type, en->lsa.id, en->lsa.rt); + OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); en->lsa.age = LSA_MAXAGE; - ospf_lsupd_flood(p, en, NULL); + ospf_flood_lsa(p, en, NULL); return 0; } @@ -183,9 +221,6 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa en->lsa.sn = LSA_ZEROSEQNO; } - OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R", - en->lsa_type, en->lsa.id, en->lsa.rt); - /* * lsa.type_raw is initialized by ospf_hash_get() to OSPFv3 LSA type. * lsa_set_options() implicitly converts it to OSPFv2 LSA type, assuming that @@ -205,7 +240,13 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa en->inst_time = now; lsasum_calculate(&en->lsa, en->lsa_body); - ospf_lsupd_flood(p, en, NULL); + OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); + + ospf_flood_lsa(p, en, NULL); + + if (en->mode == LSA_M_BASIC) + ospf_schedule_rtcalc(p); return 1; } @@ -244,15 +285,20 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa) { log(L_ERR "%s: LSA ID collision for %I/%d", p->p.name, lsa->nf->fn.prefix, lsa->nf->fn.pxlen); + + en = NULL; goto drop; } - /* XXXX check for maxage or opts change */ + if (en->mode != lsa->mode) + en->mode = lsa->mode; if (en->next_lsa_body) { /* Ignore the new LSA if it is the same as the scheduled one */ - if ((lsa_blen == en->next_lsa_blen) && !memcmp(lsa_body, en->next_lsa_body, lsa_blen)) + if ((lsa_blen == en->next_lsa_blen) && + !memcmp(lsa_body, en->next_lsa_body, lsa_blen) && + (!ospf_is_v2(p) || (lsa->opts == en->next_lsa_opts))) goto drop; /* Free scheduled LSA */ @@ -263,13 +309,19 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa) } /* Ignore the the new LSA if is the same as the current one */ - if ((lsa_length == en->lsa.length) && !memcmp(lsa_body, en->lsa_body, lsa_blen)) + if ((en->lsa.age < LSA_MAXAGE) && + (lsa_length == en->lsa.length) && + !memcmp(lsa_body, en->lsa_body, lsa_blen) && + (!ospf_is_v2(p) || (lsa->opts == lsa_get_options(&en->lsa)))) goto drop; lsa_body = lsab_flush(p); if (! ospf_do_originate_lsa(p, en, lsa_body, lsa_blen, lsa->opts)) { + OSPF_TRACE(D_EVENTS, "Postponing LSA: Type: %04x, Id: %R, Rt: %R", + en->lsa_type, en->lsa.id, en->lsa.rt); + en->next_lsa_body = lsa_body; en->next_lsa_blen = lsa_blen; en->next_lsa_opts = lsa->opts; @@ -293,8 +345,6 @@ ospf_originate_next_lsa(struct ospf_proto *p, struct top_hash_entry *en) en->next_lsa_body = NULL; en->next_lsa_blen = 0; en->next_lsa_opts = 0; - - // XXXX: schedule_rtcalc(p); } static void @@ -309,8 +359,8 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en) * switched lsa.age to LSA_MAXAGE. */ - OSPF_TRACE(D_EVENTS, "Refreshing LSA: Type: %04x, Id: %R, Rt: %R", - en->lsa_type, en->lsa.id, en->lsa.rt); + OSPF_TRACE(D_EVENTS, "Refreshing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); ASSERT(en->next_lsa_body == NULL); @@ -324,7 +374,7 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en) en->next_lsa_opts = ospf_is_v2(p) ? lsa_get_options(&en->lsa) : 0; en->lsa.age = LSA_MAXAGE; - ospf_lsupd_flood(p, en, NULL); + ospf_flood_lsa(p, en, NULL); return; } @@ -333,7 +383,7 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en) en->init_age = 0; en->inst_time = now; lsasum_calculate(&en->lsa, en->lsa_body); - ospf_lsupd_flood(p, en, NULL); + ospf_flood_lsa(p, en, NULL); } /** @@ -349,16 +399,13 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en) * immediately removed when being flushed, the caller may assume that @en still * exists after the call. The function is the opposite of ospf_originate_lsa() * and is supposed to do the right thing even in cases of postponed - * origination. Note that this function do not schedule routing table - * calculation, the caller is responsible to do it if necessary. + * origination. */ void ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en) { - OSPF_TRACE(D_EVENTS, "Flushing LSA: Type: %04x, Id: %R, Rt: %R", - en->lsa_type, en->lsa.id, en->lsa.rt); - - en->rtcalc = 0; + OSPF_TRACE(D_EVENTS, "Flushing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); if (en->next_lsa_body) { @@ -372,7 +419,12 @@ ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en) return; en->lsa.age = LSA_MAXAGE; - ospf_lsupd_flood(p, en, NULL); + ospf_flood_lsa(p, en, NULL); + + if (en->mode == LSA_M_BASIC) + ospf_schedule_rtcalc(p); + + en->mode = LSA_M_BASIC; } static void @@ -450,7 +502,6 @@ ospf_update_lsadb(struct ospf_proto *p) if (real_age >= LSA_MAXAGE) { ospf_flush_lsa(p, en); - schedule_rtcalc(p); continue; } @@ -510,9 +561,9 @@ ort_to_lsaid(struct ospf_proto *p, ort *nf) static void * -lsab_alloc(struct ospf_proto *p, unsigned size) +lsab_alloc(struct ospf_proto *p, uint size) { - unsigned offset = p->lsab_used; + uint offset = p->lsab_used; p->lsab_used += size; if (p->lsab_used > p->lsab_size) { @@ -524,7 +575,7 @@ lsab_alloc(struct ospf_proto *p, unsigned size) } static inline void * -lsab_allocz(struct ospf_proto *p, unsigned size) +lsab_allocz(struct ospf_proto *p, uint size) { void *r = lsab_alloc(p, size); bzero(r, size); @@ -547,7 +598,7 @@ lsab_reset(struct ospf_proto *p) } static inline void * -lsab_offset(struct ospf_proto *p, unsigned offset) +lsab_offset(struct ospf_proto *p, uint offset) { return ((byte *) p->lsab) + offset; } @@ -815,15 +866,6 @@ prepare_rt3_lsa_body(struct ospf_proto *p, struct ospf_area *oa) rt->options = get_rt_options(p, oa, bitv) | (oa->options & LSA_OPTIONS_MASK); } -/** - * ospf_originate_rt_lsa - build new instance of router LSA - * @oa: ospf_area which is LSA built to - * - * It builds router LSA walking through all OSPF interfaces in - * specified OSPF area. This function is mostly called from - * area_disp(). Builds new LSA, increases sequence number (if old - * instance exists) and sets age of LSA to zero. - */ static void ospf_originate_rt_lsa(struct ospf_proto *p, struct ospf_area *oa) { @@ -834,6 +876,8 @@ ospf_originate_rt_lsa(struct ospf_proto *p, struct ospf_area *oa) .opts = oa->options }; + OSPF_TRACE(D_EVENTS, "Updating router state for area %R", oa->areaid); + if (ospf_is_v2(p)) prepare_rt2_lsa_body(p, oa); else @@ -908,15 +952,6 @@ prepare_net3_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa) net->optx = options & LSA_OPTIONS_MASK; } -/** - * ospf_originate_net_lsa - originates of deletes network LSA - * @ifa: interface which is LSA originated for - * - * Interface counts number of adjacent neighbors. If this number is - * lower than one or interface is not in state %OSPF_IS_DR it deletes - * and premature ages instance of network LSA for specified interface. - * In other case, new instance of network LSA is originated. - */ static void ospf_originate_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa) { @@ -928,6 +963,8 @@ ospf_originate_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa) .ifa = ifa }; + OSPF_TRACE(D_EVENTS, "Updating network state for %s (Id: %R)", ifa->ifname, lsa.id); + if (ospf_is_v2(p)) prepare_net2_lsa_body(p, ifa); else @@ -977,10 +1014,9 @@ prepare_sum3_rt_lsa_body(struct ospf_proto *p, u32 drid, u32 metric, u32 options void ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric) { - struct top_hash_entry *en; - struct ospf_new_lsa lsa = { .type = LSA_T_SUM_NET, + .mode = LSA_M_RTCALC, .dom = oa->areaid, .id = ort_to_lsaid(p, nf), .opts = oa->options, @@ -992,32 +1028,26 @@ ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, else prepare_sum3_net_lsa_body(p, nf, metric); - en = ospf_originate_lsa(p, &lsa); - en->rtcalc = LSA_RTCALC; + ospf_originate_lsa(p, &lsa); } void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric, u32 options) { - struct top_hash_entry *en; - u32 rid = ipa_to_rid(nf->fn.prefix); - - /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ - struct ospf_new_lsa lsa = { .type = LSA_T_SUM_RT, + .mode = LSA_M_RTCALC, .dom = oa->areaid, - .id = rid, + .id = ipa_to_rid(nf->fn.prefix), /* Router ID of ASBR, irrelevant for OSPFv3 */ .opts = oa->options }; if (ospf_is_v2(p)) prepare_sum2_lsa_body(p, 0, metric); else - prepare_sum3_rt_lsa_body(p, rid, metric, options & LSA_OPTIONS_MASK); + prepare_sum3_rt_lsa_body(p, lsa.id, metric, options & LSA_OPTIONS_MASK); - en = ospf_originate_lsa(p, &lsa); - en->rtcalc = LSA_RTCALC; + ospf_originate_lsa(p, &lsa); } @@ -1076,13 +1106,15 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf, /** * originate_ext_lsa - new route received from nest and filters + * @p: OSPF protocol instance * @oa: ospf_area for which LSA is originated * @nf: network prefix and mask - * @src: the source of origination of the LSA (EXT_EXPORT/EXT_NSSA) - * @metric: the metric of a route (possibly with appropriate E-bit) + * @mode: the mode of the LSA (LSA_M_EXPORT or LSA_M_RTCALC) + * @metric: the metric of a route + * @ebit: E-bit for route metric (bool) * @fwaddr: the forwarding address * @tag: the route tag - * @pbit: P-bit for NSSA LSAs, ignored for external LSAs + * @pbit: P-bit for NSSA LSAs (bool), ignored for external LSAs * * If I receive a message that new route is installed, I try to originate an * external LSA. If @oa is an NSSA area, NSSA-LSA is originated instead. @@ -1091,13 +1123,12 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf, * the export from ospf_rt_notify(), or the NSSA-EXT translation. */ void -ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 rtcalc, +ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit) { - struct top_hash_entry *en; - struct ospf_new_lsa lsa = { .type = oa ? LSA_T_NSSA : LSA_T_EXT, + .mode = mode, /* LSA_M_EXPORT or LSA_M_RTCALC */ .dom = oa ? oa->areaid : 0, .id = ort_to_lsaid(p, nf), .opts = oa ? (pbit ? OPT_P : 0) : OPT_E, @@ -1109,8 +1140,7 @@ ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 r else prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit); - en = ospf_originate_lsa(p, &lsa); - en->rtcalc = rtcalc; + ospf_originate_lsa(p, &lsa); } static void @@ -1228,7 +1258,7 @@ ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U /* Old external route might blocked some NSSA translation */ if ((p->areano > 1) && rt_is_nssa(nf) && nf->n.oa->translate) - schedule_rtcalc(p); + ospf_schedule_rtcalc(p); return; } @@ -1262,7 +1292,7 @@ ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U } nf = (ort *) fib_get(&p->rtf, &n->n.prefix, n->n.pxlen); - ospf_originate_ext_lsa(p, oa, nf, 0, metric, ebit, fwd, tag, 1); + ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1); nf->external_rte = 1; } @@ -1320,6 +1350,8 @@ ospf_originate_link_lsa(struct ospf_proto *p, struct ospf_iface *ifa) .ifa = ifa }; + OSPF_TRACE(D_EVENTS, "Updating link state for %s (Id: %R)", ifa->ifname, lsa.id); + prepare_link_lsa_body(p, ifa); ifa->link_lsa = ospf_originate_lsa(p, &lsa); @@ -1576,6 +1608,8 @@ ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa) ifa->pxn_lsa = ospf_originate_lsa(p, &lsa); } +static inline int breaks_minlsinterval(struct top_hash_entry *en) +{ return en && (en->lsa.age < LSA_MAXAGE) && ((en->inst_time + MINLSINTERVAL) > now); } void ospf_update_topology(struct ospf_proto *p) @@ -1587,6 +1621,25 @@ ospf_update_topology(struct ospf_proto *p) { if (oa->update_rt_lsa) { + /* + * Generally, MinLSInterval is enforced in ospf_do_originate_lsa(), but + * origination of (prefix) router LSA is a special case. We do not want to + * prepare a new router LSA body and then postpone it in en->next_lsa_body + * for later origination, because there are side effects (updates of + * rt_pos_* and px_pos_* in ospf_iface structures) during that, which may + * confuse routing table calculation if executed after LSA body + * preparation but before final LSA origination (as rtcalc would use + * current rt_pos_* indexes but the old router LSA body). + * + * Here, we ensure that MinLSInterval is observed and we do not even try + * to originate these LSAs if it is not. Therefore, origination, when + * requested, will succeed unless there is also a seqnum wrapping, which + * is not a problem because in that case rtcalc is blocked by MaxAge. + */ + + if (breaks_minlsinterval(oa->rt) || breaks_minlsinterval(oa->pxr_lsa)) + continue; + ospf_originate_rt_lsa(p, oa); ospf_originate_prefix_rt_lsa(p, oa); oa->update_rt_lsa = 0; @@ -1624,8 +1677,6 @@ ospf_update_topology(struct ospf_proto *p) ifa->update_net_lsa = 0; } } - - // XXXX schedule_rtcalc(p); } @@ -1664,7 +1715,7 @@ ospf_top_hash_u32(u32 a) return a; } -static unsigned +static uint ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type) { /* In OSPFv2, we don't know Router ID when looking for network LSAs. @@ -1685,12 +1736,14 @@ ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type) /** * ospf_top_new - allocated new topology database * @p: OSPF protocol instance + * @pool: pool for allocation * - * this dynamically hashed structure is often used for keeping lsas. mainly - * its used in @ospf_area structure. + * This dynamically hashed structure is used for keeping LSAs. Mainly it is used + * for the LSA database of the OSPF protocol, but also for LSA retransmission + * and request lists of OSPF neighbors. */ struct top_graph * -ospf_top_new(pool *pool) +ospf_top_new(struct ospf_proto *p, pool *pool) { struct top_graph *f; @@ -1701,6 +1754,7 @@ ospf_top_new(pool *pool) ospf_top_ht_alloc(f); f->hash_entries = 0; f->hash_entries_min = 0; + f->ospf2 = ospf_is_v2(p); return f; } @@ -1715,8 +1769,8 @@ ospf_top_free(struct top_graph *f) static void ospf_top_rehash(struct top_graph *f, int step) { - unsigned int oldn, oldh; struct top_hash_entry **n, **oldt, **newt, *e, *x; + uint oldn, oldh; oldn = f->hash_size; oldt = f->hash_table; @@ -1752,7 +1806,7 @@ ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) e = e->next; /* Hide hash entry with empty lsa_body */ - return e->lsa_body ? e : NULL; + return (e && e->lsa_body) ? e : NULL; } /* In OSPFv2, lsa.id is the same as lsa.rt for router LSA. In OSPFv3, we don't know @@ -1780,11 +1834,15 @@ ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr) return rv; } +/* + * ospf_hash_find_rt3_first() and ospf_hash_find_rt3_next() are used exclusively + * for lsa_walk_rt_init(), lsa_walk_rt(), therefore they skip MaxAge entries. + */ static inline struct top_hash_entry * find_matching_rt3(struct top_hash_entry *e, u32 domain, u32 rtr) { while (e && (e->lsa.rt != rtr || e->lsa_type != LSA_T_RT || - e->domain != domain || e->lsa_body == NULL)) + e->domain != domain || e->lsa.age == LSA_MAXAGE)) e = e->next; return e; } @@ -1917,7 +1975,7 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) void ospf_top_dump(struct top_graph *f, struct proto *p) { - unsigned int i; + uint i; OSPF_TRACE(D_EVENTS, "Hash entries: %d", f->hash_entries); for (i = 0; i < f->hash_size; i++) @@ -1928,115 +1986,3 @@ ospf_top_dump(struct top_graph *f, struct proto *p) } } */ - - - -#if 0 - -void -update_rt_lsa(struct ospf_area *oa) -{ - struct ospf_proto *po = oa->po; - - if ((oa->rt) && ((oa->rt->inst_t + MINLSINTERVAL)) > now) - return; - - originate_rt_lsa(oa); - if (ospf_is_v3(p)) - originate_prefix_rt_lsa(oa); - - schedule_rtcalc(p); - oa->origrt = 0; -} - - - - -static inline int -check_sum2_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric) -{ - struct ospf_lsa_sum2 *sum = en->lsa_body; - - if (fn->pxlen != ip4_masklen(sum->netmask)) - return -1; - - return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric); -} - -static inline int -check_sum3_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric) -{ - struct ospf_lsa_sum3_net *sum = en->lsa_body; - ip6_addr prefix; - int pxlen; - u8 pxopts; - u16 rest; - lsa_get_ipv6_prefix(sum->prefix, &prefix, &pxlen, &pxopts, &rest); - - - if ((fn->pxlen != pxlen) || !ip6_equal(fn->prefix, prefix)) - return -1; - - return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric); -} - - -static int -check_sum_net_lsa(struct ospf_proto *po, struct top_hash_entry *en, struct fib_node *fn, u32 metric) -{ - int rv = ospf_is_v2(po) ? - check_sum2_net_lsa(en, fn, metric) : - check_sum3_net_lsa(en, fn, metric); - - if (rv < 0) - log(L_ERR "%s: LSAID collision for %I/%d", p->p.name, fn->prefix, fn->pxlen); - - return rv; -} - -static int -check_sum_rt_lsa(struct ospf_proto *po, struct top_hash_entry *en, u32 drid, u32 metric, u32 options) -{ - if (en->lsa.sn == LSA_MAXSEQNO) - return 0; - - if (ospf_is_v2(po)) - { - struct ospf_lsa_sum2 *sum = en->lsa_body; - return (sum->metric == metric); - } - else - { - struct ospf_lsa_sum3_rt *sum = en->lsa_body; - return (sum->options == options) && (sum->metric == metric) && (sum->drid == drid); - } -} - - - - - - - - OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid); - OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->ifname); - OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", fn->prefix, fn->pxlen, metric); - OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)", rid, metric); - OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d", - nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); - OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname); - OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid); - OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->ifname); - - - en = ospf_hash_find(po->gr, lsa.dom, lsa.id, po->router_id, lsa.type); - if (en && check_ext_lsa(po, en, fn, metric, fwaddr, tag)) - return; - - *length = sizeof(struct ospf_lsa_header) + po->lsab_used; - return lsab_flush(po); - - *length = po->lsab_used + sizeof(struct ospf_lsa_header); - return lsab_flush(po); - -#endif diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index e4ea79f7..b34689e2 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -18,7 +18,7 @@ struct top_hash_entry in intra-area routing table calculation */ struct top_hash_entry *next; /* Next in hash chain */ struct ospf_lsa_header lsa; - u16 lsa_type; /* lsa.type processed and converted to common values */ + u16 lsa_type; /* lsa.type processed and converted to common values (LSA_T_*) */ u16 init_age; /* Initial value for lsa.age during inst_time */ u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */ // struct ospf_area *oa; @@ -37,13 +37,115 @@ struct top_hash_entry #define OUTSPF 0 #define CANDIDATE 1 #define INSPF 2 - u8 rtcalc; /* LSA generated during RT calculation (LSA_RTCALC or LSA_STALE)*/ + u8 mode; /* LSA generated during RT calculation (LSA_RTCALC or LSA_STALE)*/ u8 nhs_reuse; /* Whether nhs nodes can be reused during merging. See a note in rt.c:merge_nexthops() */ }; -#define LSA_RTCALC 1 -#define LSA_STALE 2 + +/* Prevents ospf_hash_find() to ignore the entry, for p->lsrqh and p->lsrth */ +#define LSA_BODY_DUMMY ((void *) 1) + +/* + * LSA entry life cycle + * + * LSA entries are created by ospf_originate_lsa() (for locally originated LSAs) + * or ospf_install_lsa() (for LSAs received from neighbors). A regular (like + * newly originated) LSA entry has defined lsa_body nad lsa.age < %LSA_MAXAGE. + * When the LSA is requested to be flushed by ospf_flush_lsa(), the lsa.age is + * set to %LSA_MAXAGE and flooded. Flush process is finished asynchronously, + * when (at least) flooding is acknowledged by neighbors. This is detected in + * ospf_update_lsadb(), then ospf_clear_lsa() is called to free the LSA body but + * the LSA entry is kept. Such LSA does not formally exist, we keep an empty + * entry (until regular timeout) to know inst_time and lsa.sn in the case of + * later reorigination. After the timeout, LSA is removed by ospf_remove_lsa(). + * + * When LSA origination is requested (by ospf_originate_lsa()). but it is not + * possible to do that immediately (because of MinLSInterval or because the + * sequence number is wrapping), The new LSA is scheduled for later origination + * in next_lsa_* fields of the LSA entry. The later origination is handled by + * ospf_originate_next_lsa() called from ospf_update_lsadb(). We can see that + * both real origination and final flush is asynchronous to ospf_originate_lsa() + * and ospf_flush_lsa(). + * + * LSA entry therefore could be in three basic states: + * R - regular (lsa.age < %LSA_MAXAGE, lsa_body != NULL) + * F - flushing (lsa.age == %LSA_MAXAGE, lsa_body != NULL) + * E - empty (lsa.age == %LSA_MAXAGE, lsa_body == NULL) + * + * And these states are doubled based on whether the next LSA is scheduled + * (next_lsa_body != NULL, -n suffix) or not (next_lsa_body == NULL). We also + * use X for a state of non-existentce. We have this basic state graph + * (transitions from any state to R are omitted for clarity): + * + * X --> R ---> F ---> E --> X + * | \ / | | + * | \/ | | + * | /\ | | + * | / \ | | + * Rn --> Fn --> En + * + * The transitions are: + * + * any state -> R - new LSA origination requested and executed + * R -> Rn, F -> Fn, E -> En - new LSA origination requested and postponed + * R -> Fn - new LSA origination requested, seqnum wrapping + * Rn,Fn,En -> R - postponed LSA finally originated + * R -> R - LSA refresh done + * R -> Fn - LSA refresh with seqnum wrapping + * R -> F, Rn -> Fn - LSA age timeout + * R,Rn,Fn -> F, En -> E - LSA flush requested + * F -> E, Fn -> En - LSA flush done (acknowledged) + * E -> X - LSA real age timeout (or immediate for received LSA) + * + * The 'origination requested' and 'flush requested' transitions are triggered + * and done by ospf_originate_lsa() and ospf_flush_lsa(), the rest is handled + * asynchronously by ospf_update_lsadb(). + * + * The situation is significantly simpler for non-local (received) LSAs - there + * is no postponed origination and after flushing is done, LSAs are immediately + * removed, so it is just X -> R -> F -> X, or X -> F -> X (when MaxAge LSA is + * received). + * + * There are also some special cases related to handling of received unknown + * self-originated LSAs in ospf_advance_lsa(): + * X -> F - LSA is received and immediately flushed + * R,Rn -> Fn - LSA with MaxSeqNo received and flushed, current LSA scheduled + */ + + +#define LSA_M_BASIC 0 +#define LSA_M_EXPORT 1 +#define LSA_M_RTCALC 2 +#define LSA_M_STALE 3 + +/* + * LSA entry modes: + * + * LSA_M_BASIC - The LSA is explicitly originated using ospf_originate_lsa() and + * explicitly flushed using ospf_flush_lsa(). When the LSA is changed, the + * routing table calculation is scheduled. This is also the mode used for LSAs + * received from neighbors. Example: Router-LSAs, Network-LSAs. + * + * LSA_M_EXPORT - like LSA_M_BASIC, but the routing table calculation does not + * depend on the LSA. Therefore, the calculation is not scheduled when the LSA + * is changed. Example: AS-external-LSAs for exported routes. + * + * LSA_M_RTCALC - The LSA has to be requested using ospf_originate_lsa() during + * each routing table calculation, otherwise it is flushed automatically at the + * end of the calculation. The LSA is a result of the calculation and not a + * source for it. Therefore, the calculation is not scheduled when the LSA is + * changed. Example: Summary-LSAs. + * + * LSA_M_STALE - Temporary state for LSA_M_RTCALC that is not requested during + * the current routing table calculation. + * + * + * Note that we do not schedule the routing table calculation when the age of + * LSA_M_BASIC LSA is changed to MaxAge because of the sequence number wrapping, + * As it will be switched back to a regular one ASAP. + */ + struct top_graph { @@ -61,6 +163,7 @@ struct top_graph struct ospf_new_lsa { u16 type; + u8 mode; u32 dom; u32 id; u16 opts; @@ -69,9 +172,8 @@ struct ospf_new_lsa struct ort *nf; }; -struct top_graph *ospf_top_new(pool *); -void ospf_top_free(struct top_graph *); -void ospf_top_dump(struct top_graph *, struct proto *); +struct top_graph *ospf_top_new(struct ospf_proto *p, pool *pool); +void ospf_top_free(struct top_graph *f); struct top_hash_entry * ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body); struct top_hash_entry * ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa); @@ -84,7 +186,7 @@ static inline void ospf_flush2_lsa(struct ospf_proto *p, struct top_hash_entry * void ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric); void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric, u32 options); -void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 rtcalc, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit); +void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit); void ospf_rt_notify(struct proto *P, rtable *tbl, net *n, rte *new, rte *old, ea_list *attrs); void ospf_update_topology(struct ospf_proto *p); -- cgit v1.2.3 From 742029eb782f19c05decbd443d245f12360d5e78 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 19 Jul 2014 17:28:38 +0200 Subject: Whitespace cleanup in OSPF. --- proto/ospf/dbdes.c | 8 +++---- proto/ospf/hello.c | 6 +++--- proto/ospf/iface.c | 13 ++++++----- proto/ospf/lsalib.c | 12 +++++------ proto/ospf/lsreq.c | 2 +- proto/ospf/lsupd.c | 11 +++++----- proto/ospf/neighbor.c | 4 ++-- proto/ospf/ospf.c | 43 ++++++++++++++++++------------------ proto/ospf/ospf.h | 10 ++++----- proto/ospf/packet.c | 10 ++++----- proto/ospf/rt.c | 60 +++++++++++++++++++++++++-------------------------- proto/ospf/topology.c | 30 +++++++++++++------------- proto/ospf/topology.h | 2 +- 13 files changed, 104 insertions(+), 107 deletions(-) (limited to 'proto/ospf/rt.c') diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index 62b330ed..2b076157 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -56,7 +56,7 @@ ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt, *body = ((void *) pkt) + hlen; *count = (plen - hlen) / sizeof(struct ospf_lsa_header); } - + static void ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt) { @@ -231,7 +231,7 @@ ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int next) tm_start(n->rxmt_timer, n->ifa->rxmtint); if (!(n->myimms & DBDES_MS)) - if (!(n->myimms & DBDES_M) && + if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M)) ospf_neigh_sm(n, INM_EXDONE); break; @@ -358,7 +358,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, rcv_imms = ps->imms; rcv_ddseq = ntohl(ps->ddseq); } - + switch (n->state) { case NEIGHBOR_DOWN: @@ -397,7 +397,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if (!(rcv_imms & DBDES_I) && !(rcv_imms & DBDES_MS) && - (n->rid < p->router_id) && + (n->rid < p->router_id) && (n->dds == rcv_ddseq)) { /* I'm master! */ diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index 50cd8609..3aeb9f9a 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -114,7 +114,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) { if (i == max) { - log(L_WARN "%s: Too many neighbors on interface %s", p->p.name, ifa->ifname); + log(L_WARN "%s: Too many neighbors on interface %s", p->p.name, ifa->ifname); break; } neighbors[i] = htonl(neigh->rid); @@ -143,7 +143,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) int to_all = ifa->state > OSPF_IS_DROTHER; int me_elig = ifa->priority > 0; - + if (kind == OHS_POLL) /* Poll timer */ { WALK_LIST(nb, ifa->nbma_list) @@ -357,7 +357,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, if (ifa->type == OSPF_IT_NBMA) if ((ifa->priority == 0) && (n->priority > 0)) ospf_send_hello(n->ifa, OHS_HELLO, n); - + /* Examine list of neighbors */ for (i = 0; i < neigh_count; i++) diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 312e626a..892e8a77 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -47,7 +47,7 @@ wait_timer_hook(timer * timer) static inline uint ifa_tx_length(struct ospf_iface *ifa) { - return ifa->cf->tx_length ?: ifa->iface->mtu; + return ifa->cf->tx_length ?: ifa->iface->mtu; } static inline uint @@ -129,7 +129,7 @@ ospf_sk_open(struct ospf_iface *ifa) ifa->des_routers = IPA_NONE; if (sk_setup_broadcast(sk) < 0) - goto err; + goto err; } else { @@ -137,10 +137,10 @@ ospf_sk_open(struct ospf_iface *ifa) ifa->des_routers = ospf_is_v2(p) ? IP4_OSPF_DES_ROUTERS : IP6_OSPF_DES_ROUTERS; if (sk_setup_multicast(sk) < 0) - goto err; + goto err; if (sk_join_group(sk, ifa->all_routers) < 0) - goto err; + goto err; } } @@ -703,7 +703,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* Type could be changed in ospf_iface_new(), but if config values are same then also results are same */ - int old_type = ospf_iface_classify(old->type, ifa->addr); + int old_type = ospf_iface_classify(old->type, ifa->addr); int new_type = ospf_iface_classify(new->type, ifa->addr); if (old_type != new_type) return 0; @@ -1132,7 +1132,7 @@ ospf_reconfigure_ifaces2(struct ospf_proto *p) ospf_iface_shutdown(ifa); ospf_iface_remove(ifa); } - + ospf_iface_new(s.oa, a, s.ip); } } @@ -1307,4 +1307,3 @@ ospf_iface_info(struct ospf_iface *ifa) cli_msg(-1015, "\tBackup designed router (IP): %I", ifa->bdrip); } } - diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index e1af9f46..579d13e8 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -63,11 +63,11 @@ lsa_ntoh_body(void *n, void *h, u16 len) int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa) -{ +{ /* Handle inactive vlinks */ if (ifa->state == OSPF_IS_DOWN) return 0; - + /* 4.5.2 (Case 2) */ switch (LSA_SCOPE(type)) { @@ -238,7 +238,7 @@ lsasum_check(struct ospf_lsa_header *h, void *body) q = ep; for (p = sp; p < q; p++) { - /* + /* * I count with bytes from header and than from body * but if there is no body, it's appended to header * (probably checksum in update receiving) and I go on @@ -432,7 +432,7 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *r rt->fbit = ext->metric & LSA_EXT3_FBIT; if (rt->fbit) buf = lsa_get_ipv6_addr(buf, &rt->fwaddr); - else + else rt->fwaddr = IPA_NONE; rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0; @@ -540,7 +540,7 @@ lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *bod if (pxl > MAX_PREFIX_LENGTH) return 0; - if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + + if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + IPV6_PREFIX_SPACE(pxl))) return 0; @@ -607,7 +607,7 @@ lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, uint offset, u8 *p u8 pxl = pxlen((u32 *) (pbuf + offset)); if (pxl > MAX_PREFIX_LENGTH) return 0; - + offset += IPV6_PREFIX_SPACE(pxl); } diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 1685ef13..a6c0cf24 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -131,7 +131,7 @@ ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa, DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt); - en = ospf_hash_find(p->gr, domain, id, rt, type); + en = ospf_hash_find(p->gr, domain, id, rt, type); if (!en) { log(L_WARN "%s: Received LSREQ from %I for missing LSA (Type: %04x, Id: %R, Rt: %R)", diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 37c89a24..13ae54d1 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -277,7 +277,7 @@ ospf_prepare_lsupd(struct ospf_proto *p, struct ospf_iface *ifa, if (ospf_iface_assure_bufsize(ifa, pos + len) < 0) { /* Cannot fit in a tx buffer, skip that */ - log(L_ERR "%s: LSA too large to send on %s (Type: %04x, Id: %R, Rt: %R)", + log(L_ERR "%s: LSA too large to send on %s (Type: %04x, Id: %R, Rt: %R)", p->p.name, ifa->ifname, en->lsa_type, en->lsa.id, en->lsa.rt); break; } @@ -439,7 +439,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, lsa_n = ((void *) pkt) + offset; lsa_len = ntohs(lsa_n->length); offset += lsa_len; - + if ((offset > plen) || ((lsa_len % 4) != 0) || (lsa_len <= sizeof(struct ospf_lsa_header))) { @@ -504,7 +504,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, /* 13. (4) - ignore maxage LSA if i have no local copy */ if ((lsa.age == LSA_MAXAGE) && !en && (p->padj == 0)) { - /* 13.5. - schedule ACKs (tbl 19, case 5) */ + /* 13.5. - schedule ACKs (tbl 19, case 5) */ ospf_enqueue_lsack(n, lsa_n, ACKL_DIRECT); continue; } @@ -575,7 +575,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, /* 13. (5b) - flood new LSA */ int flood_back = ospf_flood_lsa(p, en, n); - /* 13.5. - schedule ACKs (tbl 19, cases 1+2) */ + /* 13.5. - schedule ACKs (tbl 19, cases 1+2) */ if (! flood_back) if ((ifa->state != OSPF_IS_BACKUP) || (n->rid == ifa->drid)) ospf_enqueue_lsack(n, lsa_n, ACKL_DELAY); @@ -593,7 +593,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, /* Duplicate LSA, treat as implicit ACK */ int implicit_ack = ospf_lsa_lsrt_down(en, n); - /* 13.5. - schedule ACKs (tbl 19, cases 3+4) */ + /* 13.5. - schedule ACKs (tbl 19, cases 3+4) */ if (implicit_ack) { if ((ifa->state == OSPF_IS_BACKUP) && (n->rid == ifa->drid)) @@ -631,4 +631,3 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, if ((n->state == NEIGHBOR_LOADING) && n->want_lsreq && !skip_lsreq) ospf_send_lsreq(p, n); } - diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index c182f0d2..ee1e8d0f 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -56,7 +56,7 @@ release_lsrtl(struct ospf_proto *p, struct ospf_neighbor *n) } /* Resets LSA request and retransmit lists. - * We do not reset DB summary list iterator here, + * We do not reset DB summary list iterator here, * it is reset during entering EXCHANGE state. */ static void @@ -496,7 +496,7 @@ ospf_dr_election(struct ospf_iface *ifa) u32 old_drid = ifa->drid; u32 old_bdrid = ifa->bdrid; - + ifa->drid = ndr ? ndr->rid : 0; ifa->drip = ndr ? ndr->ip : IPA_NONE; ifa->dr_iface_id = ndr ? ndr->iface_id : 0; diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index df5fe472..d65dba3b 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -10,7 +10,7 @@ /** * DOC: Open Shortest Path First (OSPF) - * + * * The OSPF protocol is quite complicated and its complex implemenation is split * to many files. In |ospf.c|, you will find mainly the interface for * communication with the core (e.g., reconfiguration hooks, shutdown and @@ -68,7 +68,7 @@ * (&ospf_proto->tick). It is responsible for aging and flushing of LSAs in the * database, updating topology information in LSAs and for routing table * calculation. - * + * * To every &ospf_iface, we connect one or more &ospf_neighbor's -- a structure * containing many timers and queues for building adjacency and for exchange of * routing messages. @@ -179,7 +179,7 @@ ospf_area_remove(struct ospf_area *oa) /* We suppose that interfaces are already removed */ ospf_flush_area(p, oa->areaid); - + fib_free(&oa->rtr); fib_free(&oa->net_fib); fib_free(&oa->enet_fib); @@ -207,7 +207,7 @@ static struct ospf_iface * ospf_find_vlink(struct ospf_proto *p, u32 voa, u32 vid) { struct ospf_iface *ifa; - WALK_LIST(ifa, p->iface_list) + WALK_LIST(ifa, p->iface_list) if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa->areaid == voa) && (ifa->vid == vid)) return ifa; return NULL; @@ -291,7 +291,7 @@ ospf_dump(struct proto *P) static struct proto * ospf_init(struct proto_config *c) { - struct ospf_config *oc = (struct ospf_config *) c; + struct ospf_config *oc = (struct ospf_config *) c; struct proto *P = proto_new(c, sizeof(struct ospf_proto)); P->accept_ra_types = RA_OPTIMAL; @@ -688,7 +688,7 @@ ospf_reconfigure(struct proto *P, struct proto_config *c) ospf_area_remove(oa); ospf_schedule_rtcalc(p); - + return 1; } @@ -753,12 +753,12 @@ ospf_sh(struct proto *P) if (oa == ifa->oa) { ifano++; - WALK_LIST(n, ifa->neigh_list) - { + WALK_LIST(n, ifa->neigh_list) + { nno++; if (n->state == NEIGHBOR_FULL) adjno++; - } + } } } @@ -779,8 +779,8 @@ ospf_sh(struct proto *P) anet = (struct area_net *) nftmp; if(firstfib) { - cli_msg(-1014, "\t\tArea networks:"); - firstfib = 0; + cli_msg(-1014, "\t\tArea networks:"); + firstfib = 0; } cli_msg(-1014, "\t\t\t%1I/%u\t%s\t%s", anet->fn.prefix, anet->fn.pxlen, anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : ""); @@ -793,8 +793,8 @@ ospf_sh(struct proto *P) anet = (struct area_net *) nftmp; if(firstfib) { - cli_msg(-1014, "\t\tArea external networks:"); - firstfib = 0; + cli_msg(-1014, "\t\tArea external networks:"); + firstfib = 0; } cli_msg(-1014, "\t\t\t%1I/%u\t%s\t%s", anet->fn.prefix, anet->fn.pxlen, anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : ""); @@ -917,7 +917,7 @@ lsa_compare_for_state(const void *p1, const void *p2) return lsa1->sn - lsa2->sn; } - else + else { if (lsa1->rt < lsa2->rt) return -1; @@ -936,7 +936,7 @@ lsa_compare_for_state(const void *p1, const void *p2) if (px1 != px2) return px1 - px2; - + return lsa1->sn - lsa2->sn; } } @@ -1004,7 +1004,7 @@ show_lsa_router(struct ospf_proto *p, struct top_hash_entry *he, int verbose) struct ospf_lsa_header *net_lsa = &(net_he->lsa); struct ospf_lsa_net *net_ln = net_he->lsa_body; - cli_msg(-1016, "\t\tnetwork %I/%d metric %u", + cli_msg(-1016, "\t\tnetwork %I/%d metric %u", ipa_from_u32(net_lsa->id & net_ln->optx), u32_masklen(net_ln->optx), rtl.metric); } @@ -1085,7 +1085,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2) he->domain = 0; /* Unmark the LSA */ lsa_parse_ext(he, ospf2, &rt); - + if (rt.fbit) bsprintf(str_via, " via %I", rt.fwaddr); @@ -1145,7 +1145,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable) return; } - /* We store interesting area-scoped LSAs in array hea and + /* We store interesting area-scoped LSAs in array hea and global-scoped (LSA_T_EXT) LSAs in array hex */ int num = p->gr->hash_entries; @@ -1343,7 +1343,7 @@ lsa_compare_for_lsadb(const void *p1, const void *p2) if (lsa1->rt != lsa2->rt) return lsa1->rt - lsa2->rt; - + if (lsa1->id != lsa2->id) return lsa1->id - lsa2->id; @@ -1390,7 +1390,7 @@ ospf_sh_lsadb(struct lsadb_show_data *ld) struct ospf_lsa_header *lsa = &(hea[i]->lsa); u16 lsa_type = lsa->type_raw & type_mask; u16 dscope = LSA_SCOPE(hea[i]->lsa_type); - + /* Hack: 1 is used for LSA_SCOPE_LINK, fixed by & 0xf000 */ if (ld->scope && (dscope != (ld->scope & 0xf000))) continue; @@ -1407,7 +1407,7 @@ ospf_sh_lsadb(struct lsadb_show_data *ld) if (ld->router && (lsa->rt != ld->router)) continue; - + if ((dscope != last_dscope) || (hea[i]->domain != last_domain)) { cli_msg(-1017, ""); @@ -1456,4 +1456,3 @@ struct protocol proto_ospf = { .get_attr = ospf_get_attr, .get_route_info = ospf_get_route_info }; - diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index e5713628..7e5996f6 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -127,8 +127,8 @@ struct ospf_area_config u8 translator; /* Translator role, for NSSA ABR */ u32 transint; /* Translator stability interval */ list patt_list; /* List of iface configs (struct ospf_iface_patt) */ - list net_list; /* List of aggregate networks for that area */ - list enet_list; /* List of aggregate external (NSSA) networks */ + list net_list; /* List of aggregate networks for that area */ + list enet_list; /* List of aggregate external (NSSA) networks */ list stubnet_list; /* List of stub networks added to Router LSA */ }; @@ -163,7 +163,7 @@ struct nbma_node node n; ip_addr ip; byte eligible; - byte found; + byte found; }; struct ospf_iface_patt @@ -215,7 +215,7 @@ struct ospf_iface_patt #define HELLOINT_D 10 #define POLLINT_D 20 #define DEADC_D 4 -#define WAIT_DMH 4 +#define WAIT_DMH 4 /* Value of Wait timer - not found it in RFC * - using 4*HELLO */ @@ -334,7 +334,7 @@ struct ospf_iface #define OSPF_I_OK 0 /* Everything OK */ #define OSPF_I_SK 1 /* Socket open failed */ #define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */ - u8 sk_dr; /* Socket is a member of designated routers group */ + u8 sk_dr; /* Socket is a member of designated routers group */ u8 marked; /* Used in OSPF reconfigure, 2 for force restart */ u16 rxbuf; /* Buffer size */ u16 tx_length; /* Soft TX packet length limit, usually MTU */ diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 96351178..d64d7d6b 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -92,7 +92,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) ifa->csn_use = now; } - /* We must have sufficient delay between sending a packet and increasing + /* We must have sufficient delay between sending a packet and increasing CSN to prevent reordering of packets (in a network) with different CSNs */ if ((now - ifa->csn_use) > 1) ifa->csn++; @@ -253,7 +253,7 @@ ospf_rx_hook(sock *sk, int size) struct ospf_iface *ifa = sk->data; struct ospf_proto *p = ifa->oa->po; - int src_local, dst_local, dst_mcast; + int src_local, dst_local, dst_mcast; src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen); dst_local = ipa_equal(sk->laddr, ifa->addr->ip); dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers); @@ -264,7 +264,7 @@ ospf_rx_hook(sock *sk, int size) * In OSPFv2, they might be for other ospf_ifaces (with different IP * prefix) on the same real iface, so we don't log it. We enforce * that (src_local || dst_local), therefore we are eliminating all - * such cases. + * such cases. */ if (dst_mcast && !src_local) return 1; @@ -277,7 +277,7 @@ ospf_rx_hook(sock *sk, int size) } else { - /* In OSPFv3, src_local and dst_local mean link-local. + /* In OSPFv3, src_local and dst_local mean link-local. * RFC 5340 says that local (non-vlink) packets use * link-local src address, but does not enforce it. Strange. */ @@ -385,7 +385,7 @@ ospf_rx_hook(sock *sk, int size) struct ospf_iface *iff = NULL; WALK_LIST(iff, p->iface_list) { - if ((iff->type == OSPF_IT_VLINK) && + if ((iff->type == OSPF_IT_VLINK) && (iff->voa == ifa->oa) && (iff->instance_id == instance_id) && (iff->vid == rid)) diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 9d146ce2..16453b87 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -1,16 +1,16 @@ /* * BIRD -- OSPF - * + * * (c) 2000--2004 Ondrej Filip * (c) 2009--2014 Ondrej Zajicek * (c) 2009--2014 CZ.NIC z.s.p.o. - * + * * Can be freely distributed and used under the terms of the GNU GPL. */ #include "ospf.h" -static void add_cand(list * l, struct top_hash_entry *en, +static void add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, u32 dist, struct ospf_area *oa, int i); static void rt_sync(struct ospf_proto *p); @@ -270,7 +270,7 @@ orta_compare(const struct ospf_proto *p, const orta *new, const orta *old) /* Prefer routes with higher Router ID, just to be more deterministic */ if (new->rid > old->rid) return 1; - + return -1; } @@ -503,7 +503,7 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_ if (en == oa->rt) { - /* + /* * Local stub networks does not have proper iface in en->nhi * (because they all have common top_hash_entry en). * We have to find iface responsible for that stub network. @@ -810,7 +810,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry return 0; } - + /* RFC 2328 16.2. calculating inter-area routes */ static void ospf_rt_sum(struct ospf_area *oa) @@ -822,7 +822,7 @@ ospf_rt_sum(struct ospf_area *oa) ort *abr; int pxlen = -1, type = -1; u8 pxopts; - + OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid); @@ -864,7 +864,7 @@ ospf_rt_sum(struct ospf_area *oa) else /* LSA_T_SUM_RT */ { lsa_parse_sum_rt(en, ospf_is_v2(p), &dst_rid, &metric, &options); - + /* We don't want local router in ASBR routing table */ if (dst_rid == p->router_id) continue; @@ -966,9 +966,9 @@ ospf_rt_sum_tr(struct ospf_area *oa) re = fib_find(&bb->rtr, &ip, MAX_PREFIX_LENGTH); } - /* 16.3 (1b) */ - if (metric == LSINFINITY) - continue; + /* 16.3 (1b) */ + if (metric == LSINFINITY) + continue; /* 16.3 (3) */ if (!re || !re->n.type) @@ -989,7 +989,7 @@ ospf_rt_sum_tr(struct ospf_area *oa) metric = abr->n.metric1 + metric; /* IAC */ /* 16.3. (5) */ - if ((metric < re->n.metric1) || + if ((metric < re->n.metric1) || ((metric == re->n.metric1) && unresolved_vlink(re))) { /* We want to replace the next-hop even if the metric is equal @@ -1075,7 +1075,7 @@ decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest) struct area_net *anet = (struct area_net *) fib_route(&nf->n.oa->net_fib, nf->fn.prefix, nf->fn.pxlen); - /* Condensed area network found */ + /* Condensed area network found */ if (anet) return 0; @@ -1132,7 +1132,7 @@ decide_nssa_lsa(struct ospf_proto *p, ort *nf, struct ospf_lsa_ext_local *rt) if (!rt_is_nssa(nf) || !oa->translate) return 0; - /* Condensed area network found */ + /* Condensed area network found */ if (fib_route(&oa->enet_fib, nf->fn.prefix, nf->fn.pxlen)) return 0; @@ -1141,7 +1141,7 @@ decide_nssa_lsa(struct ospf_proto *p, ort *nf, struct ospf_lsa_ext_local *rt) /* We do not store needed data in struct orta, we have to parse the LSA */ lsa_parse_ext(en, ospf_is_v2(p), rt); - + if (rt->pxopts & OPT_PX_NU) return 0; @@ -1200,18 +1200,18 @@ ospf_check_vlinks(struct ospf_proto *p) { struct ospf_iface *nhi = ospf_iface_find(p, tmp->nhs->iface); - if ((ifa->state != OSPF_IS_PTP) + if ((ifa->state != OSPF_IS_PTP) || (ifa->vifa != nhi) || !ipa_equal(ifa->vip, tmp->lb)) - { - OSPF_TRACE(D_EVENTS, "Vlink peer %R found", tmp->lsa.id); - ospf_iface_sm(ifa, ISM_DOWN); + { + OSPF_TRACE(D_EVENTS, "Vlink peer %R found", tmp->lsa.id); + ospf_iface_sm(ifa, ISM_DOWN); ifa->vifa = nhi; ifa->addr = nhi->addr; ifa->cost = tmp->dist; - ifa->vip = tmp->lb; - ospf_iface_sm(ifa, ISM_UP); - } + ifa->vip = tmp->lb; + ospf_iface_sm(ifa, ISM_UP); + } else if ((ifa->state == OSPF_IS_PTP) && (ifa->cost != tmp->dist)) { ifa->cost = tmp->dist; @@ -1222,11 +1222,11 @@ ospf_check_vlinks(struct ospf_proto *p) } else { - if (ifa->state > OSPF_IS_DOWN) - { - OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", ifa->vid); + if (ifa->state > OSPF_IS_DOWN) + { + OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", ifa->vid); ospf_iface_sm(ifa, ISM_DOWN); - } + } } } } @@ -1343,7 +1343,7 @@ static void translator_timer_hook(timer *timer) { struct ospf_area *oa = timer->data; - + if (oa->translate != TRANS_WAIT) return; @@ -1727,7 +1727,7 @@ ospf_rt_spf(struct ospf_proto *p) rt_sync(p); lp_flush(p->nhpool); - + p->calcrt = 0; } @@ -1756,7 +1756,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, if (inherit_nexthops(pn)) return pn; - /* + /* * There are three cases: * 1) en is a local network (and par is root) * 2) en is a ptp or ptmp neighbor (and par is root) @@ -1821,7 +1821,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, return NULL; struct ospf_lsa_link *llsa = lhe->lsa_body; - + if (ipa_zero(llsa->lladdr)) return NULL; diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index bc2de79f..4e3da0de 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -31,7 +31,7 @@ static inline void lsab_reset(struct ospf_proto *p); * ospf_install_lsa - install new LSA into database * @p: OSPF protocol instance * @lsa: LSA header - * @type: type of LSA + * @type: type of LSA * @domain: domain of LSA * @body: pointer to LSA body * @@ -93,7 +93,7 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3 * @p: OSPF protocol instance * @en: current LSA entry or NULL * @lsa: new LSA header - * @type: type of LSA + * @type: type of LSA * @domain: domain of LSA * @body: pointer to LSA body * @@ -136,7 +136,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls } else { - /* + /* * Received LSA has maximal sequence number, so we cannot simply override * it. We have to install it to the database, immediately flush it to * implement sequence number wrapping, and schedule our current LSA to be @@ -181,10 +181,10 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls en = ospf_install_lsa(p, lsa, type, domain, body); } - /* + /* * We flood the updated LSA. Although in some cases the to-be-flooded LSA is * the same as the received LSA, and therefore we should propagate it as - * regular received LSA (send the acknowledgement instead of the update to + * regular received LSA (send the acknowledgement instead of the update to * the neighbor we received it from), we cheat a bit here. */ @@ -341,7 +341,7 @@ ospf_originate_next_lsa(struct ospf_proto *p, struct top_hash_entry *en) if (! ospf_do_originate_lsa(p, en, en->next_lsa_body, en->next_lsa_blen, en->next_lsa_opts)) return; - + en->next_lsa_body = NULL; en->next_lsa_blen = 0; en->next_lsa_opts = 0; @@ -776,7 +776,7 @@ prepare_rt2_lsa_body(struct ospf_proto *p, struct ospf_area *oa) (ifa->state == OSPF_IS_LOOP) || (ifa->type == OSPF_IT_PTMP)) add_rt2_lsa_link(p, LSART_STUB, ipa_to_u32(ifa->addr->ip), 0xffffffff, 0); - else + else add_rt2_lsa_link(p, LSART_STUB, ipa_to_u32(ifa->addr->prefix), u32_mkmask(ifa->addr->pxlen), ifa->cost); i++; @@ -789,7 +789,7 @@ prepare_rt2_lsa_body(struct ospf_proto *p, struct ospf_area *oa) add_rt2_lsa_link(p, LSART_STUB, ipa_to_u32(sn->px.addr), u32_mkmask(sn->px.len), sn->cost), i++; struct ospf_lsa_rt *rt = p->lsab; - /* Store number of links in lower half of options */ + /* Store number of links in lower half of options */ rt->options = get_rt_options(p, oa, bitv) | (u16) i; } @@ -1119,7 +1119,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf, * If I receive a message that new route is installed, I try to originate an * external LSA. If @oa is an NSSA area, NSSA-LSA is originated instead. * @oa should not be a stub area. @src does not specify whether the LSA - * is external or NSSA, but it specifies the source of origination - + * is external or NSSA, but it specifies the source of origination - * the export from ospf_rt_notify(), or the NSSA-EXT translation. */ void @@ -1494,7 +1494,7 @@ prefix_same(u32 *b1, u32 *b2) int pxl1 = *b1 >> 24; int pxl2 = *b2 >> 24; int pxs, i; - + if (pxl1 != pxl2) return 0; @@ -1583,7 +1583,7 @@ prepare_prefix_net_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa) WALK_LIST(n, ifa->neigh_list) if ((n->state == NEIGHBOR_FULL) && - (en = ospf_hash_find(p->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK))) + (en = ospf_hash_find(p->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK))) add_link_lsa(p, en->lsa_body, offset, &pxc); lp = p->lsab; @@ -1886,7 +1886,7 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type); e = *ee; - while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || + while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa_type != type || e->domain != domain)) e = e->next; @@ -1914,7 +1914,7 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) void ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e) { - struct top_hash_entry **ee = f->hash_table + + struct top_hash_entry **ee = f->hash_table + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa_type); while (*ee) @@ -1955,7 +1955,7 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) rr = (struct ospf_lsa_rt_link *) (rt + 1); for (i = 0; i < lsa_rt_items(&he->lsa); i++) - OSPF_TRACE(D_EVENTS, " - %1x %-1R %-1R %5u", + OSPF_TRACE(D_EVENTS, " - %1x %-1R %-1R %5u", rr[i].type, rr[i].id, rr[i].data, rr[i].metric); break; @@ -1964,7 +1964,7 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) rts = (u32 *) (ln + 1); for (i = 0; i < lsa_net_items(&he->lsa); i++) - OSPF_TRACE(D_EVENTS, " - %-1R", rts[i]); + OSPF_TRACE(D_EVENTS, " - %-1R", rts[i]); break; default: diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index b34689e2..e2d6c773 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -18,7 +18,7 @@ struct top_hash_entry in intra-area routing table calculation */ struct top_hash_entry *next; /* Next in hash chain */ struct ospf_lsa_header lsa; - u16 lsa_type; /* lsa.type processed and converted to common values (LSA_T_*) */ + u16 lsa_type; /* lsa.type processed and converted to common values (LSA_T_*) */ u16 init_age; /* Initial value for lsa.age during inst_time */ u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */ // struct ospf_area *oa; -- cgit v1.2.3 From f8fefde318c6248ad94e7b6d60155deed9ab8eed Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 24 Oct 2014 10:27:21 +0200 Subject: Refactoring of OSPF messages. --- nest/password.c | 15 +- nest/password.h | 9 +- proto/ospf/dbdes.c | 230 +++++++++++-------------- proto/ospf/hello.c | 78 ++++----- proto/ospf/iface.c | 71 ++++---- proto/ospf/lsack.c | 5 +- proto/ospf/lsreq.c | 12 +- proto/ospf/lsupd.c | 96 +++++------ proto/ospf/neighbor.c | 455 +++++++++++++++++++++++++------------------------- proto/ospf/ospf.c | 5 +- proto/ospf/ospf.h | 40 ++++- proto/ospf/packet.c | 213 +++++++++-------------- proto/ospf/rt.c | 8 +- proto/ospf/topology.c | 4 +- proto/rip/auth.c | 6 +- 15 files changed, 591 insertions(+), 656 deletions(-) (limited to 'proto/ospf/rt.c') diff --git a/nest/password.c b/nest/password.c index 179939e2..21e42e0e 100644 --- a/nest/password.c +++ b/nest/password.c @@ -36,9 +36,18 @@ password_find(list *l, int first_fit) return pf; } -void password_cpy(char *dst, char *src, int size) +struct password_item * +password_find_by_id(list *l, int id) { - bzero(dst, size); - memcpy(dst, src, (strlen(src) < (unsigned) size ? strlen(src) : (unsigned) size)); + struct password_item *pi; + + if (!l) + return NULL; + + WALK_LIST(pi, *l) + if ((pi->id == id) && (pi->accfrom <= now_real) && (now_real < pi->accto)) + return pi; + + return NULL; } diff --git a/nest/password.h b/nest/password.h index 726af733..cd120d70 100644 --- a/nest/password.h +++ b/nest/password.h @@ -23,6 +23,13 @@ struct password_item { extern struct password_item *last_password_item; struct password_item *password_find(list *l, int first_fit); -void password_cpy(char *dst, char *src, int size); +struct password_item *password_find_by_id(list *l, int id); + +static inline int password_verify(struct password_item *p1, char *p2, uint size) +{ + char buf[size]; + strncpy(buf, p1->password, size); + return !memcmp(buf, p2, size); +} #endif diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index 2b076157..88c87164 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -98,7 +98,7 @@ ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt) static void -ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int body) +ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) { struct ospf_iface *ifa = n->ifa; struct ospf_packet *pkt; @@ -106,6 +106,7 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int body) u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu; + /* Update DBDES buffer */ if (n->ldd_bsize != ifa->tx_length) { mb_free(n->ldd_buffer); @@ -136,7 +137,8 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int body) length = sizeof(struct ospf_dbdes3_packet); } - if (body && (n->myimms & DBDES_M)) + /* Prepare DBDES body */ + if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M)) { struct ospf_lsa_header *lsas; struct top_hash_entry *en; @@ -182,7 +184,7 @@ ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) struct ospf_iface *ifa = n->ifa; OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer, - "DBDES packet sent to %I via %s", n->ip, ifa->ifname); + "DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname); sk_set_tbuf(ifa->sk, n->ldd_buffer); ospf_send_to(ifa, n->ip); sk_set_tbuf(ifa->sk, NULL); @@ -191,7 +193,6 @@ ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) /** * ospf_send_dbdes - transmit database description packet * @n: neighbor - * @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0) * * Sending of a database description packet is described in 10.8 of RFC 2328. * Reception of each packet is acknowledged in the sequence number of another. @@ -200,104 +201,78 @@ ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) * of the buffer. */ void -ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int next) +ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) { /* RFC 2328 10.8 */ + ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE)); + if (n->ifa->oa->rt == NULL) return; - switch (n->state) - { - case NEIGHBOR_EXSTART: - n->myimms |= DBDES_I; - - /* Send empty packets */ - ospf_prepare_dbdes(p, n, 0); - ospf_do_send_dbdes(p, n); - break; - - case NEIGHBOR_EXCHANGE: - n->myimms &= ~DBDES_I; - - if (next) - ospf_prepare_dbdes(p, n, 1); - - /* Send prepared packet */ - ospf_do_send_dbdes(p, n); + ospf_prepare_dbdes(p, n); + ospf_do_send_dbdes(p, n); - /* Master should restart RXMT timer for each DBDES exchange */ - if (n->myimms & DBDES_MS) - tm_start(n->rxmt_timer, n->ifa->rxmtint); + if (n->state == NEIGHBOR_EXSTART) + return; - if (!(n->myimms & DBDES_MS)) - if (!(n->myimms & DBDES_M) && - !(n->imms & DBDES_M)) - ospf_neigh_sm(n, INM_EXDONE); - break; + /* Master should restart RXMT timer for each DBDES exchange */ + if (n->myimms & DBDES_MS) + tm_start(n->rxmt_timer, n->ifa->rxmtint); - case NEIGHBOR_LOADING: - case NEIGHBOR_FULL: + if (!(n->myimms & DBDES_MS)) + if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M)) + ospf_neigh_sm(n, INM_EXDONE); +} - if (!n->ldd_buffer) - { - OSPF_TRACE(D_PACKETS, "No DBDES packet for repeating"); - ospf_neigh_sm(n, INM_KILLNBR); - return; - } +void +ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) +{ + ASSERT(n->state > NEIGHBOR_EXSTART); - /* Send last packet */ - ospf_do_send_dbdes(p, n); - break; + if (!n->ldd_buffer) + { + log(L_WARN "%s: No DBDES packet for retransmit", p->p.name); + ospf_neigh_sm(n, INM_SEQMIS); + return; } -} + /* Send last packet */ + ospf_do_send_dbdes(p, n); +} static int ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n) { struct ospf_iface *ifa = n->ifa; - struct ospf_lsa_header *lsas; + struct ospf_lsa_header *lsas, lsa; + struct top_hash_entry *en, *req; + const char *err_dsc = NULL; + u32 lsa_type, lsa_domain; uint i, lsa_count; ospf_dbdes_body(p, pkt, &lsas, &lsa_count); for (i = 0; i < lsa_count; i++) { - struct top_hash_entry *en, *req; - struct ospf_lsa_header lsa; - u32 lsa_type, lsa_domain; - lsa_ntoh_hdr(lsas + i, &lsa); lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain); /* RFC 2328 10.6 and RFC 5340 4.2.2 */ if (!lsa_type) - { - log(L_WARN "%s: Bad DBDES from %I - LSA of unknown type", p->p.name, n->ip); - goto err; - } + DROP1("LSA of unknown type"); if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS)) - { - log(L_WARN "%s: Bad DBDES from %I - LSA with AS scope in stub area", p->p.name, n->ip); - goto err; - } + DROP1("LSA with AS scope in stub area"); /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */ if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT)) - { - log(L_WARN "%s: Bad DBDES from %I - rt-summary-LSA in stub area", p->p.name, n->ip); - goto err; - } + DROP1("rt-summary-LSA in stub area"); /* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */ if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES) - { - log(L_WARN "%s: Bad DBDES from %I - LSA with invalid scope", p->p.name, n->ip); - goto err; - } + DROP1("LSA with invalid scope"); en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type); if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER)) @@ -314,7 +289,10 @@ ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_ne return 0; - err: +drop: + LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt); + LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc); + ospf_neigh_sm(n, INM_SEQMIS); return -1; } @@ -324,21 +302,19 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { struct ospf_proto *p = ifa->oa->po; + const char *err_dsc = NULL; u32 rcv_ddseq, rcv_options; u16 rcv_iface_mtu; u8 rcv_imms; - uint plen; + uint plen, err_val = 0, err_seqmis = 0; /* RFC 2328 10.6 */ plen = ntohs(pkt->length); if (plen < ospf_dbdes_hdrlen(p)) - { - log(L_ERR "OSPF: Bad DBDES packet from %I - too short (%u B)", n->ip, plen); - return; - } + DROP("too short", plen); - OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from %I via %s", n->ip, ifa->ifname); + OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname); ospf_neigh_sm(n, INM_HELLOREC); @@ -364,6 +340,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, case NEIGHBOR_DOWN: case NEIGHBOR_ATTEMPT: case NEIGHBOR_2WAY: + OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart"); return; case NEIGHBOR_INIT: @@ -376,8 +353,8 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, (rcv_iface_mtu != ifa->iface->mtu) && (rcv_iface_mtu != 0) && (ifa->iface->mtu != 0)) - log(L_WARN "OSPF: MTU mismatch with neighbor %I on interface %s (remote %d, local %d)", - n->ip, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu); + LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)", + n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu); if ((rcv_imms == DBDES_IMMS) && (n->rid > p->router_id) && @@ -389,9 +366,8 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, n->options = rcv_options; n->myimms &= ~DBDES_MS; n->imms = rcv_imms; - OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip); ospf_neigh_sm(n, INM_NEGDONE); - ospf_send_dbdes(p, n, 1); + ospf_send_dbdes(p, n); break; } @@ -404,7 +380,6 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, n->options = rcv_options; n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */ n->imms = rcv_imms; - OSPF_TRACE(D_PACKETS, "I'm master to %I", n->ip); ospf_neigh_sm(n, INM_NEGDONE); } else @@ -417,49 +392,29 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if ((rcv_imms == n->imms) && (rcv_options == n->options) && (rcv_ddseq == n->ddr)) - { - /* Duplicate packet */ - OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip); - if (!(n->myimms & DBDES_MS)) - { - /* Slave should retransmit dbdes packet */ - ospf_send_dbdes(p, n, 0); - } - return; - } + goto duplicate; - if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS)) /* M/S bit differs */ - { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)", n->ip); - ospf_neigh_sm(n, INM_SEQMIS); - break; - } + /* Do INM_SEQMIS during packet error */ + err_seqmis = 1; - if (rcv_imms & DBDES_I) /* I bit is set */ - { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)", n->ip); - ospf_neigh_sm(n, INM_SEQMIS); - break; - } + if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS)) + DROP("MS-bit mismatch", rcv_imms); - if (rcv_options != n->options) /* Options differs */ - { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)", n->ip); - ospf_neigh_sm(n, INM_SEQMIS); - break; - } + if (rcv_imms & DBDES_I) + DROP("I-bit mismatch", rcv_imms); + + if (rcv_options != n->options) + DROP("options mismatch", rcv_options); n->ddr = rcv_ddseq; n->imms = rcv_imms; if (n->myimms & DBDES_MS) { - if (rcv_ddseq != n->dds) /* MASTER */ - { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)", n->ip); - ospf_neigh_sm(n, INM_SEQMIS); - break; - } + /* MASTER */ + + if (rcv_ddseq != n->dds) + DROP("DD sequence number mismatch", rcv_ddseq); n->dds++; @@ -469,16 +424,14 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M)) ospf_neigh_sm(n, INM_EXDONE); else - ospf_send_dbdes(p, n, 1); + ospf_send_dbdes(p, n); } else { - if (rcv_ddseq != (n->dds + 1)) /* SLAVE */ - { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", n->ip); - ospf_neigh_sm(n, INM_SEQMIS); - break; - } + /* SLAVE */ + + if (rcv_ddseq != (n->dds + 1)) + DROP("DD sequence number mismatch", rcv_ddseq); n->ddr = rcv_ddseq; n->dds = rcv_ddseq; @@ -486,7 +439,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if (ospf_process_dbdes(p, pkt, n) < 0) return; - ospf_send_dbdes(p, n, 1); + ospf_send_dbdes(p, n); } break; @@ -495,25 +448,30 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if ((rcv_imms == n->imms) && (rcv_options == n->options) && (rcv_ddseq == n->ddr)) - { - /* Duplicate packet */ - OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip); - if (!(n->myimms & DBDES_MS)) - { - /* Slave should retransmit dbdes packet */ - ospf_send_dbdes(p, n, 0); - } - return; - } - else - { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)", n->ip); - DBG("PS=%u, DDR=%u, DDS=%u\n", rcv_ddseq, n->ddr, n->dds); - ospf_neigh_sm(n, INM_SEQMIS); - } - break; + goto duplicate; + + err_seqmis = 1; + + DROP("too late for DD exchange", n->state); default: - bug("Received dbdes from %I in undefined state.", n->ip); + bug("Undefined interface state"); } + return; + +duplicate: + OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate"); + + /* Slave should retransmit DBDES packet */ + if (!(n->myimms & DBDES_MS)) + ospf_rxmt_dbdes(p, n); + return; + +drop: + LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", + n->rid, ifa->ifname, err_dsc, err_val); + + if (err_seqmis) + ospf_neigh_sm(n, INM_SEQMIS); + return; } diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index 3aeb9f9a..e8b1c702 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -114,7 +114,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) { if (i == max) { - log(L_WARN "%s: Too many neighbors on interface %s", p->p.name, ifa->ifname); + log(L_WARN "%s: Too many neighbors on %s", p->p.name, ifa->ifname); break; } neighbors[i] = htonl(neigh->rid); @@ -188,16 +188,21 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr) { struct ospf_proto *p = ifa->oa->po; - char *beg = "OSPF: Bad HELLO packet from "; + const char *err_dsc = NULL; u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr; u8 rcv_options, rcv_priority; u32 *neighbors; u32 neigh_count; - uint plen, i; + uint plen, i, err_val = 0; /* RFC 2328 10.5 */ - OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s", faddr, ifa->ifname); + /* + * We may not yet havethe associate neighbor, so we use Router ID from the + * packet instead of one from the neighbor structure for log messages. + */ + u32 rcv_rid = ntohl(pkt->routerid); + OSPF_TRACE(D_PACKETS, "HELLO packet received from nbr %R on %s", rcv_rid, ifa->ifname); plen = ntohs(pkt->length); @@ -206,10 +211,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_hello2_packet *ps = (void *) pkt; if (plen < sizeof(struct ospf_hello2_packet)) - { - log(L_ERR "%s%I - too short (%u B)", beg, faddr, plen); - return; - } + DROP("too short", plen); rcv_iface_id = 0; rcv_helloint = ntohs(ps->helloint); @@ -223,10 +225,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, if ((ifa->type != OSPF_IT_VLINK) && (ifa->type != OSPF_IT_PTP) && (pxlen != ifa->addr->pxlen)) - { - log(L_ERR "%s%I - prefix length mismatch (%d)", beg, faddr, pxlen); - return; - } + DROP("prefix length mismatch", pxlen); neighbors = ps->neighbors; neigh_count = (plen - sizeof(struct ospf_hello2_packet)) / sizeof(u32); @@ -236,10 +235,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_hello3_packet *ps = (void *) pkt; if (plen < sizeof(struct ospf_hello3_packet)) - { - log(L_ERR "%s%I - too short (%u B)", beg, faddr, plen); - return; - } + DROP("too short", plen); rcv_iface_id = ntohl(ps->iface_id); rcv_helloint = ntohs(ps->helloint); @@ -254,23 +250,14 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, } if (rcv_helloint != ifa->helloint) - { - log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, rcv_helloint); - return; - } + DROP("hello interval mismatch", rcv_helloint); if (rcv_deadint != ifa->deadint) - { - log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, rcv_deadint); - return; - } + DROP("dead interval mismatch", rcv_deadint); /* Check whether bits E, N match */ if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N)) - { - log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, rcv_options); - return; - } + DROP("area type mismatch", rcv_options); /* Check consistency of existing neighbor entry */ if (n) @@ -279,11 +266,11 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP))) { /* Neighbor identified by IP address; Router ID may change */ - if (n->rid != ntohl(pkt->routerid)) + if (n->rid != rcv_rid) { - OSPF_TRACE(D_EVENTS, "Neighbor %I has changed Router ID from %R to %R", - n->ip, n->rid, ntohl(pkt->routerid)); - ospf_neigh_remove(n); + OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed Router ID to %R", + n->rid, ifa->ifname, rcv_rid); + ospf_neigh_sm(n, INM_KILLNBR); n = NULL; } } @@ -292,7 +279,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, /* Neighbor identified by Router ID; IP address may change */ if (!ipa_equal(faddr, n->ip)) { - OSPF_TRACE(D_EVENTS, "Neighbor address changed from %I to %I", n->ip, faddr); + OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed IP address to %I", + n->rid, ifa->ifname, n->ip, faddr); n->ip = faddr; } } @@ -305,28 +293,26 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct nbma_node *nn = find_nbma_node(ifa, faddr); if (!nn && ifa->strictnbma) - { - log(L_WARN "Ignoring new neighbor: %I on %s", faddr, ifa->ifname); - return; - } + DROP1("new neighbor denied"); if (nn && (ifa->type == OSPF_IT_NBMA) && (((rcv_priority == 0) && nn->eligible) || ((rcv_priority > 0) && !nn->eligible))) - { - log(L_ERR "Eligibility mismatch for neighbor: %I on %s", faddr, ifa->ifname); - return; - } + DROP("eligibility mismatch", rcv_priority); if (nn) nn->found = 1; } + // XXXX format + // "ospf1: New neighbor found: 192.168.1.1/fe80:1234:1234:1234:1234 on eth0"; + // "ospf1: New neighbor found: 192.168.1.1 on eth0 at fe80:1234:1234:1234:1234"; + // "ospf1: Neighbor 192.168.1.1 on eth0 found, IP adress fe80:1234:1234:1234:1234"; OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr, ifa->ifname); n = ospf_neighbor_new(ifa); - n->rid = ntohl(pkt->routerid); + n->rid = rcv_rid; n->ip = faddr; n->dr = rcv_dr; n->bdr = rcv_bdr; @@ -367,7 +353,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, ospf_neigh_sm(n, INM_1WAYREC); return; - found_self: +found_self: ospf_neigh_sm(n, INM_2WAYREC); @@ -400,4 +386,10 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, ((n->bdr != n_id) && (old_bdr == n_id))) ospf_iface_sm(ifa, ISM_NEICH); } + + return; + +drop: + LOG_PKT("Bad HELLO packet from nbr %R on %s - %s (%u)", + rcv_rid, ifa->ifname, err_dsc, err_val); } diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 892e8a77..e14f09cb 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -11,15 +11,16 @@ #include "ospf.h" -char *ospf_is[] = { "down", "loop", "waiting", "ptp", "drother", - "backup", "dr" +const char *ospf_is_names[] = { + "Down", "Loopback", "Waiting", "PtP", "DROther", "Backup", "DR" }; -char *ospf_ism[] = { "interface up", "wait timer fired", "backup seen", - "neighbor change", "loop indicated", "unloop indicated", "interface down" +const char *ospf_ism_names[] = { + "InterfaceUp", "WaitTimer", "BackupSeen", "NeighborChange", + "LoopInd", "UnloopInd", "InterfaceDown" }; -char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" }; +const char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" }; static void @@ -40,7 +41,7 @@ wait_timer_hook(timer * timer) struct ospf_iface *ifa = (struct ospf_iface *) timer->data; struct ospf_proto *p = ifa->oa->po; - OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s", ifa->ifname); + OSPF_TRACE(D_EVENTS, "Wait timer fired on %s", ifa->ifname); ospf_iface_sm(ifa, ISM_WAITF); } @@ -240,10 +241,7 @@ ospf_iface_down(struct ospf_iface *ifa) } WALK_LIST_DELSAFE(n, nx, ifa->neigh_list) - { - OSPF_TRACE(D_EVENTS, "Removing neighbor %I", n->ip); - ospf_neigh_remove(n); - } + ospf_neigh_sm(n, INM_KILLNBR); if (ifa->hello_timer) tm_stop(ifa->hello_timer); @@ -311,8 +309,8 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state) if (state == oldstate) return; - OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s", - ifa->ifname, ospf_is[oldstate], ospf_is[state]); + OSPF_TRACE(D_EVENTS, "Interface %s changed state from %s to %s", + ifa->ifname, ospf_is_names[oldstate], ospf_is_names[state]); ifa->state = state; @@ -351,7 +349,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state) void ospf_iface_sm(struct ospf_iface *ifa, int event) { - DBG("SM on %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]); + DBG("SM on %s. Event is '%s'\n", ifa->ifname, ospf_ism_names[event]); switch (event) { @@ -613,7 +611,8 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i continue; if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip)) - log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip); + log(L_WARN "%s: Configured neighbor address (%I) should be link-local", + p->p.name, nb->ip); add_nbma_node(ifa, nb, 0); } @@ -726,7 +725,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* HELLO TIMER */ if (ifa->helloint != new->helloint) { - OSPF_TRACE(D_EVENTS, "Changing hello interval on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing hello interval of %s from %d to %d", ifname, ifa->helloint, new->helloint); ifa->helloint = new->helloint; @@ -736,7 +735,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* RXMT TIMER */ if (ifa->rxmtint != new->rxmtint) { - OSPF_TRACE(D_EVENTS, "Changing retransmit interval on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing retransmit interval of %s from %d to %d", ifname, ifa->rxmtint, new->rxmtint); ifa->rxmtint = new->rxmtint; @@ -745,7 +744,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* POLL TIMER */ if (ifa->pollint != new->pollint) { - OSPF_TRACE(D_EVENTS, "Changing poll interval on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing poll interval of %s from %d to %d", ifname, ifa->pollint, new->pollint); ifa->pollint = new->pollint; @@ -755,7 +754,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* WAIT TIMER */ if (ifa->waitint != new->waitint) { - OSPF_TRACE(D_EVENTS, "Changing wait interval on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing wait interval of %s from %d to %d", ifname, ifa->waitint, new->waitint); ifa->waitint = new->waitint; @@ -766,7 +765,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* DEAD TIMER */ if (ifa->deadint != new->deadint) { - OSPF_TRACE(D_EVENTS, "Changing dead interval on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing dead interval of %s from %d to %d", ifname, ifa->deadint, new->deadint); ifa->deadint = new->deadint; } @@ -774,7 +773,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* INFTRANS */ if (ifa->inftransdelay != new->inftransdelay) { - OSPF_TRACE(D_EVENTS, "Changing transmit delay on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing transmit delay of %s from %d to %d", ifname, ifa->inftransdelay, new->inftransdelay); ifa->inftransdelay = new->inftransdelay; } @@ -782,7 +781,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* AUTHENTICATION */ if (ifa->autype != new->autype) { - OSPF_TRACE(D_EVENTS, "Changing authentication type on interface %s", ifname); + OSPF_TRACE(D_EVENTS, "Changing authentication type of %s", ifname); ifa->autype = new->autype; } @@ -797,7 +796,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* COST */ if (ifa->cost != new->cost) { - OSPF_TRACE(D_EVENTS, "Changing cost on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing cost of %s from %d to %d", ifname, ifa->cost, new->cost); ifa->cost = new->cost; @@ -806,7 +805,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* PRIORITY */ if (ifa->priority != new->priority) { - OSPF_TRACE(D_EVENTS, "Changing priority on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing priority of %s from %d to %d", ifname, ifa->priority, new->priority); ifa->priority = new->priority; @@ -816,7 +815,8 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* STRICT NBMA */ if (ifa->strictnbma != new->strictnbma) { - OSPF_TRACE(D_EVENTS, "Changing NBMA strictness on interface %s", ifname); + OSPF_TRACE(D_EVENTS, "Changing NBMA strictness of %s from %d to %d", + ifname, ifa->strictnbma, new->strictnbma); ifa->strictnbma = new->strictnbma; } @@ -830,14 +830,14 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) { if (nb->eligible != nb2->eligible) { - OSPF_TRACE(D_EVENTS, "Changing eligibility of neighbor %I on interface %s", + OSPF_TRACE(D_EVENTS, "Changing eligibility of NBMA neighbor %I on %s", nb->ip, ifname); nb->eligible = nb2->eligible; } } else { - OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on interface %s", + OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on %s", nb->ip, ifname); rem_node(NODE nb); mb_free(nb); @@ -852,11 +852,12 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) continue; if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip)) - log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip); + log(L_WARN "%s: Configured neighbor address (%I) should be link-local", + p->p.name, nb->ip); if (! find_nbma_node(ifa, nb->ip)) { - OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on interface %s", + OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on %s", nb->ip, ifname); add_nbma_node(ifa, nb, !!find_neigh_by_ip(ifa, nb->ip)); } @@ -867,7 +868,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* TX LENGTH */ if (old->tx_length != new->tx_length) { - OSPF_TRACE(D_EVENTS, "Changing TX length on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing TX length of %s from %d to %d", ifname, old->tx_length, new->tx_length); /* ifa cannot be vlink */ @@ -878,7 +879,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* RX BUFFER */ if (old->rx_buffer != new->rx_buffer) { - OSPF_TRACE(D_EVENTS, "Changing buffer size on interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing buffer size of %s from %d to %d", ifname, old->rx_buffer, new->rx_buffer); /* ifa cannot be vlink */ @@ -896,7 +897,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* LINK */ if (ifa->check_link != new->check_link) { - OSPF_TRACE(D_EVENTS, "%s link check on interface %s", + OSPF_TRACE(D_EVENTS, "%s link check for %s", new->check_link ? "Enabling" : "Disabling", ifname); ifa->check_link = new->check_link; @@ -908,7 +909,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* ECMP weight */ if (ifa->ecmp_weight != new->ecmp_weight) { - OSPF_TRACE(D_EVENTS, "Changing ECMP weight of interface %s from %d to %d", + OSPF_TRACE(D_EVENTS, "Changing ECMP weight of %s from %d to %d", ifname, (int)ifa->ecmp_weight + 1, (int)new->ecmp_weight + 1); ifa->ecmp_weight = new->ecmp_weight; } @@ -927,7 +928,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* BFD */ if (ifa->bfd != new->bfd) { - OSPF_TRACE(D_EVENTS, "%s BFD on interface %s", + OSPF_TRACE(D_EVENTS, "%s BFD for %s", new->bfd ? "Enabling" : "Disabling", ifname); ifa->bfd = new->bfd; @@ -1197,7 +1198,7 @@ ospf_iface_change_mtu(struct ospf_proto *p, struct ospf_iface *ifa) { /* ifa is not vlink */ - OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->ifname); + OSPF_TRACE(D_EVENTS, "Interface %s changed MTU to %d", ifa->iface->mtu); ifa->tx_length = ifa_tx_length(ifa); @@ -1285,7 +1286,7 @@ ospf_iface_info(struct ospf_iface *ifa) cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more); cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid); } - cli_msg(-1015, "\tState: %s%s", ospf_is[ifa->state], ifa->stub ? " (stub)" : ""); + cli_msg(-1015, "\tState: %s%s", ospf_is_names[ifa->state], ifa->stub ? " (stub)" : ""); cli_msg(-1015, "\tPriority: %u", ifa->priority); cli_msg(-1015, "\tCost: %u", ifa->cost); if (ifa->oa->po->ecmp) diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index 5cac3f69..e590817e 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -140,10 +140,13 @@ ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa, /* No need to check length, lsack has only basic header */ - OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet received from %I via %s", n->ip, ifa->ifname); + OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet received from nbr %R on %s", n->rid, ifa->ifname); if (n->state < NEIGHBOR_EXCHANGE) + { + OSPF_TRACE(D_PACKETS, "LSACK packet ignored - lesser state than Exchange"); return; + } ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */ diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index a6c0cf24..067ad79b 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -93,7 +93,7 @@ ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n) length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsreq_header); pkt->length = htons(length); - OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet sent to %I via %s", n->ip, ifa->ifname); + OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet sent to nbr %R on %s", n->rid, ifa->ifname); ospf_send_to(ifa, n->ip); } @@ -110,10 +110,13 @@ ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa, /* No need to check length, lsreq has only basic header */ - OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet received from %I via %s", n->ip, ifa->ifname); + OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet received from nbr %R on %s", n->rid, ifa->ifname); if (n->state < NEIGHBOR_EXCHANGE) + { + OSPF_TRACE(D_PACKETS, "LSREQ packet ignored - lesser state than Exchange"); return; + } ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */ @@ -134,8 +137,9 @@ ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa, en = ospf_hash_find(p->gr, domain, id, rt, type); if (!en) { - log(L_WARN "%s: Received LSREQ from %I for missing LSA (Type: %04x, Id: %R, Rt: %R)", - p->p.name, n->ip, type, id, rt); + LOG_LSA1("Bad LSR (Type: %04x, Id: %R, Rt: %R) in LSREQ", type, id, rt); + LOG_LSA2(" received from nbr %R on %s - LSA is missing", n->rid, ifa->ifname); + ospf_neigh_sm(n, INM_BADLSREQ); return; } diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 13ae54d1..0aa45f6a 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -338,7 +338,7 @@ ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa { i++; continue; } OSPF_PACKET(ospf_dump_lsupd, ospf_tx_buffer(ifa), - "LSUPD packet sent to %I via %s", n->ip, ifa->ifname); + "LSUPD packet sent to nbr %R on %s", n->rid, ifa->ifname); ospf_send_to(ifa, n->ip); } @@ -396,24 +396,22 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { struct ospf_proto *p = ifa->oa->po; - - /* RFC 2328 13. */ - + const char *err_dsc = NULL; + uint plen, err_val = 0; int skip_lsreq = 0; n->want_lsreq = 0; - uint plen = ntohs(pkt->length); + /* RFC 2328 13. */ + + plen = ntohs(pkt->length); if (plen < (ospf_lsupd_hdrlen(p) + sizeof(struct ospf_lsa_header))) - { - log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, plen); - return; - } + DROP("too short", plen); - OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->ifname); + OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet received from nbr %R on %s", n->rid, ifa->ifname); if (n->state < NEIGHBOR_EXCHANGE) { - OSPF_TRACE(D_PACKETS, "Received lsupd in lesser state than EXCHANGE from (%I)", n->ip); + OSPF_TRACE(D_PACKETS, "LSUPD packet ignored - lesser state than Exchange"); return; } @@ -429,33 +427,18 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, u32 lsa_len, lsa_type, lsa_domain; if (offset > bound) - { - log(L_WARN "%s: Received LSUPD from %I is too short", p->p.name, n->ip); - ospf_neigh_sm(n, INM_BADLSREQ); - return; - } + DROP("too short", plen); /* LSA header in network order */ lsa_n = ((void *) pkt) + offset; lsa_len = ntohs(lsa_n->length); offset += lsa_len; - if ((offset > plen) || ((lsa_len % 4) != 0) || - (lsa_len <= sizeof(struct ospf_lsa_header))) - { - log(L_WARN "%s: Received LSA from %I with bad length", p->p.name, n->ip); - ospf_neigh_sm(n, INM_BADLSREQ); - return; - } + if (offset > plen) + DROP("too short", plen); - /* RFC 2328 13. (1) - validate LSA checksum */ - u16 chsum = lsa_n->checksum; - if (chsum != lsasum_check(lsa_n, NULL)) - { - log(L_WARN "%s: Received LSA from %I with bad checksum: %x %x", - p->p.name, n->ip, chsum, lsa_n->checksum); - continue; - } + if (((lsa_len % 4) != 0) || (lsa_len <= sizeof(struct ospf_lsa_header))) + DROP("invalid LSA length", lsa_len); /* LSA header in host order */ lsa_ntoh_hdr(lsa_n, &lsa); @@ -464,33 +447,25 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, DBG("Update Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n", lsa_type, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum); + /* RFC 2328 13. (1) - validate LSA checksum */ + if (lsa_n->checksum != lsasum_check(lsa_n, NULL)) + SKIP("invalid checksum"); + /* RFC 2328 13. (2) */ if (!lsa_type) - { - log(L_WARN "%s: Received unknown LSA type from %I", p->p.name, n->ip); - continue; - } + SKIP("unknown type"); /* RFC 5340 4.5.1 (2) and RFC 2328 13. (3) */ if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS)) - { - log(L_WARN "%s: Received LSA with AS scope in stub area from %I", p->p.name, n->ip); - continue; - } + SKIP("AS scope in stub area"); /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */ if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT)) - { - log(L_WARN "%s: Received rt-summary-LSA in stub area from %I", p->p.name, n->ip); - continue; - } + SKIP("rt-summary-LSA in stub area"); /* RFC 5340 4.5.1 (3) */ if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES) - { - log(L_WARN "%s: Received LSA with invalid scope from %I", p->p.name, n->ip); - continue; - } + SKIP("invalid scope"); /* Find local copy of LSA in link state database */ en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type); @@ -528,9 +503,8 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, if (lsa_validate(&lsa, lsa_type, ospf_is_v2(p), body) == 0) { - log(L_WARN "%s: Received invalid LSA from %I", p->p.name, n->ip); mb_free(body); - continue; + SKIP("invalid body"); } /* 13. (5f) - handle self-originated LSAs, see also 13.4. */ @@ -542,8 +516,8 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, continue; } - /* 13. (5c) - remove old LSA from all retransmission lists */ - /* + /* 13. (5c) - remove old LSA from all retransmission lists + * * We only need to remove it from the retransmission list of the neighbor * that send us the new LSA. The old LSA is automatically replaced in * retransmission lists by the new LSA. @@ -561,8 +535,8 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, WALK_LIST(ifi, p->iface_list) WALK_LIST(ni, ifi->neigh_list) - if (ni->state > NEIGHBOR_EXSTART) - ospf_lsa_lsrt_down(en, ni); + if (ni->state > NEIGHBOR_EXSTART) + ospf_lsa_lsrt_down(en, ni); #endif /* 13. (5d) - install new LSA into database */ @@ -615,7 +589,13 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, /* Send newer local copy back to neighbor */ /* FIXME - check for MinLSArrival ? */ ospf_send_lsupd(p, &en, 1, n); + + continue; } + + skip: + LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in LSUPD", lsa_type, lsa.id, lsa.rt); + LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc); } /* Send direct LSACKs */ @@ -630,4 +610,14 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, */ if ((n->state == NEIGHBOR_LOADING) && n->want_lsreq && !skip_lsreq) ospf_send_lsreq(p, n); + + return; + +drop: + LOG_PKT("Bad LSUPD packet from nbr %R on %s - %s (%u)", + n->rid, ifa->ifname, err_dsc, err_val); + + // XXXX realy? + ospf_neigh_sm(n, INM_SEQMIS); + return; } diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index ee1e8d0f..c75b1b93 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -10,24 +10,19 @@ #include "ospf.h" -char *ospf_ns[] = { " down", - " attempt", - " init", - " 2way", - " exstart", - "exchange", - " loading", - " full" + +const char *ospf_ns_names[] = { + "Down", "Attempt", "Init", "2-Way", "ExStart", "Exchange", "Loading", "Full" }; -const char *ospf_inm[] = - { "hello received", "neighbor start", "2-way received", - "negotiation done", "exstart done", "bad ls request", "load done", - "adjacency ok?", "sequence mismatch", "1-way received", "kill neighbor", - "inactivity timer", "line down" +const char *ospf_inm_names[] = { + "HelloReceived", "Start", "2-WayReceived", "NegotiationDone", "ExchangeDone", + "BadLSReq", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "1-WayReceived", + "KillNbr", "InactivityTimer", "LLDown" }; -static void neigh_chstate(struct ospf_neighbor *n, u8 state); + +static int can_do_adj(struct ospf_neighbor *n); static void neighbor_timer_hook(timer * timer); static void rxmt_timer_hook(timer * timer); static void ackd_timer_hook(timer * t); @@ -113,8 +108,29 @@ ospf_neighbor_new(struct ospf_iface *ifa) return (n); } +static void +ospf_neigh_down(struct ospf_neighbor *n) +{ + struct ospf_iface *ifa = n->ifa; + struct ospf_proto *p = ifa->oa->po; + + if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) + { + struct nbma_node *nn = find_nbma_node(ifa, n->ip); + if (nn) + nn->found = 0; + } + + s_get(&(n->dbsi)); + release_lsrtl(p, n); + rem_node(NODE n); + rfree(n->pool); + + OSPF_TRACE(D_EVENTS, "Neighbor %R on %s removed", n->rid, ifa->ifname); +} + /** - * neigh_chstate - handles changes related to new or lod state of neighbor + * ospf_neigh_chstate - handles changes related to new or lod state of neighbor * @n: OSPF neighbor * @state: new state * @@ -122,7 +138,7 @@ ospf_neighbor_new(struct ospf_iface *ifa) * starts rxmt timers, call interface state machine etc. */ static void -neigh_chstate(struct ospf_neighbor *n, u8 state) +ospf_neigh_chstate(struct ospf_neighbor *n, u8 state) { struct ospf_iface *ifa = n->ifa; struct ospf_proto *p = ifa->oa->po; @@ -132,16 +148,11 @@ neigh_chstate(struct ospf_neighbor *n, u8 state) if (state == old_state) return; - OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from %s to %s", - n->ip, ospf_ns[old_state], ospf_ns[state]); + OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed state from %s to %s", + n->rid, ifa->ifname, ospf_ns_names[old_state], ospf_ns_names[state]); n->state = state; - if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY)) - ospf_iface_sm(ifa, ISM_NEICH); - if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY)) - ospf_iface_sm(ifa, ISM_NEICH); - /* Increase number of partial adjacencies */ if ((state == NEIGHBOR_EXCHANGE) || (state == NEIGHBOR_LOADING)) p->padj++; @@ -181,145 +192,12 @@ neigh_chstate(struct ospf_neighbor *n, u8 state) if (state > NEIGHBOR_EXSTART) n->myimms &= ~DBDES_I; -} -static inline u32 neigh_get_id(struct ospf_proto *p, struct ospf_neighbor *n) -{ return ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; } - -static struct ospf_neighbor * -elect_bdr(struct ospf_proto *p, list nl) -{ - struct ospf_neighbor *neigh, *n1, *n2; - u32 nid; - - n1 = NULL; - n2 = NULL; - WALK_LIST(neigh, nl) /* First try those decl. themselves */ - { - nid = neigh_get_id(p, neigh); - - if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ - if (neigh->priority > 0) /* Eligible */ - if (neigh->dr != nid) /* And not decl. itself DR */ - { - if (neigh->bdr == nid) /* Declaring BDR */ - { - if (n1 != NULL) - { - if (neigh->priority > n1->priority) - n1 = neigh; - else if (neigh->priority == n1->priority) - if (neigh->rid > n1->rid) - n1 = neigh; - } - else - { - n1 = neigh; - } - } - else /* And NOT declaring BDR */ - { - if (n2 != NULL) - { - if (neigh->priority > n2->priority) - n2 = neigh; - else if (neigh->priority == n2->priority) - if (neigh->rid > n2->rid) - n2 = neigh; - } - else - { - n2 = neigh; - } - } - } - } - if (n1 == NULL) - n1 = n2; - - return (n1); -} - -static struct ospf_neighbor * -elect_dr(struct ospf_proto *p, list nl) -{ - struct ospf_neighbor *neigh, *n; - u32 nid; - - n = NULL; - WALK_LIST(neigh, nl) /* And now DR */ - { - nid = neigh_get_id(p, neigh); - - if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ - if (neigh->priority > 0) /* Eligible */ - if (neigh->dr == nid) /* And declaring itself DR */ - { - if (n != NULL) - { - if (neigh->priority > n->priority) - n = neigh; - else if (neigh->priority == n->priority) - if (neigh->rid > n->rid) - n = neigh; - } - else - { - n = neigh; - } - } - } - - return (n); -} - -static int -can_do_adj(struct ospf_neighbor *n) -{ - struct ospf_iface *ifa = n->ifa; - struct ospf_proto *p = ifa->oa->po; - int i = 0; - - switch (ifa->type) - { - case OSPF_IT_PTP: - case OSPF_IT_PTMP: - case OSPF_IT_VLINK: - i = 1; - break; - case OSPF_IT_BCAST: - case OSPF_IT_NBMA: - switch (ifa->state) - { - case OSPF_IS_DOWN: - case OSPF_IS_LOOP: - bug("%s: Iface %s in down state?", p->p.name, ifa->ifname); - break; - case OSPF_IS_WAITING: - DBG("%s: Neighbor? on iface %s\n", p->p.name, ifa->ifname); - break; - case OSPF_IS_DROTHER: - if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid)) - && (n->state >= NEIGHBOR_2WAY)) - i = 1; - break; - case OSPF_IS_PTP: - case OSPF_IS_BACKUP: - case OSPF_IS_DR: - if (n->state >= NEIGHBOR_2WAY) - i = 1; - break; - default: - bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname); - break; - } - break; - default: - bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname); - break; - } - DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i); - return i; + /* Generate NeighborChange event if needed, see RFC 2328 9.2 */ + if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY)) + ospf_iface_sm(ifa, ISM_NEICH); + if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY)) + ospf_iface_sm(ifa, ISM_NEICH); } /** @@ -339,20 +217,19 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) { struct ospf_proto *p = n->ifa->oa->po; - DBG("Neighbor state machine for neighbor %I, event '%s'\n", n->ip, - ospf_inm[event]); + DBG("Neighbor state machine for %R on %s, event %s\n", + n->rid, n->ifa->ifname, ospf_inm_names[event]); switch (event) { case INM_START: - neigh_chstate(n, NEIGHBOR_ATTEMPT); + ospf_neigh_chstate(n, NEIGHBOR_ATTEMPT); /* NBMA are used different way */ break; case INM_HELLOREC: - if ((n->state == NEIGHBOR_DOWN) || - (n->state == NEIGHBOR_ATTEMPT)) - neigh_chstate(n, NEIGHBOR_INIT); + if (n->state < NEIGHBOR_INIT) + ospf_neigh_chstate(n, NEIGHBOR_INIT); /* Restart inactivity timer */ tm_start(n->inactim, n->ifa->deadint); @@ -360,15 +237,15 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) case INM_2WAYREC: if (n->state < NEIGHBOR_2WAY) - neigh_chstate(n, NEIGHBOR_2WAY); + ospf_neigh_chstate(n, NEIGHBOR_2WAY); if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n)) - neigh_chstate(n, NEIGHBOR_EXSTART); + ospf_neigh_chstate(n, NEIGHBOR_EXSTART); break; case INM_NEGDONE: if (n->state == NEIGHBOR_EXSTART) { - neigh_chstate(n, NEIGHBOR_EXCHANGE); + ospf_neigh_chstate(n, NEIGHBOR_EXCHANGE); /* Reset DB summary list iterator */ s_get(&(n->dbsi)); @@ -385,11 +262,11 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) break; case INM_EXDONE: - neigh_chstate(n, NEIGHBOR_LOADING); + ospf_neigh_chstate(n, NEIGHBOR_LOADING); break; case INM_LOADDONE: - neigh_chstate(n, NEIGHBOR_FULL); + ospf_neigh_chstate(n, NEIGHBOR_FULL); break; case INM_ADJOK: @@ -399,15 +276,15 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) /* Can In build adjacency? */ if (can_do_adj(n)) { - neigh_chstate(n, NEIGHBOR_EXSTART); + ospf_neigh_chstate(n, NEIGHBOR_EXSTART); } break; default: if (n->state >= NEIGHBOR_EXSTART) if (!can_do_adj(n)) { - reset_lists(p,n); - neigh_chstate(n, NEIGHBOR_2WAY); + reset_lists(p, n); + ospf_neigh_chstate(n, NEIGHBOR_2WAY); } break; } @@ -418,20 +295,21 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) if (n->state >= NEIGHBOR_EXCHANGE) { reset_lists(p, n); - neigh_chstate(n, NEIGHBOR_EXSTART); + ospf_neigh_chstate(n, NEIGHBOR_EXSTART); } break; case INM_KILLNBR: case INM_LLDOWN: case INM_INACTTIM: - reset_lists(p, n); - neigh_chstate(n, NEIGHBOR_DOWN); + /* No need for reset_lists() */ + ospf_neigh_chstate(n, NEIGHBOR_DOWN); + ospf_neigh_down(n); break; case INM_1WAYREC: reset_lists(p, n); - neigh_chstate(n, NEIGHBOR_INIT); + ospf_neigh_chstate(n, NEIGHBOR_INIT); break; default: @@ -440,14 +318,156 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) } } +static int +can_do_adj(struct ospf_neighbor *n) +{ + struct ospf_iface *ifa = n->ifa; + struct ospf_proto *p = ifa->oa->po; + int i = 0; + + switch (ifa->type) + { + case OSPF_IT_PTP: + case OSPF_IT_PTMP: + case OSPF_IT_VLINK: + i = 1; + break; + case OSPF_IT_BCAST: + case OSPF_IT_NBMA: + switch (ifa->state) + { + case OSPF_IS_DOWN: + case OSPF_IS_LOOP: + bug("%s: Iface %s in down state?", p->p.name, ifa->ifname); + break; + case OSPF_IS_WAITING: + DBG("%s: Neighbor? on iface %s\n", p->p.name, ifa->ifname); + break; + case OSPF_IS_DROTHER: + if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid)) + && (n->state >= NEIGHBOR_2WAY)) + i = 1; + break; + case OSPF_IS_PTP: + case OSPF_IS_BACKUP: + case OSPF_IS_DR: + if (n->state >= NEIGHBOR_2WAY) + i = 1; + break; + default: + bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname); + break; + } + break; + default: + bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname); + break; + } + DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i); + return i; +} + + +static inline u32 neigh_get_id(struct ospf_proto *p, struct ospf_neighbor *n) +{ return ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; } + +static struct ospf_neighbor * +elect_bdr(struct ospf_proto *p, list nl) +{ + struct ospf_neighbor *neigh, *n1, *n2; + u32 nid; + + n1 = NULL; + n2 = NULL; + WALK_LIST(neigh, nl) /* First try those decl. themselves */ + { + nid = neigh_get_id(p, neigh); + + if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ + if (neigh->priority > 0) /* Eligible */ + if (neigh->dr != nid) /* And not decl. itself DR */ + { + if (neigh->bdr == nid) /* Declaring BDR */ + { + if (n1 != NULL) + { + if (neigh->priority > n1->priority) + n1 = neigh; + else if (neigh->priority == n1->priority) + if (neigh->rid > n1->rid) + n1 = neigh; + } + else + { + n1 = neigh; + } + } + else /* And NOT declaring BDR */ + { + if (n2 != NULL) + { + if (neigh->priority > n2->priority) + n2 = neigh; + else if (neigh->priority == n2->priority) + if (neigh->rid > n2->rid) + n2 = neigh; + } + else + { + n2 = neigh; + } + } + } + } + if (n1 == NULL) + n1 = n2; + + return (n1); +} + +static struct ospf_neighbor * +elect_dr(struct ospf_proto *p, list nl) +{ + struct ospf_neighbor *neigh, *n; + u32 nid; + + n = NULL; + WALK_LIST(neigh, nl) /* And now DR */ + { + nid = neigh_get_id(p, neigh); + + if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ + if (neigh->priority > 0) /* Eligible */ + if (neigh->dr == nid) /* And declaring itself DR */ + { + if (n != NULL) + { + if (neigh->priority > n->priority) + n = neigh; + else if (neigh->priority == n->priority) + if (neigh->rid > n->rid) + n = neigh; + } + else + { + n = neigh; + } + } + } + + return (n); +} + /** * ospf_dr_election - (Backup) Designed Router election * @ifa: actual interface * * When the wait timer fires, it is time to elect (Backup) Designated Router. - * Structure describing me is added to this list so every electing router - * has the same list. Backup Designated Router is elected before Designated - * Router. This process is described in 9.4 of RFC 2328. + * Structure describing me is added to this list so every electing router has + * the same list. Backup Designated Router is elected before Designated + * Router. This process is described in 9.4 of RFC 2328. The function is + * supposed to be called only from ospf_iface_sm() as a part of the interface + * state machine. */ void ospf_dr_election(struct ospf_iface *ifa) @@ -506,6 +526,7 @@ ospf_dr_election(struct ospf_iface *ifa) DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid); + /* We are part of the interface state machine */ if (ifa->drid == myid) ospf_iface_chstate(ifa, OSPF_IS_DR); else if (ifa->bdrid == myid) @@ -544,39 +565,15 @@ find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip) return NULL; } -/* Neighbor is inactive for a long time. Remove it. */ static void neighbor_timer_hook(timer * timer) { struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; - struct ospf_iface *ifa = n->ifa; - struct ospf_proto *p = ifa->oa->po; - - OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I", - ifa->ifname, n->ip); - ospf_neigh_remove(n); -} - -void -ospf_neigh_remove(struct ospf_neighbor *n) -{ - struct ospf_iface *ifa = n->ifa; - struct ospf_proto *p = ifa->oa->po; - - if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) - { - struct nbma_node *nn = find_nbma_node(ifa, n->ip); - if (nn) - nn->found = 0; - } - - neigh_chstate(n, NEIGHBOR_DOWN); + struct ospf_proto *p = n->ifa->oa->po; - s_get(&(n->dbsi)); - release_lsrtl(p, n); - rem_node(NODE n); - rfree(n->pool); - OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", n->rid); + OSPF_TRACE(D_EVENTS, "Inactivity timer expired for neighbor %R on %s", + n->rid, n->ifa->ifname); + ospf_neigh_sm(n, INM_INACTTIM); } static void @@ -587,8 +584,9 @@ ospf_neigh_bfd_hook(struct bfd_request *req) if (req->down) { - OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", n->ip, n->ifa->ifname); - ospf_neigh_remove(n); + OSPF_TRACE(D_EVENTS, "BFD session down for neighbor %R on %s", + n->rid, n->ifa->ifname); + ospf_neigh_sm(n, INM_INACTTIM); } } @@ -611,7 +609,7 @@ void ospf_sh_neigh_info(struct ospf_neighbor *n) { struct ospf_iface *ifa = n->ifa; - char *pos = "other"; + char *pos = "ptp "; char etime[6]; int exp, sec, min; @@ -627,16 +625,18 @@ ospf_sh_neigh_info(struct ospf_neighbor *n) bsprintf(etime, "%02u:%02u", min, sec); } - if (n->rid == ifa->drid) - pos = "dr "; - else if (n->rid == ifa->bdrid) - pos = "bdr "; - else if ((n->ifa->type == OSPF_IT_PTP) || (n->ifa->type == OSPF_IT_PTMP) || - (n->ifa->type == OSPF_IT_VLINK)) - pos = "ptp "; + if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA)) + { + if (n->rid == ifa->drid) + pos = "dr "; + else if (n->rid == ifa->bdrid) + pos = "bdr "; + else + pos = "other"; + } cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority, - ospf_ns[n->state], pos, etime, ifa->ifname, n->ip); + ospf_ns_names[n->state], pos, etime, ifa->ifname, n->ip); } static void @@ -645,18 +645,18 @@ rxmt_timer_hook(timer *t) struct ospf_neighbor *n = t->data; struct ospf_proto *p = n->ifa->oa->po; - DBG("%s: RXMT timer fired on interface %s for neigh %I\n", + DBG("%s: RXMT timer fired on %s for neigh %I\n", p->p.name, n->ifa->ifname, n->ip); switch (n->state) { case NEIGHBOR_EXSTART: - ospf_send_dbdes(p, n, 1); + ospf_send_dbdes(p, n); return; case NEIGHBOR_EXCHANGE: - if (n->myimms & DBDES_MS) - ospf_send_dbdes(p, n, 0); + if (n->myimms & DBDES_MS) + ospf_rxmt_dbdes(p, n); case NEIGHBOR_LOADING: ospf_send_lsreq(p, n); return; @@ -666,9 +666,6 @@ rxmt_timer_hook(timer *t) if (!EMPTY_SLIST(n->lsrtl)) ospf_rxmt_lsupd(p, n); return; - - default: - return; } } @@ -678,7 +675,7 @@ ackd_timer_hook(timer *t) struct ospf_neighbor *n = t->data; struct ospf_proto *p = n->ifa->oa->po; - DBG("%s: ACKD timer fired on interface %s for neigh %I\n", + DBG("%s: ACKD timer fired on %s for neigh %I\n", p->p.name, n->ifa->ifname, n->ip); ospf_send_lsack(p, n, ACKL_DELAY); diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 470a8633..01e53922 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -252,6 +252,9 @@ ospf_start(struct proto *P) p->gr = ospf_top_new(p, P->pool); s_init_list(&(p->lsal)); + p->log_pkt_tbf = (struct tbf){ .rate = 1, .burst = 5 }; + p->log_lsa_tbf = (struct tbf){ .rate = 4, .burst = 20 }; + WALK_LIST(ac, c->area_list) ospf_area_add(p, ac); @@ -742,7 +745,7 @@ ospf_sh(struct proto *P) } cli_msg(-1014, "%s:", p->p.name); - cli_msg(-1014, "RFC1583 compatibility: %s", (p->rfc1583 ? "enable" : "disabled")); + cli_msg(-1014, "RFC1583 compatibility: %s", (p->rfc1583 ? "enabled" : "disabled")); cli_msg(-1014, "Stub router: %s", (p->stub_router ? "Yes" : "No")); cli_msg(-1014, "RT scheduler tick: %d", p->tick); cli_msg(-1014, "Number of areas: %u", p->areano); diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index f464a3ed..6df5df08 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -73,12 +73,28 @@ // FIXME: MAX_PREFIX_LENGTH #define OSPF_TRACE(flags, msg, args...) \ -do { if ((p->p.debug & flags) || OSPF_FORCE_DEBUG) \ - log(L_TRACE "%s: " msg, p->p.name , ## args ); } while(0) + do { if ((p->p.debug & flags) || OSPF_FORCE_DEBUG) \ + log(L_TRACE "%s: " msg, p->p.name , ## args ); } while(0) #define OSPF_PACKET(dumpfn, buffer, msg, args...) \ -do { if ((p->p.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \ - { log(L_TRACE "%s: " msg, p->p.name, ## args ); dumpfn(p, buffer); } } while(0) + do { if ((p->p.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \ + { log(L_TRACE "%s: " msg, p->p.name, ## args ); dumpfn(p, buffer); } } while(0) + +#define LOG_PKT(msg, args...) \ + log_rl(&p->log_pkt_tbf, L_REMOTE "%s: " msg, p->p.name, args) + +#define LOG_PKT_AUTH(msg, args...) \ + log_rl(&p->log_pkt_tbf, L_AUTH "%s: " msg, p->p.name, args) + +#define LOG_PKT_WARN(msg, args...) \ + log_rl(&p->log_pkt_tbf, L_WARN "%s: " msg, p->p.name, args) + +#define LOG_LSA1(msg, args...) \ + log_rl(&p->log_lsa_tbf, L_REMOTE "%s: " msg, p->p.name, args) + +#define LOG_LSA2(msg, args...) \ + do { if (! p->log_lsa_tbf.mark) \ + log(L_REMOTE "%s: " msg, p->p.name, args); } while(0) #define OSPF_PROTO 89 @@ -248,6 +264,8 @@ struct ospf_proto sock *vlink_sk; /* IP socket used for vlink TX */ u32 router_id; u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */ + struct tbf log_pkt_tbf; /* TBF for packet messages */ + struct tbf log_lsa_tbf; /* TBF for LSA messages */ }; struct ospf_area @@ -283,7 +301,7 @@ struct ospf_iface pool *pool; sock *sk; /* IP socket */ - list neigh_list; /* List of neigbours (struct ospf_neighbor) */ + list neigh_list; /* List of neighbors (struct ospf_neighbor) */ u32 cost; /* Cost of iface */ u32 waitint; /* number of sec before changing state from wait */ u32 rxmtint; /* number of seconds between LSA retransmissions */ @@ -368,8 +386,8 @@ struct ospf_neighbor /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in OSPFv3, we use the same type to simplify handling */ - u32 dr; /* Neigbour's idea of DR */ - u32 bdr; /* Neigbour's idea of BDR */ + u32 dr; /* Neighbor's idea of DR */ + u32 bdr; /* Neighbor's idea of BDR */ u32 iface_id; /* ID of Neighbour's iface connected to common network */ /* Database summary list iterator, controls initial dbdes exchange. @@ -890,7 +908,6 @@ void ospf_neigh_sm(struct ospf_neighbor *n, int event); void ospf_dr_election(struct ospf_iface *ifa); struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid); struct ospf_neighbor *find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip); -void ospf_neigh_remove(struct ospf_neighbor *n); void ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd); void ospf_sh_neigh_info(struct ospf_neighbor *n); @@ -916,6 +933,10 @@ static inline void ospf_send_to_des(struct ospf_iface *ifa) ospf_send_to_bdr(ifa); } +#define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0) +#define DROP1(DSC) do { err_dsc = DSC; goto drop; } while(0) +#define SKIP(DSC) do { err_dsc = DSC; goto skip; } while(0) + static inline uint ospf_pkt_hdrlen(struct ospf_proto *p) { return ospf_is_v2(p) ? (sizeof(struct ospf_packet) + sizeof(union ospf_auth)) : sizeof(struct ospf_packet); } @@ -931,7 +952,8 @@ void ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dir void ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr); /* dbdes.c */ -void ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int next); +void ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n); +void ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n); void ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n); /* lsreq.c */ diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index d64d7d6b..2814712d 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -66,7 +66,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) log(L_ERR "No suitable password found for authentication"); return; } - password_cpy(auth->password, passwd->password, sizeof(union ospf_auth)); + strncpy(auth->password, passwd->password, sizeof(auth->password)); case OSPF_AUTH_NONE: { @@ -106,7 +106,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) void *tail = ((void *) pkt) + plen; char password[OSPF_AUTH_CRYPT_SIZE]; - password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE); + strncpy(password, passwd->password, sizeof(password)); struct MD5Context ctxt; MD5Init(&ctxt); @@ -120,23 +120,22 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) } } + /* We assume OSPFv2 in ospf_pkt_checkauth() */ static int -ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size) +ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int len) { struct ospf_proto *p = ifa->oa->po; union ospf_auth *auth = (void *) (pkt + 1); - struct password_item *pass = NULL, *ptmp; - char password[OSPF_AUTH_CRYPT_SIZE]; + struct password_item *pass = NULL; + const char *err_dsc = NULL; + uint err_val = 0; uint plen = ntohs(pkt->length); u8 autype = pkt->autype; if (autype != ifa->autype) - { - OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", autype); - return 0; - } + DROP("authentication method mismatch", autype); switch (autype) { @@ -146,85 +145,65 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ case OSPF_AUTH_SIMPLE: pass = password_find(ifa->passwords, 1); if (!pass) - { - OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found"); - return 0; - } + DROP1("no password found"); + + if (!password_verify(pass, auth->password, sizeof(auth->password))) + DROP("wrong password", pass->id); - password_cpy(password, pass->password, sizeof(union ospf_auth)); - if (memcmp(auth->password, password, sizeof(union ospf_auth))) - { - OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords"); - return 0; - } return 1; case OSPF_AUTH_CRYPT: if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE) - { - OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest"); - return 0; - } - - if (plen + OSPF_AUTH_CRYPT_SIZE > size) - { - OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)", - plen + OSPF_AUTH_CRYPT_SIZE, size); - return 0; - } - - if (n) - { - u32 rcv_csn = ntohl(auth->md5.csn); - if(rcv_csn < n->csn) - { - OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn); - return 0; - } + DROP("invalid MD5 digest length", auth->md5.len); - n->csn = rcv_csn; - } + if (plen + OSPF_AUTH_CRYPT_SIZE > len) + DROP("length mismatch", len); - if (ifa->passwords) + u32 rcv_csn = ntohl(auth->md5.csn); + if (n && (rcv_csn < n->csn)) + // DROP("lower sequence number", rcv_csn); { - WALK_LIST(ptmp, *(ifa->passwords)) - { - if (auth->md5.keyid != ptmp->id) continue; - if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue; - pass = ptmp; - break; - } + /* We want to report both new and old CSN */ + LOG_PKT_AUTH("Authentication failed for nbr %R on %s - " + "lower sequence number (rcv %u, old %u)", + n->rid, ifa->ifname, rcv_csn, n->csn); + return 0; } + pass = password_find_by_id(ifa->passwords, auth->md5.keyid); if (!pass) - { - OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found"); - return 0; - } + DROP("no suitable password found", auth->md5.keyid); void *tail = ((void *) pkt) + plen; + char passwd[OSPF_AUTH_CRYPT_SIZE]; char md5sum[OSPF_AUTH_CRYPT_SIZE]; - password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE); + + strncpy(passwd, pass->password, OSPF_AUTH_CRYPT_SIZE); struct MD5Context ctxt; MD5Init(&ctxt); MD5Update(&ctxt, (char *) pkt, plen); - MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE); + MD5Update(&ctxt, passwd, OSPF_AUTH_CRYPT_SIZE); MD5Final(md5sum, &ctxt); if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE)) - { - OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest"); - return 0; - } + DROP("wrong MD5 digest", pass->id); + + if (n) + n->csn = rcv_csn; + return 1; default: - OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type"); - return 0; + bug("Unknown authentication type"); } -} +drop: + LOG_PKT_AUTH("Authentication failed for nbr %R on %s - %s (%u)", + (n ? n->rid : ntohl(pkt->routerid)), ifa->ifname, err_dsc, err_val); + + return 0; +} /** * ospf_rx_hook @@ -236,13 +215,10 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ * non generic functions. */ int -ospf_rx_hook(sock *sk, int size) +ospf_rx_hook(sock *sk, int len) { - char *mesg = "OSPF: Bad packet from "; - - /* We want just packets from sk->iface. Unfortunately, on BSD we - cannot filter out other packets at kernel level and we receive - all packets on all sockets */ + /* We want just packets from sk->iface. Unfortunately, on BSD we cannot filter + out other packets at kernel level and we receive all packets on all sockets */ if (sk->lifindex != sk->iface->index) return 1; @@ -252,6 +228,8 @@ ospf_rx_hook(sock *sk, int size) /* Initially, the packet is associated with the 'master' iface */ struct ospf_iface *ifa = sk->data; struct ospf_proto *p = ifa->oa->po; + const char *err_dsc = NULL; + uint err_val = 0; int src_local, dst_local, dst_mcast; src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen); @@ -282,41 +260,31 @@ ospf_rx_hook(sock *sk, int size) * link-local src address, but does not enforce it. Strange. */ if (dst_mcast && !src_local) - log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr); + LOG_PKT_WARN("Multicast packet received from not-link-local %I via %s", + sk->faddr, ifa->ifname); } - /* Second, we check packet size, checksum, and the protocol version */ - struct ospf_packet *pkt = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size); + /* Second, we check packet length, checksum, and the protocol version */ + struct ospf_packet *pkt = (struct ospf_packet *) ip_skip_header(sk->rbuf, &len); if (pkt == NULL) - { - log(L_ERR "%s%I - bad IP header", mesg, sk->faddr); - return 1; - } + DROP("bad IP header", len); if (ifa->check_ttl && (sk->rcv_ttl < 255)) - { - log(L_ERR "%s%I - TTL %d (< 255)", mesg, sk->faddr, sk->rcv_ttl); - return 1; - } + DROP("wrong TTL", sk->rcv_ttl); - if ((uint) size < sizeof(struct ospf_packet)) - { - log(L_ERR "%s%I - too short (%u bytes)", mesg, sk->faddr, size); - return 1; - } + if (len < sizeof(struct ospf_packet)) + DROP("too short", len); + + if (pkt->version != ospf_get_version(p)) + DROP("version mismatch", pkt->version); uint plen = ntohs(pkt->length); if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0)) - { - log(L_ERR "%s%I - invalid length (%u)", mesg, sk->faddr, plen); - return 1; - } + DROP("invalid length", plen); if (sk->flags & SKF_TRUNCATED) { - log(L_WARN "%s%I - too large (%d/%d)", mesg, sk->faddr, plen, size); - /* If we have dynamic buffers and received truncated message, we expand RX buffer */ uint bs = plen + 256; @@ -325,20 +293,11 @@ ospf_rx_hook(sock *sk, int size) if (!ifa->cf->rx_buffer && (bs > sk->rbsize)) sk_set_rbsize(sk, bs); - return 1; + DROP("truncated", plen); } - if (plen > size) - { - log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, plen, size); - return 1; - } - - if (pkt->version != ospf_get_version(p)) - { - log(L_ERR "%s%I - version %u", mesg, sk->faddr, pkt->version); - return 1; - } + if (plen > len) + DROP("length mismatch", plen); if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT)) { @@ -346,11 +305,8 @@ ospf_rx_hook(sock *sk, int size) uint blen = plen - hlen; void *body = ((void *) pkt) + hlen; - if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL)) - { - log(L_ERR "%s%I - bad checksum", mesg, sk->faddr); - return 1; - } + if (!ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL)) + DROP1("invalid checksum"); } /* Third, we resolve associated iface and handle vlinks. */ @@ -368,10 +324,7 @@ ospf_rx_hook(sock *sk, int size) /* It is real iface, source should be local (in OSPFv2) */ if (ospf_is_v2(p) && !src_local) - { - log(L_ERR "%s%I - strange source address for %s", mesg, sk->faddr, ifa->ifname); - return 1; - } + DROP1("strange source address"); goto found; } @@ -415,13 +368,11 @@ ospf_rx_hook(sock *sk, int size) if (instance_id != ifa->instance_id) return 1; - log(L_ERR "%s%I - area does not match (%R vs %R)", - mesg, sk->faddr, areaid, ifa->oa->areaid); - return 1; + DROP("area mismatch", areaid); } - found: +found: if (ifa->stub) /* This shouldn't happen */ return 1; @@ -429,18 +380,12 @@ ospf_rx_hook(sock *sk, int size) return 1; if (rid == p->router_id) - { - log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr); - return 1; - } + DROP1("my own router ID"); if (rid == 0) - { - log(L_ERR "%s%I - router id = 0.0.0.0", mesg, sk->faddr); - return 1; - } + DROP1("zero router ID"); - /* In OSPFv2, neighbors are identified by either IP or Router ID, base on network type */ + /* In OSPFv2, neighbors are identified by either IP or Router ID, based on network type */ uint t = ifa->type; struct ospf_neighbor *n; if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP))) @@ -450,16 +395,15 @@ ospf_rx_hook(sock *sk, int size) if (!n && (pkt->type != HELLO_P)) { - log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)", - sk->faddr, ifa->ifname); + // XXXX format + OSPF_TRACE(D_PACKETS, "Non-HELLO packet received from unknown neighbor %R on %s (%I)", + rid, ifa->ifname, sk->faddr); return 1; } - if (ospf_is_v2(p) && !ospf_pkt_checkauth(n, ifa, pkt, size)) - { - log(L_ERR "%s%I - authentication failed", mesg, sk->faddr); + /* ospf_pkt_checkauth() has its own error logging */ + if (ospf_is_v2(p) && !ospf_pkt_checkauth(n, ifa, pkt, len)) return 1; - } switch (pkt->type) { @@ -484,10 +428,15 @@ ospf_rx_hook(sock *sk, int size) break; default: - log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, pkt->type); - return 1; + DROP("invalid packet type", pkt->type); }; return 1; + +drop: + LOG_PKT("Bad packet from %I via %s - %s (%u)", + sk->faddr, ifa->ifname, err_dsc, err_val); + + return 1; } /* diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 16453b87..08f90b49 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -1204,7 +1204,7 @@ ospf_check_vlinks(struct ospf_proto *p) || (ifa->vifa != nhi) || !ipa_equal(ifa->vip, tmp->lb)) { - OSPF_TRACE(D_EVENTS, "Vlink peer %R found", tmp->lsa.id); + OSPF_TRACE(D_EVENTS, "Vlink peer %R found", ifa->vid); ospf_iface_sm(ifa, ISM_DOWN); ifa->vifa = nhi; ifa->addr = nhi->addr; @@ -1831,7 +1831,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, bad: /* Probably bug or some race condition, we log it */ - log(L_ERR "Unexpected case in next hop calculation"); + log(L_ERR "%s: Unexpected case in next hop calculation", p->p.name); return NULL; } @@ -1875,8 +1875,8 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, struct mpnh *nhs = calc_next_hop(oa, en, par, pos); if (!nhs) { - log(L_WARN "Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)", - en->lsa_type, en->lsa.id, en->lsa.rt); + log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)", + p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt); return; } diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 4e3da0de..15ba013a 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -758,7 +758,7 @@ prepare_rt2_lsa_body(struct ospf_proto *p, struct ospf_area *oa) break; default: - log("Unknown interface type %s", ifa->ifname); + log(L_BUG "OSPF: Unknown interface type"); break; } @@ -855,7 +855,7 @@ prepare_rt3_lsa_body(struct ospf_proto *p, struct ospf_area *oa) break; default: - log("Unknown interface type %s", ifa->ifname); + log(L_BUG "OSPF: Unknown interface type"); break; } diff --git a/proto/rip/auth.c b/proto/rip/auth.c index b7b0611e..5634547a 100644 --- a/proto/rip/auth.c +++ b/proto/rip/auth.c @@ -95,7 +95,7 @@ rip_incoming_authentication( struct proto *p, struct rip_block_auth *block, stru } memcpy(md5sum_packet, tail->md5, 16); - password_cpy(tail->md5, pass->password, 16); + strncpy(tail->md5, pass->password, 16); MD5Init(&ctxt); MD5Update(&ctxt, (char *) packet, ntohs(block->packetlen) + sizeof(struct rip_block_auth) ); @@ -131,7 +131,7 @@ rip_outgoing_authentication( struct proto *p, struct rip_block_auth *block, stru block->mustbeFFFF = 0xffff; switch (P_CF->authtype) { case AT_PLAINTEXT: - password_cpy( (char *) (&block->packetlen), passwd->password, 16); + strncpy( (char *) (&block->packetlen), passwd->password, 16); return PACKETLEN(num); case AT_MD5: { @@ -156,7 +156,7 @@ rip_outgoing_authentication( struct proto *p, struct rip_block_auth *block, stru tail->mustbeFFFF = 0xffff; tail->mustbe0001 = 0x0100; - password_cpy(tail->md5, passwd->password, 16); + strncpy(tail->md5, passwd->password, 16); MD5Init(&ctxt); MD5Update(&ctxt, (char *) packet, PACKETLEN(num) + sizeof(struct rip_md5_tail)); MD5Final(tail->md5, &ctxt); -- cgit v1.2.3 From 88a183c6c9a2b86b52f67e87bbc8b7edd32670c6 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 24 Oct 2014 11:11:43 +0200 Subject: Integrated IP functions. --- conf/cf-lex.l | 18 +- conf/confbase.Y | 2 +- lib/Modules | 7 - lib/ip.c | 376 +++++++++++++++++++++++++++++++++++++--- lib/ip.h | 471 +++++++++++++++++++++++++++++++++++++++++++++++--- lib/ipv4.c | 110 ------------ lib/ipv4.h | 116 ------------- lib/ipv6.c | 384 ---------------------------------------- lib/ipv6.h | 141 --------------- lib/printf.c | 4 +- lib/socket.h | 2 + proto/bgp/attrs.c | 2 +- proto/bgp/bgp.c | 12 +- proto/bgp/config.Y | 2 +- proto/bgp/packets.c | 8 +- proto/ospf/ospf.h | 33 +--- proto/ospf/packet.c | 3 +- proto/ospf/rt.c | 4 +- proto/ospf/topology.c | 2 +- proto/radv/packets.c | 4 +- proto/radv/radv.h | 3 - proto/rip/rip.c | 10 +- sysdep/bsd/krt-sock.c | 4 +- sysdep/unix/io.c | 23 +++ sysdep/unix/unix.h | 18 +- 25 files changed, 872 insertions(+), 887 deletions(-) delete mode 100644 lib/ipv4.c delete mode 100644 lib/ipv4.h delete mode 100644 lib/ipv6.c delete mode 100644 lib/ipv6.h (limited to 'proto/ospf/rt.c') diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 35b590bb..b3e13311 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -124,22 +124,24 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; } {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ { + ip4_addr a; + if (!ip4_pton(yytext, &a)) + cf_error("Invalid IPv4 address %s", yytext); + #ifdef IPV6 - if (ipv4_pton_u32(yytext, &cf_lval.i32)) - return RTRID; - cf_error("Invalid IPv4 address %s", yytext); + cf_lval.i32 = ip4_to_u32(a); + return RTRID; #else - if (ip_pton(yytext, &cf_lval.a)) - return IPA; - cf_error("Invalid IP address %s", yytext); + cf_lval.a = ipa_from_ip4(a); + return IPA; #endif } ({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) { #ifdef IPV6 - if (ip_pton(yytext, &cf_lval.a)) + if (ipa_pton(yytext, &cf_lval.a)) return IPA; - cf_error("Invalid IP address %s", yytext); + cf_error("Invalid IPv6 address %s", yytext); #else cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported"); #endif diff --git a/conf/confbase.Y b/conf/confbase.Y index 49831b1a..16a493e9 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -187,7 +187,7 @@ pxlen: $$ = $2; } | ':' ipa { - $$ = ipa_mklen($2); + $$ = ipa_masklen($2); if ($$ < 0) cf_error("Invalid netmask %I", $2); } ; diff --git a/lib/Modules b/lib/Modules index 7131f0b2..7254df2d 100644 --- a/lib/Modules +++ b/lib/Modules @@ -3,13 +3,6 @@ bitops.c bitops.h ip.h ip.c -#ifdef IPV6 -ipv6.c -ipv6.h -#else -ipv4.c -ipv4.h -#endif lists.c lists.h md5.c diff --git a/lib/ip.c b/lib/ip.c index aa61553e..01edf0d5 100644 --- a/lib/ip.c +++ b/lib/ip.c @@ -1,14 +1,11 @@ /* - * BIRD Library -- IP address routines common for IPv4 and IPv6 + * BIRD Library -- IP address functions * * (c) 1998--2000 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ -#include "nest/bird.h" -#include "lib/ip.h" - /** * DOC: IP addresses * @@ -18,6 +15,333 @@ * they must be manipulated using the following functions and macros. */ +#include + +#include "nest/bird.h" +#include "lib/ip.h" + + +int +ip6_compare(ip6_addr a, ip6_addr b) +{ + int i; + for (i=0; i<4; i++) + if (a.addr[i] > b.addr[i]) + return 1; + else if (a.addr[i] < b.addr[i]) + return -1; + return 0; +} + +ip6_addr +ip6_mkmask(uint n) +{ + ip6_addr a; + int i; + + for (i=0; i<4; i++) + { + if (!n) + a.addr[i] = 0; + else if (n >= 32) + { + a.addr[i] = ~0; + n -= 32; + } + else + { + a.addr[i] = u32_mkmask(n); + n = 0; + } + } + + return a; +} + +int +ip6_masklen(ip6_addr *a) +{ + int i, j, n; + + for (i=0, n=0; i<4; i++, n+=32) + if (a->addr[i] != ~0U) + { + j = u32_masklen(a->addr[i]); + if (j < 0) + return j; + n += j; + while (++i < 4) + if (a->addr[i]) + return -1; + break; + } + + return n; +} + +int +ip4_classify(ip4_addr ad) +{ + u32 a = _I(ad); + u32 b = a >> 24U; + + if (b && b <= 0xdf) + { + if (b == 0x7f) + return IADDR_HOST | SCOPE_HOST; + else if ((b == 0x0a) || + ((a & 0xffff0000) == 0xc0a80000) || + ((a & 0xfff00000) == 0xac100000)) + return IADDR_HOST | SCOPE_SITE; + else + return IADDR_HOST | SCOPE_UNIVERSE; + } + + if (b >= 0xe0 && b <= 0xef) + return IADDR_MULTICAST | SCOPE_UNIVERSE; + + if (a == 0xffffffff) + return IADDR_BROADCAST | SCOPE_LINK; + + return IADDR_INVALID; +} + +int +ip6_classify(ip6_addr *a) +{ + u32 x = a->addr[0]; + + if ((x & 0xe0000000) == 0x20000000) /* 2000::/3 Aggregatable Global Unicast Address */ + return IADDR_HOST | SCOPE_UNIVERSE; + if ((x & 0xffc00000) == 0xfe800000) /* fe80::/10 Link-Local Address */ + return IADDR_HOST | SCOPE_LINK; + if ((x & 0xffc00000) == 0xfec00000) /* fec0::/10 Site-Local Address */ + return IADDR_HOST | SCOPE_SITE; + if ((x & 0xfe000000) == 0xfc000000) /* fc00::/7 Unique Local Unicast Address (RFC 4193) */ + return IADDR_HOST | SCOPE_SITE; + if ((x & 0xff000000) == 0xff000000) /* ff00::/8 Multicast Address */ + { + uint scope = (x >> 16) & 0x0f; + switch (scope) + { + case 1: return IADDR_MULTICAST | SCOPE_HOST; + case 2: return IADDR_MULTICAST | SCOPE_LINK; + case 5: return IADDR_MULTICAST | SCOPE_SITE; + case 8: return IADDR_MULTICAST | SCOPE_ORGANIZATION; + case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE; + default: return IADDR_MULTICAST | SCOPE_UNDEFINED; + } + } + + if (!x && !a->addr[1]) + { + u32 a2 = a->addr[2]; + u32 a3 = a->addr[3]; + + if (a2 == 0 && a3 == 1) + return IADDR_HOST | SCOPE_HOST; /* Loopback address */ + if (a2 == 0) + return ip4_classify(_MI4(a3)); /* IPv4 compatible addresses */ + if (a2 == 0xffff) + return ip4_classify(_MI4(a3)); /* IPv4 mapped addresses */ + + return IADDR_INVALID; + } + + return IADDR_HOST | SCOPE_UNDEFINED; +} + + + +/* + * Conversion of IPv6 address to presentation format and vice versa. + * Heavily inspired by routines written by Paul Vixie for the BIND project + * and of course by RFC 2373. + */ + + +char * +ip4_ntop(ip4_addr a, char *b) +{ + u32 x = _I(a); + return b + bsprintf(b, "%d.%d.%d.%d", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); +} + + +char * +ip6_ntop(ip6_addr a, char *b) +{ + u16 words[8]; + int bestpos, bestlen, curpos, curlen, i; + + /* First of all, preprocess the address and find the longest run of zeros */ + bestlen = bestpos = curpos = curlen = 0; + for (i=0; i<8; i++) + { + u32 x = a.addr[i/2]; + words[i] = ((i%2) ? x : (x >> 16)) & 0xffff; + if (words[i]) + curlen = 0; + else + { + if (!curlen) + curpos = i; + curlen++; + if (curlen > bestlen) + { + bestpos = curpos; + bestlen = curlen; + } + } + } + + if (bestlen < 2) + bestpos = -1; + + /* Is it an encapsulated IPv4 address? */ + if (!bestpos && ((bestlen == 5 && a.addr[2] == 0xffff) || (bestlen == 6))) + { + u32 x = a.addr[3]; + b += bsprintf(b, "::%s%d.%d.%d.%d", + a.addr[2] ? "ffff:" : "", + (x >> 24) & 0xff, + (x >> 16) & 0xff, + (x >> 8) & 0xff, + x & 0xff); + return b; + } + + /* Normal IPv6 formatting, compress the largest sequence of zeros */ + for (i=0; i<8; i++) + { + if (i == bestpos) + { + i += bestlen - 1; + *b++ = ':'; + if (i == 7) + *b++ = ':'; + } + else + { + if (i) + *b++ = ':'; + b += bsprintf(b, "%x", words[i]); + } + } + *b = 0; + return b; +} + +int +ip4_pton(char *a, ip4_addr *o) +{ + int i; + unsigned long int l; + u32 ia = 0; + + i=4; + while (i--) + { + char *d, *c = strchr(a, '.'); + if (!c != !i) + return 0; + l = strtoul(a, &d, 10); + if (d != c && *d || l > 255) + return 0; + ia = (ia << 8) | l; + if (c) + c++; + a = c; + } + *o = ip4_from_u32(ia); + return 1; +} + +int +ip6_pton(char *a, ip6_addr *o) +{ + u16 words[8]; + int i, j, k, l, hfil; + char *start; + + if (a[0] == ':') /* Leading :: */ + { + if (a[1] != ':') + return 0; + a++; + } + + hfil = -1; + i = 0; + while (*a) + { + if (*a == ':') /* :: */ + { + if (hfil >= 0) + return 0; + + hfil = i; + a++; + continue; + } + + j = 0; + l = 0; + start = a; + for (;;) + { + if (*a >= '0' && *a <= '9') + k = *a++ - '0'; + else if (*a >= 'A' && *a <= 'F') + k = *a++ - 'A' + 10; + else if (*a >= 'a' && *a <= 'f') + k = *a++ - 'a' + 10; + else + break; + + j = (j << 4) + k; + if (j >= 0x10000 || ++l > 4) + return 0; + } + + if (*a == ':' && a[1]) + a++; + else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0)) + { /* Embedded IPv4 address */ + ip4_addr x; + if (!ip4_pton(start, &x)) + return 0; + words[i++] = _I(x) >> 16; + words[i++] = _I(x); + break; + } + else if (*a) + return 0; + + if (i >= 8) + return 0; + + words[i++] = j; + } + + /* Replace :: with an appropriate number of zeros */ + if (hfil >= 0) + { + j = 8 - i; + for (i=7; i-j >= hfil; i--) + words[i] = words[i-j]; + for (; i>=hfil; i--) + words[i] = 0; + } + + /* Convert the address to ip6_addr format */ + for (i=0; i<4; i++) + o->addr[i] = (words[2*i] << 16) | words[2*i+1]; + + return 1; +} + + /** * ip_scope_text - get textual representation of address scope * @scope: scope (%SCOPE_xxx) @@ -25,7 +349,7 @@ * Returns a pointer to a textual name of the scope given. */ char * -ip_scope_text(unsigned scope) +ip_scope_text(uint scope) { static char *scope_table[] = { "host", "link", "site", "org", "univ", "undef" }; @@ -35,6 +359,23 @@ ip_scope_text(unsigned scope) return scope_table[scope]; } +ip4_addr +ip4_class_mask(ip4_addr ad) +{ + u32 m, a = _I(ad); + + if (a < 0x80000000) + m = 0xff000000; + else if (a < 0xc0000000) + m = 0xffff0000; + else + m = 0xffffff00; + if (a & ~m) + m = 0xffffffff; + + return _MI4(m); +} + #if 0 /** * ipa_equal - compare two IP addresses for equality @@ -102,14 +443,14 @@ ip_addr ipa_not(ip_addr x) { DUMMY } ip_addr ipa_mkmask(int x) { DUMMY } /** - * ipa_mkmask - calculate netmask length + * ipa_masklen - calculate netmask length * @x: IP address * * This function checks whether @x represents a valid netmask and * returns the size of the associate network prefix or -1 for invalid * mask. */ -int ipa_mklen(ip_addr x) { DUMMY } +int ipa_masklen(ip_addr x) { DUMMY } /** * ipa_hash - hash IP addresses @@ -151,8 +492,8 @@ void ipa_ntoh(ip_addr x) { DUMMY } int ipa_classify(ip_addr x) { DUMMY } /** - * ipa_class_mask - guess netmask according to address class - * @x: IP address + * ip4_class_mask - guess netmask according to address class + * @x: IPv4 address * * This function (available in IPv4 version only) returns a * network mask according to the address class of @x. Although @@ -160,7 +501,7 @@ int ipa_classify(ip_addr x) { DUMMY } * routing protocols transferring no prefix lengths nor netmasks * and this function could be useful to them. */ -ip_addr ipa_class_mask(ip_addr x) { DUMMY } +ip4_addr ip4_class_mask(ip4_addr x) { DUMMY } /** * ipa_from_u32 - convert IPv4 address to an integer @@ -193,7 +534,7 @@ ip_addr ipa_to_u32(u32 x) { DUMMY } int ipa_compare(ip_addr x, ip_addr y) { DUMMY } /** - * ipa_build - build an IPv6 address from parts + * ipa_build6 - build an IPv6 address from parts * @a1: part #1 * @a2: part #2 * @a3: part #3 @@ -203,18 +544,7 @@ int ipa_compare(ip_addr x, ip_addr y) { DUMMY } * address. It's used for example when a protocol wants to bind its * socket to a hard-wired multicast address. */ -ip_addr ipa_build(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY } - -/** - * ipa_absolutize - convert link scope IPv6 address to universe scope - * @x: link scope IPv6 address - * @y: universe scope IPv6 prefix of the interface - * - * This function combines a link-scope IPv6 address @x with the universe - * scope prefix @x of the network assigned to an interface to get a - * universe scope form of @x. - */ -ip_addr ipa_absolutize(ip_addr x, ip_addr y) { DUMMY } +ip_addr ipa_build6(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY } /** * ip_ntop - convert IP address to textual representation diff --git a/lib/ip.h b/lib/ip.h index 023c1064..45e073d9 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -9,59 +9,474 @@ #ifndef _BIRD_IP_H_ #define _BIRD_IP_H_ -#ifndef IPV6 -#include "ipv4.h" +#include "lib/endian.h" +#include "lib/string.h" +#include "lib/bitops.h" +#include "lib/unaligned.h" + + +#define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5) +#define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6) + +#define IP6_ALL_NODES ipa_build6(0xFF020000, 0, 0, 1) +#define IP6_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 2) +#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5) +#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6) +#define IP6_RIP_ROUTERS ipa_build6(0xFF020000, 0, 0, 9) + +#define IP4_NONE _MI4(0) +#define IP6_NONE _MI6(0,0,0,0) + +#define IP4_MIN_MTU 576 +#define IP6_MIN_MTU 1280 + +#define IP_PREC_INTERNET_CONTROL 0xc0 + + +#ifdef IPV6 +#define MAX_PREFIX_LENGTH 128 +#define BITS_PER_IP_ADDRESS 128 +#define STD_ADDRESS_P_LENGTH 39 +#define SIZE_OF_IP_HEADER 40 #else -#include "ipv6.h" +#define MAX_PREFIX_LENGTH 32 +#define BITS_PER_IP_ADDRESS 32 +#define STD_ADDRESS_P_LENGTH 15 +#define SIZE_OF_IP_HEADER 24 +#endif + + +#ifdef DEBUGGING + +typedef struct ip4_addr { + u32 addr; +} ip4_addr; + +#define _MI4(x) ((struct ip4_addr) { x }) +#define _I(x) (x).addr + +#else + +typedef u32 ip4_addr; + +#define _MI4(x) (x) +#define _I(x) (x) + +#endif + + +typedef struct ip6_addr { + u32 addr[4]; +} ip6_addr; + +#define _MI6(a,b,c,d) ((struct ip6_addr) {{ a, b, c, d }}) +#define _I0(a) ((a).addr[0]) +#define _I1(a) ((a).addr[1]) +#define _I2(a) ((a).addr[2]) +#define _I3(a) ((a).addr[3]) + + +#ifdef IPV6 + +/* Structure ip_addr may contain both IPv4 and IPv6 addresses */ +typedef ip6_addr ip_addr; +#define IPA_NONE IP6_NONE + +#define ipa_from_ip4(x) _MI6(0,0,0xffff,_I(x)) +#define ipa_from_ip6(x) x +#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x)) + +#define ipa_to_ip4(x) _MI4(_I3(x)) +#define ipa_to_ip6(x) x +#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x)) + +#define ipa_is_ip4(a) ip6_is_v4mapped(a) + +#else + +/* Provisionary ip_addr definition same as ip4_addr */ +typedef ip4_addr ip_addr; +#define IPA_NONE IP4_NONE + +#define ipa_from_ip4(x) x +#define ipa_from_ip6(x) IPA_NONE +#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x)) + +#define ipa_to_ip4(x) x +#define ipa_to_ip6(x) IP6_NONE +#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x)) + +#define ipa_is_ip4(a) 1 + +#endif + + +/* + * Public constructors + */ + +#define ip4_from_u32(x) _MI4(x) +#define ip4_to_u32(x) _I(x) + +#define ip4_build(a,b,c,d) _MI4(((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +#define ip6_build(a,b,c,d) _MI6(a,b,c,d) + +#define ipa_build4(a,b,c,d) ipa_from_ip4(ip4_build(a,b,c,d)) +#define ipa_build6(a,b,c,d) ipa_from_ip6(ip6_build(a,b,c,d)) + + +/* + * Basic algebraic functions + */ + +static inline int ip4_equal(ip4_addr a, ip4_addr b) +{ return _I(a) == _I(b); } + +static inline int ip4_zero(ip4_addr a) +{ return _I(a) == 0; } + +static inline int ip4_nonzero(ip4_addr a) +{ return _I(a) != 0; } + +static inline ip4_addr ip4_and(ip4_addr a, ip4_addr b) +{ return _MI4(_I(a) & _I(b)); } + +static inline ip4_addr ip4_or(ip4_addr a, ip4_addr b) +{ return _MI4(_I(a) | _I(b)); } + +static inline ip4_addr ip4_xor(ip4_addr a, ip4_addr b) +{ return _MI4(_I(a) ^ _I(b)); } + +static inline ip4_addr ip4_not(ip4_addr a) +{ return _MI4(~_I(a)); } + + +static inline int ip6_equal(ip6_addr a, ip6_addr b) +{ return _I0(a) == _I0(b) && _I1(a) == _I1(b) && _I2(a) == _I2(b) && _I3(a) == _I3(b); } + +static inline int ip6_zero(ip6_addr a) +{ return !_I0(a) && !_I1(a) && !_I2(a) && !_I3(a); } + +static inline int ip6_nonzero(ip6_addr a) +{ return _I0(a) || _I1(a) || _I2(a) || _I3(a); } + +static inline ip6_addr ip6_and(ip6_addr a, ip6_addr b) +{ return _MI6(_I0(a) & _I0(b), _I1(a) & _I1(b), _I2(a) & _I2(b), _I3(a) & _I3(b)); } + +static inline ip6_addr ip6_or(ip6_addr a, ip6_addr b) +{ return _MI6(_I0(a) | _I0(b), _I1(a) | _I1(b), _I2(a) | _I2(b), _I3(a) | _I3(b)); } + +static inline ip6_addr ip6_xor(ip6_addr a, ip6_addr b) +{ return _MI6(_I0(a) ^ _I0(b), _I1(a) ^ _I1(b), _I2(a) ^ _I2(b), _I3(a) ^ _I3(b)); } + +static inline ip6_addr ip6_not(ip6_addr a) +{ return _MI6(~_I0(a), ~_I1(a), ~_I2(a), ~_I3(a)); } + + +#ifdef IPV6 +#define ipa_equal(x,y) ip6_equal(x,y) +#define ipa_zero(x) ip6_zero(x) +#define ipa_nonzero(x) ip6_nonzero(x) +#define ipa_and(x,y) ip6_and(x,y) +#define ipa_or(x,y) ip6_or(x,y) +#define ipa_xor(x,y) ip6_xor(x,y) +#define ipa_not(x) ip6_not(x) +#else +#define ipa_equal(x,y) ip4_equal(x,y) +#define ipa_zero(x) ip4_zero(x) +#define ipa_nonzero(x) ip4_nonzero(x) +#define ipa_and(x,y) ip4_and(x,y) +#define ipa_or(x,y) ip4_or(x,y) +#define ipa_xor(x,y) ip4_xor(x,y) +#define ipa_not(x) ip4_not(x) +#endif + + + +#ifdef IPV6 +/* + * A zero address is either a token for invalid/unused, or the prefix of default + * routes. These functions should be used in the second case, where both IPv4 + * and IPv6 zero addresses should be checked. + */ + +static inline int ipa_zero2(ip_addr a) +{ return !_I0(a) && !_I1(a) && ((_I2(a) == 0) || (_I2(a) == 0xffff)) && !_I3(a); } + +static inline int ipa_nonzero2(ip_addr a) +{ return _I0(a) || _I1(a) || ((_I2(a) != 0) && (_I2(a) != 0xffff)) || _I3(a); } + +#else +#define ipa_zero2(x) ip4_zero(x) +#define ipa_nonzero2(x) ip4_nonzero(x) +#endif + + +/* + * Hash and compare functions + */ + +static inline uint ip4_hash(ip4_addr a) +{ + /* Returns a 16-bit value */ + u32 x = _I(a); + x ^= x >> 16; + x ^= x << 10; + return x & 0xffff; +} + +static inline u32 ip4_hash32(ip4_addr a) +{ + /* Returns a 32-bit value, although low-order bits are not mixed */ + u32 x = _I(a); + x ^= x << 16; + x ^= x << 12; + return x; +} + +static inline uint ip6_hash(ip6_addr a) +{ + /* Returns a 16-bit hash key */ + u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a); + return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff; +} + +static inline u32 ip6_hash32(ip6_addr a) +{ + /* Returns a 32-bit hash key, although low-order bits are not mixed */ + u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a); + return x ^ (x << 16) ^ (x << 24); +} + +static inline int ip4_compare(ip4_addr a, ip4_addr b) +{ return (_I(a) > _I(b)) - (_I(a) < _I(b)); } + +int ip6_compare(ip6_addr a, ip6_addr b); + + +#ifdef IPV6 +#define ipa_hash(x) ip6_hash(x) +#define ipa_hash32(x) ip6_hash32(x) +#define ipa_compare(x,y) ip6_compare(x,y) +#else +#define ipa_hash(x) ip4_hash(x) +#define ipa_hash32(x) ip4_hash32(x) +#define ipa_compare(x,y) ip4_compare(x,y) #endif -#define ipa_zero(x) (!ipa_nonzero(x)) -#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l))))) -#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p)))) -#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2))))) /* - * ip_classify() returns either a negative number for invalid addresses - * or scope OR'ed together with address type. + * IP address classification */ +/* Address class */ #define IADDR_INVALID -1 #define IADDR_SCOPE_MASK 0xfff #define IADDR_HOST 0x1000 #define IADDR_BROADCAST 0x2000 #define IADDR_MULTICAST 0x4000 +/* Address scope */ +#define SCOPE_HOST 0 +#define SCOPE_LINK 1 +#define SCOPE_SITE 2 +#define SCOPE_ORGANIZATION 3 +#define SCOPE_UNIVERSE 4 +#define SCOPE_UNDEFINED 5 + +int ip4_classify(ip4_addr ad); +int ip6_classify(ip6_addr *a); + +static inline int ip6_is_link_local(ip6_addr a) +{ return (_I0(a) & 0xffc00000) == 0xfe800000; } + +static inline int ip6_is_v4mapped(ip6_addr a) +{ return _I0(a) == 0 && _I1(a) == 0 && _I2(a) == 0xffff; } + +#ifdef IPV6 +#define ipa_classify(x) ip6_classify(&(x)) +#define ipa_is_link_local(x) ip6_is_link_local(x) +#else +#define ipa_classify(x) ip4_classify(x) +#define ipa_is_link_local(x) 0 +#endif + +static inline int ipa_classify_net(ip_addr a) +{ return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); } + + /* - * Address scope + * Miscellaneous IP prefix manipulation */ -#define SCOPE_HOST 0 -#define SCOPE_LINK 1 -#define SCOPE_SITE 2 -#define SCOPE_ORGANIZATION 3 -#define SCOPE_UNIVERSE 4 -#define SCOPE_UNDEFINED 5 +static inline ip4_addr ip4_mkmask(uint n) +{ return _MI4(u32_mkmask(n)); } + +static inline int ip4_masklen(ip4_addr a) +{ return u32_masklen(_I(a)); } + +ip6_addr ip6_mkmask(uint n); +int ip6_masklen(ip6_addr *a); + +/* ipX_pxlen() requires that x != y */ +static inline uint ip4_pxlen(ip4_addr a, ip4_addr b) +{ return 31 - u32_log2(_I(a) ^ _I(b)); } + +static inline uint ip6_pxlen(ip6_addr a, ip6_addr b) +{ + int i = 0; + i += (a.addr[i] == b.addr[i]); + i += (a.addr[i] == b.addr[i]); + i += (a.addr[i] == b.addr[i]); + i += (a.addr[i] == b.addr[i]); + return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]); +} + +static inline u32 ip4_getbit(ip4_addr a, uint pos) +{ return _I(a) & (0x80000000 >> pos); } + +static inline u32 ip6_getbit(ip6_addr a, uint pos) +{ return a.addr[pos / 32] & (0x80000000 >> (pos % 32)); } + +static inline ip4_addr ip4_opposite_m1(ip4_addr a) +{ return _MI4(_I(a) ^ 1); } + +static inline ip4_addr ip4_opposite_m2(ip4_addr a) +{ return _MI4(_I(a) ^ 3); } + +static inline ip6_addr ip6_opposite_m1(ip6_addr a) +{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 1); } + +static inline ip6_addr ip6_opposite_m2(ip6_addr a) +{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 3); } + +ip4_addr ip4_class_mask(ip4_addr ad); + +#ifdef IPV6 +#define ipa_mkmask(x) ip6_mkmask(x) +#define ipa_masklen(x) ip6_masklen(&x) +#define ipa_pxlen(x,y) ip6_pxlen(x,y) +#define ipa_getbit(x,n) ip6_getbit(x,n) +#define ipa_opposite_m1(x) ip6_opposite_m1(x) +#define ipa_opposite_m2(x) ip6_opposite_m2(x) +#else +#define ipa_mkmask(x) ip4_mkmask(x) +#define ipa_masklen(x) ip4_masklen(x) +#define ipa_pxlen(x,y) ip4_pxlen(x,y) +#define ipa_getbit(x,n) ip4_getbit(x,n) +#define ipa_opposite_m1(x) ip4_opposite_m1(x) +#define ipa_opposite_m2(x) ip4_opposite_m2(x) +#endif -char *ip_scope_text(unsigned); /* - * Network prefixes + * Host/network order conversions */ -struct prefix { - ip_addr addr; - unsigned int len; -}; +static inline ip4_addr ip4_hton(ip4_addr a) +{ return _MI4(htonl(_I(a))); } + +static inline ip4_addr ip4_ntoh(ip4_addr a) +{ return _MI4(ntohl(_I(a))); } + +static inline ip6_addr ip6_hton(ip6_addr a) +{ return _MI6(htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a))); } + +static inline ip6_addr ip6_ntoh(ip6_addr a) +{ return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); } + +#ifdef IPV6 +#define ipa_hton(x) x = ip6_hton(x) +#define ipa_ntoh(x) x = ip6_ntoh(x) +#else +#define ipa_hton(x) x = ip4_hton(x) +#define ipa_ntoh(x) x = ip4_ntoh(x) +#endif + + +/* + * Unaligned data access (in network order) + */ + +static inline ip4_addr get_ip4(void *buf) +{ + return _MI4(get_u32(buf)); +} + +static inline ip6_addr get_ip6(void *buf) +{ + ip6_addr a; + memcpy(&a, buf, 16); + return ip6_ntoh(a); +} + +static inline void * put_ip4(void *buf, ip4_addr a) +{ + put_u32(buf, _I(a)); + return buf+4; +} + +static inline void * put_ip6(void *buf, ip6_addr a) +{ + a = ip6_hton(a); + memcpy(buf, &a, 16); + return buf+16; +} + +// XXXX these functions must be redesigned or removed +#ifdef IPV6 +#define get_ipa(x) get_ip6(x) +#define put_ipa(x,y) put_ip6(x,y) +#else +#define get_ipa(x) get_ip4(x) +#define put_ipa(x,y) put_ip4(x,y) +#endif + + +/* + * Binary/text form conversions + */ + +char *ip4_ntop(ip4_addr a, char *b); +char *ip6_ntop(ip6_addr a, char *b); + +static inline char * ip4_ntox(ip4_addr a, char *b) +{ return b + bsprintf(b, "%08x", _I(a)); } + +static inline char * ip6_ntox(ip6_addr a, char *b) +{ return b + bsprintf(b, "%08x.%08x.%08x.%08x", _I0(a), _I1(a), _I2(a), _I3(a)); } + +int ip4_pton(char *a, ip4_addr *o); +int ip6_pton(char *a, ip6_addr *o); + +// XXXX these functions must be redesigned or removed +#ifdef IPV6 +#define ipa_ntop(x,y) ip6_ntop(x,y) +#define ipa_ntox(x,y) ip6_ntox(x,y) +#define ipa_pton(x,y) ip6_pton(x,y) +#else +#define ipa_ntop(x,y) ip4_ntop(x,y) +#define ipa_ntox(x,y) ip4_ntox(x,y) +#define ipa_pton(x,y) ip4_pton(x,y) +#endif -static inline int ipa_classify_net(ip_addr a) -{ return ipa_zero(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); } /* - * Conversions between internal and string representation + * Miscellaneous */ -char *ip_ntop(ip_addr a, char *); -char *ip_ntox(ip_addr a, char *); -int ip_pton(char *a, ip_addr *o); +// XXXX review this + +#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l))))) +#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p)))) +#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2))))) + +char *ip_scope_text(unsigned); + +struct prefix { + ip_addr addr; + unsigned int len; +}; + #endif diff --git a/lib/ipv4.c b/lib/ipv4.c deleted file mode 100644 index 751351ca..00000000 --- a/lib/ipv4.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * BIRD Library -- IPv4 Address Manipulation Functions - * - * (c) 1998 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include - -#include "nest/bird.h" -#include "lib/ip.h" -#include "lib/string.h" - -int -ipv4_classify(u32 a) -{ - u32 b = a >> 24U; - - if (b && b <= 0xdf) - { - if (b == 0x7f) - return IADDR_HOST | SCOPE_HOST; - else if (b == 0x0a || - (a & 0xffff0000) == 0xc0a80000 || - (a & 0xfff00000) == 0xac100000) - return IADDR_HOST | SCOPE_SITE; - else - return IADDR_HOST | SCOPE_UNIVERSE; - } - if (b >= 0xe0 && b <= 0xef) - return IADDR_MULTICAST | SCOPE_UNIVERSE; - if (a == 0xffffffff) - return IADDR_BROADCAST | SCOPE_LINK; - return IADDR_INVALID; -} - -char * -ip_ntop(ip_addr a, char *b) -{ - u32 x = _I(a); - - return b + bsprintf(b, "%d.%d.%d.%d", - ((x >> 24) & 0xff), - ((x >> 16) & 0xff), - ((x >> 8) & 0xff), - (x & 0xff)); -} - -char * -ip_ntox(ip_addr a, char *b) -{ - return b + bsprintf(b, "%08x", _I(a)); -} - -u32 -ipv4_class_mask(u32 a) -{ - u32 m; - - if (a < 0x80000000) - m = 0xff000000; - else if (a < 0xc0000000) - m = 0xffff0000; - else - m = 0xffffff00; - while (a & ~m) - m |= m >> 1; - return m; -} - -int -ip_pton(char *a, ip_addr *o) -{ - int i; - unsigned long int l; - u32 ia = 0; - - i=4; - while (i--) - { - char *d, *c = strchr(a, '.'); - if (!c != !i) - return 0; - l = strtoul(a, &d, 10); - if (d != c && *d || l > 255) - return 0; - ia = (ia << 8) | l; - if (c) - c++; - a = c; - } - *o = ipa_from_u32(ia); - return 1; -} - -byte * -ipv4_skip_header(byte *pkt, int *len) -{ - int l = *len; - int q; - - if (l < 20 || (*pkt & 0xf0) != 0x40) - return NULL; - q = (*pkt & 0x0f) * 4; - if (q > l) - return NULL; - *len -= q; - return pkt + q; -} diff --git a/lib/ipv4.h b/lib/ipv4.h deleted file mode 100644 index 7fbdf2eb..00000000 --- a/lib/ipv4.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * BIRD -- IP Addresses et Cetera for IPv4 - * - * (c) 1998--1999 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#ifndef _BIRD_IPV4_H_ -#define _BIRD_IPV4_H_ - -#include "lib/endian.h" -#include "lib/bitops.h" -#include "lib/unaligned.h" - -#ifdef DEBUGGING - -/* - * Use the structural representation when you want to make sure - * nobody unauthorized attempts to handle ip_addr as number. - */ - -typedef struct ipv4_addr { - u32 addr; -} ip_addr; - -#define _I(x) (x).addr -#define _MI(x) ((struct ipv4_addr) { x }) - -#else - -typedef u32 ip_addr; - -#define _I(x) (x) -#define _MI(x) (x) - -#endif - -#define MAX_PREFIX_LENGTH 32 -#define BITS_PER_IP_ADDRESS 32 -#define STD_ADDRESS_P_LENGTH 15 -#define SIZE_OF_IP_HEADER 24 - -#define IPA_NONE (_MI(0)) - -#define ipa_equal(x,y) (_I(x) == _I(y)) -#define ipa_nonzero(x) _I(x) -#define ipa_and(x,y) _MI(_I(x) & _I(y)) -#define ipa_or(x,y) _MI(_I(x) | _I(y)) -#define ipa_xor(x,y) _MI(_I(x) ^ _I(y)) -#define ipa_not(x) _MI(~_I(x)) -#define ipa_mkmask(x) _MI(u32_mkmask(x)) -#define ipa_mklen(x) u32_masklen(_I(x)) -#define ipa_hash(x) ipv4_hash(_I(x)) -#define ipa_hash32(x) ipv4_hash32(_I(x)) -#define ipa_hton(x) x = _MI(htonl(_I(x))) -#define ipa_ntoh(x) x = _MI(ntohl(_I(x))) -#define ipa_classify(x) ipv4_classify(_I(x)) -#define ipa_has_link_scope(x) ipv4_has_link_scope(_I(x)) -#define ipa_opposite_m1(x) _MI(_I(x) ^ 1) -#define ipa_opposite_m2(x) _MI(_I(x) ^ 3) -#define ipa_class_mask(x) _MI(ipv4_class_mask(_I(x))) -#define ipa_from_u32(x) _MI(x) -#define ipa_to_u32(x) _I(x) -#define ipa_compare(x,y) ipv4_compare(_I(x),_I(y)) -/* ipa_pxlen() requires that x != y */ -#define ipa_pxlen(x, y) ipv4_pxlen(_I(x), _I(y)) -#define ipa_getbit(x, y) (_I(x) & (0x80000000 >> (y))) -#define ipa_put_addr(x, y) ipv4_put_addr(x, y) - -#define ip_skip_header(x, y) ipv4_skip_header(x, y) - -int ipv4_classify(u32); -u32 ipv4_class_mask(u32); -byte *ipv4_skip_header(byte *, int *); - -static inline int ipv4_has_link_scope(u32 a UNUSED) -{ - return 0; -} - -static inline unsigned ipv4_hash(u32 a) -{ - /* Returns a 16-bit value */ - a ^= a >> 16; - a ^= a << 10; - return a & 0xffff; -} - -static inline u32 ipv4_hash32(u32 a) -{ - /* Returns a 32-bit value, although low-order bits are not mixed */ - a ^= a << 16; - a ^= a << 12; - return a; -} - -static inline int ipv4_compare(u32 x, u32 y) -{ - return (x > y) - (x < y); -} - -static inline u32 ipv4_pxlen(u32 a, u32 b) -{ - return 31 - u32_log2(a ^ b); -} - -static inline byte * ipv4_put_addr(byte *buf, ip_addr a) -{ - put_u32(buf, _I(a)); - return buf+4; -} - -#define IP_PREC_INTERNET_CONTROL 0xc0 - -#endif diff --git a/lib/ipv6.c b/lib/ipv6.c deleted file mode 100644 index 623f6328..00000000 --- a/lib/ipv6.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * BIRD Library -- IPv6 Address Manipulation Functions - * - * (c) 1999 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include - -#include "nest/bird.h" -#include "lib/ip.h" -#include "lib/bitops.h" -#include "lib/endian.h" -#include "lib/string.h" - -/* - * See RFC 2373 for explanation of IPv6 addressing issues. - */ - -ip_addr -ipv6_mkmask(unsigned n) -{ - ip_addr a; - int i; - - for(i=0; i<4; i++) - { - if (!n) - a.addr[i] = 0; - else if (n >= 32) - { - a.addr[i] = ~0; - n -= 32; - } - else - { - a.addr[i] = u32_mkmask(n); - n = 0; - } - } - return a; -} - -unsigned -ipv6_mklen(ip_addr *a) -{ - int i, j, n; - - for(i=0, n=0; i<4; i++, n+=32) - if (a->addr[i] != ~0U) - { - j = u32_masklen(a->addr[i]); - if (j < 0) - return j; - n += j; - while (++i < 4) - if (a->addr[i]) - return -1; - break; - } - return n; -} - -int -ipv6_classify(ip_addr *a) -{ - u32 x = a->addr[0]; - - if ((x & 0xe0000000) == 0x20000000) /* 2000::/3 Aggregatable Global Unicast Address */ - return IADDR_HOST | SCOPE_UNIVERSE; - if ((x & 0xffc00000) == 0xfe800000) /* fe80::/10 Link-Local Address */ - return IADDR_HOST | SCOPE_LINK; - if ((x & 0xffc00000) == 0xfec00000) /* fec0::/10 Site-Local Address */ - return IADDR_HOST | SCOPE_SITE; - if ((x & 0xfe000000) == 0xfc000000) /* fc00::/7 Unique Local Unicast Address (RFC 4193) */ - return IADDR_HOST | SCOPE_SITE; - if ((x & 0xff000000) == 0xff000000) /* ff00::/8 Multicast Address */ - { - unsigned int scope = (x >> 16) & 0x0f; - switch (scope) - { - case 1: return IADDR_MULTICAST | SCOPE_HOST; - case 2: return IADDR_MULTICAST | SCOPE_LINK; - case 5: return IADDR_MULTICAST | SCOPE_SITE; - case 8: return IADDR_MULTICAST | SCOPE_ORGANIZATION; - case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE; - default: return IADDR_MULTICAST | SCOPE_UNDEFINED; - } - } - if (!x && !a->addr[1] && !a->addr[2]) - { - u32 y = a->addr[3]; - if (y == 1) - return IADDR_HOST | SCOPE_HOST; /* Loopback address */ - /* IPv4 compatible addresses */ - if (y >= 0x7f000000 && y < 0x80000000) - return IADDR_HOST | SCOPE_HOST; - if ((y & 0xff000000) == 0x0a000000 || - (y & 0xffff0000) == 0xc0a80000 || - (y & 0xfff00000) == 0xac100000) - return IADDR_HOST | SCOPE_SITE; - if (y >= 0x01000000 && y < 0xe0000000) - return IADDR_HOST | SCOPE_UNIVERSE; - } - return IADDR_HOST | SCOPE_UNDEFINED; -} - -void -ipv6_hton(ip_addr *a) -{ - int i; - - for(i=0; i<4; i++) - a->addr[i] = htonl(a->addr[i]); -} - -void -ipv6_ntoh(ip_addr *a) -{ - int i; - - for(i=0; i<4; i++) - a->addr[i] = ntohl(a->addr[i]); -} - -int -ipv6_compare(ip_addr X, ip_addr Y) -{ - int i; - ip_addr *x = &X; - ip_addr *y = &Y; - - for(i=0; i<4; i++) - if (x->addr[i] > y->addr[i]) - return 1; - else if (x->addr[i] < y->addr[i]) - return -1; - return 0; -} - -/* - * Conversion of IPv6 address to presentation format and vice versa. - * Heavily inspired by routines written by Paul Vixie for the BIND project - * and of course by RFC 2373. - */ - -char * -ip_ntop(ip_addr a, char *b) -{ - u16 words[8]; - int bestpos, bestlen, curpos, curlen, i; - - /* First of all, preprocess the address and find the longest run of zeros */ - bestlen = bestpos = curpos = curlen = 0; - for(i=0; i<8; i++) - { - u32 x = a.addr[i/2]; - words[i] = ((i%2) ? x : (x >> 16)) & 0xffff; - if (words[i]) - curlen = 0; - else - { - if (!curlen) - curpos = i; - curlen++; - if (curlen > bestlen) - { - bestpos = curpos; - bestlen = curlen; - } - } - } - if (bestlen < 2) - bestpos = -1; - - /* Is it an encapsulated IPv4 address? */ - if (!bestpos && - (bestlen == 5 && a.addr[2] == 0xffff || - bestlen == 6)) - { - u32 x = a.addr[3]; - b += bsprintf(b, "::%s%d.%d.%d.%d", - a.addr[2] ? "ffff:" : "", - ((x >> 24) & 0xff), - ((x >> 16) & 0xff), - ((x >> 8) & 0xff), - (x & 0xff)); - return b; - } - - /* Normal IPv6 formatting, compress the largest sequence of zeros */ - for(i=0; i<8; i++) - { - if (i == bestpos) - { - i += bestlen - 1; - *b++ = ':'; - if (i == 7) - *b++ = ':'; - } - else - { - if (i) - *b++ = ':'; - b += bsprintf(b, "%x", words[i]); - } - } - *b = 0; - return b; -} - -char * -ip_ntox(ip_addr a, char *b) -{ - int i; - - for(i=0; i<4; i++) - { - if (i) - *b++ = '.'; - b += bsprintf(b, "%08x", a.addr[i]); - } - return b; -} - -int -ipv4_pton_u32(char *a, u32 *o) -{ - int i; - unsigned long int l; - u32 ia = 0; - - i=4; - while (i--) - { - char *d, *c = strchr(a, '.'); - if (!c != !i) - return 0; - l = strtoul(a, &d, 10); - if (d != c && *d || l > 255) - return 0; - ia = (ia << 8) | l; - if (c) - c++; - a = c; - } - *o = ia; - return 1; -} - -int -ip_pton(char *a, ip_addr *o) -{ - u16 words[8]; - int i, j, k, l, hfil; - char *start; - - if (a[0] == ':') /* Leading :: */ - { - if (a[1] != ':') - return 0; - a++; - } - hfil = -1; - i = 0; - while (*a) - { - if (*a == ':') /* :: */ - { - if (hfil >= 0) - return 0; - hfil = i; - a++; - continue; - } - j = 0; - l = 0; - start = a; - for(;;) - { - if (*a >= '0' && *a <= '9') - k = *a++ - '0'; - else if (*a >= 'A' && *a <= 'F') - k = *a++ - 'A' + 10; - else if (*a >= 'a' && *a <= 'f') - k = *a++ - 'a' + 10; - else - break; - j = (j << 4) + k; - if (j >= 0x10000 || ++l > 4) - return 0; - } - if (*a == ':' && a[1]) - a++; - else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0)) - { /* Embedded IPv4 address */ - u32 x; - if (!ipv4_pton_u32(start, &x)) - return 0; - words[i++] = x >> 16; - words[i++] = x; - break; - } - else if (*a) - return 0; - if (i >= 8) - return 0; - words[i++] = j; - } - - /* Replace :: with an appropriate number of zeros */ - if (hfil >= 0) - { - j = 8 - i; - for(i=7; i-j >= hfil; i--) - words[i] = words[i-j]; - for(; i>=hfil; i--) - words[i] = 0; - } - - /* Convert the address to ip_addr format */ - for(i=0; i<4; i++) - o->addr[i] = (words[2*i] << 16) | words[2*i+1]; - return 1; -} - -void ipv6_absolutize(ip_addr *a, ip_addr *ifa) -{ - if ((a->addr[0] & 0xffc00000) == 0xfe800000 && /* a is link-scope */ - ((ifa->addr[0] & 0xe0000000) == 0x20000000 | /* ifa is AGU ... */ - (ifa->addr[0] & 0xffc00000) == 0xfec00000)) /* ... or site-scope */ - { - a->addr[0] = ifa->addr[0]; /* Copy the prefix, leave interface ID */ - a->addr[1] = ifa->addr[1]; - } -} - -#ifdef TEST - -#include "bitops.c" - -static void test(char *x) -{ - ip_addr a; - char c[STD_ADDRESS_P_LENGTH+1]; - - printf("%-40s ", x); - if (!ip_pton(x, &a)) - { - puts("BAD"); - return; - } - ip_ntop(a, c); - printf("%-40s %04x\n", c, ipv6_classify(&a)); -} - -int main(void) -{ - puts("Positive tests:"); - test("1:2:3:4:5:6:7:8"); - test("dead:beef:DEAD:BEEF::f00d"); - test("::"); - test("::1"); - test("1::"); - test("::1.234.5.6"); - test("::ffff:1.234.5.6"); - test("::fffe:1.234.5.6"); - test("1:2:3:4:5:6:7::8"); - test("2080::8:800:200c:417a"); - test("ff01::101"); - - puts("Negative tests:"); - test(":::"); - test("1:2:3:4:5:6:7:8:"); - test("1::2::3"); - test("::12345"); - test("::1.2.3.4:5"); - test(":1:2:3:4:5:6:7:8"); - test("g:1:2:3:4:5:6:7"); - return 0; -} - -#endif diff --git a/lib/ipv6.h b/lib/ipv6.h deleted file mode 100644 index b935a6ef..00000000 --- a/lib/ipv6.h +++ /dev/null @@ -1,141 +0,0 @@ - -/* - * BIRD -- IP Addresses et Cetera for IPv6 - * - * (c) 1999--2000 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#ifndef _BIRD_IPV6_H_ -#define _BIRD_IPV6_H_ - -#include -#include -#include "lib/string.h" -#include "lib/bitops.h" -#include "lib/unaligned.h" - -typedef struct ipv6_addr { - u32 addr[4]; -} ip_addr; - -#define _MI(a,b,c,d) ((struct ipv6_addr) {{ a, b, c, d }}) -#define _I0(a) ((a).addr[0]) -#define _I1(a) ((a).addr[1]) -#define _I2(a) ((a).addr[2]) -#define _I3(a) ((a).addr[3]) - -#define MAX_PREFIX_LENGTH 128 -#define BITS_PER_IP_ADDRESS 128 -#define STD_ADDRESS_P_LENGTH 39 -#define SIZE_OF_IP_HEADER 40 - -#define IPA_NONE _MI(0,0,0,0) - -#define ipa_equal(x,y) ({ ip_addr _a=(x), _b=(y); \ - _I0(_a) == _I0(_b) && \ - _I1(_a) == _I1(_b) && \ - _I2(_a) == _I2(_b) && \ - _I3(_a) == _I3(_b); }) -#define ipa_nonzero(x) ({ ip_addr _a=(x); (_I0(_a) || _I1(_a) || _I2(_a) || _I3(_a)); }) -#define ipa_and(x,y) ({ ip_addr _a=(x), _b=(y); \ - _MI(_I0(_a) & _I0(_b), \ - _I1(_a) & _I1(_b), \ - _I2(_a) & _I2(_b), \ - _I3(_a) & _I3(_b)); }) -#define ipa_or(x,y) ({ ip_addr _a=(x), _b=(y); \ - _MI(_I0(_a) | _I0(_b), \ - _I1(_a) | _I1(_b), \ - _I2(_a) | _I2(_b), \ - _I3(_a) | _I3(_b)); }) -#define ipa_xor(x,y) ({ ip_addr _a=(x), _b=(y); \ - _MI(_I0(_a) ^ _I0(_b), \ - _I1(_a) ^ _I1(_b), \ - _I2(_a) ^ _I2(_b), \ - _I3(_a) ^ _I3(_b)); }) -#define ipa_not(x) ({ ip_addr _a=(x); _MI(~_I0(_a),~_I1(_a),~_I2(_a),~_I3(_a)); }) -#define ipa_mkmask(x) ipv6_mkmask(x) -#define ipa_mklen(x) ipv6_mklen(&(x)) -#define ipa_hash(x) ipv6_hash(&(x)) -#define ipa_hash32(x) ipv6_hash32(&(x)) -#define ipa_hton(x) ipv6_hton(&(x)) -#define ipa_ntoh(x) ipv6_ntoh(&(x)) -#define ipa_classify(x) ipv6_classify(&(x)) -#define ipa_has_link_scope(x) ipv6_has_link_scope(&(x)) -#define ipa_opposite_m1(x) ({ ip_addr _a=(x); _MI(_I0(_a),_I1(_a),_I2(_a),_I3(_a) ^ 1); }) -#define ipa_opposite_m2(x) ({ ip_addr _a=(x); _MI(_I0(_a),_I1(_a),_I2(_a),_I3(_a) ^ 3); }) -/* ipa_class_mask don't make sense with IPv6 */ -/* ipa_from_u32 and ipa_to_u32 replaced by ipa_build */ -#define ipa_build(a,b,c,d) _MI(a,b,c,d) -#define ipa_compare(x,y) ipv6_compare(x,y) -/* ipa_pxlen() requires that x != y */ -#define ipa_pxlen(x, y) ipv6_pxlen(x, y) -#define ipa_getbit(x, y) ipv6_getbit(x, y) -#define ipa_put_addr(x, y) ipv6_put_addr(x, y) -#define ipa_absolutize(x,y) ipv6_absolutize(x,y) - -/* In IPv6, SOCK_RAW does not return packet header */ -#define ip_skip_header(x, y) x - -ip_addr ipv6_mkmask(unsigned); -unsigned ipv6_mklen(ip_addr *); -int ipv6_classify(ip_addr *); -void ipv6_hton(ip_addr *); -void ipv6_ntoh(ip_addr *); -int ipv6_compare(ip_addr, ip_addr); -int ipv4_pton_u32(char *, u32 *); -void ipv6_absolutize(ip_addr *, ip_addr *); - -static inline int ipv6_has_link_scope(ip_addr *a) -{ - return ((a->addr[0] & 0xffc00000) == 0xfe800000); -} - -/* - * This hash function looks well, but once IPv6 enters - * mainstream use, we need to check that it has good - * distribution properties on real routing tables. - */ - -static inline unsigned ipv6_hash(ip_addr *a) -{ - /* Returns a 16-bit hash key */ - u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a); - return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff; -} - -static inline u32 ipv6_hash32(ip_addr *a) -{ - /* Returns a 32-bit hash key, although low-order bits are not ixed */ - u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a); - return x ^ (x << 16) ^ (x << 24); -} - -static inline u32 ipv6_getbit(ip_addr a, u32 y) -{ - return a.addr[y / 32] & (0x80000000 >> (y % 32)); -} - -static inline u32 ipv6_pxlen(ip_addr a, ip_addr b) -{ - int i = 0; - i+= (a.addr[i] == b.addr[i]); - i+= (a.addr[i] == b.addr[i]); - i+= (a.addr[i] == b.addr[i]); - i+= (a.addr[i] == b.addr[i]); - return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]); -} - -static inline byte * ipv6_put_addr(byte *buf, ip_addr a) -{ - put_u32(buf+0, _I0(a)); - put_u32(buf+4, _I1(a)); - put_u32(buf+8, _I2(a)); - put_u32(buf+12, _I3(a)); - return buf+16; -} - -#define IP_PREC_INTERNET_CONTROL 0xc0 - -#endif diff --git a/lib/printf.c b/lib/printf.c index ebecc140..3eb988fa 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -283,9 +283,9 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args) /* IP address */ case 'I': if (flags & SPECIAL) - ip_ntox(va_arg(args, ip_addr), ipbuf); + ipa_ntox(va_arg(args, ip_addr), ipbuf); else { - ip_ntop(va_arg(args, ip_addr), ipbuf); + ipa_ntop(va_arg(args, ip_addr), ipbuf); if (field_width == 1) field_width = STD_ADDRESS_P_LENGTH; } diff --git a/lib/socket.h b/lib/socket.h index f1fffa94..a5b85aa2 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -91,6 +91,8 @@ int sk_set_ipv6_checksum(sock *s, int offset); int sk_set_icmp6_filter(sock *s, int p1, int p2); void sk_log_error(sock *s, const char *p); +byte * sk_rx_buffer(sock *s, int *len); /* Temporary */ + extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */ diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 1d37bfd7..a091ed1e 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -991,7 +991,7 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p if (p->cf->next_hop_self || rta->dest != RTD_ROUTER || ipa_equal(rta->gw, IPA_NONE) || - ipa_has_link_scope(rta->gw) || + ipa_is_link_local(rta->gw) || (!p->is_internal && !p->cf->next_hop_keep && (!p->neigh || (rta->iface != p->neigh->iface)))) set_next_hop(z, p->source_addr); diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index e2339112..27825d7f 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -689,7 +689,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c s->password = p->cf->password; s->tx_hook = bgp_connected; BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J", s->daddr, p->cf->iface, - s->saddr, ipa_has_link_scope(s->saddr) ? s->iface : NULL); + s->saddr, ipa_is_link_local(s->saddr) ? s->iface : NULL); bgp_setup_conn(p, conn); bgp_setup_sk(conn, s); bgp_conn_set_state(conn, BS_CONNECT); @@ -735,7 +735,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) { struct bgp_proto *p = (struct bgp_proto *) pc->proto; if (ipa_equal(p->cf->remote_ip, sk->daddr) && - (!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface))) + (!ipa_is_link_local(sk->daddr) || (p->cf->iface == sk->iface))) { /* We are in proper state and there is no other incoming connection */ int acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) && @@ -750,7 +750,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) } BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s", - sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, + sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL, sk->dport, acc ? "accepted" : "rejected"); if (!acc) @@ -779,7 +779,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) } log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)", - sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport); + sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL, sk->dport); reject: rfree(sk); return 0; @@ -1169,8 +1169,8 @@ bgp_check_config(struct bgp_config *c) if (c->multihop && (c->gw_mode == GW_DIRECT)) cf_error("Multihop BGP cannot use direct gateway mode"); - if (c->multihop && (ipa_has_link_scope(c->remote_ip) || - ipa_has_link_scope(c->source_addr))) + if (c->multihop && (ipa_is_link_local(c->remote_ip) || + ipa_is_link_local(c->source_addr))) cf_error("Multihop BGP cannot be used with link-local addresses"); if (c->multihop && c->bfd && ipa_zero(c->source_addr)) diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 8e0b2412..c8345530 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -63,7 +63,7 @@ bgp_proto: | bgp_proto NEIGHBOR ipa ipa_scope ipa_port AS expr ';' { if (ipa_nonzero(BGP_CFG->remote_ip)) cf_error("Only one neighbor per BGP instance is allowed"); - if (!ipa_has_link_scope($3) != !$4) + if (!ipa_is_link_local($3) != !$4) cf_error("Link-local address and interface scope must be used together"); BGP_CFG->remote_ip = $3; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 0b9de8c1..69646c7d 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -69,8 +69,8 @@ mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4) put_u16(buf+0, (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0); put_u16(buf+2, BGP_AF); buf+=4; - buf = ipa_put_addr(buf, conn->sk ? conn->sk->daddr : IPA_NONE); - buf = ipa_put_addr(buf, conn->sk ? conn->sk->saddr : IPA_NONE); + buf = put_ipa(buf, conn->sk ? conn->sk->daddr : IPA_NONE); + buf = put_ipa(buf, conn->sk ? conn->sk->saddr : IPA_NONE); return buf; } @@ -522,7 +522,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) *tmp++ = BGP_AF_IPV6; *tmp++ = 1; - if (ipa_has_link_scope(ip)) + if (ipa_is_link_local(ip)) ip = IPA_NONE; if (ipa_nonzero(ip_ll)) @@ -1034,7 +1034,7 @@ bgp_set_next_hop(struct bgp_proto *p, rta *a) int second = (nh->u.ptr->length == NEXT_HOP_LENGTH) && ipa_nonzero(nexthop[1]); /* First address should not be link-local, but may be zero in direct mode */ - if (ipa_has_link_scope(*nexthop)) + if (ipa_is_link_local(*nexthop)) *nexthop = IPA_NONE; #else int second = 0; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 6df5df08..e535287c 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -37,36 +37,9 @@ #endif -#define IP4_MIN_MTU 576 -#define IP6_MIN_MTU 1280 - -#define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5) -#define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6) - -#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5) -#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6) - #ifdef IPV6 -#define ip4_addr u32 -#define ip6_addr ip_addr -#define _MI6(x1,x2,x3,x4) _MI(x1, x2, x3, x4) -#define ipa_is_link_local(x) ipa_has_link_scope(x) -#define ipa_from_u32(x) _MI6(0,0,0xffff,x) -#define ipa_to_u32(x) _I3(x) -#define ipa_build4(a,b,c,d) IPA_NONE -#define ipa_build6(a,b,c,d) _MI6(a,b,c,d) #define OSPF_IS_V2 0 #else -#define ip4_addr u32 -#define ip6_addr ip_addr -#define _I0(X) 0 -#define _I1(X) 0 -#define _I2(X) 0 -#define _I3(X) 0 -#define _MI6(x1,x2,x3,x4) IPA_NONE -#define ipa_is_link_local(x) 0 -#define ipa_build4(a,b,c,d) _MI(((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) -#define ipa_build6(a,b,c,d) IPA_NONE #define OSPF_IS_V2 1 #endif @@ -744,10 +717,12 @@ lsa_net_count(struct ospf_lsa_header *lsa) #define ipa_from_rid(x) ipa_from_u32(x) #define ipa_to_rid(x) ipa_to_u32(x) - #define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4) #define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32) +/* FIXME: these four functions should be significantly redesigned w.r.t. integration, + also should be named as ospf3_* instead of *_ipv6_* */ + static inline u32 * lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest) { @@ -787,6 +762,7 @@ lsa_get_ipv6_addr(u32 *buf, ip_addr *addr) static inline u32 * put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh) { +#ifdef IPV6 *buf++ = ((pxlen << 24) | (pxopts << 16) | lh); if (pxlen > 0) @@ -797,6 +773,7 @@ put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh) *buf++ = _I2(addr); if (pxlen > 96) *buf++ = _I3(addr); +#endif return buf; } diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 2814712d..a545c7fd 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -265,7 +265,8 @@ ospf_rx_hook(sock *sk, int len) } /* Second, we check packet length, checksum, and the protocol version */ - struct ospf_packet *pkt = (struct ospf_packet *) ip_skip_header(sk->rbuf, &len); + struct ospf_packet *pkt = (void *) sk_rx_buffer(sk, &len); + if (pkt == NULL) DROP("bad IP header", len); diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 08f90b49..b616c0d1 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -1822,10 +1822,10 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, struct ospf_lsa_link *llsa = lhe->lsa_body; - if (ipa_zero(llsa->lladdr)) + if (ip6_zero(llsa->lladdr)) return NULL; - return new_nexthop(p, llsa->lladdr, pn->iface, pn->weight); + return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight); } } diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 15ba013a..42bf9c45 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -1319,7 +1319,7 @@ prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa) ASSERT(p->lsab_used == 0); ll = lsab_allocz(p, sizeof(struct ospf_lsa_link)); ll->options = ifa->oa->options | (ifa->priority << 24); - ll->lladdr = ifa->addr->ip; + ll->lladdr = ipa_to_ip6(ifa->addr->ip); ll = NULL; /* buffer might be reallocated later */ struct ifa *a; diff --git a/proto/radv/packets.c b/proto/radv/packets.c index ef869722..3862af8d 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -343,7 +343,7 @@ radv_send_ra(struct radv_iface *ifa, int shutdown) } RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); - sk_send_to(ifa->sk, ifa->plen, AllNodes, 0); + sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0); } @@ -432,7 +432,7 @@ radv_sk_open(struct radv_iface *ifa) if (sk_setup_multicast(sk) < 0) goto err; - if (sk_join_group(sk, AllRouters) < 0) + if (sk_join_group(sk, IP6_ALL_ROUTERS) < 0) goto err; ifa->sk = sk; diff --git a/proto/radv/radv.h b/proto/radv/radv.h index bb80d65f..48ba9c1a 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -26,9 +26,6 @@ #define ICMPV6_PROTO 58 -#define AllNodes _MI(0xFF020000, 0, 0, 1) /* FF02::1 */ -#define AllRouters _MI(0xFF020000, 0, 0, 2) /* FF02::2 */ - #define ICMPV6_RS 133 #define ICMPV6_RA 134 diff --git a/proto/rip/rip.c b/proto/rip/rip.c index bc9ffc5f..a0c28e72 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -305,7 +305,7 @@ advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme, struct A.flags = 0; #ifndef IPV6 A.gw = ipa_nonzero(b->nexthop) ? b->nexthop : whotoldme; - pxlen = ipa_mklen(b->netmask); + pxlen = ipa_masklen(b->netmask); #else /* FIXME: next hop is in other packet for v6 */ A.gw = whotoldme; @@ -365,7 +365,7 @@ process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme, stru #ifndef IPV6 metric = ntohl( block->metric ); - pxlen = ipa_mklen(block->netmask); + pxlen = ipa_masklen(block->netmask); #else metric = block->metric; pxlen = block->pxlen; @@ -447,7 +447,7 @@ rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr ipa_ntoh( block->netmask ); ipa_ntoh( block->nexthop ); if (packet->heading.version == RIP_V1) /* FIXME (nonurgent): switch to disable this? */ - block->netmask = ipa_class_mask(block->network); + block->netmask = ip4_class_mask(ipa_to_ip4(block->network)); #endif process_block( p, block, whotoldme, iface ); } @@ -721,7 +721,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_ #ifndef IPV6 rif->sock->daddr = ipa_from_u32(0xe0000009); #else - rif->sock->daddr = ipa_build(0xff020000, 0, 0, 9); + rif->sock->daddr = IP6_RIP_ROUTERS; #endif } else { rif->sock->daddr = new->addr->brd; @@ -812,7 +812,7 @@ rip_if_notify(struct proto *p, unsigned c, struct iface *iface) #ifndef IPV6 lock->addr = ipa_from_u32(0xe0000009); #else - ip_pton("FF02::9", &lock->addr); + lock->addr = IP6_RIP_ROUTERS; #endif else lock->addr = iface->addr->brd; diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 621f7309..0e65c51c 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -382,7 +382,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) SKIP("strange class/scope\n"); - int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_mklen(imask); + int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_masklen(imask); if (pxlen < 0) { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; } @@ -653,7 +653,7 @@ krt_read_addr(struct ks_msg *msg, int scan) ibrd = ipa_from_sa(&brd); - if ((masklen = ipa_mklen(imask)) < 0) + if ((masklen = ipa_masklen(imask)) < 0) { log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name); return; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 164038ec..04f0fe50 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -764,6 +764,29 @@ sk_set_tos6(sock *s, int tos) return 0; } +static inline byte * +sk_skip_ip_header(byte *pkt, int *len) +{ + if ((*len < 20) || ((*pkt & 0xf0) != 0x40)) + return NULL; + + int hlen = (*pkt & 0x0f) * 4; + if ((hlen < 20) || (hlen > *len)) + return NULL; + + *len -= hlen; + return pkt + hlen; +} + +byte * +sk_rx_buffer(sock *s, int *len) +{ + if (sk_is_ipv4(s) && (s->type == SK_IP)) + return sk_skip_ip_header(s->rbuf, len); + else + return s->rbuf; +} + /* * Public socket functions diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 518713bc..3cee96b4 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -47,19 +47,9 @@ typedef struct sockaddr_bird { #ifdef IPV6 #define BIRD_AF AF_INET6 -#define _MI6(x1,x2,x3,x4) _MI(x1, x2, x3, x4) -#define ipa_is_link_local(x) ipa_has_link_scope(x) #define ipa_from_sa(x) ipa_from_sa6(x) -#define ipa_from_u32(x) _MI6(0,0,0xffff,x) -#define ipa_to_u32(x) _I3(x) #else #define BIRD_AF AF_INET -#define _I0(X) 0 -#define _I1(X) 0 -#define _I2(X) 0 -#define _I3(X) 0 -#define _MI6(x1,x2,x3,x4) IPA_NONE -#define ipa_is_link_local(x) 0 #define ipa_from_sa(x) ipa_from_sa4(x) #endif @@ -75,7 +65,7 @@ static inline ip_addr ipa_from_in4(struct in_addr a) { return ipa_from_u32(ntohl(a.s_addr)); } static inline ip_addr ipa_from_in6(struct in6_addr a) -{ return _MI6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); } +{ return ipa_build6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); } static inline ip_addr ipa_from_sa4(sockaddr *sa) { return ipa_from_in4(((struct sockaddr_in *) sa)->sin_addr); } @@ -86,8 +76,14 @@ static inline ip_addr ipa_from_sa6(sockaddr *sa) static inline struct in_addr ipa_to_in4(ip_addr a) { return (struct in_addr) { htonl(ipa_to_u32(a)) }; } +#ifdef IPV6 static inline struct in6_addr ipa_to_in6(ip_addr a) { return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; } +#else +/* Temporary dummy */ +static inline struct in6_addr ipa_to_in6(ip_addr a) +{ return (struct in6_addr) { .s6_addr32 = { 0, 0, 0, 0 } }; } +#endif void sockaddr_fill(sockaddr *sa, int af, ip_addr a, struct iface *ifa, uint port); int sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *port); -- cgit v1.2.3