Temporary integrated OSPF commit.

This commit is contained in:
Ondrej Zajicek 2014-06-26 11:58:57 +02:00
parent 9eceab33f9
commit 70945cb645
28 changed files with 5077 additions and 5271 deletions

View file

@ -2332,6 +2332,7 @@ protocol ospf <name> {
tx length <num>; tx length <num>;
type [broadcast|bcast|pointopoint|ptp| type [broadcast|bcast|pointopoint|ptp|
nonbroadcast|nbma|pointomultipoint|ptmp]; nonbroadcast|nbma|pointomultipoint|ptmp];
link lsa suppression <switch>;
strict nonbroadcast <switch>; strict nonbroadcast <switch>;
real broadcast <switch>; real broadcast <switch>;
ptp netmask <switch>; ptp netmask <switch>;
@ -2596,9 +2597,16 @@ protocol ospf <name> {
communication, or if the NBMA network is used as an (possibly communication, or if the NBMA network is used as an (possibly
unnumbered) PtP link. unnumbered) PtP link.
<tag>strict nonbroadcast <M>switch</M></tag> <tag>link lsa suppression <m/switch/</tag>
In OSPFv3, link LSAs are generated for each link, announcing link-local
IPv6 address of the router to its local neighbors. These are useless on
PtP or PtMP networks and this option allows to suppress the link LSA
origination for such interfaces. The option is ignored on other than PtP
or PtMP interfaces. Default value is no.
<tag>strict nonbroadcast <m/switch/</tag>
If set, don't send hello to any undefined neighbor. This switch is If set, don't send hello to any undefined neighbor. This switch is
ignored on other than NBMA or PtMP networks. Default value is no. ignored on other than NBMA or PtMP interfaces. Default value is no.
<tag>real broadcast <m/switch/</tag> <tag>real broadcast <m/switch/</tag>
In <cf/type broadcast/ or <cf/type ptp/ network configuration, OSPF In <cf/type broadcast/ or <cf/type ptp/ network configuration, OSPF

View file

@ -33,6 +33,12 @@
#define ABS(a) ((a)>=0 ? (a) : -(a)) #define ABS(a) ((a)>=0 ? (a) : -(a))
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
#define BIT32_VAL(p) (((u32) 1) << ((p) % 32))
#define BIT32_TEST(b,p) ((b)[(p)/32] & BIT32_VAL(p))
#define BIT32_SET(b,p) ((b)[(p)/32] |= BIT32_VAL(p))
#define BIT32_CLR(b,p) ((b)[(p)/32] &= ~BIT32_VAL(p))
#define BIT32_ZERO(b,l) memset((b), 0, (l)/8)
#ifndef NULL #ifndef NULL
#define NULL ((void *) 0) #define NULL ((void *) 0)
#endif #endif

View file

@ -68,10 +68,12 @@ typedef struct siterator {
#define SNODE (snode *) #define SNODE (snode *)
#define SHEAD(list) ((void *)((list).head)) #define SHEAD(list) ((void *)((list).head))
#define STAIL(list) ((void *)((list).tail)) #define STAIL(list) ((void *)((list).tail))
#define WALK_SLIST(n,list) for(n=SHEAD(list);(SNODE (n))->next; \ #define SNODE_NEXT(n) ((void *)((SNODE (n))->next))
n=(void *)((SNODE (n))->next)) #define SNODE_VALID(n) ((SNODE (n))->next)
#define WALK_SLIST(n,list) for(n=SHEAD(list); SNODE_VALID(n); n=SNODE_NEXT(n))
#define WALK_SLIST_DELSAFE(n,nxt,list) \ #define WALK_SLIST_DELSAFE(n,nxt,list) \
for(n=SHEAD(list); nxt=(void *)((SNODE (n))->next); n=(void *) nxt) for(n=SHEAD(list); nxt=SNODE_NEXT(n); n=(void *) nxt)
#define EMPTY_SLIST(list) (!(list).head->next) #define EMPTY_SLIST(list) (!(list).head->next)
void s_add_tail(slist *, snode *); void s_add_tail(slist *, snode *);

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)
@ -61,12 +48,12 @@ ospf_area_finish(void)
cf_error("Backbone area cannot be stub/NSSA"); cf_error("Backbone area cannot be stub/NSSA");
if (this_area->summary && (this_area->type == OPT_E)) if (this_area->summary && (this_area->type == OPT_E))
cf_error("Only Stub/NSSA areas can use summary propagation"); cf_error("Only stub/NSSA areas can use summary propagation");
if (this_area->default_nssa && ((this_area->type != OPT_N) || ! this_area->summary)) if (this_area->default_nssa && ((this_area->type != OPT_N) || ! this_area->summary))
cf_error("Only NSSA areas with summary propagation can use NSSA default route"); cf_error("Only NSSA areas with summary propagation can use NSSA default route");
if ((this_area->default_cost & LSA_EXT_EBIT) && ! this_area->default_nssa) if ((this_area->default_cost & LSA_EXT3_EBIT) && ! this_area->default_nssa)
cf_error("Only NSSA default route can use type 2 metric"); cf_error("Only NSSA default route can use type 2 metric");
} }
@ -80,15 +67,22 @@ ospf_proto_finish(void)
int areano = 0; int areano = 0;
int backbone = 0; int backbone = 0;
int nssa = 0;
struct ospf_area_config *ac; struct ospf_area_config *ac;
WALK_LIST(ac, cf->area_list) WALK_LIST(ac, cf->area_list)
{ {
areano++; areano++;
if (ac->areaid == 0) if (ac->areaid == 0)
backbone = 1; backbone = 1;
if (ac->type == OPT_N)
nssa = 1;
} }
cf->abr = areano > 1; cf->abr = areano > 1;
/* Route export or NSSA translation (RFC 3101 3.1) */
cf->asbr = (this_proto->out_filter != FILTER_REJECT) || (nssa && cf->abr);
if (cf->abr && !backbone) if (cf->abr && !backbone)
{ {
struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config)); struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config));
@ -101,26 +95,27 @@ ospf_proto_finish(void)
} }
if (!cf->abr && !EMPTY_LIST(cf->vlink_list)) if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
cf_error( "Vlinks cannot be used on single area router"); cf_error("Vlinks cannot be used on single area router");
if (cf->asbr && (areano == 1) && (this_area->type == 0))
cf_error("ASBR must be in non-stub area");
} }
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, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
@ -132,7 +127,7 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL) CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY) CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH) CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
CF_KEYWORDS(SECONDARY, MERGE) CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION)
%type <t> opttext %type <t> opttext
%type <ld> lsadb_args %type <ld> lsadb_args
@ -146,8 +141,8 @@ ospf_proto_start: proto_start OSPF {
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->rfc1583 = DEFAULT_RFC1583; OSPF_CFG->tick = OSPF_DEFAULT_TICK;
OSPF_CFG->tick = DEFAULT_OSPFTICK; OSPF_CFG->ospf2 = OSPF_IS_V2;
} }
; ;
@ -160,7 +155,7 @@ ospf_proto_item:
proto_item proto_item
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; } | RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; } | STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| 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"); }
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; } | MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
| 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"); }
@ -171,9 +166,9 @@ ospf_area_start: AREA idval {
this_area = cfg_allocz(sizeof(struct ospf_area_config)); this_area = cfg_allocz(sizeof(struct ospf_area_config));
add_tail(&OSPF_CFG->area_list, NODE this_area); add_tail(&OSPF_CFG->area_list, NODE this_area);
this_area->areaid = $2; this_area->areaid = $2;
this_area->default_cost = DEFAULT_STUB_COST; this_area->default_cost = OSPF_DEFAULT_STUB_COST;
this_area->type = OPT_E; this_area->type = OPT_E;
this_area->transint = DEFAULT_TRANSINT; this_area->transint = OSPF_DEFAULT_TRANSINT;
init_list(&this_area->patt_list); init_list(&this_area->patt_list);
init_list(&this_area->net_list); init_list(&this_area->net_list);
@ -195,9 +190,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_EXT3_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 '}'
@ -249,10 +244,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
@ -292,18 +287,19 @@ 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"); }
| PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (OSPF_VERSION != 2) cf_error("Real netmask option requires OSPFv2"); } | PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (!ospf_cfg_is_v2()) cf_error("PtP netmask 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 ; }
| STUB bool { OSPF_PATT->stub = $2 ; } | STUB bool { OSPF_PATT->stub = $2 ; }
| 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"); }
| LINK LSA SUPPRESSION bool { OSPF_PATT->link_lsa_suppression = $4; if (!ospf_cfg_is_v3()) cf_error("Link LSA suppression option requires OSPFv3"); }
| NEIGHBORS '{' nbma_list '}' | NEIGHBORS '{' nbma_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 NORMAL { OSPF_PATT->rx_buffer = 0; } | RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
| RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; } | RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
| RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); } | RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
@ -314,7 +310,7 @@ ospf_iface_item:
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; } | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); } | BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
| SECONDARY bool { OSPF_PATT->bsd_secondary = $2; } | SECONDARY bool { OSPF_PATT->bsd_secondary = $2; }
| password_list | password_list { ospf_check_auth(); }
; ;
pref_list: pref_list:
@ -349,7 +345,7 @@ nbma_eligible:
| ELIGIBLE { $$ = 1; } | ELIGIBLE { $$ = 1; }
; ;
nbma_item: IPA nbma_eligible ';' nbma_item: ipa nbma_eligible ';'
{ {
this_nbma = cfg_allocz(sizeof(struct nbma_node)); this_nbma = cfg_allocz(sizeof(struct nbma_node));
add_tail(&OSPF_PATT->nbma_list, NODE this_nbma); add_tail(&OSPF_PATT->nbma_list, NODE this_nbma);
@ -384,11 +380,11 @@ ospf_iface_start:
ospf_instance_id: ospf_instance_id:
/* empty */ /* empty */
| INSTANCE expr { set_instance_id($2); } | INSTANCE expr { OSPF_PATT->instance_id = $2; }
; ;
ospf_iface_patt_list: ospf_iface_patt_list:
iface_patt_list { if (OSPF_VERSION == 3) iface_patt_check(); } ospf_instance_id iface_patt_list { if (ospf_cfg_is_v3()) iface_patt_check(); } ospf_instance_id
; ;
ospf_iface_opts: ospf_iface_opts:

View file

@ -2,6 +2,8 @@
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 1999--2004 Ondrej Filip <feela@network.cz> * (c) 1999--2004 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (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.
*/ */
@ -9,62 +11,185 @@
#include "ospf.h" #include "ospf.h"
#ifdef OSPFv2 struct ospf_dbdes2_packet
struct ospf_dbdes_packet
{ {
struct ospf_packet ospf_packet; struct ospf_packet hdr;
union ospf_auth auth;
u16 iface_mtu; u16 iface_mtu;
u8 options; u8 options;
union imms imms; /* I, M, MS bits */ u8 imms; /* I, M, MS bits */
u32 ddseq; u32 ddseq;
struct ospf_lsa_header lsas[];
}; };
#define hton_opt(X) X struct ospf_dbdes3_packet
#define ntoh_opt(X) X
#endif
#ifdef OSPFv3
struct ospf_dbdes_packet
{ {
struct ospf_packet ospf_packet; struct ospf_packet hdr;
u32 options; u32 options;
u16 iface_mtu; u16 iface_mtu;
u8 padding; u8 padding;
union imms imms; /* I, M, MS bits */ u8 imms; /* I, M, MS bits */
u32 ddseq; u32 ddseq;
struct ospf_lsa_header lsas[];
}; };
#define hton_opt(X) htonl(X)
#define ntoh_opt(X) ntohl(X)
#endif
static inline uint
static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt) ospf_dbdes_hdrlen(struct ospf_proto *p)
{ {
struct ospf_packet *op = &pkt->ospf_packet; return ospf_is_v2(p) ?
sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
ASSERT(op->type == DBDES_P);
ospf_dump_common(p, op);
log(L_TRACE "%s: imms %s%s%s",
p->name, pkt->imms.bit.ms ? "MS " : "",
pkt->imms.bit.m ? "M " : "",
pkt->imms.bit.i ? "I " : "" );
log(L_TRACE "%s: ddseq %u", p->name, ntohl(pkt->ddseq));
struct ospf_lsa_header *plsa = (void *) (pkt + 1);
unsigned int i, j;
j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
sizeof(struct ospf_lsa_header);
for (i = 0; i < j; i++)
ospf_dump_lsahdr(p, plsa + i);
} }
static void
ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
struct ospf_lsa_header **body, uint *count)
{
uint plen = ntohs(pkt->length);
uint hlen = ospf_dbdes_hdrlen(p);
*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)
{
struct ospf_lsa_header *lsas;
uint i, lsa_count;
u32 pkt_ddseq;
u16 pkt_iface_mtu;
u8 pkt_imms;
ASSERT(pkt->type == DBDES_P);
ospf_dump_common(p, pkt);
if (ospf_is_v2(p))
{
struct ospf_dbdes2_packet *ps = (void *) pkt;
pkt_iface_mtu = ntohs(ps->iface_mtu);
pkt_imms = ps->imms;
pkt_ddseq = ntohl(ps->ddseq);
}
else /* OSPFv3 */
{
struct ospf_dbdes3_packet *ps = (void *) pkt;
pkt_iface_mtu = ntohs(ps->iface_mtu);
pkt_imms = ps->imms;
pkt_ddseq = ntohl(ps->ddseq);
}
log(L_TRACE "%s: mtu %u", p->p.name, pkt_iface_mtu);
log(L_TRACE "%s: imms %s%s%s", p->p.name,
(pkt_imms & DBDES_I) ? "I " : "",
(pkt_imms & DBDES_M) ? "M " : "",
(pkt_imms & DBDES_MS) ? "MS" : "");
log(L_TRACE "%s: ddseq %u", p->p.name, pkt_ddseq);
ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
for (i = 0; i < lsa_count; i++)
ospf_dump_lsahdr(p, lsas + i);
}
static void
ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int body)
{
struct ospf_iface *ifa = n->ifa;
struct ospf_packet *pkt;
uint length;
u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
if (n->ldd_bsize != ifa->tx_length)
{
mb_free(n->ldd_buffer);
n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
n->ldd_bsize = ifa->tx_length;
}
pkt = n->ldd_buffer;
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
if (ospf_is_v2(p))
{
struct ospf_dbdes2_packet *ps = (void *) pkt;
ps->iface_mtu = htons(iface_mtu);
ps->options = ifa->oa->options;
ps->imms = 0; /* Will be set later */
ps->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes2_packet);
}
else /* OSPFv3 */
{
struct ospf_dbdes3_packet *ps = (void *) pkt;
ps->options = htonl(ifa->oa->options);
ps->iface_mtu = htons(iface_mtu);
ps->padding = 0;
ps->imms = 0; /* Will be set later */
ps->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes3_packet);
}
if (body && (n->myimms & DBDES_M))
{
struct ospf_lsa_header *lsas;
struct top_hash_entry *en;
uint i = 0, lsa_max;
ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
en = (void *) s_get(&(n->dbsi));
while (i < lsa_max)
{
if (!SNODE_VALID(en))
{
n->myimms &= ~DBDES_M; /* Unset More bit */
break;
}
if ((en->lsa.age < LSA_MAXAGE) &&
lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
{
lsa_hton_hdr(&(en->lsa), lsas + i);
i++;
}
en = SNODE_NEXT(en);
}
s_put(&(n->dbsi), SNODE en);
length += i * sizeof(struct ospf_lsa_header);
}
if (ospf_is_v2(p))
((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
else
((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
pkt->length = htons(length);
}
static void
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);
sk_set_tbuf(ifa->sk, n->ldd_buffer);
ospf_send_to(ifa, n->ip);
sk_set_tbuf(ifa->sk, NULL);
}
/** /**
* ospf_dbdes_send - transmit database description packet * ospf_send_dbdes - transmit database description packet
* @n: neighbor * @n: neighbor
* @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0) * @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0)
* *
@ -75,355 +200,322 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
* of the buffer. * of the buffer.
*/ */
void void
ospf_dbdes_send(struct ospf_neighbor *n, int next) ospf_send_dbdes(struct ospf_neighbor *n, int next)
{ {
struct ospf_dbdes_packet *pkt;
struct ospf_packet *op;
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
struct ospf_area *oa = ifa->oa; struct ospf_area *oa = ifa->oa;
struct proto_ospf *po = oa->po; struct ospf_proto *p = oa->po;
struct proto *p = &po->proto;
u16 length, i, j;
/* FIXME ??? */ /* RFC 2328 10.8 */
if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
update_rt_lsa(oa); if (oa->rt == NULL)
return;
switch (n->state) switch (n->state)
{ {
case NEIGHBOR_EXSTART: /* Send empty packets */ case NEIGHBOR_EXSTART:
n->myimms.bit.i = 1; n->myimms |= DBDES_I;
pkt = ospf_tx_buffer(ifa);
op = &pkt->ospf_packet;
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
pkt->options = hton_opt(oa->options);
pkt->imms = n->myimms;
pkt->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes_packet);
op->length = htons(length);
OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->ifname); /* Send empty packets */
ospf_send_to(ifa, n->ip); ospf_prepare_dbdes(p, n, 0);
ospf_do_send_dbdes(p, n);
break; break;
case NEIGHBOR_EXCHANGE: case NEIGHBOR_EXCHANGE:
n->myimms.bit.i = 0; n->myimms &= ~DBDES_I;
if (next) if (next)
{ ospf_prepare_dbdes(p, n, 1);
snode *sn;
struct ospf_lsa_header *lsa;
if (n->ldd_bsize != ifa->tx_length) /* Send prepared packet */
{ ospf_do_send_dbdes(p, n);
mb_free(n->ldd_buffer);
n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
n->ldd_bsize = ifa->tx_length;
}
pkt = n->ldd_buffer; /* Master should restart RXMT timer for each DBDES exchange */
op = (struct ospf_packet *) pkt; if (n->myimms & DBDES_MS)
tm_start(n->rxmt_timer, n->ifa->rxmtint);
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); if (!(n->myimms & DBDES_MS))
pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu); if (!(n->myimms & DBDES_M) &&
pkt->ddseq = htonl(n->dds); !(n->imms & DBDES_M))
pkt->options = hton_opt(oa->options); ospf_neigh_sm(n, INM_EXDONE);
break;
j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */
lsa = (n->ldd_buffer + sizeof(struct ospf_dbdes_packet));
if (n->myimms.bit.m)
{
sn = s_get(&(n->dbsi));
DBG("Number of LSA: %d\n", j);
for (; i > 0; i--)
{
struct top_hash_entry *en= (struct top_hash_entry *) sn;
if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
{
htonlsah(&(en->lsa), lsa);
DBG("Working on: %d\n", i);
DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body);
lsa++;
}
else i++; /* No lsa added */
if (sn == STAIL(po->lsal))
{
i--;
break;
}
sn = sn->next;
}
if (sn == STAIL(po->lsal))
{
DBG("Number of LSA NOT sent: %d\n", i);
DBG("M bit unset.\n");
n->myimms.bit.m = 0; /* Unset more bit */
}
s_put(&(n->dbsi), sn);
}
pkt->imms.byte = n->myimms.byte;
length = (j - i) * sizeof(struct ospf_lsa_header) +
sizeof(struct ospf_dbdes_packet);
op->length = htons(length);
DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip);
}
case NEIGHBOR_LOADING: case NEIGHBOR_LOADING:
case NEIGHBOR_FULL: case NEIGHBOR_FULL:
length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0;
if (!length) if (!n->ldd_buffer)
{ {
OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating"); OSPF_TRACE(D_PACKETS, "No DBDES packet for repeating");
ospf_neigh_sm(n, INM_KILLNBR); ospf_neigh_sm(n, INM_KILLNBR);
return; return;
} }
/* Send last packet from ldd buffer */ /* Send last packet */
ospf_do_send_dbdes(p, n);
OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
sk_set_tbuf(ifa->sk, n->ldd_buffer);
ospf_send_to(ifa, n->ip);
sk_set_tbuf(ifa->sk, NULL);
if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */
if (!n->myimms.bit.ms)
{
if ((n->myimms.bit.m == 0) && (n->imms.bit.m == 0) &&
(n->state == NEIGHBOR_EXCHANGE))
{
ospf_neigh_sm(n, INM_EXDONE);
}
}
break;
default: /* Ignore it */
break; break;
} }
} }
static void
ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n) static int
ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
{ {
struct ospf_lsa_header *plsa, lsa; struct ospf_iface *ifa = n->ifa;
struct top_hash_entry *he, *sn; struct ospf_lsa_header *lsas;
struct ospf_area *oa = n->ifa->oa; uint i, lsa_count;
struct top_graph *gr = oa->po->gr;
struct ospf_packet *op;
int i, j;
op = (struct ospf_packet *) ps; ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
plsa = (void *) (ps + 1); for (i = 0; i < lsa_count; i++)
j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
sizeof(struct ospf_lsa_header);
for (i = 0; i < j; i++)
{ {
ntohlsah(plsa + i, &lsa); struct top_hash_entry *en, *req;
u32 dom = ospf_lsa_domain(lsa.type, n->ifa); struct ospf_lsa_header lsa;
if (((he = ospf_hash_find_header(gr, dom, &lsa)) == NULL) || u32 lsa_type, lsa_domain;
(lsa_comp(&lsa, &(he->lsa)) == 1))
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)
{ {
/* Is this condition necessary? */ log(L_WARN "%s: Bad DBDES from %I - LSA of unknown type", p->p.name, n->ip);
if (ospf_hash_find_header(n->lsrqh, dom, &lsa) == NULL) goto err;
{ }
sn = ospf_hash_get_header(n->lsrqh, dom, &lsa);
ntohlsah(plsa + i, &(sn->lsa)); if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
s_add_tail(&(n->lsrql), SNODE sn); {
} log(L_WARN "%s: Bad DBDES from %I - LSA with AS scope in stub area", p->p.name, n->ip);
goto err;
}
/* 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;
}
/* 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;
}
en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
{
req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
if (!SNODE_VALID(req))
s_add_tail(&n->lsrql, SNODE req);
req->lsa = lsa;
} }
} }
return 0;
err:
ospf_neigh_sm(n, INM_SEQMIS);
return -1;
} }
void void
ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n) struct ospf_neighbor *n)
{ {
struct proto_ospf *po = ifa->oa->po; struct ospf_proto *p = ifa->oa->po;
struct proto *p = &po->proto; u32 rcv_ddseq, rcv_options;
u16 rcv_iface_mtu;
u8 rcv_imms;
uint plen;
unsigned int size = ntohs(ps_i->length); /* RFC 2328 10.6 */
if (size < sizeof(struct ospf_dbdes_packet))
plen = ntohs(pkt->length);
if (plen < ospf_dbdes_hdrlen(p))
{ {
log(L_ERR "Bad OSPF DBDES packet from %I - too short (%u B)", n->ip, size); log(L_ERR "OSPF: Bad DBDES packet from %I - too short (%u B)", n->ip, plen);
return; return;
} }
struct ospf_dbdes_packet *ps = (void *) ps_i; OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from %I via %s", n->ip, ifa->ifname);
u32 ps_ddseq = ntohl(ps->ddseq);
u32 ps_options = ntoh_opt(ps->options);
u16 ps_iface_mtu = ntohs(ps->iface_mtu);
OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->ifname);
ospf_neigh_sm(n, INM_HELLOREC); ospf_neigh_sm(n, INM_HELLOREC);
if (ospf_is_v2(p))
{
struct ospf_dbdes2_packet *ps = (void *) pkt;
rcv_iface_mtu = ntohs(ps->iface_mtu);
rcv_options = ps->options;
rcv_imms = ps->imms;
rcv_ddseq = ntohl(ps->ddseq);
}
else /* OSPFv3 */
{
struct ospf_dbdes3_packet *ps = (void *) pkt;
rcv_options = ntohl(ps->options);
rcv_iface_mtu = ntohs(ps->iface_mtu);
rcv_imms = ps->imms;
rcv_ddseq = ntohl(ps->ddseq);
}
switch (n->state) switch (n->state)
{ {
case NEIGHBOR_DOWN: case NEIGHBOR_DOWN:
case NEIGHBOR_ATTEMPT: case NEIGHBOR_ATTEMPT:
case NEIGHBOR_2WAY: case NEIGHBOR_2WAY:
return; return;
break;
case NEIGHBOR_INIT: case NEIGHBOR_INIT:
ospf_neigh_sm(n, INM_2WAYREC); ospf_neigh_sm(n, INM_2WAYREC);
if (n->state != NEIGHBOR_EXSTART) if (n->state != NEIGHBOR_EXSTART)
return; return;
case NEIGHBOR_EXSTART: case NEIGHBOR_EXSTART:
if ((ifa->type != OSPF_IT_VLINK) &&
(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);
if ((ifa->type != OSPF_IT_VLINK) && (ps_iface_mtu != ifa->iface->mtu) if ((rcv_imms == DBDES_IMMS) &&
&& (ps_iface_mtu != 0) && (ifa->iface->mtu != 0)) (n->rid > p->router_id) &&
log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)", (plen == ospf_dbdes_hdrlen(p)))
n->ip, ifa->ifname, ps_iface_mtu, ifa->iface->mtu);
if ((ps->imms.bit.m && ps->imms.bit.ms && ps->imms.bit.i)
&& (n->rid > po->router_id) && (size == sizeof(struct ospf_dbdes_packet)))
{ {
/* I'm slave! */ /* I'm slave! */
n->dds = ps_ddseq; n->dds = rcv_ddseq;
n->ddr = ps_ddseq; n->ddr = rcv_ddseq;
n->options = ps_options; n->options = rcv_options;
n->myimms.bit.ms = 0; n->myimms &= ~DBDES_MS;
n->imms.byte = ps->imms.byte; n->imms = rcv_imms;
OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip); OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip);
ospf_neigh_sm(n, INM_NEGDONE); ospf_neigh_sm(n, INM_NEGDONE);
ospf_dbdes_send(n, 1); ospf_send_dbdes(n, 1);
break; break;
} }
if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) && if (!(rcv_imms & DBDES_I) &&
(n->rid < po->router_id) && (n->dds == ps_ddseq)) !(rcv_imms & DBDES_MS) &&
(n->rid < p->router_id) &&
(n->dds == rcv_ddseq))
{ {
/* I'm master! */ /* I'm master! */
n->options = ps_options; n->options = rcv_options;
n->ddr = ps_ddseq - 1; /* It will be set corectly a few lines down */ n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */
n->imms.byte = ps->imms.byte; n->imms = rcv_imms;
OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip); OSPF_TRACE(D_PACKETS, "I'm master to %I", n->ip);
ospf_neigh_sm(n, INM_NEGDONE); ospf_neigh_sm(n, INM_NEGDONE);
} }
else else
{ {
DBG("%s: Nothing happend to %I (imms=%u)\n", p->name, n->ip, DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
ps->imms.byte);
break; break;
} }
case NEIGHBOR_EXCHANGE: case NEIGHBOR_EXCHANGE:
if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) && if ((rcv_imms == n->imms) &&
(ps_ddseq == n->ddr)) (rcv_options == n->options) &&
(rcv_ddseq == n->ddr))
{ {
/* Duplicate packet */ /* Duplicate packet */
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip);
if (n->myimms.bit.ms == 0) if (!(n->myimms & DBDES_MS))
{ {
/* Slave should retransmit dbdes packet */ /* Slave should retransmit dbdes packet */
ospf_dbdes_send(n, 0); ospf_send_dbdes(n, 0);
} }
return; return;
} }
n->ddr = ps_ddseq; if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS)) /* M/S bit differs */
if (ps->imms.bit.ms != n->imms.bit.ms) /* M/S bit differs */
{ {
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)", OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)", n->ip);
n->ip);
ospf_neigh_sm(n, INM_SEQMIS); ospf_neigh_sm(n, INM_SEQMIS);
break; break;
} }
if (ps->imms.bit.i) /* I bit is set */ if (rcv_imms & DBDES_I) /* I bit is set */
{ {
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)", OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)", n->ip);
n->ip);
ospf_neigh_sm(n, INM_SEQMIS); ospf_neigh_sm(n, INM_SEQMIS);
break; break;
} }
n->imms.byte = ps->imms.byte; if (rcv_options != n->options) /* Options differs */
if (ps_options != n->options) /* Options differs */
{ {
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)", OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)", n->ip);
n->ip);
ospf_neigh_sm(n, INM_SEQMIS); ospf_neigh_sm(n, INM_SEQMIS);
break; break;
} }
if (n->myimms.bit.ms) n->ddr = rcv_ddseq;
n->imms = rcv_imms;
if (n->myimms & DBDES_MS)
{ {
if (ps_ddseq != n->dds) /* MASTER */ if (rcv_ddseq != n->dds) /* MASTER */
{ {
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)", OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)", n->ip);
n->ip);
ospf_neigh_sm(n, INM_SEQMIS); ospf_neigh_sm(n, INM_SEQMIS);
break; break;
} }
n->dds++;
DBG("Incrementing dds\n");
ospf_dbdes_reqladd(ps, n);
if ((n->myimms.bit.m == 0) && (ps->imms.bit.m == 0))
{
ospf_neigh_sm(n, INM_EXDONE);
}
else
{
ospf_dbdes_send(n, 1);
}
n->dds++;
if (ospf_process_dbdes(p, pkt, n) < 0)
return;
if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
ospf_neigh_sm(n, INM_EXDONE);
else
ospf_send_dbdes(n, 1);
} }
else else
{ {
if (ps_ddseq != (n->dds + 1)) /* SLAVE */ if (rcv_ddseq != (n->dds + 1)) /* SLAVE */
{ {
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", n->ip); OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", n->ip);
ospf_neigh_sm(n, INM_SEQMIS); ospf_neigh_sm(n, INM_SEQMIS);
break; break;
} }
n->ddr = ps_ddseq;
n->dds = ps_ddseq;
ospf_dbdes_reqladd(ps, n);
ospf_dbdes_send(n, 1);
}
n->ddr = rcv_ddseq;
n->dds = rcv_ddseq;
if (ospf_process_dbdes(p, pkt, n) < 0)
return;
ospf_send_dbdes(n, 1);
}
break; break;
case NEIGHBOR_LOADING: case NEIGHBOR_LOADING:
case NEIGHBOR_FULL: case NEIGHBOR_FULL:
if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) if ((rcv_imms == n->imms) &&
&& (ps_ddseq == n->ddr)) (rcv_options == n->options) &&
/* Only duplicate are accepted */ (rcv_ddseq == n->ddr))
{ {
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); /* Duplicate packet */
if (n->myimms.bit.ms == 0) OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip);
if (!(n->myimms & DBDES_MS))
{ {
/* Slave should retransmit dbdes packet */ /* Slave should retransmit dbdes packet */
ospf_dbdes_send(n, 0); ospf_send_dbdes(n, 0);
} }
return; return;
} }
else else
{ {
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)", OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)", n->ip);
n->ip); DBG("PS=%u, DDR=%u, DDS=%u\n", rcv_ddseq, n->ddr, n->dds);
DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds);
ospf_neigh_sm(n, INM_SEQMIS); ospf_neigh_sm(n, INM_SEQMIS);
} }
break; break;
default: default:
bug("Received dbdes from %I in undefined state.", n->ip); bug("Received dbdes from %I in undefined state.", n->ip);
} }

