Temporary integrated OSPF commit.
This commit is contained in:
parent
9eceab33f9
commit
70945cb645
28 changed files with 5077 additions and 5271 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 *);
|
||||||
|
|
|
@ -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));
|
||||||
|
@ -102,25 +96,26 @@ 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 '}'
|
||||||
|
@ -250,9 +245,9 @@ ospf_vlink_item:
|
||||||
| 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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
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;
|
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)
|
|
||||||
{
|
|
||||||
struct ospf_lsa_header *plsa, lsa;
|
|
||||||
struct top_hash_entry *he, *sn;
|
|
||||||
struct ospf_area *oa = n->ifa->oa;
|
|
||||||
struct top_graph *gr = oa->po->gr;
|
|
||||||
struct ospf_packet *op;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
op = (struct ospf_packet *) ps;
|
static int
|
||||||
|
ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
|
||||||
plsa = (void *) (ps + 1);
|
|
||||||
|
|
||||||
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 ospf_iface *ifa = n->ifa;
|
||||||
u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
|
struct ospf_lsa_header *lsas;
|
||||||
if (((he = ospf_hash_find_header(gr, dom, &lsa)) == NULL) ||
|
uint i, lsa_count;
|
||||||
(lsa_comp(&lsa, &(he->lsa)) == 1))
|
|
||||||
|
ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
|
||||||
|
|
||||||
|
for (i = 0; i < lsa_count; i++)
|
||||||
{
|
{
|
||||||
/* Is this condition necessary? */
|
struct top_hash_entry *en, *req;
|
||||||
if (ospf_hash_find_header(n->lsrqh, dom, &lsa) == NULL)
|
struct ospf_lsa_header lsa;
|
||||||
|
u32 lsa_type, lsa_domain;
|
||||||
|
|
||||||
|
lsa_ntoh_hdr(lsas + i, &lsa);
|
||||||
|
lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
|
||||||
|
|
||||||
|
/* RFC 2328 10.6 and RFC 5340 4.2.2 */
|
||||||
|
|
||||||
|
if (!lsa_type)
|
||||||
{
|
{
|
||||||
sn = ospf_hash_get_header(n->lsrqh, dom, &lsa);
|
log(L_WARN "%s: Bad DBDES from %I - LSA of unknown type", p->p.name, n->ip);
|
||||||
ntohlsah(plsa + i, &(sn->lsa));
|
goto err;
|
||||||
s_add_tail(&(n->lsrql), SNODE sn);
|
}
|
||||||
}
|
|
||||||
|
if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
|
||||||
|
{
|
||||||
|
log(L_WARN "%s: Bad DBDES from %I - LSA with AS scope in stub area", p->p.name, n->ip);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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++;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_ */
|
|
|
@ -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) ||
|
if ((ifa->type == OSPF_IT_VLINK) ||
|
||||||
((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
|
((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
|
||||||
pkt->netmask = IPA_NONE;
|
ps->netmask = 0;
|
||||||
#endif
|
else
|
||||||
|
ps->netmask = htonl(u32_mkmask(ifa->addr->pxlen));
|
||||||
|
|
||||||
pkt->helloint = ntohs(ifa->helloint);
|
ps->helloint = ntohs(ifa->helloint);
|
||||||
pkt->priority = ifa->priority;
|
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));
|
||||||
|
|
||||||
#ifdef OSPFv3
|
length = sizeof(struct ospf_hello2_packet);
|
||||||
pkt->iface_id = htonl(ifa->iface_id);
|
neighbors = ps->neighbors;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct ospf_hello3_packet *ps = (void *) pkt;
|
||||||
|
|
||||||
pkt->options3 = ifa->oa->options >> 16;
|
ps->iface_id = htonl(ifa->iface_id);
|
||||||
pkt->options2 = ifa->oa->options >> 8;
|
ps->priority = ifa->priority;
|
||||||
#endif
|
ps->options3 = ifa->oa->options >> 16;
|
||||||
pkt->options = ifa->oa->options;
|
ps->options2 = ifa->oa->options >> 8;
|
||||||
|
ps->options = ifa->oa->options;
|
||||||
|
ps->helloint = ntohs(ifa->helloint);
|
||||||
|
ps->deadint = htons(ifa->deadint);
|
||||||
|
ps->dr = htonl(ifa->drid);
|
||||||
|
ps->bdr = htonl(ifa->bdrid);
|
||||||
|
|
||||||
#ifdef OSPFv2
|
length = sizeof(struct ospf_hello3_packet);
|
||||||
pkt->deadint = htonl(ifa->deadint);
|
neighbors = ps->neighbors;
|
||||||
pkt->dr = htonl(ipa_to_u32(ifa->drip));
|
}
|
||||||
pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
|
|
||||||
#else /* OSPFv3 */
|
i = 0;
|
||||||
pkt->deadint = htons(ifa->deadint);
|
max = (ospf_pkt_maxsize(ifa) - length) / sizeof(u32);
|
||||||
pkt->dr = htonl(ifa->drid);
|
|
||||||
pkt->bdr = htonl(ifa->bdrid);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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()");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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_ */
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
void
|
||||||
* =====================================
|
ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int queue)
|
||||||
* Note, that h is in network endianity!
|
{
|
||||||
* =====================================
|
/* Note that h_n is in network endianity */
|
||||||
*/
|
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);
|
||||||
|
DBG("Adding %s ack for %R, ID: %R, RT: %R, Type: %u\n",
|
||||||
|
(queue == ACKL_DIRECT) ? "direct" : "delayed",
|
||||||
|
n->rid, ntohl(h_n->id), ntohl(h_n->rt), h_n->type);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
|
ospf_reset_lsack_queue(struct ospf_neighbor *n)
|
||||||
int queue)
|
|
||||||
{
|
{
|
||||||
struct lsah_n *no = mb_alloc(n->pool, sizeof(struct lsah_n));
|
struct lsa_node *no;
|
||||||
memcpy(&no->lsa, h, sizeof(struct ospf_lsa_header));
|
|
||||||
add_tail(&n->ackl[queue], NODE no);
|
WALK_LIST_FIRST(no, n->ackl[ACKL_DELAY])
|
||||||
DBG("Adding (%s) ack for %R, ID: %R, RT: %R, Type: %u\n", s_queue[queue],
|
{
|
||||||
n->rid, ntohl(h->id), ntohl(h->rt), h->type);
|
rem_node(NODE no);
|
||||||
|
mb_free(no);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* RFC 2328 13.5 */
|
||||||
|
|
||||||
|
pkt = ospf_tx_buffer(ifa);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsa_header);
|
||||||
|
pkt->length = htons(length);
|
||||||
|
|
||||||
|
OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent via %s", ifa->ifname);
|
||||||
|
|
||||||
|
if (ifa->type == OSPF_IT_BCAST)
|
||||||
|
{
|
||||||
|
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
|
||||||
|
ospf_send_to_all(ifa);
|
||||||
|
else
|
||||||
|
ospf_send_to_des(ifa);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_lsack_send(struct ospf_neighbor *n, int queue)
|
ospf_lsack_send(struct ospf_neighbor *n, int queue)
|
||||||
{
|
{
|
||||||
struct ospf_packet *op;
|
|
||||||
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]))
|
|
||||||
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]))
|
while (!EMPTY_LIST(n->ackl[queue]))
|
||||||
{
|
ospf_send_lsack(n, 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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (ifa->type == OSPF_IT_BCAST)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header);
|
|
||||||
op->length = htons(len);
|
|
||||||
DBG("Sending! Len=%u\n", len);
|
|
||||||
|
|
||||||
OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
|
|
||||||
|
|
||||||
if (ifa->type == OSPF_IT_BCAST)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_ */
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
if (i != 0)
|
|
||||||
i--;
|
|
||||||
|
|
||||||
length =
|
DBG("Requesting %uth LSA: Type: %04u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
|
||||||
sizeof(struct ospf_lsreq_packet) + (j -
|
i, en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
|
||||||
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);
|
u32 etype = lsa_get_etype(&en->lsa, p);
|
||||||
ospf_send_to(n->ifa, n->ip);
|
lsrs[i].type = htonl(etype);
|
||||||
|
lsrs[i].rt = htonl(en->lsa.rt);
|
||||||
|
lsrs[i].id = htonl(en->lsa.id);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsreq_header);
|
||||||
|
pkt->length = htons(length);
|
||||||
|
|
||||||
|
OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet sent to %I via %s", n->ip, ifa->ifname);
|
||||||
|
ospf_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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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_ */
|
|
|
@ -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;
|
|
||||||
|
|
||||||
oldstate = n->state;
|
|
||||||
|
|
||||||
if (oldstate != state)
|
|
||||||
{
|
{
|
||||||
struct ospf_iface *ifa = n->ifa;
|
struct ospf_iface *ifa = n->ifa;
|
||||||
struct proto_ospf *po = ifa->oa->po;
|
struct ospf_proto *p = ifa->oa->po;
|
||||||
struct proto *p = &po->proto;
|
u8 old_state = n->state;
|
||||||
|
int old_fadj = ifa->fadj;
|
||||||
|
|
||||||
|
if (state == old_state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from %s to %s",
|
||||||
|
n->ip, ospf_ns[old_state], ospf_ns[state]);
|
||||||
|
|
||||||
n->state = state;
|
n->state = state;
|
||||||
|
|
||||||
OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from \"%s\" to \"%s\".",
|
if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY))
|
||||||
n->ip, ospf_ns[oldstate], ospf_ns[state]);
|
|
||||||
|
|
||||||
if ((state == NEIGHBOR_2WAY) && (oldstate < NEIGHBOR_2WAY))
|
|
||||||
ospf_iface_sm(ifa, ISM_NEICH);
|
ospf_iface_sm(ifa, ISM_NEICH);
|
||||||
if ((state < NEIGHBOR_2WAY) && (oldstate >= NEIGHBOR_2WAY))
|
if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY))
|
||||||
ospf_iface_sm(ifa, ISM_NEICH);
|
ospf_iface_sm(ifa, ISM_NEICH);
|
||||||
|
|
||||||
if (oldstate == NEIGHBOR_FULL) /* Decrease number of adjacencies */
|
/* Increase number of partial adjacencies */
|
||||||
{
|
if ((state == NEIGHBOR_EXCHANGE) || (state == NEIGHBOR_LOADING))
|
||||||
ifa->fadj--;
|
p->padj++;
|
||||||
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 */
|
/* 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++;
|
ifa->fadj++;
|
||||||
schedule_rt_lsa(ifa->oa);
|
|
||||||
if (ifa->type == OSPF_IT_VLINK) schedule_rt_lsa(ifa->voa);
|
/* Decrease number of full adjacencies */
|
||||||
schedule_net_lsa(ifa);
|
if (old_state == NEIGHBOR_FULL)
|
||||||
|
ifa->fadj--;
|
||||||
|
|
||||||
|
if (ifa->fadj != old_fadj)
|
||||||
|
{
|
||||||
|
/* RFC 2328 12.4 Event 4 - neighbor enters/leaves Full state */
|
||||||
|
ospf_notify_rt_lsa(ifa->oa);
|
||||||
|
ospf_notify_net_lsa(ifa);
|
||||||
|
|
||||||
|
/* RFC 2328 12.4 Event 8 - vlink state change */
|
||||||
|
if (ifa->type == OSPF_IT_VLINK)
|
||||||
|
ospf_notify_rt_lsa(ifa->voa);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == NEIGHBOR_EXSTART)
|
if (state == NEIGHBOR_EXSTART)
|
||||||
{
|
{
|
||||||
if (n->adj == 0) /* First time adjacency */
|
/* First time adjacency */
|
||||||
{
|
if (n->adj == 0)
|
||||||
n->dds = random_u32();
|
n->dds = random_u32();
|
||||||
}
|
|
||||||
n->dds++;
|
n->dds++;
|
||||||
n->myimms.byte = 0;
|
n->myimms = DBDES_IMMS;
|
||||||
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)
|
||||||
|
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
|
else if (ifa->bdrid == myid)
|
||||||
{
|
|
||||||
if (myid == ifa->bdrid)
|
|
||||||
ospf_iface_chstate(ifa, OSPF_IS_BACKUP);
|
ospf_iface_chstate(ifa, OSPF_IS_BACKUP);
|
||||||
else
|
else
|
||||||
ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
@ -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,57 +15,46 @@
|
||||||
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)
|
||||||
|
@ -75,13 +66,16 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
|
||||||
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:
|
case OSPF_AUTH_NONE:
|
||||||
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) -
|
{
|
||||||
sizeof(union ospf_auth), (pkt + 1),
|
void *body = (void *) (auth + 1);
|
||||||
ntohs(pkt->length) -
|
uint blen = plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth);
|
||||||
sizeof(struct ospf_packet), NULL);
|
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OSPF_AUTH_CRYPT:
|
case OSPF_AUTH_CRYPT:
|
||||||
passwd = password_find(ifa->passwords, 0);
|
passwd = password_find(ifa->passwords, 0);
|
||||||
if (!passwd)
|
if (!passwd)
|
||||||
|
@ -105,45 +99,50 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
|
||||||
|
|
||||||
ifa->csn_use = now;
|
ifa->csn_use = now;
|
||||||
|
|
||||||
pkt->u.md5.keyid = passwd->id;
|
auth->md5.zero = 0;
|
||||||
pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE;
|
auth->md5.keyid = passwd->id;
|
||||||
pkt->u.md5.zero = 0;
|
auth->md5.len = OSPF_AUTH_CRYPT_SIZE;
|
||||||
pkt->u.md5.csn = htonl(ifa->csn);
|
auth->md5.csn = htonl(ifa->csn);
|
||||||
tail = ((void *)pkt) + ntohs(pkt->length);
|
|
||||||
MD5Init(&ctxt);
|
void *tail = ((void *) pkt) + plen;
|
||||||
MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
|
char password[OSPF_AUTH_CRYPT_SIZE];
|
||||||
password_cpy(password, passwd->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);
|
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
|
||||||
MD5Final(tail, &ctxt);
|
MD5Final(tail, &ctxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
bug("Unknown authentication type");
|
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:
|
case OSPF_AUTH_SIMPLE:
|
||||||
pass = password_find(ifa->passwords, 1);
|
pass = password_find(ifa->passwords, 1);
|
||||||
if (!pass)
|
if (!pass)
|
||||||
|
@ -151,39 +150,46 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_
|
||||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found");
|
OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
password_cpy(password, pass->password, sizeof(union ospf_auth));
|
|
||||||
|
|
||||||
if (memcmp(pkt->u.password, password, sizeof(union ospf_auth)))
|
password_cpy(password, pass->password, sizeof(union ospf_auth));
|
||||||
|
if (memcmp(auth->password, password, sizeof(union ospf_auth)))
|
||||||
{
|
{
|
||||||
char ppass[sizeof(union ospf_auth) + 1];
|
OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords");
|
||||||
bzero(ppass, (sizeof(union ospf_auth) + 1));
|
|
||||||
memcpy(ppass, pkt->u.password, sizeof(union ospf_auth));
|
|
||||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords (%s)", ppass);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
|
||||||
case OSPF_AUTH_CRYPT:
|
case OSPF_AUTH_CRYPT:
|
||||||
if (pkt->u.md5.len != OSPF_AUTH_CRYPT_SIZE)
|
if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE)
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
|
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE > size)
|
if (plen + OSPF_AUTH_CRYPT_SIZE > size)
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)",
|
OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)",
|
||||||
ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE, size);
|
plen + OSPF_AUTH_CRYPT_SIZE, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tail = ((void *)pkt) + ntohs(pkt->length);
|
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)
|
if (ifa->passwords)
|
||||||
{
|
{
|
||||||
WALK_LIST(ptmp, *(ifa->passwords))
|
WALK_LIST(ptmp, *(ifa->passwords))
|
||||||
{
|
{
|
||||||
if (pkt->u.md5.keyid != ptmp->id) continue;
|
if (auth->md5.keyid != ptmp->id) continue;
|
||||||
if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue;
|
if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue;
|
||||||
pass = ptmp;
|
pass = ptmp;
|
||||||
break;
|
break;
|
||||||
|
@ -196,50 +202,29 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n)
|
void *tail = ((void *) pkt) + plen;
|
||||||
{
|
char md5sum[OSPF_AUTH_CRYPT_SIZE];
|
||||||
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);
|
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);
|
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
|
||||||
MD5Final(md5sum, &ctxt);
|
MD5Final(md5sum, &ctxt);
|
||||||
|
|
||||||
if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
|
if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
|
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
|
OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
|
||||||
return 0;
|
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,15 +251,15 @@ 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.
|
/* First, we eliminate packets with strange address combinations.
|
||||||
* In OSPFv2, they might be for other ospf_ifaces (with different IP
|
* In OSPFv2, they might be for other ospf_ifaces (with different IP
|
||||||
* prefix) on the same real iface, so we don't log it. We enforce
|
* prefix) on the same real iface, so we don't log it. We enforce
|
||||||
|
@ -289,20 +274,21 @@ ospf_rx_hook(sock *sk, int size)
|
||||||
/* 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.
|
/* In OSPFv3, src_local and dst_local mean link-local.
|
||||||
* RFC 5340 says that local (non-vlink) packets use
|
* RFC 5340 says that local (non-vlink) packets use
|
||||||
* link-local src address, but does not enforce it. Strange.
|
* link-local src address, but does not enforce it. Strange.
|
||||||
*/
|
*/
|
||||||
if (dst_mcast && !src_local)
|
if (dst_mcast && !src_local)
|
||||||
log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
|
log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
|
||||||
#endif
|
}
|
||||||
|
|
||||||
/* 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,64 +334,60 @@ 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),
|
uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth);
|
||||||
plen - sizeof(struct ospf_packet), NULL)))
|
uint blen = plen - hlen;
|
||||||
|
void *body = ((void *) pkt) + hlen;
|
||||||
|
|
||||||
|
if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
|
||||||
{
|
{
|
||||||
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
|
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
/* Matching area ID */
|
||||||
|
|
||||||
|
if (instance_id != ifa->instance_id)
|
||||||
|
return 1;
|
||||||
|
|
||||||
/* It is real iface, source should be local (in OSPFv2) */
|
/* It is real iface, source should be local (in OSPFv2) */
|
||||||
#ifdef OSPFv2
|
if (ospf_is_v2(p) && !src_local)
|
||||||
if (!src_local)
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if (dst_mcast || (areaid != 0))
|
|
||||||
{
|
{
|
||||||
/* Obvious mismatch */
|
log(L_ERR "%s%I - strange source address for %s", mesg, sk->faddr, ifa->ifname);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef OSPFv2
|
goto found;
|
||||||
/* We ignore mismatch in OSPFv3, because there might be
|
|
||||||
other instance with different instance ID */
|
|
||||||
log(L_ERR "%s%I - area does not match (%R vs %R)",
|
|
||||||
mesg, sk->faddr, areaid, ifa->oa->areaid);
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
else
|
else if ((areaid == 0) && !dst_mcast)
|
||||||
{
|
{
|
||||||
/* Some vlink? */
|
/* Backbone area ID and possible vlink packet */
|
||||||
|
|
||||||
|
if ((p->areano == 1) || !oa_is_ext(ifa->oa))
|
||||||
|
return 1;
|
||||||
|
|
||||||
struct ospf_iface *iff = NULL;
|
struct ospf_iface *iff = NULL;
|
||||||
|
WALK_LIST(iff, p->iface_list)
|
||||||
WALK_LIST(iff, po->iface_list)
|
|
||||||
{
|
{
|
||||||
if ((iff->type == OSPF_IT_VLINK) &&
|
if ((iff->type == OSPF_IT_VLINK) &&
|
||||||
(iff->voa == ifa->oa) &&
|
(iff->voa == ifa->oa) &&
|
||||||
#ifdef OSPFv3
|
(iff->instance_id == instance_id) &&
|
||||||
(iff->instance_id == ps->instance_id) &&
|
|
||||||
#endif
|
|
||||||
(iff->vid == rid))
|
(iff->vid == rid))
|
||||||
{
|
{
|
||||||
/* Vlink should be UP */
|
/* Vlink should be UP */
|
||||||
|
@ -417,20 +399,36 @@ ospf_rx_hook(sock *sk, int size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef OSPFv2
|
/*
|
||||||
log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr);
|
* Cannot find matching vlink. It is either misconfigured vlink; NBMA or
|
||||||
#endif
|
* 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
|
||||||
|
{
|
||||||
|
/* Non-matching area ID but cannot be vlink packet */
|
||||||
|
|
||||||
|
if (instance_id != ifa->instance_id)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
log(L_ERR "%s%I - area does not match (%R vs %R)",
|
||||||
|
mesg, sk->faddr, areaid, ifa->oa->areaid);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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_ */
|
|
915
proto/ospf/rt.c
915
proto/ospf/rt.c
File diff suppressed because it is too large
Load diff
|
@ -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
|
@ -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_ */
|
||||||
|
|
Loading…
Reference in a new issue