0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-08 18:11:54 +00:00

Temporary integrated commit (OSPF), unfinished.

This commit is contained in:
Ondrej Zajicek 2012-10-19 16:26:51 +02:00
parent 5aa9d7447c
commit 19e239576f
11 changed files with 302 additions and 305 deletions

View File

@ -21,7 +21,9 @@ static list *this_nets;
static struct area_net_config *this_pref; static struct area_net_config *this_pref;
static struct ospf_stubnet_config *this_stubnet; 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 static void
ospf_iface_finish(void) ospf_iface_finish(void)
{ {
@ -38,21 +40,6 @@ ospf_iface_finish(void)
if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL)) if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
log(L_WARN "Password option without authentication option does not make sense"); 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 static void
ospf_area_finish(void) ospf_area_finish(void)
@ -104,25 +91,23 @@ ospf_proto_finish(void)
} }
static inline void static inline void
check_defcost(int cost) ospf_check_defcost(int cost)
{ {
if ((cost <= 0) || (cost >= LSINFINITY)) if ((cost <= 0) || (cost >= LSINFINITY))
cf_error("Default cost must be in range 1-%d", LSINFINITY-1); cf_error("Default cost must be in range 1-%d", LSINFINITY-1);
} }
static inline void static inline void
set_instance_id(unsigned id) ospf_check_auth(void)
{ {
#ifdef OSPFv3 if (ospf_cfg_is_v3())
OSPF_PATT->instance_id = id; cf_error("Authentication not supported in OSPFv3");
#else
cf_error("Instance ID requires OSPFv3");
#endif
} }
CF_DECLS 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(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, COST2, RETRANSMIT)
CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST) CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST)
CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP) CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP)
@ -134,16 +119,23 @@ CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL)
%type <t> opttext %type <t> opttext
%type <ld> lsadb_args %type <ld> lsadb_args
%type <i> ospf_proto_key
CF_GRAMMAR CF_GRAMMAR
CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } ) 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); this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1);
init_list(&OSPF_CFG->area_list); init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list); init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->tick = OSPF_DEFAULT_TICK; OSPF_CFG->tick = OSPF_DEFAULT_TICK;
OSPF_CFG->ospf2 = $2;
} }
; ;
@ -155,7 +147,7 @@ ospf_proto:
ospf_proto_item: ospf_proto_item:
proto_item proto_item
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; } | 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"); } | 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"); } | TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); }
| ospf_area | ospf_area
@ -189,9 +181,9 @@ ospf_area_item:
| NSSA { this_area->type = OPT_N; } | NSSA { this_area->type = OPT_N; }
| SUMMARY bool { this_area->summary = $2; } | SUMMARY bool { this_area->summary = $2; }
| DEFAULT NSSA bool { this_area->default_nssa = $3; } | DEFAULT NSSA bool { this_area->default_nssa = $3; }
| DEFAULT 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; 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; check_defcost($3); } | STUB COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
| TRANSLATOR bool { this_area->translator = $2; } | TRANSLATOR bool { this_area->translator = $2; }
| TRANSLATOR STABILITY expr { this_area->transint = $3; } | TRANSLATOR STABILITY expr { this_area->transint = $3; }
| NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}' | NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}'
@ -243,10 +235,10 @@ ospf_vlink_item:
| WAIT expr { OSPF_PATT->waitint = $2 ; } | 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 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"); } | 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 NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; } | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; } | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
| password_list | password_list { ospf_check_auth(); }
; ;
ospf_vlink_start: VIRTUAL LINK idval ospf_vlink_start: VIRTUAL LINK idval
@ -286,7 +278,7 @@ ospf_iface_item:
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; } | TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; } | TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
| TYPE PTMP { 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"); } | 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"); } | 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 ; } | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
@ -294,13 +286,13 @@ ospf_iface_item:
| CHECK LINK bool { OSPF_PATT->check_link = $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"); } | 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 '}' | NEIGHBORS '{' ipa_list '}'
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; } | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; } | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; } | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
| RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; } | RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; }
| RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; } | 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"); } | 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: pref_list:
@ -376,7 +368,10 @@ ospf_iface_start:
ospf_instance_id: ospf_instance_id:
/* empty */ /* 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: ospf_iface_opts:

View File

@ -505,7 +505,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
else if (ospf_is_v3(po)) else if (ospf_is_v3(po))
OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R", OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
iface->name, ip->instance_id, oa->areaid); 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", OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R",
iface->name, addr->opposite, oa->areaid); iface->name, addr->opposite, oa->areaid);
else else
@ -801,16 +801,60 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
} }
#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 * 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); 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 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; struct proto_ospf *po = (struct proto_ospf *) p;
@ -828,7 +872,7 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
WALK_LIST(oa, po->area_list) WALK_LIST(oa, po->area_list)
{ {
struct ospf_iface_patt *ip; 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) if (!done)
ospf_iface_new(oa, a, ip); ospf_iface_new(oa, a, ip);
@ -852,70 +896,8 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
} }
} }
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 void
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) ospf_ifa_notify3(struct proto *p, unsigned flags, struct ifa *a)
{
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)
{ {
struct proto_ospf *po = (struct proto_ospf *) p; struct proto_ospf *po = (struct proto_ospf *) p;
@ -939,7 +921,7 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
int iid = 0; int iid = 0;
struct ospf_iface_patt *ip; 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); ospf_iface_new(oa, a, ip);
if (ip->instance_id == 0) if (ip->instance_id == 0)
@ -980,19 +962,44 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
} }
} }
static struct ospf_iface *
ospf_iface_find_by_key(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; static void
ospf_ifaces_reconfigure2(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_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 static void
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) ospf_ifaces_reconfigure3(struct ospf_area *oa, struct ospf_area_config *nac)
{ {
struct ospf_iface_patt *ip; struct ospf_iface_patt *ip;
struct iface *iface; struct iface *iface;
@ -1008,12 +1015,12 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
continue; continue;
int iid = 0; 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; iid = ip->instance_id + 1;
/* Main inner loop */ /* 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 (ifa)
{ {
if (ospf_iface_reconfigure(ifa, ip)) if (ospf_iface_reconfigure(ifa, ip))
@ -1029,7 +1036,15 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
} }
} }
#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 static void
ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa) ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)

View File

@ -14,7 +14,8 @@ void ospf_iface_chstate(struct ospf_iface *ifa, u8 state);
void ospf_iface_sm(struct ospf_iface *ifa, int event); void ospf_iface_sm(struct ospf_iface *ifa, int event);
struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what); 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_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_info(struct ospf_iface *ifa);
void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip); void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip);
void ospf_iface_remove(struct ospf_iface *ifa); void ospf_iface_remove(struct ospf_iface *ifa);

View File

@ -394,7 +394,7 @@ lsa_walk_rt3(struct ospf_lsa_rt_walk *rt)
{ {
while (rt->buf >= rt->bufend) 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) if (!rt->en)
return 0; return 0;
@ -423,7 +423,7 @@ lsa_walk_rt_init(struct proto_ospf *po, struct top_hash_entry *act, struct ospf_
if (rt->ospf2) if (rt->ospf2)
rt->en = act; rt->en = act;
else 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->buf = rt->en->lsa_body;
rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header); rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header);
@ -779,7 +779,7 @@ lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
struct top_hash_entry * struct top_hash_entry *
lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body) 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; int change = 0;
struct top_hash_entry *en; struct top_hash_entry *en;
@ -790,13 +790,11 @@ lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain,
} }
else else
{ {
if ((en->lsa.length != lsa->length) if ((en->lsa.length != lsa->length) ||
#ifdef OSPFv2 (en->lsa.type_raw != lsa->type_raw) || /* check for OSPFv2 options */
|| (en->lsa.options != lsa->options) (en->lsa.age == LSA_MAXAGE) ||
#endif (lsa->age == LSA_MAXAGE) ||
|| (en->lsa.age == LSA_MAXAGE) memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
|| (lsa->age == LSA_MAXAGE)
|| memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
change = 1; change = 1;
s_rem_node(SNODE en); s_rem_node(SNODE en);