View file

@ -1,17 +0,0 @@
/*
* BIRD -- OSPF
*
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_DBDES_H_
#define _BIRD_OSPF_DBDES_H_
void ospf_dbdes_send(struct ospf_neighbor *n, int next);
void ospf_dbdes_receive(struct ospf_packet *ps, struct ospf_iface *ifa,
struct ospf_neighbor *n);
#endif /* _BIRD_OSPF_DBDES_H_ */

View file

@ -2,6 +2,8 @@
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 1999--2004 Ondrej Filip <feela@network.cz> * (c) 1999--2004 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (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.
*/ */
@ -9,25 +11,26 @@
#include "ospf.h" #include "ospf.h"
#ifdef OSPFv2 struct ospf_hello2_packet
struct ospf_hello_packet
{ {
struct ospf_packet ospf_packet; struct ospf_packet hdr;
ip_addr netmask; union ospf_auth auth;
u32 netmask;
u16 helloint; u16 helloint;
u8 options; u8 options;
u8 priority; u8 priority;
u32 deadint; u32 deadint;
u32 dr; u32 dr;
u32 bdr; u32 bdr;
u32 neighbors[];
}; };
#endif
struct ospf_hello3_packet
#ifdef OSPFv3
struct ospf_hello_packet
{ {
struct ospf_packet ospf_packet; struct ospf_packet hdr;
u32 iface_id; u32 iface_id;
u8 priority; u8 priority;
u8 options3; u8 options3;
@ -37,286 +40,92 @@ struct ospf_hello_packet
u16 deadint; u16 deadint;
u32 dr; u32 dr;
u32 bdr; u32 bdr;
u32 neighbors[];
}; };
#endif
void void
ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
struct ospf_neighbor *n, ip_addr faddr)
{ {
struct proto_ospf *po = ifa->oa->po; struct ospf_proto *p = ifa->oa->po;
struct proto *p = &po->proto; struct ospf_packet *pkt;
char *beg = "OSPF: Bad HELLO packet from ";
unsigned int size, i, twoway, peers;
u32 tmp;
u32 *pnrid;
size = ntohs(ps_i->length);
if (size < sizeof(struct ospf_hello_packet))
{
log(L_ERR "%s%I - too short (%u B)", beg, faddr, size);
return;
}
struct ospf_hello_packet *ps = (void *) ps_i;
OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s", faddr, ifa->ifname);
#ifdef OSPFv2
ip_addr mask = ps->netmask;
ipa_ntoh(mask);
if ((ifa->type != OSPF_IT_VLINK) &&
(ifa->type != OSPF_IT_PTP) &&
!ipa_equal(mask, ipa_mkmask(ifa->addr->pxlen)))
{
log(L_ERR "%s%I - netmask mismatch (%I)", beg, faddr, mask);
return;
}
#endif
tmp = ntohs(ps->helloint);
if (tmp != ifa->helloint)
{
log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, tmp);
return;
}
#ifdef OSPFv2
tmp = ntohl(ps->deadint);
#else /* OSPFv3 */
tmp = ntohs(ps->deadint);
#endif
if (tmp != ifa->deadint)
{
log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
return;
}
/* Check whether bits E, N match */
if ((ps->options ^ ifa->oa->options) & (OPT_E | OPT_N))
{
log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, ps->options);
return;
}
#ifdef OSPFv2
if (n && (n->rid != ntohl(ps_i->routerid)))
{
OSPF_TRACE(D_EVENTS,
"Neighbor %I has changed router id from %R to %R.",
n->ip, n->rid, ntohl(ps_i->routerid));
ospf_neigh_remove(n);
n = NULL;
}
#endif
if (!n)
{
if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
{
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;
}
if (nn && (ifa->type == OSPF_IT_NBMA) &&
(((ps->priority == 0) && nn->eligible) ||
((ps->priority > 0) && !nn->eligible)))
{
log(L_ERR "Eligibility mismatch for neighbor: %I on %s", faddr, ifa->ifname);
return;
}
if (nn)
nn->found = 1;
}
OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr, ifa->ifname);
n = ospf_neighbor_new(ifa);
n->rid = ntohl(ps_i->routerid);
n->ip = faddr;
n->dr = ntohl(ps->dr);
n->bdr = ntohl(ps->bdr);
n->priority = ps->priority;
#ifdef OSPFv3
n->iface_id = ntohl(ps->iface_id);
#endif
if (n->ifa->cf->bfd)
ospf_neigh_update_bfd(n, n->ifa->bfd);
}
#ifdef OSPFv3 /* NOTE: this could also be relevant for OSPFv2 on PtP ifaces */
else if (!ipa_equal(faddr, n->ip))
{
OSPF_TRACE(D_EVENTS, "Neighbor address changed from %I to %I", n->ip, faddr);
n->ip = faddr;
}
#endif
ospf_neigh_sm(n, INM_HELLOREC);
pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32);
twoway = 0;
for (i = 0; i < peers; i++)
{
if (ntohl(pnrid[i]) == po->router_id)
{
DBG("%s: Twoway received from %I\n", p->name, faddr);
ospf_neigh_sm(n, INM_2WAYREC);
twoway = 1;
break;
}
}
if (!twoway)
ospf_neigh_sm(n, INM_1WAYREC);
u32 olddr = n->dr;
u32 oldbdr = n->bdr;
u32 oldpriority = n->priority;
#ifdef OSPFv3
u32 oldiface_id = n->iface_id;
#endif
n->dr = ntohl(ps->dr);
n->bdr = ntohl(ps->bdr);
n->priority = ps->priority;
#ifdef OSPFv3
n->iface_id = ntohl(ps->iface_id);
#endif
/* Check priority change */
if (n->state >= NEIGHBOR_2WAY)
{
#ifdef OSPFv2
u32 neigh = ipa_to_u32(n->ip);
#else /* OSPFv3 */
u32 neigh = n->rid;
#endif
if (n->priority != oldpriority)
ospf_iface_sm(ifa, ISM_NEICH);
#ifdef OSPFv3
if (n->iface_id != oldiface_id)
ospf_iface_sm(ifa, ISM_NEICH);
#endif
/* Neighbor is declaring itself ad DR and there is no BDR */
if ((n->dr == neigh) && (n->bdr == 0)
&& (n->state != NEIGHBOR_FULL))
ospf_iface_sm(ifa, ISM_BACKS);
/* Neighbor is declaring itself as BDR */
if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL))
ospf_iface_sm(ifa, ISM_BACKS);
/* Neighbor is newly declaring itself as DR or BDR */
if (((n->dr == neigh) && (n->dr != olddr))
|| ((n->bdr == neigh) && (n->bdr != oldbdr)))
ospf_iface_sm(ifa, ISM_NEICH);
/* Neighbor is no more declaring itself as DR or BDR */
if (((olddr == neigh) && (n->dr != olddr))
|| ((oldbdr == neigh) && (n->bdr != oldbdr)))
ospf_iface_sm(ifa, ISM_NEICH);
}
if (ifa->type == OSPF_IT_NBMA)
{
if ((ifa->priority == 0) && (n->priority > 0))
ospf_hello_send(n->ifa, OHS_HELLO, n);
}
ospf_neigh_sm(n, INM_HELLOREC);
}
void
ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
{
struct ospf_hello_packet *pkt;
struct ospf_packet *op;
struct proto *p;
struct ospf_neighbor *neigh, *n1; struct ospf_neighbor *neigh, *n1;
u16 length;
int i;
struct nbma_node *nb; struct nbma_node *nb;
u32 *neighbors;
uint length;
int i, max;
if (ifa->state <= OSPF_IS_LOOP) if (ifa->state <= OSPF_IS_LOOP)
return; return;
if (ifa->stub) if (ifa->stub)
return; /* Don't send any packet on stub iface */ return;
p = (struct proto *) (ifa->oa->po);
DBG("%s: Hello/Poll timer fired on interface %s with IP %I\n",
p->name, ifa->ifname, ifa->addr->ip);
/* Now we should send a hello packet */
pkt = ospf_tx_buffer(ifa); pkt = ospf_tx_buffer(ifa);
op = &pkt->ospf_packet;
/* Now fill ospf_hello header */
ospf_pkt_fill_hdr(ifa, pkt, HELLO_P); ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
#ifdef OSPFv2 if (ospf_is_v2(p))
pkt->netmask = ipa_mkmask(ifa->addr->pxlen); {
ipa_hton(pkt->netmask); struct ospf_hello2_packet *ps = (void *) pkt;
if ((ifa->type == OSPF_IT_VLINK) ||
((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
pkt->netmask = IPA_NONE;
#endif
pkt->helloint = ntohs(ifa->helloint); if ((ifa->type == OSPF_IT_VLINK) ||
pkt->priority = ifa->priority; ((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
ps->netmask = 0;
else
ps->netmask = htonl(u32_mkmask(ifa->addr->pxlen));
#ifdef OSPFv3 ps->helloint = ntohs(ifa->helloint);
pkt->iface_id = htonl(ifa->iface_id); ps->options = ifa->oa->options;
ps->priority = ifa->priority;
ps->deadint = htonl(ifa->deadint);
ps->dr = htonl(ipa_to_u32(ifa->drip));
ps->bdr = htonl(ipa_to_u32(ifa->bdrip));
pkt->options3 = ifa->oa->options >> 16; length = sizeof(struct ospf_hello2_packet);
pkt->options2 = ifa->oa->options >> 8; neighbors = ps->neighbors;
#endif }
pkt->options = ifa->oa->options; else
{
struct ospf_hello3_packet *ps = (void *) pkt;
#ifdef OSPFv2 ps->iface_id = htonl(ifa->iface_id);
pkt->deadint = htonl(ifa->deadint); ps->priority = ifa->priority;
pkt->dr = htonl(ipa_to_u32(ifa->drip)); ps->options3 = ifa->oa->options >> 16;
pkt->bdr = htonl(ipa_to_u32(ifa->bdrip)); ps->options2 = ifa->oa->options >> 8;
#else /* OSPFv3 */ ps->options = ifa->oa->options;
pkt->deadint = htons(ifa->deadint); ps->helloint = ntohs(ifa->helloint);
pkt->dr = htonl(ifa->drid); ps->deadint = htons(ifa->deadint);
pkt->bdr = htonl(ifa->bdrid); ps->dr = htonl(ifa->drid);
#endif ps->bdr = htonl(ifa->bdrid);
length = sizeof(struct ospf_hello3_packet);
neighbors = ps->neighbors;
}
i = 0;
max = (ospf_pkt_maxsize(ifa) - length) / sizeof(u32);
/* Fill all neighbors */ /* Fill all neighbors */
i = 0;
if (kind != OHS_SHUTDOWN) if (kind != OHS_SHUTDOWN)
{ {
u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
WALK_LIST(neigh, ifa->neigh_list) WALK_LIST(neigh, ifa->neigh_list)
{ {
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa)) if (i == max)
{ {
log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->ifname); log(L_WARN "%s: Too many neighbors on interface %s", p->p.name, ifa->ifname);
break; break;
} }
*(pp + i) = htonl(neigh->rid); neighbors[i] = htonl(neigh->rid);
i++; i++;
} }
} }
length = sizeof(struct ospf_hello_packet) + i * sizeof(u32); length += i * sizeof(u32);
op->length = htons(length); pkt->length = htons(length);
OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
switch(ifa->type) switch(ifa->type)
{ {
@ -369,8 +178,226 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
break; break;
default: default:
bug("Bug in ospf_hello_send()"); bug("Bug in ospf_send_hello()");
}
}
void
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 ";
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;
/* RFC 2328 10.5 */
OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s", faddr, ifa->ifname);
plen = ntohs(pkt->length);
if (ospf_is_v2(p))
{
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;
}
rcv_iface_id = 0;
rcv_helloint = ntohs(ps->helloint);
rcv_deadint = ntohl(ps->deadint);
rcv_dr = ntohl(ps->dr);
rcv_bdr = ntohl(ps->bdr);
rcv_options = ps->options;
rcv_priority = ps->priority;
int pxlen = u32_masklen(ntohl(ps->netmask));
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;
}
neighbors = ps->neighbors;
neigh_count = (plen - sizeof(struct ospf_hello2_packet)) / sizeof(u32);
}
else /* OSPFv3 */
{
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;
}
rcv_iface_id = ntohl(ps->iface_id);
rcv_helloint = ntohs(ps->helloint);
rcv_deadint = ntohs(ps->deadint);
rcv_dr = ntohl(ps->dr);
rcv_bdr = ntohl(ps->bdr);
rcv_options = ps->options;
rcv_priority = ps->priority;
neighbors = ps->neighbors;
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
} }
OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname); if (rcv_helloint != ifa->helloint)
{
log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, rcv_helloint);
return;
}
if (rcv_deadint != ifa->deadint)
{
log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, rcv_deadint);
return;
}
/* 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;
}
/* Check consistency of existing neighbor entry */
if (n)
{
unsigned 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 */
if (n->rid != ntohl(pkt->routerid))
{
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);
n = NULL;
}
}
else /* OSPFv3 or OSPFv2/PtP */
{
/* 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);
n->ip = faddr;
}
}
}
if (!n)
{
if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
{
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;
}
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;
}
if (nn)
nn->found = 1;
}
OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr, ifa->ifname);
n = ospf_neighbor_new(ifa);
n->rid = ntohl(pkt->routerid);
n->ip = faddr;
n->dr = rcv_dr;
n->bdr = rcv_bdr;
n->priority = rcv_priority;
n->iface_id = rcv_iface_id;
if (n->ifa->cf->bfd)
ospf_neigh_update_bfd(n, n->ifa->bfd);
}
u32 n_id = ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid;
u32 old_dr = n->dr;
u32 old_bdr = n->bdr;
u32 old_priority = n->priority;
u32 old_iface_id = n->iface_id;
n->dr = rcv_dr;
n->bdr = rcv_bdr;
n->priority = rcv_priority;
n->iface_id = rcv_iface_id;
/* Update inactivity timer */
ospf_neigh_sm(n, INM_HELLOREC);
/* RFC 2328 9.5.1 - non-eligible routers reply to hello on NBMA nets */
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++)
if (neighbors[i] == htonl(p->router_id))
goto found_self;
ospf_neigh_sm(n, INM_1WAYREC);
return;
found_self:
ospf_neigh_sm(n, INM_2WAYREC);
if (n->iface_id != old_iface_id)
{
/* If neighbor is DR, also update cached DR interface ID */
if (ifa->drid == n->rid)
ifa->dr_iface_id = n->iface_id;
/* RFC 5340 4.4.3 Event 4 - change of neighbor's interface ID */
ospf_notify_rt_lsa(ifa->oa);
/* Missed in RFC 5340 4.4.3 Event 4 - (Px-)Net-LSA uses iface_id to ref Link-LSAs */
ospf_notify_net_lsa(ifa);
}
if (ifa->state == OSPF_IS_WAITING)
{
/* Neighbor is declaring itself DR (and there is no BDR) or as BDR */
if (((n->dr == n_id) && (n->bdr == 0)) || (n->bdr == n_id))
ospf_iface_sm(ifa, ISM_BACKS);
}
else if (ifa->state >= OSPF_IS_DROTHER)
{
/* Neighbor changed priority or started/stopped declaring itself as DR/BDR */
if ((n->priority != old_priority) ||
((n->dr == n_id) && (old_dr != n_id)) ||
((n->dr != n_id) && (old_dr == n_id)) ||
((n->bdr == n_id) && (old_bdr != n_id)) ||
((n->bdr != n_id) && (old_bdr == n_id)))
ospf_iface_sm(ifa, ISM_NEICH);
}
} }

