mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-17 08:38:42 +00:00
Temporary integrated OSPF commit.
This commit is contained in:
parent
9eceab33f9
commit
70945cb645
@ -2332,6 +2332,7 @@ protocol ospf <name> {
|
||||
tx length <num>;
|
||||
type [broadcast|bcast|pointopoint|ptp|
|
||||
nonbroadcast|nbma|pointomultipoint|ptmp];
|
||||
link lsa suppression <switch>;
|
||||
strict nonbroadcast <switch>;
|
||||
real broadcast <switch>;
|
||||
ptp netmask <switch>;
|
||||
@ -2596,9 +2597,16 @@ protocol ospf <name> {
|
||||
communication, or if the NBMA network is used as an (possibly
|
||||
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
|
||||
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>
|
||||
In <cf/type broadcast/ or <cf/type ptp/ network configuration, OSPF
|
||||
|
@ -33,6 +33,12 @@
|
||||
#define ABS(a) ((a)>=0 ? (a) : -(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
|
||||
#define NULL ((void *) 0)
|
||||
#endif
|
||||
|
@ -68,10 +68,12 @@ typedef struct siterator {
|
||||
#define SNODE (snode *)
|
||||
#define SHEAD(list) ((void *)((list).head))
|
||||
#define STAIL(list) ((void *)((list).tail))
|
||||
#define WALK_SLIST(n,list) for(n=SHEAD(list);(SNODE (n))->next; \
|
||||
n=(void *)((SNODE (n))->next))
|
||||
#define SNODE_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) \
|
||||
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)
|
||||
|
||||
void s_add_tail(slist *, snode *);
|
||||
|
@ -21,7 +21,9 @@ static list *this_nets;
|
||||
static struct area_net_config *this_pref;
|
||||
static struct ospf_stubnet_config *this_stubnet;
|
||||
|
||||
#ifdef OSPFv2
|
||||
static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; }
|
||||
static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; }
|
||||
|
||||
static void
|
||||
ospf_iface_finish(void)
|
||||
{
|
||||
@ -38,21 +40,6 @@ ospf_iface_finish(void)
|
||||
if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
|
||||
log(L_WARN "Password option without authentication option does not make sense");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OSPFv3
|
||||
static void
|
||||
ospf_iface_finish(void)
|
||||
{
|
||||
struct ospf_iface_patt *ip = OSPF_PATT;
|
||||
|
||||
if (ip->deadint == 0)
|
||||
ip->deadint = ip->deadc * ip->helloint;
|
||||
|
||||
if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL))
|
||||
cf_error("Authentication not supported in OSPFv3");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ospf_area_finish(void)
|
||||
@ -61,12 +48,12 @@ ospf_area_finish(void)
|
||||
cf_error("Backbone area cannot be stub/NSSA");
|
||||
|
||||
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))
|
||||
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");
|
||||
}
|
||||
|
||||
@ -80,15 +67,22 @@ ospf_proto_finish(void)
|
||||
|
||||
int areano = 0;
|
||||
int backbone = 0;
|
||||
int nssa = 0;
|
||||
struct ospf_area_config *ac;
|
||||
WALK_LIST(ac, cf->area_list)
|
||||
{
|
||||
areano++;
|
||||
if (ac->areaid == 0)
|
||||
backbone = 1;
|
||||
backbone = 1;
|
||||
if (ac->type == OPT_N)
|
||||
nssa = 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)
|
||||
{
|
||||
struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config));
|
||||
@ -101,26 +95,27 @@ ospf_proto_finish(void)
|
||||
}
|
||||
|
||||
if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
|
||||
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
|
||||
check_defcost(int cost)
|
||||
ospf_check_defcost(int cost)
|
||||
{
|
||||
if ((cost <= 0) || (cost >= LSINFINITY))
|
||||
cf_error("Default cost must be in range 1-%d", LSINFINITY-1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_instance_id(unsigned id)
|
||||
ospf_check_auth(void)
|
||||
{
|
||||
#ifdef OSPFv3
|
||||
OSPF_PATT->instance_id = id;
|
||||
#else
|
||||
cf_error("Instance ID requires OSPFv3");
|
||||
#endif
|
||||
if (ospf_cfg_is_v3())
|
||||
cf_error("Authentication not supported in OSPFv3");
|
||||
}
|
||||
|
||||
|
||||
CF_DECLS
|
||||
|
||||
CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
|
||||
@ -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(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
|
||||
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 <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);
|
||||
init_list(&OSPF_CFG->area_list);
|
||||
init_list(&OSPF_CFG->vlink_list);
|
||||
OSPF_CFG->rfc1583 = DEFAULT_RFC1583;
|
||||
OSPF_CFG->tick = DEFAULT_OSPFTICK;
|
||||
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
|
||||
OSPF_CFG->ospf2 = OSPF_IS_V2;
|
||||
}
|
||||
;
|
||||
|
||||
@ -160,7 +155,7 @@ ospf_proto_item:
|
||||
proto_item
|
||||
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
|
||||
| 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"); }
|
||||
| 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"); }
|
||||
@ -171,9 +166,9 @@ ospf_area_start: AREA idval {
|
||||
this_area = cfg_allocz(sizeof(struct ospf_area_config));
|
||||
add_tail(&OSPF_CFG->area_list, NODE this_area);
|
||||
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->transint = DEFAULT_TRANSINT;
|
||||
this_area->transint = OSPF_DEFAULT_TRANSINT;
|
||||
|
||||
init_list(&this_area->patt_list);
|
||||
init_list(&this_area->net_list);
|
||||
@ -195,9 +190,9 @@ ospf_area_item:
|
||||
| NSSA { this_area->type = OPT_N; }
|
||||
| SUMMARY bool { this_area->summary = $2; }
|
||||
| DEFAULT NSSA bool { this_area->default_nssa = $3; }
|
||||
| DEFAULT COST expr { this_area->default_cost = $3; check_defcost($3); }
|
||||
| DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT_EBIT; check_defcost($3); }
|
||||
| STUB COST expr { this_area->default_cost = $3; check_defcost($3); }
|
||||
| DEFAULT COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
|
||||
| DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT3_EBIT; ospf_check_defcost($3); }
|
||||
| STUB COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
|
||||
| TRANSLATOR bool { this_area->translator = $2; }
|
||||
| TRANSLATOR STABILITY expr { this_area->transint = $3; }
|
||||
| NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}'
|
||||
@ -249,10 +244,10 @@ ospf_vlink_item:
|
||||
| WAIT expr { OSPF_PATT->waitint = $2 ; }
|
||||
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
|
||||
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
|
||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
|
||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
|
||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
|
||||
| password_list
|
||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
|
||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
|
||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
|
||||
| password_list { ospf_check_auth(); }
|
||||
;
|
||||
|
||||
ospf_vlink_start: VIRTUAL LINK idval
|
||||
@ -292,18 +287,19 @@ ospf_iface_item:
|
||||
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
|
||||
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
|
||||
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
|
||||
| REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (OSPF_VERSION != 2) cf_error("Real broadcast option requires OSPFv2"); }
|
||||
| PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (OSPF_VERSION != 2) cf_error("Real netmask 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_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"); }
|
||||
| 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 ; }
|
||||
| STUB bool { OSPF_PATT->stub = $2 ; }
|
||||
| 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"); }
|
||||
| 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 '}'
|
||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
|
||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
|
||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
|
||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
|
||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
|
||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
|
||||
| RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
|
||||
| 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"); }
|
||||
@ -314,7 +310,7 @@ ospf_iface_item:
|
||||
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
|
||||
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
|
||||
| SECONDARY bool { OSPF_PATT->bsd_secondary = $2; }
|
||||
| password_list
|
||||
| password_list { ospf_check_auth(); }
|
||||
;
|
||||
|
||||
pref_list:
|
||||
@ -349,7 +345,7 @@ nbma_eligible:
|
||||
| ELIGIBLE { $$ = 1; }
|
||||
;
|
||||
|
||||
nbma_item: IPA nbma_eligible ';'
|
||||
nbma_item: ipa nbma_eligible ';'
|
||||
{
|
||||
this_nbma = cfg_allocz(sizeof(struct nbma_node));
|
||||
add_tail(&OSPF_PATT->nbma_list, NODE this_nbma);
|
||||
@ -384,11 +380,11 @@ ospf_iface_start:
|
||||
|
||||
ospf_instance_id:
|
||||
/* empty */
|
||||
| INSTANCE expr { set_instance_id($2); }
|
||||
| INSTANCE expr { OSPF_PATT->instance_id = $2; }
|
||||
;
|
||||
|
||||
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:
|
||||
|
@ -2,6 +2,8 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (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.
|
||||
*/
|
||||
@ -9,62 +11,185 @@
|
||||
#include "ospf.h"
|
||||
|
||||
|
||||
#ifdef OSPFv2
|
||||
struct ospf_dbdes_packet
|
||||
struct ospf_dbdes2_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_packet hdr;
|
||||
union ospf_auth auth;
|
||||
|
||||
u16 iface_mtu;
|
||||
u8 options;
|
||||
union imms imms; /* I, M, MS bits */
|
||||
u8 imms; /* I, M, MS bits */
|
||||
u32 ddseq;
|
||||
|
||||
struct ospf_lsa_header lsas[];
|
||||
};
|
||||
|
||||
#define hton_opt(X) X
|
||||
#define ntoh_opt(X) X
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef OSPFv3
|
||||
struct ospf_dbdes_packet
|
||||
struct ospf_dbdes3_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_packet hdr;
|
||||
|
||||
u32 options;
|
||||
u16 iface_mtu;
|
||||
u8 padding;
|
||||
union imms imms; /* I, M, MS bits */
|
||||
u8 imms; /* I, M, MS bits */
|
||||
u32 ddseq;
|
||||
|
||||
struct ospf_lsa_header lsas[];
|
||||
};
|
||||
|
||||
#define hton_opt(X) htonl(X)
|
||||
#define ntoh_opt(X) ntohl(X)
|
||||
#endif
|
||||
|
||||
|
||||
static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
|
||||
static inline uint
|
||||
ospf_dbdes_hdrlen(struct ospf_proto *p)
|
||||
{
|
||||
struct ospf_packet *op = &pkt->ospf_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);
|
||||
return ospf_is_v2(p) ?
|
||||
sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
* @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.
|
||||
*/
|
||||
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_area *oa = ifa->oa;
|
||||
struct proto_ospf *po = oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
u16 length, i, j;
|
||||
struct ospf_proto *p = oa->po;
|
||||
|
||||
/* FIXME ??? */
|
||||
if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
|
||||
update_rt_lsa(oa);
|
||||
/* RFC 2328 10.8 */
|
||||
|
||||
if (oa->rt == NULL)
|
||||
return;
|
||||
|
||||
switch (n->state)
|
||||
{
|
||||
case NEIGHBOR_EXSTART: /* Send empty packets */
|
||||
n->myimms.bit.i = 1;
|
||||
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);
|
||||
case NEIGHBOR_EXSTART:
|
||||
n->myimms |= DBDES_I;
|
||||
|
||||
OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
|
||||
ospf_send_to(ifa, n->ip);
|
||||
/* Send empty packets */
|
||||
ospf_prepare_dbdes(p, n, 0);
|
||||
ospf_do_send_dbdes(p, n);
|
||||
break;
|
||||
|
||||
case NEIGHBOR_EXCHANGE:
|
||||
n->myimms.bit.i = 0;
|
||||
n->myimms &= ~DBDES_I;
|
||||
|
||||
if (next)
|
||||
{
|
||||
snode *sn;
|
||||
struct ospf_lsa_header *lsa;
|
||||
ospf_prepare_dbdes(p, n, 1);
|
||||
|
||||
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;
|
||||
}
|
||||
/* Send prepared packet */
|
||||
ospf_do_send_dbdes(p, n);
|
||||
|
||||
pkt = n->ldd_buffer;
|
||||
op = (struct ospf_packet *) pkt;
|
||||
/* Master should restart RXMT timer for each DBDES exchange */
|
||||
if (n->myimms & DBDES_MS)
|
||||
tm_start(n->rxmt_timer, n->ifa->rxmtint);
|
||||
|
||||
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
|
||||
pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
|
||||
pkt->ddseq = htonl(n->dds);
|
||||
pkt->options = hton_opt(oa->options);
|
||||
|
||||
j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */
|
||||
lsa = (n->ldd_buffer + sizeof(struct ospf_dbdes_packet));
|
||||
|
||||
if (n->myimms.bit.m)
|
||||
{
|
||||
sn = s_get(&(n->dbsi));
|
||||
|
||||
DBG("Number of LSA: %d\n", j);
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
struct top_hash_entry *en= (struct top_hash_entry *) sn;
|
||||
|
||||
if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
|
||||
{
|
||||
htonlsah(&(en->lsa), lsa);
|
||||
DBG("Working on: %d\n", i);
|
||||
DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body);
|
||||
|
||||
lsa++;
|
||||
}
|
||||
else i++; /* No lsa added */
|
||||
|
||||
if (sn == STAIL(po->lsal))
|
||||
{
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
sn = sn->next;
|
||||
}
|
||||
|
||||
if (sn == STAIL(po->lsal))
|
||||
{
|
||||
DBG("Number of LSA NOT sent: %d\n", i);
|
||||
DBG("M bit unset.\n");
|
||||
n->myimms.bit.m = 0; /* Unset more bit */
|
||||
}
|
||||
|
||||
s_put(&(n->dbsi), sn);
|
||||
}
|
||||
|
||||
pkt->imms.byte = n->myimms.byte;
|
||||
|
||||
length = (j - i) * sizeof(struct ospf_lsa_header) +
|
||||
sizeof(struct ospf_dbdes_packet);
|
||||
op->length = htons(length);
|
||||
|
||||
DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip);
|
||||
}
|
||||
if (!(n->myimms & DBDES_MS))
|
||||
if (!(n->myimms & DBDES_M) &&
|
||||
!(n->imms & DBDES_M))
|
||||
ospf_neigh_sm(n, INM_EXDONE);
|
||||
break;
|
||||
|
||||
case NEIGHBOR_LOADING:
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send last packet from ldd buffer */
|
||||
|
||||
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 */
|
||||
/* Send last packet */
|
||||
ospf_do_send_dbdes(p, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
|
||||
|
||||
static int
|
||||
ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_lsa_header *plsa, lsa;
|
||||
struct 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;
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_lsa_header *lsas;
|
||||
uint i, lsa_count;
|
||||
|
||||
op = (struct ospf_packet *) ps;
|
||||
ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
|
||||
|
||||
plsa = (void *) (ps + 1);
|
||||
|
||||
j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
|
||||
sizeof(struct ospf_lsa_header);
|
||||
|
||||
for (i = 0; i < j; i++)
|
||||
for (i = 0; i < lsa_count; i++)
|
||||
{
|
||||
ntohlsah(plsa + i, &lsa);
|
||||
u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
|
||||
if (((he = ospf_hash_find_header(gr, dom, &lsa)) == NULL) ||
|
||||
(lsa_comp(&lsa, &(he->lsa)) == 1))
|
||||
struct top_hash_entry *en, *req;
|
||||
struct ospf_lsa_header lsa;
|
||||
u32 lsa_type, lsa_domain;
|
||||
|
||||
lsa_ntoh_hdr(lsas + i, &lsa);
|
||||
lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
|
||||
|
||||
/* RFC 2328 10.6 and RFC 5340 4.2.2 */
|
||||
|
||||
if (!lsa_type)
|
||||
{
|
||||
/* Is this condition necessary? */
|
||||
if (ospf_hash_find_header(n->lsrqh, dom, &lsa) == NULL)
|
||||
{
|
||||
sn = ospf_hash_get_header(n->lsrqh, dom, &lsa);
|
||||
ntohlsah(plsa + i, &(sn->lsa));
|
||||
s_add_tail(&(n->lsrql), SNODE sn);
|
||||
}
|
||||
log(L_WARN "%s: Bad DBDES from %I - LSA of unknown type", p->p.name, n->ip);
|
||||
goto err;
|
||||
}
|
||||
|
||||
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
|
||||
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 proto_ospf *po = ifa->oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
u32 rcv_ddseq, rcv_options;
|
||||
u16 rcv_iface_mtu;
|
||||
u8 rcv_imms;
|
||||
uint plen;
|
||||
|
||||
unsigned int size = ntohs(ps_i->length);
|
||||
if (size < sizeof(struct ospf_dbdes_packet))
|
||||
/* RFC 2328 10.6 */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
struct ospf_dbdes_packet *ps = (void *) ps_i;
|
||||
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_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from %I via %s", n->ip, ifa->ifname);
|
||||
|
||||
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)
|
||||
{
|
||||
case NEIGHBOR_DOWN:
|
||||
case NEIGHBOR_ATTEMPT:
|
||||
case NEIGHBOR_2WAY:
|
||||
return;
|
||||
break;
|
||||
|
||||
case NEIGHBOR_INIT:
|
||||
ospf_neigh_sm(n, INM_2WAYREC);
|
||||
if (n->state != NEIGHBOR_EXSTART)
|
||||
return;
|
||||
|
||||
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)
|
||||
&& (ps_iface_mtu != 0) && (ifa->iface->mtu != 0))
|
||||
log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)",
|
||||
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)))
|
||||
if ((rcv_imms == DBDES_IMMS) &&
|
||||
(n->rid > p->router_id) &&
|
||||
(plen == ospf_dbdes_hdrlen(p)))
|
||||
{
|
||||
/* I'm slave! */
|
||||
n->dds = ps_ddseq;
|
||||
n->ddr = ps_ddseq;
|
||||
n->options = ps_options;
|
||||
n->myimms.bit.ms = 0;
|
||||
n->imms.byte = ps->imms.byte;
|
||||
OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip);
|
||||
n->dds = rcv_ddseq;
|
||||
n->ddr = rcv_ddseq;
|
||||
n->options = rcv_options;
|
||||
n->myimms &= ~DBDES_MS;
|
||||
n->imms = rcv_imms;
|
||||
OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip);
|
||||
ospf_neigh_sm(n, INM_NEGDONE);
|
||||
ospf_dbdes_send(n, 1);
|
||||
ospf_send_dbdes(n, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) &&
|
||||
(n->rid < po->router_id) && (n->dds == ps_ddseq))
|
||||
if (!(rcv_imms & DBDES_I) &&
|
||||
!(rcv_imms & DBDES_MS) &&
|
||||
(n->rid < p->router_id) &&
|
||||
(n->dds == rcv_ddseq))
|
||||
{
|
||||
/* I'm master! */
|
||||
n->options = ps_options;
|
||||
n->ddr = ps_ddseq - 1; /* It will be set corectly a few lines down */
|
||||
n->imms.byte = ps->imms.byte;
|
||||
OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip);
|
||||
n->options = rcv_options;
|
||||
n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */
|
||||
n->imms = rcv_imms;
|
||||
OSPF_TRACE(D_PACKETS, "I'm master to %I", n->ip);
|
||||
ospf_neigh_sm(n, INM_NEGDONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("%s: Nothing happend to %I (imms=%u)\n", p->name, n->ip,
|
||||
ps->imms.byte);
|
||||
DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
|
||||
break;
|
||||
}
|
||||
|
||||
case NEIGHBOR_EXCHANGE:
|
||||
if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) &&
|
||||
(ps_ddseq == n->ddr))
|
||||
if ((rcv_imms == n->imms) &&
|
||||
(rcv_options == n->options) &&
|
||||
(rcv_ddseq == n->ddr))
|
||||
{
|
||||
/* Duplicate packet */
|
||||
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
|
||||
if (n->myimms.bit.ms == 0)
|
||||
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip);
|
||||
if (!(n->myimms & DBDES_MS))
|
||||
{
|
||||
/* Slave should retransmit dbdes packet */
|
||||
ospf_dbdes_send(n, 0);
|
||||
ospf_send_dbdes(n, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
n->ddr = ps_ddseq;
|
||||
|
||||
if (ps->imms.bit.ms != n->imms.bit.ms) /* M/S bit differs */
|
||||
if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS)) /* M/S bit differs */
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)",
|
||||
n->ip);
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)", n->ip);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
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)",
|
||||
n->ip);
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)", n->ip);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
break;
|
||||
}
|
||||
|
||||
n->imms.byte = ps->imms.byte;
|
||||
|
||||
if (ps_options != n->options) /* Options differs */
|
||||
if (rcv_options != n->options) /* Options differs */
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
|
||||
n->ip);
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)", n->ip);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
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)",
|
||||
n->ip);
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)", n->ip);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
break;
|
||||
}
|
||||
n->dds++;
|
||||
DBG("Incrementing dds\n");
|
||||
ospf_dbdes_reqladd(ps, n);
|
||||
if ((n->myimms.bit.m == 0) && (ps->imms.bit.m == 0))
|
||||
{
|
||||
ospf_neigh_sm(n, INM_EXDONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ospf_dbdes_send(n, 1);
|
||||
}
|
||||
|
||||
n->dds++;
|
||||
|
||||
if (ospf_process_dbdes(p, pkt, n) < 0)
|
||||
return;
|
||||
|
||||
if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
|
||||
ospf_neigh_sm(n, INM_EXDONE);
|
||||
else
|
||||
ospf_send_dbdes(n, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
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_neigh_sm(n, INM_SEQMIS);
|
||||
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;
|
||||
|
||||
case NEIGHBOR_LOADING:
|
||||
case NEIGHBOR_FULL:
|
||||
if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options)
|
||||
&& (ps_ddseq == n->ddr))
|
||||
/* Only duplicate are accepted */
|
||||
if ((rcv_imms == n->imms) &&
|
||||
(rcv_options == n->options) &&
|
||||
(rcv_ddseq == n->ddr))
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
|
||||
if (n->myimms.bit.ms == 0)
|
||||
/* Duplicate packet */
|
||||
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip);
|
||||
if (!(n->myimms & DBDES_MS))
|
||||
{
|
||||
/* Slave should retransmit dbdes packet */
|
||||
ospf_dbdes_send(n, 0);
|
||||
ospf_send_dbdes(n, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)",
|
||||
n->ip);
|
||||
DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds);
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)", n->ip);
|
||||
DBG("PS=%u, DDR=%u, DDS=%u\n", rcv_ddseq, n->ddr, n->dds);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
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
|
||||
*
|
||||
* (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.
|
||||
*/
|
||||
@ -9,25 +11,26 @@
|
||||
#include "ospf.h"
|
||||
|
||||
|
||||
#ifdef OSPFv2
|
||||
struct ospf_hello_packet
|
||||
struct ospf_hello2_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
ip_addr netmask;
|
||||
struct ospf_packet hdr;
|
||||
union ospf_auth auth;
|
||||
|
||||
u32 netmask;
|
||||
u16 helloint;
|
||||
u8 options;
|
||||
u8 priority;
|
||||
u32 deadint;
|
||||
u32 dr;
|
||||
u32 bdr;
|
||||
|
||||
u32 neighbors[];
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef OSPFv3
|
||||
struct ospf_hello_packet
|
||||
struct ospf_hello3_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_packet hdr;
|
||||
|
||||
u32 iface_id;
|
||||
u8 priority;
|
||||
u8 options3;
|
||||
@ -37,286 +40,92 @@ struct ospf_hello_packet
|
||||
u16 deadint;
|
||||
u32 dr;
|
||||
u32 bdr;
|
||||
|
||||
u32 neighbors[];
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n, ip_addr faddr)
|
||||
ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||
{
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
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_proto *p = ifa->oa->po;
|
||||
struct ospf_packet *pkt;
|
||||
struct ospf_neighbor *neigh, *n1;
|
||||
u16 length;
|
||||
int i;
|
||||
struct nbma_node *nb;
|
||||
u32 *neighbors;
|
||||
uint length;
|
||||
int i, max;
|
||||
|
||||
if (ifa->state <= OSPF_IS_LOOP)
|
||||
return;
|
||||
|
||||
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);
|
||||
op = &pkt->ospf_packet;
|
||||
|
||||
/* Now fill ospf_hello header */
|
||||
ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
|
||||
|
||||
#ifdef OSPFv2
|
||||
pkt->netmask = ipa_mkmask(ifa->addr->pxlen);
|
||||
ipa_hton(pkt->netmask);
|
||||
if ((ifa->type == OSPF_IT_VLINK) ||
|
||||
((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
|
||||
pkt->netmask = IPA_NONE;
|
||||
#endif
|
||||
if (ospf_is_v2(p))
|
||||
{
|
||||
struct ospf_hello2_packet *ps = (void *) pkt;
|
||||
|
||||
pkt->helloint = ntohs(ifa->helloint);
|
||||
pkt->priority = ifa->priority;
|
||||
if ((ifa->type == OSPF_IT_VLINK) ||
|
||||
((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
|
||||
ps->netmask = 0;
|
||||
else
|
||||
ps->netmask = htonl(u32_mkmask(ifa->addr->pxlen));
|
||||
|
||||
#ifdef OSPFv3
|
||||
pkt->iface_id = htonl(ifa->iface_id);
|
||||
ps->helloint = ntohs(ifa->helloint);
|
||||
ps->options = ifa->oa->options;
|
||||
ps->priority = ifa->priority;
|
||||
ps->deadint = htonl(ifa->deadint);
|
||||
ps->dr = htonl(ipa_to_u32(ifa->drip));
|
||||
ps->bdr = htonl(ipa_to_u32(ifa->bdrip));
|
||||
|
||||
pkt->options3 = ifa->oa->options >> 16;
|
||||
pkt->options2 = ifa->oa->options >> 8;
|
||||
#endif
|
||||
pkt->options = ifa->oa->options;
|
||||
length = sizeof(struct ospf_hello2_packet);
|
||||
neighbors = ps->neighbors;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ospf_hello3_packet *ps = (void *) pkt;
|
||||
|
||||
#ifdef OSPFv2
|
||||
pkt->deadint = htonl(ifa->deadint);
|
||||
pkt->dr = htonl(ipa_to_u32(ifa->drip));
|
||||
pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
|
||||
#else /* OSPFv3 */
|
||||
pkt->deadint = htons(ifa->deadint);
|
||||
pkt->dr = htonl(ifa->drid);
|
||||
pkt->bdr = htonl(ifa->bdrid);
|
||||
#endif
|
||||
ps->iface_id = htonl(ifa->iface_id);
|
||||
ps->priority = ifa->priority;
|
||||
ps->options3 = ifa->oa->options >> 16;
|
||||
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);
|
||||
|
||||
length = sizeof(struct ospf_hello3_packet);
|
||||
neighbors = ps->neighbors;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
max = (ospf_pkt_maxsize(ifa) - length) / sizeof(u32);
|
||||
|
||||
/* Fill all neighbors */
|
||||
i = 0;
|
||||
|
||||
if (kind != OHS_SHUTDOWN)
|
||||
{
|
||||
u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
|
||||
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;
|
||||
}
|
||||
*(pp + i) = htonl(neigh->rid);
|
||||
neighbors[i] = htonl(neigh->rid);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
|
||||
op->length = htons(length);
|
||||
length += i * sizeof(u32);
|
||||
pkt->length = htons(length);
|
||||
|
||||
OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
|
||||
|
||||
switch(ifa->type)
|
||||
{
|
||||
@ -369,8 +178,226 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||
break;
|
||||
|
||||
default:
|
||||
bug("Bug in ospf_hello_send()");
|
||||
bug("Bug in ospf_send_hello()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n, ip_addr faddr)
|
||||
{
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
char *beg = "OSPF: Bad HELLO packet from ";
|
||||
u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr;
|
||||
u8 rcv_options, rcv_priority;
|
||||
u32 *neighbors;
|
||||
u32 neigh_count;
|
||||
uint plen, i;
|
||||
|
||||
/* RFC 2328 10.5 */
|
||||
|
||||
OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s", faddr, ifa->ifname);
|
||||
|
||||
plen = ntohs(pkt->length);
|
||||
|
||||
if (ospf_is_v2(p))
|
||||
{
|
||||
struct ospf_hello2_packet *ps = (void *) pkt;
|
||||
|
||||
if (plen < sizeof(struct ospf_hello2_packet))
|
||||
{
|
||||
log(L_ERR "%s%I - too short (%u B)", beg, faddr, plen);
|
||||
return;
|
||||
}
|
||||
|
||||
rcv_iface_id = 0;
|
||||
rcv_helloint = ntohs(ps->helloint);
|
||||
rcv_deadint = ntohl(ps->deadint);
|
||||
rcv_dr = ntohl(ps->dr);
|
||||
rcv_bdr = ntohl(ps->bdr);
|
||||
rcv_options = ps->options;
|
||||
rcv_priority = ps->priority;
|
||||
|
||||
int pxlen = u32_masklen(ntohl(ps->netmask));
|
||||
if ((ifa->type != OSPF_IT_VLINK) &&
|
||||
(ifa->type != OSPF_IT_PTP) &&
|
||||
(pxlen != ifa->addr->pxlen))
|
||||
{
|
||||
log(L_ERR "%s%I - prefix length mismatch (%d)", beg, faddr, pxlen);
|
||||
return;
|
||||
}
|
||||
|
||||
neighbors = ps->neighbors;
|
||||
neigh_count = (plen - sizeof(struct ospf_hello2_packet)) / sizeof(u32);
|
||||
}
|
||||
else /* OSPFv3 */
|
||||
{
|
||||
struct ospf_hello3_packet *ps = (void *) pkt;
|
||||
|
||||
if (plen < sizeof(struct ospf_hello3_packet))
|
||||
{
|
||||
log(L_ERR "%s%I - too short (%u B)", beg, faddr, plen);
|
||||
return;
|
||||
}
|
||||
|
||||
rcv_iface_id = ntohl(ps->iface_id);
|
||||
rcv_helloint = ntohs(ps->helloint);
|
||||
rcv_deadint = ntohs(ps->deadint);
|
||||
rcv_dr = ntohl(ps->dr);
|
||||
rcv_bdr = ntohl(ps->bdr);
|
||||
rcv_options = ps->options;
|
||||
rcv_priority = ps->priority;
|
||||
|
||||
neighbors = ps->neighbors;
|
||||
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
|
||||
}
|
||||
|
||||
OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
|
||||
if (rcv_helloint != ifa->helloint)
|
||||
{
|
||||
log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, rcv_helloint);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rcv_deadint != ifa->deadint)
|
||||
{
|
||||
log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, rcv_deadint);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check whether bits E, N match */
|
||||
if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N))
|
||||
{
|
||||
log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, rcv_options);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check consistency of existing neighbor entry */
|
||||
if (n)
|
||||
{
|
||||
unsigned t = ifa->type;
|
||||
if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
|
||||
{
|
||||
/* Neighbor identified by IP address; Router ID may change */
|
||||
if (n->rid != ntohl(pkt->routerid))
|
||||
{
|
||||
OSPF_TRACE(D_EVENTS, "Neighbor %I has changed Router ID from %R to %R",
|
||||
n->ip, n->rid, ntohl(pkt->routerid));
|
||||
ospf_neigh_remove(n);
|
||||
n = NULL;
|
||||
}
|
||||
}
|
||||
else /* OSPFv3 or OSPFv2/PtP */
|
||||
{
|
||||
/* Neighbor identified by Router ID; IP address may change */
|
||||
if (!ipa_equal(faddr, n->ip))
|
||||
{
|
||||
OSPF_TRACE(D_EVENTS, "Neighbor address changed from %I to %I", n->ip, faddr);
|
||||
n->ip = faddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!n)
|
||||
{
|
||||
if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
|
||||
{
|
||||
struct nbma_node *nn = find_nbma_node(ifa, faddr);
|
||||
|
||||
if (!nn && ifa->strictnbma)
|
||||
{
|
||||
log(L_WARN "Ignoring new neighbor: %I on %s", faddr, ifa->ifname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nn && (ifa->type == OSPF_IT_NBMA) &&
|
||||
(((rcv_priority == 0) && nn->eligible) ||
|
||||
((rcv_priority > 0) && !nn->eligible)))
|
||||
{
|
||||
log(L_ERR "Eligibility mismatch for neighbor: %I on %s", faddr, ifa->ifname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nn)
|
||||
nn->found = 1;
|
||||
}
|
||||
|
||||
OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr, ifa->ifname);
|
||||
|
||||
n = ospf_neighbor_new(ifa);
|
||||
|
||||
n->rid = ntohl(pkt->routerid);
|
||||
n->ip = faddr;
|
||||
n->dr = rcv_dr;
|
||||
n->bdr = rcv_bdr;
|
||||
n->priority = rcv_priority;
|
||||
n->iface_id = rcv_iface_id;
|
||||
|
||||
if (n->ifa->cf->bfd)
|
||||
ospf_neigh_update_bfd(n, n->ifa->bfd);
|
||||
}
|
||||
|
||||
u32 n_id = ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid;
|
||||
|
||||
u32 old_dr = n->dr;
|
||||
u32 old_bdr = n->bdr;
|
||||
u32 old_priority = n->priority;
|
||||
u32 old_iface_id = n->iface_id;
|
||||
|
||||
n->dr = rcv_dr;
|
||||
n->bdr = rcv_bdr;
|
||||
n->priority = rcv_priority;
|
||||
n->iface_id = rcv_iface_id;
|
||||
|
||||
|
||||
/* Update inactivity timer */
|
||||
ospf_neigh_sm(n, INM_HELLOREC);
|
||||
|
||||
/* RFC 2328 9.5.1 - non-eligible routers reply to hello on NBMA nets */
|
||||
if (ifa->type == OSPF_IT_NBMA)
|
||||
if ((ifa->priority == 0) && (n->priority > 0))
|
||||
ospf_send_hello(n->ifa, OHS_HELLO, n);
|
||||
|
||||
|
||||
/* Examine list of neighbors */
|
||||
for (i = 0; i < neigh_count; i++)
|
||||
if (neighbors[i] == htonl(p->router_id))
|
||||
goto found_self;
|
||||
|
||||
ospf_neigh_sm(n, INM_1WAYREC);
|
||||
return;
|
||||
|
||||
found_self:
|
||||
ospf_neigh_sm(n, INM_2WAYREC);
|
||||
|
||||
|
||||
if (n->iface_id != old_iface_id)
|
||||
{
|
||||
/* If neighbor is DR, also update cached DR interface ID */
|
||||
if (ifa->drid == n->rid)
|
||||
ifa->dr_iface_id = n->iface_id;
|
||||
|
||||
/* RFC 5340 4.4.3 Event 4 - change of neighbor's interface ID */
|
||||
ospf_notify_rt_lsa(ifa->oa);
|
||||
|
||||
/* Missed in RFC 5340 4.4.3 Event 4 - (Px-)Net-LSA uses iface_id to ref Link-LSAs */
|
||||
ospf_notify_net_lsa(ifa);
|
||||
}
|
||||
|
||||
if (ifa->state == OSPF_IS_WAITING)
|
||||
{
|
||||
/* Neighbor is declaring itself DR (and there is no BDR) or as BDR */
|
||||
if (((n->dr == n_id) && (n->bdr == 0)) || (n->bdr == n_id))
|
||||
ospf_iface_sm(ifa, ISM_BACKS);
|
||||
}
|
||||
else if (ifa->state >= OSPF_IS_DROTHER)
|
||||
{
|
||||
/* Neighbor changed priority or started/stopped declaring itself as DR/BDR */
|
||||
if ((n->priority != old_priority) ||
|
||||
((n->dr == n_id) && (old_dr != n_id)) ||
|
||||
((n->dr != n_id) && (old_dr == n_id)) ||
|
||||
((n->bdr == n_id) && (old_bdr != n_id)) ||
|
||||
((n->bdr != n_id) && (old_bdr == n_id)))
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
* (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.
|
||||
*/
|
||||
@ -9,184 +11,175 @@
|
||||
#include "ospf.h"
|
||||
|
||||
|
||||
/*
|
||||
struct ospf_lsack_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_lsa_header lsh[];
|
||||
struct ospf_packet hdr;
|
||||
// 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 void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt)
|
||||
static inline void
|
||||
ospf_lsack_body(struct ospf_proto *p, struct ospf_packet *pkt,
|
||||
struct ospf_lsa_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 == LSACK_P);
|
||||
ospf_dump_common(p, op);
|
||||
*body = ((void *) pkt) + hlen;
|
||||
*count = (plen - hlen) / sizeof(struct ospf_lsa_header);
|
||||
}
|
||||
|
||||
unsigned int i, j;
|
||||
j = (ntohs(op->length) - sizeof(struct ospf_lsack_packet)) /
|
||||
sizeof(struct ospf_lsa_header);
|
||||
static void
|
||||
ospf_dump_lsack(struct ospf_proto *p, struct ospf_packet *pkt)
|
||||
{
|
||||
struct ospf_lsa_header *lsas;
|
||||
uint i, lsa_count;
|
||||
|
||||
for (i = 0; i < j; i++)
|
||||
ospf_dump_lsahdr(p, pkt->lsh + i);
|
||||
ASSERT(pkt->type == LSACK_P);
|
||||
ospf_dump_common(p, pkt);
|
||||
|
||||
ospf_lsack_body(p, pkt, &lsas, &lsa_count);
|
||||
for (i = 0; i < lsa_count; i++)
|
||||
ospf_dump_lsahdr(p, lsas + i);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* =====================================
|
||||
* Note, that h is in network endianity!
|
||||
* =====================================
|
||||
*/
|
||||
|
||||
void
|
||||
ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
|
||||
int queue)
|
||||
ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int queue)
|
||||
{
|
||||
struct lsah_n *no = mb_alloc(n->pool, sizeof(struct lsah_n));
|
||||
memcpy(&no->lsa, h, sizeof(struct ospf_lsa_header));
|
||||
/* 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", s_queue[queue],
|
||||
n->rid, ntohl(h->id), ntohl(h->rt), h->type);
|
||||
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
|
||||
ospf_lsack_send(struct ospf_neighbor *n, int queue)
|
||||
ospf_reset_lsack_queue(struct ospf_neighbor *n)
|
||||
{
|
||||
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;
|
||||
struct lsa_node *no;
|
||||
|
||||
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]))
|
||||
WALK_LIST_FIRST(no, n->ackl[ACKL_DELAY])
|
||||
{
|
||||
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);
|
||||
static inline void
|
||||
ospf_send_lsack(struct ospf_neighbor *n, int queue)
|
||||
{
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct ospf_lsa_header *lsas;
|
||||
struct ospf_packet *pkt;
|
||||
struct lsa_node *no;
|
||||
uint i, lsa_max, length;
|
||||
|
||||
if (ifa->type == OSPF_IT_BCAST)
|
||||
{
|
||||
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);
|
||||
}
|
||||
/* RFC 2328 13.5 */
|
||||
|
||||
ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header);
|
||||
op->length = htons(len);
|
||||
DBG("Sending! Len=%u\n", len);
|
||||
length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsa_header);
|
||||
pkt->length = htons(length);
|
||||
|
||||
OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
|
||||
OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent via %s", ifa->ifname);
|
||||
|
||||
if (ifa->type == OSPF_IT_BCAST)
|
||||
{
|
||||
if ((ifa->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);
|
||||
ospf_send_to_des(ifa);
|
||||
}
|
||||
else
|
||||
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
ospf_lsack_send(struct ospf_neighbor *n, int queue)
|
||||
{
|
||||
while (!EMPTY_LIST(n->ackl[queue]))
|
||||
ospf_send_lsack(n, queue);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n)
|
||||
{
|
||||
struct proto *p = &ifa->oa->po->proto;
|
||||
struct ospf_lsa_header lsa;
|
||||
struct top_hash_entry *en;
|
||||
unsigned int i, lsano;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct ospf_lsa_header lsa, *lsas;
|
||||
struct top_hash_entry *ret, *en;
|
||||
uint i, lsa_count;
|
||||
u32 lsa_type, lsa_domain;
|
||||
|
||||
unsigned int size = ntohs(ps_i->length);
|
||||
if (size < sizeof(struct ospf_lsack_packet))
|
||||
{
|
||||
log(L_ERR "Bad OSPF LSACK packet from %I - too short (%u B)", n->ip, size);
|
||||
return;
|
||||
}
|
||||
/* RFC 2328 13.7 */
|
||||
|
||||
struct ospf_lsack_packet *ps = (void *) ps_i;
|
||||
OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
|
||||
/* No need to check length, lsack has only basic header */
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
lsano = (size - sizeof(struct ospf_lsack_packet)) /
|
||||
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 */
|
||||
ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
|
||||
|
||||
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))
|
||||
continue;
|
||||
|
||||
OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip);
|
||||
OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R",
|
||||
lsa.type, lsa.id, lsa.rt);
|
||||
lsa_type, lsa.id, lsa.rt);
|
||||
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",
|
||||
lsa.age, lsa.sn, lsa.checksum);
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG("Deleting LS Id: %R RT: %R Type: %u from LS Retl for neighbor %R\n",
|
||||
lsa.id, lsa.rt, lsa.type, n->rid);
|
||||
s_rem_node(SNODE en);
|
||||
ospf_hash_delete(n->lsrth, en);
|
||||
en = ospf_hash_find_entry(p->gr, ret);
|
||||
if (en)
|
||||
en->ret_count--;
|
||||
|
||||
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
|
||||
*
|
||||
* (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.
|
||||
*/
|
||||
|
||||
#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
|
||||
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);
|
||||
#ifdef OSPFv2
|
||||
n->options = h->options;
|
||||
#endif
|
||||
n->type = htont(h->type);
|
||||
n->type_raw = htons(h->type_raw);
|
||||
n->id = htonl(h->id);
|
||||
n->rt = htonl(h->rt);
|
||||
n->sn = htonl(h->sn);
|
||||
@ -107,13 +25,10 @@ htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
|
||||
}
|
||||
|
||||
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);
|
||||
#ifdef OSPFv2
|
||||
h->options = n->options;
|
||||
#endif
|
||||
h->type = ntoht(n->type);
|
||||
h->type_raw = ntohs(n->type_raw);
|
||||
h->id = ntohl(n->id);
|
||||
h->rt = ntohl(n->rt);
|
||||
h->sn = ntohl(n->sn);
|
||||
@ -122,28 +37,120 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
|
||||
}
|
||||
|
||||
void
|
||||
htonlsab(void *h, void *n, u16 len)
|
||||
lsa_hton_body(void *h, void *n, u16 len)
|
||||
{
|
||||
u32 *hid = h;
|
||||
u32 *nid = n;
|
||||
unsigned i;
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < (len / sizeof(u32)); i++)
|
||||
nid[i] = htonl(hid[i]);
|
||||
}
|
||||
|
||||
void
|
||||
ntohlsab(void *n, void *h, u16 len)
|
||||
lsa_ntoh_body(void *n, void *h, u16 len)
|
||||
{
|
||||
u32 *nid = n;
|
||||
u32 *hid = h;
|
||||
unsigned i;
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < (len / sizeof(u32)); i++)
|
||||
hid[i] = ntohl(nid[i]);
|
||||
}
|
||||
#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
|
||||
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;
|
||||
|
||||
// log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length);
|
||||
htonlsah(h, h);
|
||||
htonlsab1(body, length - sizeof(struct ospf_lsa_header));
|
||||
lsa_hton_hdr(h, h);
|
||||
lsa_hton_body1(body, length - sizeof(struct ospf_lsa_header));
|
||||
|
||||
/*
|
||||
char buf[1024];
|
||||
@ -202,8 +209,8 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body)
|
||||
|
||||
// log(L_WARN "Checksum result %4x", h->checksum);
|
||||
|
||||
ntohlsah(h, h);
|
||||
ntohlsab1(body, length - sizeof(struct ospf_lsa_header));
|
||||
lsa_ntoh_hdr(h, h);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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)))
|
||||
return 0;
|
||||
|
||||
struct ospf_lsa_rt_link *rtl = (struct ospf_lsa_rt_link *) (body + 1);
|
||||
max = lsa_rt_count(lsa);
|
||||
uint i = 0;
|
||||
void *buf = body;
|
||||
void *bufend = buf + lsa->length - HDRLEN;
|
||||
buf += sizeof(struct ospf_lsa_rt);
|
||||
|
||||
#ifdef OSPFv2
|
||||
if (body->links != max)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < max; i++)
|
||||
while (buf < bufend)
|
||||
{
|
||||
u8 type = rtl[i].type;
|
||||
if (!((type == LSART_PTP) ||
|
||||
(type == LSART_NET) ||
|
||||
#ifdef OSPFv2
|
||||
(type == LSART_STUB) ||
|
||||
#endif
|
||||
(type == LSART_VLNK)))
|
||||
struct ospf_lsa_rt2_link *l = buf;
|
||||
buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
|
||||
i++;
|
||||
|
||||
if (buf > bufend)
|
||||
return 0;
|
||||
|
||||
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 1;
|
||||
@ -333,37 +511,18 @@ lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef OSPFv2
|
||||
|
||||
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;
|
||||
|
||||
/* 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 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
|
||||
pxlen(u32 *buf)
|
||||
@ -372,36 +531,48 @@ pxlen(u32 *buf)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
u8 pxl = pxlen(body->prefix);
|
||||
if (pxl > MAX_PREFIX_LENGTH)
|
||||
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)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
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 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
u8 pxl = pxlen(body->rest);
|
||||
@ -409,23 +580,23 @@ lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
|
||||
return 0;
|
||||
|
||||
int len = IPV6_PREFIX_SPACE(pxl);
|
||||
if (body->metric & LSA_EXT_FBIT) // forwardinf address
|
||||
if (body->metric & LSA_EXT3_FBIT) // forwardinf address
|
||||
len += 16;
|
||||
if (body->metric & LSA_EXT_TBIT) // route tag
|
||||
if (body->metric & LSA_EXT3_TBIT) // route tag
|
||||
len += 4;
|
||||
if (*body->rest & 0xFFFF) // referenced LS type field
|
||||
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 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
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:
|
||||
return lsa_validate_rt(lsa, body);
|
||||
return lsa_validate_rt2(lsa, body);
|
||||
case LSA_T_NET:
|
||||
return lsa_validate_net(lsa, body);
|
||||
case LSA_T_SUM_NET:
|
||||
return lsa_validate_sum_net(lsa, body);
|
||||
return lsa_validate_sum2(lsa, body);
|
||||
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_NSSA:
|
||||
return lsa_validate_ext(lsa, body);
|
||||
#ifdef OSPFv3
|
||||
return lsa_validate_ext2(lsa, body);
|
||||
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:
|
||||
return lsa_validate_link(lsa, body);
|
||||
case LSA_T_PREFIX:
|
||||
return lsa_validate_prefix(lsa, body);
|
||||
#endif
|
||||
default:
|
||||
/* In OSPFv3, unknown LSAs are OK,
|
||||
In OSPFv2, unknown LSAs are already rejected
|
||||
*/
|
||||
return 1;
|
||||
return 1; /* Unknown LSAs are OK in OSPFv3 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* (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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_LSALIB_H_
|
||||
#define _BIRD_OSPF_LSALIB_H_
|
||||
|
||||
#ifdef CPU_BIG_ENDIAN
|
||||
static inline void htonlsah(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 htonlsab(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 htonlsab1(void *h, u16 len) { };
|
||||
static inline void ntohlsab1(void *n, u16 len) { };
|
||||
static inline void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; };
|
||||
static inline void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; };
|
||||
static inline void lsa_hton_body(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); };
|
||||
static inline void lsa_ntoh_body(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); };
|
||||
static inline void lsa_hton_body1(void *h, u16 len) { };
|
||||
static inline void lsa_ntoh_body1(void *n, u16 len) { };
|
||||
#else
|
||||
void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
|
||||
void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
|
||||
void htonlsab(void *h, void *n, u16 len);
|
||||
void ntohlsab(void *n, void *h, u16 len);
|
||||
static inline void htonlsab1(void *h, u16 len) { htonlsab(h, h, len); };
|
||||
static inline void ntohlsab1(void *n, u16 len) { ntohlsab(n, n, len); };
|
||||
void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
|
||||
void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
|
||||
void lsa_hton_body(void *h, void *n, u16 len);
|
||||
void lsa_ntoh_body(void *n, void *h, u16 len);
|
||||
static inline void lsa_hton_body1(void *h, u16 len) { lsa_hton_body(h, h, len); };
|
||||
static inline void lsa_ntoh_body1(void *n, u16 len) { lsa_ntoh_body(n, n, len); };
|
||||
#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);
|
||||
u16 lsasum_check(struct ospf_lsa_header *h, void *body);
|
||||
#define CMP_NEWER 1
|
||||
#define CMP_SAME 0
|
||||
#define CMP_OLDER -1
|
||||
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);
|
||||
int lsa_validate(struct ospf_lsa_header *lsa, void *body);
|
||||
struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
|
||||
void ospf_age(struct proto_ospf *po);
|
||||
void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po);
|
||||
void ospf_flush_area(struct proto_ospf *po, u32 areaid);
|
||||
|
||||
void lsa_walk_rt_init(struct ospf_proto *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
|
||||
int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
|
||||
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric);
|
||||
void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
|
||||
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_ */
|
||||
|
@ -2,6 +2,8 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (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.
|
||||
*/
|
||||
@ -9,47 +11,55 @@
|
||||
#include "ospf.h"
|
||||
|
||||
|
||||
/*
|
||||
struct ospf_lsreq_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_lsreq_header lsh[];
|
||||
struct ospf_packet hdr;
|
||||
// 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);
|
||||
ospf_dump_common(p, op);
|
||||
|
||||
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));
|
||||
*body = ((void *) pkt) + hlen;
|
||||
*count = (plen - hlen) / sizeof(struct ospf_lsreq_header);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_lsreq_send(struct ospf_neighbor *n)
|
||||
static void
|
||||
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 ospf_lsreq_packet *pk;
|
||||
struct ospf_packet *op;
|
||||
struct ospf_lsreq_header *lsh;
|
||||
u16 length;
|
||||
int i, j;
|
||||
struct proto *p = &n->ifa->oa->po->proto;
|
||||
struct ospf_packet *pkt;
|
||||
uint i, lsr_max, length;
|
||||
|
||||
pk = ospf_tx_buffer(n->ifa);
|
||||
op = &pk->ospf_packet;
|
||||
/* RFC 2328 10.9 */
|
||||
|
||||
ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P);
|
||||
|
||||
sn = SHEAD(n->lsrql);
|
||||
if (EMPTY_SLIST(n->lsrql))
|
||||
{
|
||||
if (n->state == NEIGHBOR_LOADING)
|
||||
@ -57,90 +67,80 @@ ospf_lsreq_send(struct ospf_neighbor *n)
|
||||
return;
|
||||
}
|
||||
|
||||
i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) /
|
||||
sizeof(struct ospf_lsreq_header);
|
||||
lsh = pk->lsh;
|
||||
pkt = ospf_tx_buffer(ifa);
|
||||
ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P);
|
||||
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;
|
||||
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))
|
||||
if (i == lsr_max)
|
||||
break;
|
||||
sn = sn->next;
|
||||
|
||||
DBG("Requesting %uth LSA: Type: %04u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
|
||||
i, en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
|
||||
|
||||
u32 etype = lsa_get_etype(&en->lsa, p);
|
||||
lsrs[i].type = htonl(etype);
|
||||
lsrs[i].rt = htonl(en->lsa.rt);
|
||||
lsrs[i].id = htonl(en->lsa.id);
|
||||
i++;
|
||||
}
|
||||
if (i != 0)
|
||||
i--;
|
||||
|
||||
length =
|
||||
sizeof(struct ospf_lsreq_packet) + (j -
|
||||
i) * sizeof(struct ospf_lsreq_header);
|
||||
op->length = htons(length);
|
||||
length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsreq_header);
|
||||
pkt->length = htons(length);
|
||||
|
||||
OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->ifname);
|
||||
ospf_send_to(n->ifa, n->ip);
|
||||
OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet sent to %I via %s", n->ip, ifa->ifname);
|
||||
ospf_send_to(ifa, n->ip);
|
||||
}
|
||||
|
||||
|
||||
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_area *oa = ifa->oa;
|
||||
struct proto_ospf *po = oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
struct ospf_lsreq_header *lsh;
|
||||
struct l_lsr_head *llsh;
|
||||
list uplist;
|
||||
slab *upslab;
|
||||
int i, lsano;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct ospf_lsreq_header *lsrs;
|
||||
uint i, lsr_count;
|
||||
|
||||
unsigned int size = ntohs(ps_i->length);
|
||||
if (size < sizeof(struct ospf_lsreq_packet))
|
||||
{
|
||||
log(L_ERR "Bad OSPF LSREQ packet from %I - too short (%u B)", n->ip, size);
|
||||
return;
|
||||
}
|
||||
/* RFC 2328 10.7 */
|
||||
|
||||
struct ospf_lsreq_packet *ps = (void *) ps_i;
|
||||
OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->ifname);
|
||||
/* No need to check length, lsreq has only basic header */
|
||||
|
||||
OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet received from %I via %s", n->ip, ifa->ifname);
|
||||
|
||||
if (n->state < NEIGHBOR_EXCHANGE)
|
||||
return;
|
||||
|
||||
ospf_neigh_sm(n, INM_HELLOREC);
|
||||
ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
|
||||
|
||||
lsh = ps->lsh;
|
||||
init_list(&uplist);
|
||||
upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
|
||||
ospf_lsreq_body(p, pkt, &lsrs, &lsr_count);
|
||||
|
||||
lsano = (size - sizeof(struct ospf_lsreq_packet)) /
|
||||
sizeof(struct ospf_lsreq_header);
|
||||
for (i = 0; i < lsano; lsh++, i++)
|
||||
struct top_hash_entry *en, *entries[lsr_count];
|
||||
|
||||
for (i = 0; i < lsr_count; i++)
|
||||
{
|
||||
u32 hid = ntohl(lsh->id);
|
||||
u32 hrt = ntohl(lsh->rt);
|
||||
u32 htype = ntohl(lsh->type);
|
||||
u32 dom = ospf_lsa_domain(htype, ifa);
|
||||
DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", lsh->type, hid, hrt);
|
||||
llsh = sl_alloc(upslab);
|
||||
llsh->lsh.id = hid;
|
||||
llsh->lsh.rt = hrt;
|
||||
llsh->lsh.type = htype;
|
||||
add_tail(&uplist, NODE llsh);
|
||||
if (ospf_hash_find(po->gr, dom, hid, hrt, htype) == NULL)
|
||||
u32 id, rt, type, domain;
|
||||
|
||||
id = ntohl(lsrs[i].id);
|
||||
rt = ntohl(lsrs[i].rt);
|
||||
lsa_get_type_domain_(ntohl(lsrs[i].type), ifa, &type, &domain);
|
||||
|
||||
DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt);
|
||||
|
||||
en = ospf_hash_find(p->gr, domain, id, rt, type);
|
||||
if (!en)
|
||||
{
|
||||
log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R",
|
||||
n->ip, htype, hid, hrt);
|
||||
log(L_WARN "%s: Received LSREQ from %I for missing LSA (Type: %04x, Id: %R, Rt: %R)",
|
||||
p->p.name, n->ip, type, id, rt);
|
||||
ospf_neigh_sm(n, INM_BADLSREQ);
|
||||
rfree(upslab);
|
||||
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
|
||||
*
|
||||
* (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.
|
||||
*/
|
||||
@ -26,8 +28,6 @@ const char *ospf_inm[] =
|
||||
};
|
||||
|
||||
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 rxmt_timer_hook(timer * timer);
|
||||
static void ackd_timer_hook(timer * t);
|
||||
@ -37,11 +37,9 @@ init_lists(struct ospf_neighbor *n)
|
||||
{
|
||||
s_init_list(&(n->lsrql));
|
||||
n->lsrqh = ospf_top_new(n->pool);
|
||||
s_init(&(n->lsrqi), &(n->lsrql));
|
||||
|
||||
s_init_list(&(n->lsrtl));
|
||||
n->lsrth = ospf_top_new(n->pool);
|
||||
s_init(&(n->lsrti), &(n->lsrtl));
|
||||
}
|
||||
|
||||
/* Resets LSA request and retransmit lists.
|
||||
@ -59,9 +57,8 @@ reset_lists(struct ospf_neighbor *n)
|
||||
struct ospf_neighbor *
|
||||
ospf_neighbor_new(struct ospf_iface *ifa)
|
||||
{
|
||||
struct proto *p = (struct proto *) (ifa->oa->po);
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
struct pool *pool = rp_new(p->pool, "OSPF Neighbor");
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct pool *pool = rp_new(p->p.pool, "OSPF Neighbor");
|
||||
struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor));
|
||||
|
||||
n->pool = pool;
|
||||
@ -72,14 +69,14 @@ ospf_neighbor_new(struct ospf_iface *ifa)
|
||||
n->state = NEIGHBOR_DOWN;
|
||||
|
||||
init_lists(n);
|
||||
s_init(&(n->dbsi), &(po->lsal));
|
||||
s_init(&(n->dbsi), &(p->lsal));
|
||||
|
||||
n->inactim = tm_new(pool);
|
||||
n->inactim->data = n;
|
||||
n->inactim->randomize = 0;
|
||||
n->inactim->hook = neighbor_timer_hook;
|
||||
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->data = n;
|
||||
@ -87,7 +84,7 @@ ospf_neighbor_new(struct ospf_iface *ifa)
|
||||
n->rxmt_timer->hook = rxmt_timer_hook;
|
||||
n->rxmt_timer->recurrent = 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->data = n;
|
||||
@ -97,7 +94,7 @@ ospf_neighbor_new(struct ospf_iface *ifa)
|
||||
init_list(&n->ackl[ACKL_DIRECT]);
|
||||
init_list(&n->ackl[ACKL_DELAY]);
|
||||
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);
|
||||
}
|
||||
@ -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
|
||||
* starts rxmt timers, call interface state machine etc.
|
||||
*/
|
||||
|
||||
static void
|
||||
neigh_chstate(struct ospf_neighbor *n, u8 state)
|
||||
{
|
||||
u8 oldstate;
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
u8 old_state = n->state;
|
||||
int old_fadj = ifa->fadj;
|
||||
|
||||
oldstate = n->state;
|
||||
if (state == old_state)
|
||||
return;
|
||||
|
||||
if (oldstate != state)
|
||||
OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from %s to %s",
|
||||
n->ip, ospf_ns[old_state], ospf_ns[state]);
|
||||
|
||||
n->state = state;
|
||||
|
||||
if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY))
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY))
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
|
||||
/* Increase number of partial adjacencies */
|
||||
if ((state == NEIGHBOR_EXCHANGE) || (state == NEIGHBOR_LOADING))
|
||||
p->padj++;
|
||||
|
||||
/* Decrease number of partial adjacencies */
|
||||
if ((old_state == NEIGHBOR_EXCHANGE) || (old_state == NEIGHBOR_LOADING))
|
||||
p->padj--;
|
||||
|
||||
/* Increase number of full adjacencies */
|
||||
if (state == NEIGHBOR_FULL)
|
||||
ifa->fadj++;
|
||||
|
||||
/* Decrease number of full adjacencies */
|
||||
if (old_state == NEIGHBOR_FULL)
|
||||
ifa->fadj--;
|
||||
|
||||
if (ifa->fadj != old_fadj)
|
||||
{
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
/* RFC 2328 12.4 Event 4 - neighbor enters/leaves Full state */
|
||||
ospf_notify_rt_lsa(ifa->oa);
|
||||
ospf_notify_net_lsa(ifa);
|
||||
|
||||
n->state = state;
|
||||
|
||||
OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from \"%s\" to \"%s\".",
|
||||
n->ip, ospf_ns[oldstate], ospf_ns[state]);
|
||||
|
||||
if ((state == NEIGHBOR_2WAY) && (oldstate < NEIGHBOR_2WAY))
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
if ((state < NEIGHBOR_2WAY) && (oldstate >= NEIGHBOR_2WAY))
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
|
||||
if (oldstate == NEIGHBOR_FULL) /* Decrease number of adjacencies */
|
||||
{
|
||||
ifa->fadj--;
|
||||
schedule_rt_lsa(ifa->oa);
|
||||
if (ifa->type == OSPF_IT_VLINK) schedule_rt_lsa(ifa->voa);
|
||||
schedule_net_lsa(ifa);
|
||||
}
|
||||
|
||||
if (state == NEIGHBOR_FULL) /* Increase number of adjacencies */
|
||||
{
|
||||
ifa->fadj++;
|
||||
schedule_rt_lsa(ifa->oa);
|
||||
if (ifa->type == OSPF_IT_VLINK) schedule_rt_lsa(ifa->voa);
|
||||
schedule_net_lsa(ifa);
|
||||
}
|
||||
if (state == NEIGHBOR_EXSTART)
|
||||
{
|
||||
if (n->adj == 0) /* First time adjacency */
|
||||
{
|
||||
n->dds = random_u32();
|
||||
}
|
||||
n->dds++;
|
||||
n->myimms.byte = 0;
|
||||
n->myimms.bit.ms = 1;
|
||||
n->myimms.bit.m = 1;
|
||||
n->myimms.bit.i = 1;
|
||||
}
|
||||
if (state > NEIGHBOR_EXSTART)
|
||||
n->myimms.bit.i = 0;
|
||||
/* 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)
|
||||
{
|
||||
/* First time adjacency */
|
||||
if (n->adj == 0)
|
||||
n->dds = random_u32();
|
||||
|
||||
n->dds++;
|
||||
n->myimms = DBDES_IMMS;
|
||||
}
|
||||
|
||||
if (state > NEIGHBOR_EXSTART)
|
||||
n->myimms &= ~DBDES_I;
|
||||
}
|
||||
|
||||
static inline u32 neigh_get_id(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||
{ return ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; }
|
||||
|
||||
static struct ospf_neighbor *
|
||||
electbdr(list nl)
|
||||
elect_bdr(struct ospf_proto *p, list nl)
|
||||
{
|
||||
struct ospf_neighbor *neigh, *n1, *n2;
|
||||
u32 nid;
|
||||
@ -176,11 +182,7 @@ electbdr(list nl)
|
||||
n2 = NULL;
|
||||
WALK_LIST(neigh, nl) /* First try those decl. themselves */
|
||||
{
|
||||
#ifdef OSPFv2
|
||||
nid = ipa_to_u32(neigh->ip);
|
||||
#else /* OSPFv3 */
|
||||
nid = neigh->rid;
|
||||
#endif
|
||||
nid = neigh_get_id(p, neigh);
|
||||
|
||||
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
|
||||
if (neigh->priority > 0) /* Eligible */
|
||||
@ -225,7 +227,7 @@ electbdr(list nl)
|
||||
}
|
||||
|
||||
static struct ospf_neighbor *
|
||||
electdr(list nl)
|
||||
elect_dr(struct ospf_proto *p, list nl)
|
||||
{
|
||||
struct ospf_neighbor *neigh, *n;
|
||||
u32 nid;
|
||||
@ -233,11 +235,7 @@ electdr(list nl)
|
||||
n = NULL;
|
||||
WALK_LIST(neigh, nl) /* And now DR */
|
||||
{
|
||||
#ifdef OSPFv2
|
||||
nid = ipa_to_u32(neigh->ip);
|
||||
#else /* OSPFv3 */
|
||||
nid = neigh->rid;
|
||||
#endif
|
||||
nid = neigh_get_id(p, neigh);
|
||||
|
||||
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
|
||||
if (neigh->priority > 0) /* Eligible */
|
||||
@ -264,13 +262,9 @@ electdr(list nl)
|
||||
static int
|
||||
can_do_adj(struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_iface *ifa;
|
||||
struct proto *p;
|
||||
int i;
|
||||
|
||||
ifa = n->ifa;
|
||||
p = (struct proto *) (ifa->oa->po);
|
||||
i = 0;
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
int i = 0;
|
||||
|
||||
switch (ifa->type)
|
||||
{
|
||||
@ -285,10 +279,10 @@ can_do_adj(struct ospf_neighbor *n)
|
||||
{
|
||||
case OSPF_IS_DOWN:
|
||||
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;
|
||||
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;
|
||||
case OSPF_IS_DROTHER:
|
||||
if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
|
||||
@ -302,15 +296,15 @@ can_do_adj(struct ospf_neighbor *n)
|
||||
i = 1;
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -329,8 +323,7 @@ can_do_adj(struct ospf_neighbor *n)
|
||||
void
|
||||
ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||
{
|
||||
struct proto_ospf *po = n->ifa->oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
struct ospf_proto *p = n->ifa->oa->po;
|
||||
|
||||
DBG("Neighbor state machine for neighbor %I, event '%s'\n", n->ip,
|
||||
ospf_inm[event]);
|
||||
@ -341,23 +334,23 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||
neigh_chstate(n, NEIGHBOR_ATTEMPT);
|
||||
/* NBMA are used different way */
|
||||
break;
|
||||
|
||||
case INM_HELLOREC:
|
||||
switch (n->state)
|
||||
{
|
||||
case NEIGHBOR_ATTEMPT:
|
||||
case NEIGHBOR_DOWN:
|
||||
if ((n->state == NEIGHBOR_DOWN) ||
|
||||
(n->state == NEIGHBOR_ATTEMPT))
|
||||
neigh_chstate(n, NEIGHBOR_INIT);
|
||||
default:
|
||||
tm_start(n->inactim, n->ifa->deadint); /* Restart inactivity timer */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restart inactivity timer */
|
||||
tm_start(n->inactim, n->ifa->deadint);
|
||||
break;
|
||||
|
||||
case INM_2WAYREC:
|
||||
if (n->state < NEIGHBOR_2WAY)
|
||||
neigh_chstate(n, NEIGHBOR_2WAY);
|
||||
if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
|
||||
neigh_chstate(n, NEIGHBOR_EXSTART);
|
||||
break;
|
||||
|
||||
case INM_NEGDONE:
|
||||
if (n->state == NEIGHBOR_EXSTART)
|
||||
{
|
||||
@ -365,25 +358,22 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||
|
||||
/* Reset DB summary list iterator */
|
||||
s_get(&(n->dbsi));
|
||||
s_init(&(n->dbsi), &po->lsal);
|
||||
s_init(&(n->dbsi), &p->lsal);
|
||||
|
||||
while (!EMPTY_LIST(n->ackl[ACKL_DELAY]))
|
||||
{
|
||||
struct lsah_n *no;
|
||||
no = (struct lsah_n *) HEAD(n->ackl[ACKL_DELAY]);
|
||||
rem_node(NODE no);
|
||||
mb_free(no);
|
||||
}
|
||||
ospf_reset_lsack_queue(n);
|
||||
}
|
||||
else
|
||||
bug("NEGDONE and I'm not in EXSTART?");
|
||||
break;
|
||||
|
||||
case INM_EXDONE:
|
||||
neigh_chstate(n, NEIGHBOR_LOADING);
|
||||
break;
|
||||
|
||||
case INM_LOADDONE:
|
||||
neigh_chstate(n, NEIGHBOR_FULL);
|
||||
break;
|
||||
|
||||
case INM_ADJOK:
|
||||
switch (n->state)
|
||||
{
|
||||
@ -404,6 +394,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case INM_SEQMIS:
|
||||
case INM_BADLSREQ:
|
||||
if (n->state >= NEIGHBOR_EXCHANGE)
|
||||
@ -412,24 +403,27 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||
neigh_chstate(n, NEIGHBOR_EXSTART);
|
||||
}
|
||||
break;
|
||||
|
||||
case INM_KILLNBR:
|
||||
case INM_LLDOWN:
|
||||
case INM_INACTTIM:
|
||||
reset_lists(n);
|
||||
neigh_chstate(n, NEIGHBOR_DOWN);
|
||||
break;
|
||||
|
||||
case INM_1WAYREC:
|
||||
reset_lists(n);
|
||||
neigh_chstate(n, NEIGHBOR_INIT);
|
||||
break;
|
||||
|
||||
default:
|
||||
bug("%s: INM - Unknown event?", p->name);
|
||||
bug("%s: INM - Unknown event?", p->p.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bdr_election - (Backup) Designed Router election
|
||||
* ospf_dr_election - (Backup) Designed Router election
|
||||
* @ifa: actual interface
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
bdr_election(struct ospf_iface *ifa)
|
||||
ospf_dr_election(struct ospf_iface *ifa)
|
||||
{
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
u32 myid = po->router_id;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct ospf_neighbor *neigh, *ndr, *nbdr, me;
|
||||
int doadj;
|
||||
u32 myid = p->router_id;
|
||||
|
||||
DBG("(B)DR election.\n");
|
||||
|
||||
@ -452,19 +445,14 @@ bdr_election(struct ospf_iface *ifa)
|
||||
me.priority = ifa->priority;
|
||||
me.ip = ifa->addr->ip;
|
||||
|
||||
#ifdef OSPFv2
|
||||
me.dr = ipa_to_u32(ifa->drip);
|
||||
me.bdr = ipa_to_u32(ifa->bdrip);
|
||||
#else /* OSPFv3 */
|
||||
me.dr = ifa->drid;
|
||||
me.bdr = ifa->bdrid;
|
||||
me.dr = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid;
|
||||
me.bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid;
|
||||
me.iface_id = ifa->iface_id;
|
||||
#endif
|
||||
|
||||
add_tail(&ifa->neigh_list, NODE & me);
|
||||
|
||||
nbdr = electbdr(ifa->neigh_list);
|
||||
ndr = electdr(ifa->neigh_list);
|
||||
nbdr = elect_bdr(p, ifa->neigh_list);
|
||||
ndr = elect_dr(p, ifa->neigh_list);
|
||||
|
||||
if (ndr == NULL)
|
||||
ndr = nbdr;
|
||||
@ -475,56 +463,47 @@ bdr_election(struct ospf_iface *ifa)
|
||||
|| ((ifa->bdrid == myid) && (nbdr != &me))
|
||||
|| ((ifa->bdrid != myid) && (nbdr == &me)))
|
||||
{
|
||||
#ifdef OSPFv2
|
||||
me.dr = ndr ? ipa_to_u32(ndr->ip) : 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
|
||||
me.dr = ndr ? neigh_get_id(p, ndr) : 0;
|
||||
me.bdr = nbdr ? neigh_get_id(p, nbdr) : 0;
|
||||
|
||||
nbdr = electbdr(ifa->neigh_list);
|
||||
ndr = electdr(ifa->neigh_list);
|
||||
nbdr = elect_bdr(p, ifa->neigh_list);
|
||||
ndr = elect_dr(p, ifa->neigh_list);
|
||||
|
||||
if (ndr == NULL)
|
||||
ndr = nbdr;
|
||||
}
|
||||
|
||||
u32 odrid = ifa->drid;
|
||||
u32 obdrid = ifa->bdrid;
|
||||
rem_node(NODE & me);
|
||||
|
||||
|
||||
u32 old_drid = ifa->drid;
|
||||
u32 old_bdrid = ifa->bdrid;
|
||||
|
||||
ifa->drid = ndr ? ndr->rid : 0;
|
||||
ifa->drip = ndr ? ndr->ip : IPA_NONE;
|
||||
ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
|
||||
|
||||
ifa->bdrid = nbdr ? nbdr->rid : 0;
|
||||
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);
|
||||
|
||||
doadj = ((ifa->drid != odrid) || (ifa->bdrid != obdrid));
|
||||
|
||||
if (myid == ifa->drid)
|
||||
if (ifa->drid == myid)
|
||||
ospf_iface_chstate(ifa, OSPF_IS_DR);
|
||||
else if (ifa->bdrid == myid)
|
||||
ospf_iface_chstate(ifa, OSPF_IS_BACKUP);
|
||||
else
|
||||
{
|
||||
if (myid == ifa->bdrid)
|
||||
ospf_iface_chstate(ifa, OSPF_IS_BACKUP);
|
||||
else
|
||||
ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
|
||||
}
|
||||
ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
|
||||
|
||||
rem_node(NODE & me);
|
||||
|
||||
if (doadj)
|
||||
{
|
||||
/* Review neighbor adjacencies if DR or BDR changed */
|
||||
if ((ifa->drid != old_drid) || (ifa->bdrid != old_bdrid))
|
||||
WALK_LIST(neigh, ifa->neigh_list)
|
||||
{
|
||||
ospf_neigh_sm(neigh, INM_ADJOK);
|
||||
}
|
||||
}
|
||||
if (neigh->state >= NEIGHBOR_2WAY)
|
||||
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 *
|
||||
@ -553,9 +532,9 @@ neighbor_timer_hook(timer * timer)
|
||||
{
|
||||
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
|
||||
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);
|
||||
ospf_neigh_remove(n);
|
||||
}
|
||||
@ -564,7 +543,7 @@ void
|
||||
ospf_neigh_remove(struct ospf_neighbor *n)
|
||||
{
|
||||
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))
|
||||
{
|
||||
@ -577,20 +556,18 @@ ospf_neigh_remove(struct ospf_neighbor *n)
|
||||
neigh_chstate(n, NEIGHBOR_DOWN);
|
||||
rem_node(NODE n);
|
||||
rfree(n->pool);
|
||||
OSPF_TRACE(D_EVENTS, "Deleting neigbor.");
|
||||
OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", n->rid);
|
||||
}
|
||||
|
||||
static void
|
||||
ospf_neigh_bfd_hook(struct bfd_request *req)
|
||||
{
|
||||
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)
|
||||
{
|
||||
OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s",
|
||||
n->ip, n->ifa->ifname);
|
||||
|
||||
OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", n->ip, n->ifa->ifname);
|
||||
ospf_neigh_remove(n);
|
||||
}
|
||||
}
|
||||
@ -646,52 +623,32 @@ static void
|
||||
rxmt_timer_hook(timer * timer)
|
||||
{
|
||||
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
|
||||
// struct proto *p = &n->ifa->oa->po->proto;
|
||||
struct top_hash_entry *en;
|
||||
struct ospf_proto *p = n->ifa->oa->po;
|
||||
|
||||
DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n",
|
||||
p->name, n->ifa->ifname, n->ip);
|
||||
DBG("%s: RXMT timer fired on interface %s for neigh %I\n",
|
||||
p->p.name, n->ifa->ifname, n->ip);
|
||||
|
||||
if(n->state < NEIGHBOR_EXSTART) return;
|
||||
|
||||
if (n->state == NEIGHBOR_EXSTART)
|
||||
switch (n->state)
|
||||
{
|
||||
ospf_dbdes_send(n, 1);
|
||||
case NEIGHBOR_EXSTART:
|
||||
ospf_send_dbdes(n, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((n->state == NEIGHBOR_EXCHANGE) && n->myimms.bit.ms) /* I'm master */
|
||||
ospf_dbdes_send(n, 0);
|
||||
case NEIGHBOR_EXCHANGE:
|
||||
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)
|
||||
ospf_lsreq_send(n); /* EXCHANGE or LOADING */
|
||||
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);
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
* (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.
|
||||
*/
|
||||
@ -13,233 +15,216 @@
|
||||
void
|
||||
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;
|
||||
|
||||
pkt = (struct ospf_packet *) buf;
|
||||
|
||||
pkt->version = OSPF_VERSION;
|
||||
|
||||
pkt->version = ospf_get_version(p);
|
||||
pkt->type = h_type;
|
||||
|
||||
pkt->routerid = htonl(po->router_id);
|
||||
pkt->length = htons(ospf_pkt_maxsize(ifa));
|
||||
pkt->routerid = htonl(p->router_id);
|
||||
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->instance_id = ifa->instance_id;
|
||||
pkt->autype = ifa->autype;
|
||||
}
|
||||
|
||||
unsigned
|
||||
uint
|
||||
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)
|
||||
headers += OSPF_AUTH_CRYPT_SIZE;
|
||||
#endif
|
||||
|
||||
return ifa->tx_length - headers;
|
||||
}
|
||||
|
||||
#ifdef OSPFv2
|
||||
|
||||
/* We assume OSPFv2 in ospf_pkt_finalize() */
|
||||
static void
|
||||
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
|
||||
{
|
||||
struct password_item *passwd = NULL;
|
||||
void *tail;
|
||||
struct MD5Context ctxt;
|
||||
char password[OSPF_AUTH_CRYPT_SIZE];
|
||||
union ospf_auth *auth = (void *) (pkt + 1);
|
||||
uint plen = ntohs(pkt->length);
|
||||
|
||||
pkt->checksum = 0;
|
||||
pkt->autype = htons(ifa->autype);
|
||||
bzero(&pkt->u, sizeof(union ospf_auth));
|
||||
pkt->autype = ifa->autype;
|
||||
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 */
|
||||
|
||||
switch(ifa->autype)
|
||||
switch (ifa->autype)
|
||||
{
|
||||
case OSPF_AUTH_SIMPLE:
|
||||
passwd = password_find(ifa->passwords, 1);
|
||||
if (!passwd)
|
||||
{
|
||||
log( L_ERR "No suitable password found for authentication" );
|
||||
return;
|
||||
}
|
||||
password_cpy(pkt->u.password, passwd->password, sizeof(union ospf_auth));
|
||||
case OSPF_AUTH_NONE:
|
||||
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) -
|
||||
sizeof(union ospf_auth), (pkt + 1),
|
||||
ntohs(pkt->length) -
|
||||
sizeof(struct ospf_packet), NULL);
|
||||
break;
|
||||
case OSPF_AUTH_CRYPT:
|
||||
passwd = password_find(ifa->passwords, 0);
|
||||
if (!passwd)
|
||||
{
|
||||
log( L_ERR "No suitable password found for authentication" );
|
||||
return;
|
||||
}
|
||||
case OSPF_AUTH_SIMPLE:
|
||||
passwd = password_find(ifa->passwords, 1);
|
||||
if (!passwd)
|
||||
{
|
||||
log(L_ERR "No suitable password found for authentication");
|
||||
return;
|
||||
}
|
||||
password_cpy(auth->password, passwd->password, sizeof(union ospf_auth));
|
||||
|
||||
/* Perhaps use random value to prevent replay attacks after
|
||||
reboot when system does not have independent RTC? */
|
||||
if (!ifa->csn)
|
||||
{
|
||||
ifa->csn = (u32) now;
|
||||
ifa->csn_use = now;
|
||||
}
|
||||
case OSPF_AUTH_NONE:
|
||||
{
|
||||
void *body = (void *) (auth + 1);
|
||||
uint blen = plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth);
|
||||
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
/* We must have sufficient delay between sending a packet and increasing
|
||||
CSN to prevent reordering of packets (in a network) with different CSNs */
|
||||
if ((now - ifa->csn_use) > 1)
|
||||
ifa->csn++;
|
||||
case OSPF_AUTH_CRYPT:
|
||||
passwd = password_find(ifa->passwords, 0);
|
||||
if (!passwd)
|
||||
{
|
||||
log(L_ERR "No suitable password found for authentication");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Perhaps use random value to prevent replay attacks after
|
||||
reboot when system does not have independent RTC? */
|
||||
if (!ifa->csn)
|
||||
{
|
||||
ifa->csn = (u32) now;
|
||||
ifa->csn_use = now;
|
||||
}
|
||||
|
||||
pkt->u.md5.keyid = passwd->id;
|
||||
pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE;
|
||||
pkt->u.md5.zero = 0;
|
||||
pkt->u.md5.csn = htonl(ifa->csn);
|
||||
tail = ((void *)pkt) + ntohs(pkt->length);
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
|
||||
password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Final(tail, &ctxt);
|
||||
break;
|
||||
default:
|
||||
bug("Unknown authentication type");
|
||||
/* We must have sufficient delay between sending a packet and increasing
|
||||
CSN to prevent reordering of packets (in a network) with different CSNs */
|
||||
if ((now - ifa->csn_use) > 1)
|
||||
ifa->csn++;
|
||||
|
||||
ifa->csn_use = now;
|
||||
|
||||
auth->md5.zero = 0;
|
||||
auth->md5.keyid = passwd->id;
|
||||
auth->md5.len = OSPF_AUTH_CRYPT_SIZE;
|
||||
auth->md5.csn = htonl(ifa->csn);
|
||||
|
||||
void *tail = ((void *) pkt) + plen;
|
||||
char password[OSPF_AUTH_CRYPT_SIZE];
|
||||
password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
|
||||
|
||||
struct MD5Context ctxt;
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) pkt, plen);
|
||||
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Final(tail, &ctxt);
|
||||
break;
|
||||
|
||||
default:
|
||||
bug("Unknown authentication type");
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume OSPFv2 in ospf_pkt_checkauth() */
|
||||
static int
|
||||
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 proto *p = &po->proto;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
union ospf_auth *auth = (void *) (pkt + 1);
|
||||
struct password_item *pass = NULL, *ptmp;
|
||||
void *tail;
|
||||
char md5sum[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;
|
||||
}
|
||||
|
||||
switch(ifa->autype)
|
||||
switch (autype)
|
||||
{
|
||||
case OSPF_AUTH_NONE:
|
||||
return 1;
|
||||
break;
|
||||
case OSPF_AUTH_SIMPLE:
|
||||
pass = password_find(ifa->passwords, 1);
|
||||
if (!pass)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found");
|
||||
return 0;
|
||||
}
|
||||
password_cpy(password, pass->password, sizeof(union ospf_auth));
|
||||
case OSPF_AUTH_NONE:
|
||||
return 1;
|
||||
|
||||
if (memcmp(pkt->u.password, password, sizeof(union ospf_auth)))
|
||||
{
|
||||
char ppass[sizeof(union ospf_auth) + 1];
|
||||
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 1;
|
||||
break;
|
||||
case OSPF_AUTH_CRYPT:
|
||||
if (pkt->u.md5.len != OSPF_AUTH_CRYPT_SIZE)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE > size)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)",
|
||||
ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tail = ((void *)pkt) + ntohs(pkt->length);
|
||||
|
||||
if (ifa->passwords)
|
||||
{
|
||||
WALK_LIST(ptmp, *(ifa->passwords))
|
||||
{
|
||||
if (pkt->u.md5.keyid != ptmp->id) continue;
|
||||
if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue;
|
||||
pass = ptmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pass)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n)
|
||||
{
|
||||
u32 rcv_csn = ntohl(pkt->u.md5.csn);
|
||||
if(rcv_csn < n->csn)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->csn = rcv_csn;
|
||||
}
|
||||
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
|
||||
password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Final(md5sum, &ctxt);
|
||||
if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
|
||||
case OSPF_AUTH_SIMPLE:
|
||||
pass = password_find(ifa->passwords, 1);
|
||||
if (!pass)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
password_cpy(password, pass->password, sizeof(union ospf_auth));
|
||||
if (memcmp(auth->password, password, sizeof(union ospf_auth)))
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
case OSPF_AUTH_CRYPT:
|
||||
if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (plen + OSPF_AUTH_CRYPT_SIZE > size)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)",
|
||||
plen + OSPF_AUTH_CRYPT_SIZE, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n)
|
||||
{
|
||||
u32 rcv_csn = ntohl(auth->md5.csn);
|
||||
if(rcv_csn < n->csn)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->csn = rcv_csn;
|
||||
}
|
||||
|
||||
if (ifa->passwords)
|
||||
{
|
||||
WALK_LIST(ptmp, *(ifa->passwords))
|
||||
{
|
||||
if (auth->md5.keyid != ptmp->id) continue;
|
||||
if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue;
|
||||
pass = ptmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pass)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *tail = ((void *) pkt) + plen;
|
||||
char md5sum[OSPF_AUTH_CRYPT_SIZE];
|
||||
password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
|
||||
|
||||
struct MD5Context ctxt;
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) pkt, plen);
|
||||
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Final(md5sum, &ctxt);
|
||||
|
||||
if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
default:
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* OSPFv3 authentication not yet supported */
|
||||
|
||||
static inline void
|
||||
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
|
||||
{ }
|
||||
|
||||
static int
|
||||
ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
|
||||
{ return 1; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* ospf_rx_hook
|
||||
@ -266,43 +251,44 @@ ospf_rx_hook(sock *sk, int size)
|
||||
|
||||
/* Initially, the packet is associated with the 'master' iface */
|
||||
struct ospf_iface *ifa = sk->data;
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
// struct proto *p = &po->proto;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
|
||||
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);
|
||||
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
|
||||
/* First, we eliminate packets with strange address combinations.
|
||||
* In OSPFv2, they might be for other ospf_ifaces (with different IP
|
||||
* prefix) on the same real iface, so we don't log it. We enforce
|
||||
* that (src_local || dst_local), therefore we are eliminating all
|
||||
* such cases.
|
||||
*/
|
||||
if (dst_mcast && !src_local)
|
||||
return 1;
|
||||
if (!dst_mcast && !dst_local)
|
||||
return 1;
|
||||
if (ospf_is_v2(p))
|
||||
{
|
||||
/* First, we eliminate packets with strange address combinations.
|
||||
* In OSPFv2, they might be for other ospf_ifaces (with different IP
|
||||
* prefix) on the same real iface, so we don't log it. We enforce
|
||||
* that (src_local || dst_local), therefore we are eliminating all
|
||||
* such cases.
|
||||
*/
|
||||
if (dst_mcast && !src_local)
|
||||
return 1;
|
||||
if (!dst_mcast && !dst_local)
|
||||
return 1;
|
||||
|
||||
/* Ignore my own broadcast packets */
|
||||
if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
|
||||
return 1;
|
||||
#else /* OSPFv3 */
|
||||
|
||||
/* In OSPFv3, src_local and dst_local mean link-local.
|
||||
* RFC 5340 says that local (non-vlink) packets use
|
||||
* link-local src address, but does not enforce it. Strange.
|
||||
*/
|
||||
if (dst_mcast && !src_local)
|
||||
log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
|
||||
#endif
|
||||
/* Ignore my own broadcast packets */
|
||||
if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In OSPFv3, src_local and dst_local mean link-local.
|
||||
* RFC 5340 says that local (non-vlink) packets use
|
||||
* link-local src address, but does not enforce it. Strange.
|
||||
*/
|
||||
if (dst_mcast && !src_local)
|
||||
log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
return 1;
|
||||
@ -314,13 +300,13 @@ ospf_rx_hook(sock *sk, int size)
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint plen = ntohs(ps->length);
|
||||
uint plen = ntohs(pkt->length);
|
||||
if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0))
|
||||
{
|
||||
log(L_ERR "%s%I - invalid length (%u)", mesg, sk->faddr, plen);
|
||||
@ -348,89 +334,101 @@ ospf_rx_hook(sock *sk, int size)
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef OSPFv2
|
||||
if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
|
||||
(!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
|
||||
plen - sizeof(struct ospf_packet), NULL)))
|
||||
if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT))
|
||||
{
|
||||
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth);
|
||||
uint blen = plen - hlen;
|
||||
void *body = ((void *) pkt) + hlen;
|
||||
|
||||
if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
|
||||
{
|
||||
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Third, we resolve associated iface and handle vlinks. */
|
||||
|
||||
u32 areaid = ntohl(ps->areaid);
|
||||
u32 rid = ntohl(ps->routerid);
|
||||
u32 areaid = ntohl(pkt->areaid);
|
||||
u32 rid = ntohl(pkt->routerid);
|
||||
u8 instance_id = pkt->instance_id;
|
||||
|
||||
if ((areaid == ifa->oa->areaid)
|
||||
#ifdef OSPFv3
|
||||
&& (ps->instance_id == ifa->instance_id)
|
||||
#endif
|
||||
)
|
||||
if (areaid == ifa->oa->areaid)
|
||||
{
|
||||
/* It is real iface, source should be local (in OSPFv2) */
|
||||
#ifdef OSPFv2
|
||||
if (!src_local)
|
||||
/* Matching area ID */
|
||||
|
||||
if (instance_id != ifa->instance_id)
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
else if (dst_mcast || (areaid != 0))
|
||||
{
|
||||
/* Obvious mismatch */
|
||||
|
||||
#ifdef OSPFv2
|
||||
/* 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
|
||||
/* It is real iface, source should be local (in OSPFv2) */
|
||||
if (ospf_is_v2(p) && !src_local)
|
||||
{
|
||||
log(L_ERR "%s%I - strange source address for %s", mesg, sk->faddr, ifa->ifname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
goto found;
|
||||
}
|
||||
else if ((areaid == 0) && !dst_mcast)
|
||||
{
|
||||
/* Backbone area ID and possible vlink packet */
|
||||
|
||||
if ((p->areano == 1) || !oa_is_ext(ifa->oa))
|
||||
return 1;
|
||||
|
||||
struct ospf_iface *iff = NULL;
|
||||
WALK_LIST(iff, p->iface_list)
|
||||
{
|
||||
if ((iff->type == OSPF_IT_VLINK) &&
|
||||
(iff->voa == ifa->oa) &&
|
||||
(iff->instance_id == instance_id) &&
|
||||
(iff->vid == rid))
|
||||
{
|
||||
/* Vlink should be UP */
|
||||
if (iff->state != OSPF_IS_PTP)
|
||||
return 1;
|
||||
|
||||
ifa = iff;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cannot find matching vlink. It is either misconfigured vlink; NBMA or
|
||||
* PtMP with misconfigured area ID, or packet for some other instance (that
|
||||
* is possible even if instance_id == ifa->instance_id, because it may be
|
||||
* also vlink packet in the other instance, which is different namespace).
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some vlink? */
|
||||
struct ospf_iface *iff = NULL;
|
||||
/* Non-matching area ID but cannot be vlink packet */
|
||||
|
||||
WALK_LIST(iff, po->iface_list)
|
||||
{
|
||||
if ((iff->type == OSPF_IT_VLINK) &&
|
||||
(iff->voa == ifa->oa) &&
|
||||
#ifdef OSPFv3
|
||||
(iff->instance_id == ps->instance_id) &&
|
||||
#endif
|
||||
(iff->vid == rid))
|
||||
{
|
||||
/* Vlink should be UP */
|
||||
if (iff->state != OSPF_IS_PTP)
|
||||
return 1;
|
||||
|
||||
ifa = iff;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
if (instance_id != ifa->instance_id)
|
||||
return 1;
|
||||
|
||||
#ifdef OSPFv2
|
||||
log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr);
|
||||
#endif
|
||||
log(L_ERR "%s%I - area does not match (%R vs %R)",
|
||||
mesg, sk->faddr, areaid, ifa->oa->areaid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
found:
|
||||
if (ifa->stub) /* This shouldn't happen */
|
||||
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;
|
||||
|
||||
if (rid == po->router_id)
|
||||
if (rid == p->router_id)
|
||||
{
|
||||
log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr);
|
||||
return 1;
|
||||
@ -442,62 +440,51 @@ ospf_rx_hook(sock *sk, int size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef OSPFv2
|
||||
/* In OSPFv2, neighbors are identified by either IP or Router ID, base on network type */
|
||||
uint t = ifa->type;
|
||||
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);
|
||||
else
|
||||
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)",
|
||||
sk->faddr, ifa->ifname);
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dump packet
|
||||
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)
|
||||
switch (pkt->type)
|
||||
{
|
||||
case HELLO_P:
|
||||
DBG("%s: Hello received.\n", p->name);
|
||||
ospf_hello_receive(ps, ifa, n, sk->faddr);
|
||||
ospf_receive_hello(pkt, ifa, n, sk->faddr);
|
||||
break;
|
||||
|
||||
case DBDES_P:
|
||||
DBG("%s: Database description received.\n", p->name);
|
||||
ospf_dbdes_receive(ps, ifa, n);
|
||||
ospf_receive_dbdes(pkt, ifa, n);
|
||||
break;
|
||||
|
||||
case LSREQ_P:
|
||||
DBG("%s: Link state request received.\n", p->name);
|
||||
ospf_lsreq_receive(ps, ifa, n);
|
||||
ospf_receive_lsreq(pkt, ifa, n);
|
||||
break;
|
||||
|
||||
case LSUPD_P:
|
||||
DBG("%s: Link state update received.\n", p->name);
|
||||
ospf_lsupd_receive(ps, ifa, n);
|
||||
ospf_receive_lsupd(pkt, ifa, n);
|
||||
break;
|
||||
|
||||
case LSACK_P:
|
||||
DBG("%s: Link state ack received.\n", p->name);
|
||||
ospf_lsack_receive(ps, ifa, n);
|
||||
ospf_receive_lsack(pkt, ifa, n);
|
||||
break;
|
||||
|
||||
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;
|
||||
@ -508,7 +495,7 @@ void
|
||||
ospf_tx_hook(sock * sk)
|
||||
{
|
||||
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);
|
||||
}
|
||||
*/
|
||||
@ -517,16 +504,35 @@ void
|
||||
ospf_err_hook(sock * sk, int err)
|
||||
{
|
||||
struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
|
||||
struct proto *p = &(ifa->oa->po->proto);
|
||||
log(L_ERR "%s: Socket error on %s: %M", p->name, ifa->ifname, err);
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
log(L_ERR "%s: Socket error on %s: %M", p->p.name, ifa->ifname, err);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_verr_hook(sock *sk, int err)
|
||||
{
|
||||
struct proto_ospf *po = (struct proto_ospf *) (sk->data);
|
||||
struct proto *p = &po->proto;
|
||||
log(L_ERR "%s: Vlink socket error: %M", p->name, err);
|
||||
struct ospf_proto *p = (struct ospf_proto *) (sk->data);
|
||||
log(L_ERR "%s: Vlink socket error: %M", p->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
|
||||
@ -542,28 +548,8 @@ ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
|
||||
void
|
||||
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);
|
||||
if (!ipa_equal(ifa->bdrip, IPA_NONE))
|
||||
if (ipa_nonzero(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_ */
|
1009
proto/ospf/rt.c
1009
proto/ospf/rt.c
File diff suppressed because it is too large
Load Diff
@ -10,9 +10,9 @@
|
||||
#ifndef _BIRD_OSPF_RT_H_
|
||||
#define _BIRD_OSPF_RT_H_
|
||||
|
||||
#define ORT_UNDEF -1
|
||||
#define ORT_ROUTER 1
|
||||
|
||||
#define ORT_NET 0
|
||||
#define ORT_ROUTER 1
|
||||
|
||||
typedef struct orta
|
||||
{
|
||||
@ -51,26 +51,33 @@ typedef struct orta
|
||||
}
|
||||
orta;
|
||||
|
||||
|
||||
/* Values for fn.flags in struct ort */
|
||||
#define OSPF_RT_PERSISTENT 0x01
|
||||
|
||||
typedef struct ort
|
||||
{
|
||||
/*
|
||||
* We use fn.x0 to mark persistent rt entries, that are needed for summary
|
||||
* LSAs that don't have 'proper' rt entry (area networks + default to stubs)
|
||||
* to keep uid stable (used for LSA ID in OSPFv3 - see fibnode_to_lsaid()).
|
||||
* We use OSPF_RT_PERSISTENT to mark persistent rt entries, that are
|
||||
* needed for summary LSAs that don't have 'proper' rt entry (area
|
||||
* networks + default to stubs) to keep uid stable (used for LSA ID
|
||||
* in OSPFv3 - see fibnode_to_lsaid()).
|
||||
*
|
||||
* We use fn.x1 to note whether the external route was originated
|
||||
* from the route export (in ospf_rt_notify()) or from the NSSA
|
||||
* route translation (in check_nssa_lsa()).
|
||||
* We use ORT_RT_EXPORT and ORT_RT_NSSA to note whether the
|
||||
* external/NSSA route was originated from the route export (in
|
||||
* ospf_rt_notify()) or from the NSSA route translation (in
|
||||
* check_nssa_lsa()).
|
||||
*
|
||||
* old_* values are here to represent the last route update. old_rta
|
||||
* is cached (we keep reference), mainly for multipath nexthops.
|
||||
* old_rta == NULL means route 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.
|
||||
*/
|
||||
struct fib_node fn;
|
||||
orta n;
|
||||
u32 old_metric1, old_metric2, old_tag, old_rid;
|
||||
rta *old_rta;
|
||||
u8 external_rte;
|
||||
}
|
||||
ort;
|
||||
|
||||
@ -114,7 +121,7 @@ static inline int rt_is_nssa(ort *nf)
|
||||
* 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);
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,8 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (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.
|
||||
*/
|
||||
@ -16,79 +18,102 @@ struct top_hash_entry
|
||||
in intra-area routing table calculation */
|
||||
struct top_hash_entry *next; /* Next in hash chain */
|
||||
struct ospf_lsa_header lsa;
|
||||
u16 lsa_type; /* lsa.type processed and converted to common values */
|
||||
u16 init_age; /* Initial value for lsa.age during inst_time */
|
||||
u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */
|
||||
// struct ospf_area *oa;
|
||||
void *lsa_body;
|
||||
bird_clock_t inst_t; /* Time of installation into DB */
|
||||
void *lsa_body; /* May be NULL if LSA was flushed but hash entry was kept */
|
||||
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() */
|
||||
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) */
|
||||
#endif
|
||||
u32 dist; /* Distance from the root */
|
||||
u16 ini_age;
|
||||
int ret_count; /* Number of retransmission lists referencing the entry */
|
||||
u8 color;
|
||||
#define OUTSPF 0
|
||||
#define CANDIDATE 1
|
||||
#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.
|
||||
See a note in rt.c:merge_nexthops() */
|
||||
};
|
||||
|
||||
#define LSA_RTCALC 1
|
||||
#define LSA_STALE 2
|
||||
|
||||
struct top_graph
|
||||
{
|
||||
pool *pool; /* Pool we allocate from */
|
||||
slab *hash_slab; /* Slab for hash entries */
|
||||
struct top_hash_entry **hash_table; /* Hashing (modelled a`la fib) */
|
||||
unsigned int hash_size;
|
||||
unsigned int hash_order;
|
||||
unsigned int hash_mask;
|
||||
unsigned int hash_entries;
|
||||
unsigned int hash_entries_min, hash_entries_max;
|
||||
uint ospf2; /* Whether it is for OSPFv2 or OSPFv3 */
|
||||
uint hash_size;
|
||||
uint hash_order;
|
||||
uint hash_mask;
|
||||
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 *);
|
||||
void ospf_top_free(struct top_graph *);
|
||||
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,
|
||||
u32 type);
|
||||
struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
|
||||
u32 type);
|
||||
struct top_hash_entry * ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
|
||||
struct top_hash_entry * ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa);
|
||||
void ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
|
||||
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 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);
|
||||
void originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED);
|
||||
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_find_entry(struct top_graph *f, struct top_hash_entry *en)
|
||||
{ return ospf_hash_find(f, en->domain, en->lsa.id, en->lsa.rt, en->lsa_type); }
|
||||
|
||||
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_first(struct top_graph *f, u32 domain, u32 rtr);
|
||||
struct top_hash_entry * ospf_hash_find_rt_next(struct top_hash_entry *e);
|
||||
#endif
|
||||
struct top_hash_entry * ospf_hash_find_rt3_first(struct top_graph *f, u32 domain, u32 rtr);
|
||||
struct top_hash_entry * ospf_hash_find_rt3_next(struct top_hash_entry *e);
|
||||
|
||||
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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user