static struct area_net_config *this_pref;
static struct ospf_stubnet_config *this_stubnet;
-#ifdef OSPFv2
+static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; }
+static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; }
+
static void
ospf_iface_finish(void)
{
if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
log(L_WARN "Password option without authentication option does not make sense");
}
-#endif
-
-#ifdef OSPFv3
-static void
-ospf_iface_finish(void)
-{
- struct ospf_iface_patt *ip = OSPF_PATT;
-
- if (ip->deadint == 0)
- ip->deadint = ip->deadc * ip->helloint;
-
- if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL))
- cf_error("Authentication not supported in OSPFv3");
-}
-#endif
static void
ospf_area_finish(void)
}
static inline void
-check_defcost(int cost)
+ospf_check_defcost(int cost)
{
if ((cost <= 0) || (cost >= LSINFINITY))
cf_error("Default cost must be in range 1-%d", LSINFINITY-1);
}
static inline void
-set_instance_id(unsigned id)
+ospf_check_auth(void)
{
-#ifdef OSPFv3
- OSPF_PATT->instance_id = id;
-#else
- cf_error("Instance ID requires OSPFv3");
-#endif
+ if (ospf_cfg_is_v3())
+ cf_error("Authentication not supported in OSPFv3");
}
+
CF_DECLS
-CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
+CF_KEYWORDS(OSPF, OSPF2, OSPF3, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, COST2, RETRANSMIT)
CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST)
CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP)
%type <t> opttext
%type <ld> lsadb_args
+%type <i> ospf_proto_key
CF_GRAMMAR
CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } )
-ospf_proto_start: proto_start OSPF {
+ospf_proto_key:
+ OSPF2 { $$ = 1; }
+ | OSPF3 { $$ = 0; }
+ ;
+
+ospf_proto_start: proto_start ospf_proto_key {
this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1);
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
+ OSPF_CFG->ospf2 = $2;
}
;
ospf_proto_item:
proto_item
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
- | ECMP bool { OSPF_CFG->ecmp = $2 ? DEFAULT_ECMP_LIMIT : 0; }
+ | ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
| TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); }
| ospf_area
| NSSA { this_area->type = OPT_N; }
| SUMMARY bool { this_area->summary = $2; }
| DEFAULT NSSA bool { this_area->default_nssa = $3; }
- | DEFAULT COST expr { this_area->default_cost = $3; check_defcost($3); }
- | DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT_EBIT; check_defcost($3); }
- | STUB COST expr { this_area->default_cost = $3; check_defcost($3); }
+ | DEFAULT COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
+ | DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT_EBIT; ospf_check_defcost($3); }
+ | STUB COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
| TRANSLATOR bool { this_area->translator = $2; }
| TRANSLATOR STABILITY expr { this_area->transint = $3; }
| NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}'
| WAIT expr { OSPF_PATT->waitint = $2 ; }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
- | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
- | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
- | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
- | password_list
+ | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
+ | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
+ | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
+ | password_list { ospf_check_auth(); }
;
ospf_vlink_start: VIRTUAL LINK idval
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
- | REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (OSPF_VERSION != 2) cf_error("Real broadcast option requires OSPFv2"); }
+ | REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (!ospf_cfg_is_v2()) cf_error("Real broadcast option requires OSPFv2"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); }
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
| CHECK LINK bool { OSPF_PATT->check_link = $3; }
| ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
| NEIGHBORS '{' ipa_list '}'
- | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
- | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
- | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
+ | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
+ | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
+ | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
| RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; }
| RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; }
| RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if (($3 < OSPF_RXBUF_MINSIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
- | password_list
+ | password_list { ospf_check_auth(); }
;
pref_list:
ospf_instance_id:
/* empty */
- | INSTANCE expr { set_instance_id($2); }
+ | INSTANCE expr {
+ if (ospf_cfg_is_v2()) cf_error("Instance ID requires OSPFv3");
+ OSPF_PATT->instance_id = $2;
+ }
;
ospf_iface_opts:
else if (ospf_is_v3(po))
OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
iface->name, ip->instance_id, oa->areaid);
- else if (ifa->addr->flags & IA_PEER)
+ else if (addr->flags & IA_PEER)
OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R",
iface->name, addr->opposite, oa->areaid);
else
}
-#ifdef OSPFv2
+/*
+ * Matching ifaces and addresses to OSPF ifaces/patterns
+ * ospfX_ifa_notify(), ospfX_ifaces_reconfigure()
+ *
+ * This is significantly different in OSPFv2 and OSPFv3.
+ * In OSPFv2, OSPF ifaces are created for each IP prefix (struct ifa)
+ * In OSPFv3, OSPF ifaces are created based on real iface (struct iface),
+ * but there may be several ones with different instance_id
+ */
static inline struct ospf_iface_patt *
-ospf_iface_patt_find(struct ospf_area_config *ac, struct ifa *a)
+ospf_iface_patt_find2(struct ospf_area_config *ac, struct ifa *a)
{
return (struct ospf_iface_patt *) iface_patt_find(&ac->patt_list, a->iface, a);
}
+struct ospf_iface_patt *
+ospf_iface_patt_find3(struct ospf_area_config *ac, struct iface *iface, int iid)
+{
+ struct ospf_iface_patt *pt, *res = NULL;
+
+ WALK_LIST(pt, ac->patt_list)
+ if ((pt->instance_id >= iid) && (iface_patt_match(&pt->i, iface, NULL)) &&
+ (!res || (pt->instance_id < res->instance_id)))
+ res = pt;
+
+ return res;
+}
+
+static struct ospf_iface *
+ospf_iface_find_by_key2(struct ospf_area *oa, struct ifa *a)
+{
+ struct ospf_iface *ifa;
+ WALK_LIST(ifa, oa->po->iface_list)
+ if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->type != OSPF_IT_VLINK))
+ return ifa;
+
+ return NULL;
+}
+
+static struct ospf_iface *
+ospf_iface_find_by_key3(struct ospf_area *oa, struct ifa *a, int iid)
+{
+ struct ospf_iface *ifa;
+ WALK_LIST(ifa, oa->po->iface_list)
+ if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
+ return ifa;
+
+ return NULL;
+}
+
+
void
-ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
+ospf_ifa_notify2(struct proto *p, unsigned flags, struct ifa *a)
{
struct proto_ospf *po = (struct proto_ospf *) p;
WALK_LIST(oa, po->area_list)
{
struct ospf_iface_patt *ip;
- if (ip = ospf_iface_patt_find(oa->ac, a))
+ if (ip = ospf_iface_patt_find2(oa->ac, a))
{
if (!done)
ospf_iface_new(oa, a, ip);
}
}
-static struct ospf_iface *
-ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
-{
- struct ospf_iface *ifa;
- WALK_LIST(ifa, oa->po->iface_list)
- if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->type != OSPF_IT_VLINK))
- return ifa;
-
- return NULL;
-}
-
-void
-ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
-{
- struct ospf_iface_patt *ip;
- struct iface *iface;
- struct ifa *a;
-
- WALK_LIST(iface, iface_list)
- WALK_LIST(a, iface->addrs)
- {
- if (a->flags & IA_SECONDARY)
- continue;
-
- if (a->scope <= SCOPE_LINK)
- continue;
-
- if (ip = ospf_iface_patt_find(oa->ac, a))
- {
- /* Main inner loop */
- struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a);
- if (ifa)
- {
- if (ospf_iface_reconfigure(ifa, ip))
- continue;
-
- /* Hard restart */
- ospf_iface_shutdown(ifa);
- ospf_iface_remove(ifa);
- }
-
- ospf_iface_new(oa, a, ip);
- }
- }
-}
-
-
-#else /* OSPFv3 */
-
-struct ospf_iface_patt *
-ospf_iface_patt_find(struct ospf_area_config *ac, struct iface *iface, int iid)
-{
- struct ospf_iface_patt *pt, *res = NULL;
-
- WALK_LIST(pt, ac->patt_list)
- if ((pt->instance_id >= iid) && (iface_patt_match(&pt->i, iface, NULL)) &&
- (!res || (pt->instance_id < res->instance_id)))
- res = pt;
-
- return res;
-}
-
void
-ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
+ospf_ifa_notify3(struct proto *p, unsigned flags, struct ifa *a)
{
struct proto_ospf *po = (struct proto_ospf *) p;
int iid = 0;
struct ospf_iface_patt *ip;
- while (ip = ospf_iface_patt_find(oa->ac, a->iface, iid))
+ while (ip = ospf_iface_patt_find3(oa->ac, a->iface, iid))
{
ospf_iface_new(oa, a, ip);
if (ip->instance_id == 0)
}
}
-static struct ospf_iface *
-ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
+
+static void
+ospf_ifaces_reconfigure2(struct ospf_area *oa, struct ospf_area_config *nac)
{
- struct ospf_iface *ifa;
- WALK_LIST(ifa, oa->po->iface_list)
- if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
- return ifa;
+ struct ospf_iface_patt *ip;
+ struct iface *iface;
+ struct ifa *a;
- return NULL;
+ WALK_LIST(iface, iface_list)
+ WALK_LIST(a, iface->addrs)
+ {
+ if (a->flags & IA_SECONDARY)
+ continue;
+
+ if (a->scope <= SCOPE_LINK)
+ continue;
+
+ if (ip = ospf_iface_patt_find2(oa->ac, a))
+ {
+ /* Main inner loop */
+ struct ospf_iface *ifa = ospf_iface_find_by_key2(oa, a);
+ if (ifa)
+ {
+ if (ospf_iface_reconfigure(ifa, ip))
+ continue;
+
+ /* Hard restart */
+ ospf_iface_shutdown(ifa);
+ ospf_iface_remove(ifa);
+ }
+
+ ospf_iface_new(oa, a, ip);
+ }
+ }
}
-void
-ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
+static void
+ospf_ifaces_reconfigure3(struct ospf_area *oa, struct ospf_area_config *nac)
{
struct ospf_iface_patt *ip;
struct iface *iface;
continue;
int iid = 0;
- while (ip = ospf_iface_patt_find(nac, iface, iid))
+ while (ip = ospf_iface_patt_find3(nac, iface, iid))
{
iid = ip->instance_id + 1;
/* Main inner loop */
- struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a, ip->instance_id);
+ struct ospf_iface *ifa = ospf_iface_find_by_key3(oa, a, ip->instance_id);
if (ifa)
{
if (ospf_iface_reconfigure(ifa, ip))
}
}
-#endif
+void
+ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
+{
+ if (ospf_is_v2(oa->po))
+ ospf_ifaces_reconfigure2(oa, nac);
+ else
+ ospf_ifaces_reconfigure3(oa, nac);
+}
+
static void
ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
void ospf_iface_sm(struct ospf_iface *ifa, int event);
struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what);
void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface);
-void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
+void ospf_ifa_notify2(struct proto *p, unsigned flags, struct ifa *a);
+void ospf_ifa_notify3(struct proto *p, unsigned flags, struct ifa *a);
void ospf_iface_info(struct ospf_iface *ifa);
void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip);
void ospf_iface_remove(struct ospf_iface *ifa);
{
while (rt->buf >= rt->bufend)
{
- rt->en = ospf_hash_find_rt_next(rt->en);
+ rt->en = ospf_hash_find_rt3_next(rt->en);
if (!rt->en)
return 0;
if (rt->ospf2)
rt->en = act;
else
- rt->en = ospf_hash_find_rt_first(po->gr, act->domain, act->lsa.rt);
+ rt->en = ospf_hash_find_rt3_first(po->gr, act->domain, act->lsa.rt);
rt->buf = rt->en->lsa_body;
rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header);
struct top_hash_entry *
lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body)
{
- /* LSA can be temporarrily, but body must be mb_allocated. */
+ /* LSA can be temporary, but body must be mb_allocated. */
int change = 0;
struct top_hash_entry *en;
}
else
{
- if ((en->lsa.length != lsa->length)
-#ifdef OSPFv2
- || (en->lsa.options != lsa->options)
-#endif
- || (en->lsa.age == LSA_MAXAGE)
- || (lsa->age == LSA_MAXAGE)
- || memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
+ if ((en->lsa.length != lsa->length) ||
+ (en->lsa.type_raw != lsa->type_raw) || /* check for OSPFv2 options */
+ (en->lsa.age == LSA_MAXAGE) ||
+ (lsa->age == LSA_MAXAGE) ||
+ memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
change = 1;
s_rem_node(SNODE en);
static struct proto *
ospf_init(struct proto_config *c)
{
+ struct ospf_config *oc = (struct ospf_config *) c;
struct proto *p = proto_new(c, sizeof(struct proto_ospf));
p->make_tmp_attrs = ospf_make_tmp_attrs;
p->accept_ra_types = RA_OPTIMAL;
p->rt_notify = ospf_rt_notify;
p->if_notify = ospf_if_notify;
- p->ifa_notify = ospf_ifa_notify;
+ p->ifa_notify = oc->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
p->rte_better = ospf_rte_better;
p->rte_same = ospf_rte_same;
* values
*/
-#ifdef OSPFv3
-
static struct ospf_lsa_header *
fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *src,
struct ospf_lsa_prefix *px)
{
dst->age = src->age;
- dst->type = px->ref_type;
+ dst->type_raw = px->ref_type;
dst->id = px->ref_id;
dst->rt = px->ref_rt;
dst->sn = src->sn;
return dst;
}
-#endif
-static int lsa_compare_ospf3; // XXXX fixme
+static int lsa_compare_ospf3;
static int
lsa_compare_for_state(const void *p1, const void *p2)
struct ospf_lsa_header lsatmp1, lsatmp2;
u16 lsa1_type = he1->lsa_type;
u16 lsa2_type = he2->lsa_type;
- int px1 = 0;
- int px2 = 0;
if (he1->domain != he2->domain)
return he1->domain - he2->domain;
- if (lsa_compare_ospf3)
- {
- px1 = (lsa1_type == LSA_T_PREFIX);
- px2 = (lsa2_type == LSA_T_PREFIX);
- xxxx();
- if (px1)
- {
- lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body);
- lsa1_type = lsa1->type;
- px1 = 1;
- }
+ /* px1 or px2 assumes OSPFv3 */
+ int px1 = (lsa1_type == LSA_T_PREFIX);
+ int px2 = (lsa2_type == LSA_T_PREFIX);
+
+ if (px1)
+ {
+ lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body);
+ lsa1_type = lsa1->type_raw; /* FIXME: handle unknown ref_type */
+ }
- if (px2)
- lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body);
+ if (px2)
+ {
+ lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body);
+ lsa2_type = lsa2->type_raw;
}
if (nt1)
{
-#ifdef OSPFv3
/* In OSPFv3, networks are named based on ID of DR */
- if (lsa1->rt != lsa2->rt)
+ if (lsa_compare_ospf3 && (lsa1->rt != lsa2->rt))
return lsa1->rt - lsa2->rt;
-#endif
/* For OSPFv2, this is IP of the network,
for OSPFv3, this is interface ID */
if (ospf_is_v2(po))
{
/* In OSPFv2, we try to find network-LSA to get prefix/pxlen */
- struct top_hash_entry *net_he = ospf_hash_find_net(po->gr, he->domain, rtl.id, 0);
+ struct top_hash_entry *net_he = ospf_hash_find_net2(po->gr, he->domain, rtl.id);
if (net_he)
{
}
static inline void
-show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode)
+show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
{
struct ospf_lsa_prefix *px = he->lsa_body;
ip_addr pxa;
int i;
/* We check whether given prefix-LSA is related to the current node */
- if ((px->ref_type != cnode->type_raw) || (px->ref_rt != cnode->rt))
+ if ((px->ref_type != cnode->lsa.type_raw) || (px->ref_rt != cnode->lsa.rt))
return;
if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0))
return;
- if ((px->ref_type == LSA_T_NET) && (px->ref_id != cnode->id))
+ if ((px->ref_type == LSA_T_NET) && (px->ref_id != cnode->lsa.id))
return;
buf = px->rest;
ospf_sh_state(struct proto *p, int verbose, int reachable)
{
struct proto_ospf *po = (struct proto_ospf *) p;
- struct ospf_lsa_header *cnode = NULL;
int ospf2 = ospf_is_v2(po);
int num = po->gr->hash_entries;
unsigned int i, ix, j1, j2, jx;
struct top_hash_entry *hea[num];
struct top_hash_entry *hex[verbose ? num : 0];
struct top_hash_entry *he;
+ struct top_hash_entry *cnode = NULL;
j1 = j2 = jx = 0;
WALK_SLIST(he, po->lsal)
if ((j1 + j2) != num)
die("Fatal mismatch");
+ lsa_compare_ospf3 = !ospf2;
qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state);
qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET))
&& ((he->color == INSPF) || !reachable))
{
- cnode = &(he->lsa);
+ cnode = he;
if (he->domain != last_area)
{
continue;
}
- ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->rt));
+ ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->lsa.rt));
switch (he->lsa_type)
{
case LSA_T_RT:
- if (he->lsa.id == cnode->id)
+ if (he->lsa.id == cnode->lsa.id)
show_lsa_router(po, he, verbose);
break;
break;
case LSA_T_SUM_NET:
- if (cnode->type == LSA_T_RT)
+ if (cnode->lsa_type == LSA_T_RT)
show_lsa_sum_net(he, ospf2);
break;
case LSA_T_SUM_RT:
- if (cnode->type == LSA_T_RT)
+ if (cnode->lsa_type == LSA_T_RT)
show_lsa_sum_rt(he, ospf2);
break;
/* In these cases, we close the current node */
if ((i+1 == j1)
|| (hea[i+1]->domain != last_area)
- || (hea[i+1]->lsa.rt != cnode->rt)
+ || (hea[i+1]->lsa.rt != cnode->lsa.rt)
|| (hea[i+1]->lsa_type == LSA_T_NET))
{
- while ((ix < jx) && (hex[ix]->lsa.rt < cnode->rt))
+ while ((ix < jx) && (hex[ix]->lsa.rt < cnode->lsa.rt))
ix++;
- while ((ix < jx) && (hex[ix]->lsa.rt == cnode->rt))
+ while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
show_lsa_external(hex[ix++], ospf2);
cnode = NULL;
unsigned int i, j;
int last_dscope = -1;
u32 last_domain = 0;
+ u16 type_mask = ospf_is_v2(po) ? 0x00ff : 0xffff; /* see lsa_get_type() */
if (p->proto_state != PS_UP)
{
for (i = 0; i < j; i++)
{
struct ospf_lsa_header *lsa = &(hea[i]->lsa);
- int dscope = LSA_SCOPE(hea[i]->lsa_type);
-
+ 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;
if ((ld->scope == LSA_SCOPE_AREA) && (hea[i]->domain != ld->area))
continue;
- /* Ignore high nibble */
- // XXXX check
- if (ld->type && ((lsa->type & 0x0fff) != (ld->type & 0x0fff)))
+ /* For user convenience ignore high nibble */
+ if (ld->type && ((lsa_type & 0x0fff) != (ld->type & 0x0fff)))
continue;
if (ld->lsid && (lsa->id != ld->lsid))
}
cli_msg(-1017," %04x %-15R %-15R %5u %08x %04x",
- lsa->type, lsa->id, lsa->rt, lsa->age, lsa->sn, lsa->checksum);
+ lsa_type, lsa->id, lsa->rt, lsa->age, lsa->sn, lsa->checksum);
}
cli_msg(0, "");
}
struct protocol proto_ospf = {
- name: "OSPF",
- template: "ospf%d",
- attr_class: EAP_OSPF,
- preference: DEF_PREF_OSPF,
- init: ospf_init,
- dump: ospf_dump,
- start: ospf_start,
- shutdown: ospf_shutdown,
- reconfigure: ospf_reconfigure,
- get_status: ospf_get_status,
- get_attr: ospf_get_attr,
- get_route_info: ospf_get_route_info
- // show_proto_info: ospf_sh
+ .name = "OSPF",
+ .template = "ospf%d",
+ .attr_class = EAP_OSPF,
+ .preference = DEF_PREF_OSPF,
+ .init = ospf_init,
+ .dump = ospf_dump,
+ .start = ospf_start,
+ .shutdown = ospf_shutdown,
+ .reconfigure = ospf_reconfigure,
+ .get_status = ospf_get_status,
+ .get_attr = ospf_get_attr,
+ .get_route_info = ospf_get_route_info
};
+
* BIRD -- OSPF
*
* (c) 1999--2005 Ondrej Filip <feela@network.cz>
+ * (c) 2009--2012 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2009--2012 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#define OSPF_PROTO 89
-
-// XXXX
-#define OSPFv3 1
-#define OSPF_VERSION 3
-
-
-
#define LSREFRESHTIME 1800 /* 30 minutes */
#define MINLSINTERVAL 5
#define MINLSARRIVAL 1
{
struct proto_config c;
unsigned tick;
+ byte ospf2;
byte rfc1583;
byte abr;
- int ecmp;
+ byte ecmp;
list area_list; /* list of struct ospf_area_config */
list vlink_list; /* list of struct ospf_iface_patt */
};
{ pkt->vdep = htons(val << 8); }
-// XXXX
-/*
-#define LSA_T_RT 1
-#define LSA_T_NET 2
-#define LSA_T_SUM_NET 3
-#define LSA_T_SUM_RT 4
-#define LSA_T_EXT 5
-#define LSA_T_NSSA 7
-*/
-
#define LSA_T_RT 0x2001
#define LSA_T_NET 0x2002
#define LSA_T_SUM_NET 0x2003
/ sizeof(u32);
}
+/* 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 */
+
+#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)
list area_list;
int areano; /* Number of area I belong to */
struct fib rtf; /* Routing table */
+ byte ospf2; /* OSPF v2 or v3 */
byte rfc1583; /* RFC1583 compatibility */
byte ebit; /* Did I originate any ext lsa? */
byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
void schedule_net_lsa(struct ospf_iface *ifa);
static inline int ospf_is_v2(struct proto_ospf *po)
-{ return 0; } // XXXX fixme
+{ return po->ospf2; }
+
static inline int ospf_is_v3(struct proto_ospf *po)
-{ return 1; } // XXXX fixme
+{ return ! po->ospf2; }
+
+static inline int ospf_get_version(struct proto_ospf *po)
+{ return ospf_is_v2(po) ? 2 : 3; }
static inline void lsa_fix_options(struct proto_ospf *po, struct ospf_lsa_header *lsa, u8 options)
{ if (ospf_is_v2(po)) lsa_set_options(lsa, options); }
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
+
static inline struct ospf_area *ospf_main_area(struct proto_ospf *po)
{ return (po->areano == 1) ? HEAD(po->area_list) : po->backbone; }
static inline int oa_is_stub(struct ospf_area *oa)
{ return (oa->options & (OPT_E | OPT_N)) == 0; }
+
static inline int oa_is_ext(struct ospf_area *oa)
{ return oa->options & OPT_E; }
+
static inline int oa_is_nssa(struct ospf_area *oa)
{ return oa->options & OPT_N; }
-
void schedule_link_lsa(struct ospf_iface *ifa); // XXXX caller ??
void ospf_sh_neigh(struct proto *p, char *iff);
* BIRD -- OSPF
*
* (c) 1999--2005 Ondrej Filip <feela@network.cz>
+ * (c) 2009--2012 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2009--2012 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
pkt = (struct ospf_packet *) buf;
- pkt->version = OSPF_VERSION;
+ pkt->version = ospf_get_version(po);
pkt->type = h_type;
return 1;
}
- if (pkt->version != OSPF_VERSION)
+ if (pkt->version != ospf_get_version(po))
{
log(L_ERR "%s%I - version %u", mesg, sk->faddr, pkt->version);
return 1;
void ospf_send_to_bdr(struct ospf_iface *ifa);
static inline void ospf_send_to_all(struct ospf_iface *ifa)
-{
- ospf_send_to(ifa, ifa->all_routers);
-}
+{ ospf_send_to(ifa, ifa->all_routers); }
static inline void ospf_send_to_des(struct ospf_iface *ifa)
{
ospf_send_to_bdr(ifa);
}
-static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; }
+static inline unsigned ospf_pkt_hdrlen(struct proto_ospf *po)
+{
+ return ospf_is_v2(po) ?
+ (sizeof(struct ospf_packet) + sizeof(union ospf_auth)) :
+ sizeof(struct ospf_packet);
+}
+
+
+static inline void * ospf_tx_buffer(struct ospf_iface *ifa)
+{ return ifa->sk->tbuf; }
-static inline unsigned
-ospf_pkt_bufsize(struct ospf_iface *ifa)
+static inline unsigned ospf_pkt_bufsize(struct ospf_iface *ifa)
{
/* Reserve buffer space for authentication footer */
- return ifa->sk->tbsize -
- (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
+ unsigned res_size = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
+ return ifa->sk->tbsize - res_size;
}
/*
- * BIRD -- OSPF
+ * BIRD -- OSPF
*
- * (c) 2000--2004 Ondrej Filip <feela@network.cz>
+ * (c) 2000--2004 Ondrej Filip <feela@network.cz>
+ * (c) 2009--2012 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2009--2012 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"
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 */
-
-#define ipa_from_rid(x) ipa_from_u32(x)
static inline void reset_ri(ort *ort)
{
*
* (c) 1999 Martin Mares <mj@ucw.cz>
* (c) 1999--2004 Ondrej Filip <feela@network.cz>
+ * (c) 2009--2012 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2009--2012 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
void originate_prefix_net_lsa(struct ospf_iface *ifa);
void flush_prefix_net_lsa(struct ospf_iface *ifa);
-#ifdef OSPFv2
-#define ipa_to_rid(x) _I(x)
-#else /* OSPFv3 */
-#define ipa_to_rid(x) _I3(x)
-#endif
-
static inline u32
fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
if (ospf_is_v3(po))
return fn->uid;
- u32 id = _I(fn->prefix);
+ u32 id = ipa_to_u32(fn->prefix);
if ((po->rfc1583) || (fn->pxlen == 0) || (fn->pxlen == 32))
return id;
OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)",
fn->prefix, fn->pxlen, metric);
- /* options argument is used in ORT_NET and OSPFv3 only */
lsa.age = 0;
lsa.type_raw = LSA_T_SUM_NET;
lsa.id = fibnode_to_lsaid(po, fn);
(ifa->type == OSPF_IT_VLINK))
continue;
-#ifdef OSPFv2
- a = ifa->addr;
- if (a->flags & IA_PEER)
- continue;
-
- np = ((a->flags & IA_HOST) || ifa->stub) ? 2 : 1;
- if (np > cur_np)
- {
- cur_addr = a;
- cur_np = np;
- }
-
-#else /* OSPFv3 */
- WALK_LIST(a, ifa->iface->addrs)
+ if (ospf_is_v2(po))
{
- if ((a->flags & IA_SECONDARY) ||
- (a->flags & IA_PEER) ||
- (a->scope <= SCOPE_LINK))
+ a = ifa->addr;
+ if (a->flags & IA_PEER)
continue;
np = ((a->flags & IA_HOST) || ifa->stub) ? 2 : 1;
cur_np = np;
}
}
-#endif
+ else /* OSPFv3 */
+ {
+ WALK_LIST(a, ifa->iface->addrs)
+ {
+ if ((a->flags & IA_SECONDARY) ||
+ (a->flags & IA_PEER) ||
+ (a->scope <= SCOPE_LINK))
+ continue;
+
+ np = ((a->flags & IA_HOST) || ifa->stub) ? 2 : 1;
+ if (np > cur_np)
+ {
+ cur_addr = a;
+ cur_np = np;
+ }
+ }
+ }
}
return cur_addr ? cur_addr->ip : IPA_NONE;
return e;
}
-
-#ifdef OSPFv2
-
-/* In OSPFv2, sometimes we don't know Router ID when looking for network LSAs.
- There should be just one, so we find any match. */
-struct top_hash_entry *
-ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif)
-{
- struct top_hash_entry *e;
- e = f->hash_table[ospf_top_hash(f, domain, id, 0, LSA_T_NET)];
-
- while (e && (e->lsa.id != id || e->lsa.type != LSA_T_NET || e->domain != domain))
- e = e->next;
-
- return e;
-}
-
-#endif
-
-
-#ifdef OSPFv3
-
-/* In OSPFv3, usually we don't know LSA ID when looking for router
- LSAs. We return matching LSA with smallest LSA ID. */
+/* In OSPFv2, lsa.id is the same as lsa.rt for router LSA. In OSPFv3, we don't know
+ lsa.id when looking for router LSAs. We return matching LSA with smallest lsa.id. */
struct top_hash_entry *
ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
{
struct top_hash_entry *rv = NULL;
struct top_hash_entry *e;
- e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)];
-
+ /* We can put rtr for lsa.id to hash fn, it is ignored in OSPFv3 */
+ e = f->hash_table[ospf_top_hash(f, domain, rtr, rtr, LSA_T_RT)];
+
while (e)
+ {
+ if (e->lsa.rt == rtr && e->lsa_type == LSA_T_RT && e->domain == domain)
{
- if (e->lsa.rt == rtr && e->lsa.type == LSA_T_RT && e->domain == domain)
- if (!rv || e->lsa.id < rv->lsa.id)
- rv = e;
- e = e->next;
+ if (f->ospf2 && (e->lsa.id == rtr))
+ return e;
+ if (!f->ospf2 && (!rv || e->lsa.id < rv->lsa.id))
+ rv = e;
}
+ e = e->next;
+ }
return rv;
}
static inline struct top_hash_entry *
-find_matching_rt(struct top_hash_entry *e, u32 domain, u32 rtr)
+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))
+ while (e && (e->lsa.rt != rtr || e->lsa_type != LSA_T_RT || e->domain != domain))
e = e->next;
return e;
}
struct top_hash_entry *
-ospf_hash_find_rt_first(struct top_graph *f, u32 domain, u32 rtr)
+ospf_hash_find_rt3_first(struct top_graph *f, u32 domain, u32 rtr)
{
struct top_hash_entry *e;
e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)];
- return find_matching_rt(e, domain, rtr);
+ return find_matching_rt3(e, domain, rtr);
}
struct top_hash_entry *
-ospf_hash_find_rt_next(struct top_hash_entry *e)
+ospf_hash_find_rt3_next(struct top_hash_entry *e)
{
- return find_matching_rt(e->next, e->domain, e->lsa.rt);
+ return find_matching_rt3(e->next, e->domain, e->lsa.rt);
}
-#endif
+/* In OSPFv2, we don't know Router ID when looking for network LSAs.
+ There should be just one, so we find any match. */
+struct top_hash_entry *
+ospf_hash_find_net2(struct top_graph *f, u32 domain, u32 id)
+{
+ struct top_hash_entry *e;
+ e = f->hash_table[ospf_top_hash(f, domain, id, 0, LSA_T_NET)];
+
+ while (e && (e->lsa.id != id || e->lsa_type != LSA_T_NET || e->domain != domain))
+ e = e->next;
+
+ return e;
+}
struct top_hash_entry *
pool *pool; /* Pool we allocate from */
slab *hash_slab; /* Slab for hash entries */
struct top_hash_entry **hash_table; /* Hashing (modelled a`la fib) */
+ unsigned int ospf2; /* Whether it is for OSPFv2 or OSPFv3 */
unsigned int hash_size;
unsigned int hash_order;
unsigned int hash_mask;
void originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, u32 metric, ip_addr fwaddr, u32 tag, int pbit);
void flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src);
+struct top_hash_entry * ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr);
+struct top_hash_entry * ospf_hash_find_rt3_first(struct top_graph *f, u32 domain, u32 rtr);
+struct top_hash_entry * ospf_hash_find_rt3_next(struct top_hash_entry *e);
-#ifdef OSPFv2
-struct top_hash_entry * ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif);
-
-static inline struct top_hash_entry *
-ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
-{
- return ospf_hash_find(f, domain, rtr, rtr, LSA_T_RT);
-}
+struct top_hash_entry * ospf_hash_find_net2(struct top_graph *f, u32 domain, u32 id);
-#else /* OSPFv3 */
+/* In OSPFv2, id is network IP prefix (lsa.id) while lsa.rt field is unknown
+ In OSPFv3, id is lsa.rt of DR while nif is neighbor iface id (lsa.id) */
static inline struct top_hash_entry *
ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif)
{
- return ospf_hash_find(f, domain, nif, id, LSA_T_NET);
+ return f->ospf2 ?
+ ospf_hash_find_net2(f, domain, id) :
+ ospf_hash_find(f, domain, nif, id, LSA_T_NET);
}
-struct top_hash_entry * ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr);
-struct top_hash_entry * ospf_hash_find_rt_first(struct top_graph *f, u32 domain, u32 rtr);
-struct top_hash_entry * ospf_hash_find_rt_next(struct top_hash_entry *e);
-#endif
-
-
#endif /* _BIRD_OSPF_TOPOLOGY_H_ */