View file

@ -1,21 +0,0 @@
/*
* BIRD -- OSPF
*
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_HELLO_H_
#define _BIRD_OSPF_HELLO_H_
void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n, ip_addr faddr);
void ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn);
#define OHS_HELLO 0
#define OHS_POLL 1
#define OHS_SHUTDOWN 2
#endif /* _BIRD_OSPF_HELLO_H_ */

File diff suppressed because it is too large Load diff

View file

@ -1,36 +0,0 @@
/*
* BIRD -- OSPF
*
* (c) 1999--2005 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_IFACE_H_
#define _BIRD_OSPF_IFACE_H_
void ospf_iface_chstate(struct ospf_iface *ifa, u8 state);
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_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_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip);
void ospf_iface_remove(struct ospf_iface *ifa);
void ospf_iface_shutdown(struct ospf_iface *ifa);
int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new);
void ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac);
int ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen);
void ospf_open_vlink_sk(struct proto_ospf *po);
struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip);
static inline struct nbma_node *
find_nbma_node(struct ospf_iface *ifa, ip_addr ip)
{ return find_nbma_node_in(&ifa->nbma_list, ip); }
#endif /* _BIRD_OSPF_IFACE_H_ */

View file

@ -1,7 +1,9 @@
/* /*
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 2000-2004 Ondrej Filip <feela@network.cz> * (c) 2000--2004 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (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.
*/ */
@ -9,184 +11,175 @@
#include "ospf.h" #include "ospf.h"
/*
struct ospf_lsack_packet struct ospf_lsack_packet
{ {
struct ospf_packet ospf_packet; struct ospf_packet hdr;
struct ospf_lsa_header lsh[]; // union ospf_auth auth;
struct ospf_lsa_header lsas[];
};
*/
struct lsa_node
{
node n;
struct ospf_lsa_header lsa;
}; };
char *s_queue[] = { "direct", "delayed" }; static inline void
ospf_lsack_body(struct ospf_proto *p, struct ospf_packet *pkt,
struct ospf_lsa_header **body, uint *count)
static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt)
{ {
struct ospf_packet *op = &pkt->ospf_packet; uint plen = ntohs(pkt->length);
uint hlen = ospf_pkt_hdrlen(p);
ASSERT(op->type == LSACK_P); *body = ((void *) pkt) + hlen;
ospf_dump_common(p, op); *count = (plen - hlen) / sizeof(struct ospf_lsa_header);
}
unsigned int i, j; static void
j = (ntohs(op->length) - sizeof(struct ospf_lsack_packet)) / ospf_dump_lsack(struct ospf_proto *p, struct ospf_packet *pkt)
sizeof(struct ospf_lsa_header); {
struct ospf_lsa_header *lsas;
uint i, lsa_count;
for (i = 0; i < j; i++) ASSERT(pkt->type == LSACK_P);
ospf_dump_lsahdr(p, pkt->lsh + i); ospf_dump_common(p, pkt);
ospf_lsack_body(p, pkt, &lsas, &lsa_count);
for (i = 0; i < lsa_count; i++)
ospf_dump_lsahdr(p, lsas + i);
} }
/*
* =====================================
* Note, that h is in network endianity!
* =====================================
*/
void void
ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h, ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int queue)
int queue)
{ {
struct lsah_n *no = mb_alloc(n->pool, sizeof(struct lsah_n)); /* Note that h_n is in network endianity */
memcpy(&no->lsa, h, sizeof(struct ospf_lsa_header)); struct lsa_node *no = mb_alloc(n->pool, sizeof(struct lsa_node));
memcpy(&no->lsa, h_n, sizeof(struct ospf_lsa_header));
add_tail(&n->ackl[queue], NODE no); add_tail(&n->ackl[queue], NODE no);
DBG("Adding (%s) ack for %R, ID: %R, RT: %R, Type: %u\n", s_queue[queue], DBG("Adding %s ack for %R, ID: %R, RT: %R, Type: %u\n",
n->rid, ntohl(h->id), ntohl(h->rt), h->type); (queue == ACKL_DIRECT) ? "direct" : "delayed",
n->rid, ntohl(h_n->id), ntohl(h_n->rt), h_n->type);
} }
void void
ospf_lsack_send(struct ospf_neighbor *n, int queue) ospf_reset_lsack_queue(struct ospf_neighbor *n)
{ {
struct ospf_packet *op; struct lsa_node *no;
struct ospf_lsack_packet *pk;
u16 len, i = 0;
struct ospf_lsa_header *h;
struct lsah_n *no;
struct ospf_iface *ifa = n->ifa;
struct proto *p = &n->ifa->oa->po->proto;
if (EMPTY_LIST(n->ackl[queue])) WALK_LIST_FIRST(no, n->ackl[ACKL_DELAY])
return;
pk = ospf_tx_buffer(ifa);
op = &pk->ospf_packet;
ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
h = pk->lsh;
while (!EMPTY_LIST(n->ackl[queue]))
{ {
no = (struct lsah_n *) HEAD(n->ackl[queue]);
memcpy(h + i, &no->lsa, sizeof(struct ospf_lsa_header));
DBG("Iter %u ID: %R, RT: %R, Type: %04x\n", i, ntohl((h + i)->id),
ntohl((h + i)->rt), (h + i)->type);
i++;
rem_node(NODE no); rem_node(NODE no);
mb_free(no); mb_free(no);
if ((i * sizeof(struct ospf_lsa_header) + }
sizeof(struct ospf_lsack_packet)) > ospf_pkt_maxsize(n->ifa)) }
{
if (!EMPTY_LIST(n->ackl[queue]))
{
len =
sizeof(struct ospf_lsack_packet) +
i * sizeof(struct ospf_lsa_header);
op->length = htons(len);
DBG("Sending and continuing! Len=%u\n", len);
OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname); static inline void
ospf_send_lsack(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;
uint i, lsa_max, length;
if (ifa->type == OSPF_IT_BCAST) /* RFC 2328 13.5 */
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
ospf_send_to_all(ifa);
else if (ifa->cf->real_bcast)
ospf_send_to_bdr(ifa);
else
ospf_send_to(ifa, AllDRouters);
}
else
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
else
ospf_send_to_bdr(ifa);
}
ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); pkt = ospf_tx_buffer(ifa);
i = 0; ospf_pkt_fill_hdr(ifa, pkt, LSACK_P);
} ospf_lsack_body(p, pkt, &lsas, &lsa_max);
}
for (i = 0; i < lsa_max && !EMPTY_LIST(n->ackl[queue]); i++)
{
no = (struct lsa_node *) HEAD(n->ackl[queue]);
memcpy(&lsas[i], &no->lsa, sizeof(struct ospf_lsa_header));
DBG("Iter %u ID: %R, RT: %R, Type: %04x\n",
i, ntohl(lsas[i].id), ntohl(lsas[i].rt), lsas[i].type);
rem_node(NODE no);
mb_free(no);
} }
len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header); length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsa_header);
op->length = htons(len); pkt->length = htons(length);
DBG("Sending! Len=%u\n", len);
OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname); OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent via %s", ifa->ifname);
if (ifa->type == OSPF_IT_BCAST) if (ifa->type == OSPF_IT_BCAST)
{ {
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
ospf_send_to_all(ifa); ospf_send_to_all(ifa);
else if (ifa->cf->real_bcast)
ospf_send_to_bdr(ifa);
else else
ospf_send_to(ifa, AllDRouters); ospf_send_to_des(ifa);
} }
else else
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
} }
void void
ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, ospf_lsack_send(struct ospf_neighbor *n, int queue)
{
while (!EMPTY_LIST(n->ackl[queue]))
ospf_send_lsack(n, queue);
}
void
ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n) struct ospf_neighbor *n)
{ {
struct proto *p = &ifa->oa->po->proto; struct ospf_proto *p = ifa->oa->po;
struct ospf_lsa_header lsa; struct ospf_lsa_header lsa, *lsas;
struct top_hash_entry *en; struct top_hash_entry *ret, *en;
unsigned int i, lsano; uint i, lsa_count;
u32 lsa_type, lsa_domain;
unsigned int size = ntohs(ps_i->length); /* RFC 2328 13.7 */
if (size < sizeof(struct ospf_lsack_packet))
{
log(L_ERR "Bad OSPF LSACK packet from %I - too short (%u B)", n->ip, size);
return;
}
struct ospf_lsack_packet *ps = (void *) ps_i; /* No need to check length, lsack has only basic header */
OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
ospf_neigh_sm(n, INM_HELLOREC); OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE) if (n->state < NEIGHBOR_EXCHANGE)
return; return;
lsano = (size - sizeof(struct ospf_lsack_packet)) / ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
sizeof(struct ospf_lsa_header);
for (i = 0; i < lsano; i++)
{
ntohlsah(ps->lsh + i, &lsa);
u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
if ((en = ospf_hash_find_header(n->lsrth, dom, &lsa)) == NULL)
continue; /* pg 155 */
if (lsa_comp(&lsa, &en->lsa) != CMP_SAME) /* pg 156 */ ospf_lsack_body(p, pkt, &lsas, &lsa_count);
for (i = 0; i < lsa_count; i++)
{
lsa_ntoh_hdr(&lsas[i], &lsa);
lsa_get_type_domain(&lsa, n->ifa, &lsa_type, &lsa_domain);
ret = ospf_hash_find(n->lsrth, lsa_domain, lsa.id, lsa.rt, lsa_type);
if (!ret)
continue;
if (lsa_comp(&lsa, &ret->lsa) != CMP_SAME)
{ {
if ((lsa.sn == LSA_MAXSEQNO) && (lsa.age == LSA_MAXAGE)) if ((lsa.sn == LSA_MAXSEQNO) && (lsa.age == LSA_MAXAGE))
continue; continue;
OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip); OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip);
OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R", OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R",
lsa.type, lsa.id, lsa.rt); lsa_type, lsa.id, lsa.rt);
OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x", OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x",
en->lsa.age, en->lsa.sn, en->lsa.checksum); ret->lsa.age, ret->lsa.sn, ret->lsa.checksum);
OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x", OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x",
lsa.age, lsa.sn, lsa.checksum); lsa.age, lsa.sn, lsa.checksum);
continue; continue;
} }
DBG("Deleting LS Id: %R RT: %R Type: %u from LS Retl for neighbor %R\n", en = ospf_hash_find_entry(p->gr, ret);
lsa.id, lsa.rt, lsa.type, n->rid); if (en)
s_rem_node(SNODE en); en->ret_count--;
ospf_hash_delete(n->lsrth, en);
DBG("Deleting LSA (Type: %04x Id: %R Rt: %R) from lsrtl for neighbor %R\n",
lsa_type, lsa.id, lsa.rt, n->rid);
s_rem_node(SNODE ret);
ospf_hash_delete(n->lsrth, ret);
} }
} }