View File

@ -292,6 +292,7 @@ ospf_dump(struct proto *p)
static struct proto * static struct proto *
ospf_init(struct proto_config *c) ospf_init(struct proto_config *c)
{ {
struct ospf_config *oc = (struct ospf_config *) c;
struct proto *p = proto_new(c, sizeof(struct proto_ospf)); struct proto *p = proto_new(c, sizeof(struct proto_ospf));
p->make_tmp_attrs = ospf_make_tmp_attrs; p->make_tmp_attrs = ospf_make_tmp_attrs;
@ -301,7 +302,7 @@ ospf_init(struct proto_config *c)
p->accept_ra_types = RA_OPTIMAL; p->accept_ra_types = RA_OPTIMAL;
p->rt_notify = ospf_rt_notify; p->rt_notify = ospf_rt_notify;
p->if_notify = ospf_if_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_better = ospf_rte_better;
p->rte_same = ospf_rte_same; p->rte_same = ospf_rte_same;
@ -915,14 +916,12 @@ ospf_sh_iface(struct proto *p, char *iff)
* values * values
*/ */
#ifdef OSPFv3
static struct ospf_lsa_header * static struct ospf_lsa_header *
fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *src, fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *src,
struct ospf_lsa_prefix *px) struct ospf_lsa_prefix *px)
{ {
dst->age = src->age; dst->age = src->age;
dst->type = px->ref_type; dst->type_raw = px->ref_type;
dst->id = px->ref_id; dst->id = px->ref_id;
dst->rt = px->ref_rt; dst->rt = px->ref_rt;
dst->sn = src->sn; dst->sn = src->sn;
@ -930,9 +929,8 @@ fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *sr
return dst; return dst;
} }
#endif
static int lsa_compare_ospf3; // XXXX fixme static int lsa_compare_ospf3;
static int static int
lsa_compare_for_state(const void *p1, const void *p2) lsa_compare_for_state(const void *p1, const void *p2)
@ -944,27 +942,25 @@ lsa_compare_for_state(const void *p1, const void *p2)
struct ospf_lsa_header lsatmp1, lsatmp2; struct ospf_lsa_header lsatmp1, lsatmp2;
u16 lsa1_type = he1->lsa_type; u16 lsa1_type = he1->lsa_type;
u16 lsa2_type = he2->lsa_type; u16 lsa2_type = he2->lsa_type;
int px1 = 0;
int px2 = 0;
if (he1->domain != he2->domain) if (he1->domain != he2->domain)
return he1->domain - he2->domain; return he1->domain - he2->domain;
if (lsa_compare_ospf3)
/* px1 or px2 assumes OSPFv3 */
int px1 = (lsa1_type == LSA_T_PREFIX);
int px2 = (lsa2_type == LSA_T_PREFIX);
if (px1)
{ {
px1 = (lsa1_type == LSA_T_PREFIX); lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body);
px2 = (lsa2_type == LSA_T_PREFIX); lsa1_type = lsa1->type_raw; /* FIXME: handle unknown ref_type */
xxxx(); }
if (px1) if (px2)
{ {
lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body); lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body);
lsa1_type = lsa1->type; lsa2_type = lsa2->type_raw;
px1 = 1;
}
if (px2)
lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body);
} }
@ -976,11 +972,9 @@ lsa_compare_for_state(const void *p1, const void *p2)
if (nt1) if (nt1)
{ {
#ifdef OSPFv3
/* In OSPFv3, networks are named based on ID of DR */ /* 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; return lsa1->rt - lsa2->rt;
#endif
/* For OSPFv2, this is IP of the network, /* For OSPFv2, this is IP of the network,
for OSPFv3, this is interface ID */ for OSPFv3, this is interface ID */
@ -1062,7 +1056,7 @@ show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he, int verbose)
if (ospf_is_v2(po)) if (ospf_is_v2(po))
{ {
/* In OSPFv2, we try to find network-LSA to get prefix/pxlen */ /* 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) if (net_he)
{ {
@ -1163,7 +1157,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
} }
static inline void 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; struct ospf_lsa_prefix *px = he->lsa_body;
ip_addr pxa; ip_addr pxa;
@ -1174,13 +1168,13 @@ show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode)
int i; int i;
/* We check whether given prefix-LSA is related to the current node */ /* 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; return;
if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0)) if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0))
return; 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; return;
buf = px->rest; buf = px->rest;
@ -1199,7 +1193,6 @@ void
ospf_sh_state(struct proto *p, int verbose, int reachable) ospf_sh_state(struct proto *p, int verbose, int reachable)
{ {
struct proto_ospf *po = (struct proto_ospf *) p; struct proto_ospf *po = (struct proto_ospf *) p;
struct ospf_lsa_header *cnode = NULL;
int ospf2 = ospf_is_v2(po); int ospf2 = ospf_is_v2(po);
int num = po->gr->hash_entries; int num = po->gr->hash_entries;
unsigned int i, ix, j1, j2, jx; unsigned int i, ix, j1, j2, jx;
@ -1218,6 +1211,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
struct top_hash_entry *hea[num]; struct top_hash_entry *hea[num];
struct top_hash_entry *hex[verbose ? num : 0]; struct top_hash_entry *hex[verbose ? num : 0];
struct top_hash_entry *he; struct top_hash_entry *he;
struct top_hash_entry *cnode = NULL;
j1 = j2 = jx = 0; j1 = j2 = jx = 0;
WALK_SLIST(he, po->lsal) WALK_SLIST(he, po->lsal)
@ -1257,6 +1251,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
if ((j1 + j2) != num) if ((j1 + j2) != num)
die("Fatal mismatch"); die("Fatal mismatch");
lsa_compare_ospf3 = !ospf2;
qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state); qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state);
qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state); qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
@ -1290,7 +1285,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET)) if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET))
&& ((he->color == INSPF) || !reachable)) && ((he->color == INSPF) || !reachable))
{ {
cnode = &(he->lsa); cnode = he;
if (he->domain != last_area) if (he->domain != last_area)
{ {
@ -1304,12 +1299,12 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
continue; 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) switch (he->lsa_type)
{ {
case LSA_T_RT: case LSA_T_RT:
if (he->lsa.id == cnode->id) if (he->lsa.id == cnode->lsa.id)
show_lsa_router(po, he, verbose); show_lsa_router(po, he, verbose);
break; break;
@ -1318,12 +1313,12 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
break; break;
case LSA_T_SUM_NET: case LSA_T_SUM_NET:
if (cnode->type == LSA_T_RT) if (cnode->lsa_type == LSA_T_RT)
show_lsa_sum_net(he, ospf2); show_lsa_sum_net(he, ospf2);
break; break;
case LSA_T_SUM_RT: case LSA_T_SUM_RT:
if (cnode->type == LSA_T_RT) if (cnode->lsa_type == LSA_T_RT)
show_lsa_sum_rt(he, ospf2); show_lsa_sum_rt(he, ospf2);
break; break;
@ -1340,13 +1335,13 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
/* In these cases, we close the current node */ /* In these cases, we close the current node */
if ((i+1 == j1) if ((i+1 == j1)
|| (hea[i+1]->domain != last_area) || (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)) || (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++; 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); show_lsa_external(hex[ix++], ospf2);
cnode = NULL; cnode = NULL;
@ -1426,6 +1421,7 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
unsigned int i, j; unsigned int i, j;
int last_dscope = -1; int last_dscope = -1;
u32 last_domain = 0; u32 last_domain = 0;
u16 type_mask = ospf_is_v2(po) ? 0x00ff : 0xffff; /* see lsa_get_type() */
if (p->proto_state != PS_UP) if (p->proto_state != PS_UP)
{ {
@ -1452,17 +1448,18 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
for (i = 0; i < j; i++) for (i = 0; i < j; i++)
{ {
struct ospf_lsa_header *lsa = &(hea[i]->lsa); 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))) if (ld->scope && (dscope != (ld->scope & 0xf000)))
continue; continue;
if ((ld->scope == LSA_SCOPE_AREA) && (hea[i]->domain != ld->area)) if ((ld->scope == LSA_SCOPE_AREA) && (hea[i]->domain != ld->area))
continue; continue;
/* Ignore high nibble */ /* For user convenience ignore high nibble */
// XXXX check if (ld->type && ((lsa_type & 0x0fff) != (ld->type & 0x0fff)))
if (ld->type && ((lsa->type & 0x0fff) != (ld->type & 0x0fff)))
continue; continue;
if (ld->lsid && (lsa->id != ld->lsid)) if (ld->lsid && (lsa->id != ld->lsid))
@ -1499,24 +1496,24 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
} }
cli_msg(-1017," %04x %-15R %-15R %5u %08x %04x", 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, ""); cli_msg(0, "");
} }
struct protocol proto_ospf = { struct protocol proto_ospf = {
name: "OSPF", .name = "OSPF",
template: "ospf%d", .template = "ospf%d",
attr_class: EAP_OSPF, .attr_class = EAP_OSPF,
preference: DEF_PREF_OSPF, .preference = DEF_PREF_OSPF,
init: ospf_init, .init = ospf_init,
dump: ospf_dump, .dump = ospf_dump,
start: ospf_start, .start = ospf_start,
shutdown: ospf_shutdown, .shutdown = ospf_shutdown,
reconfigure: ospf_reconfigure, .reconfigure = ospf_reconfigure,
get_status: ospf_get_status, .get_status = ospf_get_status,
get_attr: ospf_get_attr, .get_attr = ospf_get_attr,
get_route_info: ospf_get_route_info .get_route_info = ospf_get_route_info
// show_proto_info: ospf_sh
}; };

View File

@ -2,6 +2,8 @@
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 1999--2005 Ondrej Filip <feela@network.cz> * (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. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
@ -53,13 +55,6 @@ do { if ((po->proto.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
#define OSPF_PROTO 89 #define OSPF_PROTO 89
// XXXX
#define OSPFv3 1
#define OSPF_VERSION 3
#define LSREFRESHTIME 1800 /* 30 minutes */ #define LSREFRESHTIME 1800 /* 30 minutes */
#define MINLSINTERVAL 5 #define MINLSINTERVAL 5
#define MINLSARRIVAL 1 #define MINLSARRIVAL 1
@ -75,9 +70,10 @@ struct ospf_config
{ {
struct proto_config c; struct proto_config c;
unsigned tick; unsigned tick;
byte ospf2;
byte rfc1583; byte rfc1583;
byte abr; byte abr;
int ecmp; byte ecmp;
list area_list; /* list of struct ospf_area_config */ list area_list; /* list of struct ospf_area_config */
list vlink_list; /* list of struct ospf_iface_patt */ list vlink_list; /* list of struct ospf_iface_patt */
}; };
@ -314,16 +310,6 @@ static inline void ospf_pkt_set_instance_id(struct ospf_packet *pkt, u16 val)
{ pkt->vdep = htons(val << 8); } { 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_RT 0x2001
#define LSA_T_NET 0x2002 #define LSA_T_NET 0x2002
#define LSA_T_SUM_NET 0x2003 #define LSA_T_SUM_NET 0x2003
@ -524,6 +510,12 @@ lsa_net_count(struct ospf_lsa_header *lsa)
/ sizeof(u32); / 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_SPACE(x) ((((x) + 63) / 32) * 4)
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32) #define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
@ -723,6 +715,7 @@ struct proto_ospf
list area_list; list area_list;
int areano; /* Number of area I belong to */ int areano; /* Number of area I belong to */
struct fib rtf; /* Routing table */ struct fib rtf; /* Routing table */
byte ospf2; /* OSPF v2 or v3 */
byte rfc1583; /* RFC1583 compatibility */ byte rfc1583; /* RFC1583 compatibility */
byte ebit; /* Did I originate any ext lsa? */ byte ebit; /* Did I originate any ext lsa? */
byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
@ -776,26 +769,32 @@ void schedule_rtcalc(struct proto_ospf *po);
void schedule_net_lsa(struct ospf_iface *ifa); void schedule_net_lsa(struct ospf_iface *ifa);
static inline int ospf_is_v2(struct proto_ospf *po) 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) 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) 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); } { if (ospf_is_v2(po)) lsa_set_options(lsa, options); }
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid); struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
static inline struct ospf_area *ospf_main_area(struct proto_ospf *po) static inline struct ospf_area *ospf_main_area(struct proto_ospf *po)
{ return (po->areano == 1) ? HEAD(po->area_list) : po->backbone; } { return (po->areano == 1) ? HEAD(po->area_list) : po->backbone; }
static inline int oa_is_stub(struct ospf_area *oa) static inline int oa_is_stub(struct ospf_area *oa)
{ return (oa->options & (OPT_E | OPT_N)) == 0; } { return (oa->options & (OPT_E | OPT_N)) == 0; }
static inline int oa_is_ext(struct ospf_area *oa) static inline int oa_is_ext(struct ospf_area *oa)
{ return oa->options & OPT_E; } { return oa->options & OPT_E; }
static inline int oa_is_nssa(struct ospf_area *oa) static inline int oa_is_nssa(struct ospf_area *oa)
{ return oa->options & OPT_N; } { return oa->options & OPT_N; }
void schedule_link_lsa(struct ospf_iface *ifa); // XXXX caller ?? void schedule_link_lsa(struct ospf_iface *ifa); // XXXX caller ??
void ospf_sh_neigh(struct proto *p, char *iff); void ospf_sh_neigh(struct proto *p, char *iff);