View file

@ -1,25 +0,0 @@
/*
* BIRD -- OSPF
*
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_LSACK_H_
#define _BIRD_OSPF_LSACK_H_
struct lsah_n
{
node n;
struct ospf_lsa_header lsa;
};
void ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n);
void ospf_lsack_send(struct ospf_neighbor *n, int queue);
void ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
int queue);
#endif /* _BIRD_OSPF_LSACK_H_ */

View file

@ -2,103 +2,21 @@
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 1999--2004 Ondrej Filip <feela@network.cz> * (c) 1999--2004 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (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" #include "ospf.h"
void
flush_lsa(struct top_hash_entry *en, struct proto_ospf *po)
{
struct proto *p = &po->proto;
OSPF_TRACE(D_EVENTS,
"Going to remove LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seqno: 0x%x",
en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.age, en->lsa.sn);
s_rem_node(SNODE en);
if (en->lsa_body != NULL)
mb_free(en->lsa_body);
en->lsa_body = NULL;
ospf_hash_delete(po->gr, en);
}
void
ospf_flush_area(struct proto_ospf *po, u32 areaid)
{
struct top_hash_entry *en, *nxt;
WALK_SLIST_DELSAFE(en, nxt, po->lsal)
{
if ((LSA_SCOPE(&en->lsa) == LSA_SCOPE_AREA) && (en->domain == areaid))
flush_lsa(en, po);
}
}
/**
* ospf_age
* @po: ospf protocol
*
* This function is periodicaly invoked from ospf_disp(). It computes the new
* age of all LSAs and old (@age is higher than %LSA_MAXAGE) LSAs are flushed
* whenever possible. If an LSA originated by the router itself is older
* than %LSREFRESHTIME a new instance is originated.
*
* The RFC says that a router should check the checksum of every LSA to detect
* hardware problems. BIRD does not do this to minimalize CPU utilization.
*
* If routing table calculation is scheduled, it also invalidates the old routing
* table calculation results.
*/
void
ospf_age(struct proto_ospf *po)
{
struct proto *p = &po->proto;
struct top_hash_entry *en, *nxt;
int flush = can_flush_lsa(po);
WALK_SLIST_DELSAFE(en, nxt, po->lsal)
{
if (en->lsa.age == LSA_MAXAGE)
{
if (flush)
flush_lsa(en, po);
continue;
}
if ((en->lsa.rt == po->router_id) && (en->lsa.age >= LSREFRESHTIME))
{
OSPF_TRACE(D_EVENTS, "Refreshing my LSA: Type: %u, Id: %R, Rt: %R",
en->lsa.type, en->lsa.id, en->lsa.rt);
en->lsa.sn++;
en->lsa.age = 0;
en->inst_t = now;
en->ini_age = 0;
lsasum_calculate(&en->lsa, en->lsa_body);
ospf_lsupd_flood(po, NULL, NULL, &en->lsa, en->domain, 1);
continue;
}
if ((en->lsa.age = (en->ini_age + (now - en->inst_t))) >= LSA_MAXAGE)
{
if (flush)
{
flush_lsa(en, po);
schedule_rtcalc(po);
}
else
en->lsa.age = LSA_MAXAGE;
}
}
}
#ifndef CPU_BIG_ENDIAN #ifndef CPU_BIG_ENDIAN
void void
htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
{ {
n->age = htons(h->age); n->age = htons(h->age);
#ifdef OSPFv2 n->type_raw = htons(h->type_raw);
n->options = h->options;
#endif
n->type = htont(h->type);
n->id = htonl(h->id); n->id = htonl(h->id);
n->rt = htonl(h->rt); n->rt = htonl(h->rt);
n->sn = htonl(h->sn); n->sn = htonl(h->sn);
@ -107,13 +25,10 @@ htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
} }
void void
ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
{ {
h->age = ntohs(n->age); h->age = ntohs(n->age);
#ifdef OSPFv2 h->type_raw = ntohs(n->type_raw);
h->options = n->options;
#endif
h->type = ntoht(n->type);
h->id = ntohl(n->id); h->id = ntohl(n->id);
h->rt = ntohl(n->rt); h->rt = ntohl(n->rt);
h->sn = ntohl(n->sn); h->sn = ntohl(n->sn);
@ -122,28 +37,120 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
} }
void void
htonlsab(void *h, void *n, u16 len) lsa_hton_body(void *h, void *n, u16 len)
{ {
u32 *hid = h; u32 *hid = h;
u32 *nid = n; u32 *nid = n;
unsigned i; uint i;
for (i = 0; i < (len / sizeof(u32)); i++) for (i = 0; i < (len / sizeof(u32)); i++)
nid[i] = htonl(hid[i]); nid[i] = htonl(hid[i]);
} }
void void
ntohlsab(void *n, void *h, u16 len) lsa_ntoh_body(void *n, void *h, u16 len)
{ {
u32 *nid = n; u32 *nid = n;
u32 *hid = h; u32 *hid = h;
unsigned i; uint i;
for (i = 0; i < (len / sizeof(u32)); i++) for (i = 0; i < (len / sizeof(u32)); i++)
hid[i] = ntohl(nid[i]); hid[i] = ntohl(nid[i]);
} }
#endif /* little endian */ #endif /* little endian */
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))
{
case LSA_SCOPE_LINK:
return ifa->iface_id == domain;
case LSA_SCOPE_AREA:
return ifa->oa->areaid == domain;
case LSA_SCOPE_AS:
if (ifa->type == OSPF_IT_VLINK)
return 0;
if (!oa_is_ext(ifa->oa))
return 0;
return 1;
default:
log(L_ERR "OSPF: LSA with invalid scope");
return 0;
}
}
static int
unknown_lsa_type(u32 type)
{
switch (type)
{
case LSA_T_RT:
case LSA_T_NET:
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
case LSA_T_EXT:
case LSA_T_NSSA:
case LSA_T_LINK:
case LSA_T_PREFIX:
return 0;
default:
return 1;
}
}
#define LSA_V2_TMAX 8
static const u16 lsa_v2_types[LSA_V2_TMAX] =
{0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA};
void
lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain)
{
if (ospf_is_v2(ifa->oa->po))
{
itype = itype & LSA_T_V2_MASK;
itype = (itype < LSA_V2_TMAX) ? lsa_v2_types[itype] : 0;
}
else
{
/* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */
if (unknown_lsa_type(itype) && !(itype & LSA_UBIT))
itype = itype & ~LSA_SCOPE_MASK;
}
*otype = itype;
switch (LSA_SCOPE(itype))
{
case LSA_SCOPE_LINK:
*domain = ifa->iface_id;
return;
case LSA_SCOPE_AREA:
*domain = ifa->oa->areaid;
return;
case LSA_SCOPE_AS:
default:
*domain = 0;
return;
}
}
/* /*
void void
buf_dump(const char *hdr, const byte *buf, int blen) buf_dump(const char *hdr, const byte *buf, int blen)
@ -188,8 +195,8 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body)
u16 length = h->length; u16 length = h->length;
// log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length); // log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length);
htonlsah(h, h); lsa_hton_hdr(h, h);
htonlsab1(body, length - sizeof(struct ospf_lsa_header)); lsa_hton_body1(body, length - sizeof(struct ospf_lsa_header));
/* /*
char buf[1024]; char buf[1024];
@ -202,8 +209,8 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body)
// log(L_WARN "Checksum result %4x", h->checksum); // log(L_WARN "Checksum result %4x", h->checksum);
ntohlsah(h, h); lsa_ntoh_hdr(h, h);
ntohlsab1(body, length - sizeof(struct ospf_lsa_header)); lsa_ntoh_body1(body, length - sizeof(struct ospf_lsa_header));
} }
/* /*
@ -292,33 +299,204 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
return CMP_SAME; return CMP_SAME;
} }
static inline int
lsa_walk_rt2(struct ospf_lsa_rt_walk *rt)
{
if (rt->buf >= rt->bufend)
return 0;
struct ospf_lsa_rt2_link *l = rt->buf;
rt->buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
rt->type = l->type;
rt->metric = l->metric;
rt->id = l->id;
rt->data = l->data;
return 1;
}
static inline int
lsa_walk_rt3(struct ospf_lsa_rt_walk *rt)
{
while (rt->buf >= rt->bufend)
{
rt->en = ospf_hash_find_rt3_next(rt->en);
if (!rt->en)
return 0;
rt->buf = rt->en->lsa_body;
rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header);
rt->buf += sizeof(struct ospf_lsa_rt);
}
struct ospf_lsa_rt3_link *l = rt->buf;
rt->buf += sizeof(struct ospf_lsa_rt3_link);
rt->type = l->type;
rt->metric = l->metric;
rt->lif = l->lif;
rt->nif = l->nif;
rt->id = l->id;
return 1;
}
void
lsa_walk_rt_init(struct ospf_proto *p, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt)
{
rt->ospf2 = ospf_is_v2(p);
rt->id = rt->data = rt->lif = rt->nif = 0;
if (rt->ospf2)
rt->en = act;
else
rt->en = ospf_hash_find_rt3_first(p->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);
rt->buf += sizeof(struct ospf_lsa_rt);
}
int
lsa_walk_rt(struct ospf_lsa_rt_walk *rt)
{
return rt->ospf2 ? lsa_walk_rt2(rt) : lsa_walk_rt3(rt);
}
void
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric)
{
if (ospf2)
{
struct ospf_lsa_sum2 *ls = en->lsa_body;
*ip = ipa_from_u32(en->lsa.id & ls->netmask);
*pxlen = u32_masklen(ls->netmask);
*pxopts = 0;
*metric = ls->metric & LSA_METRIC_MASK;
}
else
{
struct ospf_lsa_sum3_net *ls = en->lsa_body;
u16 rest;
lsa_get_ipv6_prefix(ls->prefix, ip, pxlen, pxopts, &rest);
*metric = ls->metric & LSA_METRIC_MASK;
}
}
void
lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options)
{
if (ospf2)
{
struct ospf_lsa_sum2 *ls = en->lsa_body;
*drid = en->lsa.id;
*metric = ls->metric & LSA_METRIC_MASK;
*options = 0;
}
else
{
struct ospf_lsa_sum3_rt *ls = en->lsa_body;
*drid = ls->drid;
*metric = ls->metric & LSA_METRIC_MASK;
*options = ls->options & LSA_OPTIONS_MASK;
}
}
void
lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt)
{
if (ospf2)
{
struct ospf_lsa_ext2 *ext = en->lsa_body;
rt->ip = ipa_from_u32(en->lsa.id & ext->netmask);
rt->pxlen = u32_masklen(ext->netmask);
rt->pxopts = 0;
rt->metric = ext->metric & LSA_METRIC_MASK;
rt->ebit = ext->metric & LSA_EXT2_EBIT;
rt->fbit = ext->fwaddr;
rt->fwaddr = ipa_from_u32(ext->fwaddr);
rt->tag = ext->tag;
rt->propagate = lsa_get_options(&en->lsa) & OPT_P;
}
else
{
struct ospf_lsa_ext3 *ext = en->lsa_body;
u16 rest;
u32 *buf = lsa_get_ipv6_prefix(ext->rest, &rt->ip, &rt->pxlen, &rt->pxopts, &rest);
rt->metric = ext->metric & LSA_METRIC_MASK;
rt->ebit = ext->metric & LSA_EXT3_EBIT;
rt->fbit = ext->metric & LSA_EXT3_FBIT;
if (rt->fbit)
buf = lsa_get_ipv6_addr(buf, &rt->fwaddr);
else
rt->fwaddr = IPA_NONE;
rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0;
rt->propagate = rt->pxopts & OPT_PX_P;
}
}
#define HDRLEN sizeof(struct ospf_lsa_header) #define HDRLEN sizeof(struct ospf_lsa_header)
static int static int
lsa_validate_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
{ {
unsigned int i, max;
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt))) if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
return 0; return 0;
struct ospf_lsa_rt_link *rtl = (struct ospf_lsa_rt_link *) (body + 1); uint i = 0;
max = lsa_rt_count(lsa); void *buf = body;
void *bufend = buf + lsa->length - HDRLEN;
buf += sizeof(struct ospf_lsa_rt);
#ifdef OSPFv2 while (buf < bufend)
if (body->links != max)
return 0;
#endif
for (i = 0; i < max; i++)
{ {
u8 type = rtl[i].type; struct ospf_lsa_rt2_link *l = buf;
if (!((type == LSART_PTP) || buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
(type == LSART_NET) || i++;
#ifdef OSPFv2
(type == LSART_STUB) || if (buf > bufend)
#endif return 0;
(type == LSART_VLNK)))
if (!((l->type == LSART_PTP) ||
(l->type == LSART_NET) ||
(l->type == LSART_STUB) ||
(l->type == LSART_VLNK)))
return 0;
}
if ((body->options & LSA_RT2_LINKS) != i)
return 0;
return 1;
}
static int
lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
{
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
return 0;
void *buf = body;
void *bufend = buf + lsa->length - HDRLEN;
buf += sizeof(struct ospf_lsa_rt);
while (buf < bufend)
{
struct ospf_lsa_rt3_link *l = buf;
buf += sizeof(struct ospf_lsa_rt3_link);
if (buf > bufend)
return 0;
if (!((l->type == LSART_PTP) ||
(l->type == LSART_NET) ||
(l->type == LSART_VLNK)))
return 0; return 0;
} }
return 1; return 1;
@ -333,37 +511,18 @@ lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
return 1; return 1;
} }
#ifdef OSPFv2
static int static int
lsa_validate_sum(struct ospf_lsa_header *lsa, struct ospf_lsa_sum *body) lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body)
{ {
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum))) if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2)))
return 0; return 0;
/* First field should have TOS = 0, we ignore other TOS fields */ /* First field should have TOS = 0, we ignore other TOS fields */
if ((body->metric & LSA_SUM_TOS) != 0) if ((body->metric & LSA_SUM2_TOS) != 0)
return 0; return 0;
return 1; return 1;
} }
#define lsa_validate_sum_net(A,B) lsa_validate_sum(A,B)
#define lsa_validate_sum_rt(A,B) lsa_validate_sum(A,B)
static int
lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
{
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext)))
return 0;
/* First field should have TOS = 0, we ignore other TOS fields */
if ((body->metric & LSA_EXT_TOS) != 0)
return 0;
return 1;
}
#else /* OSPFv3 */
static inline int static inline int
pxlen(u32 *buf) pxlen(u32 *buf)
@ -372,36 +531,48 @@ pxlen(u32 *buf)
} }
static int static int
lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_net *body) lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body)
{ {
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum_net) + 4)) if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4))
return 0; return 0;
u8 pxl = pxlen(body->prefix); u8 pxl = pxlen(body->prefix);
if (pxl > MAX_PREFIX_LENGTH) if (pxl > MAX_PREFIX_LENGTH)
return 0; return 0;
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_net) + if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) +
IPV6_PREFIX_SPACE(pxl))) IPV6_PREFIX_SPACE(pxl)))
return 0; return 0;
return 1; return 1;
} }
static int static int
lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_rt *body) lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body)
{ {
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_rt))) if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt)))
return 0; return 0;
return 1; return 1;
} }
static int static int
lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body) lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body)
{ {
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext) + 4)) if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext2)))
return 0;
/* First field should have TOS = 0, we ignore other TOS fields */
if ((body->metric & LSA_EXT2_TOS) != 0)
return 0;
return 1;
}
static int
lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
{
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4))
return 0; return 0;
u8 pxl = pxlen(body->rest); u8 pxl = pxlen(body->rest);
@ -409,23 +580,23 @@ lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
return 0; return 0;
int len = IPV6_PREFIX_SPACE(pxl); int len = IPV6_PREFIX_SPACE(pxl);
if (body->metric & LSA_EXT_FBIT) // forwardinf address if (body->metric & LSA_EXT3_FBIT) // forwardinf address
len += 16; len += 16;
if (body->metric & LSA_EXT_TBIT) // route tag if (body->metric & LSA_EXT3_TBIT) // route tag
len += 4; len += 4;
if (*body->rest & 0xFFFF) // referenced LS type field if (*body->rest & 0xFFFF) // referenced LS type field
len += 4; len += 4;
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext) + len)) if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext3) + len))
return 0; return 0;
return 1; return 1;
} }
static int static int
lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, unsigned int offset, u8 *pbuf) lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, uint offset, u8 *pbuf)
{ {
unsigned int bound = lsa->length - HDRLEN - 4; uint bound = lsa->length - HDRLEN - 4;
u32 i; u32 i;
for (i = 0; i < pxcount; i++) for (i = 0; i < pxcount; i++)
@ -464,8 +635,6 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body); return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body);
} }
#endif
/** /**
* lsa_validate - check whether given LSA is valid * lsa_validate - check whether given LSA is valid
@ -477,85 +646,48 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
*/ */
int int
lsa_validate(struct ospf_lsa_header *lsa, void *body) lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
{ {
switch (lsa->type) if (ospf2)
{
switch (lsa_type)
{ {
case LSA_T_RT: case LSA_T_RT:
return lsa_validate_rt(lsa, body); return lsa_validate_rt2(lsa, body);
case LSA_T_NET: case LSA_T_NET:
return lsa_validate_net(lsa, body); return lsa_validate_net(lsa, body);
case LSA_T_SUM_NET: case LSA_T_SUM_NET:
return lsa_validate_sum_net(lsa, body); return lsa_validate_sum2(lsa, body);
case LSA_T_SUM_RT: case LSA_T_SUM_RT:
return lsa_validate_sum_rt(lsa, body); return lsa_validate_sum2(lsa, body);
case LSA_T_EXT: case LSA_T_EXT:
case LSA_T_NSSA: case LSA_T_NSSA:
return lsa_validate_ext(lsa, body); return lsa_validate_ext2(lsa, body);
#ifdef OSPFv3 default:
return 0; /* Should not happen, unknown LSAs are already rejected */
}
}
else
{
switch (lsa_type)
{
case LSA_T_RT:
return lsa_validate_rt3(lsa, body);
case LSA_T_NET:
return lsa_validate_net(lsa, body);
case LSA_T_SUM_NET:
return lsa_validate_sum3_net(lsa, body);
case LSA_T_SUM_RT:
return lsa_validate_sum3_rt(lsa, body);
case LSA_T_EXT:
case LSA_T_NSSA:
return lsa_validate_ext3(lsa, body);
case LSA_T_LINK: case LSA_T_LINK:
return lsa_validate_link(lsa, body); return lsa_validate_link(lsa, body);
case LSA_T_PREFIX: case LSA_T_PREFIX:
return lsa_validate_prefix(lsa, body); return lsa_validate_prefix(lsa, body);
#endif
default: default:
/* In OSPFv3, unknown LSAs are OK, return 1; /* Unknown LSAs are OK in OSPFv3 */
In OSPFv2, unknown LSAs are already rejected
*/
return 1;
} }
}
/**
* lsa_install_new - install new LSA into database
* @po: OSPF protocol
* @lsa: LSA header
* @domain: domain of LSA
* @body: pointer to LSA body
*
* This function ensures installing new LSA into LSA database. Old instance is
* replaced. Several actions are taken to detect if new routing table
* calculation is necessary. This is described in 13.2 of RFC 2328.
*/
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. */
int change = 0;
struct top_hash_entry *en;
if ((en = ospf_hash_find_header(po->gr, domain, lsa)) == NULL)
{
en = ospf_hash_get_header(po->gr, domain, lsa);
change = 1;
} }
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)))
change = 1;
s_rem_node(SNODE en);
}
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);
s_add_tail(&po->lsal, SNODE en);
en->inst_t = now;
if (en->lsa_body != NULL)
mb_free(en->lsa_body);
en->lsa_body = body;
memcpy(&en->lsa, lsa, sizeof(struct ospf_lsa_header));
en->ini_age = en->lsa.age;
if (change)
schedule_rtcalc(po);
return en;
} }

View file

@ -1,42 +1,63 @@
/* /*
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 1999 - 2000 Ondrej Filip <feela@network.cz> * (c) 1999--2000 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (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.
*
*/ */
#ifndef _BIRD_OSPF_LSALIB_H_ #ifndef _BIRD_OSPF_LSALIB_H_
#define _BIRD_OSPF_LSALIB_H_ #define _BIRD_OSPF_LSALIB_H_
#ifdef CPU_BIG_ENDIAN #ifdef CPU_BIG_ENDIAN
static inline void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; }; static inline void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; };
static inline void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; }; static inline void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; };
static inline void htonlsab(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); }; static inline void lsa_hton_body(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); };
static inline void ntohlsab(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); }; static inline void lsa_ntoh_body(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); };
static inline void htonlsab1(void *h, u16 len) { }; static inline void lsa_hton_body1(void *h, u16 len) { };
static inline void ntohlsab1(void *n, u16 len) { }; static inline void lsa_ntoh_body1(void *n, u16 len) { };
#else #else
void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n); void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h); void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
void htonlsab(void *h, void *n, u16 len); void lsa_hton_body(void *h, void *n, u16 len);
void ntohlsab(void *n, void *h, u16 len); void lsa_ntoh_body(void *n, void *h, u16 len);
static inline void htonlsab1(void *h, u16 len) { htonlsab(h, h, len); }; static inline void lsa_hton_body1(void *h, u16 len) { lsa_hton_body(h, h, len); };
static inline void ntohlsab1(void *n, u16 len) { ntohlsab(n, n, len); }; static inline void lsa_ntoh_body1(void *n, u16 len) { lsa_ntoh_body(n, n, len); };
#endif #endif
struct ospf_lsa_rt_walk {
struct top_hash_entry *en;
void *buf, *bufend;
int ospf2;
u16 type, metric;
u32 id, data, lif, nif;
};
void lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain);
static inline void lsa_get_type_domain(struct ospf_lsa_header *lsa, struct ospf_iface *ifa, u32 *otype, u32 *domain)
{ lsa_get_type_domain_(lsa->type_raw, ifa, otype, domain); }
static inline u32 lsa_get_etype(struct ospf_lsa_header *h, struct ospf_proto *p)
{ return ospf_is_v2(p) ? (h->type_raw & LSA_T_V2_MASK) : h->type_raw; }
int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa);
void lsasum_calculate(struct ospf_lsa_header *header, void *body); void lsasum_calculate(struct ospf_lsa_header *header, void *body);
u16 lsasum_check(struct ospf_lsa_header *h, void *body); u16 lsasum_check(struct ospf_lsa_header *h, void *body);
#define CMP_NEWER 1 #define CMP_NEWER 1
#define CMP_SAME 0 #define CMP_SAME 0
#define CMP_OLDER -1 #define CMP_OLDER -1
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2); int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);
int lsa_validate(struct ospf_lsa_header *lsa, void *body); void lsa_walk_rt_init(struct ospf_proto *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body); int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
void ospf_age(struct proto_ospf *po); void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric);
void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po); void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
void ospf_flush_area(struct proto_ospf *po, u32 areaid); void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt);
int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
#endif /* _BIRD_OSPF_LSALIB_H_ */ #endif /* _BIRD_OSPF_LSALIB_H_ */

View file

@ -2,6 +2,8 @@
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 2000--2004 Ondrej Filip <feela@network.cz> * (c) 2000--2004 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (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.
*/ */
@ -9,47 +11,55 @@
#include "ospf.h" #include "ospf.h"
/*
struct ospf_lsreq_packet struct ospf_lsreq_packet
{ {
struct ospf_packet ospf_packet; struct ospf_packet hdr;
struct ospf_lsreq_header lsh[]; // union ospf_auth auth;
struct ospf_lsreq_header lsrs[];
}; };
*/
static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt) static inline void
ospf_lsreq_body(struct ospf_proto *p, struct ospf_packet *pkt,
struct ospf_lsreq_header **body, uint *count)
{ {
struct ospf_packet *op = &pkt->ospf_packet; uint plen = ntohs(pkt->length);
uint hlen = ospf_pkt_hdrlen(p);
ASSERT(op->type == LSREQ_P); *body = ((void *) pkt) + hlen;
ospf_dump_common(p, op); *count = (plen - hlen) / sizeof(struct ospf_lsreq_header);
unsigned int i, j;
j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) /
sizeof(struct ospf_lsreq_header);
for (i = 0; i < j; i++)
log(L_TRACE "%s: LSR Type: %04x, Id: %R, Rt: %R", p->name,
htonl(pkt->lsh[i].type), htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt));
} }
void static void
ospf_lsreq_send(struct ospf_neighbor *n) ospf_dump_lsreq(struct ospf_proto *p, struct ospf_packet *pkt)
{ {
snode *sn; struct ospf_lsreq_header *lsrs;
uint i, lsr_count;
ASSERT(pkt->type == LSREQ_P);
ospf_dump_common(p, pkt);
ospf_lsreq_body(p, pkt, &lsrs, &lsr_count);
for (i = 0; i < lsr_count; i++)
log(L_TRACE "%s: LSR Type: %04x, Id: %R, Rt: %R", p->p.name,
ntohl(lsrs[i].type), ntohl(lsrs[i].id), ntohl(lsrs[i].rt));
}
void
ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n)
{
struct ospf_iface *ifa = n->ifa;
struct ospf_lsreq_header *lsrs;
struct top_hash_entry *en; struct top_hash_entry *en;
struct ospf_lsreq_packet *pk; struct ospf_packet *pkt;
struct ospf_packet *op; uint i, lsr_max, length;
struct ospf_lsreq_header *lsh;
u16 length;
int i, j;
struct proto *p = &n->ifa->oa->po->proto;
pk = ospf_tx_buffer(n->ifa); /* RFC 2328 10.9 */
op = &pk->ospf_packet;
ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P);
sn = SHEAD(n->lsrql);
if (EMPTY_SLIST(n->lsrql)) if (EMPTY_SLIST(n->lsrql))
{ {
if (n->state == NEIGHBOR_LOADING) if (n->state == NEIGHBOR_LOADING)
@ -57,90 +67,80 @@ ospf_lsreq_send(struct ospf_neighbor *n)
return; return;
} }
i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) / pkt = ospf_tx_buffer(ifa);
sizeof(struct ospf_lsreq_header); ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P);
lsh = pk->lsh; ospf_lsreq_body(p, pkt, &lsrs, &lsr_max);
for (; i > 0; i--) // for (i = 0; i < lsr_max; i++)
i = 0;
WALK_SLIST(en, n->lsrql)
{ {
en = (struct top_hash_entry *) sn; if (i == lsr_max)
lsh->type = htonl(en->lsa.type);
lsh->rt = htonl(en->lsa.rt);
lsh->id = htonl(en->lsa.id);
DBG("Requesting %uth LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
i, en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
lsh++;
if (sn == STAIL(n->lsrql))
break; break;
sn = sn->next;
DBG("Requesting %uth LSA: Type: %04u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
i, en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
u32 etype = lsa_get_etype(&en->lsa, p);
lsrs[i].type = htonl(etype);
lsrs[i].rt = htonl(en->lsa.rt);
lsrs[i].id = htonl(en->lsa.id);
i++;
} }
if (i != 0)
i--;
length = length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsreq_header);
sizeof(struct ospf_lsreq_packet) + (j - pkt->length = htons(length);
i) * sizeof(struct ospf_lsreq_header);
op->length = htons(length);
OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->ifname); OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet sent to %I via %s", n->ip, ifa->ifname);
ospf_send_to(n->ifa, n->ip); ospf_send_to(ifa, n->ip);
} }
void void
ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n) struct ospf_neighbor *n)
{ {
struct ospf_area *oa = ifa->oa; struct ospf_proto *p = ifa->oa->po;
struct proto_ospf *po = oa->po; struct ospf_lsreq_header *lsrs;
struct proto *p = &po->proto; uint i, lsr_count;
struct ospf_lsreq_header *lsh;
struct l_lsr_head *llsh;
list uplist;
slab *upslab;
int i, lsano;
unsigned int size = ntohs(ps_i->length); /* RFC 2328 10.7 */
if (size < sizeof(struct ospf_lsreq_packet))
{
log(L_ERR "Bad OSPF LSREQ packet from %I - too short (%u B)", n->ip, size);
return;
}
struct ospf_lsreq_packet *ps = (void *) ps_i; /* No need to check length, lsreq has only basic header */
OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->ifname);
OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet received from %I via %s", n->ip, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE) if (n->state < NEIGHBOR_EXCHANGE)
return; return;
ospf_neigh_sm(n, INM_HELLOREC); ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
lsh = ps->lsh; ospf_lsreq_body(p, pkt, &lsrs, &lsr_count);
init_list(&uplist);
upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
lsano = (size - sizeof(struct ospf_lsreq_packet)) / struct top_hash_entry *en, *entries[lsr_count];
sizeof(struct ospf_lsreq_header);
for (i = 0; i < lsano; lsh++, i++) for (i = 0; i < lsr_count; i++)
{ {
u32 hid = ntohl(lsh->id); u32 id, rt, type, domain;
u32 hrt = ntohl(lsh->rt);
u32 htype = ntohl(lsh->type); id = ntohl(lsrs[i].id);
u32 dom = ospf_lsa_domain(htype, ifa); rt = ntohl(lsrs[i].rt);
DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", lsh->type, hid, hrt); lsa_get_type_domain_(ntohl(lsrs[i].type), ifa, &type, &domain);
llsh = sl_alloc(upslab);
llsh->lsh.id = hid; DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt);
llsh->lsh.rt = hrt;
llsh->lsh.type = htype; en = ospf_hash_find(p->gr, domain, id, rt, type);
add_tail(&uplist, NODE llsh); if (!en)
if (ospf_hash_find(po->gr, dom, hid, hrt, htype) == NULL)
{ {
log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R", log(L_WARN "%s: Received LSREQ from %I for missing LSA (Type: %04x, Id: %R, Rt: %R)",
n->ip, htype, hid, hrt); p->p.name, n->ip, type, id, rt);
ospf_neigh_sm(n, INM_BADLSREQ); ospf_neigh_sm(n, INM_BADLSREQ);
rfree(upslab);
return; return;
} }
entries[i] = en;
} }
ospf_lsupd_send_list(n, &uplist);
rfree(upslab); ospf_send_lsupd(p, entries, lsr_count, n);
} }

View file

@ -1,17 +0,0 @@
/*
* BIRD -- OSPF
*
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_LSREQ_H_
#define _BIRD_OSPF_LSREQ_H_
void ospf_lsreq_send(struct ospf_neighbor *n);
void ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n);
#endif /* _BIRD_OSPF_LSREQ_H_ */

File diff suppressed because it is too large Load diff

View file

@ -1,25 +0,0 @@
/*
* BIRD -- OSPF
*
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_LSUPD_H_
#define _BIRD_OSPF_LSUPD_H_
void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n);
void ospf_dump_common(struct proto *p, struct ospf_packet *op);
void ospf_lsupd_send_list(struct ospf_neighbor *n, list * l);
void ospf_lsupd_receive(struct ospf_packet *ps_i,
struct ospf_iface *ifa, struct ospf_neighbor *n);
int ospf_lsupd_flood(struct proto_ospf *po,
struct ospf_neighbor *n, struct ospf_lsa_header *hn,
struct ospf_lsa_header *hh, u32 domain, int rtl);
void ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en);
int ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa);
#endif /* _BIRD_OSPF_LSUPD_H_ */

View file