View File

@ -2,6 +2,8 @@
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 1999--2005 Ondrej Filip <feela@network.cz> * (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. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
@ -18,7 +20,7 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
pkt = (struct ospf_packet *) buf; pkt = (struct ospf_packet *) buf;
pkt->version = OSPF_VERSION; pkt->version = ospf_get_version(po);
pkt->type = h_type; pkt->type = h_type;
@ -334,7 +336,7 @@ ospf_rx_hook(sock *sk, int size)
return 1; 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); log(L_ERR "%s%I - version %u", mesg, sk->faddr, pkt->version);
return 1; return 1;

View File

@ -21,9 +21,7 @@ void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
void ospf_send_to_bdr(struct ospf_iface *ifa); void ospf_send_to_bdr(struct ospf_iface *ifa);
static inline void ospf_send_to_all(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) static inline void ospf_send_to_des(struct ospf_iface *ifa)
{ {
@ -33,14 +31,22 @@ static inline void ospf_send_to_des(struct ospf_iface *ifa)
ospf_send_to_bdr(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 unsigned
ospf_pkt_bufsize(struct ospf_iface *ifa) static inline void * ospf_tx_buffer(struct ospf_iface *ifa)
{ return ifa->sk->tbuf; }
static inline unsigned ospf_pkt_bufsize(struct ospf_iface *ifa)
{ {
/* Reserve buffer space for authentication footer */ /* Reserve buffer space for authentication footer */
return ifa->sk->tbsize - unsigned res_size = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
(ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0; return ifa->sk->tbsize - res_size;
} }

View File

@ -1,9 +1,11 @@
/* /*
* 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" #include "ospf.h"
@ -13,10 +15,6 @@ static void add_cand(list * l, struct top_hash_entry *en,
struct ospf_area *oa, int i); struct ospf_area *oa, int i);
static void rt_sync(struct proto_ospf *po); 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) static inline void reset_ri(ort *ort)
{ {

View File

@ -3,6 +3,8 @@
* *
* (c) 1999 Martin Mares <mj@ucw.cz> * (c) 1999 Martin Mares <mj@ucw.cz>
* (c) 1999--2004 Ondrej Filip <feela@network.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. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
@ -24,12 +26,6 @@ void originate_prefix_rt_lsa(struct ospf_area *oa);
void originate_prefix_net_lsa(struct ospf_iface *ifa); void originate_prefix_net_lsa(struct ospf_iface *ifa);
void flush_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 static inline u32
fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn) fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
@ -75,7 +71,7 @@ fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
if (ospf_is_v3(po)) if (ospf_is_v3(po))
return fn->uid; return fn->uid;
u32 id = _I(fn->prefix); u32 id = ipa_to_u32(fn->prefix);
if ((po->rfc1583) || (fn->pxlen == 0) || (fn->pxlen == 32)) if ((po->rfc1583) || (fn->pxlen == 0) || (fn->pxlen == 32))
return id; return id;
@ -760,7 +756,6 @@ originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric)
OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)",
fn->prefix, fn->pxlen, metric); fn->prefix, fn->pxlen, metric);
/* options argument is used in ORT_NET and OSPFv3 only */
lsa.age = 0; lsa.age = 0;
lsa.type_raw = LSA_T_SUM_NET; lsa.type_raw = LSA_T_SUM_NET;
lsa.id = fibnode_to_lsaid(po, fn); lsa.id = fibnode_to_lsaid(po, fn);
@ -999,24 +994,10 @@ find_surrogate_fwaddr(struct ospf_area *oa)
(ifa->type == OSPF_IT_VLINK)) (ifa->type == OSPF_IT_VLINK))
continue; continue;
#ifdef OSPFv2 if (ospf_is_v2(po))
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; a = ifa->addr;
cur_np = np; if (a->flags & IA_PEER)
}
#else /* OSPFv3 */
WALK_LIST(a, ifa->iface->addrs)
{
if ((a->flags & IA_SECONDARY) ||
(a->flags & IA_PEER) ||
(a->scope <= SCOPE_LINK))
continue; continue;
np = ((a->flags & IA_HOST) || ifa->stub) ? 2 : 1; np = ((a->flags & IA_HOST) || ifa->stub) ? 2 : 1;
@ -1026,7 +1007,23 @@ find_surrogate_fwaddr(struct ospf_area *oa)
cur_np = np; 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 cur_addr ? cur_addr->ip : IPA_NONE;
@ -1637,71 +1634,66 @@ ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
return e; return e;
} }
/* In OSPFv2, lsa.id is the same as lsa.rt for router LSA. In OSPFv3, we don't know
#ifdef OSPFv2 lsa.id when looking for router LSAs. We return matching LSA with smallest lsa.id. */
/* 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. */
struct top_hash_entry * struct top_hash_entry *
ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr) ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
{ {
struct top_hash_entry *rv = NULL; struct top_hash_entry *rv = NULL;
struct top_hash_entry *e; 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) 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 (f->ospf2 && (e->lsa.id == rtr))
if (!rv || e->lsa.id < rv->lsa.id) return e;
rv = e; if (!f->ospf2 && (!rv || e->lsa.id < rv->lsa.id))
e = e->next; rv = e;
} }
e = e->next;
}
return rv; return rv;
} }
static inline struct top_hash_entry * 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; e = e->next;
return e; return e;
} }
struct top_hash_entry * 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; struct top_hash_entry *e;
e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)]; 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 * 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 * struct top_hash_entry *

View File

@ -39,6 +39,7 @@ struct top_graph
pool *pool; /* Pool we allocate from */ pool *pool; /* Pool we allocate from */
slab *hash_slab; /* Slab for hash entries */ slab *hash_slab; /* Slab for hash entries */
struct top_hash_entry **hash_table; /* Hashing (modelled a`la fib) */ 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_size;
unsigned int hash_order; unsigned int hash_order;
unsigned int hash_mask; unsigned int hash_mask;
@ -71,28 +72,21 @@ void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type);
void originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, u32 metric, ip_addr fwaddr, u32 tag, int pbit); 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); 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_net2(struct top_graph *f, u32 domain, u32 id);
struct top_hash_entry * ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif);
static inline struct top_hash_entry * /* In OSPFv2, id is network IP prefix (lsa.id) while lsa.rt field is unknown
ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr) In OSPFv3, id is lsa.rt of DR while nif is neighbor iface id (lsa.id) */
{
return ospf_hash_find(f, domain, rtr, rtr, LSA_T_RT);
}
#else /* OSPFv3 */
static inline struct top_hash_entry * static inline struct top_hash_entry *
ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif) 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_ */ #endif /* _BIRD_OSPF_TOPOLOGY_H_ */