@ -1,7 +1,9 @@
/* /*
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz> * (c) 1999--2004 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (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.
*/ */
@ -26,8 +28,6 @@ const char *ospf_inm[] =
}; };
static void neigh_chstate(struct ospf_neighbor *n, u8 state); static void neigh_chstate(struct ospf_neighbor *n, u8 state);
static struct ospf_neighbor *electbdr(list nl);
static struct ospf_neighbor *electdr(list nl);
static void neighbor_timer_hook(timer * timer); static void neighbor_timer_hook(timer * timer);
static void rxmt_timer_hook(timer * timer); static void rxmt_timer_hook(timer * timer);
static void ackd_timer_hook(timer * t); static void ackd_timer_hook(timer * t);
@ -37,11 +37,9 @@ init_lists(struct ospf_neighbor *n)
{ {
s_init_list(&(n->lsrql)); s_init_list(&(n->lsrql));
n->lsrqh = ospf_top_new(n->pool); n->lsrqh = ospf_top_new(n->pool);
s_init(&(n->lsrqi), &(n->lsrql));
s_init_list(&(n->lsrtl)); s_init_list(&(n->lsrtl));
n->lsrth = ospf_top_new(n->pool); n->lsrth = ospf_top_new(n->pool);
s_init(&(n->lsrti), &(n->lsrtl));
} }
/* Resets LSA request and retransmit lists. /* Resets LSA request and retransmit lists.
@ -59,9 +57,8 @@ reset_lists(struct ospf_neighbor *n)
struct ospf_neighbor * struct ospf_neighbor *
ospf_neighbor_new(struct ospf_iface *ifa) ospf_neighbor_new(struct ospf_iface *ifa)
{ {
struct proto *p = (struct proto *) (ifa->oa->po); struct ospf_proto *p = ifa->oa->po;
struct proto_ospf *po = ifa->oa->po; struct pool *pool = rp_new(p->p.pool, "OSPF Neighbor");
struct pool *pool = rp_new(p->pool, "OSPF Neighbor");
struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor)); struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor));
n->pool = pool; n->pool = pool;
@ -72,14 +69,14 @@ ospf_neighbor_new(struct ospf_iface *ifa)
n->state = NEIGHBOR_DOWN; n->state = NEIGHBOR_DOWN;
init_lists(n); init_lists(n);
s_init(&(n->dbsi), &(po->lsal)); s_init(&(n->dbsi), &(p->lsal));
n->inactim = tm_new(pool); n->inactim = tm_new(pool);
n->inactim->data = n; n->inactim->data = n;
n->inactim->randomize = 0; n->inactim->randomize = 0;
n->inactim->hook = neighbor_timer_hook; n->inactim->hook = neighbor_timer_hook;
n->inactim->recurrent = 0; n->inactim->recurrent = 0;
DBG("%s: Installing inactivity timer.\n", p->name); DBG("%s: Installing inactivity timer.\n", p->p.name);
n->rxmt_timer = tm_new(pool); n->rxmt_timer = tm_new(pool);
n->rxmt_timer->data = n; n->rxmt_timer->data = n;
@ -87,7 +84,7 @@ ospf_neighbor_new(struct ospf_iface *ifa)
n->rxmt_timer->hook = rxmt_timer_hook; n->rxmt_timer->hook = rxmt_timer_hook;
n->rxmt_timer->recurrent = ifa->rxmtint; n->rxmt_timer->recurrent = ifa->rxmtint;
tm_start(n->rxmt_timer, n->ifa->rxmtint); tm_start(n->rxmt_timer, n->ifa->rxmtint);
DBG("%s: Installing rxmt timer.\n", p->name); DBG("%s: Installing rxmt timer.\n", p->p.name);
n->ackd_timer = tm_new(pool); n->ackd_timer = tm_new(pool);
n->ackd_timer->data = n; n->ackd_timer->data = n;
@ -97,7 +94,7 @@ ospf_neighbor_new(struct ospf_iface *ifa)
init_list(&n->ackl[ACKL_DIRECT]); init_list(&n->ackl[ACKL_DIRECT]);
init_list(&n->ackl[ACKL_DELAY]); init_list(&n->ackl[ACKL_DELAY]);
tm_start(n->ackd_timer, n->ifa->rxmtint / 2); tm_start(n->ackd_timer, n->ifa->rxmtint / 2);
DBG("%s: Installing ackd timer.\n", p->name); DBG("%s: Installing ackd timer.\n", p->p.name);
return (n); return (n);
} }
@ -110,64 +107,73 @@ ospf_neighbor_new(struct ospf_iface *ifa)
* Many actions have to be taken acording to a change of state of a neighbor. It * Many actions have to be taken acording to a change of state of a neighbor. It
* starts rxmt timers, call interface state machine etc. * starts rxmt timers, call interface state machine etc.
*/ */
static void static void
neigh_chstate(struct ospf_neighbor *n, u8 state) neigh_chstate(struct ospf_neighbor *n, u8 state)
{ {
u8 oldstate; struct ospf_iface *ifa = n->ifa;
struct ospf_proto *p = ifa->oa->po;
u8 old_state = n->state;
int old_fadj = ifa->fadj;
oldstate = n->state; if (state == old_state)
return;
if (oldstate != state) OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from %s to %s",
n->ip, ospf_ns[old_state], ospf_ns[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++;
/* Decrease number of partial adjacencies */
if ((old_state == NEIGHBOR_EXCHANGE) || (old_state == NEIGHBOR_LOADING))
p->padj--;
/* Increase number of full adjacencies */
if (state == NEIGHBOR_FULL)
ifa->fadj++;
/* Decrease number of full adjacencies */
if (old_state == NEIGHBOR_FULL)
ifa->fadj--;
if (ifa->fadj != old_fadj)
{ {
struct ospf_iface *ifa = n->ifa; /* RFC 2328 12.4 Event 4 - neighbor enters/leaves Full state */
struct proto_ospf *po = ifa->oa->po; ospf_notify_rt_lsa(ifa->oa);
struct proto *p = &po->proto; ospf_notify_net_lsa(ifa);
n->state = state; /* RFC 2328 12.4 Event 8 - vlink state change */
if (ifa->type == OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from \"%s\" to \"%s\".", ospf_notify_rt_lsa(ifa->voa);
n->ip, ospf_ns[oldstate], ospf_ns[state]);
if ((state == NEIGHBOR_2WAY) && (oldstate < NEIGHBOR_2WAY))
ospf_iface_sm(ifa, ISM_NEICH);
if ((state < NEIGHBOR_2WAY) && (oldstate >= NEIGHBOR_2WAY))
ospf_iface_sm(ifa, ISM_NEICH);
if (oldstate == NEIGHBOR_FULL) /* Decrease number of adjacencies */
{
ifa->fadj--;
schedule_rt_lsa(ifa->oa);
if (ifa->type == OSPF_IT_VLINK) schedule_rt_lsa(ifa->voa);
schedule_net_lsa(ifa);
}
if (state == NEIGHBOR_FULL) /* Increase number of adjacencies */
{
ifa->fadj++;
schedule_rt_lsa(ifa->oa);
if (ifa->type == OSPF_IT_VLINK) schedule_rt_lsa(ifa->voa);
schedule_net_lsa(ifa);
}
if (state == NEIGHBOR_EXSTART)
{
if (n->adj == 0) /* First time adjacency */
{
n->dds = random_u32();
}
n->dds++;
n->myimms.byte = 0;
n->myimms.bit.ms = 1;
n->myimms.bit.m = 1;
n->myimms.bit.i = 1;
}
if (state > NEIGHBOR_EXSTART)
n->myimms.bit.i = 0;
} }
if (state == NEIGHBOR_EXSTART)
{
/* First time adjacency */
if (n->adj == 0)
n->dds = random_u32();
n->dds++;
n->myimms = DBDES_IMMS;
}
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 * static struct ospf_neighbor *
electbdr(list nl) elect_bdr(struct ospf_proto *p, list nl)
{ {
struct ospf_neighbor *neigh, *n1, *n2; struct ospf_neighbor *neigh, *n1, *n2;
u32 nid; u32 nid;
@ -176,11 +182,7 @@ electbdr(list nl)
n2 = NULL; n2 = NULL;
WALK_LIST(neigh, nl) /* First try those decl. themselves */ WALK_LIST(neigh, nl) /* First try those decl. themselves */
{ {
#ifdef OSPFv2 nid = neigh_get_id(p, neigh);
nid = ipa_to_u32(neigh->ip);
#else /* OSPFv3 */
nid = neigh->rid;
#endif
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
if (neigh->priority > 0) /* Eligible */ if (neigh->priority > 0) /* Eligible */
@ -225,7 +227,7 @@ electbdr(list nl)
} }
static struct ospf_neighbor * static struct ospf_neighbor *
electdr(list nl) elect_dr(struct ospf_proto *p, list nl)
{ {
struct ospf_neighbor *neigh, *n; struct ospf_neighbor *neigh, *n;
u32 nid; u32 nid;
@ -233,11 +235,7 @@ electdr(list nl)
n = NULL; n = NULL;
WALK_LIST(neigh, nl) /* And now DR */ WALK_LIST(neigh, nl) /* And now DR */
{ {
#ifdef OSPFv2 nid = neigh_get_id(p, neigh);
nid = ipa_to_u32(neigh->ip);
#else /* OSPFv3 */
nid = neigh->rid;
#endif
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
if (neigh->priority > 0) /* Eligible */ if (neigh->priority > 0) /* Eligible */
@ -264,13 +262,9 @@ electdr(list nl)
static int static int
can_do_adj(struct ospf_neighbor *n) can_do_adj(struct ospf_neighbor *n)
{ {
struct ospf_iface *ifa; struct ospf_iface *ifa = n->ifa;
struct proto *p; struct ospf_proto *p = ifa->oa->po;
int i; int i = 0;
ifa = n->ifa;
p = (struct proto *) (ifa->oa->po);
i = 0;
switch (ifa->type) switch (ifa->type)
{ {
@ -285,10 +279,10 @@ can_do_adj(struct ospf_neighbor *n)
{ {
case OSPF_IS_DOWN: case OSPF_IS_DOWN:
case OSPF_IS_LOOP: case OSPF_IS_LOOP:
bug("%s: Iface %s in down state?", p->name, ifa->ifname); bug("%s: Iface %s in down state?", p->p.name, ifa->ifname);
break; break;
case OSPF_IS_WAITING: case OSPF_IS_WAITING:
DBG("%s: Neighbor? on iface %s\n", p->name, ifa->ifname); DBG("%s: Neighbor? on iface %s\n", p->p.name, ifa->ifname);
break; break;
case OSPF_IS_DROTHER: case OSPF_IS_DROTHER:
if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid)) if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
@ -302,15 +296,15 @@ can_do_adj(struct ospf_neighbor *n)
i = 1; i = 1;
break; break;
default: default:
bug("%s: Iface %s in unknown state?", p->name, ifa->ifname); bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname);
break; break;
} }
break; break;
default: default:
bug("%s: Iface %s is unknown type?", p->name, ifa->ifname); bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname);
break; break;
} }
DBG("%s: Iface %s can_do_adj=%d\n", p->name, ifa->ifname, i); DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i);
return i; return i;
} }
@ -329,8 +323,7 @@ can_do_adj(struct ospf_neighbor *n)
void void
ospf_neigh_sm(struct ospf_neighbor *n, int event) ospf_neigh_sm(struct ospf_neighbor *n, int event)
{ {
struct proto_ospf *po = n->ifa->oa->po; struct ospf_proto *p = n->ifa->oa->po;
struct proto *p = &po->proto;
DBG("Neighbor state machine for neighbor %I, event '%s'\n", n->ip, DBG("Neighbor state machine for neighbor %I, event '%s'\n", n->ip,
ospf_inm[event]); ospf_inm[event]);
@ -341,23 +334,23 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
neigh_chstate(n, NEIGHBOR_ATTEMPT); neigh_chstate(n, NEIGHBOR_ATTEMPT);
/* NBMA are used different way */ /* NBMA are used different way */
break; break;
case INM_HELLOREC: case INM_HELLOREC:
switch (n->state) if ((n->state == NEIGHBOR_DOWN) ||
{ (n->state == NEIGHBOR_ATTEMPT))
case NEIGHBOR_ATTEMPT:
case NEIGHBOR_DOWN:
neigh_chstate(n, NEIGHBOR_INIT); neigh_chstate(n, NEIGHBOR_INIT);
default:
tm_start(n->inactim, n->ifa->deadint); /* Restart inactivity timer */ /* Restart inactivity timer */
break; tm_start(n->inactim, n->ifa->deadint);
}
break; break;
case INM_2WAYREC: case INM_2WAYREC:
if (n->state < NEIGHBOR_2WAY) if (n->state < NEIGHBOR_2WAY)
neigh_chstate(n, NEIGHBOR_2WAY); neigh_chstate(n, NEIGHBOR_2WAY);
if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n)) if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
neigh_chstate(n, NEIGHBOR_EXSTART); neigh_chstate(n, NEIGHBOR_EXSTART);
break; break;
case INM_NEGDONE: case INM_NEGDONE:
if (n->state == NEIGHBOR_EXSTART) if (n->state == NEIGHBOR_EXSTART)
{ {
@ -365,25 +358,22 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
/* Reset DB summary list iterator */ /* Reset DB summary list iterator */
s_get(&(n->dbsi)); s_get(&(n->dbsi));
s_init(&(n->dbsi), &po->lsal); s_init(&(n->dbsi), &p->lsal);
while (!EMPTY_LIST(n->ackl[ACKL_DELAY])) ospf_reset_lsack_queue(n);
{
struct lsah_n *no;
no = (struct lsah_n *) HEAD(n->ackl[ACKL_DELAY]);
rem_node(NODE no);
mb_free(no);
}
} }
else else
bug("NEGDONE and I'm not in EXSTART?"); bug("NEGDONE and I'm not in EXSTART?");
break; break;
case INM_EXDONE: case INM_EXDONE:
neigh_chstate(n, NEIGHBOR_LOADING); neigh_chstate(n, NEIGHBOR_LOADING);
break; break;
case INM_LOADDONE: case INM_LOADDONE:
neigh_chstate(n, NEIGHBOR_FULL); neigh_chstate(n, NEIGHBOR_FULL);
break; break;
case INM_ADJOK: case INM_ADJOK:
switch (n->state) switch (n->state)
{ {
@ -404,6 +394,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
break; break;
} }
break; break;
case INM_SEQMIS: case INM_SEQMIS:
case INM_BADLSREQ: case INM_BADLSREQ:
if (n->state >= NEIGHBOR_EXCHANGE) if (n->state >= NEIGHBOR_EXCHANGE)
@ -412,24 +403,27 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
neigh_chstate(n, NEIGHBOR_EXSTART); neigh_chstate(n, NEIGHBOR_EXSTART);
} }
break; break;
case INM_KILLNBR: case INM_KILLNBR:
case INM_LLDOWN: case INM_LLDOWN:
case INM_INACTTIM: case INM_INACTTIM:
reset_lists(n); reset_lists(n);
neigh_chstate(n, NEIGHBOR_DOWN); neigh_chstate(n, NEIGHBOR_DOWN);
break; break;
case INM_1WAYREC: case INM_1WAYREC:
reset_lists(n); reset_lists(n);
neigh_chstate(n, NEIGHBOR_INIT); neigh_chstate(n, NEIGHBOR_INIT);
break; break;
default: default:
bug("%s: INM - Unknown event?", p->name); bug("%s: INM - Unknown event?", p->p.name);
break; break;
} }
} }
/** /**
* bdr_election - (Backup) Designed Router election * ospf_dr_election - (Backup) Designed Router election
* @ifa: actual interface * @ifa: actual interface
* *
* When the wait timer fires, it is time to elect (Backup) Designated Router. * When the wait timer fires, it is time to elect (Backup) Designated Router.
@ -438,12 +432,11 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
* Router. This process is described in 9.4 of RFC 2328. * Router. This process is described in 9.4 of RFC 2328.
*/ */
void void
bdr_election(struct ospf_iface *ifa) ospf_dr_election(struct ospf_iface *ifa)
{ {
struct proto_ospf *po = ifa->oa->po; struct ospf_proto *p = ifa->oa->po;
u32 myid = po->router_id;
struct ospf_neighbor *neigh, *ndr, *nbdr, me; struct ospf_neighbor *neigh, *ndr, *nbdr, me;
int doadj; u32 myid = p->router_id;
DBG("(B)DR election.\n"); DBG("(B)DR election.\n");
@ -452,19 +445,14 @@ bdr_election(struct ospf_iface *ifa)
me.priority = ifa->priority; me.priority = ifa->priority;
me.ip = ifa->addr->ip; me.ip = ifa->addr->ip;
#ifdef OSPFv2 me.dr = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid;
me.dr = ipa_to_u32(ifa->drip); me.bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid;
me.bdr = ipa_to_u32(ifa->bdrip);
#else /* OSPFv3 */
me.dr = ifa->drid;
me.bdr = ifa->bdrid;
me.iface_id = ifa->iface_id; me.iface_id = ifa->iface_id;
#endif
add_tail(&ifa->neigh_list, NODE & me); add_tail(&ifa->neigh_list, NODE & me);
nbdr = electbdr(ifa->neigh_list); nbdr = elect_bdr(p, ifa->neigh_list);
ndr = electdr(ifa->neigh_list); ndr = elect_dr(p, ifa->neigh_list);
if (ndr == NULL) if (ndr == NULL)
ndr = nbdr; ndr = nbdr;
@ -475,56 +463,47 @@ bdr_election(struct ospf_iface *ifa)
|| ((ifa->bdrid == myid) && (nbdr != &me)) || ((ifa->bdrid == myid) && (nbdr != &me))
|| ((ifa->bdrid != myid) && (nbdr == &me))) || ((ifa->bdrid != myid) && (nbdr == &me)))
{ {
#ifdef OSPFv2 me.dr = ndr ? neigh_get_id(p, ndr) : 0;
me.dr = ndr ? ipa_to_u32(ndr->ip) : 0; me.bdr = nbdr ? neigh_get_id(p, nbdr) : 0;
me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : 0;
#else /* OSPFv3 */
me.dr = ndr ? ndr->rid : 0;
me.bdr = nbdr ? nbdr->rid : 0;
#endif
nbdr = electbdr(ifa->neigh_list); nbdr = elect_bdr(p, ifa->neigh_list);
ndr = electdr(ifa->neigh_list); ndr = elect_dr(p, ifa->neigh_list);
if (ndr == NULL) if (ndr == NULL)
ndr = nbdr; ndr = nbdr;
} }
u32 odrid = ifa->drid; rem_node(NODE & me);
u32 obdrid = ifa->bdrid;
u32 old_drid = ifa->drid;
u32 old_bdrid = ifa->bdrid;
ifa->drid = ndr ? ndr->rid : 0; ifa->drid = ndr ? ndr->rid : 0;
ifa->drip = ndr ? ndr->ip : IPA_NONE; ifa->drip = ndr ? ndr->ip : IPA_NONE;
ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
ifa->bdrid = nbdr ? nbdr->rid : 0; ifa->bdrid = nbdr ? nbdr->rid : 0;
ifa->bdrip = nbdr ? nbdr->ip : IPA_NONE; ifa->bdrip = nbdr ? nbdr->ip : IPA_NONE;
#ifdef OSPFv3
ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
#endif
DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid); DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid);
doadj = ((ifa->drid != odrid) || (ifa->bdrid != obdrid)); if (ifa->drid == myid)
if (myid == ifa->drid)
ospf_iface_chstate(ifa, OSPF_IS_DR); ospf_iface_chstate(ifa, OSPF_IS_DR);
else if (ifa->bdrid == myid)
ospf_iface_chstate(ifa, OSPF_IS_BACKUP);
else else
{ ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
if (myid == ifa->bdrid)
ospf_iface_chstate(ifa, OSPF_IS_BACKUP);
else
ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
}
rem_node(NODE & me); /* Review neighbor adjacencies if DR or BDR changed */
if ((ifa->drid != old_drid) || (ifa->bdrid != old_bdrid))
if (doadj)
{
WALK_LIST(neigh, ifa->neigh_list) WALK_LIST(neigh, ifa->neigh_list)
{ if (neigh->state >= NEIGHBOR_2WAY)
ospf_neigh_sm(neigh, INM_ADJOK); ospf_neigh_sm(neigh, INM_ADJOK);
}
} /* RFC 2328 12.4 Event 3 - DR change */
if (ifa->drid != old_drid)
ospf_notify_rt_lsa(ifa->oa);
} }
struct ospf_neighbor * struct ospf_neighbor *
@ -553,9 +532,9 @@ neighbor_timer_hook(timer * timer)
{ {
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
struct proto *p = &ifa->oa->po->proto; struct ospf_proto *p = ifa->oa->po;
OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I.", OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I",
ifa->ifname, n->ip); ifa->ifname, n->ip);
ospf_neigh_remove(n); ospf_neigh_remove(n);
} }
@ -564,7 +543,7 @@ void
ospf_neigh_remove(struct ospf_neighbor *n) ospf_neigh_remove(struct ospf_neighbor *n)
{ {
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
struct proto *p = &ifa->oa->po->proto; struct ospf_proto *p = ifa->oa->po;
if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
{ {
@ -577,20 +556,18 @@ ospf_neigh_remove(struct ospf_neighbor *n)
neigh_chstate(n, NEIGHBOR_DOWN); neigh_chstate(n, NEIGHBOR_DOWN);
rem_node(NODE n); rem_node(NODE n);
rfree(n->pool); rfree(n->pool);
OSPF_TRACE(D_EVENTS, "Deleting neigbor."); OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", n->rid);
} }
static void static void
ospf_neigh_bfd_hook(struct bfd_request *req) ospf_neigh_bfd_hook(struct bfd_request *req)
{ {
struct ospf_neighbor *n = req->data; struct ospf_neighbor *n = req->data;
struct proto *p = &n->ifa->oa->po->proto; struct ospf_proto *p = n->ifa->oa->po;
if (req->down) if (req->down)
{ {
OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", n->ip, n->ifa->ifname);
n->ip, n->ifa->ifname);
ospf_neigh_remove(n); ospf_neigh_remove(n);
} }
} }
@ -646,52 +623,32 @@ static void
rxmt_timer_hook(timer * timer) rxmt_timer_hook(timer * timer)
{ {
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
// struct proto *p = &n->ifa->oa->po->proto; struct ospf_proto *p = n->ifa->oa->po;
struct top_hash_entry *en;
DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n", DBG("%s: RXMT timer fired on interface %s for neigh %I\n",
p->name, n->ifa->ifname, n->ip); p->p.name, n->ifa->ifname, n->ip);
if(n->state < NEIGHBOR_EXSTART) return; switch (n->state)
if (n->state == NEIGHBOR_EXSTART)
{ {
ospf_dbdes_send(n, 1); case NEIGHBOR_EXSTART:
ospf_send_dbdes(n, 1);
return; return;
}
if ((n->state == NEIGHBOR_EXCHANGE) && n->myimms.bit.ms) /* I'm master */ case NEIGHBOR_EXCHANGE:
ospf_dbdes_send(n, 0); if (n->myimms & DBDES_MS)
ospf_send_dbdes(n, 0);
case NEIGHBOR_LOADING:
ospf_send_lsreq(p, n);
return;
case NEIGHBOR_FULL:
/* LSA retransmissions */
if (!EMPTY_SLIST(n->lsrtl))
ospf_rxmt_lsupd(p, n);
return;
if (n->state < NEIGHBOR_FULL) default:
ospf_lsreq_send(n); /* EXCHANGE or LOADING */ return;
else
{
if (!EMPTY_SLIST(n->lsrtl)) /* FULL */
{
list uplist;
slab *upslab;
struct l_lsr_head *llsh;
init_list(&uplist);
upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
WALK_SLIST(en, n->lsrtl)
{
if ((SNODE en)->next == (SNODE en))
bug("RTList is cycled");
llsh = sl_alloc(upslab);
llsh->lsh.id = en->lsa.id;
llsh->lsh.rt = en->lsa.rt;
llsh->lsh.type = en->lsa.type;
DBG("Working on ID: %R, RT: %R, Type: %u\n",
en->lsa.id, en->lsa.rt, en->lsa.type);
add_tail(&uplist, NODE llsh);
}
ospf_lsupd_send_list(n, &uplist);
rfree(upslab);
}
} }
} }

View file

@ -1,22 +0,0 @@
/*
* BIRD -- OSPF
*
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_NEIGHBOR_H_
#define _BIRD_OSPF_NEIGHBOR_H_
struct ospf_neighbor *ospf_neighbor_new(struct ospf_iface *ifa);
void ospf_neigh_sm(struct ospf_neighbor *n, int event);
void bdr_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);
#endif /* _BIRD_OSPF_NEIGHBOR_H_ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

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--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (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.
*/ */
@ -13,233 +15,216 @@
void void
ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type) ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
{ {
struct proto_ospf *po = ifa->oa->po; struct ospf_proto *p = ifa->oa->po;
struct ospf_packet *pkt; struct ospf_packet *pkt;
pkt = (struct ospf_packet *) buf; pkt = (struct ospf_packet *) buf;
pkt->version = OSPF_VERSION; pkt->version = ospf_get_version(p);
pkt->type = h_type; pkt->type = h_type;
pkt->length = htons(ospf_pkt_maxsize(ifa));
pkt->routerid = htonl(po->router_id); pkt->routerid = htonl(p->router_id);
pkt->areaid = htonl(ifa->oa->areaid); pkt->areaid = htonl(ifa->oa->areaid);
#ifdef OSPFv3
pkt->instance_id = ifa->instance_id;
#endif
#ifdef OSPFv2
pkt->autype = htons(ifa->autype);
#endif
pkt->checksum = 0; pkt->checksum = 0;
pkt->instance_id = ifa->instance_id;
pkt->autype = ifa->autype;
} }
unsigned uint
ospf_pkt_maxsize(struct ospf_iface *ifa) ospf_pkt_maxsize(struct ospf_iface *ifa)
{ {
unsigned headers = SIZE_OF_IP_HEADER; uint headers = SIZE_OF_IP_HEADER;
#ifdef OSPFv2 /* Relevant just for OSPFv2 */
if (ifa->autype == OSPF_AUTH_CRYPT) if (ifa->autype == OSPF_AUTH_CRYPT)
headers += OSPF_AUTH_CRYPT_SIZE; headers += OSPF_AUTH_CRYPT_SIZE;
#endif
return ifa->tx_length - headers; return ifa->tx_length - headers;
} }
#ifdef OSPFv2 /* We assume OSPFv2 in ospf_pkt_finalize() */
static void static void
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
{ {
struct password_item *passwd = NULL; struct password_item *passwd = NULL;
void *tail; union ospf_auth *auth = (void *) (pkt + 1);
struct MD5Context ctxt; uint plen = ntohs(pkt->length);
char password[OSPF_AUTH_CRYPT_SIZE];
pkt->checksum = 0; pkt->checksum = 0;
pkt->autype = htons(ifa->autype); pkt->autype = ifa->autype;
bzero(&pkt->u, sizeof(union ospf_auth)); bzero(auth, sizeof(union ospf_auth));
/* Compatibility note: pkt->u may contain anything if autype is /* Compatibility note: auth may contain anything if autype is
none, but nonzero values do not work with Mikrotik OSPF */ none, but nonzero values do not work with Mikrotik OSPF */
switch(ifa->autype) switch (ifa->autype)
{ {
case OSPF_AUTH_SIMPLE: case OSPF_AUTH_SIMPLE:
passwd = password_find(ifa->passwords, 1); passwd = password_find(ifa->passwords, 1);
if (!passwd) if (!passwd)
{ {
log( L_ERR "No suitable password found for authentication" ); log(L_ERR "No suitable password found for authentication");
return; return;
} }
password_cpy(pkt->u.password, passwd->password, sizeof(union ospf_auth)); password_cpy(auth->password, passwd->password, sizeof(union ospf_auth));
case OSPF_AUTH_NONE:
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) -
sizeof(union ospf_auth), (pkt + 1),
ntohs(pkt->length) -
sizeof(struct ospf_packet), NULL);
break;
case OSPF_AUTH_CRYPT:
passwd = password_find(ifa->passwords, 0);
if (!passwd)
{
log( L_ERR "No suitable password found for authentication" );
return;
}
/* Perhaps use random value to prevent replay attacks after case OSPF_AUTH_NONE:
reboot when system does not have independent RTC? */ {
if (!ifa->csn) void *body = (void *) (auth + 1);
{ uint blen = plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth);
ifa->csn = (u32) now; pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL);
ifa->csn_use = now; }
} break;
/* We must have sufficient delay between sending a packet and increasing case OSPF_AUTH_CRYPT:
CSN to prevent reordering of packets (in a network) with different CSNs */ passwd = password_find(ifa->passwords, 0);
if ((now - ifa->csn_use) > 1) if (!passwd)
ifa->csn++; {
log(L_ERR "No suitable password found for authentication");
return;
}
/* Perhaps use random value to prevent replay attacks after
reboot when system does not have independent RTC? */
if (!ifa->csn)
{
ifa->csn = (u32) now;
ifa->csn_use = now; ifa->csn_use = now;
}
pkt->u.md5.keyid = passwd->id; /* We must have sufficient delay between sending a packet and increasing
pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE; CSN to prevent reordering of packets (in a network) with different CSNs */
pkt->u.md5.zero = 0; if ((now - ifa->csn_use) > 1)
pkt->u.md5.csn = htonl(ifa->csn); ifa->csn++;
tail = ((void *)pkt) + ntohs(pkt->length);
MD5Init(&ctxt); ifa->csn_use = now;
MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE); auth->md5.zero = 0;
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE); auth->md5.keyid = passwd->id;
MD5Final(tail, &ctxt); auth->md5.len = OSPF_AUTH_CRYPT_SIZE;
break; auth->md5.csn = htonl(ifa->csn);
default:
bug("Unknown authentication type"); void *tail = ((void *) pkt) + plen;
char password[OSPF_AUTH_CRYPT_SIZE];
password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
struct MD5Context ctxt;
MD5Init(&ctxt);
MD5Update(&ctxt, (char *) pkt, plen);
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
MD5Final(tail, &ctxt);
break;
default:
bug("Unknown authentication type");
} }
} }
/* We assume OSPFv2 in ospf_pkt_checkauth() */
static int 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 size)
{ {
struct proto_ospf *po = ifa->oa->po; struct ospf_proto *p = ifa->oa->po;
struct proto *p = &po->proto; union ospf_auth *auth = (void *) (pkt + 1);
struct password_item *pass = NULL, *ptmp; struct password_item *pass = NULL, *ptmp;
void *tail;
char md5sum[OSPF_AUTH_CRYPT_SIZE];
char password[OSPF_AUTH_CRYPT_SIZE]; char password[OSPF_AUTH_CRYPT_SIZE];
struct MD5Context ctxt;
uint plen = ntohs(pkt->length);
u8 autype = pkt->autype;
if (pkt->autype != htons(ifa->autype)) if (autype != ifa->autype)
{ {
OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype)); OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", autype);
return 0; return 0;
} }
switch(ifa->autype) switch (autype)
{ {
case OSPF_AUTH_NONE: case OSPF_AUTH_NONE:
return 1; return 1;
break;
case OSPF_AUTH_SIMPLE:
pass = password_find(ifa->passwords, 1);
if (!pass)
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found");
return 0;
}
password_cpy(password, pass->password, sizeof(union ospf_auth));
if (memcmp(pkt->u.password, password, sizeof(union ospf_auth))) case OSPF_AUTH_SIMPLE:
{ pass = password_find(ifa->passwords, 1);
char ppass[sizeof(union ospf_auth) + 1]; if (!pass)
bzero(ppass, (sizeof(union ospf_auth) + 1)); {
memcpy(ppass, pkt->u.password, sizeof(union ospf_auth)); OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found");
OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords (%s)", ppass);
return 0;
}
return 1;
break;
case OSPF_AUTH_CRYPT:
if (pkt->u.md5.len != OSPF_AUTH_CRYPT_SIZE)
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
return 0;
}
if (ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE > size)
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)",
ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE, size);
return 0;
}
tail = ((void *)pkt) + ntohs(pkt->length);
if (ifa->passwords)
{
WALK_LIST(ptmp, *(ifa->passwords))
{
if (pkt->u.md5.keyid != ptmp->id) continue;
if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue;
pass = ptmp;
break;
}
}
if (!pass)
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found");
return 0;
}
if (n)
{
u32 rcv_csn = ntohl(pkt->u.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;
}
n->csn = rcv_csn;
}
MD5Init(&ctxt);
MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
MD5Update(&ctxt, password, 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;
}
return 1;
break;
default:
OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
return 0; return 0;
}
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;
}
n->csn = rcv_csn;
}
if (ifa->passwords)
{
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;
}
}
if (!pass)
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found");
return 0;
}
void *tail = ((void *) pkt) + plen;
char md5sum[OSPF_AUTH_CRYPT_SIZE];
password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
struct MD5Context ctxt;
MD5Init(&ctxt);
MD5Update(&ctxt, (char *) pkt, plen);
MD5Update(&ctxt, password, 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;
}
return 1;
default:
OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
return 0;
} }
} }
#else
/* OSPFv3 authentication not yet supported */
static inline void
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
{ }
static int
ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
{ return 1; }
#endif
/** /**
* ospf_rx_hook * ospf_rx_hook
@ -266,43 +251,44 @@ ospf_rx_hook(sock *sk, int size)
/* Initially, the packet is associated with the 'master' iface */ /* Initially, the packet is associated with the 'master' iface */
struct ospf_iface *ifa = sk->data; struct ospf_iface *ifa = sk->data;
struct proto_ospf *po = ifa->oa->po; struct ospf_proto *p = ifa->oa->po;
// struct proto *p = &po->proto;
int src_local, dst_local UNUSED, dst_mcast; int src_local, dst_local, dst_mcast;
src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen); src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
dst_local = ipa_equal(sk->laddr, ifa->addr->ip); dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, AllDRouters); dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers);
#ifdef OSPFv2 if (ospf_is_v2(p))
/* First, we eliminate packets with strange address combinations. {
* In OSPFv2, they might be for other ospf_ifaces (with different IP /* First, we eliminate packets with strange address combinations.
* prefix) on the same real iface, so we don't log it. We enforce * In OSPFv2, they might be for other ospf_ifaces (with different IP
* that (src_local || dst_local), therefore we are eliminating all * prefix) on the same real iface, so we don't log it. We enforce
* such cases. * that (src_local || dst_local), therefore we are eliminating all
*/ * such cases.
if (dst_mcast && !src_local) */
return 1; if (dst_mcast && !src_local)
if (!dst_mcast && !dst_local) return 1;
return 1; if (!dst_mcast && !dst_local)
return 1;
/* Ignore my own broadcast packets */ /* Ignore my own broadcast packets */
if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip)) if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
return 1; return 1;
#else /* OSPFv3 */ }
else
/* In OSPFv3, src_local and dst_local mean link-local. {
* RFC 5340 says that local (non-vlink) packets use /* In OSPFv3, src_local and dst_local mean link-local.
* link-local src address, but does not enforce it. Strange. * RFC 5340 says that local (non-vlink) packets use
*/ * 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); if (dst_mcast && !src_local)
#endif log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
}
/* Second, we check packet size, checksum, and the protocol version */ /* Second, we check packet size, checksum, and the protocol version */
struct ospf_packet *ps = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size); struct ospf_packet *pkt = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size);
if (ps == NULL) if (pkt == NULL)
{ {
log(L_ERR "%s%I - bad IP header", mesg, sk->faddr); log(L_ERR "%s%I - bad IP header", mesg, sk->faddr);
return 1; return 1;
@ -314,13 +300,13 @@ ospf_rx_hook(sock *sk, int size)
return 1; return 1;
} }
if ((unsigned) size < sizeof(struct ospf_packet)) if ((uint) size < sizeof(struct ospf_packet))
{ {
log(L_ERR "%s%I - too short (%u bytes)", mesg, sk->faddr, size); log(L_ERR "%s%I - too short (%u bytes)", mesg, sk->faddr, size);
return 1; return 1;
} }
uint plen = ntohs(ps->length); uint plen = ntohs(pkt->length);
if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0)) if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0))
{ {
log(L_ERR "%s%I - invalid length (%u)", mesg, sk->faddr, plen); log(L_ERR "%s%I - invalid length (%u)", mesg, sk->faddr, plen);
@ -348,89 +334,101 @@ ospf_rx_hook(sock *sk, int size)
return 1; return 1;
} }
if (ps->version != OSPF_VERSION) if (pkt->version != ospf_get_version(p))
{ {
log(L_ERR "%s%I - version %u", mesg, sk->faddr, ps->version); log(L_ERR "%s%I - version %u", mesg, sk->faddr, pkt->version);
return 1; return 1;
} }
#ifdef OSPFv2 if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT))
if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
(!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
plen - sizeof(struct ospf_packet), NULL)))
{ {
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr); uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth);
return 1; uint blen = plen - hlen;
} void *body = ((void *) pkt) + hlen;
#endif
if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
{
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
return 1;
}
}
/* Third, we resolve associated iface and handle vlinks. */ /* Third, we resolve associated iface and handle vlinks. */
u32 areaid = ntohl(ps->areaid); u32 areaid = ntohl(pkt->areaid);
u32 rid = ntohl(ps->routerid); u32 rid = ntohl(pkt->routerid);
u8 instance_id = pkt->instance_id;
if ((areaid == ifa->oa->areaid) if (areaid == ifa->oa->areaid)
#ifdef OSPFv3
&& (ps->instance_id == ifa->instance_id)
#endif
)
{ {
/* It is real iface, source should be local (in OSPFv2) */ /* Matching area ID */
#ifdef OSPFv2
if (!src_local) if (instance_id != ifa->instance_id)
return 1; return 1;
#endif
}
else if (dst_mcast || (areaid != 0))
{
/* Obvious mismatch */
#ifdef OSPFv2 /* It is real iface, source should be local (in OSPFv2) */
/* We ignore mismatch in OSPFv3, because there might be if (ospf_is_v2(p) && !src_local)
other instance with different instance ID */ {
log(L_ERR "%s%I - area does not match (%R vs %R)", log(L_ERR "%s%I - strange source address for %s", mesg, sk->faddr, ifa->ifname);
mesg, sk->faddr, areaid, ifa->oa->areaid); return 1;
#endif }
goto found;
}
else if ((areaid == 0) && !dst_mcast)
{
/* Backbone area ID and possible vlink packet */
if ((p->areano == 1) || !oa_is_ext(ifa->oa))
return 1;
struct ospf_iface *iff = NULL;
WALK_LIST(iff, p->iface_list)
{
if ((iff->type == OSPF_IT_VLINK) &&
(iff->voa == ifa->oa) &&
(iff->instance_id == instance_id) &&
(iff->vid == rid))
{
/* Vlink should be UP */
if (iff->state != OSPF_IS_PTP)
return 1;
ifa = iff;
goto found;
}
}
/*
* Cannot find matching vlink. It is either misconfigured vlink; NBMA or
* PtMP with misconfigured area ID, or packet for some other instance (that
* is possible even if instance_id == ifa->instance_id, because it may be
* also vlink packet in the other instance, which is different namespace).
*/
return 1; return 1;
} }
else else
{ {
/* Some vlink? */ /* Non-matching area ID but cannot be vlink packet */
struct ospf_iface *iff = NULL;
WALK_LIST(iff, po->iface_list) if (instance_id != ifa->instance_id)
{ return 1;
if ((iff->type == OSPF_IT_VLINK) &&
(iff->voa == ifa->oa) &&
#ifdef OSPFv3
(iff->instance_id == ps->instance_id) &&
#endif
(iff->vid == rid))
{
/* Vlink should be UP */
if (iff->state != OSPF_IS_PTP)
return 1;
ifa = iff;
goto found;
}
}
#ifdef OSPFv2 log(L_ERR "%s%I - area does not match (%R vs %R)",
log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr); mesg, sk->faddr, areaid, ifa->oa->areaid);
#endif
return 1; return 1;
} }
found: found:
if (ifa->stub) /* This shouldn't happen */ if (ifa->stub) /* This shouldn't happen */
return 1; return 1;
if (ipa_equal(sk->laddr, AllDRouters) && (ifa->sk_dr == 0)) if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0))
return 1; return 1;
if (rid == po->router_id) if (rid == p->router_id)
{ {
log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr); log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr);
return 1; return 1;
@ -442,62 +440,51 @@ ospf_rx_hook(sock *sk, int size)
return 1; return 1;
} }
#ifdef OSPFv2
/* 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, base on network type */
uint t = ifa->type;
struct ospf_neighbor *n; struct ospf_neighbor *n;
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
n = find_neigh_by_ip(ifa, sk->faddr); n = find_neigh_by_ip(ifa, sk->faddr);
else else
n = find_neigh(ifa, rid); n = find_neigh(ifa, rid);
#else
struct ospf_neighbor *n = find_neigh(ifa, rid);
#endif
if(!n && (ps->type != HELLO_P)) if (!n && (pkt->type != HELLO_P))
{ {
log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)", log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)",
sk->faddr, ifa->ifname); sk->faddr, ifa->ifname);
return 1; return 1;
} }
if (!ospf_pkt_checkauth(n, ifa, ps, size)) if (ospf_is_v2(p) && !ospf_pkt_checkauth(n, ifa, pkt, size))
{ {
log(L_ERR "%s%I - authentication failed", mesg, sk->faddr); log(L_ERR "%s%I - authentication failed", mesg, sk->faddr);
return 1; return 1;
} }
/* Dump packet switch (pkt->type)
pu8=(u8 *)(sk->rbuf+5*4);
for(i=0;i<ntohs(ps->length);i+=4)
DBG("%s: received %u,%u,%u,%u\n",p->name, pu8[i+0], pu8[i+1], pu8[i+2],
pu8[i+3]);
DBG("%s: received size: %u\n",p->name,size);
*/
switch (ps->type)
{ {
case HELLO_P: case HELLO_P:
DBG("%s: Hello received.\n", p->name); ospf_receive_hello(pkt, ifa, n, sk->faddr);
ospf_hello_receive(ps, ifa, n, sk->faddr);
break; break;
case DBDES_P: case DBDES_P:
DBG("%s: Database description received.\n", p->name); ospf_receive_dbdes(pkt, ifa, n);
ospf_dbdes_receive(ps, ifa, n);
break; break;
case LSREQ_P: case LSREQ_P:
DBG("%s: Link state request received.\n", p->name); ospf_receive_lsreq(pkt, ifa, n);
ospf_lsreq_receive(ps, ifa, n);
break; break;
case LSUPD_P: case LSUPD_P:
DBG("%s: Link state update received.\n", p->name); ospf_receive_lsupd(pkt, ifa, n);
ospf_lsupd_receive(ps, ifa, n);
break; break;
case LSACK_P: case LSACK_P:
DBG("%s: Link state ack received.\n", p->name); ospf_receive_lsack(pkt, ifa, n);
ospf_lsack_receive(ps, ifa, n);
break; break;
default: default:
log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, ps->type); log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, pkt->type);
return 1; return 1;
}; };
return 1; return 1;
@ -508,7 +495,7 @@ void
ospf_tx_hook(sock * sk) ospf_tx_hook(sock * sk)
{ {
struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
// struct proto *p = (struct proto *) (ifa->oa->po); // struct proto *p = (struct proto *) (ifa->oa->p);
log(L_ERR "OSPF: TX hook called on %s", ifa->ifname); log(L_ERR "OSPF: TX hook called on %s", ifa->ifname);
} }
*/ */
@ -517,16 +504,35 @@ void
ospf_err_hook(sock * sk, int err) ospf_err_hook(sock * sk, int err)
{ {
struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
struct proto *p = &(ifa->oa->po->proto); struct ospf_proto *p = ifa->oa->po;
log(L_ERR "%s: Socket error on %s: %M", p->name, ifa->ifname, err); log(L_ERR "%s: Socket error on %s: %M", p->p.name, ifa->ifname, err);
} }
void void
ospf_verr_hook(sock *sk, int err) ospf_verr_hook(sock *sk, int err)
{ {
struct proto_ospf *po = (struct proto_ospf *) (sk->data); struct ospf_proto *p = (struct ospf_proto *) (sk->data);
struct proto *p = &po->proto; log(L_ERR "%s: Vlink socket error: %M", p->p.name, err);
log(L_ERR "%s: Vlink socket error: %M", p->name, err); }
void
ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
{
sock *sk = ifa->sk;
struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
int plen = ntohs(pkt->length);
if (ospf_is_v2(ifa->oa->po))
{
if (ifa->autype == OSPF_AUTH_CRYPT)
plen += OSPF_AUTH_CRYPT_SIZE;
ospf_pkt_finalize(ifa, pkt);
}
int done = sk_send_to(sk, plen, dst, 0);
if (!done)
log(L_WARN "OSPF: TX queue full on %s", ifa->ifname);
} }
void void
@ -542,28 +548,8 @@ ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
void void
ospf_send_to_bdr(struct ospf_iface *ifa) ospf_send_to_bdr(struct ospf_iface *ifa)
{ {
if (!ipa_equal(ifa->drip, IPA_NONE)) if (ipa_nonzero(ifa->drip))
ospf_send_to(ifa, ifa->drip); ospf_send_to(ifa, ifa->drip);
if (!ipa_equal(ifa->bdrip, IPA_NONE)) if (ipa_nonzero(ifa->bdrip))
ospf_send_to(ifa, ifa->bdrip); ospf_send_to(ifa, ifa->bdrip);
} }
void
ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
{
sock *sk = ifa->sk;
struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
int len = ntohs(pkt->length);
#ifdef OSPFv2
if (ifa->autype == OSPF_AUTH_CRYPT)
len += OSPF_AUTH_CRYPT_SIZE;
#endif
ospf_pkt_finalize(ifa, pkt);
int done = sk_send_to(sk, len, dst, 0);
if (!done)
log(L_WARN "OSPF: TX queue full on %s", ifa->ifname);
}

View file

@ -1,28 +0,0 @@
/*
* BIRD -- OSPF
*
* (c) 1999--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_PACKET_H_
#define _BIRD_OSPF_PACKET_H_
void ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type);
uint ospf_pkt_maxsize(struct ospf_iface *ifa);
int ospf_rx_hook(sock * sk, int size);
// void ospf_tx_hook(sock * sk);
void ospf_err_hook(sock * sk, int err);
void ospf_verr_hook(sock *sk, int err);
void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
void ospf_send_to_bdr(struct ospf_iface *ifa);
void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); }
static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; }
#endif /* _BIRD_OSPF_PACKET_H_ */

File diff suppressed because it is too large Load diff

View file

@ -10,9 +10,9 @@
#ifndef _BIRD_OSPF_RT_H_ #ifndef _BIRD_OSPF_RT_H_
#define _BIRD_OSPF_RT_H_ #define _BIRD_OSPF_RT_H_
#define ORT_UNDEF -1
#define ORT_ROUTER 1
#define ORT_NET 0 #define ORT_NET 0
#define ORT_ROUTER 1
typedef struct orta typedef struct orta
{ {
@ -51,26 +51,33 @@ typedef struct orta
} }
orta; orta;
/* Values for fn.flags in struct ort */
#define OSPF_RT_PERSISTENT 0x01
typedef struct ort typedef struct ort
{ {
/* /*
* We use fn.x0 to mark persistent rt entries, that are needed for summary * We use OSPF_RT_PERSISTENT to mark persistent rt entries, that are
* LSAs that don't have 'proper' rt entry (area networks + default to stubs) * needed for summary LSAs that don't have 'proper' rt entry (area
* to keep uid stable (used for LSA ID in OSPFv3 - see fibnode_to_lsaid()). * networks + default to stubs) to keep uid stable (used for LSA ID
* in OSPFv3 - see fibnode_to_lsaid()).
* *
* We use fn.x1 to note whether the external route was originated * We use ORT_RT_EXPORT and ORT_RT_NSSA to note whether the
* from the route export (in ospf_rt_notify()) or from the NSSA * external/NSSA route was originated from the route export (in
* route translation (in check_nssa_lsa()). * ospf_rt_notify()) or from the NSSA route translation (in
* check_nssa_lsa()).
* *
* old_* values are here to represent the last route update. old_rta * old_* values are here to represent the last route update. old_rta
* is cached (we keep reference), mainly for multipath nexthops. * is cached (we keep reference), mainly for multipath nexthops.
* old_rta == NULL means route wasn not in the last update, in that * old_rta == NULL means route was not in the last update, in that
* case other old_* values are not valid. * case other old_* values are not valid.
*/ */
struct fib_node fn; struct fib_node fn;
orta n; orta n;
u32 old_metric1, old_metric2, old_tag, old_rid; u32 old_metric1, old_metric2, old_tag, old_rid;
rta *old_rta; rta *old_rta;
u8 external_rte;
} }
ort; ort;
@ -114,7 +121,7 @@ static inline int rt_is_nssa(ort *nf)
* appear in ASBR pre-selection and external routes processing. * appear in ASBR pre-selection and external routes processing.
*/ */
void ospf_rt_spf(struct proto_ospf *po); void ospf_rt_spf(struct ospf_proto *p);
void ospf_rt_initort(struct fib_node *fn); void ospf_rt_initort(struct fib_node *fn);

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,8 @@
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 1999--2004 Ondrej Filip <feela@network.cz> * (c) 1999--2004 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (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.
*/ */
@ -16,79 +18,102 @@ struct top_hash_entry
in intra-area routing table calculation */ in intra-area routing table calculation */
struct top_hash_entry *next; /* Next in hash chain */ struct top_hash_entry *next; /* Next in hash chain */
struct ospf_lsa_header lsa; struct ospf_lsa_header lsa;
u16 lsa_type; /* lsa.type processed and converted to common values */
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 */ u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */
// struct ospf_area *oa; // struct ospf_area *oa;
void *lsa_body; void *lsa_body; /* May be NULL if LSA was flushed but hash entry was kept */
bird_clock_t inst_t; /* Time of installation into DB */ void *next_lsa_body; /* For postponed LSA origination */
u16 next_lsa_blen; /* For postponed LSA origination */
u16 next_lsa_opts; /* For postponed LSA origination */
bird_clock_t inst_time; /* Time of installation into DB */
struct ort *nf; /* Reference fibnode for sum and ext LSAs, NULL for otherwise */
struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */ struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */ ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */
#ifdef OSPFv3
u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */ u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
#endif
u32 dist; /* Distance from the root */ u32 dist; /* Distance from the root */
u16 ini_age; int ret_count; /* Number of retransmission lists referencing the entry */
u8 color; u8 color;
#define OUTSPF 0 #define OUTSPF 0
#define CANDIDATE 1 #define CANDIDATE 1
#define INSPF 2 #define INSPF 2
u8 rtcalc; /* LSA generated during RT calculation (LSA_RTCALC or LSA_STALE)*/
u8 nhs_reuse; /* Whether nhs nodes can be reused during merging. u8 nhs_reuse; /* Whether nhs nodes can be reused during merging.
See a note in rt.c:merge_nexthops() */ See a note in rt.c:merge_nexthops() */
}; };
#define LSA_RTCALC 1
#define LSA_STALE 2
struct top_graph 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 hash_size; uint ospf2; /* Whether it is for OSPFv2 or OSPFv3 */
unsigned int hash_order; uint hash_size;
unsigned int hash_mask; uint hash_order;
unsigned int hash_entries; uint hash_mask;
unsigned int hash_entries_min, hash_entries_max; uint hash_entries;
uint hash_entries_min, hash_entries_max;
};
struct ospf_new_lsa
{
u16 type;
u32 dom;
u32 id;
u16 opts;
u16 length;
struct ospf_iface *ifa;
struct ort *nf;
}; };
struct top_graph *ospf_top_new(pool *); struct top_graph *ospf_top_new(pool *);
void ospf_top_free(struct top_graph *); void ospf_top_free(struct top_graph *);
void ospf_top_dump(struct top_graph *, struct proto *); void ospf_top_dump(struct top_graph *, struct proto *);
u32 ospf_lsa_domain(u32 type, struct ospf_iface *ifa);
struct top_hash_entry *ospf_hash_find_header(struct top_graph *f, u32 domain,
struct ospf_lsa_header *h);
struct top_hash_entry *ospf_hash_get_header(struct top_graph *f, u32 domain,
struct ospf_lsa_header *h);
struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, struct top_hash_entry * ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
u32 type); struct top_hash_entry * ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa);
struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr, void ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
u32 type); void ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en);
void ospf_update_lsadb(struct ospf_proto *p);
static inline void ospf_flush2_lsa(struct ospf_proto *p, struct top_hash_entry **en)
{ if (*en) { ospf_flush_lsa(p, *en); *en = NULL; } }
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_rt_notify(struct proto *P, rtable *tbl, net *n, rte *new, rte *old, ea_list *attrs);
void ospf_update_topology(struct ospf_proto *p);
struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type);
struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type);
void ospf_hash_delete(struct top_graph *, struct top_hash_entry *); void ospf_hash_delete(struct top_graph *, struct top_hash_entry *);
void originate_rt_lsa(struct ospf_area *oa);
void update_rt_lsa(struct ospf_area *oa);
void originate_net_lsa(struct ospf_iface *ifa);
void update_net_lsa(struct ospf_iface *ifa);
void update_link_lsa(struct ospf_iface *ifa);
int can_flush_lsa(struct proto_ospf *po);
void originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric); static inline struct top_hash_entry * ospf_hash_find_entry(struct top_graph *f, struct top_hash_entry *en)
void originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED); { return ospf_hash_find(f, en->domain, en->lsa.id, en->lsa.rt, en->lsa_type); }
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 flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int nssa);
static inline struct top_hash_entry * ospf_hash_get_entry(struct top_graph *f, struct top_hash_entry *en)
{ return ospf_hash_get(f, en->domain, en->lsa.id, en->lsa.rt, en->lsa_type); }
#ifdef OSPFv2
struct top_hash_entry * ospf_hash_find_net(struct top_graph *f, u32 domain, u32 lsa);
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);
}
#else /* OSPFv3 */
struct top_hash_entry * ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr); 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_rt3_first(struct top_graph *f, u32 domain, u32 rtr);
struct top_hash_entry * ospf_hash_find_rt_next(struct top_hash_entry *e); struct top_hash_entry * ospf_hash_find_rt3_next(struct top_hash_entry *e);
#endif
struct top_hash_entry * ospf_hash_find_net2(struct top_graph *f, u32 domain, u32 id);
/* 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 f->ospf2 ?
ospf_hash_find_net2(f, domain, id) :
ospf_hash_find(f, domain, nif, id, LSA_T_NET);
}
#endif /* _BIRD_OSPF_TOPOLOGY_H_ */ #endif /* _BIRD_OSPF_TOPOLOGY_H_ */