summaryrefslogtreecommitdiff
path: root/proto/ospf
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf')
-rw-r--r--proto/ospf/config.Y128
-rw-r--r--proto/ospf/dbdes.c652
-rw-r--r--proto/ospf/dbdes.h17
-rw-r--r--proto/ospf/hello.c538
-rw-r--r--proto/ospf/hello.h21
-rw-r--r--proto/ospf/iface.c726
-rw-r--r--proto/ospf/iface.h36
-rw-r--r--proto/ospf/lsack.c235
-rw-r--r--proto/ospf/lsack.h25
-rw-r--r--proto/ospf/lsalib.c560
-rw-r--r--proto/ospf/lsalib.h61
-rw-r--r--proto/ospf/lsreq.c192
-rw-r--r--proto/ospf/lsreq.h17
-rw-r--r--proto/ospf/lsupd.c1074
-rw-r--r--proto/ospf/lsupd.h25
-rw-r--r--proto/ospf/neighbor.c822
-rw-r--r--proto/ospf/neighbor.h22
-rw-r--r--proto/ospf/ospf.c1182
-rw-r--r--proto/ospf/ospf.h1083
-rw-r--r--proto/ospf/packet.c661
-rw-r--r--proto/ospf/packet.h28
-rw-r--r--proto/ospf/rt.c1066
-rw-r--r--proto/ospf/rt.h58
-rw-r--r--proto/ospf/topology.c2372
-rw-r--r--proto/ospf/topology.h215
25 files changed, 5868 insertions, 5948 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 478529bc..268b9539 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -19,9 +19,11 @@ static struct ospf_area_config *this_area;
static struct nbma_node *this_nbma;
static list *this_nets;
static struct area_net_config *this_pref;
-static struct ospf_stubnet_config *this_stubnet;
+static struct ospf_stubnet_config *this_stubnet;
+
+static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; }
+static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; }
-#ifdef OSPFv2
static void
ospf_iface_finish(void)
{
@@ -30,6 +32,9 @@ ospf_iface_finish(void)
if (ip->deadint == 0)
ip->deadint = ip->deadc * ip->helloint;
+ if (ip->waitint == 0)
+ ip->waitint = ip->deadc * ip->helloint;
+
ip->passwords = get_passwords();
if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
@@ -38,21 +43,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 +51,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 +70,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 +98,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 +130,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 +144,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,10 +158,11 @@ 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"); }
+ | INSTANCE ID expr { OSPF_CFG->instance_id = $3; if (($3<0) || ($3>255)) cf_error("Instance ID must be in range 0-255"); }
| ospf_area
;
@@ -171,9 +170,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 +194,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 '}'
@@ -218,7 +217,7 @@ ospf_stubnet_start:
add_tail(&this_area->stubnet_list, NODE this_stubnet);
this_stubnet->px = $1;
this_stubnet->cost = COST_D;
- }
+ }
;
ospf_stubnet_opts:
@@ -244,15 +243,15 @@ ospf_vlink_opts:
ospf_vlink_item:
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
- | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
+ | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
- | WAIT expr { OSPF_PATT->waitint = $2 ; }
+ | WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
- | 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
@@ -266,12 +265,10 @@ ospf_vlink_start: VIRTUAL LINK idval
OSPF_PATT->helloint = HELLOINT_D;
OSPF_PATT->rxmtint = RXMTINT_D;
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
- OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
OSPF_PATT->deadc = DEADC_D;
- OSPF_PATT->deadint = 0;
OSPF_PATT->type = OSPF_IT_VLINK;
+ OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list);
- OSPF_PATT->autype = OSPF_AUTH_NONE;
reset_passwords();
}
;
@@ -280,8 +277,8 @@ ospf_iface_item:
COST expr { OSPF_PATT->cost = $2 ; if (($2<=0) || ($2>65535)) cf_error("Cost must be in range 1-65535"); }
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
| POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); }
- | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
- | WAIT expr { OSPF_PATT->waitint = $2 ; }
+ | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); }
+ | WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
| TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
@@ -292,20 +289,21 @@ 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 ; }
- | RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
- | RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
+ | 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"); }
| TX tos { OSPF_PATT->tx_tos = $2; }
| TX PRIORITY expr { OSPF_PATT->tx_priority = $3; }
@@ -314,7 +312,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:
@@ -348,8 +346,8 @@ nbma_eligible:
/* empty */ { $$ = 0; }
| 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);
@@ -357,7 +355,7 @@ nbma_item: IPA nbma_eligible ';'
this_nbma->eligible=$2;
}
;
-
+
ospf_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
@@ -369,12 +367,10 @@ ospf_iface_start:
OSPF_PATT->rxmtint = RXMTINT_D;
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
OSPF_PATT->priority = PRIORITY_D;
- OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
OSPF_PATT->deadc = DEADC_D;
- OSPF_PATT->deadint = 0;
OSPF_PATT->type = OSPF_IT_UNDEF;
+ OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list);
- OSPF_PATT->autype = OSPF_AUTH_NONE;
OSPF_PATT->ptp_netmask = 2; /* not specified */
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
OSPF_PATT->tx_priority = sk_priority_control;
@@ -384,12 +380,12 @@ ospf_iface_start:
ospf_instance_id:
/* empty */
- | INSTANCE expr { set_instance_id($2); }
+ | INSTANCE expr { OSPF_PATT->instance_id = $2; if (($2<0) || ($2>255)) cf_error("Instance ID must be in range 0-255"); }
;
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:
/* empty */
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c
index 6b291344..65bdb3ec 100644
--- a/proto/ospf/dbdes.c
+++ b/proto/ospf/dbdes.c
@@ -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,422 +11,470 @@
#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;
-};
-
-#define hton_opt(X) X
-#define ntoh_opt(X) X
-#endif
+ struct ospf_lsa_header lsas[];
+};
-#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;
+ return ospf_is_v2(p) ?
+ sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
+}
- ASSERT(op->type == DBDES_P);
- ospf_dump_common(p, op);
- log(L_TRACE "%s: imms %s%s%s",
- p->name, pkt->imms.bit.ms ? "MS " : "",
- pkt->imms.bit.m ? "M " : "",
- pkt->imms.bit.i ? "I " : "" );
- log(L_TRACE "%s: ddseq %u", p->name, ntohl(pkt->ddseq));
- struct ospf_lsa_header *plsa = (void *) (pkt + 1);
- unsigned int i, j;
+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);
- j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
- sizeof(struct ospf_lsa_header);
+ *body = ((void *) pkt) + hlen;
+ *count = (plen - hlen) / sizeof(struct ospf_lsa_header);
+}
- for (i = 0; i < j; i++)
- ospf_dump_lsahdr(p, plsa + i);
+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);
}
-/**
- * ospf_dbdes_send - transmit database description packet
- * @n: neighbor
- * @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0)
- *
- * Sending of a database description packet is described in 10.8 of RFC 2328.
- * Reception of each packet is acknowledged in the sequence number of another.
- * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
- * does not reply, I don't create a new packet but just send the content
- * of the buffer.
- */
-void
-ospf_dbdes_send(struct ospf_neighbor *n, int next)
+static void
+ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
{
- 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_packet *pkt;
+ uint length;
- /* FIXME ??? */
- if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
- update_rt_lsa(oa);
+ u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
- switch (n->state)
+ /* Update DBDES buffer */
+ if (n->ldd_bsize != ifa->tx_length)
{
- 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);
-
- OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
- ospf_send_to(ifa, n->ip);
- break;
-
- case NEIGHBOR_EXCHANGE:
- n->myimms.bit.i = 0;
+ mb_free(n->ldd_buffer);
+ n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
+ n->ldd_bsize = ifa->tx_length;
+ }
- if (next)
- {
- snode *sn;
- struct ospf_lsa_header *lsa;
+ pkt = n->ldd_buffer;
+ ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
- 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;
- }
+ 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);
+ }
- pkt = n->ldd_buffer;
- op = (struct ospf_packet *) pkt;
+ /* Prepare DBDES body */
+ if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M))
+ {
+ struct ospf_lsa_header *lsas;
+ struct top_hash_entry *en;
+ uint i = 0, lsa_max;
- 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);
+ ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
+ en = (void *) s_get(&(n->dbsi));
- 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));
+ while (i < lsa_max)
+ {
+ if (!SNODE_VALID(en))
+ {
+ n->myimms &= ~DBDES_M; /* Unset More bit */
+ break;
+ }
- if (n->myimms.bit.m)
+ if ((en->lsa.age < LSA_MAXAGE) &&
+ lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
{
- 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);
+ lsa_hton_hdr(&(en->lsa), lsas + i);
+ i++;
}
- pkt->imms.byte = n->myimms.byte;
+ en = SNODE_NEXT(en);
+ }
- length = (j - i) * sizeof(struct ospf_lsa_header) +
- sizeof(struct ospf_dbdes_packet);
- op->length = htons(length);
+ s_put(&(n->dbsi), SNODE en);
- DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip);
- }
+ length += i * sizeof(struct ospf_lsa_header);
+ }
- case NEIGHBOR_LOADING:
- case NEIGHBOR_FULL:
- length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0;
+ if (ospf_is_v2(p))
+ ((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
+ else
+ ((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
- if (!length)
- {
- OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating");
- ospf_neigh_sm(n, INM_KILLNBR);
- return;
- }
+ pkt->length = htons(length);
+}
- /* Send last packet from ldd buffer */
+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);
+ OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
+ "DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
+ sk_set_tbuf(ifa->sk, n->ldd_buffer);
+ ospf_send_to(ifa, n->ip);
+ sk_set_tbuf(ifa->sk, NULL);
+}
- sk_set_tbuf(ifa->sk, n->ldd_buffer);
- ospf_send_to(ifa, n->ip);
- sk_set_tbuf(ifa->sk, NULL);
+/**
+ * ospf_send_dbdes - transmit database description packet
+ * @n: neighbor
+ *
+ * Sending of a database description packet is described in 10.8 of RFC 2328.
+ * Reception of each packet is acknowledged in the sequence number of another.
+ * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
+ * does not reply, I don't create a new packet but just send the content
+ * of the buffer.
+ */
+void
+ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
+{
+ /* RFC 2328 10.8 */
- if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */
+ ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));
- 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;
+ if (n->ifa->oa->rt == NULL)
+ return;
- default: /* Ignore it */
- break;
- }
+ ospf_prepare_dbdes(p, n);
+ ospf_do_send_dbdes(p, n);
}
-static void
-ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
+void
+ospf_rxmt_dbdes(struct ospf_proto *p, 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;
+ ASSERT(n->state > NEIGHBOR_EXSTART);
- op = (struct ospf_packet *) ps;
+ if (!n->ldd_buffer)
+ {
+ log(L_WARN "%s: No DBDES packet for retransmit", p->p.name);
+ ospf_neigh_sm(n, INM_SEQMIS);
+ return;
+ }
- plsa = (void *) (ps + 1);
+ /* Send last packet */
+ ospf_do_send_dbdes(p, n);
+}
- j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
- sizeof(struct ospf_lsa_header);
+static int
+ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct ospf_lsa_header *lsas, lsa;
+ struct top_hash_entry *en, *req;
+ const char *err_dsc = NULL;
+ u32 lsa_type, lsa_domain;
+ uint i, lsa_count;
- for (i = 0; i < j; i++)
+ ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
+
+ 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))
+ 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)
+ DROP1("LSA of unknown type");
+
+ if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
+ DROP1("LSA with AS scope in stub area");
+
+ /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
+ if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
+ DROP1("rt-summary-LSA in stub area");
+
+ /* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */
+ if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
+ DROP1("LSA with invalid scope");
+
+ en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
+ if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
{
- /* 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);
- }
+ /* This should be splitted to ospf_lsa_lsrq_up() */
+ 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);
+
+ if (!SNODE_VALID(n->lsrqi))
+ n->lsrqi = req;
+
+ req->lsa = lsa;
+ req->lsa_body = LSA_BODY_DUMMY;
+
+ if (!tm_active(n->lsrq_timer))
+ tm_start(n->lsrq_timer, 0);
}
}
+
+ return 0;
+
+drop:
+ LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt);
+ LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);
+
+ 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;
+ const char *err_dsc = NULL;
+ u32 rcv_ddseq, rcv_options;
+ u16 rcv_iface_mtu;
+ u8 rcv_imms;
+ uint plen, err_val = 0;
+
+ /* RFC 2328 10.6 */
- unsigned int size = ntohs(ps_i->length);
- if (size < sizeof(struct ospf_dbdes_packet))
+ plen = ntohs(pkt->length);
+ if (plen < ospf_dbdes_hdrlen(p))
{
- log(L_ERR "Bad OSPF DBDES packet from %I - too short (%u B)", n->ip, size);
+ LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", 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 nbr %R on %s", n->rid, 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:
+ OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
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) && (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)))
+ case NEIGHBOR_EXSTART:
+ if ((ifa->type != OSPF_IT_VLINK) &&
+ (rcv_iface_mtu != ifa->iface->mtu) &&
+ (rcv_iface_mtu != 0) &&
+ (ifa->iface->mtu != 0))
+ LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
+ n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
+
+ 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;
+ tm_stop(n->dbdes_timer);
ospf_neigh_sm(n, INM_NEGDONE);
- ospf_dbdes_send(n, 1);
+ ospf_send_dbdes(p, n);
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_neigh_sm(n, INM_NEGDONE);
+ /* Continue to the NEIGHBOR_EXCHANGE case */
}
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))
- {
- /* Duplicate packet */
- OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
- if (n->myimms.bit.ms == 0)
- {
- /* Slave should retransmit dbdes packet */
- ospf_dbdes_send(n, 0);
- }
- return;
- }
+ if ((rcv_imms == n->imms) &&
+ (rcv_options == n->options) &&
+ (rcv_ddseq == n->ddr))
+ goto duplicate;
- n->ddr = ps_ddseq;
+ if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
+ DROP("MS-bit mismatch", rcv_imms);
- if (ps->imms.bit.ms != n->imms.bit.ms) /* M/S bit differs */
- {
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)",
- n->ip);
- ospf_neigh_sm(n, INM_SEQMIS);
- break;
- }
+ if (rcv_imms & DBDES_I)
+ DROP("I-bit mismatch", rcv_imms);
- if (ps->imms.bit.i) /* I bit is set */
- {
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)",
- n->ip);
- ospf_neigh_sm(n, INM_SEQMIS);
- break;
- }
+ if (rcv_options != n->options)
+ DROP("options mismatch", rcv_options);
- n->imms.byte = ps->imms.byte;
+ n->ddr = rcv_ddseq;
+ n->imms = rcv_imms;
- if (ps_options != n->options) /* Options differs */
+ if (n->myimms & DBDES_MS)
{
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
- n->ip);
- ospf_neigh_sm(n, INM_SEQMIS);
- break;
- }
+ /* MASTER */
+
+ if (rcv_ddseq != n->dds)
+ DROP("DD sequence number mismatch", rcv_ddseq);
- if (n->myimms.bit.ms)
- {
- if (ps_ddseq != n->dds) /* MASTER */
- {
- 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))
+
+ if (ospf_process_dbdes(p, pkt, n) < 0)
+ return;
+
+ if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
{
+ tm_stop(n->dbdes_timer);
ospf_neigh_sm(n, INM_EXDONE);
- }
- else
- {
- ospf_dbdes_send(n, 1);
+ break;
}
+ ospf_send_dbdes(p, n);
+ tm_start(n->dbdes_timer, n->ifa->rxmtint);
}
else
{
- if (ps_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);
- }
+ /* SLAVE */
+
+ if (rcv_ddseq != (n->dds + 1))
+ DROP("DD sequence number mismatch", rcv_ddseq);
+
+ n->ddr = rcv_ddseq;
+ n->dds = rcv_ddseq;
+ if (ospf_process_dbdes(p, pkt, n) < 0)
+ return;
+
+ ospf_send_dbdes(p, n);
+
+ if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
+ ospf_neigh_sm(n, INM_EXDONE);
+ }
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 */
- {
- OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
- if (n->myimms.bit.ms == 0)
- {
- /* Slave should retransmit dbdes packet */
- ospf_dbdes_send(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_neigh_sm(n, INM_SEQMIS);
- }
- break;
+ if ((rcv_imms == n->imms) &&
+ (rcv_options == n->options) &&
+ (rcv_ddseq == n->ddr))
+ goto duplicate;
+
+ DROP("too late for DD exchange", n->state);
+
default:
- bug("Received dbdes from %I in undefined state.", n->ip);
+ bug("Undefined interface state");
}
+ return;
+
+duplicate:
+ OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");
+
+ /* Slave should retransmit DBDES packet */
+ if (!(n->myimms & DBDES_MS))
+ ospf_rxmt_dbdes(p, n);
+ return;
+
+drop:
+ LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
+ n->rid, ifa->ifname, err_dsc, err_val);
+
+ ospf_neigh_sm(n, INM_SEQMIS);
+ return;
}
diff --git a/proto/ospf/dbdes.h b/proto/ospf/dbdes.h
deleted file mode 100644
index 63cca0a2..00000000
--- a/proto/ospf/dbdes.h
+++ /dev/null
@@ -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_ */
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index e8bce09f..50cf1407 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -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;
-};
-#endif
+ u32 neighbors[];
+};
-#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;
-};
-#endif
-
-
-void
-ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
- struct ospf_neighbor *n, ip_addr faddr)
-{
- 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);
- }
+ u32 neighbors[];
+};
- 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)
+ospf_send_hello(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
-
- pkt->helloint = ntohs(ifa->helloint);
- pkt->priority = ifa->priority;
-
-#ifdef OSPFv3
- pkt->iface_id = htonl(ifa->iface_id);
-
- pkt->options3 = ifa->oa->options >> 16;
- pkt->options2 = ifa->oa->options >> 8;
-#endif
- pkt->options = ifa->oa->options;
-
-#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
+ if (ospf_is_v2(p))
+ {
+ struct ospf_hello2_packet *ps = (void *) pkt;
+
+ 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));
+
+ 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));
+
+ length = sizeof(struct ospf_hello2_packet);
+ neighbors = ps->neighbors;
+ }
+ else
+ {
+ struct ospf_hello3_packet *ps = (void *) pkt;
+
+ 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;
+ }
- /* Fill all neighbors */
i = 0;
+ max = (ospf_pkt_maxsize(ifa) - length) / sizeof(u32);
+ /* Fill all neighbors */
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 %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)
{
@@ -334,7 +143,7 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
int to_all = ifa->state > OSPF_IS_DROTHER;
int me_elig = ifa->priority > 0;
-
+
if (kind == OHS_POLL) /* Poll timer */
{
WALK_LIST(nb, ifa->nbma_list)
@@ -369,8 +178,215 @@ 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()");
}
+}
- OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
+
+void
+ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
+ struct ospf_neighbor *n, ip_addr faddr)
+{
+ struct ospf_proto *p = ifa->oa->po;
+ const char *err_dsc = NULL;
+ 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, err_val = 0;
+
+ /* RFC 2328 10.5 */
+
+ /*
+ * We may not yet havethe associate neighbor, so we use Router ID from the
+ * packet instead of one from the neighbor structure for log messages.
+ */
+ u32 rcv_rid = ntohl(pkt->routerid);
+ OSPF_TRACE(D_PACKETS, "HELLO packet received from nbr %R on %s", rcv_rid, 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))
+ DROP("too short", plen);
+
+ 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))
+ DROP("prefix length mismatch", pxlen);
+
+ 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))
+ DROP("too short", plen);
+
+ rcv_iface_id = ntohl(ps->iface_id);
+ rcv_helloint = ntohs(ps->helloint);
+ rcv_deadint = ntohs(ps->deadint);
+ rcv_dr = ntohl(ps->dr);
+ rcv_bdr = ntohl(ps->bdr);
+ rcv_options = ps->options;
+ rcv_priority = ps->priority;
+
+ neighbors = ps->neighbors;
+ neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
+ }
+
+ if (rcv_helloint != ifa->helloint)
+ DROP("hello interval mismatch", rcv_helloint);
+
+ if (rcv_deadint != ifa->deadint)
+ DROP("dead interval mismatch", rcv_deadint);
+
+ /* Check whether bits E, N match */
+ if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N))
+ DROP("area type mismatch", rcv_options);
+
+ /* Check consistency of existing neighbor entry */
+ if (n)
+ {
+ uint 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 != rcv_rid)
+ {
+ OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed Router ID to %R",
+ n->rid, ifa->ifname, rcv_rid);
+ ospf_neigh_sm(n, INM_KILLNBR);
+ 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 %R on %s changed IP address to %I",
+ n->rid, ifa->ifname, 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)
+ DROP1("new neighbor denied");
+
+ if (nn && (ifa->type == OSPF_IT_NBMA) &&
+ (((rcv_priority == 0) && nn->eligible) ||
+ ((rcv_priority > 0) && !nn->eligible)))
+ DROP("eligibility mismatch", rcv_priority);
+
+ if (nn)
+ nn->found = 1;
+ }
+
+ OSPF_TRACE(D_EVENTS, "New neighbor %R on %s, IP address %I",
+ rcv_rid, ifa->ifname, faddr);
+
+ n = ospf_neighbor_new(ifa);
+
+ n->rid = rcv_rid;
+ 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);
+ }
+
+ return;
+
+drop:
+ LOG_PKT("Bad HELLO packet from nbr %R on %s - %s (%u)",
+ rcv_rid, ifa->ifname, err_dsc, err_val);
}
diff --git a/proto/ospf/hello.h b/proto/ospf/hello.h
deleted file mode 100644
index 0e476692..00000000
--- a/proto/ospf/hello.h
+++ /dev/null
@@ -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_ */
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 50cf15e2..656184c6 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -2,48 +2,53 @@
* 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.
*/
#include "ospf.h"
-char *ospf_is[] = { "down", "loop", "waiting", "ptp", "drother",
- "backup", "dr"
+
+const char *ospf_is_names[] = {
+ "Down", "Loopback", "Waiting", "PtP", "DROther", "Backup", "DR"
};
-char *ospf_ism[] = { "interface up", "wait timer fired", "backup seen",
- "neighbor change", "loop indicated", "unloop indicated", "interface down"
+const char *ospf_ism_names[] = {
+ "InterfaceUp", "WaitTimer", "BackupSeen", "NeighborChange",
+ "LoopInd", "UnloopInd", "InterfaceDown"
};
-char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" };
+const char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" };
+
static void
poll_timer_hook(timer * timer)
{
- ospf_hello_send(timer->data, OHS_POLL, NULL);
+ ospf_send_hello(timer->data, OHS_POLL, NULL);
}
static void
hello_timer_hook(timer * timer)
{
- ospf_hello_send(timer->data, OHS_HELLO, NULL);
+ ospf_send_hello(timer->data, OHS_HELLO, NULL);
}
static void
wait_timer_hook(timer * timer)
{
struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
- struct proto *p = &ifa->oa->po->proto;
+ struct ospf_proto *p = ifa->oa->po;
- OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->ifname);
+ OSPF_TRACE(D_EVENTS, "Wait timer fired on %s", ifa->ifname);
ospf_iface_sm(ifa, ISM_WAITF);
}
static inline uint
ifa_tx_length(struct ospf_iface *ifa)
{
- return ifa->cf->tx_length ?: ifa->iface->mtu;
+ return ifa->cf->tx_length ?: ifa->iface->mtu;
}
static inline uint
@@ -53,15 +58,20 @@ ifa_bufsize(struct ospf_iface *ifa)
return MAX(bsize, ifa->tx_length);
}
+static inline uint
+ifa_flood_queue_size(struct ospf_iface *ifa)
+{
+ return ifa->tx_length / 24;
+}
+
int
ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen)
{
plen += SIZE_OF_IP_HEADER;
-#ifdef OSPFv2
+ /* This is relevant just for OSPFv2 */
if (ifa->autype == OSPF_AUTH_CRYPT)
plen += OSPF_AUTH_CRYPT_SIZE;
-#endif
if (plen <= ifa->sk->tbsize)
return 0;
@@ -77,12 +87,14 @@ ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen)
struct nbma_node *
-find_nbma_node_in(list *nnl, ip_addr ip)
+find_nbma_node_(list *nnl, ip_addr ip)
{
struct nbma_node *nn;
+
WALK_LIST(nn, *nnl)
if (ipa_equal(nn->ip, ip))
return nn;
+
return NULL;
}
@@ -90,7 +102,7 @@ find_nbma_node_in(list *nnl, ip_addr ip)
static int
ospf_sk_open(struct ospf_iface *ifa)
{
- struct proto_ospf *po = ifa->oa->po;
+ struct ospf_proto *p = ifa->oa->po;
sock *sk = sk_new(ifa->pool);
sk->type = SK_IP;
@@ -111,30 +123,31 @@ ospf_sk_open(struct ospf_iface *ifa)
if (sk_open(sk) < 0)
goto err;
-#ifdef OSPFv3
- /* 12 is an offset of the checksum in an OSPF packet */
- if (sk_set_ipv6_checksum(sk, 12) < 0)
- goto err;
-#endif
+ /* 12 is an offset of the checksum in an OSPFv3 packet */
+ if (ospf_is_v3(p))
+ if (sk_set_ipv6_checksum(sk, 12) < 0)
+ goto err;
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
{
if (ifa->cf->real_bcast)
{
ifa->all_routers = ifa->addr->brd;
+ ifa->des_routers = IPA_NONE;
if (sk_setup_broadcast(sk) < 0)
- goto err;
+ goto err;
}
else
{
- ifa->all_routers = AllSPFRouters;
+ ifa->all_routers = ospf_is_v2(p) ? IP4_OSPF_ALL_ROUTERS : IP6_OSPF_ALL_ROUTERS;
+ ifa->des_routers = ospf_is_v2(p) ? IP4_OSPF_DES_ROUTERS : IP6_OSPF_DES_ROUTERS;
if (sk_setup_multicast(sk) < 0)
- goto err;
+ goto err;
if (sk_join_group(sk, ifa->all_routers) < 0)
- goto err;
+ goto err;
}
}
@@ -143,7 +156,7 @@ ospf_sk_open(struct ospf_iface *ifa)
return 1;
err:
- sk_log_error(sk, po->proto.name);
+ sk_log_error(sk, p->p.name);
rfree(sk);
return 0;
}
@@ -154,8 +167,8 @@ ospf_sk_join_dr(struct ospf_iface *ifa)
if (ifa->sk_dr)
return;
- if (sk_join_group(ifa->sk, AllDRouters) < 0)
- sk_log_error(ifa->sk, ifa->oa->po->proto.name);
+ if (sk_join_group(ifa->sk, ifa->des_routers) < 0)
+ sk_log_error(ifa->sk, ifa->oa->po->p.name);
ifa->sk_dr = 1;
}
@@ -166,16 +179,16 @@ ospf_sk_leave_dr(struct ospf_iface *ifa)
if (!ifa->sk_dr)
return;
- if (sk_leave_group(ifa->sk, AllDRouters) < 0)
- sk_log_error(ifa->sk, ifa->oa->po->proto.name);
+ if (sk_leave_group(ifa->sk, ifa->des_routers) < 0)
+ sk_log_error(ifa->sk, ifa->oa->po->p.name);
ifa->sk_dr = 0;
}
void
-ospf_open_vlink_sk(struct proto_ospf *po)
+ospf_open_vlink_sk(struct ospf_proto *p)
{
- sock *sk = sk_new(po->proto.pool);
+ sock *sk = sk_new(p->p.pool);
sk->type = SK_IP;
sk->dport = OSPF_PROTO;
@@ -185,48 +198,48 @@ ospf_open_vlink_sk(struct proto_ospf *po)
sk->err_hook = ospf_verr_hook;
sk->rbsize = 0;
- sk->tbsize = OSPF_VLINK_MTU;
- sk->data = (void *) po;
+ sk->tbsize = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
+ sk->data = (void *) p;
sk->flags = 0;
if (sk_open(sk) < 0)
goto err;
-#ifdef OSPFv3
- /* 12 is an offset of the checksum in an OSPF packet */
- if (sk_set_ipv6_checksum(sk, 12) < 0)
- goto err;
-#endif
+ /* 12 is an offset of the checksum in an OSPFv3 packet */
+ if (ospf_is_v3(p))
+ if (sk_set_ipv6_checksum(sk, 12) < 0)
+ goto err;
- po->vlink_sk = sk;
+ p->vlink_sk = sk;
return;
err:
- sk_log_error(sk, po->proto.name);
- log(L_ERR "%s: Cannot open virtual link socket", po->proto.name);
+ sk_log_error(sk, p->p.name);
+ log(L_ERR "%s: Cannot open virtual link socket", p->p.name);
rfree(sk);
}
static void
ospf_iface_down(struct ospf_iface *ifa)
{
+ struct ospf_proto *p = ifa->oa->po;
struct ospf_neighbor *n, *nx;
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
struct ospf_iface *iff;
if (ifa->type != OSPF_IT_VLINK)
{
-#ifdef OSPFv2
- OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
- ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
-#else
- OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
- ifa->ifname, ifa->instance_id, ifa->oa->areaid);
-#endif
+ if (ospf_is_v3(ifa->oa->po))
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
+ ifa->ifname, ifa->instance_id, ifa->oa->areaid);
+ else if (ifa->addr->flags & IA_PEER)
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (peer %I) from area %R",
+ ifa->ifname, ifa->addr->opposite, ifa->oa->areaid);
+ else
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
+ ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
/* First of all kill all the related vlinks */
- WALK_LIST(iff, po->iface_list)
+ WALK_LIST(iff, p->iface_list)
{
if ((iff->type == OSPF_IT_VLINK) && (iff->vifa == ifa))
ospf_iface_sm(iff, ISM_DOWN);
@@ -234,10 +247,7 @@ ospf_iface_down(struct ospf_iface *ifa)
}
WALK_LIST_DELSAFE(n, nx, ifa->neigh_list)
- {
- OSPF_TRACE(D_EVENTS, "Removing neighbor %I", n->ip);
- ospf_neigh_remove(n);
- }
+ ospf_neigh_sm(n, INM_KILLNBR);
if (ifa->hello_timer)
tm_stop(ifa->hello_timer);
@@ -248,6 +258,10 @@ ospf_iface_down(struct ospf_iface *ifa)
if (ifa->wait_timer)
tm_stop(ifa->wait_timer);
+ ospf_flush2_lsa(p, &ifa->link_lsa);
+ ospf_flush2_lsa(p, &ifa->net_lsa);
+ ospf_flush2_lsa(p, &ifa->pxn_lsa);
+
if (ifa->type == OSPF_IT_VLINK)
{
ifa->vifa = NULL;
@@ -258,20 +272,25 @@ ospf_iface_down(struct ospf_iface *ifa)
ifa->rt_pos_beg = 0;
ifa->rt_pos_end = 0;
-#ifdef OSPFv3
ifa->px_pos_beg = 0;
ifa->px_pos_end = 0;
-#endif
}
void
ospf_iface_remove(struct ospf_iface *ifa)
{
- struct proto *p = &ifa->oa->po->proto;
+ struct ospf_proto *p = ifa->oa->po;
+ int i;
+
if (ifa->type == OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid);
+ /* Release LSAs from flood queue */
+ if (!ifa->stub)
+ for (i = 0; i < ifa->flood_queue_used; i++)
+ ifa->flood_queue[i]->ret_count--;
+
ospf_iface_sm(ifa, ISM_DOWN);
rem_node(NODE ifa);
rfree(ifa->pool);
@@ -281,7 +300,7 @@ void
ospf_iface_shutdown(struct ospf_iface *ifa)
{
if (ifa->state > OSPF_IS_DOWN)
- ospf_hello_send(ifa, OHS_SHUTDOWN, NULL);
+ ospf_send_hello(ifa, OHS_SHUTDOWN, NULL);
}
/**
@@ -296,23 +315,18 @@ ospf_iface_shutdown(struct ospf_iface *ifa)
void
ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
{
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
+ struct ospf_proto *p = ifa->oa->po;
u8 oldstate = ifa->state;
- if (oldstate == state)
+ if (state == oldstate)
return;
- ifa->state = state;
+ OSPF_TRACE(D_EVENTS, "Interface %s changed state from %s to %s",
+ ifa->ifname, ospf_is_names[oldstate], ospf_is_names[state]);
- if (ifa->type == OSPF_IT_VLINK)
- OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s",
- ifa->vid, ospf_is[oldstate], ospf_is[state]);
- else
- OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
- ifa->ifname, ospf_is[oldstate], ospf_is[state]);
+ ifa->state = state;
- if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk)
+ if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk)
{
if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
ospf_sk_join_dr(ifa);
@@ -320,22 +334,17 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
ospf_sk_leave_dr(ifa);
}
- if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL))
- {
- ifa->net_lsa->lsa.age = LSA_MAXAGE;
- if (state >= OSPF_IS_WAITING)
- ospf_lsupd_flush_nlsa(po, ifa->net_lsa);
-
- if (can_flush_lsa(po))
- flush_lsa(ifa->net_lsa, po);
- ifa->net_lsa = NULL;
- }
-
if ((oldstate > OSPF_IS_LOOP) && (state <= OSPF_IS_LOOP))
ospf_iface_down(ifa);
- schedule_rt_lsa(ifa->oa);
- // FIXME flushling of link LSA
+ /* RFC 2328 12.4 Event 2 - iface state change */
+ ospf_notify_rt_lsa(ifa->oa);
+
+ /* RFC 5340 4.4.3 Event 1 - iface state change */
+ ospf_notify_link_lsa(ifa);
+
+ /* RFC 2328 12.4 Event 3 - iface enters/leaves DR state */
+ ospf_notify_net_lsa(ifa);
}
/**
@@ -352,7 +361,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
void
ospf_iface_sm(struct ospf_iface *ifa, int event)
{
- DBG("SM on iface %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]);
+ DBG("SM on %s. Event is '%s'\n", ifa->ifname, ospf_ism_names[event]);
switch (event)
{
@@ -360,7 +369,9 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
if (ifa->state <= OSPF_IS_LOOP)
{
/* Now, nothing should be adjacent */
- if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP) || (ifa->type == OSPF_IT_VLINK))
+ if ((ifa->type == OSPF_IT_PTP) ||
+ (ifa->type == OSPF_IT_PTMP) ||
+ (ifa->type == OSPF_IT_VLINK))
{
ospf_iface_chstate(ifa, OSPF_IS_PTP);
}
@@ -382,26 +393,19 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
if (ifa->poll_timer)
tm_start(ifa->poll_timer, ifa->pollint);
- ospf_hello_send(ifa, OHS_HELLO, NULL);
- schedule_link_lsa(ifa);
+ ospf_send_hello(ifa, OHS_HELLO, NULL);
}
break;
case ISM_BACKS:
case ISM_WAITF:
if (ifa->state == OSPF_IS_WAITING)
- {
- bdr_election(ifa);
- }
+ ospf_dr_election(ifa);
break;
case ISM_NEICH:
- if ((ifa->state == OSPF_IS_DROTHER) || (ifa->state == OSPF_IS_DR) ||
- (ifa->state == OSPF_IS_BACKUP))
- {
- bdr_election(ifa);
- schedule_rt_lsa(ifa->oa);
- }
+ if (ifa->state >= OSPF_IS_DROTHER)
+ ospf_dr_election(ifa);
break;
case ISM_LOOP:
@@ -427,7 +431,7 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
}
static u8
-ospf_iface_classify_int(struct iface *ifa, struct ifa *addr)
+ospf_iface_classify_(struct iface *ifa, struct ifa *addr)
{
if (ipa_nonzero(addr->opposite))
return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP : OSPF_IT_PTMP;
@@ -445,17 +449,19 @@ ospf_iface_classify_int(struct iface *ifa, struct ifa *addr)
static inline u8
ospf_iface_classify(u8 type, struct ifa *addr)
{
- return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_int(addr->iface, addr);
+ return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_(addr->iface, addr);
}
struct ospf_iface *
-ospf_iface_find(struct proto_ospf *p, struct iface *what)
+ospf_iface_find(struct ospf_proto *p, struct iface *what)
{
- struct ospf_iface *i;
+ struct ospf_iface *ifa;
+
+ WALK_LIST(ifa, p->iface_list)
+ if ((ifa->iface == what) && (ifa->type != OSPF_IT_VLINK))
+ return ifa;
- WALK_LIST(i, p->iface_list) if ((i->iface == what) && (i->type != OSPF_IT_VLINK))
- return i;
return NULL;
}
@@ -463,13 +469,12 @@ static void
ospf_iface_add(struct object_lock *lock)
{
struct ospf_iface *ifa = lock->data;
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
+ struct ospf_proto *p = ifa->oa->po;
/* Open socket if interface is not stub */
if (! ifa->stub && ! ospf_sk_open(ifa))
{
- log(L_ERR "%s: Cannot open socket for %s, declaring as stub", p->name, ifa->ifname);
+ log(L_ERR "%s: Cannot open socket for %s, declaring as stub", p->p.name, ifa->ifname);
ifa->ioprob = OSPF_I_SK;
ifa->stub = 1;
}
@@ -483,6 +488,9 @@ ospf_iface_add(struct object_lock *lock)
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
ifa->wait_timer = tm_new_set(ifa->pool, wait_timer_hook, ifa, 0, 0);
+
+ ifa->flood_queue_size = ifa_flood_queue_size(ifa);
+ ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *));
}
/* Do iface UP, unless there is no link and we use link detection */
@@ -525,20 +533,22 @@ ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
void
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
{
- struct proto *p = &oa->po->proto;
+ struct ospf_proto *p = oa->po;
struct iface *iface = addr->iface;
struct ospf_iface *ifa;
struct pool *pool;
-#ifdef OSPFv2
- OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
- iface->name, addr->prefix, addr->pxlen, oa->areaid);
-#else
- OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
- iface->name, ip->instance_id, oa->areaid);
-#endif
+ if (ospf_is_v3(p))
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
+ iface->name, ip->instance_id, oa->areaid);
+ else if (addr->flags & IA_PEER)
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R",
+ iface->name, addr->opposite, oa->areaid);
+ else
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
+ iface->name, addr->prefix, addr->pxlen, oa->areaid);
- pool = rp_new(p->pool, "OSPF Interface");
+ pool = rp_new(p->p.pool, "OSPF Interface");
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
ifa->iface = iface;
ifa->addr = addr;
@@ -560,24 +570,18 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->deadint = ip->deadint;
ifa->stub = ospf_iface_stubby(ip, addr);
ifa->ioprob = OSPF_I_OK;
-
ifa->tx_length = ifa_tx_length(ifa);
ifa->check_link = ip->check_link;
ifa->ecmp_weight = ip->ecmp_weight;
ifa->check_ttl = (ip->ttl_security == 1);
ifa->bfd = ip->bfd;
-
-#ifdef OSPFv2
ifa->autype = ip->autype;
ifa->passwords = ip->passwords;
+ ifa->instance_id = ip->instance_id;
+
ifa->ptp_netmask = !(addr->flags & IA_PEER);
if (ip->ptp_netmask < 2)
ifa->ptp_netmask = ip->ptp_netmask;
-#endif
-
-#ifdef OSPFv3
- ifa->instance_id = ip->instance_id;
-#endif
ifa->type = ospf_iface_classify(ip->type, addr);
@@ -586,13 +590,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
int old_type = ifa->type;
u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST;
-#ifdef OSPFv2
- if ((ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
+ if (ospf_is_v2(p) && (ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
ifa->type = OSPF_IT_PTP;
- if ((ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
+ if (ospf_is_v2(p) && (ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
ifa->type = OSPF_IT_PTMP;
-#endif
if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag))
ifa->type = OSPF_IT_NBMA;
@@ -602,8 +604,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
if (ifa->type != old_type)
log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
- p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
+ p->p.name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
+
+ if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP))
+ ifa->link_lsa_suppression = ip->link_lsa_suppression;
ifa->state = OSPF_IS_DOWN;
init_list(&ifa->neigh_list);
@@ -617,34 +622,23 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
should be used). Because OSPFv3 iface is not subnet-specific,
there is no need for ipa_in_net() check */
-#ifdef OSPFv2
- if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
+ if (ospf_is_v2(p) && !ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
continue;
-#else
- if (!ipa_has_link_scope(nb->ip))
- log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip);
-#endif
+
+ if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
+ log(L_WARN "%s: Configured neighbor address (%I) should be link-local",
+ p->p.name, nb->ip);
add_nbma_node(ifa, nb, 0);
}
add_tail(&oa->po->iface_list, NODE ifa);
- /*
- * In some cases we allow more ospf_ifaces on one physical iface.
- * In OSPFv2, if they use different IP address prefix.
- * In OSPFv3, if they use different instance_id.
- * Therefore, we store such info to lock->addr field.
- */
-
struct object_lock *lock = olock_new(pool);
-#ifdef OSPFv2
- lock->addr = ifa->addr->prefix;
-#else /* OSPFv3 */
- lock->addr = _MI(0,0,0,ifa->instance_id);
-#endif
+ lock->addr = ospf_is_v2(p) ? ifa->addr->prefix : IPA_NONE;
lock->type = OBJLOCK_IP;
lock->port = OSPF_PROTO;
+ lock->inst = ifa->instance_id;
lock->iface = iface;
lock->data = ifa;
lock->hook = ospf_iface_add;
@@ -653,50 +647,43 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
}
void
-ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip)
+ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip)
{
- struct proto *p = &po->proto;
struct ospf_iface *ifa;
struct pool *pool;
- if (!po->vlink_sk)
+ if (!p->vlink_sk)
return;
OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
/* Vlink ifname is stored just after the ospf_iface structure */
- pool = rp_new(p->pool, "OSPF Vlink");
+ pool = rp_new(p->p.pool, "OSPF Vlink");
ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16);
- ifa->oa = po->backbone;
+ ifa->oa = p->backbone;
ifa->cf = ip;
ifa->pool = pool;
/* Assign iface ID, for vlinks, this is ugly hack */
- u32 vlink_id = po->last_vlink_id++;
+ u32 vlink_id = p->last_vlink_id++;
ifa->iface_id = vlink_id + OSPF_VLINK_ID_OFFSET;
ifa->ifname = (void *) (ifa + 1);
bsprintf(ifa->ifname, "vlink%d", vlink_id);
- ifa->voa = ospf_find_area(po, ip->voa);
+ ifa->voa = ospf_find_area(p, ip->voa);
ifa->vid = ip->vid;
- ifa->sk = po->vlink_sk;
+ ifa->sk = p->vlink_sk;
ifa->helloint = ip->helloint;
ifa->rxmtint = ip->rxmtint;
ifa->waitint = ip->waitint;
ifa->deadint = ip->deadint;
ifa->inftransdelay = ip->inftransdelay;
- ifa->tx_length = OSPF_VLINK_MTU;
-
-#ifdef OSPFv2
+ ifa->tx_length = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
ifa->autype = ip->autype;
ifa->passwords = ip->passwords;
-#endif
-
-#ifdef OSPFv3
ifa->instance_id = ip->instance_id;
-#endif
ifa->type = OSPF_IT_VLINK;
@@ -704,13 +691,16 @@ ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip)
init_list(&ifa->neigh_list);
init_list(&ifa->nbma_list);
- add_tail(&po->iface_list, NODE ifa);
+ add_tail(&p->iface_list, NODE ifa);
ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
+
+ ifa->flood_queue_size = ifa_flood_queue_size(ifa);
+ ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *));
}
static void
-ospf_iface_change_timer(timer *tm, unsigned val)
+ospf_iface_change_timer(timer *tm, uint val)
{
if (!tm)
return;
@@ -721,10 +711,24 @@ ospf_iface_change_timer(timer *tm, unsigned val)
tm_start(tm, val);
}
+static inline void
+ospf_iface_update_flood_queue_size(struct ospf_iface *ifa)
+{
+ uint old_size = ifa->flood_queue_size;
+ uint new_size = ifa_flood_queue_size(ifa);
+
+ if (new_size <= old_size)
+ return;
+
+ ifa->flood_queue_size = new_size;
+ ifa->flood_queue = mb_realloc(ifa->flood_queue, new_size * sizeof(void *));
+ bzero(ifa->flood_queue + old_size, (new_size - old_size) * sizeof(void *));
+}
+
int
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
{
- struct proto *p = &ifa->oa->po->proto;
+ struct ospf_proto *p = ifa->oa->po;
struct ospf_iface_patt *old = ifa->cf;
char *ifname = ifa->ifname;
@@ -753,7 +757,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* HELLO TIMER */
if (ifa->helloint != new->helloint)
{
- OSPF_TRACE(D_EVENTS, "Changing hello interval on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing hello interval of %s from %d to %d",
ifname, ifa->helloint, new->helloint);
ifa->helloint = new->helloint;
@@ -763,16 +767,17 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* RXMT TIMER */
if (ifa->rxmtint != new->rxmtint)
{
- OSPF_TRACE(D_EVENTS, "Changing retransmit interval on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing retransmit interval of %s from %d to %d",
ifname, ifa->rxmtint, new->rxmtint);
ifa->rxmtint = new->rxmtint;
+ /* FIXME: Update neighbors' timers */
}
/* POLL TIMER */
if (ifa->pollint != new->pollint)
{
- OSPF_TRACE(D_EVENTS, "Changing poll interval on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing poll interval of %s from %d to %d",
ifname, ifa->pollint, new->pollint);
ifa->pollint = new->pollint;
@@ -782,7 +787,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* WAIT TIMER */
if (ifa->waitint != new->waitint)
{
- OSPF_TRACE(D_EVENTS, "Changing wait interval on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing wait interval of %s from %d to %d",
ifname, ifa->waitint, new->waitint);
ifa->waitint = new->waitint;
@@ -793,7 +798,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* DEAD TIMER */
if (ifa->deadint != new->deadint)
{
- OSPF_TRACE(D_EVENTS, "Changing dead interval on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing dead interval of %s from %d to %d",
ifname, ifa->deadint, new->deadint);
ifa->deadint = new->deadint;
}
@@ -801,22 +806,20 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* INFTRANS */
if (ifa->inftransdelay != new->inftransdelay)
{
- OSPF_TRACE(D_EVENTS, "Changing transmit delay on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing transmit delay of %s from %d to %d",
ifname, ifa->inftransdelay, new->inftransdelay);
ifa->inftransdelay = new->inftransdelay;
}
-#ifdef OSPFv2
/* AUTHENTICATION */
if (ifa->autype != new->autype)
{
- OSPF_TRACE(D_EVENTS, "Changing authentication type on interface %s", ifname);
+ OSPF_TRACE(D_EVENTS, "Changing authentication type of %s", ifname);
ifa->autype = new->autype;
}
/* Update passwords */
ifa->passwords = new->passwords;
-#endif
/* Remaining options are just for proper interfaces */
if (ifa->type == OSPF_IT_VLINK)
@@ -826,7 +829,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* COST */
if (ifa->cost != new->cost)
{
- OSPF_TRACE(D_EVENTS, "Changing cost on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing cost of %s from %d to %d",
ifname, ifa->cost, new->cost);
ifa->cost = new->cost;
@@ -835,15 +838,18 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* PRIORITY */
if (ifa->priority != new->priority)
{
- OSPF_TRACE(D_EVENTS, "Changing priority on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing priority of %s from %d to %d",
ifname, ifa->priority, new->priority);
+
ifa->priority = new->priority;
+ ospf_notify_link_lsa(ifa);
}
/* STRICT NBMA */
if (ifa->strictnbma != new->strictnbma)
{
- OSPF_TRACE(D_EVENTS, "Changing NBMA strictness on interface %s", ifname);
+ OSPF_TRACE(D_EVENTS, "Changing NBMA strictness of %s from %d to %d",
+ ifname, ifa->strictnbma, new->strictnbma);
ifa->strictnbma = new->strictnbma;
}
@@ -852,19 +858,19 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* NBMA LIST - remove or update old */
WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
{
- struct nbma_node *nb2 = find_nbma_node_in(&new->nbma_list, nb->ip);
+ struct nbma_node *nb2 = find_nbma_node_(&new->nbma_list, nb->ip);
if (nb2)
{
if (nb->eligible != nb2->eligible)
{
- OSPF_TRACE(D_EVENTS, "Changing eligibility of neighbor %I on interface %s",
+ OSPF_TRACE(D_EVENTS, "Changing eligibility of NBMA neighbor %I on %s",
nb->ip, ifname);
nb->eligible = nb2->eligible;
}
}
else
{
- OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on interface %s",
+ OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on %s",
nb->ip, ifname);
rem_node(NODE nb);
mb_free(nb);
@@ -875,17 +881,16 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
WALK_LIST(nb, new->nbma_list)
{
/* See related note in ospf_iface_new() */
-#ifdef OSPFv2
- if (!ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
+ if (ospf_is_v2(p) && !ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
continue;
-#else
- if (!ipa_has_link_scope(nb->ip))
- log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip);
-#endif
+
+ if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
+ log(L_WARN "%s: Configured neighbor address (%I) should be link-local",
+ p->p.name, nb->ip);
if (! find_nbma_node(ifa, nb->ip))
{
- OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on interface %s",
+ OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on %s",
nb->ip, ifname);
add_nbma_node(ifa, nb, !!find_neigh_by_ip(ifa, nb->ip));
}
@@ -896,18 +901,21 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* TX LENGTH */
if (old->tx_length != new->tx_length)
{
- OSPF_TRACE(D_EVENTS, "Changing TX length on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing TX length of %s from %d to %d",
ifname, old->tx_length, new->tx_length);
/* ifa cannot be vlink */
ifa->tx_length = ifa_tx_length(ifa);
update_buffers = 1;
+
+ if (!ifa->stub)
+ ospf_iface_update_flood_queue_size(ifa);
}
/* RX BUFFER */
if (old->rx_buffer != new->rx_buffer)
{
- OSPF_TRACE(D_EVENTS, "Changing buffer size on interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing buffer size of %s from %d to %d",
ifname, old->rx_buffer, new->rx_buffer);
/* ifa cannot be vlink */
@@ -925,7 +933,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* LINK */
if (ifa->check_link != new->check_link)
{
- OSPF_TRACE(D_EVENTS, "%s link check on interface %s",
+ OSPF_TRACE(D_EVENTS, "%s link check for %s",
new->check_link ? "Enabling" : "Disabling", ifname);
ifa->check_link = new->check_link;
@@ -937,15 +945,26 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* ECMP weight */
if (ifa->ecmp_weight != new->ecmp_weight)
{
- OSPF_TRACE(D_EVENTS, "Changing ECMP weight of interface %s from %d to %d",
+ OSPF_TRACE(D_EVENTS, "Changing ECMP weight of %s from %d to %d",
ifname, (int)ifa->ecmp_weight + 1, (int)new->ecmp_weight + 1);
ifa->ecmp_weight = new->ecmp_weight;
}
+ /* Link LSA suppression */
+ if (((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP)) &&
+ (ifa->link_lsa_suppression != new->link_lsa_suppression))
+ {
+ OSPF_TRACE(D_EVENTS, "Changing link LSA suppression of %s from %d to %d",
+ ifname, ifa->link_lsa_suppression, new->link_lsa_suppression);
+
+ ifa->link_lsa_suppression = new->link_lsa_suppression;
+ ospf_notify_link_lsa(ifa);
+ }
+
/* BFD */
if (ifa->bfd != new->bfd)
{
- OSPF_TRACE(D_EVENTS, "%s BFD on interface %s",
+ OSPF_TRACE(D_EVENTS, "%s BFD for %s",
new->bfd ? "Enabling" : "Disabling", ifname);
ifa->bfd = new->bfd;
@@ -961,131 +980,122 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
}
-#ifdef OSPFv2
+/*
+ * State for matching iface pattterns walk
+ *
+ * This is significantly different in OSPFv2 and OSPFv3.
+ * In OSPFv2, OSPF ifaces are created for each IP prefix (struct ifa)
+ * In OSPFv3, OSPF ifaces are created based on real iface (struct iface)
+ * We support instance_id for both OSPFv2 (RFC 6549) and OSPFv3.
+ *
+ * We process one ifa/iface and match it for all configured instance IDs. We
+ * maintain bitfields to track whether given instance ID was already matched.
+ * We have two bitfields, one global (active) and one per area (ignore), to
+ * detect misconfigured cases where one iface with one instance ID matches in
+ * multiple areas.
+ */
-static inline struct ospf_iface_patt *
-ospf_iface_patt_find(struct ospf_area_config *ac, struct ifa *a)
-{
- return (struct ospf_iface_patt *) iface_patt_find(&ac->patt_list, a->iface, a);
-}
+struct ospf_mip_walk {
+ u32 active[8]; /* Bitfield of active instance IDs */
+ u32 ignore[8]; /* Bitfield of instance IDs matched in current area */
+ struct ospf_area *oa; /* Current area */
+ struct ospf_iface_patt *ip; /* Current iface pattern */
+ struct iface *iface; /* Specified iface (input) */
+ struct ifa *a; /* Specified ifa (input) */
+ int warn; /* Whether iface matched in multiple areas */
+};
-void
-ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
+static int
+ospf_walk_matching_iface_patts(struct ospf_proto *p, struct ospf_mip_walk *s)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
-
- if (a->flags & IA_SECONDARY)
- return;
+ int id;
- if (a->scope <= SCOPE_LINK)
- return;
+ if (s->ip)
+ goto step;
- /* In OSPFv2, we create OSPF iface for each address. */
- if (flags & IF_CHANGE_UP)
+ WALK_LIST(s->oa, p->area_list)
{
- int done = 0;
- struct ospf_area *oa;
- WALK_LIST(oa, po->area_list)
+ if (s->oa->marked)
+ continue;
+
+ WALK_LIST(s->ip, s->oa->ac->patt_list)
{
- struct ospf_iface_patt *ip;
- if (ip = ospf_iface_patt_find(oa->ac, a))
+ id = s->ip->instance_id;
+ if (BIT32_TEST(s->ignore, id))
+ continue;
+
+ if (iface_patt_match(&s->ip->i, s->iface, s->a))
{
- if (!done)
- ospf_iface_new(oa, a, ip);
- done++;
- }
- }
+ /* Now we matched ifa/iface/instance_id for the first time in current area */
+ BIT32_SET(s->ignore, id);
- if (done > 1)
- log(L_WARN "%s: Interface %s (IP %I) matches for multiple areas", p->name, a->iface->name, a->ip);
- }
+ /* If we already found it in previous areas, ignore it and add warning */
+ if (BIT32_TEST(s->active, id))
+ { s->warn = 1; continue; }
- if (flags & IF_CHANGE_DOWN)
- {
- struct ospf_iface *ifa, *ifx;
- WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
- {
- if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
- ospf_iface_remove(ifa);
- /* See a note in ospf_iface_notify() */
+ BIT32_SET(s->active, id);
+ return 1;
+ step:
+ ;
+ }
}
+ BIT32_ZERO(s->ignore, 256);
}
+
+ if (s->warn)
+ log(L_WARN "%s: Interface %s matches for multiple areas", p->p.name, s->iface->name);
+
+ return 0;
}
+
static struct ospf_iface *
-ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
+ospf_iface_find_by_key(struct ospf_proto *p, struct ifa *a, int instance_id)
{
struct ospf_iface *ifa;
- WALK_LIST(ifa, oa->po->iface_list)
- if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->type != OSPF_IT_VLINK))
+
+ WALK_LIST(ifa, p->iface_list)
+ if ((ifa->addr == a) && (ifa->instance_id == instance_id) &&
+ (ifa->type != OSPF_IT_VLINK))
return ifa;
return NULL;
}
+
void
-ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
+ospf_ifa_notify2(struct proto *P, uint flags, struct ifa *a)
{
- struct proto *p = &oa->po->proto;
- struct ospf_iface_patt *ip;
- struct iface *iface;
- struct ifa *a;
-
- WALK_LIST(iface, iface_list)
- {
- if (! (iface->flags & IF_UP))
- continue;
-
- WALK_LIST(a, iface->addrs)
- {
- if (a->flags & IA_SECONDARY)
- continue;
+ struct ospf_proto *p = (struct ospf_proto *) P;
- if (a->scope <= SCOPE_LINK)
- continue;
+ if (a->flags & IA_SECONDARY)
+ return;
- if (ip = ospf_iface_patt_find(oa->ac, a))
- {
- /* Main inner loop */
- struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a);
- if (ifa)
- {
- if (ospf_iface_reconfigure(ifa, ip))
- continue;
+ if (a->scope <= SCOPE_LINK)
+ return;
- /* Hard restart */
- log(L_INFO "%s: Restarting interface %s (%I/%d) in area %R",
- p->name, ifa->ifname, a->prefix, a->pxlen, oa->areaid);
- ospf_iface_shutdown(ifa);
- ospf_iface_remove(ifa);
- }
-
- ospf_iface_new(oa, a, ip);
- }
- }
+ /* In OSPFv2, we create OSPF iface for each address. */
+ if (flags & IF_CHANGE_UP)
+ {
+ struct ospf_mip_walk s = { .iface = a->iface, .a = a };
+ while (ospf_walk_matching_iface_patts(p, &s))
+ ospf_iface_new(s.oa, a, s.ip);
}
-}
-
-
-#else /* OSPFv3 */
-
-struct ospf_iface_patt *
-ospf_iface_patt_find(struct ospf_area_config *ac, struct iface *iface, int iid)
-{
- struct ospf_iface_patt *pt, *res = NULL;
- WALK_LIST(pt, ac->patt_list)
- if ((pt->instance_id >= iid) && (iface_patt_match(&pt->i, iface, NULL)) &&
- (!res || (pt->instance_id < res->instance_id)))
- res = pt;
-
- return res;
+ if (flags & IF_CHANGE_DOWN)
+ {
+ struct ospf_iface *ifa, *ifx;
+ WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
+ if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
+ ospf_iface_remove(ifa);
+ /* See a note in ospf_iface_notify() */
+ }
}
void
-ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
+ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
+ struct ospf_proto *p = (struct ospf_proto *) P;
if (a->flags & IA_SECONDARY)
return;
@@ -1099,71 +1109,79 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
{
if (flags & IF_CHANGE_UP)
{
- int done0 = 0;
- struct ospf_area *oa;
-
- WALK_LIST(oa, po->area_list)
- {
- int iid = 0;
-
- struct ospf_iface_patt *ip;
- while (ip = ospf_iface_patt_find(oa->ac, a->iface, iid))
- {
- ospf_iface_new(oa, a, ip);
- if (ip->instance_id == 0)
- done0++;
- iid = ip->instance_id + 1;
- }
- }
-
- if (done0 > 1)
- log(L_WARN "%s: Interface %s matches for multiple areas",
- p->name, a->iface->name);
+ struct ospf_mip_walk s = { .iface = a->iface };
+ while (ospf_walk_matching_iface_patts(p, &s))
+ ospf_iface_new(s.oa, a, s.ip);
}
if (flags & IF_CHANGE_DOWN)
{
struct ospf_iface *ifa, *ifx;
- WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
- {
- if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
+ WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
+ if ((ifa->addr == a) && (ifa->type != OSPF_IT_VLINK))
ospf_iface_remove(ifa);
- /* See a note in ospf_iface_notify() */
- }
}
}
else
{
struct ospf_iface *ifa;
- WALK_LIST(ifa, po->iface_list)
- {
+ WALK_LIST(ifa, p->iface_list)
if (ifa->iface == a->iface)
{
- schedule_rt_lsa(ifa->oa);
- /* Event 5 from RFC5340 4.4.3. */
- schedule_link_lsa(ifa);
- return;
+ /* RFC 5340 4.4.3 Event 5 - prefix added/deleted */
+ ospf_notify_link_lsa(ifa);
+ ospf_notify_rt_lsa(ifa->oa);
}
- }
}
}
-static struct ospf_iface *
-ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
+
+static void
+ospf_reconfigure_ifaces2(struct ospf_proto *p)
{
- struct ospf_iface *ifa;
- WALK_LIST(ifa, oa->po->iface_list)
- if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
- return ifa;
+ struct iface *iface;
+ struct ifa *a;
- return NULL;
+ WALK_LIST(iface, iface_list)
+ {
+ if (! (iface->flags & IF_UP))
+ continue;
+
+ WALK_LIST(a, iface->addrs)
+ {
+ if (a->flags & IA_SECONDARY)
+ continue;
+
+ if (a->scope <= SCOPE_LINK)
+ continue;
+
+ struct ospf_mip_walk s = { .iface = iface, .a = a };
+ while (ospf_walk_matching_iface_patts(p, &s))
+ {
+ /* Main inner loop */
+ struct ospf_iface *ifa = ospf_iface_find_by_key(p, a, s.ip->instance_id);
+ if (ifa)
+ {
+ if ((ifa->oa == s.oa) && (ifa->marked < 2) &&
+ ospf_iface_reconfigure(ifa, s.ip))
+ continue;
+
+ /* Hard restart */
+ log(L_INFO "%s: Restarting interface %s (%I/%d) in area %R",
+ p->p.name, ifa->ifname, a->prefix, a->pxlen, s.oa->areaid);
+ ospf_iface_shutdown(ifa);
+ ospf_iface_remove(ifa);
+ }
+
+ ospf_iface_new(s.oa, a, s.ip);
+ }
+ }
+ }
}
-void
-ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
+static void
+ospf_reconfigure_ifaces3(struct ospf_proto *p)
{
- struct proto *p = &oa->po->proto;
- struct ospf_iface_patt *ip;
struct iface *iface;
struct ifa *a;
@@ -1180,41 +1198,46 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
if (a->scope != SCOPE_LINK)
continue;
- int iid = 0;
- while (ip = ospf_iface_patt_find(nac, iface, iid))
+ struct ospf_mip_walk s = { .iface = iface };
+ while (ospf_walk_matching_iface_patts(p, &s))
{
- iid = ip->instance_id + 1;
-
/* Main inner loop */
- struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a, ip->instance_id);
+ struct ospf_iface *ifa = ospf_iface_find_by_key(p, a, s.ip->instance_id);
if (ifa)
{
- if (ospf_iface_reconfigure(ifa, ip))
+ if ((ifa->oa == s.oa) && (ifa->marked < 2) &&
+ ospf_iface_reconfigure(ifa, s.ip))
continue;
/* Hard restart */
log(L_INFO "%s: Restarting interface %s (IID %d) in area %R",
- p->name, ifa->ifname, ifa->instance_id, oa->areaid);
+ p->p.name, ifa->ifname, ifa->instance_id, s.oa->areaid);
ospf_iface_shutdown(ifa);
ospf_iface_remove(ifa);
}
- ospf_iface_new(oa, a, ip);
+ ospf_iface_new(s.oa, a, s.ip);
}
}
}
}
-#endif
+void
+ospf_reconfigure_ifaces(struct ospf_proto *p)
+{
+ if (ospf_is_v2(p))
+ ospf_reconfigure_ifaces2(p);
+ else
+ ospf_reconfigure_ifaces3(p);
+}
+
static void
-ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
+ospf_iface_change_mtu(struct ospf_proto *p, struct ospf_iface *ifa)
{
- struct proto *p = &po->proto;
-
/* ifa is not vlink */
- OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->ifname);
+ OSPF_TRACE(D_EVENTS, "Interface %s changed MTU to %d", ifa->iface->mtu);
ifa->tx_length = ifa_tx_length(ifa);
@@ -1227,10 +1250,13 @@ ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
sk_set_rbsize(ifa->sk, bsize);
if (bsize > ifa->sk->tbsize)
sk_set_tbsize(ifa->sk, bsize);
+
+ if (!ifa->stub)
+ ospf_iface_update_flood_queue_size(ifa);
}
static void
-ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
+ospf_iface_notify(struct ospf_proto *p, uint flags, struct ospf_iface *ifa)
{
/* ifa is not vlink */
@@ -1244,13 +1270,13 @@ ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
ospf_iface_sm(ifa, (ifa->iface->flags & IF_LINK_UP) ? ISM_UNLOOP : ISM_LOOP);
if (flags & IF_CHANGE_MTU)
- ospf_iface_change_mtu(po, ifa);
+ ospf_iface_change_mtu(p, ifa);
}
void
-ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
+ospf_if_notify(struct proto *P, uint flags, struct iface *iface)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
+ struct ospf_proto *p = (struct ospf_proto *) P;
/*
if (iface->flags & IF_IGNORE)
@@ -1262,9 +1288,9 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
return;
struct ospf_iface *ifa, *ifx;
- WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
+ WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
if (ifa->iface == iface)
- ospf_iface_notify(po, flags, ifa);
+ ospf_iface_notify(p, flags, ifa);
/* We use here that even shutting down iface also shuts down
the vlinks, but vlinks are not freed and stays in the
@@ -1286,24 +1312,23 @@ ospf_iface_info(struct ospf_iface *ifa)
if (ifa->type == OSPF_IT_VLINK)
{
- cli_msg(-1015, "Virtual link %s to %R:", ifa->ifname, ifa->vid);
+ cli_msg(-1015, "Virtual link %s to %R", ifa->ifname, ifa->vid);
cli_msg(-1015, "\tPeer IP: %I", ifa->vip);
cli_msg(-1015, "\tTransit area: %R (%u)", ifa->voa->areaid, ifa->voa->areaid);
}
else
{
-#ifdef OSPFv2
- if (ifa->addr->flags & IA_PEER)
+ if (ospf_is_v3(ifa->oa->po))
+ cli_msg(-1015, "Interface %s (IID %d)", ifa->ifname, ifa->instance_id);
+ else if (ifa->addr->flags & IA_PEER)
cli_msg(-1015, "Interface %s (peer %I)", ifa->ifname, ifa->addr->opposite);
else
cli_msg(-1015, "Interface %s (%I/%d)", ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen);
-#else /* OSPFv3 */
- cli_msg(-1015, "Interface %s (IID %d)", ifa->ifname, ifa->instance_id);
-#endif
+
cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
}
- cli_msg(-1015, "\tState: %s%s", ospf_is[ifa->state], ifa->stub ? " (stub)" : "");
+ cli_msg(-1015, "\tState: %s%s", ospf_is_names[ifa->state], ifa->stub ? " (stub)" : "");
cli_msg(-1015, "\tPriority: %u", ifa->priority);
cli_msg(-1015, "\tCost: %u", ifa->cost);
if (ifa->oa->po->ecmp)
@@ -1325,4 +1350,3 @@ ospf_iface_info(struct ospf_iface *ifa)
cli_msg(-1015, "\tBackup designed router (IP): %I", ifa->bdrip);
}
}
-
diff --git a/proto/ospf/iface.h b/proto/ospf/iface.h
deleted file mode 100644
index 5a250e0a..00000000
--- a/proto/ospf/iface.h
+++ /dev/null
@@ -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_ */
diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c
index fd8ead01..251b5e47 100644
--- a/proto/ospf/lsack.c
+++ b/proto/ospf/lsack.c
@@ -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,171 @@
#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[];
+};
+*/
-char *s_queue[] = { "direct", "delayed" };
+struct lsa_node
+{
+ node n;
+ struct ospf_lsa_header lsa;
+};
-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;
+ WALK_LIST_FIRST(no, n->ackl[ACKL_DELAY])
+ {
+ rem_node(NODE no);
+ mb_free(no);
+ }
+}
+
+static inline void
+ospf_send_lsack_(struct ospf_proto *p, struct ospf_neighbor *n, int queue)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct ospf_lsa_header *lsas;
+ struct ospf_packet *pkt;
+ struct lsa_node *no;
+ uint i, lsa_max, length;
- pk = ospf_tx_buffer(ifa);
- op = &pk->ospf_packet;
+ /* RFC 2328 13.5 */
- ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
- h = pk->lsh;
+ pkt = ospf_tx_buffer(ifa);
+ ospf_pkt_fill_hdr(ifa, pkt, LSACK_P);
+ ospf_lsack_body(p, pkt, &lsas, &lsa_max);
- while (!EMPTY_LIST(n->ackl[queue]))
+ for (i = 0; i < lsa_max && !EMPTY_LIST(n->ackl[queue]); i++)
{
- 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++;
+ 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);
- if ((i * sizeof(struct ospf_lsa_header) +
- sizeof(struct ospf_lsack_packet)) > ospf_pkt_maxsize(n->ifa))
- {
- if (!EMPTY_LIST(n->ackl[queue]))
- {
- len =
- sizeof(struct ospf_lsack_packet) +
- i * sizeof(struct ospf_lsa_header);
- op->length = htons(len);
- DBG("Sending and continuing! Len=%u\n", len);
-
- OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
-
- if (ifa->type == OSPF_IT_BCAST)
- {
- if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
- ospf_send_to_all(ifa);
- else if (ifa->cf->real_bcast)
- ospf_send_to_bdr(ifa);
- else
- ospf_send_to(ifa, AllDRouters);
- }
- else
- {
- if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
- ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
- else
- ospf_send_to_bdr(ifa);
- }
-
- ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
- i = 0;
- }
- }
}
- len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header);
- op->length = htons(len);
- DBG("Sending! Len=%u\n", len);
+ 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_send_lsack(struct ospf_proto *p, struct ospf_neighbor *n, int queue)
+{
+ while (!EMPTY_LIST(n->ackl[queue]))
+ ospf_send_lsack_(p, 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 nbr %R on %s", n->rid, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE)
+ {
+ OSPF_TRACE(D_PACKETS, "LSACK packet ignored - lesser state than Exchange");
return;
+ }
+
+ ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
- lsano = (size - sizeof(struct ospf_lsack_packet)) /
- sizeof(struct ospf_lsa_header);
- for (i = 0; i < lsano; i++)
+ ospf_lsack_body(p, pkt, &lsas, &lsa_count);
+ for (i = 0; i < lsa_count; 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 */
+ lsa_ntoh_hdr(&lsas[i], &lsa);
+ lsa_get_type_domain(&lsa, n->ifa, &lsa_type, &lsa_domain);
- if (lsa_comp(&lsa, &en->lsa) != CMP_SAME) /* pg 156 */
+ 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);
- OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x",
- en->lsa.age, en->lsa.sn, en->lsa.checksum);
- OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x",
- lsa.age, lsa.sn, lsa.checksum);
+ OSPF_TRACE(D_PACKETS, "Strange LSACK from nbr %R on %s", n->rid, ifa->ifname);
+ OSPF_TRACE(D_PACKETS, " Type: %04x, Id: %R, Rt: %R",
+ lsa_type, lsa.id, lsa.rt);
+ OSPF_TRACE(D_PACKETS, " I have: Seq: %08x, Age: %4u, Sum: %04x",
+ ret->lsa.sn, ret->lsa.age, ret->lsa.checksum);
+ OSPF_TRACE(D_PACKETS, " It has: Seq: %08x, Age: %4u, Sum: %04x",
+ lsa.sn, lsa.age, 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);
+ DBG("Deleting LSA (Type: %04x Id: %R Rt: %R) from lsrtl for neighbor %R\n",
+ lsa_type, lsa.id, lsa.rt, n->rid);
+
+ en = ospf_hash_find_entry(p->gr, ret);
+ ospf_lsa_lsrt_down_(en, n, ret);
}
}
diff --git a/proto/ospf/lsack.h b/proto/ospf/lsack.h
deleted file mode 100644
index 63a436d6..00000000
--- a/proto/ospf/lsack.h
+++ /dev/null
@@ -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_ */
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c
index bcf7bcdd..579d13e8 100644
--- a/proto/ospf/lsalib.c
+++ b/proto/ospf/lsalib.c
@@ -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));
}
/*
@@ -231,7 +238,7 @@ lsasum_check(struct ospf_lsa_header *h, void *body)
q = ep;
for (p = sp; p < q; p++)
{
- /*
+ /*
* I count with bytes from header and than from body
* but if there is no body, it's appended to header
* (probably checksum in update receiving) and I go on
@@ -292,79 +299,231 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
return CMP_SAME;
}
-#define HDRLEN sizeof(struct ospf_lsa_header)
-static int
-lsa_validate_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
+static inline int
+lsa_walk_rt2(struct ospf_lsa_rt_walk *rt)
{
- unsigned int i, max;
-
- if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
+ if (rt->buf >= rt->bufend)
return 0;
- struct ospf_lsa_rt_link *rtl = (struct ospf_lsa_rt_link *) (body + 1);
- max = lsa_rt_count(lsa);
+ 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);
-#ifdef OSPFv2
- if (body->links != max)
- return 0;
-#endif
+ rt->type = l->type;
+ rt->metric = l->metric;
+ rt->id = l->id;
+ rt->data = l->data;
+ return 1;
+}
- for (i = 0; i < max; i++)
+static inline int
+lsa_walk_rt3(struct ospf_lsa_rt_walk *rt)
+{
+ while (rt->buf >= rt->bufend)
{
- u8 type = rtl[i].type;
- if (!((type == LSART_PTP) ||
- (type == LSART_NET) ||
-#ifdef OSPFv2
- (type == LSART_STUB) ||
-#endif
- (type == LSART_VLNK)))
+ 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_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
+lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
{
- if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net)))
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
+ return 0;
+
+ uint i = 0;
+ void *buf = body;
+ void *bufend = buf + lsa->length - HDRLEN;
+ buf += sizeof(struct ospf_lsa_rt);
+
+ while (buf < bufend)
+ {
+ 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;
}
-#ifdef OSPFv2
static int
-lsa_validate_sum(struct ospf_lsa_header *lsa, struct ospf_lsa_sum *body)
+lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
{
- if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum)))
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
return 0;
- /* First field should have TOS = 0, we ignore other TOS fields */
- if ((body->metric & LSA_SUM_TOS) != 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;
+}
+
+static int
+lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
+{
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net)))
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)
+lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body)
{
- if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext)))
+ 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_EXT_TOS) != 0)
+ if ((body->metric & LSA_SUM2_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_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body)
+{
+ if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt)))
+ return 0;
+
+ return 1;
+}
static int
-lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_rt *body)
+lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body)
{
- if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_rt)))
+ 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_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
+lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
{
- if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext) + 4))
+ 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++)
@@ -436,7 +607,7 @@ lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, unsigned int offse
u8 pxl = pxlen((u32 *) (pbuf + offset));
if (pxl > MAX_PREFIX_LENGTH)
return 0;
-
+
offset += IPV6_PREFIX_SPACE(pxl);
}
@@ -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;
}
diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h
index 0b556ec5..d9e1a610 100644
--- a/proto/ospf/lsalib.h
+++ b/proto/ospf/lsalib.h
@@ -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_ */
diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c
index 15854ce7..657c0247 100644
--- a/proto/ospf/lsreq.c
+++ b/proto/ospf/lsreq.c
@@ -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,138 +11,136 @@
#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);
+
+ *body = ((void *) pkt) + hlen;
+ *count = (plen - hlen) / sizeof(struct ospf_lsreq_header);
+}
- ASSERT(op->type == LSREQ_P);
- ospf_dump_common(p, op);
+static void
+ospf_dump_lsreq(struct ospf_proto *p, struct ospf_packet *pkt)
+{
+ struct ospf_lsreq_header *lsrs;
+ uint i, lsr_count;
- unsigned int i, j;
- j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) /
- sizeof(struct ospf_lsreq_header);
+ ASSERT(pkt->type == LSREQ_P);
+ ospf_dump_common(p, pkt);
- 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));
+ 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_lsreq_send(struct ospf_neighbor *n)
+ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n)
{
- snode *sn;
- 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;
-
- pk = ospf_tx_buffer(n->ifa);
- op = &pk->ospf_packet;
-
- ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P);
-
- sn = SHEAD(n->lsrql);
- if (EMPTY_SLIST(n->lsrql))
- {
- if (n->state == NEIGHBOR_LOADING)
- ospf_neigh_sm(n, INM_LOADDONE);
- return;
- }
+ struct ospf_iface *ifa = n->ifa;
+ struct ospf_lsreq_header *lsrs;
+ struct top_hash_entry *req;
+ struct ospf_packet *pkt;
+ uint i, lsr_max, length;
+
+ /* RFC 2328 10.9 */
- i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) /
- sizeof(struct ospf_lsreq_header);
- lsh = pk->lsh;
+ /* ASSERT((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrql)); */
- for (; i > 0; i--)
+ pkt = ospf_tx_buffer(ifa);
+ ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P);
+ ospf_lsreq_body(p, pkt, &lsrs, &lsr_max);
+
+ i = 0;
+ WALK_SLIST(req, 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, req->lsa_type, req->lsa.id, req->lsa.rt, req->lsa.sn, req->lsa.age);
+
+ u32 etype = lsa_get_etype(&req->lsa, p);
+ lsrs[i].type = htonl(etype);
+ lsrs[i].rt = htonl(req->lsa.rt);
+ lsrs[i].id = htonl(req->lsa.id);
+ i++;
}
- if (i != 0)
- i--;
- length =
- sizeof(struct ospf_lsreq_packet) + (j -
- i) * sizeof(struct ospf_lsreq_header);
- op->length = htons(length);
+ /* We store the position to see whether requested LSAs have been received */
+ n->lsrqi = req;
+
+ 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 nbr %R on %s", n->rid, 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;
-
- 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;
- }
+ struct ospf_proto *p = ifa->oa->po;
+ struct ospf_lsreq_header *lsrs;
+ uint i, lsr_count;
+
+ /* 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 nbr %R on %s", n->rid, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE)
+ {
+ OSPF_TRACE(D_PACKETS, "LSREQ packet ignored - lesser state than 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_LSA1("Bad LSR (Type: %04x, Id: %R, Rt: %R) in LSREQ", type, id, rt);
+ LOG_LSA2(" received from nbr %R on %s - LSA is missing", n->rid, ifa->ifname);
+
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);
}
diff --git a/proto/ospf/lsreq.h b/proto/ospf/lsreq.h
deleted file mode 100644
index a12edde2..00000000
--- a/proto/ospf/lsreq.h
+++ /dev/null
@@ -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_ */
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index 8f65c532..ea32923a 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -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,755 +11,705 @@
#include "ospf.h"
+/*
struct ospf_lsupd_packet
{
- struct ospf_packet ospf_packet;
- u32 lsano; /* Number of LSA's */
+ struct ospf_packet hdr;
+ // union ospf_auth auth;
+
+ u32 lsa_count;
+ void lsas[];
};
+*/
-/* Beware of unaligned access */
-void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n)
+void
+ospf_dump_lsahdr(struct ospf_proto *p, struct ospf_lsa_header *lsa_n)
{
struct ospf_lsa_header lsa;
- ntohlsah(lsa_n, &lsa);
+ u32 lsa_etype;
+
+ lsa_ntoh_hdr(lsa_n, &lsa);
+ lsa_etype = lsa_get_etype(&lsa, p);
- log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x",
- p->name, lsa.type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum);
+ log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Seq: %08x, Age: %u, Sum: %04x",
+ p->p.name, lsa_etype, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum);
}
-void ospf_dump_common(struct proto *p, struct ospf_packet *op)
+void
+ospf_dump_common(struct ospf_proto *p, struct ospf_packet *pkt)
{
- log(L_TRACE "%s: length %d", p->name, ntohs(op->length));
- log(L_TRACE "%s: router %R", p->name, ntohl(op->routerid));
+ log(L_TRACE "%s: length %d", p->p.name, ntohs(pkt->length));
+ log(L_TRACE "%s: router %R", p->p.name, ntohl(pkt->routerid));
}
-static void ospf_dump_lsupd(struct proto *p, struct ospf_lsupd_packet *pkt)
+static inline uint
+ospf_lsupd_hdrlen(struct ospf_proto *p)
{
- struct ospf_packet *op = &pkt->ospf_packet;
+ return ospf_pkt_hdrlen(p) + 4; /* + u32 lsa count field */
+}
- ASSERT(op->type == LSUPD_P);
- ospf_dump_common(p, op);
+static inline u32
+ospf_lsupd_get_lsa_count(struct ospf_packet *pkt, uint hdrlen)
+{
+ u32 *c = ((void *) pkt) + hdrlen - 4;
+ return ntohl(*c);
+}
- /* We know that ntohs(op->length) >= sizeof(struct ospf_lsa_header) */
- u8 *pbuf= (u8 *) pkt;
- unsigned int offset = sizeof(struct ospf_lsupd_packet);
- unsigned int bound = ntohs(op->length) - sizeof(struct ospf_lsa_header);
- unsigned int i, j, lsalen;
+static inline void
+ospf_lsupd_set_lsa_count(struct ospf_packet *pkt, uint hdrlen, u32 val)
+{
+ u32 *c = ((void *) pkt) + hdrlen - 4;
+ *c = htonl(val);
+}
- j = ntohl(pkt->lsano);
- for (i = 0; i < j; i++)
- {
- if (offset > bound)
- {
- log(L_TRACE "%s: LSA invalid", p->name);
- return;
- }
+static inline void
+ospf_lsupd_body(struct ospf_proto *p, struct ospf_packet *pkt,
+ uint *offset, uint *lsa_count)
+{
+ uint hlen = ospf_lsupd_hdrlen(p);
+ *offset = hlen;
+ *lsa_count = ospf_lsupd_get_lsa_count(pkt, hlen);
+}
- struct ospf_lsa_header *lsa = (void *) (pbuf + offset);
- ospf_dump_lsahdr(p, lsa);
- lsalen = ntohs(lsa->length);
- offset += lsalen;
+static void
+ospf_dump_lsupd(struct ospf_proto *p, struct ospf_packet *pkt)
+{
+ uint offset, plen, i, lsa_count, lsa_len;
- if (((lsalen % 4) != 0) || (lsalen <= sizeof(struct ospf_lsa_header)))
- {
- log(L_TRACE "%s: LSA invalid", p->name);
- return;
- }
- }
+ ASSERT(pkt->type == LSUPD_P);
+ ospf_dump_common(p, pkt);
+
+ plen = ntohs(pkt->length);
+ ospf_lsupd_body(p, pkt, &offset, &lsa_count);
+ for (i = 0; i < lsa_count; i++)
+ {
+ if ((offset + sizeof(struct ospf_lsa_header)) > plen)
+ goto invalid;
+
+ struct ospf_lsa_header *lsa = ((void *) pkt) + offset;
+ lsa_len = ntohs(lsa->length);
+
+ if (((lsa_len % 4) != 0) || (lsa_len <= sizeof(struct ospf_lsa_header)))
+ goto invalid;
+
+ ospf_dump_lsahdr(p, lsa);
+ offset += lsa_len;
+ }
+ return;
+
+invalid:
+ log(L_TRACE "%s: LSA invalid", p->p.name);
+ return;
}
-#ifdef OSPFv2
+static inline void
+ospf_lsa_lsrq_down(struct top_hash_entry *req, struct ospf_neighbor *n, struct ospf_neighbor *from)
+{
+ if (req == n->lsrqi)
+ n->lsrqi = SNODE_NEXT(req);
-int
-ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
+ s_rem_node(SNODE req);
+ ospf_hash_delete(n->lsrqh, req);
+
+ if (EMPTY_SLIST(n->lsrql))
+ {
+ tm_stop(n->lsrq_timer);
+
+ if (n->state == NEIGHBOR_LOADING)
+ ospf_neigh_sm(n, INM_LOADDONE);
+ }
+}
+
+static inline void
+ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n)
{
- if (lsa->type == LSA_T_EXT)
- {
- if (ifa->type == OSPF_IT_VLINK)
- return 0;
- if (!oa_is_ext(ifa->oa))
- return 0;
- return 1;
- }
- else
- return ifa->oa->areaid == domain;
+ struct top_hash_entry *ret = ospf_hash_get_entry(n->lsrth, en);
+
+ if (!SNODE_VALID(ret))
+ {
+ en->ret_count++;
+ s_add_tail(&n->lsrtl, SNODE ret);
+ }
+
+ ret->lsa = en->lsa;
+ ret->lsa_body = LSA_BODY_DUMMY;
+
+ if (!tm_active(n->lsrt_timer))
+ tm_start(n->lsrt_timer, n->ifa->rxmtint);
}
-#else /* OSPFv3 */
+void
+ospf_lsa_lsrt_down_(struct top_hash_entry *en, struct ospf_neighbor *n, struct top_hash_entry *ret)
+{
+ if (en)
+ en->ret_count--;
-static int
-unknown_lsa_type(struct ospf_lsa_header *lsa)
+ s_rem_node(SNODE ret);
+ ospf_hash_delete(n->lsrth, ret);
+
+ if (EMPTY_SLIST(n->lsrtl))
+ tm_stop(n->lsrt_timer);
+}
+
+static inline int
+ospf_lsa_lsrt_down(struct top_hash_entry *en, struct ospf_neighbor *n)
{
- switch (lsa->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;
- }
+ struct top_hash_entry *ret = ospf_hash_find_entry(n->lsrth, en);
+
+ if (ret)
+ ospf_lsa_lsrt_down_(en, n, ret);
+
+ return ret != NULL;
}
-int
-ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
-{
- u32 scope = LSA_SCOPE(lsa);
+void
+ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n)
+{
+ struct top_hash_entry *en;
- /* Handle inactive vlinks */
- if (ifa->state == OSPF_IS_DOWN)
- return 0;
+ WALK_SLIST(en, p->lsal)
+ if ((en->lsa.age == LSA_MAXAGE) && (en->lsa_body != NULL) &&
+ lsa_flooding_allowed(en->lsa_type, en->domain, n->ifa))
+ ospf_lsa_lsrt_up(en, n);
- /* 4.5.2 (Case 2) */
- if (unknown_lsa_type(lsa) && !(lsa->type & LSA_UBIT))
- scope = LSA_SCOPE_LINK;
+ /* If we found any flushed LSA, we send them ASAP */
+ if (tm_active(n->lsrt_timer))
+ tm_start(n->lsrt_timer, 0);
+}
- switch (scope)
- {
- case LSA_SCOPE_LINK:
- return ifa->iface_id == domain;
+static int ospf_flood_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, uint lsa_min_count, struct ospf_iface *ifa);
- case LSA_SCOPE_AREA:
- return ifa->oa->areaid == domain;
+static void
+ospf_enqueue_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa)
+{
+ if (ifa->flood_queue_used == ifa->flood_queue_size)
+ {
+ /* If we already have full queue, we send some packets */
+ uint sent = ospf_flood_lsupd(p, ifa->flood_queue, ifa->flood_queue_used, ifa->flood_queue_used / 2, ifa);
+ int i;
- case LSA_SCOPE_AS:
- if (ifa->type == OSPF_IT_VLINK)
- return 0;
- if (!oa_is_ext(ifa->oa))
- return 0;
- return 1;
+ for (i = 0; i < sent; i++)
+ ifa->flood_queue[i]->ret_count--;
- default:
- log(L_ERR "LSA with invalid scope");
- return 0;
- }
+ ifa->flood_queue_used -= sent;
+ memmove(ifa->flood_queue, ifa->flood_queue + sent, ifa->flood_queue_used * sizeof(void *));
+ bzero(ifa->flood_queue + ifa->flood_queue_used, sent * sizeof(void *));
+ }
+
+ en->ret_count++;
+ ifa->flood_queue[ifa->flood_queue_used] = en;
+ ifa->flood_queue_used++;
+
+ if (!ev_active(p->flood_event))
+ ev_schedule(p->flood_event);
+}
+
+void
+ospf_flood_event(void *ptr)
+{
+ struct ospf_proto *p = ptr;
+ struct ospf_iface *ifa;
+ int i, count;
+
+ WALK_LIST(ifa, p->iface_list)
+ {
+ if (ifa->flood_queue_used == 0)
+ continue;
+
+ count = ifa->flood_queue_used;
+ ospf_flood_lsupd(p, ifa->flood_queue, count, count, ifa);
+
+ for (i = 0; i < count; i++)
+ ifa->flood_queue[i]->ret_count--;
+
+ ifa->flood_queue_used = 0;
+ bzero(ifa->flood_queue, count * sizeof(void *));
+ }
}
-#endif
/**
- * ospf_lsupd_flood - send received or generated lsa to the neighbors
- * @po: OSPF protocol
- * @n: neighbor than sent this lsa (or NULL if generated)
- * @hn: LSA header followed by lsa body in network endianity (may be NULL)
- * @hh: LSA header in host endianity (must be filled)
- * @domain: domain of LSA (must be filled)
- * @rtl: add this LSA into retransmission list
- *
+ * ospf_flood_lsa - send LSA to the neighbors
+ * @p: OSPF protocol instance
+ * @en: LSA entry
+ * @from: neighbor than sent this LSA (or NULL if LSA is local)
*
* return value - was the LSA flooded back?
*/
-
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)
+ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from)
{
struct ospf_iface *ifa;
- struct ospf_neighbor *nn;
- struct top_hash_entry *en;
- struct proto *p = &po->proto;
- int ret, retval = 0;
+ struct ospf_neighbor *n;
- /* pg 148 */
- WALK_LIST(ifa, po->iface_list)
+ /* RFC 2328 13.3 */
+
+ int back = 0;
+ WALK_LIST(ifa, p->iface_list)
{
if (ifa->stub)
continue;
- if (! ospf_lsa_flooding_allowed(hh, domain, ifa))
+ if (! lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
continue;
DBG("Wanted to flood LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
hh->type, hh->id, hh->rt, hh->sn, hh->age);
- ret = 0;
- WALK_LIST(nn, ifa->neigh_list)
+ int used = 0;
+ WALK_LIST(n, ifa->neigh_list)
{
/* 13.3 (1a) */
- if (nn->state < NEIGHBOR_EXCHANGE)
+ if (n->state < NEIGHBOR_EXCHANGE)
continue;
/* 13.3 (1b) */
- if (nn->state < NEIGHBOR_FULL)
+ if (n->state < NEIGHBOR_FULL)
{
- if ((en = ospf_hash_find_header(nn->lsrqh, domain, hh)) != NULL)
+ struct top_hash_entry *req = ospf_hash_find_entry(n->lsrqh, en);
+ if (req != NULL)
{
- DBG("That LSA found in lsreq list for neigh %R\n", nn->rid);
+ int cmp = lsa_comp(&en->lsa, &req->lsa);
- switch (lsa_comp(hh, &en->lsa))
- {
- case CMP_OLDER:
- continue;
- break;
- case CMP_SAME:
- s_rem_node(SNODE en);
- if (en->lsa_body != NULL)
- mb_free(en->lsa_body);
- en->lsa_body = NULL;
- DBG("Removing from lsreq list for neigh %R\n", nn->rid);
- ospf_hash_delete(nn->lsrqh, en);
- if ((EMPTY_SLIST(nn->lsrql)) && (nn->state == NEIGHBOR_LOADING))
- ospf_neigh_sm(nn, INM_LOADDONE);
+ /* If same or newer, remove LSA from the link state request list */
+ if (cmp > CMP_OLDER)
+ ospf_lsa_lsrq_down(req, n, from);
+
+ /* If older or same, skip processing of this neighbor */
+ if (cmp < CMP_NEWER)
continue;
- break;
- case CMP_NEWER:
- s_rem_node(SNODE en);
- if (en->lsa_body != NULL)
- mb_free(en->lsa_body);
- en->lsa_body = NULL;
- DBG("Removing from lsreq list for neigh %R\n", nn->rid);
- ospf_hash_delete(nn->lsrqh, en);
- if ((EMPTY_SLIST(nn->lsrql)) && (nn->state == NEIGHBOR_LOADING))
- ospf_neigh_sm(nn, INM_LOADDONE);
- break;
- default:
- bug("Bug in lsa_comp?");
- }
}
}
/* 13.3 (1c) */
- if (nn == n)
+ if (n == from)
continue;
- /* 13.3 (1d) */
- if (rtl)
- {
- /* In OSPFv3, there should be check whether receiving router understand
- that type of LSA (for LSA types with U-bit == 0). But as we does not support
- any optional LSA types, this is not needed yet */
+ /* In OSPFv3, there should be check whether receiving router understand
+ that type of LSA (for LSA types with U-bit == 0). But as we do not support
+ any optional LSA types, this is not needed yet */
- if ((en = ospf_hash_find_header(nn->lsrth, domain, hh)) == NULL)
- {
- en = ospf_hash_get_header(nn->lsrth, domain, hh);
- }
- else
- {
- s_rem_node(SNODE en);
- }
- s_add_tail(&nn->lsrtl, SNODE en);
- memcpy(&en->lsa, hh, sizeof(struct ospf_lsa_header));
- DBG("Adding that LSA for flood to %I\n", nn->ip);
- }
- else
- {
- if ((en = ospf_hash_find_header(nn->lsrth, domain, hh)) != NULL)
- {
- s_rem_node(SNODE en);
- ospf_hash_delete(nn->lsrth, en);
- }
- }
+ /* 13.3 (1d) - add LSA to the link state retransmission list */
+ ospf_lsa_lsrt_up(en, n);
- ret = 1;
+ used = 1;
}
- if (ret == 0)
- continue; /* pg 150 (2) */
+ /* 13.3 (2) */
+ if (!used)
+ continue;
- if (n && (n->ifa == ifa))
+ if (from && (from->ifa == ifa))
{
- if ((n->rid == ifa->drid) || n->rid == ifa->bdrid)
- continue; /* pg 150 (3) */
+ /* 13.3 (3) */
+ if ((from->rid == ifa->drid) || (from->rid == ifa->bdrid))
+ continue;
+
+ /* 13.3 (4) */
if (ifa->state == OSPF_IS_BACKUP)
- continue; /* pg 150 (4) */
- retval = 1;
+ continue;
+
+ back = 1;
}
- {
- u16 len, age;
- struct ospf_lsupd_packet *pk;
- struct ospf_packet *op;
- struct ospf_lsa_header *lh;
-
- /* Check iface buffer size */
- uint len2 = sizeof(struct ospf_lsupd_packet) + (hn ? ntohs(hn->length) : hh->length);
- if (ospf_iface_assure_bufsize(ifa, len2) < 0)
- {
- /* Cannot fit in a tx buffer, skip that iface */
- log(L_ERR "OSPF: LSA too large to flood on %s (Type: %04x, Id: %R, Rt: %R)",
- ifa->ifname, hh->type, hh->id, hh->rt);
- continue;
- }
+ /* 13.3 (5) - finally flood the packet */
+ ospf_enqueue_lsa(p, en, ifa);
+ }
- pk = ospf_tx_buffer(ifa);
- op = &pk->ospf_packet;
+ return back;
+}
+
+static uint
+ospf_prepare_lsupd(struct ospf_proto *p, struct ospf_iface *ifa,
+ struct top_hash_entry **lsa_list, uint lsa_count)
+{
+ struct ospf_packet *pkt;
+ uint hlen, pos, i, maxsize;
+
+ pkt = ospf_tx_buffer(ifa);
+ hlen = ospf_lsupd_hdrlen(p);
+ maxsize = ospf_pkt_maxsize(ifa);
- ospf_pkt_fill_hdr(ifa, pk, LSUPD_P);
- pk->lsano = htonl(1);
+ ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P);
+ pos = hlen;
- lh = (struct ospf_lsa_header *) (pk + 1);
+ for (i = 0; i < lsa_count; i++)
+ {
+ struct top_hash_entry *en = lsa_list[i];
+ uint len = en->lsa.length;
+
+ if ((pos + len) > maxsize)
+ {
+ /* The packet if full, stop adding LSAs and sent it */
+ if (i > 0)
+ break;
- /* Copy LSA into the packet */
- if (hn)
+ /* LSA is larger than MTU, check buffer size */
+ if (ospf_iface_assure_bufsize(ifa, pos + len) < 0)
{
- memcpy(lh, hn, ntohs(hn->length));
+ /* Cannot fit in a tx buffer, skip that */
+ log(L_ERR "%s: LSA too large to send on %s (Type: %04x, Id: %R, Rt: %R)",
+ p->p.name, ifa->ifname, en->lsa_type, en->lsa.id, en->lsa.rt);
+ break;
}
- else
- {
- u8 *help;
- struct top_hash_entry *en;
- htonlsah(hh, lh);
- help = (u8 *) (lh + 1);
- en = ospf_hash_find_header(po->gr, domain, hh);
- htonlsab(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header));
- }
+ /* TX buffer could be reallocated */
+ pkt = ospf_tx_buffer(ifa);
+ }
+
+ struct ospf_lsa_header *buf = ((void *) pkt) + pos;
+ lsa_hton_hdr(&en->lsa, buf);
+ lsa_hton_body(en->lsa_body, ((void *) buf) + sizeof(struct ospf_lsa_header),
+ len - sizeof(struct ospf_lsa_header));
+ buf->age = htons(MIN(en->lsa.age + ifa->inftransdelay, LSA_MAXAGE));
+
+ pos += len;
+ }
- len = sizeof(struct ospf_lsupd_packet) + ntohs(lh->length);
+ ospf_lsupd_set_lsa_count(pkt, hlen, i);
+ pkt->length = htons(pos);
- age = ntohs(lh->age);
- age += ifa->inftransdelay;
- if (age > LSA_MAXAGE)
- age = LSA_MAXAGE;
- lh->age = htons(age);
+ return i;
+}
- op->length = htons(len);
- OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet flooded via %s", ifa->ifname);
+static int
+ospf_flood_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, uint lsa_min_count, struct ospf_iface *ifa)
+{
+ uint i, c;
- switch (ifa->type)
- {
- case OSPF_IT_BCAST:
- if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
- ospf_send_to_all(ifa);
- else if (ifa->cf->real_bcast)
- ospf_send_to_bdr(ifa);
- else
- ospf_send_to(ifa, AllDRouters);
- break;
+ for (i = 0; i < lsa_min_count; i += c)
+ {
+ c = ospf_prepare_lsupd(p, ifa, lsa_list + i, lsa_count - i);
- case OSPF_IT_NBMA:
- if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
- ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
- else
- ospf_send_to_bdr(ifa);
- break;
+ if (!c) /* Too large LSA */
+ { i++; continue; }
- case OSPF_IT_PTP:
+ OSPF_PACKET(ospf_dump_lsupd, ospf_tx_buffer(ifa),
+ "LSUPD packet flooded 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);
- break;
+ else
+ ospf_send_to_des(ifa);
+ }
+ else
+ ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
+ }
- case OSPF_IT_PTMP:
- ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
- break;
+ return i;
+}
- case OSPF_IT_VLINK:
- ospf_send_to(ifa, ifa->vip);
- break;
+int
+ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, struct ospf_neighbor *n)
+{
+ struct ospf_iface *ifa = n->ifa;
+ uint i, c;
- default:
- bug("Bug in ospf_lsupd_flood()");
- }
- }
+ for (i = 0; i < lsa_count; i += c)
+ {
+ c = ospf_prepare_lsupd(p, ifa, lsa_list + i, lsa_count - i);
+
+ if (!c) /* Too large LSA */
+ { i++; continue; }
+
+ OSPF_PACKET(ospf_dump_lsupd, ospf_tx_buffer(ifa),
+ "LSUPD packet sent to nbr %R on %s", n->rid, ifa->ifname);
+
+ ospf_send_to(ifa, n->ip);
}
- return retval;
+
+ return i;
}
-void /* I send all I received in LSREQ */
-ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
+void
+ospf_rxmt_lsupd(struct ospf_proto *p, struct ospf_neighbor *n)
{
- struct ospf_area *oa = n->ifa->oa;
- struct proto *p = &oa->po->proto;
- struct l_lsr_head *lsr;
- struct top_hash_entry *en;
- struct ospf_lsupd_packet *pkt;
- u32 len, len2, lsano;
- char *buf;
+ uint max = 2 * n->ifa->flood_queue_size;
+ struct top_hash_entry *entries[max];
+ struct top_hash_entry *ret, *nxt, *en;
+ uint i = 0;
- pkt = ospf_tx_buffer(n->ifa);
- buf = (void *) pkt;
+ /* ASSERT((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrtl)); */
- lsr = HEAD(*l);
- while(NODE_NEXT(lsr))
+ WALK_SLIST_DELSAFE(ret, nxt, n->lsrtl)
{
- /* Prepare the packet */
- ospf_pkt_fill_hdr(n->ifa, pkt, LSUPD_P);
- len = sizeof(struct ospf_lsupd_packet);
- lsano = 0;
+ if (i == max)
+ break;
- /* Fill the packet with LSAs */
- while(NODE_NEXT(lsr))
+ en = ospf_hash_find_entry(p->gr, ret);
+ if (!en)
{
- u32 domain = ospf_lsa_domain(lsr->lsh.type, n->ifa);
- en = ospf_hash_find(oa->po->gr, domain, lsr->lsh.id, lsr->lsh.rt, lsr->lsh.type);
- if (en == NULL)
- {
- /* Probably flushed LSA, this should not happen */
- // log(L_WARN "OSPF: LSA disappeared (Type: %04x, Id: %R, Rt: %R)", lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt);
- lsr = NODE_NEXT(lsr);
- continue;
- }
+ /* Probably flushed LSA, this should not happen */
+ log(L_WARN "%s: LSA disappeared (Type: %04x, Id: %R, Rt: %R)",
+ p->p.name, ret->lsa_type, ret->lsa.id, ret->lsa.rt);
- len2 = len + en->lsa.length;
- if (len2 > ospf_pkt_maxsize(n->ifa))
- {
- /* The packet if full, stop adding LSAs and sent it */
- if (lsano > 0)
- break;
+ s_rem_node(SNODE ret);
+ ospf_hash_delete(n->lsrth, ret);
- /* LSA is larger than MTU, check buffer size */
- if (ospf_iface_assure_bufsize(n->ifa, len2) < 0)
- {
- /* Cannot fit in a tx buffer, skip that */
- log(L_ERR "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)",
- lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt);
- lsr = NODE_NEXT(lsr);
- continue;
- }
+ continue;
+ }
- /* TX buffer could be reallocated */
- pkt = ospf_tx_buffer(n->ifa);
- buf = (void *) pkt;
- }
+ entries[i] = en;
+ i++;
+ }
- /* Copy the LSA to the packet */
- htonlsah(&(en->lsa), (struct ospf_lsa_header *) (buf + len));
- htonlsab(en->lsa_body, buf + len + sizeof(struct ospf_lsa_header),
- en->lsa.length - sizeof(struct ospf_lsa_header));
- len = len2;
- lsano++;
- lsr = NODE_NEXT(lsr);
- }
+ ospf_send_lsupd(p, entries, i, n);
+}
- if (lsano == 0)
- break;
- /* Send the packet */
- pkt->lsano = htonl(lsano);
- pkt->ospf_packet.length = htons(len);
- OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet sent to %I via %s",
- n->ip, n->ifa->ifname);
- ospf_send_to(n->ifa, n->ip);
- }
+static inline int
+ospf_addr_is_local(struct ospf_proto *p, struct ospf_area *oa, ip_addr ip)
+{
+ struct ospf_iface *ifa;
+ WALK_LIST(ifa, p->iface_list)
+ if ((ifa->oa == oa) && ifa->addr && ipa_equal(ifa->addr->ip, ip))
+ return 1;
+
+ return 0;
}
void
-ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n)
{
+ struct ospf_proto *p = ifa->oa->po;
+ const char *err_dsc = NULL;
+ uint plen, err_val = 0;
- struct ospf_neighbor *ntmp;
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
- unsigned int i, max, sendreq = 1;
+ /* RFC 2328 13. */
- unsigned int size = ntohs(ps_i->length);
- if (size < (sizeof(struct ospf_lsupd_packet) + sizeof(struct ospf_lsa_header)))
+ plen = ntohs(pkt->length);
+ if (plen < ospf_lsupd_hdrlen(p))
{
- log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, size);
+ LOG_PKT("Bad LSUPD packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
return;
}
- struct ospf_lsupd_packet *ps = (void *) ps_i;
- OSPF_PACKET(ospf_dump_lsupd, ps, "LSUPD packet received from %I via %s", n->ip, ifa->ifname);
+ OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet received from nbr %R on %s", n->rid, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE)
{
- OSPF_TRACE(D_PACKETS, "Received lsupd in lesser state than EXCHANGE from (%I)", n->ip);
+ OSPF_TRACE(D_PACKETS, "LSUPD packet ignored - lesser state than Exchange");
return;
}
ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */
- unsigned int offset = sizeof(struct ospf_lsupd_packet);
- unsigned int bound = size - sizeof(struct ospf_lsa_header);
+ uint offset, i, lsa_count;
+ ospf_lsupd_body(p, pkt, &offset, &lsa_count);
- max = ntohl(ps->lsano);
- for (i = 0; i < max; i++)
+ for (i = 0; i < lsa_count; i++)
{
- struct ospf_lsa_header lsatmp;
- struct top_hash_entry *lsadb;
+ struct ospf_lsa_header lsa, *lsa_n;
+ struct top_hash_entry *en;
+ u32 lsa_len, lsa_type, lsa_domain;
- if (offset > bound)
- {
- log(L_WARN "Received lsupd from %I is too short!", n->ip);
- ospf_neigh_sm(n, INM_BADLSREQ);
- return;
- }
+ if ((offset + sizeof(struct ospf_lsa_header)) > plen)
+ DROP("too short", plen);
- struct ospf_lsa_header *lsa = (void *) (((u8 *) ps) + offset);
- unsigned int lsalen = ntohs(lsa->length);
- offset += lsalen;
-
- if ((offset > size) || ((lsalen % 4) != 0) ||
- (lsalen <= sizeof(struct ospf_lsa_header)))
- {
- log(L_WARN "Received LSA from %I with bad length", n->ip);
- ospf_neigh_sm(n, INM_BADLSREQ);
- break;
- }
+ /* LSA header in network order */
+ lsa_n = ((void *) pkt) + offset;
+ lsa_len = ntohs(lsa_n->length);
+ offset += lsa_len;
- /* pg 143 (1) */
- u16 chsum = lsa->checksum;
- if (chsum != lsasum_check(lsa, NULL))
- {
- log(L_WARN "Received bad lsa checksum from %I: %x %x", n->ip, chsum, lsa->checksum);
- continue;
- }
+ if (offset > plen)
+ DROP("too short", plen);
-#ifdef OSPFv2
- /* pg 143 (2) */
- if ((lsa->type == 0) || (lsa->type == 6) || (lsa->type > LSA_T_NSSA))
- {
- log(L_WARN "Unknown LSA type from %I", n->ip);
- continue;
- }
+ if (((lsa_len % 4) != 0) || (lsa_len <= sizeof(struct ospf_lsa_header)))
+ DROP("invalid LSA length", lsa_len);
- /* pg 143 (3) */
- if ((lsa->type == LSA_T_EXT) && !oa_is_ext(ifa->oa))
- {
- log(L_WARN "Received External LSA in stub area from %I", n->ip);
- continue;
- }
-#else /* OSPFv3 */
- u16 scope = ntoht(lsa->type) & LSA_SCOPE_MASK;
+ /* LSA header in host order */
+ lsa_ntoh_hdr(lsa_n, &lsa);
+ lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
- /* 4.5.1 (2) */
- if ((scope == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa))
- {
- log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip);
- continue;
- }
+ DBG("Update Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n",
+ lsa_type, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum);
- /* 4.5.1 (3) */
- if (scope == LSA_SCOPE_RES)
- {
- log(L_WARN "Received LSA with invalid scope from %I", n->ip);
- continue;
- }
-#endif
+ /* RFC 2328 13. (1) - validate LSA checksum */
+ if (lsa_n->checksum != lsasum_check(lsa_n, NULL))
+ SKIP("invalid checksum");
+
+ /* RFC 2328 13. (2) */
+ if (!lsa_type)
+ SKIP("unknown type");
+
+ /* RFC 5340 4.5.1 (2) and RFC 2328 13. (3) */
+ if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
+ SKIP("AS scope in stub area");
- ntohlsah(lsa, &lsatmp);
+ /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
+ if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
+ SKIP("rt-summary-LSA in stub area");
- DBG("Update Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n",
- lsatmp.type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum);
+ /* RFC 5340 4.5.1 (3) */
+ if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
+ SKIP("invalid scope");
- /* FIXME domain should be link id for unknown LSA types with zero Ubit */
- u32 domain = ospf_lsa_domain(lsatmp.type, ifa);
- lsadb = ospf_hash_find_header(po->gr, domain, &lsatmp);
+ /* Find local copy of LSA in link state database */
+ en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
#ifdef LOCAL_DEBUG
- if (lsadb)
- DBG("I have Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n",
- lsadb->lsa.type, lsadb->lsa.id, lsadb->lsa.rt,
- lsadb->lsa.sn, lsadb->lsa.age, lsadb->lsa.checksum);
+ if (en)
+ DBG("I have Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n",
+ en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age, en->lsa.checksum);
#endif
- /* pg 143 (4) */
- if ((lsatmp.age == LSA_MAXAGE) && (lsadb == NULL) && can_flush_lsa(po))
+ /* 13. (4) - ignore maxage LSA if i have no local copy */
+ if ((lsa.age == LSA_MAXAGE) && !en && (p->padj == 0))
{
- ospf_lsack_enqueue(n, lsa, ACKL_DIRECT);
+ /* 13.5. - schedule ACKs (tbl 19, case 5) */
+ ospf_enqueue_lsack(n, lsa_n, ACKL_DIRECT);
continue;
}
- /* pg 144 (5) */
- if ((lsadb == NULL) || (lsa_comp(&lsatmp, &lsadb->lsa) == CMP_NEWER))
+ /* 13. (5) - received LSA is newer (or no local copy) */
+ if (!en || (lsa_comp(&lsa, &en->lsa) == CMP_NEWER))
{
- struct ospf_iface *ift = NULL;
- int self = (lsatmp.rt == po->router_id);
-
- DBG("PG143(5): Received LSA is newer\n");
-
-#ifdef OSPFv2
- /* 13.4 - check self-originated LSAs of NET type */
- if ((!self) && (lsatmp.type == LSA_T_NET))
- {
- struct ospf_iface *nifa;
- WALK_LIST(nifa, po->iface_list)
- {
- if (!nifa->iface)
- continue;
- if (ipa_equal(nifa->addr->ip, ipa_from_u32(lsatmp.id)))
- {
- self = 1;
- break;
- }
- }
- }
-#endif
-
- /* pg 145 (5f) - premature aging of self originated lsa */
- if (self)
+ /* 13. (5a) - enforce minimum time between updates for received LSAs */
+ /* We also use this to ratelimit reactions to received self-originated LSAs */
+ if (en && ((now - en->inst_time) < MINLSARRIVAL))
{
- if ((lsatmp.age == LSA_MAXAGE) && (lsatmp.sn == LSA_MAXSEQNO))
- {
- ospf_lsack_enqueue(n, lsa, ACKL_DIRECT);
- continue;
- }
-
- OSPF_TRACE(D_EVENTS, "Received old self-originated LSA (Type: %04x, Id: %R, Rt: %R)",
- lsatmp.type, lsatmp.id, lsatmp.rt);
-
- if (lsadb)
- {
- OSPF_TRACE(D_EVENTS, "Reflooding new self-originated LSA with newer sequence number");
- lsadb->lsa.sn = lsatmp.sn + 1;
- lsadb->lsa.age = 0;
- lsadb->inst_t = now;
- lsadb->ini_age = 0;
- lsasum_calculate(&lsadb->lsa, lsadb->lsa_body);
- ospf_lsupd_flood(po, NULL, NULL, &lsadb->lsa, domain, 1);
- }
- else
- {
- OSPF_TRACE(D_EVENTS, "Premature aging it");
- lsatmp.age = LSA_MAXAGE;
- lsatmp.sn = LSA_MAXSEQNO;
- lsa->age = htons(LSA_MAXAGE);
- lsa->sn = htonl(LSA_MAXSEQNO);
- lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */
- lsatmp.checksum = ntohs(lsa->checksum);
- ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0);
- }
+ OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival");
continue;
}
- /* pg 144 (5a) */
- if (lsadb && ((now - lsadb->inst_t) <= MINLSARRIVAL)) /* FIXME: test for flooding? */
- {
- OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MINLSARRIVAL");
- sendreq = 0;
- continue;
- }
+ /* Copy and validate LSA body */
+ int blen = lsa.length - sizeof(struct ospf_lsa_header);
+ void *body = mb_alloc(p->p.pool, blen);
+ lsa_ntoh_body(lsa_n + 1, body, blen);
- /* Remove old from all ret lists */
- /* pg 144 (5c) */
- /* Must be done before (5b), otherwise it also removes the new entries from (5b) */
- if (lsadb)
- WALK_LIST(ift, po->iface_list)
- WALK_LIST(ntmp, ift->neigh_list)
+ if (lsa_validate(&lsa, lsa_type, ospf_is_v2(p), body) == 0)
{
- struct top_hash_entry *en;
- if (ntmp->state > NEIGHBOR_EXSTART)
- if ((en = ospf_hash_find_header(ntmp->lsrth, domain, &lsadb->lsa)) != NULL)
- {
- s_rem_node(SNODE en);
- ospf_hash_delete(ntmp->lsrth, en);
- }
+ mb_free(body);
+ SKIP("invalid body");
}
- /* pg 144 (5b) */
- if (ospf_lsupd_flood(po, n, lsa, &lsatmp, domain, 1) == 0)
+ /* 13. (5f) - handle self-originated LSAs, see also 13.4. */
+ if ((lsa.rt == p->router_id) ||
+ (ospf_is_v2(p) && (lsa_type == LSA_T_NET) && ospf_addr_is_local(p, ifa->oa, ipa_from_u32(lsa.id))))
{
- DBG("Wasn't flooded back\n"); /* ps 144(5e), pg 153 */
- if (ifa->state == OSPF_IS_BACKUP)
- {
- if (ifa->drid == n->rid)
- ospf_lsack_enqueue(n, lsa, ACKL_DELAY);
- }
- else
- ospf_lsack_enqueue(n, lsa, ACKL_DELAY);
+ OSPF_TRACE(D_EVENTS, "Received unexpected self-originated LSA");
+ ospf_advance_lsa(p, en, &lsa, lsa_type, lsa_domain, body);
+ continue;
}
- if ((lsatmp.age == LSA_MAXAGE) && (lsatmp.sn == LSA_MAXSEQNO)
- && lsadb && can_flush_lsa(po))
- {
- flush_lsa(lsadb, po);
- schedule_rtcalc(po);
- continue;
- } /* FIXME lsack? */
+ /* 13. (5c) - remove old LSA from all retransmission lists
+ *
+ * We only need to remove it from the retransmission list of the neighbor
+ * that send us the new LSA. The old LSA is automatically replaced in
+ * retransmission lists by the new LSA.
+ */
+ if (en)
+ ospf_lsa_lsrt_down(en, n);
+
+#if 0
+ /*
+ * Old code for removing LSA from all retransmission lists. Must be done
+ * before (5b), otherwise it also removes the new entries from (5b).
+ */
+ struct ospf_iface *ifi;
+ struct ospf_neighbor *ni;
+
+ WALK_LIST(ifi, p->iface_list)
+ WALK_LIST(ni, ifi->neigh_list)
+ if (ni->state > NEIGHBOR_EXSTART)
+ ospf_lsa_lsrt_down(en, ni);
+#endif
- /* pg 144 (5d) */
- void *body = mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header));
- ntohlsab(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header));
+ /* 13. (5d) - install new LSA into database */
+ en = ospf_install_lsa(p, &lsa, lsa_type, lsa_domain, body);
- /* We will do validation check after flooding and
- acknowledging given LSA to minimize problems
- when communicating with non-validating peer */
- if (lsa_validate(&lsatmp, body) == 0)
- {
- log(L_WARN "Received invalid LSA from %I", n->ip);
- mb_free(body);
- continue;
- }
+ /* RFC 5340 4.4.3 Events 6+7 - new Link LSA received */
+ if (lsa_type == LSA_T_LINK)
+ ospf_notify_net_lsa(ifa);
- lsadb = lsa_install_new(po, &lsatmp, domain, body);
- DBG("New LSA installed in DB\n");
+ /* 13. (5b) - flood new LSA */
+ int flood_back = ospf_flood_lsa(p, en, n);
-#ifdef OSPFv3
- /* Events 6,7 from RFC5340 4.4.3. */
- if ((lsatmp.type == LSA_T_LINK) &&
- (ifa->state == OSPF_IS_DR))
- schedule_net_lsa(ifa);
-#endif
+ /* 13.5. - schedule ACKs (tbl 19, cases 1+2) */
+ if (! flood_back)
+ if ((ifa->state != OSPF_IS_BACKUP) || (n->rid == ifa->drid))
+ ospf_enqueue_lsack(n, lsa_n, ACKL_DELAY);
+
+ /* FIXME: remove LSA entry if it is LSA_MAXAGE and it is possible? */
continue;
}
- /* FIXME pg145 (6) */
+ /* 13. (6) - received LSA is in Link state request list (but not newer) */
+ if (ospf_hash_find_entry(n->lsrqh, en) != NULL)
+ DROP1("error in LSA database exchange");
- /* pg145 (7) */
- if (lsa_comp(&lsatmp, &lsadb->lsa) == CMP_SAME)
+ /* 13. (7) - received LSA is same */
+ if (lsa_comp(&lsa, &en->lsa) == CMP_SAME)
{
- struct top_hash_entry *en;
- DBG("PG145(7) Got the same LSA\n");
- if ((en = ospf_hash_find_header(n->lsrth, lsadb->domain, &lsadb->lsa)) != NULL)
- {
- /* pg145 (7a) */
- s_rem_node(SNODE en);
- ospf_hash_delete(n->lsrth, en);
+ /* Duplicate LSA, treat as implicit ACK */
+ int implicit_ack = ospf_lsa_lsrt_down(en, n);
- if (ifa->state == OSPF_IS_BACKUP)
- {
- if (n->rid == ifa->drid)
- ospf_lsack_enqueue(n, lsa, ACKL_DELAY);
- }
- }
- else
+ /* 13.5. - schedule ACKs (tbl 19, cases 3+4) */
+ if (implicit_ack)
{
- /* pg145 (7b) */
- ospf_lsack_enqueue(n, lsa, ACKL_DIRECT);
+ if ((ifa->state == OSPF_IS_BACKUP) && (n->rid == ifa->drid))
+ ospf_enqueue_lsack(n, lsa_n, ACKL_DELAY);
}
- sendreq = 0;
+ else
+ ospf_enqueue_lsack(n, lsa_n, ACKL_DIRECT);
+
continue;
}
- /* pg145 (8) */
- if ((lsadb->lsa.age == LSA_MAXAGE) && (lsadb->lsa.sn == LSA_MAXSEQNO))
+ /* 13. (8) - received LSA is older */
{
+ /* Seqnum is wrapping, wait until it is flushed */
+ if ((en->lsa.age == LSA_MAXAGE) && (en->lsa.sn == LSA_MAXSEQNO))
+ continue;
+
+ /* Send newer local copy back to neighbor */
+ /* FIXME - check for MinLSArrival ? */
+ ospf_send_lsupd(p, &en, 1, n);
+
continue;
}
- {
- list l;
- struct l_lsr_head ll;
- init_list(&l);
- ll.lsh.id = lsadb->lsa.id;
- ll.lsh.rt = lsadb->lsa.rt;
- ll.lsh.type = lsadb->lsa.type;
- add_tail(&l, NODE & ll);
- ospf_lsupd_send_list(n, &l);
- }
+ skip:
+ LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in LSUPD", lsa_type, lsa.id, lsa.rt);
+ LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);
}
- /* Send direct LSAs */
- ospf_lsack_send(n, ACKL_DIRECT);
+ /* Send direct LSACKs */
+ ospf_send_lsack(p, n, ACKL_DIRECT);
- if (sendreq && (n->state == NEIGHBOR_LOADING))
+ /* Send enqueued LSAs immediately, do not wait for flood_event */
+ if (ev_active(p->flood_event))
{
- ospf_lsreq_send(n); /* Ask for another part of neighbor's database */
+ ev_postpone(p->flood_event);
+ ospf_flood_event(p);
}
-}
-void
-ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en)
-{
- struct ospf_lsa_header *lsa = &en->lsa;
- struct proto *p = &po->proto;
-
- lsa->age = LSA_MAXAGE;
- lsa->sn = LSA_MAXSEQNO;
- lsasum_calculate(lsa, en->lsa_body);
- OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!");
- OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R", lsa->type, lsa->id, lsa->rt);
- ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0);
+ /*
+ * During loading, we should ask for another batch of LSAs. This is only
+ * vaguely mentioned in RFC 2328. We send a new LSREQ if all requests sent in
+ * the last packet were already answered and/or removed from the LS request
+ * list and therefore lsrqi is pointing to the first node of the list.
+ */
+ if (!EMPTY_SLIST(n->lsrql) && (n->lsrqi == SHEAD(n->lsrql)))
+ {
+ ospf_send_lsreq(p, n);
+ tm_start(n->lsrq_timer, n->ifa->rxmtint);
+ }
+
+ return;
+
+drop:
+ LOG_PKT("Bad LSUPD packet from nbr %R on %s - %s (%u)",
+ n->rid, ifa->ifname, err_dsc, err_val);
+
+ /* Malformed LSUPD - there is no defined error event, we abuse BadLSReq */
+ ospf_neigh_sm(n, INM_BADLSREQ);
+ return;
}
diff --git a/proto/ospf/lsupd.h b/proto/ospf/lsupd.h
deleted file mode 100644
index 8bacfe65..00000000
--- a/proto/ospf/lsupd.h
+++ /dev/null
@@ -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_ */
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index faaaf232..c5d44dec 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -1,67 +1,84 @@
/*
* 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.
*/
#include "ospf.h"
-char *ospf_ns[] = { " down",
- " attempt",
- " init",
- " 2way",
- " exstart",
- "exchange",
- " loading",
- " full"
+
+const char *ospf_ns_names[] = {
+ "Down", "Attempt", "Init", "2-Way", "ExStart", "Exchange", "Loading", "Full"
};
-const char *ospf_inm[] =
- { "hello received", "neighbor start", "2-way received",
- "negotiation done", "exstart done", "bad ls request", "load done",
- "adjacency ok?", "sequence mismatch", "1-way received", "kill neighbor",
- "inactivity timer", "line down"
+const char *ospf_inm_names[] = {
+ "HelloReceived", "Start", "2-WayReceived", "NegotiationDone", "ExchangeDone",
+ "BadLSReq", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "1-WayReceived",
+ "KillNbr", "InactivityTimer", "LLDown"
};
-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);
+
+static int can_do_adj(struct ospf_neighbor *n);
+static void inactivity_timer_hook(timer * timer);
+static void dbdes_timer_hook(timer *t);
+static void lsrq_timer_hook(timer *t);
+static void lsrt_timer_hook(timer *t);
+static void ackd_timer_hook(timer *t);
+
static void
-init_lists(struct ospf_neighbor *n)
+init_lists(struct ospf_proto *p, struct ospf_neighbor *n)
{
s_init_list(&(n->lsrql));
- n->lsrqh = ospf_top_new(n->pool);
- s_init(&(n->lsrqi), &(n->lsrql));
+ n->lsrqi = SHEAD(n->lsrql);
+ n->lsrqh = ospf_top_new(p, n->pool);
s_init_list(&(n->lsrtl));
- n->lsrth = ospf_top_new(n->pool);
- s_init(&(n->lsrti), &(n->lsrtl));
+ n->lsrth = ospf_top_new(p, n->pool);
+}
+
+static void
+release_lsrtl(struct ospf_proto *p, struct ospf_neighbor *n)
+{
+ struct top_hash_entry *ret, *en;
+
+ WALK_SLIST(ret, n->lsrtl)
+ {
+ en = ospf_hash_find_entry(p->gr, ret);
+ if (en)
+ en->ret_count--;
+ }
}
/* Resets LSA request and retransmit lists.
- * We do not reset DB summary list iterator here,
+ * We do not reset DB summary list iterator here,
* it is reset during entering EXCHANGE state.
*/
static void
-reset_lists(struct ospf_neighbor *n)
+reset_lists(struct ospf_proto *p, struct ospf_neighbor *n)
{
+ release_lsrtl(p, n);
ospf_top_free(n->lsrqh);
ospf_top_free(n->lsrth);
- init_lists(n);
+ ospf_reset_lsack_queue(n);
+
+ tm_stop(n->dbdes_timer);
+ tm_stop(n->lsrq_timer);
+ tm_stop(n->lsrt_timer);
+ tm_stop(n->ackd_timer);
+
+ init_lists(p, 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;
@@ -71,103 +88,281 @@ ospf_neighbor_new(struct ospf_iface *ifa)
n->csn = 0;
n->state = NEIGHBOR_DOWN;
- init_lists(n);
- s_init(&(n->dbsi), &(po->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);
-
- n->rxmt_timer = tm_new(pool);
- n->rxmt_timer->data = n;
- n->rxmt_timer->randomize = 0;
- 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);
-
- n->ackd_timer = tm_new(pool);
- n->ackd_timer->data = n;
- n->ackd_timer->randomize = 0;
- n->ackd_timer->hook = ackd_timer_hook;
- n->ackd_timer->recurrent = ifa->rxmtint / 2;
+ init_lists(p, n);
+ s_init(&(n->dbsi), &(p->lsal));
+
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);
+
+ n->inactim = tm_new_set(pool, inactivity_timer_hook, n, 0, 0);
+ n->dbdes_timer = tm_new_set(pool, dbdes_timer_hook, n, 0, ifa->rxmtint);
+ n->lsrq_timer = tm_new_set(pool, lsrq_timer_hook, n, 0, ifa->rxmtint);
+ n->lsrt_timer = tm_new_set(pool, lsrt_timer_hook, n, 0, ifa->rxmtint);
+ n->ackd_timer = tm_new_set(pool, ackd_timer_hook, n, 0, ifa->rxmtint / 2);
return (n);
}
+static void
+ospf_neigh_down(struct ospf_neighbor *n)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct ospf_proto *p = ifa->oa->po;
+
+ if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
+ {
+ struct nbma_node *nn = find_nbma_node(ifa, n->ip);
+ if (nn)
+ nn->found = 0;
+ }
+
+ s_get(&(n->dbsi));
+ release_lsrtl(p, n);
+ rem_node(NODE n);
+ rfree(n->pool);
+
+ OSPF_TRACE(D_EVENTS, "Neighbor %R on %s removed", n->rid, ifa->ifname);
+}
+
/**
- * neigh_chstate - handles changes related to new or lod state of neighbor
+ * ospf_neigh_chstate - handles changes related to new or lod state of neighbor
* @n: OSPF neighbor
* @state: new state
*
* 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)
+ospf_neigh_chstate(struct ospf_neighbor *n, u8 state)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct ospf_proto *p = ifa->oa->po;
+ u8 old_state = n->state;
+ int old_fadj = ifa->fadj;
+
+ if (state == old_state)
+ return;
+
+ OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed state from %s to %s",
+ n->rid, ifa->ifname, ospf_ns_names[old_state], ospf_ns_names[state]);
+
+ n->state = state;
+
+ /* 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)
+ {
+ /* RFC 2328 12.4 Event 4 - neighbor enters/leaves Full state */
+ ospf_notify_rt_lsa(ifa->oa);
+ ospf_notify_net_lsa(ifa);
+
+ /* RFC 2328 12.4 Event 8 - vlink state change */
+ if (ifa->type == OSPF_IT_VLINK)
+ ospf_notify_rt_lsa(ifa->voa);
+ }
+
+ if (state == NEIGHBOR_EXSTART)
+ {
+ /* First time adjacency */
+ if (n->adj == 0)
+ n->dds = random_u32();
+
+ n->dds++;
+ n->myimms = DBDES_IMMS;
+
+ tm_start(n->dbdes_timer, 0);
+ tm_start(n->ackd_timer, ifa->rxmtint / 2);
+ }
+
+ if (state > NEIGHBOR_EXSTART)
+ n->myimms &= ~DBDES_I;
+
+ /* Generate NeighborChange event if needed, see RFC 2328 9.2 */
+ 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);
+}
+
+/**
+ * ospf_neigh_sm - ospf neighbor state machine
+ * @n: neighor
+ * @event: actual event
+ *
+ * This part implements the neighbor state machine as described in 10.3 of
+ * RFC 2328. The only difference is that state %NEIGHBOR_ATTEMPT is not
+ * used. We discover neighbors on nonbroadcast networks in the
+ * same way as on broadcast networks. The only difference is in
+ * sending hello packets. These are sent to IPs listed in
+ * @ospf_iface->nbma_list .
+ */
+void
+ospf_neigh_sm(struct ospf_neighbor *n, int event)
{
- u8 oldstate;
+ struct ospf_proto *p = n->ifa->oa->po;
- oldstate = n->state;
+ DBG("Neighbor state machine for %R on %s, event %s\n",
+ n->rid, n->ifa->ifname, ospf_inm_names[event]);
- if (oldstate != state)
+ switch (event)
{
- struct ospf_iface *ifa = n->ifa;
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
+ case INM_START:
+ ospf_neigh_chstate(n, NEIGHBOR_ATTEMPT);
+ /* NBMA are used different way */
+ break;
+
+ case INM_HELLOREC:
+ if (n->state < NEIGHBOR_INIT)
+ ospf_neigh_chstate(n, NEIGHBOR_INIT);
- n->state = state;
+ /* Restart inactivity timer */
+ tm_start(n->inactim, n->ifa->deadint);
+ break;
+
+ case INM_2WAYREC:
+ if (n->state < NEIGHBOR_2WAY)
+ ospf_neigh_chstate(n, NEIGHBOR_2WAY);
+ if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
+ ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
+ break;
+
+ case INM_NEGDONE:
+ if (n->state == NEIGHBOR_EXSTART)
+ {
+ ospf_neigh_chstate(n, NEIGHBOR_EXCHANGE);
+
+ /* Reset DB summary list iterator */
+ s_get(&(n->dbsi));
+ s_init(&(n->dbsi), &p->lsal);
+
+ /* Add MaxAge LSA entries to retransmission list */
+ ospf_add_flushed_to_lsrt(p, n);
+ }
+ else
+ bug("NEGDONE and I'm not in EXSTART?");
+ break;
- OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from \"%s\" to \"%s\".",
- n->ip, ospf_ns[oldstate], ospf_ns[state]);
+ case INM_EXDONE:
+ if (!EMPTY_SLIST(n->lsrql))
+ ospf_neigh_chstate(n, NEIGHBOR_LOADING);
+ else
+ ospf_neigh_chstate(n, NEIGHBOR_FULL);
+ break;
- 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);
+ case INM_LOADDONE:
+ ospf_neigh_chstate(n, NEIGHBOR_FULL);
+ break;
- if (oldstate == NEIGHBOR_FULL) /* Decrease number of adjacencies */
+ case INM_ADJOK:
+ /* Can In build adjacency? */
+ if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
+ {
+ ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
+ }
+ else if ((n->state >= NEIGHBOR_EXSTART) && !can_do_adj(n))
{
- ifa->fadj--;
- schedule_rt_lsa(ifa->oa);
- if (ifa->type == OSPF_IT_VLINK) schedule_rt_lsa(ifa->voa);
- schedule_net_lsa(ifa);
+ reset_lists(p, n);
+ ospf_neigh_chstate(n, NEIGHBOR_2WAY);
}
+ break;
- if (state == NEIGHBOR_FULL) /* Increase number of adjacencies */
+ case INM_SEQMIS:
+ case INM_BADLSREQ:
+ if (n->state >= NEIGHBOR_EXCHANGE)
{
- ifa->fadj++;
- schedule_rt_lsa(ifa->oa);
- if (ifa->type == OSPF_IT_VLINK) schedule_rt_lsa(ifa->voa);
- schedule_net_lsa(ifa);
+ reset_lists(p, n);
+ ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
}
- if (state == NEIGHBOR_EXSTART)
+ break;
+
+ case INM_KILLNBR:
+ case INM_LLDOWN:
+ case INM_INACTTIM:
+ /* No need for reset_lists() */
+ ospf_neigh_chstate(n, NEIGHBOR_DOWN);
+ ospf_neigh_down(n);
+ break;
+
+ case INM_1WAYREC:
+ reset_lists(p, n);
+ ospf_neigh_chstate(n, NEIGHBOR_INIT);
+ break;
+
+ default:
+ bug("%s: INM - Unknown event?", p->p.name);
+ break;
+ }
+}
+
+static int
+can_do_adj(struct ospf_neighbor *n)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct ospf_proto *p = ifa->oa->po;
+ int i = 0;
+
+ switch (ifa->type)
+ {
+ case OSPF_IT_PTP:
+ case OSPF_IT_PTMP:
+ case OSPF_IT_VLINK:
+ i = 1;
+ break;
+ case OSPF_IT_BCAST:
+ case OSPF_IT_NBMA:
+ switch (ifa->state)
{
- 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;
+ case OSPF_IS_DOWN:
+ case OSPF_IS_LOOP:
+ 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->p.name, ifa->ifname);
+ break;
+ case OSPF_IS_DROTHER:
+ if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
+ && (n->state >= NEIGHBOR_2WAY))
+ i = 1;
+ break;
+ case OSPF_IS_PTP:
+ case OSPF_IS_BACKUP:
+ case OSPF_IS_DR:
+ if (n->state >= NEIGHBOR_2WAY)
+ i = 1;
+ break;
+ default:
+ bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname);
+ break;
}
- if (state > NEIGHBOR_EXSTART)
- n->myimms.bit.i = 0;
+ break;
+ default:
+ bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname);
+ break;
}
+ DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i);
+ return 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 +371,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 +416,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 +424,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 */
@@ -261,189 +448,23 @@ electdr(list nl)
return (n);
}
-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;
-
- switch (ifa->type)
- {
- case OSPF_IT_PTP:
- case OSPF_IT_PTMP:
- case OSPF_IT_VLINK:
- i = 1;
- break;
- case OSPF_IT_BCAST:
- case OSPF_IT_NBMA:
- switch (ifa->state)
- {
- case OSPF_IS_DOWN:
- case OSPF_IS_LOOP:
- bug("%s: Iface %s in down state?", p->name, ifa->ifname);
- break;
- case OSPF_IS_WAITING:
- DBG("%s: Neighbor? on iface %s\n", p->name, ifa->ifname);
- break;
- case OSPF_IS_DROTHER:
- if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
- && (n->state >= NEIGHBOR_2WAY))
- i = 1;
- break;
- case OSPF_IS_PTP:
- case OSPF_IS_BACKUP:
- case OSPF_IS_DR:
- if (n->state >= NEIGHBOR_2WAY)
- i = 1;
- break;
- default:
- bug("%s: Iface %s in unknown state?", p->name, ifa->ifname);
- break;
- }
- break;
- default:
- bug("%s: Iface %s is unknown type?", p->name, ifa->ifname);
- break;
- }
- DBG("%s: Iface %s can_do_adj=%d\n", p->name, ifa->ifname, i);
- return i;
-}
-
-/**
- * ospf_neigh_sm - ospf neighbor state machine
- * @n: neighor
- * @event: actual event
- *
- * This part implements the neighbor state machine as described in 10.3 of
- * RFC 2328. The only difference is that state %NEIGHBOR_ATTEMPT is not
- * used. We discover neighbors on nonbroadcast networks in the
- * same way as on broadcast networks. The only difference is in
- * sending hello packets. These are sent to IPs listed in
- * @ospf_iface->nbma_list .
- */
-void
-ospf_neigh_sm(struct ospf_neighbor *n, int event)
-{
- struct proto_ospf *po = n->ifa->oa->po;
- struct proto *p = &po->proto;
-
- DBG("Neighbor state machine for neighbor %I, event '%s'\n", n->ip,
- ospf_inm[event]);
-
- switch (event)
- {
- case INM_START:
- neigh_chstate(n, NEIGHBOR_ATTEMPT);
- /* NBMA are used different way */
- break;
- case INM_HELLOREC:
- switch (n->state)
- {
- case NEIGHBOR_ATTEMPT:
- case NEIGHBOR_DOWN:
- neigh_chstate(n, NEIGHBOR_INIT);
- default:
- tm_start(n->inactim, n->ifa->deadint); /* Restart inactivity timer */
- break;
- }
- 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)
- {
- neigh_chstate(n, NEIGHBOR_EXCHANGE);
-
- /* Reset DB summary list iterator */
- s_get(&(n->dbsi));
- s_init(&(n->dbsi), &po->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);
- }
- }
- 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)
- {
- case NEIGHBOR_2WAY:
- /* Can In build adjacency? */
- if (can_do_adj(n))
- {
- neigh_chstate(n, NEIGHBOR_EXSTART);
- }
- break;
- default:
- if (n->state >= NEIGHBOR_EXSTART)
- if (!can_do_adj(n))
- {
- reset_lists(n);
- neigh_chstate(n, NEIGHBOR_2WAY);
- }
- break;
- }
- break;
- case INM_SEQMIS:
- case INM_BADLSREQ:
- if (n->state >= NEIGHBOR_EXCHANGE)
- {
- reset_lists(n);
- 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);
- 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.
- * Structure describing me is added to this list so every electing router
- * has the same list. Backup Designated Router is elected before Designated
- * Router. This process is described in 9.4 of RFC 2328.
+ * Structure describing me is added to this list so every electing router has
+ * the same list. Backup Designated Router is elected before Designated
+ * Router. This process is described in 9.4 of RFC 2328. The function is
+ * supposed to be called only from ospf_iface_sm() as a part of the interface
+ * state machine.
*/
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 +473,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 +491,48 @@ 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)
+ /* We are part of the interface state machine */
+ 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);
- }
-
- rem_node(NODE & me);
+ ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
- 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 *
@@ -547,51 +555,28 @@ find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip)
return NULL;
}
-/* Neighbor is inactive for a long time. Remove it. */
static void
-neighbor_timer_hook(timer * timer)
+inactivity_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;
-
- OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I.",
- ifa->ifname, n->ip);
- ospf_neigh_remove(n);
-}
-
-void
-ospf_neigh_remove(struct ospf_neighbor *n)
-{
- struct ospf_iface *ifa = n->ifa;
- struct proto *p = &ifa->oa->po->proto;
-
- if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
- {
- struct nbma_node *nn = find_nbma_node(ifa, n->ip);
- if (nn)
- nn->found = 0;
- }
+ struct ospf_proto *p = n->ifa->oa->po;
- s_get(&(n->dbsi));
- neigh_chstate(n, NEIGHBOR_DOWN);
- rem_node(NODE n);
- rfree(n->pool);
- OSPF_TRACE(D_EVENTS, "Deleting neigbor.");
+ OSPF_TRACE(D_EVENTS, "Inactivity timer expired for nbr %R on %s",
+ n->rid, n->ifa->ifname);
+ ospf_neigh_sm(n, INM_INACTTIM);
}
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_neigh_remove(n);
+ OSPF_TRACE(D_EVENTS, "BFD session down for nbr %R on %s",
+ n->rid, n->ifa->ifname);
+ ospf_neigh_sm(n, INM_INACTTIM);
}
}
@@ -610,11 +595,60 @@ ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd)
}
+static void
+dbdes_timer_hook(timer *t)
+{
+ struct ospf_neighbor *n = t->data;
+ struct ospf_proto *p = n->ifa->oa->po;
+
+ // OSPF_TRACE(D_EVENTS, "DBDES timer expired for nbr %R on %s", n->rid, n->ifa->ifname);
+
+ if (n->state == NEIGHBOR_EXSTART)
+ ospf_send_dbdes(p, n);
+
+ if ((n->state == NEIGHBOR_EXCHANGE) && (n->myimms & DBDES_MS))
+ ospf_rxmt_dbdes(p, n);
+}
+
+static void
+lsrq_timer_hook(timer *t)
+{
+ struct ospf_neighbor *n = t->data;
+ struct ospf_proto *p = n->ifa->oa->po;
+
+ // OSPF_TRACE(D_EVENTS, "LSRQ timer expired for nbr %R on %s", n->rid, n->ifa->ifname);
+
+ if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrql))
+ ospf_send_lsreq(p, n);
+}
+
+static void
+lsrt_timer_hook(timer *t)
+{
+ struct ospf_neighbor *n = t->data;
+ struct ospf_proto *p = n->ifa->oa->po;
+
+ // OSPF_TRACE(D_EVENTS, "LSRT timer expired for nbr %R on %s", n->rid, n->ifa->ifname);
+
+ if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrtl))
+ ospf_rxmt_lsupd(p, n);
+}
+
+static void
+ackd_timer_hook(timer *t)
+{
+ struct ospf_neighbor *n = t->data;
+ struct ospf_proto *p = n->ifa->oa->po;
+
+ ospf_send_lsack(p, n, ACKL_DELAY);
+}
+
+
void
ospf_sh_neigh_info(struct ospf_neighbor *n)
{
struct ospf_iface *ifa = n->ifa;
- char *pos = "other";
+ char *pos = "PtP ";
char etime[6];
int exp, sec, min;
@@ -630,74 +664,16 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
bsprintf(etime, "%02u:%02u", min, sec);
}
- if (n->rid == ifa->drid)
- pos = "dr ";
- else if (n->rid == ifa->bdrid)
- pos = "bdr ";
- else if ((n->ifa->type == OSPF_IT_PTP) || (n->ifa->type == OSPF_IT_PTMP) ||
- (n->ifa->type == OSPF_IT_VLINK))
- pos = "ptp ";
-
- cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority,
- ospf_ns[n->state], pos, etime, ifa->ifname, n->ip);
-}
-
-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;
-
- DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n",
- p->name, n->ifa->ifname, n->ip);
-
- if(n->state < NEIGHBOR_EXSTART) return;
-
- if (n->state == NEIGHBOR_EXSTART)
- {
- ospf_dbdes_send(n, 1);
- return;
- }
-
- if ((n->state == NEIGHBOR_EXCHANGE) && n->myimms.bit.ms) /* I'm master */
- ospf_dbdes_send(n, 0);
-
-
- if (n->state < NEIGHBOR_FULL)
- ospf_lsreq_send(n); /* EXCHANGE or LOADING */
- else
+ if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
{
- 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);
- }
+ if (n->rid == ifa->drid)
+ pos = "DR ";
+ else if (n->rid == ifa->bdrid)
+ pos = "BDR ";
+ else
+ pos = "Other";
}
-}
-static void
-ackd_timer_hook(timer * t)
-{
- struct ospf_neighbor *n = t->data;
- ospf_lsack_send(n, ACKL_DELAY);
+ cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority,
+ ospf_ns_names[n->state], pos, etime, ifa->ifname, n->ip);
}
diff --git a/proto/ospf/neighbor.h b/proto/ospf/neighbor.h
deleted file mode 100644
index e674927d..00000000
--- a/proto/ospf/neighbor.h
+++ /dev/null
@@ -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_ */
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 6756ff49..dab7aab8 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -2,109 +2,107 @@
* 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.
*/
/**
* DOC: Open Shortest Path First (OSPF)
- *
- * The OSPF protocol is quite complicated and its complex implemenation is
- * split to many files. In |ospf.c|, you will find mainly the interface
- * for communication with the core (e.g., reconfiguration hooks, shutdown
- * and initialisation and so on). In |packet.c|, you will find various
- * functions for sending and receiving generic OSPF packets. There are
- * also routines for authentication and checksumming. File |iface.c| contains
- * the interface state machine and functions for allocation and deallocation of OSPF's
- * interface data structures. Source |neighbor.c| includes the neighbor state
- * machine and functions for election of Designated Router and Backup
- * Designated router. In |hello.c|, there are routines for sending
- * and receiving of hello packets as well as functions for maintaining
- * wait times and the inactivity timer. Files |lsreq.c|, |lsack.c|, |dbdes.c|
- * contain functions for sending and receiving of link-state requests,
- * link-state acknowledgements and database descriptions respectively.
- * In |lsupd.c|, there are functions for sending and receiving
- * of link-state updates and also the flooding algorithm. Source |topology.c| is
- * a place where routines for searching LSAs in the link-state database,
- * adding and deleting them reside, there also are functions for originating
- * of various types of LSAs (router LSA, net LSA, external LSA). File |rt.c|
- * contains routines for calculating the routing table. |lsalib.c| is a set
- * of various functions for working with the LSAs (endianity conversions,
- * calculation of checksum etc.).
*
- * One instance of the protocol is able to hold LSA databases for
- * multiple OSPF areas, to exchange routing information between
- * multiple neighbors and to calculate the routing tables. The core
- * structure is &proto_ospf to which multiple &ospf_area and
- * &ospf_iface structures are connected. &ospf_area is also connected to
- * &top_hash_graph which is a dynamic hashing structure that
- * describes the link-state database. It allows fast search, addition
- * and deletion. Each LSA is kept in two pieces: header and body. Both of them are
+ * The OSPF protocol is quite complicated and its complex implemenation is split
+ * to many files. In |ospf.c|, you will find mainly the interface for
+ * communication with the core (e.g., reconfiguration hooks, shutdown and
+ * initialisation and so on). File |iface.c| contains the interface state
+ * machine and functions for allocation and deallocation of OSPF's interface
+ * data structures. Source |neighbor.c| includes the neighbor state machine and
+ * functions for election of Designated Router and Backup Designated router. In
+ * |packet.c|, you will find various functions for sending and receiving generic
+ * OSPF packets. There are also routines for authentication and checksumming.
+ * In |hello.c|, there are routines for sending and receiving of hello packets
+ * as well as functions for maintaining wait times and the inactivity timer.
+ * Files |lsreq.c|, |lsack.c|, |dbdes.c| contain functions for sending and
+ * receiving of link-state requests, link-state acknowledgements and database
+ * descriptions respectively. In |lsupd.c|, there are functions for sending and
+ * receiving of link-state updates and also the flooding algorithm. Source
+ * |topology.c| is a place where routines for searching LSAs in the link-state
+ * database, adding and deleting them reside, there also are functions for
+ * originating of various types of LSAs (router LSA, net LSA, external LSA).
+ * File |rt.c| contains routines for calculating the routing table. |lsalib.c|
+ * is a set of various functions for working with the LSAs (endianity
+ * conversions, calculation of checksum etc.).
+ *
+ * One instance of the protocol is able to hold LSA databases for multiple OSPF
+ * areas, to exchange routing information between multiple neighbors and to
+ * calculate the routing tables. The core structure is &ospf_proto to which
+ * multiple &ospf_area and &ospf_iface structures are connected. &ospf_proto is
+ * also connected to &top_hash_graph which is a dynamic hashing structure that
+ * describes the link-state database. It allows fast search, addition and
+ * deletion. Each LSA is kept in two pieces: header and body. Both of them are
* kept in the endianity of the CPU.
*
- * In OSPFv2 specification, it is implied that there is one IP prefix
- * for each physical network/interface (unless it is an ptp link). But
- * in modern systems, there might be more independent IP prefixes
- * associated with an interface. To handle this situation, we have
- * one &ospf_iface for each active IP prefix (instead for each active
- * iface); This behaves like virtual interface for the purpose of OSPF.
- * If we receive packet, we associate it with a proper virtual interface
- * mainly according to its source address.
+ * In OSPFv2 specification, it is implied that there is one IP prefix for each
+ * physical network/interface (unless it is an ptp link). But in modern systems,
+ * there might be more independent IP prefixes associated with an interface. To
+ * handle this situation, we have one &ospf_iface for each active IP prefix
+ * (instead for each active iface); This behaves like virtual interface for the
+ * purpose of OSPF. If we receive packet, we associate it with a proper virtual
+ * interface mainly according to its source address.
*
- * OSPF keeps one socket per &ospf_iface. This allows us (compared to
- * one socket approach) to evade problems with a limit of multicast
- * groups per socket and with sending multicast packets to appropriate
- * interface in a portable way. The socket is associated with
- * underlying physical iface and should not receive packets received
- * on other ifaces (unfortunately, this is not true on
- * BSD). Generally, one packet can be received by more sockets (for
- * example, if there are more &ospf_iface on one physical iface),
- * therefore we explicitly filter received packets according to
- * src/dst IP address and received iface.
+ * OSPF keeps one socket per &ospf_iface. This allows us (compared to one socket
+ * approach) to evade problems with a limit of multicast groups per socket and
+ * with sending multicast packets to appropriate interface in a portable way.
+ * The socket is associated with underlying physical iface and should not
+ * receive packets received on other ifaces (unfortunately, this is not true on
+ * BSD). Generally, one packet can be received by more sockets (for example, if
+ * there are more &ospf_iface on one physical iface), therefore we explicitly
+ * filter received packets according to src/dst IP address and received iface.
*
- * Vlinks are implemented using particularly degenerate form of
- * &ospf_iface, which has several exceptions: it does not have its
- * iface or socket (it copies these from 'parent' &ospf_iface) and it
- * is present in iface list even when down (it is not freed in
- * ospf_iface_down()).
+ * Vlinks are implemented using particularly degenerate form of &ospf_iface,
+ * which has several exceptions: it does not have its iface or socket (it copies
+ * these from 'parent' &ospf_iface) and it is present in iface list even when
+ * down (it is not freed in ospf_iface_down()).
*
* The heart beat of ospf is ospf_disp(). It is called at regular intervals
- * (&proto_ospf->tick). It is responsible for aging and flushing of LSAs in
- * the database, for routing table calculaction and it call area_disp() of every
- * ospf_area.
- *
- * The function area_disp() is
- * responsible for late originating of router LSA and network LSA
- * and for cleanup before routing table calculation process in
- * the area.
- * To every &ospf_iface, we connect one or more
- * &ospf_neighbor's -- a structure containing many timers and queues
- * for building adjacency and for exchange of routing messages.
+ * (&ospf_proto->tick). It is responsible for aging and flushing of LSAs in the
+ * database, updating topology information in LSAs and for routing table
+ * calculation.
+ *
+ * To every &ospf_iface, we connect one or more &ospf_neighbor's -- a structure
+ * containing many timers and queues for building adjacency and for exchange of
+ * routing messages.
*
- * BIRD's OSPF implementation respects RFC2328 in every detail, but
- * some of internal algorithms do differ. The RFC recommends making a snapshot
- * of the link-state database when a new adjacency is forming and sending
- * the database description packets based on the information in this
- * snapshot. The database can be quite large in some networks, so
- * rather we walk through a &slist structure which allows us to
- * continue even if the actual LSA we were working with is deleted. New
- * LSAs are added at the tail of this &slist.
+ * BIRD's OSPF implementation respects RFC2328 in every detail, but some of
+ * internal algorithms do differ. The RFC recommends making a snapshot of the
+ * link-state database when a new adjacency is forming and sending the database
+ * description packets based on the information in this snapshot. The database
+ * can be quite large in some networks, so rather we walk through a &slist
+ * structure which allows us to continue even if the actual LSA we were working
+ * with is deleted. New LSAs are added at the tail of this &slist.
*
- * We also don't keep a separate OSPF routing table, because the core
- * helps us by being able to recognize when a route is updated
- * to an identical one and it suppresses the update automatically.
- * Due to this, we can flush all the routes we've recalculated and
- * also those we've deleted to the core's routing table and the
- * core will take care of the rest. This simplifies the process
+ * We also do not keep a separate OSPF routing table, because the core helps us
+ * by being able to recognize when a route is updated to an identical one and it
+ * suppresses the update automatically. Due to this, we can flush all the routes
+ * we have recalculated and also those we have deleted to the core's routing
+ * table and the core will take care of the rest. This simplifies the process
* and conserves memory.
+ *
+ * Supported standards:
+ * - RFC 2328 - main OSPFv2 standard
+ * - RFC 5340 - main OSPFv3 standard
+ * - RFC 3101 - OSPFv2 NSSA areas
+ * - RFC 6549 - OSPFv2 multi-instance extensions
+ * - RFC 6987 - OSPF stub router advertisement
*/
#include <stdlib.h>
#include "ospf.h"
-
-static int ospf_reload_routes(struct proto *p);
-static void ospf_rt_notify(struct proto *p, struct rtable *table UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs);
+static int ospf_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool);
+static struct ea_list *ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool);
+static void ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs);
+static int ospf_reload_routes(struct proto *P);
static int ospf_rte_better(struct rte *new, struct rte *old);
static int ospf_rte_same(struct rte *new, struct rte *old);
static void ospf_disp(timer *timer);
@@ -114,83 +112,81 @@ ospf_area_initfib(struct fib_node *fn)
{
struct area_net *an = (struct area_net *) fn;
an->hidden = 0;
- an->active = -1; /* Force to regenerate summary lsa */
- /* ac->oldactive will be rewritten by ospf_rt_spf() */
+ an->active = 0;
}
static void
add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
{
- struct proto_ospf *po = oa->po;
- struct area_net_config *anc;
- struct area_net *an;
+ struct ospf_proto *p = oa->po;
+ struct area_net_config *anc;
+ struct area_net *an;
- fib_init(&oa->net_fib, po->proto.pool, sizeof(struct area_net), 0, ospf_area_initfib);
- fib_init(&oa->enet_fib, po->proto.pool, sizeof(struct area_net), 0, ospf_area_initfib);
+ fib_init(&oa->net_fib, p->p.pool, sizeof(struct area_net), 0, ospf_area_initfib);
+ fib_init(&oa->enet_fib, p->p.pool, sizeof(struct area_net), 0, ospf_area_initfib);
- WALK_LIST(anc, ac->net_list)
- {
- an = (struct area_net *) fib_get(&oa->net_fib, &anc->px.addr, anc->px.len);
- an->hidden = anc->hidden;
- }
+ WALK_LIST(anc, ac->net_list)
+ {
+ an = (struct area_net *) fib_get(&oa->net_fib, &anc->px.addr, anc->px.len);
+ an->hidden = anc->hidden;
+ }
- WALK_LIST(anc, ac->enet_list)
- {
- an = (struct area_net *) fib_get(&oa->enet_fib, &anc->px.addr, anc->px.len);
- an->hidden = anc->hidden;
- an->tag = anc->tag;
- }
+ WALK_LIST(anc, ac->enet_list)
+ {
+ an = (struct area_net *) fib_get(&oa->enet_fib, &anc->px.addr, anc->px.len);
+ an->hidden = anc->hidden;
+ an->tag = anc->tag;
+ }
}
static void
-ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf)
+ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
{
- struct proto *p = &po->proto;
struct ospf_area *oa;
OSPF_TRACE(D_EVENTS, "Adding area %R", ac->areaid);
- oa = mb_allocz(p->pool, sizeof(struct ospf_area));
- add_tail(&po->area_list, NODE oa);
- po->areano++;
+ oa = mb_allocz(p->p.pool, sizeof(struct ospf_area));
+ add_tail(&p->area_list, NODE oa);
+ p->areano++;
oa->ac = ac;
oa->areaid = ac->areaid;
oa->rt = NULL;
- oa->po = po;
- fib_init(&oa->rtr, p->pool, sizeof(ort), 0, ospf_rt_initort);
+ oa->po = p;
+ fib_init(&oa->rtr, p->p.pool, sizeof(ort), 0, ospf_rt_initort);
add_area_nets(oa, ac);
if (oa->areaid == 0)
- po->backbone = oa;
+ p->backbone = oa;
-#ifdef OSPFv2
- oa->options = ac->type;
-#else /* OSPFv3 */
- oa->options = ac->type | OPT_V6 | (po->stub_router ? 0 : OPT_R);
-#endif
+ if (ospf_is_v2(p))
+ oa->options = ac->type;
+ else
+ oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
- /*
- * Set E-bit for NSSA ABR routers. No need to explicitly call
- * schedule_rt_lsa() for other areas, will be done anyway.
- * We use cf->abr because po->areano is not yet complete.
- */
- if (oa_is_nssa(oa) && ((struct ospf_config *) (p->cf))->abr)
- po->ebit = 1;
+ ospf_notify_rt_lsa(oa);
+}
- if (reconf)
- ospf_ifaces_reconfigure(oa, ac);
+static void
+ospf_flush_area(struct ospf_proto *p, u32 areaid)
+{
+ struct top_hash_entry *en;
+
+ WALK_SLIST(en, p->lsal)
+ if ((LSA_SCOPE(en->lsa_type) == LSA_SCOPE_AREA) && (en->domain == areaid))
+ ospf_flush_lsa(p, en);
}
static void
ospf_area_remove(struct ospf_area *oa)
{
- struct proto *p = &oa->po->proto;
+ struct ospf_proto *p = oa->po;
OSPF_TRACE(D_EVENTS, "Removing area %R", oa->areaid);
/* We suppose that interfaces are already removed */
- ospf_flush_area(oa->po, oa->areaid);
-
+ ospf_flush_area(p, oa->areaid);
+
fib_free(&oa->rtr);
fib_free(&oa->net_fib);
fib_free(&oa->enet_fib);
@@ -198,87 +194,91 @@ ospf_area_remove(struct ospf_area *oa)
if (oa->translator_timer)
rfree(oa->translator_timer);
- oa->po->areano--;
+ p->areano--;
rem_node(NODE oa);
mb_free(oa);
}
struct ospf_area *
-ospf_find_area(struct proto_ospf *po, u32 aid)
+ospf_find_area(struct ospf_proto *p, u32 aid)
{
struct ospf_area *oa;
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
if (((struct ospf_area *) oa)->areaid == aid)
return oa;
return NULL;
}
static struct ospf_iface *
-ospf_find_vlink(struct proto_ospf *po, u32 voa, u32 vid)
+ospf_find_vlink(struct ospf_proto *p, u32 voa, u32 vid)
{
struct ospf_iface *ifa;
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa->areaid == voa) && (ifa->vid == vid))
return ifa;
return NULL;
}
static int
-ospf_start(struct proto *p)
+ospf_start(struct proto *P)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
- struct ospf_config *c = (struct ospf_config *) (p->cf);
+ struct ospf_proto *p = (struct ospf_proto *) P;
+ struct ospf_config *c = (struct ospf_config *) (P->cf);
struct ospf_area_config *ac;
- po->router_id = proto_get_router_id(p->cf);
- po->rfc1583 = c->rfc1583;
- po->stub_router = c->stub_router;
- po->merge_external = c->merge_external;
- po->ebit = 0;
- po->ecmp = c->ecmp;
- po->tick = c->tick;
- po->disp_timer = tm_new(p->pool);
- po->disp_timer->data = po;
- po->disp_timer->randomize = 0;
- po->disp_timer->hook = ospf_disp;
- po->disp_timer->recurrent = po->tick;
- tm_start(po->disp_timer, 1);
- po->lsab_size = 256;
- po->lsab_used = 0;
- po->lsab = mb_alloc(p->pool, po->lsab_size);
- po->nhpool = lp_new(p->pool, 12*sizeof(struct mpnh));
- init_list(&(po->iface_list));
- init_list(&(po->area_list));
- fib_init(&po->rtf, p->pool, sizeof(ort), 0, ospf_rt_initort);
- po->areano = 0;
- po->gr = ospf_top_new(p->pool);
- s_init_list(&(po->lsal));
+ p->router_id = proto_get_router_id(P->cf);
+ p->ospf2 = c->ospf2;
+ p->rfc1583 = c->rfc1583;
+ p->stub_router = c->stub_router;
+ p->merge_external = c->merge_external;
+ p->asbr = c->asbr;
+ p->ecmp = c->ecmp;
+ p->tick = c->tick;
+ p->disp_timer = tm_new_set(P->pool, ospf_disp, p, 0, p->tick);
+ tm_start(p->disp_timer, 1);
+ p->lsab_size = 256;
+ p->lsab_used = 0;
+ p->lsab = mb_alloc(P->pool, p->lsab_size);
+ p->nhpool = lp_new(P->pool, 12*sizeof(struct mpnh));
+ init_list(&(p->iface_list));
+ init_list(&(p->area_list));
+ fib_init(&p->rtf, P->pool, sizeof(ort), 0, ospf_rt_initort);
+ p->areano = 0;
+ p->gr = ospf_top_new(p, P->pool);
+ s_init_list(&(p->lsal));
+
+ p->flood_event = ev_new(P->pool);
+ p->flood_event->hook = ospf_flood_event;
+ p->flood_event->data = p;
+
+ p->log_pkt_tbf = (struct tbf){ .rate = 1, .burst = 5 };
+ p->log_lsa_tbf = (struct tbf){ .rate = 4, .burst = 20 };
WALK_LIST(ac, c->area_list)
- ospf_area_add(po, ac, 0);
+ ospf_area_add(p, ac);
if (c->abr)
- ospf_open_vlink_sk(po);
+ ospf_open_vlink_sk(p);
/* Add all virtual links */
struct ospf_iface_patt *ic;
WALK_LIST(ic, c->vlink_list)
- ospf_iface_new_vlink(po, ic);
+ ospf_iface_new_vlink(p, ic);
return PS_UP;
}
static void
-ospf_dump(struct proto *p)
+ospf_dump(struct proto *P)
{
+ struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_iface *ifa;
struct ospf_neighbor *n;
- struct proto_ospf *po = (struct proto_ospf *) p;
- OSPF_TRACE(D_EVENTS, "Area number: %d", po->areano);
+ OSPF_TRACE(D_EVENTS, "Area number: %d", p->areano);
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
{
OSPF_TRACE(D_EVENTS, "Interface: %s", ifa->ifname);
OSPF_TRACE(D_EVENTS, "state: %u", ifa->state);
@@ -292,7 +292,7 @@ ospf_dump(struct proto *p)
/*
OSPF_TRACE(D_EVENTS, "LSA graph dump start:");
- ospf_top_dump(po->gr, p);
+ ospf_top_dump(p->gr, p);
OSPF_TRACE(D_EVENTS, "LSA graph dump finished");
*/
neigh_dump_all();
@@ -301,20 +301,21 @@ ospf_dump(struct proto *p)
static struct proto *
ospf_init(struct proto_config *c)
{
- struct proto *p = proto_new(c, sizeof(struct proto_ospf));
-
- p->accept_ra_types = RA_OPTIMAL;
- p->rt_notify = ospf_rt_notify;
- p->if_notify = ospf_if_notify;
- p->ifa_notify = ospf_ifa_notify;
- p->import_control = ospf_import_control;
- p->reload_routes = ospf_reload_routes;
- p->make_tmp_attrs = ospf_make_tmp_attrs;
- p->store_tmp_attrs = ospf_store_tmp_attrs;
- p->rte_better = ospf_rte_better;
- p->rte_same = ospf_rte_same;
-
- return p;
+ struct ospf_config *oc = (struct ospf_config *) c;
+ struct proto *P = proto_new(c, sizeof(struct ospf_proto));
+
+ P->accept_ra_types = RA_OPTIMAL;
+ P->rt_notify = ospf_rt_notify;
+ P->if_notify = ospf_if_notify;
+ P->ifa_notify = oc->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
+ P->import_control = ospf_import_control;
+ P->reload_routes = ospf_reload_routes;
+ P->make_tmp_attrs = ospf_make_tmp_attrs;
+ P->store_tmp_attrs = ospf_store_tmp_attrs;
+ P->rte_better = ospf_rte_better;
+ P->rte_same = ospf_rte_same;
+
+ return P;
}
/* If new is better return 1 */
@@ -379,119 +380,56 @@ ospf_build_attrs(ea_list * next, struct linpool *pool, u32 m1, u32 m2,
return l;
}
-void
-schedule_net_lsa(struct ospf_iface *ifa)
-{
- struct proto *p = &ifa->oa->po->proto;
-
- OSPF_TRACE(D_EVENTS, "Scheduling network-LSA origination for iface %s", ifa->ifname);
- ifa->orignet = 1;
-}
-
-#ifdef OSPFv3
-void
-schedule_link_lsa(struct ospf_iface *ifa)
-{
- struct proto *p = &ifa->oa->po->proto;
-
- OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->ifname);
- ifa->origlink = 1;
-}
-#endif
void
-schedule_rt_lsa(struct ospf_area *oa)
+ospf_schedule_rtcalc(struct ospf_proto *p)
{
- struct proto *p = &oa->po->proto;
-
- OSPF_TRACE(D_EVENTS, "Scheduling router-LSA origination for area %R", oa->areaid);
- oa->origrt = 1;
-}
-
-void
-schedule_rtcalc(struct proto_ospf *po)
-{
- struct proto *p = &po->proto;
-
- if (po->calcrt)
+ if (p->calcrt)
return;
OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation");
- po->calcrt = 1;
+ p->calcrt = 1;
}
static int
-ospf_reload_routes(struct proto *p)
+ospf_reload_routes(struct proto *P)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
+ struct ospf_proto *p = (struct ospf_proto *) P;
- if (po->calcrt != 2)
+ if (p->calcrt != 2)
OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation with route reload");
- po->calcrt = 2;
+ p->calcrt = 2;
return 1;
}
-/**
- * area_disp - invokes origination of
- * router LSA and routing table cleanup
- * @oa: ospf area
- *
- * It invokes aging and when @ospf_area->origrt is set to 1, start
- * function for origination of router, network LSAs.
- */
-void
-area_disp(struct ospf_area *oa)
-{
- struct proto_ospf *po = oa->po;
- struct ospf_iface *ifa;
-
- /* Now try to originage rt_lsa */
- if (oa->origrt)
- update_rt_lsa(oa);
-
- /* Now try to originate network LSA's */
- WALK_LIST(ifa, po->iface_list)
- {
-#ifdef OSPFv3
- /* Link LSA should be originated before Network LSA */
- if (ifa->origlink && (ifa->oa == oa))
- update_link_lsa(ifa);
-#endif
-
- if (ifa->orignet && (ifa->oa == oa))
- update_net_lsa(ifa);
- }
-}
/**
* ospf_disp - invokes routing table calculation, aging and also area_disp()
- * @timer: timer usually called every @proto_ospf->tick second, @timer->data
- * point to @proto_ospf
+ * @timer: timer usually called every @ospf_proto->tick second, @timer->data
+ * point to @ospf_proto
*/
-void
+static void
ospf_disp(timer * timer)
{
- struct proto_ospf *po = timer->data;
- struct ospf_area *oa;
+ struct ospf_proto *p = timer->data;
- WALK_LIST(oa, po->area_list)
- area_disp(oa);
+ /* Originate or flush local topology LSAs */
+ ospf_update_topology(p);
- /* Age LSA DB */
- ospf_age(po);
+ /* Process LSA DB */
+ ospf_update_lsadb(p);
/* Calculate routing table */
- if (po->calcrt)
- ospf_rt_spf(po);
+ if (p->calcrt)
+ ospf_rt_spf(p);
}
-
/**
* ospf_import_control - accept or reject new route from nest's routing table
- * @p: current instance of protocol
+ * @P: OSPF protocol instance
* @new: the new route
* @attrs: list of attributes
* @pool: pool for allocation of attributes
@@ -499,15 +437,14 @@ ospf_disp(timer * timer)
* Its quite simple. It does not accept our own routes and leaves the decision on
* import to the filters.
*/
-
-int
-ospf_import_control(struct proto *p, rte ** new, ea_list ** attrs,
- struct linpool *pool)
+static int
+ospf_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
{
- struct ospf_area *oa = ospf_main_area((struct proto_ospf *) p);
+ struct ospf_proto *p = (struct ospf_proto *) P;
+ struct ospf_area *oa = ospf_main_area(p);
rte *e = *new;
- if (e->attrs->src->proto == p)
+ if (e->attrs->src->proto == P)
return -1; /* Reject our own routes */
if (oa_is_stub(oa))
@@ -520,14 +457,14 @@ ospf_import_control(struct proto *p, rte ** new, ea_list ** attrs,
return 0; /* Leave decision to the filters */
}
-struct ea_list *
+static struct ea_list *
ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool)
{
return ospf_build_attrs(NULL, pool, rt->u.ospf.metric1, rt->u.ospf.metric2,
rt->u.ospf.tag, rt->u.ospf.router_id);
}
-void
+static void
ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
{
rt->u.ospf.metric1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY);
@@ -538,27 +475,27 @@ ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
/**
* ospf_shutdown - Finish of OSPF instance
- * @p: current instance of protocol
+ * @P: OSPF protocol instance
*
* RFC does not define any action that should be taken before router
* shutdown. To make my neighbors react as fast as possible, I send
* them hello packet with empty neighbor list. They should start
* their neighbor state machine with event %NEIGHBOR_1WAY.
*/
-
static int
-ospf_shutdown(struct proto *p)
+ospf_shutdown(struct proto *P)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
+ struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_iface *ifa;
+
OSPF_TRACE(D_EVENTS, "Shutdown requested");
/* And send to all my neighbors 1WAY */
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
ospf_iface_shutdown(ifa);
/* Cleanup locked rta entries */
- FIB_WALK(&po->rtf, nftmp)
+ FIB_WALK(&p->rtf, nftmp)
{
rta_free(((ort *) nftmp)->old_rta);
}
@@ -568,49 +505,11 @@ ospf_shutdown(struct proto *p)
}
static void
-ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs)
+ospf_get_status(struct proto *P, byte * buf)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
- struct ospf_area *oa = ospf_main_area(po);
- ort *nf = (ort *) fib_get(&po->rtf, &n->n.prefix, n->n.pxlen);
- struct fib_node *fn = &nf->fn;
-
- if (!new)
- {
- if (fn->x1 != EXT_EXPORT)
- return;
-
- flush_ext_lsa(oa, fn, oa_is_nssa(oa));
-
- /* Old external route might blocked some NSSA translation */
- if (po->areano > 1)
- schedule_rtcalc(po);
-
- return;
- }
+ struct ospf_proto *p = (struct ospf_proto *) P;
- /* Get route attributes */
- u32 m1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY);
- u32 m2 = ea_get_int(attrs, EA_OSPF_METRIC2, 10000);
- u32 metric = (m1 != LSINFINITY) ? m1 : (m2 | LSA_EXT_EBIT);
- u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0);
- ip_addr gw = IPA_NONE;
- // FIXME check for gw should be per ifa, not per iface
- if ((new->attrs->dest == RTD_ROUTER) &&
- ipa_nonzero(new->attrs->gw) &&
- !ipa_has_link_scope(new->attrs->gw) &&
- (ospf_iface_find((struct proto_ospf *) p, new->attrs->iface) != NULL))
- gw = new->attrs->gw;
-
- originate_ext_lsa(oa, fn, EXT_EXPORT, metric, gw, tag, 1);
-}
-
-static void
-ospf_get_status(struct proto *p, byte * buf)
-{
- struct proto_ospf *po = (struct proto_ospf *) p;
-
- if (p->proto_state == PS_DOWN)
+ if (p->p.proto_state == PS_DOWN)
buf[0] = 0;
else
{
@@ -618,7 +517,7 @@ ospf_get_status(struct proto *p, byte * buf)
struct ospf_neighbor *n;
int adj = 0;
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
WALK_LIST(n, ifa->neigh_list) if (n->state == NEIGHBOR_FULL)
adj = 1;
@@ -636,18 +535,18 @@ ospf_get_route_info(rte * rte, byte * buf, ea_list * attrs UNUSED)
switch (rte->attrs->source)
{
- case RTS_OSPF:
- type = "I";
- break;
- case RTS_OSPF_IA:
- type = "IA";
- break;
- case RTS_OSPF_EXT1:
- type = "E1";
- break;
- case RTS_OSPF_EXT2:
- type = "E2";
- break;
+ case RTS_OSPF:
+ type = "I";
+ break;
+ case RTS_OSPF_IA:
+ type = "IA";
+ break;
+ case RTS_OSPF_EXT1:
+ type = "E1";
+ break;
+ case RTS_OSPF_EXT2:
+ type = "E2";
+ break;
}
buf += bsprintf(buf, " %s", type);
@@ -688,18 +587,24 @@ ospf_get_attr(eattr * a, byte * buf, int buflen UNUSED)
static void
ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{
+ struct ospf_proto *p = oa->po;
+ struct ospf_area_config *oac = oa->ac;
+ struct ospf_iface *ifa;
+
oa->ac = nac;
- // FIXME better area type reconfiguration
-#ifdef OSPFv2
- oa->options = nac->type;
-#else /* OSPFv3 */
- oa->options = nac->type | OPT_V6 | (oa->po->stub_router ? 0 : OPT_R);
-#endif
- if (oa_is_nssa(oa) && (oa->po->areano > 1))
- oa->po->ebit = 1;
+ if (ospf_is_v2(p))
+ oa->options = nac->type;
+ else
+ oa->options = nac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
- ospf_ifaces_reconfigure(oa, nac);
+ if (nac->type != oac->type)
+ {
+ /* Force restart of area interfaces */
+ WALK_LIST(ifa, p->iface_list)
+ if (ifa->oa == oa)
+ ifa->marked = 2;
+ }
/* Handle net_list */
fib_free(&oa->net_fib);
@@ -709,12 +614,12 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
/* No need to handle stubnet_list */
oa->marked = 0;
- schedule_rt_lsa(oa);
+ ospf_notify_rt_lsa(oa);
}
/**
* ospf_reconfigure - reconfiguration hook
- * @p: current instance of protocol (with old configuration)
+ * @P: current instance of protocol (with old configuration)
* @c: new configuration requested by user
*
* This hook tries to be a little bit intelligent. Instance of OSPF
@@ -723,95 +628,99 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
* nonbroadcast network, cost of interface, etc.
*/
static int
-ospf_reconfigure(struct proto *p, struct proto_config *c)
+ospf_reconfigure(struct proto *P, struct proto_config *c)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
- struct ospf_config *old = (struct ospf_config *) (p->cf);
+ struct ospf_proto *p = (struct ospf_proto *) P;
+ struct ospf_config *old = (struct ospf_config *) (P->cf);
struct ospf_config *new = (struct ospf_config *) c;
struct ospf_area_config *nac;
struct ospf_area *oa, *oax;
struct ospf_iface *ifa, *ifx;
struct ospf_iface_patt *ip;
- if (proto_get_router_id(c) != po->router_id)
+ if (proto_get_router_id(c) != p->router_id)
return 0;
- if (po->rfc1583 != new->rfc1583)
+ if (p->rfc1583 != new->rfc1583)
return 0;
if (old->abr != new->abr)
return 0;
- po->stub_router = new->stub_router;
- po->merge_external = new->merge_external;
- po->ecmp = new->ecmp;
- po->tick = new->tick;
- po->disp_timer->recurrent = po->tick;
- tm_start(po->disp_timer, 1);
+ p->stub_router = new->stub_router;
+ p->merge_external = new->merge_external;
+ p->asbr = new->asbr;
+ p->ecmp = new->ecmp;
+ p->tick = new->tick;
+ p->disp_timer->recurrent = p->tick;
+ tm_start(p->disp_timer, 1);
/* Mark all areas and ifaces */
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
oa->marked = 1;
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
ifa->marked = 1;
/* Add and update areas */
WALK_LIST(nac, new->area_list)
{
- oa = ospf_find_area(po, nac->areaid);
+ oa = ospf_find_area(p, nac->areaid);
if (oa)
ospf_area_reconfigure(oa, nac);
else
- ospf_area_add(po, nac, 1);
+ ospf_area_add(p, nac);
}
+ /* Add and update interfaces */
+ ospf_reconfigure_ifaces(p);
+
/* Add and update vlinks */
WALK_LIST(ip, new->vlink_list)
{
- ifa = ospf_find_vlink(po, ip->voa, ip->vid);
+ ifa = ospf_find_vlink(p, ip->voa, ip->vid);
if (ifa)
ospf_iface_reconfigure(ifa, ip);
else
- ospf_iface_new_vlink(po, ip);
+ ospf_iface_new_vlink(p, ip);
}
/* Delete remaining ifaces and areas */
- WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
+ WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
if (ifa->marked)
{
ospf_iface_shutdown(ifa);
ospf_iface_remove(ifa);
}
- WALK_LIST_DELSAFE(oa, oax, po->area_list)
+ WALK_LIST_DELSAFE(oa, oax, p->area_list)
if (oa->marked)
ospf_area_remove(oa);
- schedule_rtcalc(po);
-
+ ospf_schedule_rtcalc(p);
+
return 1;
}
void
-ospf_sh_neigh(struct proto *p, char *iff)
+ospf_sh_neigh(struct proto *P, char *iff)
{
+ struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_iface *ifa = NULL;
struct ospf_neighbor *n;
- struct proto_ospf *po = (struct proto_ospf *) p;
- if (p->proto_state != PS_UP)
+ if (p->p.proto_state != PS_UP)
{
- cli_msg(-1013, "%s: is not up", p->name);
+ cli_msg(-1013, "%s: is not up", p->p.name);
cli_msg(0, "");
return;
}
- cli_msg(-1013, "%s:", p->name);
+ cli_msg(-1013, "%s:", p->p.name);
cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-10s %-12s", "Router ID", "Pri",
" State", "DTime", "Interface", "Router IP");
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
if ((iff == NULL) || patmatch(iff, ifa->ifname))
WALK_LIST(n, ifa->neigh_list)
ospf_sh_neigh_info(n);
@@ -819,47 +728,47 @@ ospf_sh_neigh(struct proto *p, char *iff)
}
void
-ospf_sh(struct proto *p)
+ospf_sh(struct proto *P)
{
+ struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_area *oa;
- struct proto_ospf *po = (struct proto_ospf *) p;
struct ospf_iface *ifa;
struct ospf_neighbor *n;
int ifano, nno, adjno, firstfib;
struct area_net *anet;
- if (p->proto_state != PS_UP)
+ if (p->p.proto_state != PS_UP)
{
- cli_msg(-1014, "%s: is not up", p->name);
+ cli_msg(-1014, "%s: is not up", p->p.name);
cli_msg(0, "");
return;
}
- cli_msg(-1014, "%s:", p->name);
- cli_msg(-1014, "RFC1583 compatibility: %s", (po->rfc1583 ? "enable" : "disabled"));
- cli_msg(-1014, "Stub router: %s", (po->stub_router ? "Yes" : "No"));
- cli_msg(-1014, "RT scheduler tick: %d", po->tick);
- cli_msg(-1014, "Number of areas: %u", po->areano);
- cli_msg(-1014, "Number of LSAs in DB:\t%u", po->gr->hash_entries);
+ cli_msg(-1014, "%s:", p->p.name);
+ cli_msg(-1014, "RFC1583 compatibility: %s", (p->rfc1583 ? "enabled" : "disabled"));
+ cli_msg(-1014, "Stub router: %s", (p->stub_router ? "Yes" : "No"));
+ cli_msg(-1014, "RT scheduler tick: %d", p->tick);
+ cli_msg(-1014, "Number of areas: %u", p->areano);
+ cli_msg(-1014, "Number of LSAs in DB:\t%u", p->gr->hash_entries);
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
{
cli_msg(-1014, "\tArea: %R (%u) %s", oa->areaid, oa->areaid,
oa->areaid == 0 ? "[BACKBONE]" : "");
ifano = 0;
nno = 0;
adjno = 0;
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
{
if (oa == ifa->oa)
{
ifano++;
- WALK_LIST(n, ifa->neigh_list)
- {
+ WALK_LIST(n, ifa->neigh_list)
+ {
nno++;
if (n->state == NEIGHBOR_FULL)
adjno++;
- }
+ }
}
}
@@ -880,8 +789,8 @@ ospf_sh(struct proto *p)
anet = (struct area_net *) nftmp;
if(firstfib)
{
- cli_msg(-1014, "\t\tArea networks:");
- firstfib = 0;
+ cli_msg(-1014, "\t\tArea networks:");
+ firstfib = 0;
}
cli_msg(-1014, "\t\t\t%1I/%u\t%s\t%s", anet->fn.prefix, anet->fn.pxlen,
anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
@@ -894,8 +803,8 @@ ospf_sh(struct proto *p)
anet = (struct area_net *) nftmp;
if(firstfib)
{
- cli_msg(-1014, "\t\tArea external networks:");
- firstfib = 0;
+ cli_msg(-1014, "\t\tArea external networks:");
+ firstfib = 0;
}
cli_msg(-1014, "\t\t\t%1I/%u\t%s\t%s", anet->fn.prefix, anet->fn.pxlen,
anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
@@ -907,20 +816,20 @@ ospf_sh(struct proto *p)
}
void
-ospf_sh_iface(struct proto *p, char *iff)
+ospf_sh_iface(struct proto *P, char *iff)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
+ struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_iface *ifa = NULL;
- if (p->proto_state != PS_UP)
+ if (p->p.proto_state != PS_UP)
{
- cli_msg(-1015, "%s: is not up", p->name);
+ cli_msg(-1015, "%s: is not up", p->p.name);
cli_msg(0, "");
return;
}
- cli_msg(-1015, "%s:", p->name);
- WALK_LIST(ifa, po->iface_list)
+ cli_msg(-1015, "%s:", p->p.name);
+ WALK_LIST(ifa, p->iface_list)
if ((iff == NULL) || patmatch(iff, ifa->ifname))
ospf_iface_info(ifa);
cli_msg(0, "");
@@ -939,14 +848,12 @@ ospf_sh_iface(struct proto *p, char *iff)
* values
*/
-#ifdef OSPFv3
-
static struct ospf_lsa_header *
fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *src,
struct ospf_lsa_prefix *px)
{
dst->age = src->age;
- dst->type = px->ref_type;
+ dst->type_raw = px->ref_type;
dst->id = px->ref_id;
dst->rt = px->ref_rt;
dst->sn = src->sn;
@@ -954,49 +861,59 @@ fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *sr
return dst;
}
-#endif
+
+static int lsa_compare_ospf3;
static int
lsa_compare_for_state(const void *p1, const void *p2)
{
- struct top_hash_entry * he1 = * (struct top_hash_entry **) p1;
- struct top_hash_entry * he2 = * (struct top_hash_entry **) p2;
+ struct top_hash_entry *he1 = * (struct top_hash_entry **) p1;
+ struct top_hash_entry *he2 = * (struct top_hash_entry **) p2;
struct ospf_lsa_header *lsa1 = &(he1->lsa);
struct ospf_lsa_header *lsa2 = &(he2->lsa);
+ struct ospf_lsa_header lsatmp1, lsatmp2;
+ u16 lsa1_type = he1->lsa_type;
+ u16 lsa2_type = he2->lsa_type;
if (he1->domain < he2->domain)
return -1;
if (he1->domain > he2->domain)
return 1;
-#ifdef OSPFv3
- struct ospf_lsa_header lsatmp1, lsatmp2;
- int px1 = (lsa1->type == LSA_T_PREFIX);
- int px2 = (lsa2->type == LSA_T_PREFIX);
+ /* px1 or px2 assumes OSPFv3 */
+ int px1 = (lsa1_type == LSA_T_PREFIX);
+ int px2 = (lsa2_type == LSA_T_PREFIX);
if (px1)
+ {
lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body);
+ lsa1_type = lsa1->type_raw; /* FIXME: handle unknown ref_type */
+ }
if (px2)
+ {
lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body);
-#endif
+ lsa2_type = lsa2->type_raw;
+ }
+
- int nt1 = (lsa1->type == LSA_T_NET);
- int nt2 = (lsa2->type == LSA_T_NET);
+ int nt1 = (lsa1_type == LSA_T_NET);
+ int nt2 = (lsa2_type == LSA_T_NET);
if (nt1 != nt2)
return nt1 - nt2;
if (nt1)
{
-#ifdef OSPFv3
- /* In OSPFv3, neworks are named base on ID of DR */
- if (lsa1->rt < lsa2->rt)
- return -1;
- if (lsa1->rt > lsa2->rt)
- return 1;
-#endif
+ /* In OSPFv3, networks are named based on ID of DR */
+ if (lsa_compare_ospf3)
+ {
+ if (lsa1->rt < lsa2->rt)
+ return -1;
+ if (lsa1->rt > lsa2->rt)
+ return 1;
+ }
/* For OSPFv2, this is IP of the network,
for OSPFv3, this is interface ID */
@@ -1005,23 +922,21 @@ lsa_compare_for_state(const void *p1, const void *p2)
if (lsa1->id > lsa2->id)
return 1;
-#ifdef OSPFv3
if (px1 != px2)
return px1 - px2;
-#endif
return lsa1->sn - lsa2->sn;
}
- else
+ else
{
if (lsa1->rt < lsa2->rt)
return -1;
if (lsa1->rt > lsa2->rt)
return 1;
- if (lsa1->type < lsa2->type)
+ if (lsa1_type < lsa2_type)
return -1;
- if (lsa1->type > lsa2->type)
+ if (lsa1_type > lsa2_type)
return 1;
if (lsa1->id < lsa2->id)
@@ -1029,11 +944,9 @@ lsa_compare_for_state(const void *p1, const void *p2)
if (lsa1->id > lsa2->id)
return 1;
-#ifdef OSPFv3
if (px1 != px2)
return px1 - px2;
-#endif
-
+
return lsa1->sn - lsa2->sn;
}
}
@@ -1069,79 +982,77 @@ show_lsa_distance(struct top_hash_entry *he)
}
static inline void
-show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he, int first, int verbose)
+show_lsa_router(struct ospf_proto *p, struct top_hash_entry *he, int verbose)
{
- struct ospf_lsa_header *lsa = &(he->lsa);
- struct ospf_lsa_rt *rt = he->lsa_body;
- struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1);
- int max = lsa_rt_count(lsa);
- int i;
-
- if (first)
- {
- cli_msg(-1016, "");
- cli_msg(-1016, "\trouter %R", he->lsa.rt);
- show_lsa_distance(he);
- }
+ struct ospf_lsa_rt_walk rtl;
+ cli_msg(-1016, "");
+ cli_msg(-1016, "\trouter %R", he->lsa.rt);
+ show_lsa_distance(he);
- for (i = 0; i < max; i++)
- if (rr[i].type == LSART_VLNK)
- cli_msg(-1016, "\t\tvlink %R metric %u", rr[i].id, rr[i].metric);
+ lsa_walk_rt_init(p, he, &rtl);
+ while (lsa_walk_rt(&rtl))
+ if (rtl.type == LSART_VLNK)
+ cli_msg(-1016, "\t\tvlink %R metric %u", rtl.id, rtl.metric);
- for (i = 0; i < max; i++)
- if (rr[i].type == LSART_PTP)
- cli_msg(-1016, "\t\trouter %R metric %u", rr[i].id, rr[i].metric);
+ lsa_walk_rt_init(p, he, &rtl);
+ while (lsa_walk_rt(&rtl))
+ if (rtl.type == LSART_PTP)
+ cli_msg(-1016, "\t\trouter %R metric %u", rtl.id, rtl.metric);
- for (i = 0; i < max; i++)
- if (rr[i].type == LSART_NET)
+ lsa_walk_rt_init(p, he, &rtl);
+ while (lsa_walk_rt(&rtl))
+ if (rtl.type == LSART_NET)
{
-#ifdef OSPFv2
- struct top_hash_entry *net_he = ospf_hash_find_net(po->gr, he->domain, rr[i].id);
-
- if (net_he)
+ if (ospf_is_v2(p))
{
- struct ospf_lsa_header *net_lsa = &(net_he->lsa);
- struct ospf_lsa_net *net_ln = net_he->lsa_body;
+ /* In OSPFv2, we try to find network-LSA to get prefix/pxlen */
+ struct top_hash_entry *net_he = ospf_hash_find_net2(p->gr, he->domain, rtl.id);
- cli_msg(-1016, "\t\tnetwork %I/%d metric %u",
- ipa_and(ipa_from_u32(net_lsa->id), net_ln->netmask),
- ipa_mklen(net_ln->netmask), rr[i].metric);
+ if (net_he && (net_he->lsa.age < LSA_MAXAGE))
+ {
+ struct ospf_lsa_header *net_lsa = &(net_he->lsa);
+ struct ospf_lsa_net *net_ln = net_he->lsa_body;
+
+ cli_msg(-1016, "\t\tnetwork %I/%d metric %u",
+ ipa_from_u32(net_lsa->id & net_ln->optx),
+ u32_masklen(net_ln->optx), rtl.metric);
+ }
+ else
+ cli_msg(-1016, "\t\tnetwork [%R] metric %u", rtl.id, rtl.metric);
}
else
- cli_msg(-1016, "\t\tnetwork [%R] metric %u", rr[i].id, rr[i].metric);
-
-#else /* OSPFv3 */
- cli_msg(-1016, "\t\tnetwork [%R-%u] metric %u", rr[i].id, rr[i].nif, rr[i].metric);
-#endif
+ cli_msg(-1016, "\t\tnetwork [%R-%u] metric %u", rtl.id, rtl.nif, rtl.metric);
}
-#ifdef OSPFv2
- if (!verbose)
- return;
-
- for (i = 0; i < max; i++)
- if (rr[i].type == LSART_STUB)
- cli_msg(-1016, "\t\tstubnet %I/%d metric %u", ipa_from_u32(rr[i].id),
- ipa_mklen(ipa_from_u32(rr[i].data)), rr[i].metric);
-#endif
+ if (ospf_is_v2(p) && verbose)
+ {
+ lsa_walk_rt_init(p, he, &rtl);
+ while (lsa_walk_rt(&rtl))
+ if (rtl.type == LSART_STUB)
+ cli_msg(-1016, "\t\tstubnet %I/%d metric %u",
+ ipa_from_u32(rtl.id), u32_masklen(rtl.data), rtl.metric);
+ }
}
static inline void
-show_lsa_network(struct top_hash_entry *he)
+show_lsa_network(struct top_hash_entry *he, int ospf2)
{
struct ospf_lsa_header *lsa = &(he->lsa);
struct ospf_lsa_net *ln = he->lsa_body;
u32 i;
-#ifdef OSPFv2
- cli_msg(-1016, "");
- cli_msg(-1016, "\tnetwork %I/%d", ipa_and(ipa_from_u32(lsa->id), ln->netmask), ipa_mklen(ln->netmask));
- cli_msg(-1016, "\t\tdr %R", lsa->rt);
-#else /* OSPFv3 */
- cli_msg(-1016, "");
- cli_msg(-1016, "\tnetwork [%R-%u]", lsa->rt, lsa->id);
-#endif
+ if (ospf2)
+ {
+ cli_msg(-1016, "");
+ cli_msg(-1016, "\tnetwork %I/%d", ipa_from_u32(lsa->id & ln->optx), u32_masklen(ln->optx));
+ cli_msg(-1016, "\t\tdr %R", lsa->rt);
+ }
+ else
+ {
+ cli_msg(-1016, "");
+ cli_msg(-1016, "\tnetwork [%R-%u]", lsa->rt, lsa->id);
+ }
show_lsa_distance(he);
@@ -1150,97 +1061,54 @@ show_lsa_network(struct top_hash_entry *he)
}
static inline void
-show_lsa_sum_net(struct top_hash_entry *he)
+show_lsa_sum_net(struct top_hash_entry *he, int ospf2)
{
ip_addr ip;
int pxlen;
-
-#ifdef OSPFv2
- struct ospf_lsa_sum *ls = he->lsa_body;
- pxlen = ipa_mklen(ls->netmask);
- ip = ipa_and(ipa_from_u32(he->lsa.id), ls->netmask);
-#else /* OSPFv3 */
u8 pxopts;
- u16 rest;
- struct ospf_lsa_sum_net *ls = he->lsa_body;
- lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest);
-#endif
+ u32 metric;
- cli_msg(-1016, "\t\txnetwork %I/%d metric %u", ip, pxlen, ls->metric);
+ lsa_parse_sum_net(he, ospf2, &ip, &pxlen, &pxopts, &metric);
+ cli_msg(-1016, "\t\txnetwork %I/%d metric %u", ip, pxlen, metric);
}
static inline void
-show_lsa_sum_rt(struct top_hash_entry *he)
+show_lsa_sum_rt(struct top_hash_entry *he, int ospf2)
{
+ u32 metric;
u32 dst_rid;
+ u32 options;
-#ifdef OSPFv2
- struct ospf_lsa_sum *ls = he->lsa_body;
- dst_rid = he->lsa.id;
- // options = 0;
-#else /* OSPFv3 */
- struct ospf_lsa_sum_rt *ls = he->lsa_body;
- dst_rid = ls->drid;
- // options = ls->options & OPTIONS_MASK;
-#endif
-
- cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, ls->metric);
+ lsa_parse_sum_rt(he, ospf2, &dst_rid, &metric, &options);
+ cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, metric);
}
static inline void
-show_lsa_external(struct top_hash_entry *he)
+show_lsa_external(struct top_hash_entry *he, int ospf2)
{
- struct ospf_lsa_ext *ext = he->lsa_body;
+ struct ospf_lsa_ext_local rt;
char str_via[STD_ADDRESS_P_LENGTH + 8] = "";
char str_tag[16] = "";
- ip_addr ip, rt_fwaddr;
- int pxlen, ebit, rt_fwaddr_valid;
- u32 rt_tag, rt_metric;
- if (he->lsa.type == LSA_T_EXT)
+ if (he->lsa_type == LSA_T_EXT)
he->domain = 0; /* Unmark the LSA */
- rt_metric = ext->metric & METRIC_MASK;
- ebit = ext->metric & LSA_EXT_EBIT;
-#ifdef OSPFv2
- ip = ipa_and(ipa_from_u32(he->lsa.id), ext->netmask);
- pxlen = ipa_mklen(ext->netmask);
- rt_fwaddr = ext->fwaddr;
- rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE);
- rt_tag = ext->tag;
-#else /* OSPFv3 */
- u8 pxopts;
- u16 rest;
- u32 *buf = ext->rest;
- buf = lsa_get_ipv6_prefix(buf, &ip, &pxlen, &pxopts, &rest);
-
- rt_fwaddr_valid = ext->metric & LSA_EXT_FBIT;
- if (rt_fwaddr_valid)
- buf = lsa_get_ipv6_addr(buf, &rt_fwaddr);
- else
- rt_fwaddr = IPA_NONE;
-
- if (ext->metric & LSA_EXT_TBIT)
- rt_tag = *buf++;
- else
- rt_tag = 0;
-#endif
-
- if (rt_fwaddr_valid)
- bsprintf(str_via, " via %I", rt_fwaddr);
+ lsa_parse_ext(he, ospf2, &rt);
+
+ if (rt.fbit)
+ bsprintf(str_via, " via %I", rt.fwaddr);
- if (rt_tag)
- bsprintf(str_tag, " tag %08x", rt_tag);
+ if (rt.tag)
+ bsprintf(str_tag, " tag %08x", rt.tag);
cli_msg(-1016, "\t\t%s %I/%d metric%s %u%s%s",
- (he->lsa.type == LSA_T_NSSA) ? "nssa-ext" : "external",
- ip, pxlen, ebit ? "2" : "", rt_metric, str_via, str_tag);
+ (he->lsa_type == LSA_T_NSSA) ? "nssa-ext" : "external",
+ rt.ip, rt.pxlen, rt.ebit ? "2" : "", rt.metric, str_via, str_tag);
}
-#ifdef OSPFv3
static inline void
-show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode)
+show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
{
struct ospf_lsa_prefix *px = he->lsa_body;
ip_addr pxa;
@@ -1251,13 +1119,13 @@ show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode)
int i;
/* We check whether given prefix-LSA is related to the current node */
- if ((px->ref_type != cnode->type) || (px->ref_rt != cnode->rt))
+ if ((px->ref_type != cnode->lsa.type_raw) || (px->ref_rt != cnode->lsa.rt))
return;
if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0))
return;
- if ((px->ref_type == LSA_T_NET) && (px->ref_id != cnode->id))
+ if ((px->ref_type == LSA_T_NET) && (px->ref_id != cnode->lsa.id))
return;
buf = px->rest;
@@ -1271,71 +1139,70 @@ show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode)
cli_msg(-1016, "\t\taddress %I/%d", pxa, pxlen);
}
}
-#endif
void
-ospf_sh_state(struct proto *p, int verbose, int reachable)
+ospf_sh_state(struct proto *P, int verbose, int reachable)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
- struct ospf_lsa_header *cnode = NULL;
- unsigned int i, ix, j1, j2, jx;
+ struct ospf_proto *p = (struct ospf_proto *) P;
+ int ospf2 = ospf_is_v2(p);
+ uint i, ix, j1, jx;
u32 last_area = 0xFFFFFFFF;
- if (p->proto_state != PS_UP)
+ if (p->p.proto_state != PS_UP)
{
- cli_msg(-1016, "%s: is not up", p->name);
+ cli_msg(-1016, "%s: is not up", p->p.name);
cli_msg(0, "");
return;
}
- /* We store interesting area-scoped LSAs in array hea and
+ /* We store interesting area-scoped LSAs in array hea and
global-scoped (LSA_T_EXT) LSAs in array hex */
- int num = po->gr->hash_entries;
+ int num = p->gr->hash_entries;
struct top_hash_entry *hea[num];
struct top_hash_entry *hex[verbose ? num : 0];
struct top_hash_entry *he;
+ struct top_hash_entry *cnode = NULL;
- j1 = j2 = jx = 0;
- WALK_SLIST(he, po->lsal)
+ j1 = jx = 0;
+ WALK_SLIST(he, p->lsal)
{
int accept;
- switch (he->lsa.type)
- {
- case LSA_T_RT:
- case LSA_T_NET:
- accept = 1;
- break;
+ if (he->lsa.age == LSA_MAXAGE)
+ continue;
- case LSA_T_SUM_NET:
- case LSA_T_SUM_RT:
- case LSA_T_NSSA:
-#ifdef OSPFv3
- case LSA_T_PREFIX:
-#endif
- accept = verbose;
- break;
+ switch (he->lsa_type)
+ {
+ case LSA_T_RT:
+ case LSA_T_NET:
+ accept = 1;
+ break;
- case LSA_T_EXT:
- if (verbose)
- {
- he->domain = 1; /* Abuse domain field to mark the LSA */
- hex[jx++] = he;
- }
- default:
- accept = 0;
+ case LSA_T_SUM_NET:
+ case LSA_T_SUM_RT:
+ case LSA_T_NSSA:
+ case LSA_T_PREFIX:
+ accept = verbose;
+ break;
+
+ case LSA_T_EXT:
+ if (verbose)
+ {
+ he->domain = 1; /* Abuse domain field to mark the LSA */
+ hex[jx++] = he;
}
+ default:
+ accept = 0;
+ }
if (accept)
hea[j1++] = he;
- else
- j2++;
}
- if ((j1 + j2) != num)
- die("Fatal mismatch");
+ ASSERT(j1 <= num && jx <= num);
+ lsa_compare_ospf3 = !ospf2;
qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state);
qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
@@ -1366,10 +1233,10 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
/* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */
if (!cnode)
{
- if (((he->lsa.type == LSA_T_RT) || (he->lsa.type == LSA_T_NET))
+ if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET))
&& ((he->color == INSPF) || !reachable))
{
- cnode = &(he->lsa);
+ cnode = he;
if (he->domain != last_area)
{
@@ -1383,51 +1250,50 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
continue;
}
- ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->rt));
+ ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->lsa.rt));
- switch (he->lsa.type)
+ switch (he->lsa_type)
{
- case LSA_T_RT:
- show_lsa_router(po, he, he->lsa.id == cnode->id, verbose);
- break;
+ case LSA_T_RT:
+ if (he->lsa.id == cnode->lsa.id)
+ show_lsa_router(p, he, verbose);
+ break;
- case LSA_T_NET:
- show_lsa_network(he);
- break;
+ case LSA_T_NET:
+ show_lsa_network(he, ospf2);
+ break;
- case LSA_T_SUM_NET:
- if (cnode->type == LSA_T_RT)
- show_lsa_sum_net(he);
- break;
+ case LSA_T_SUM_NET:
+ if (cnode->lsa_type == LSA_T_RT)
+ show_lsa_sum_net(he, ospf2);
+ break;
- case LSA_T_SUM_RT:
- if (cnode->type == LSA_T_RT)
- show_lsa_sum_rt(he);
- break;
+ case LSA_T_SUM_RT:
+ if (cnode->lsa_type == LSA_T_RT)
+ show_lsa_sum_rt(he, ospf2);
+ break;
-#ifdef OSPFv3
- case LSA_T_PREFIX:
- show_lsa_prefix(he, cnode);
- break;
-#endif
+ case LSA_T_EXT:
+ case LSA_T_NSSA:
+ show_lsa_external(he, ospf2);
+ break;
- case LSA_T_EXT:
- case LSA_T_NSSA:
- show_lsa_external(he);
- break;
+ case LSA_T_PREFIX:
+ show_lsa_prefix(he, cnode);
+ break;
}
/* In these cases, we close the current node */
if ((i+1 == j1)
|| (hea[i+1]->domain != last_area)
- || (hea[i+1]->lsa.rt != cnode->rt)
- || (hea[i+1]->lsa.type == LSA_T_NET))
+ || (hea[i+1]->lsa.rt != cnode->lsa.rt)
+ || (hea[i+1]->lsa_type == LSA_T_NET))
{
- while ((ix < jx) && (hex[ix]->lsa.rt < cnode->rt))
+ while ((ix < jx) && (hex[ix]->lsa.rt < cnode->lsa.rt))
ix++;
- while ((ix < jx) && (hex[ix]->lsa.rt == cnode->rt))
- show_lsa_external(hex[ix++]);
+ while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
+ show_lsa_external(hex[ix++], ospf2);
cnode = NULL;
}
@@ -1461,7 +1327,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
last_rt = he->lsa.rt;
}
- show_lsa_external(he);
+ show_lsa_external(he, ospf2);
}
}
@@ -1476,8 +1342,8 @@ lsa_compare_for_lsadb(const void *p1, const void *p2)
struct top_hash_entry * he2 = * (struct top_hash_entry **) p2;
struct ospf_lsa_header *lsa1 = &(he1->lsa);
struct ospf_lsa_header *lsa2 = &(he2->lsa);
- int sc1 = LSA_SCOPE(lsa1);
- int sc2 = LSA_SCOPE(lsa2);
+ int sc1 = LSA_SCOPE(he1->lsa_type);
+ int sc2 = LSA_SCOPE(he2->lsa_type);
if (sc1 != sc2)
return sc2 - sc1;
@@ -1487,12 +1353,12 @@ lsa_compare_for_lsadb(const void *p1, const void *p2)
if (lsa1->rt != lsa2->rt)
return lsa1->rt - lsa2->rt;
-
+
if (lsa1->id != lsa2->id)
return lsa1->id - lsa2->id;
- if (lsa1->type != lsa2->type)
- return lsa1->type - lsa2->type;
+ if (he1->lsa_type != he2->lsa_type)
+ return he1->lsa_type - he2->lsa_type;
return lsa1->sn - lsa2->sn;
}
@@ -1500,48 +1366,50 @@ lsa_compare_for_lsadb(const void *p1, const void *p2)
void
ospf_sh_lsadb(struct lsadb_show_data *ld)
{
- struct proto *p = proto_get_named(ld->name, &proto_ospf);
- struct proto_ospf *po = (struct proto_ospf *) p;
- int num = po->gr->hash_entries;
- unsigned int i, j;
+ struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf);
+ uint num = p->gr->hash_entries;
+ uint i, j;
int last_dscope = -1;
u32 last_domain = 0;
+ u16 type_mask = ospf_is_v2(p) ? 0x00ff : 0xffff; /* see lsa_etype() */
- if (p->proto_state != PS_UP)
+ if (p->p.proto_state != PS_UP)
{
- cli_msg(-1017, "%s: is not up", p->name);
+ cli_msg(-1017, "%s: is not up", p->p.name);
cli_msg(0, "");
return;
}
if (ld->router == SH_ROUTER_SELF)
- ld->router = po->router_id;
+ ld->router = p->router_id;
struct top_hash_entry *hea[num];
struct top_hash_entry *he;
j = 0;
- WALK_SLIST(he, po->lsal)
- hea[j++] = he;
+ WALK_SLIST(he, p->lsal)
+ if (he->lsa_body)
+ hea[j++] = he;
- if (j != num)
- die("Fatal mismatch");
+ ASSERT(j <= num);
qsort(hea, j, sizeof(struct top_hash_entry *), lsa_compare_for_lsadb);
for (i = 0; i < j; i++)
{
struct ospf_lsa_header *lsa = &(hea[i]->lsa);
- int dscope = LSA_SCOPE(lsa);
+ u16 lsa_type = lsa->type_raw & type_mask;
+ u16 dscope = LSA_SCOPE(hea[i]->lsa_type);
+ /* Hack: 1 is used for LSA_SCOPE_LINK, fixed by & 0xf000 */
if (ld->scope && (dscope != (ld->scope & 0xf000)))
continue;
if ((ld->scope == LSA_SCOPE_AREA) && (hea[i]->domain != ld->area))
continue;
- /* Ignore high nibble */
- if (ld->type && ((lsa->type & 0x0fff) != (ld->type & 0x0fff)))
+ /* For user convenience ignore high nibble */
+ if (ld->type && ((lsa_type & 0x0fff) != (ld->type & 0x0fff)))
continue;
if (ld->lsid && (lsa->id != ld->lsid))
@@ -1549,54 +1417,52 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
if (ld->router && (lsa->rt != ld->router))
continue;
-
+
if ((dscope != last_dscope) || (hea[i]->domain != last_domain))
{
cli_msg(-1017, "");
switch (dscope)
{
- case LSA_SCOPE_AS:
- cli_msg(-1017, "Global");
- break;
- case LSA_SCOPE_AREA:
- cli_msg(-1017, "Area %R", hea[i]->domain);
- break;
-#ifdef OSPFv3
- case LSA_SCOPE_LINK:
- {
- struct iface *ifa = if_find_by_index(hea[i]->domain);
- cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?");
- }
- break;
-#endif
+ case LSA_SCOPE_AS:
+ cli_msg(-1017, "Global");
+ break;
+
+ case LSA_SCOPE_AREA:
+ cli_msg(-1017, "Area %R", hea[i]->domain);
+ break;
+
+ case LSA_SCOPE_LINK:
+ {
+ struct iface *ifa = if_find_by_index(hea[i]->domain);
+ cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?");
+ }
+ break;
}
cli_msg(-1017, "");
- cli_msg(-1017," Type LS ID Router Age Sequence Checksum");
+ cli_msg(-1017," Type LS ID Router Sequence Age Checksum");
last_dscope = dscope;
last_domain = hea[i]->domain;
}
-
- cli_msg(-1017," %04x %-15R %-15R %5u %08x %04x",
- lsa->type, lsa->id, lsa->rt, lsa->age, lsa->sn, lsa->checksum);
+ cli_msg(-1017," %04x %-15R %-15R %08x %5u %04x",
+ lsa_type, lsa->id, lsa->rt, lsa->sn, lsa->age, lsa->checksum);
}
cli_msg(0, "");
}
struct protocol proto_ospf = {
- name: "OSPF",
- template: "ospf%d",
- attr_class: EAP_OSPF,
- preference: DEF_PREF_OSPF,
- init: ospf_init,
- dump: ospf_dump,
- start: ospf_start,
- shutdown: ospf_shutdown,
- reconfigure: ospf_reconfigure,
- get_status: ospf_get_status,
- get_attr: ospf_get_attr,
- get_route_info: ospf_get_route_info
- // show_proto_info: ospf_sh
+ .name = "OSPF",
+ .template = "ospf%d",
+ .attr_class = EAP_OSPF,
+ .preference = DEF_PREF_OSPF,
+ .init = ospf_init,
+ .dump = ospf_dump,
+ .start = ospf_start,
+ .shutdown = ospf_shutdown,
+ .reconfigure = ospf_reconfigure,
+ .get_status = ospf_get_status,
+ .get_attr = ospf_get_attr,
+ .get_route_info = ospf_get_route_info
};
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index d7b3d57a..c324f431 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -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.
*/
@@ -9,23 +11,6 @@
#ifndef _BIRD_OSPF_H_
#define _BIRD_OSPF_H_
-#define MAXNETS 10
-#define OSPF_MIN_PKT_SIZE 256
-#define OSPF_MAX_PKT_SIZE 65535
-
-#ifdef LOCAL_DEBUG
-#define OSPF_FORCE_DEBUG 1
-#else
-#define OSPF_FORCE_DEBUG 0
-#endif
-#define OSPF_TRACE(flags, msg, args...) do { if ((p->debug & flags) || OSPF_FORCE_DEBUG) \
- log(L_TRACE "%s: " msg, p->name , ## args ); } while(0)
-
-#define OSPF_PACKET(dumpfn, buffer, msg, args...) \
-do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
-{ log(L_TRACE "%s: " msg, p->name, ## args ); dumpfn(p, buffer); } } while(0)
-
-
#include "nest/bird.h"
#include "lib/checksum.h"
@@ -44,33 +29,61 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
#include "conf/conf.h"
#include "lib/string.h"
-#define OSPF_PROTO 89
-#ifndef IPV6
-#define OSPFv2 1
-#define OSPF_VERSION 2
-#define OSPF_VLINK_MTU 576 /* RFC 2328 A.1 */
-#define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */
-#define AllDRouters ipa_from_u32(0xe0000006) /* 224.0.0.6 */
+#ifdef LOCAL_DEBUG
+#define OSPF_FORCE_DEBUG 1
+#else
+#define OSPF_FORCE_DEBUG 0
+#endif
+
+
+#ifdef IPV6
+#define OSPF_IS_V2 0
#else
-#define OSPFv3 1
-#define OSPF_VERSION 3
-#define OSPF_VLINK_MTU 1280 /* RFC 5340 A.1 */
-#define AllSPFRouters _MI(0xFF020000, 0, 0, 5) /* FF02::5 */
-#define AllDRouters _MI(0xFF020000, 0, 0, 6) /* FF02::6 */
+#define OSPF_IS_V2 1
#endif
+// FIXME: MAX_PREFIX_LENGTH
+
+#define OSPF_TRACE(flags, msg, args...) \
+ do { if ((p->p.debug & flags) || OSPF_FORCE_DEBUG) \
+ log(L_TRACE "%s: " msg, p->p.name , ## args ); } while(0)
+
+#define OSPF_PACKET(dumpfn, buffer, msg, args...) \
+ do { if ((p->p.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
+ { log(L_TRACE "%s: " msg, p->p.name, ## args ); dumpfn(p, buffer); } } while(0)
+
+#define LOG_PKT(msg, args...) \
+ log_rl(&p->log_pkt_tbf, L_REMOTE "%s: " msg, p->p.name, args)
+
+#define LOG_PKT_AUTH(msg, args...) \
+ log_rl(&p->log_pkt_tbf, L_AUTH "%s: " msg, p->p.name, args)
+
+#define LOG_PKT_WARN(msg, args...) \
+ log_rl(&p->log_pkt_tbf, L_WARN "%s: " msg, p->p.name, args)
+
+#define LOG_LSA1(msg, args...) \
+ log_rl(&p->log_lsa_tbf, L_REMOTE "%s: " msg, p->p.name, args)
+
+#define LOG_LSA2(msg, args...) \
+ do { if (! p->log_lsa_tbf.mark) \
+ log(L_REMOTE "%s: " msg, p->p.name, args); } while(0)
+
+
+#define OSPF_PROTO 89
#define LSREFRESHTIME 1800 /* 30 minutes */
#define MINLSINTERVAL 5
#define MINLSARRIVAL 1
#define LSINFINITY 0xffffff
-#define DEFAULT_OSPFTICK 1
-#define DEFAULT_RFC1583 0 /* compatibility with rfc1583 */
-#define DEFAULT_STUB_COST 1000
-#define DEFAULT_ECMP_LIMIT 16
-#define DEFAULT_TRANSINT 40
+#define OSPF_DEFAULT_TICK 1
+#define OSPF_DEFAULT_STUB_COST 1000
+#define OSPF_DEFAULT_ECMP_LIMIT 16
+#define OSPF_DEFAULT_TRANSINT 40
+
+#define OSPF_MIN_PKT_SIZE 256
+#define OSPF_MAX_PKT_SIZE 65535
#define OSPF_VLINK_ID_OFFSET 0x80000000
@@ -78,99 +91,177 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
struct ospf_config
{
struct proto_config c;
- unsigned tick;
- byte rfc1583;
- byte stub_router;
- byte merge_external;
- byte abr;
+ uint tick;
+ u8 ospf2;
+ u8 rfc1583;
+ u8 stub_router;
+ u8 merge_external;
+ u8 instance_id;
+ u8 abr;
+ u8 asbr;
int ecmp;
- list area_list; /* list of struct ospf_area_config */
- list vlink_list; /* list of struct ospf_iface_patt */
+ list area_list; /* list of area configs (struct ospf_area_config) */
+ list vlink_list; /* list of configured vlinks (struct ospf_iface_patt) */
};
-struct nbma_node
+struct ospf_area_config
{
node n;
- ip_addr ip;
- byte eligible;
- byte found;
+ u32 areaid;
+ u32 default_cost; /* Cost of default route for stub areas
+ (With possible LSA_EXT3_EBIT for NSSA areas) */
+ u8 type; /* Area type (standard, stub, NSSA), represented
+ by option flags (OPT_E, OPT_N) */
+ u8 summary; /* Import summaries to this stub/NSSA area, valid for ABR */
+ u8 default_nssa; /* Generate default NSSA route for NSSA+summary area */
+ u8 translator; /* Translator role, for NSSA ABR */
+ u32 transint; /* Translator stability interval */
+ list patt_list; /* List of iface configs (struct ospf_iface_patt) */
+ list net_list; /* List of aggregate networks for that area */
+ list enet_list; /* List of aggregate external (NSSA) networks */
+ list stubnet_list; /* List of stub networks added to Router LSA */
};
struct area_net_config
{
node n;
struct prefix px;
- int hidden;
u32 tag;
+ u8 hidden;
};
struct area_net
{
struct fib_node fn;
- int hidden;
- int active;
- u32 metric;
+ u32 metric; /* With possible LSA_EXT3_EBIT for NSSA area nets */
u32 tag;
+ u8 hidden;
+ u8 active;
};
struct ospf_stubnet_config
{
node n;
struct prefix px;
- int hidden, summary;
u32 cost;
+ u8 hidden;
+ u8 summary;
};
-struct ospf_area_config
+struct nbma_node
{
node n;
- u32 areaid;
- u32 default_cost; /* Cost of default route for stub areas */
- u8 type; /* Area type (standard, stub, NSSA), represented
- by option flags (OPT_E, OPT_N) */
- u8 summary; /* Import summaries to this stub/NSSA area, valid for ABR */
- u8 default_nssa; /* Generate default NSSA route for NSSA+summary area */
- u8 translator; /* Translator role, for NSSA ABR */
- u32 transint; /* Translator stability interval */
- list patt_list;
- list net_list; /* List of aggregate networks for that area */
- list enet_list; /* List of aggregate external (NSSA) networks */
- list stubnet_list; /* List of stub networks added to Router LSA */
+ ip_addr ip;
+ byte eligible;
+ byte found;
};
+struct ospf_iface_patt
+{
+ struct iface_patt i;
+ u32 type;
+ u32 stub;
+ u32 cost;
+ u32 helloint;
+ u32 rxmtint;
+ u32 pollint;
+ u32 waitint;
+ u32 deadc;
+ u32 deadint;
+ u32 inftransdelay;
+ list nbma_list;
+ u32 priority;
+ u32 voa;
+ u32 vid;
+ int tx_tos;
+ int tx_priority;
+ u16 tx_length;
+ u16 rx_buffer;
-/* Option flags */
+#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
+ u8 instance_id;
+ u8 autype; /* Not really used in OSPFv3 */
+#define OSPF_AUTH_NONE 0
+#define OSPF_AUTH_SIMPLE 1
+#define OSPF_AUTH_CRYPT 2
+#define OSPF_AUTH_CRYPT_SIZE 16
+ u8 strictnbma;
+ u8 check_link;
+ u8 ecmp_weight;
+ u8 link_lsa_suppression;
+ u8 real_bcast; /* Not really used in OSPFv3 */
+ u8 ptp_netmask; /* bool + 2 for unspecified */
+ u8 ttl_security; /* bool + 2 for TX only */
+ u8 bfd;
+ u8 bsd_secondary;
+ list *passwords;
+};
-#define OPT_E 0x02
-#define OPT_N 0x08
-#define OPT_DC 0x20
+/* Default values for interface parameters */
+#define COST_D 10
+#define RXMTINT_D 5
+#define INFTRANSDELAY_D 1
+#define PRIORITY_D 1
+#define HELLOINT_D 10
+#define POLLINT_D 20
+#define DEADC_D 4
+#define WAIT_DMH 4
+ /* Value of Wait timer - not found it in RFC * - using 4*HELLO */
-#ifdef OSPFv2
-#define OPT_P 0x08 /* flags P and N share position, see NSSA RFC */
-#define OPT_EA 0x10
-/* VEB flags are are stored independently in 'u16 options' */
-#define OPT_RT_B (0x01 << 8)
-#define OPT_RT_E (0x02 << 8)
-#define OPT_RT_V (0x04 << 8)
-#define OPT_RT_NT (0x10 << 8)
-#endif
-#ifdef OSPFv3
-#define OPT_V6 0x01
-#define OPT_R 0x10
+struct ospf_proto
+{
+ struct proto p;
+ timer *disp_timer; /* OSPF proto dispatcher */
+ uint tick;
+ struct top_graph *gr; /* LSA graph */
+ slist lsal; /* List of all LSA's */
+ int calcrt; /* Routing table calculation scheduled?
+ 0=no, 1=normal, 2=forced reload */
+ list iface_list; /* List of OSPF interfaces (struct ospf_iface) */
+ list area_list; /* List of OSPF areas (struct ospf_area) */
+ int areano; /* Number of area I belong to */
+ int padj; /* Number of neighbors in Exchange or Loading state */
+ struct fib rtf; /* Routing table */
+ byte ospf2; /* OSPF v2 or v3 */
+ byte rfc1583; /* RFC1583 compatibility */
+ byte stub_router; /* Do not forward transit traffic */
+ byte merge_external; /* Should i merge external routes? */
+ byte asbr; /* May i originate any ext/NSSA lsa? */
+ byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
+ struct ospf_area *backbone; /* If exists */
+ event *flood_event; /* Event for flooding LS updates */
+ void *lsab; /* LSA buffer used when originating router LSAs */
+ int lsab_size, lsab_used;
+ linpool *nhpool; /* Linpool used for next hops computed in SPF */
+ sock *vlink_sk; /* IP socket used for vlink TX */
+ u32 router_id;
+ u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */
+ struct tbf log_pkt_tbf; /* TBF for packet messages */
+ struct tbf log_lsa_tbf; /* TBF for LSA messages */
+};
-/* VEB flags are are stored together with options in 'u32 options' */
-#define OPT_RT_B (0x01 << 24)
-#define OPT_RT_E (0x02 << 24)
-#define OPT_RT_V (0x04 << 24)
-#define OPT_RT_NT (0x10 << 24)
+struct ospf_area
+{
+ node n;
+ u32 areaid;
+ struct ospf_area_config *ac; /* Related area config */
+ struct top_hash_entry *rt; /* My own router LSA */
+ struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
+ list cand; /* List of candidates for RT calc. */
+ struct fib net_fib; /* Networks to advertise or not */
+ struct fib enet_fib; /* External networks for NSSAs */
+ u32 options; /* Optional features */
+ u8 update_rt_lsa; /* Rt lsa origination scheduled? */
+ u8 trcap; /* Transit capability? */
+ u8 marked; /* Used in OSPF reconfigure */
+ u8 translate; /* Translator state (TRANS_*), for NSSA ABR */
+ timer *translator_timer; /* For NSSA translator switch */
+ struct ospf_proto *po;
+ struct fib rtr; /* Routing tables for routers */
+};
-#define OPT_PX_NU 0x01
-#define OPT_PX_LA 0x02
-#define OPT_PX_P 0x08
-#define OPT_PX_DN 0x10
-#endif
struct ospf_iface
@@ -184,7 +275,7 @@ struct ospf_iface
pool *pool;
sock *sk; /* IP socket */
- list neigh_list; /* List of neigbours */
+ list neigh_list; /* List of neighbors (struct ospf_neighbor) */
u32 cost; /* Cost of iface */
u32 waitint; /* number of sec before changing state from wait */
u32 rxmtint; /* number of seconds between LSA retransmissions */
@@ -199,154 +290,194 @@ struct ospf_iface
transmit a Link State Update Packet over this
interface. LSAs contained in the update */
u16 helloint; /* number of seconds between hello sending */
-
-#ifdef OSPFv2
list *passwords;
- u16 autype;
u32 csn; /* Last used crypt seq number */
bird_clock_t csn_use; /* Last time when packet with that CSN was sent */
-#endif
-
- ip_addr all_routers; /* */
- ip_addr drip; /* Designated router */
- ip_addr bdrip; /* Backup DR */
- u32 drid;
- u32 bdrid;
+ ip_addr all_routers; /* Multicast (or broadcast) address for all routers */
+ ip_addr des_routers; /* Multicast (or NULL) address for designated routers */
+ ip_addr drip; /* Designated router IP */
+ ip_addr bdrip; /* Backup DR IP */
+ u32 drid; /* DR Router ID */
+ u32 bdrid; /* BDR Router ID */
s16 rt_pos_beg; /* Position of iface in Router-LSA, begin, inclusive */
s16 rt_pos_end; /* Position of iface in Router-LSA, end, exclusive */
-
-#ifdef OSPFv3
s16 px_pos_beg; /* Position of iface in Rt Prefix-LSA, begin, inclusive */
s16 px_pos_end; /* Position of iface in Rt Prefix-LSA, end, exclusive */
-
u32 dr_iface_id; /* if drid is valid, this is iface_id of DR (for connecting network) */
u8 instance_id; /* Used to differentiate between more OSPF
instances on one interface */
-#endif
-
- u8 type; /* OSPF view of type */
-#define OSPF_IT_BCAST 0
-#define OSPF_IT_NBMA 1
-#define OSPF_IT_PTP 2
-#define OSPF_IT_PTMP 3
-#define OSPF_IT_VLINK 4
-#define OSPF_IT_UNDEF 5
+ u8 autype; /* Authentication type (OSPF_AUTH_*) */
+ u8 type; /* OSPF view of type (OSPF_IT_*) */
u8 strictnbma; /* Can I talk with unknown neighbors? */
u8 stub; /* Inactive interface */
- u8 state; /* Interface state machine */
-#define OSPF_IS_DOWN 0 /* Not working */
-#define OSPF_IS_LOOP 1 /* Iface with no link */
-#define OSPF_IS_WAITING 2 /* Waiting for Wait timer */
-#define OSPF_IS_PTP 3 /* PTP operational */
-#define OSPF_IS_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */
-#define OSPF_IS_BACKUP 5 /* I'm BDR */
-#define OSPF_IS_DR 6 /* I'm DR */
+ u8 state; /* Interface state machine (OSPF_IS_*) */
timer *wait_timer; /* WAIT timer */
timer *hello_timer; /* HELLOINT timer */
timer *poll_timer; /* Poll Interval - for NBMA */
-/* Default values for interface parameters */
-#define COST_D 10
-#define RXMTINT_D 5
-#define INFTRANSDELAY_D 1
-#define PRIORITY_D 1
-#define HELLOINT_D 10
-#define POLLINT_D 20
-#define DEADC_D 4
-#define WAIT_DMH 4
- /* Value of Wait timer - not found it in RFC * - using 4*HELLO */
- struct top_hash_entry *net_lsa; /* Originated network LSA */
- int orignet; /* Schedule network LSA origination */
-#ifdef OSPFv3
- int origlink; /* Schedule link LSA origination */
struct top_hash_entry *link_lsa; /* Originated link LSA */
+ struct top_hash_entry *net_lsa; /* Originated network LSA */
struct top_hash_entry *pxn_lsa; /* Originated prefix LSA */
-#endif
- int fadj; /* Number of full adjacent neigh */
+ struct top_hash_entry **flood_queue; /* LSAs queued for LSUPD */
+ u8 update_link_lsa;
+ u8 update_net_lsa;
+ u16 flood_queue_used; /* The current number of LSAs in flood_queue */
+ u16 flood_queue_size; /* The maximum number of LSAs in flood_queue */
+ int fadj; /* Number of fully adjacent neighbors */
list nbma_list;
u8 priority; /* A router priority for DR election */
u8 ioprob;
#define OSPF_I_OK 0 /* Everything OK */
#define OSPF_I_SK 1 /* Socket open failed */
#define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */
- u8 sk_dr; /* Socket is a member of DRouters group */
- u8 marked; /* Used in OSPF reconfigure */
+ u8 sk_dr; /* Socket is a member of designated routers group */
+ u8 marked; /* Used in OSPF reconfigure, 2 for force restart */
u16 rxbuf; /* Buffer size */
u16 tx_length; /* Soft TX packet length limit, usually MTU */
u8 check_link; /* Whether iface link change is used */
u8 ecmp_weight; /* Weight used for ECMP */
+ u8 link_lsa_suppression; /* Suppression of Link-LSA origination */
u8 ptp_netmask; /* Send real netmask for P2P */
u8 check_ttl; /* Check incoming packets for TTL 255 */
u8 bfd; /* Use BFD on iface */
};
-struct ospf_md5
+struct ospf_neighbor
{
- u16 zero;
- u8 keyid;
- u8 len;
- u32 csn;
-};
+ node n;
+ pool *pool;
+ struct ospf_iface *ifa;
+ u8 state;
+ timer *inactim; /* Inactivity timer */
+ u8 imms; /* I, M, Master/slave received */
+ u8 myimms; /* I, M Master/slave */
+ u32 dds; /* DD Sequence number being sent */
+ u32 ddr; /* last Dat Des packet received */
-union ospf_auth
-{
- u8 password[8];
- struct ospf_md5 md5;
+ u32 rid; /* Router ID */
+ ip_addr ip; /* IP of it's interface */
+ u8 priority; /* Priority */
+ u8 adj; /* built adjacency? */
+ u32 options; /* Options received */
+
+ /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in
+ OSPFv3, we use the same type to simplify handling */
+ u32 dr; /* Neighbor's idea of DR */
+ u32 bdr; /* Neighbor's idea of BDR */
+ u32 iface_id; /* ID of Neighbour's iface connected to common network */
+
+ /* Database summary list iterator, controls initial dbdes exchange.
+ * Advances in the LSA list as dbdes packets are sent.
+ */
+ siterator dbsi; /* iterator of po->lsal */
+
+ /* Link state request list, controls initial LSA exchange.
+ * Entries added when received in dbdes packets, removed as sent in lsreq packets.
+ */
+ slist lsrql; /* slist of struct top_hash_entry from n->lsrqh */
+ struct top_graph *lsrqh;
+ struct top_hash_entry *lsrqi; /* Pointer to the first unsent node in lsrql */
+
+ /* Link state retransmission list, controls LSA retransmission during flood.
+ * Entries added as sent in lsupd packets, removed when received in lsack packets.
+ * These entries hold ret_count in appropriate LSA entries.
+ */
+ slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */
+ struct top_graph *lsrth;
+ timer *dbdes_timer; /* DBDES exchange timer */
+ timer *lsrq_timer; /* LSA request timer */
+ timer *lsrt_timer; /* LSA retransmission timer */
+ list ackl[2];
+#define ACKL_DIRECT 0
+#define ACKL_DELAY 1
+ timer *ackd_timer; /* Delayed ack timer */
+ struct bfd_request *bfd_req; /* BFD request, if BFD is used */
+ void *ldd_buffer; /* Last database description packet */
+ u32 ldd_bsize; /* Buffer size for ldd_buffer */
+ u32 csn; /* Last received crypt seq number (for MD5) */
};
-/* Packet types */
-#define HELLO_P 1 /* Hello */
-#define DBDES_P 2 /* Database description */
-#define LSREQ_P 3 /* Link state request */
-#define LSUPD_P 4 /* Link state update */
-#define LSACK_P 5 /* Link state acknowledgement */
+/* OSPF interface types */
+#define OSPF_IT_BCAST 0
+#define OSPF_IT_NBMA 1
+#define OSPF_IT_PTP 2
+#define OSPF_IT_PTMP 3
+#define OSPF_IT_VLINK 4
+#define OSPF_IT_UNDEF 5
-/* Area IDs */
-#define BACKBONE 0
+/* OSPF interface states */
+#define OSPF_IS_DOWN 0 /* Not active */
+#define OSPF_IS_LOOP 1 /* Iface with no link */
+#define OSPF_IS_WAITING 2 /* Waiting for Wait timer */
+#define OSPF_IS_PTP 3 /* PTP operational */
+#define OSPF_IS_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */
+#define OSPF_IS_BACKUP 5 /* I'm BDR */
+#define OSPF_IS_DR 6 /* I'm DR */
+/* Definitions for interface state machine */
+#define ISM_UP 0 /* Interface Up */
+#define ISM_WAITF 1 /* Wait timer fired */
+#define ISM_BACKS 2 /* Backup seen */
+#define ISM_NEICH 3 /* Neighbor change */
+#define ISM_LOOP 4 /* Link down */
+#define ISM_UNLOOP 5 /* Link up */
+#define ISM_DOWN 6 /* Interface down */
-struct immsb
-{
-#ifdef CPU_BIG_ENDIAN
- u8 padding:5;
- u8 i:1;
- u8 m:1;
- u8 ms:1;
-#else
- u8 ms:1;
- u8 m:1;
- u8 i:1;
- u8 padding:5;
-#endif
-}__attribute__((packed));
-union imms
-{
- u8 byte;
- struct immsb bit;
-}__attribute__((packed));
-#define DBDES_MS 1
-#define DBDES_M 2
-#define DBDES_I 4
+/* OSPF neighbor states */
+#define NEIGHBOR_DOWN 0
+#define NEIGHBOR_ATTEMPT 1
+#define NEIGHBOR_INIT 2
+#define NEIGHBOR_2WAY 3
+#define NEIGHBOR_EXSTART 4
+#define NEIGHBOR_EXCHANGE 5
+#define NEIGHBOR_LOADING 6
+#define NEIGHBOR_FULL 7
+/* Definitions for neighbor state machine */
+#define INM_HELLOREC 0 /* Hello Received */
+#define INM_START 1 /* Neighbor start - for NBMA */
+#define INM_2WAYREC 2 /* 2-Way received */
+#define INM_NEGDONE 3 /* Negotiation done */
+#define INM_EXDONE 4 /* Exchange done */
+#define INM_BADLSREQ 5 /* Bad LS Request */
+#define INM_LOADDONE 6 /* Load done */
+#define INM_ADJOK 7 /* AdjOK? */
+#define INM_SEQMIS 8 /* Sequence number mismatch */
+#define INM_1WAYREC 9 /* 1-Way */
+#define INM_KILLNBR 10 /* Kill Neighbor */
+#define INM_INACTTIM 11 /* Inactivity timer */
+#define INM_LLDOWN 12 /* Line down */
-#ifdef OSPFv2
+#define TRANS_OFF 0
+#define TRANS_ON 1
+#define TRANS_WAIT 2 /* Waiting before the end of translation */
-struct ospf_packet
-{
- u8 version;
- u8 type;
- u16 length;
- u32 routerid;
- u32 areaid;
- u16 checksum;
- u16 autype;
- union ospf_auth u;
-};
-#else /* OSPFv3 packet descriptions */
+/* Generic option flags */
+#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */
+#define OPT_E 0x02 /* Related to AS-external LSAs */
+#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */
+#define OPT_N 0x08 /* Related to NSSA */
+#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */
+#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */
+#define OPT_R 0x10 /* OSPFv3, originator is active router */
+#define OPT_DC 0x20 /* Related to demand circuits, not used */
+
+/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
+#define OPT_RT_B (0x01 << 24)
+#define OPT_RT_E (0x02 << 24)
+#define OPT_RT_V (0x04 << 24)
+#define OPT_RT_NT (0x10 << 24)
+
+/* Prefix flags, specific for OSPFv3 */
+#define OPT_PX_NU 0x01
+#define OPT_PX_LA 0x02
+#define OPT_PX_P 0x08
+#define OPT_PX_DN 0x10
+
struct ospf_packet
{
@@ -356,41 +487,37 @@ struct ospf_packet
u32 routerid;
u32 areaid;
u16 checksum;
- u8 instance_id;
- u8 zero;
+ u8 instance_id; /* See RFC 6549 */
+ u8 autype; /* Undefined for OSPFv3 */
};
-
-#endif
-
-
-
-
-struct ospf_lsa_header
+struct ospf_md5
{
- u16 age; /* LS Age */
-#define LSA_MAXAGE 3600 /* 1 hour */
-#define LSA_CHECKAGE 300 /* 5 minutes */
-#define LSA_MAXAGEDIFF 900 /* 15 minutes */
+ u16 zero;
+ u8 keyid;
+ u8 len;
+ u32 csn;
+};
-#ifdef OSPFv2
- u8 options;
- u8 type;
+union ospf_auth
+{
+ u8 password[8];
+ struct ospf_md5 md5;
+};
-#define LSA_T_RT 1
-#define LSA_T_NET 2
-#define LSA_T_SUM_NET 3
-#define LSA_T_SUM_RT 4
-#define LSA_T_EXT 5
-#define LSA_T_NSSA 7
+/* Packet types */
+#define HELLO_P 1 /* Hello */
+#define DBDES_P 2 /* Database description */
+#define LSREQ_P 3 /* Link state request */
+#define LSUPD_P 4 /* Link state update */
+#define LSACK_P 5 /* Link state acknowledgement */
-#define LSA_SCOPE_AREA 0x2000
-#define LSA_SCOPE_AS 0x4000
-#define LSA_SCOPE(lsa) (((lsa)->type == LSA_T_EXT) ? LSA_SCOPE_AS : LSA_SCOPE_AREA)
+#define DBDES_I 4 /* Init bit */
+#define DBDES_M 2 /* More bit */
+#define DBDES_MS 1 /* Master/Slave bit */
+#define DBDES_IMMS (DBDES_I | DBDES_M | DBDES_MS)
-#else /* OSPFv3 */
- u16 type;
#define LSA_T_RT 0x2001
#define LSA_T_NET 0x2002
@@ -401,6 +528,8 @@ struct ospf_lsa_header
#define LSA_T_LINK 0x0008
#define LSA_T_PREFIX 0x2009
+#define LSA_T_V2_MASK 0x00ff
+
#define LSA_UBIT 0x8000
#define LSA_SCOPE_LINK 0x0000
@@ -408,91 +537,93 @@ struct ospf_lsa_header
#define LSA_SCOPE_AS 0x4000
#define LSA_SCOPE_RES 0x6000
#define LSA_SCOPE_MASK 0x6000
+#define LSA_SCOPE(type) ((type) & LSA_SCOPE_MASK)
-#define LSA_SCOPE(lsa) ((lsa)->type & LSA_SCOPE_MASK)
-#endif
+
+#define LSA_MAXAGE 3600 /* 1 hour */
+#define LSA_CHECKAGE 300 /* 5 minutes */
+#define LSA_MAXAGEDIFF 900 /* 15 minutes */
+
+#define LSA_ZEROSEQNO ((s32) 0x80000000)
+#define LSA_INITSEQNO ((s32) 0x80000001)
+#define LSA_MAXSEQNO ((s32) 0x7fffffff)
+
+#define LSA_METRIC_MASK 0x00FFFFFF
+#define LSA_OPTIONS_MASK 0x00FFFFFF
+
+
+#define LSART_PTP 1
+#define LSART_NET 2
+#define LSART_STUB 3
+#define LSART_VLNK 4
+
+#define LSA_RT2_LINKS 0x0000FFFF
+
+#define LSA_SUM2_TOS 0xFF000000
+
+#define LSA_EXT2_TOS 0x7F000000
+#define LSA_EXT2_EBIT 0x80000000
+
+#define LSA_EXT3_EBIT 0x4000000
+#define LSA_EXT3_FBIT 0x2000000
+#define LSA_EXT3_TBIT 0x1000000
+
+
+struct ospf_lsa_header
+{
+ u16 age; /* LS Age */
+ u16 type_raw; /* Type, mixed with options on OSPFv2 */
u32 id;
u32 rt; /* Advertising router */
s32 sn; /* LS Sequence number */
-#define LSA_INITSEQNO ((s32) 0x80000001)
-#define LSA_MAXSEQNO ((s32) 0x7fffffff)
u16 checksum;
u16 length;
};
-#define LSART_PTP 1
-#define LSART_NET 2
-#define LSART_STUB 3
-#define LSART_VLNK 4
+/* In OSPFv2, options are embedded in higher half of type_raw */
+static inline u8 lsa_get_options(struct ospf_lsa_header *lsa)
+{ return lsa->type_raw >> 8; }
+static inline void lsa_set_options(struct ospf_lsa_header *lsa, u16 options)
+{ lsa->type_raw = (lsa->type_raw & 0xff) | (options << 8); }
-#ifdef OSPFv2
struct ospf_lsa_rt
{
-#ifdef CPU_BIG_ENDIAN
- u16 options; /* VEB flags only */
- u16 links;
-#else
- u16 links;
- u16 options; /* VEB flags only */
-#endif
+ u32 options; /* VEB flags, mixed with link count for OSPFv2 and options for OSPFv3 */
};
-struct ospf_lsa_rt_link
+struct ospf_lsa_rt2_link
{
u32 id;
u32 data;
#ifdef CPU_BIG_ENDIAN
u8 type;
- u8 padding;
+ u8 no_tos;
u16 metric;
#else
u16 metric;
- u8 padding;
+ u8 no_tos;
u8 type;
#endif
};
-struct ospf_lsa_net
-{
- ip_addr netmask;
- u32 routers[];
-};
-
-struct ospf_lsa_sum
-{
- ip_addr netmask;
- u32 metric;
-};
-
-struct ospf_lsa_ext
-{
- ip_addr netmask;
- u32 metric;
- ip_addr fwaddr;
- u32 tag;
-};
-
-#define LSA_SUM_TOS 0xFF000000
-#define LSA_EXT_TOS 0x7F000000
-#define LSA_EXT_EBIT 0x80000000
-
-/* Endianity swap for lsa->type */
-#define ntoht(x) x
-#define htont(x) x
-
-
-#else /* OSPFv3 */
-
-struct ospf_lsa_rt
+struct ospf_lsa_rt2_tos
{
- u32 options;
+#ifdef CPU_BIG_ENDIAN
+ u8 tos;
+ u8 padding;
+ u16 metric;
+#else
+ u16 metric;
+ u8 padding;
+ u8 tos;
+#endif
};
-struct ospf_lsa_rt_link
+struct ospf_lsa_rt3_link
{
#ifdef CPU_BIG_ENDIAN
u8 type;
@@ -508,35 +639,58 @@ struct ospf_lsa_rt_link
u32 id; /* Neighbor router ID */
};
+
struct ospf_lsa_net
{
- u32 options;
+ u32 optx; /* Netmask for OSPFv2, options for OSPFv3 */
u32 routers[];
};
-struct ospf_lsa_sum_net
+struct ospf_lsa_sum2
+{
+ u32 netmask;
+ u32 metric;
+};
+
+struct ospf_lsa_sum3_net
{
u32 metric;
u32 prefix[];
};
-struct ospf_lsa_sum_rt
+struct ospf_lsa_sum3_rt
{
u32 options;
u32 metric;
u32 drid;
};
-struct ospf_lsa_ext
+struct ospf_lsa_ext2
+{
+ u32 netmask;
+ u32 metric;
+ u32 fwaddr;
+ u32 tag;
+};
+
+struct ospf_lsa_ext3
{
u32 metric;
u32 rest[];
};
+struct ospf_lsa_ext_local
+{
+ ip_addr ip, fwaddr;
+ int pxlen;
+ u32 metric, ebit, fbit, tag, propagate;
+ u8 pxopts;
+};
+
struct ospf_lsa_link
{
u32 options;
- ip_addr lladdr;
+ ip6_addr lladdr;
u32 pxcount;
u32 rest[];
};
@@ -555,39 +709,26 @@ struct ospf_lsa_prefix
u32 rest[];
};
-#define LSA_EXT_EBIT 0x4000000
-#define LSA_EXT_FBIT 0x2000000
-#define LSA_EXT_TBIT 0x1000000
-
-/* Endianity swap for lsa->type */
-#define ntoht(x) ntohs(x)
-#define htont(x) htons(x)
-
-#endif
-
-#define METRIC_MASK 0x00FFFFFF
-#define OPTIONS_MASK 0x00FFFFFF
-
-static inline unsigned
-lsa_rt_count(struct ospf_lsa_header *lsa)
-{
- return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_rt))
- / sizeof(struct ospf_lsa_rt_link);
-}
-static inline unsigned
+static inline uint
lsa_net_count(struct ospf_lsa_header *lsa)
{
return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net))
/ sizeof(u32);
}
+/* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address)
+ as index, so we need to encapsulate RID to IP address */
-#ifdef OSPFv3
+#define ipa_from_rid(x) ipa_from_u32(x)
+#define ipa_to_rid(x) ipa_to_u32(x)
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
+/* FIXME: these four functions should be significantly redesigned w.r.t. integration,
+ also should be named as ospf3_* instead of *_ipv6_* */
+
static inline u32 *
lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest)
{
@@ -599,6 +740,7 @@ lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest)
*addr = IPA_NONE;
+#ifdef IPV6
if (pxl > 0)
_I0(*addr) = *buf++;
if (pxl > 32)
@@ -611,6 +753,7 @@ lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest)
/* Clean up remaining bits */
if (pxl < 128)
addr->addr[pxl / 32] &= u32_mkmask(pxl % 32);
+#endif
return buf;
}
@@ -625,6 +768,7 @@ lsa_get_ipv6_addr(u32 *buf, ip_addr *addr)
static inline u32 *
put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh)
{
+#ifdef IPV6
*buf++ = ((pxlen << 24) | (pxopts << 16) | lh);
if (pxlen > 0)
@@ -635,6 +779,7 @@ put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh)
*buf++ = _I2(addr);
if (pxlen > 96)
*buf++ = _I3(addr);
+#endif
return buf;
}
@@ -645,257 +790,179 @@ put_ipv6_addr(u32 *buf, ip_addr addr)
return buf + 4;
}
-#endif
-
-
struct ospf_lsreq_header
{
u32 type;
u32 id;
- u32 rt; /* Advertising router */
+ u32 rt;
};
-struct l_lsr_head
-{
- node n;
- struct ospf_lsreq_header lsh;
-};
-struct ospf_neighbor
-{
- node n;
- pool *pool;
- struct ospf_iface *ifa;
- u8 state;
-#define NEIGHBOR_DOWN 0
-#define NEIGHBOR_ATTEMPT 1
-#define NEIGHBOR_INIT 2
-#define NEIGHBOR_2WAY 3
-#define NEIGHBOR_EXSTART 4
-#define NEIGHBOR_EXCHANGE 5
-#define NEIGHBOR_LOADING 6
-#define NEIGHBOR_FULL 7
- timer *inactim; /* Inactivity timer */
- union imms imms; /* I, M, Master/slave received */
- u32 dds; /* DD Sequence number being sent */
- u32 ddr; /* last Dat Des packet received */
- union imms myimms; /* I, M Master/slave */
- u32 rid; /* Router ID */
- ip_addr ip; /* IP of it's interface */
- u8 priority; /* Priority */
- u8 adj; /* built adjacency? */
- u32 options; /* Options received */
-
- /* dr and bdr store IP address in OSPFv2 and router ID in OSPFv3,
- we use the same type to simplify handling */
- u32 dr; /* Neigbour's idea of DR */
- u32 bdr; /* Neigbour's idea of BDR */
-
-#ifdef OSPFv3
- u32 iface_id; /* ID of Neighbour's iface connected to common network */
-#endif
+#define SH_ROUTER_SELF 0xffffffff
- siterator dbsi; /* Database summary list iterator */
- slist lsrql; /* Link state request */
- struct top_graph *lsrqh; /* LSA graph */
- siterator lsrqi;
- slist lsrtl; /* Link state retransmission list */
- siterator lsrti;
- struct top_graph *lsrth;
- timer *rxmt_timer; /* RXMT timer */
- list ackl[2];
-#define ACKL_DIRECT 0
-#define ACKL_DELAY 1
- timer *ackd_timer; /* Delayed ack timer */
- struct bfd_request *bfd_req; /* BFD request, if BFD is used */
- void *ldd_buffer; /* Last database description packet */
- u32 ldd_bsize; /* Buffer size for ldd_buffer */
- u32 csn; /* Last received crypt seq number (for MD5) */
+struct lsadb_show_data {
+ struct symbol *name; /* Protocol to request data from */
+ u16 type; /* LSA Type, 0 -> all */
+ u16 scope; /* Scope, 0 -> all, hack to handle link scope as 1 */
+ u32 area; /* Specified for area scope */
+ u32 lsid; /* LSA ID, 0 -> all */
+ u32 router; /* Advertising router, 0 -> all */
};
-/* Definitions for interface state machine */
-#define ISM_UP 0 /* Interface Up */
-#define ISM_WAITF 1 /* Wait timer fired */
-#define ISM_BACKS 2 /* Backup seen */
-#define ISM_NEICH 3 /* Neighbor change */
-#define ISM_LOOP 4 /* Link down */
-#define ISM_UNLOOP 5 /* Link up */
-#define ISM_DOWN 6 /* Interface down */
-/* Definitions for neighbor state machine */
-#define INM_HELLOREC 0 /* Hello Received */
-#define INM_START 1 /* Neighbor start - for NBMA */
-#define INM_2WAYREC 2 /* 2-Way received */
-#define INM_NEGDONE 3 /* Negotiation done */
-#define INM_EXDONE 4 /* Exchange done */
-#define INM_BADLSREQ 5 /* Bad LS Request */
-#define INM_LOADDONE 6 /* Load done */
-#define INM_ADJOK 7 /* AdjOK? */
-#define INM_SEQMIS 8 /* Sequence number mismatch */
-#define INM_1WAYREC 9 /* 1-Way */
-#define INM_KILLNBR 10 /* Kill Neighbor */
-#define INM_INACTTIM 11 /* Inactivity timer */
-#define INM_LLDOWN 12 /* Line down */
+#define EA_OSPF_METRIC1 EA_CODE(EAP_OSPF, 0)
+#define EA_OSPF_METRIC2 EA_CODE(EAP_OSPF, 1)
+#define EA_OSPF_TAG EA_CODE(EAP_OSPF, 2)
+#define EA_OSPF_ROUTER_ID EA_CODE(EAP_OSPF, 3)
-struct ospf_area
-{
- node n;
- u32 areaid;
- struct ospf_area_config *ac; /* Related area config */
- struct top_hash_entry *rt; /* My own router LSA */
- struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
- list cand; /* List of candidates for RT calc. */
- struct fib net_fib; /* Networks to advertise or not */
- struct fib enet_fib; /* External networks for NSSAs */
- u32 options; /* Optional features */
- byte origrt; /* Rt lsa origination scheduled? */
- byte trcap; /* Transit capability? */
- byte marked; /* Used in OSPF reconfigure */
- byte translate; /* Translator state (TRANS_*), for NSSA ABR */
- timer *translator_timer; /* For NSSA translator switch */
- struct proto_ospf *po;
- struct fib rtr; /* Routing tables for routers */
-};
-#define TRANS_OFF 0
-#define TRANS_ON 1
-#define TRANS_WAIT 2 /* Waiting before the end of translation */
+/* ospf.c */
+void ospf_schedule_rtcalc(struct ospf_proto *p);
-struct proto_ospf
-{
- struct proto proto;
- timer *disp_timer; /* OSPF proto dispatcher */
- unsigned tick;
- struct top_graph *gr; /* LSA graph */
- slist lsal; /* List of all LSA's */
- int calcrt; /* Routing table calculation scheduled?
- 0=no, 1=normal, 2=forced reload */
- list iface_list; /* Interfaces we really use */
- list area_list;
- int areano; /* Number of area I belong to */
- struct fib rtf; /* Routing table */
- byte rfc1583; /* RFC1583 compatibility */
- byte stub_router; /* Do not forward transit traffic */
- byte merge_external; /* Should i merge external routes? */
- byte ebit; /* Did I originate any ext lsa? */
- byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
- struct ospf_area *backbone; /* If exists */
- void *lsab; /* LSA buffer used when originating router LSAs */
- int lsab_size, lsab_used;
- linpool *nhpool; /* Linpool used for next hops computed in SPF */
- sock *vlink_sk; /* IP socket used for vlink TX */
- u32 router_id;
- u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */
-};
+static inline void ospf_notify_rt_lsa(struct ospf_area *oa)
+{ oa->update_rt_lsa = 1; }
-struct ospf_iface_patt
-{
- struct iface_patt i;
- u32 type;
- u32 stub;
- u32 cost;
- u32 helloint;
- u32 rxmtint;
- u32 pollint;
- u32 waitint;
- u32 deadc;
- u32 deadint;
- u32 inftransdelay;
- list nbma_list;
- u32 priority;
- u32 voa;
- u32 vid;
- int tx_tos;
- int tx_priority;
- u16 tx_length;
- u16 rx_buffer;
+static inline void ospf_notify_net_lsa(struct ospf_iface *ifa)
+{ ifa->update_net_lsa = 1; }
-#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
- u16 autype; /* Not really used in OSPFv3 */
-#define OSPF_AUTH_NONE 0
-#define OSPF_AUTH_SIMPLE 1
-#define OSPF_AUTH_CRYPT 2
-#define OSPF_AUTH_CRYPT_SIZE 16
- u8 strictnbma;
- u8 check_link;
- u8 ecmp_weight;
- u8 real_bcast; /* Not really used in OSPFv3 */
- u8 ptp_netmask; /* bool + 2 for unspecified */
- u8 ttl_security; /* bool + 2 for TX only */
- u8 bfd;
- u8 bsd_secondary;
+static inline void ospf_notify_link_lsa(struct ospf_iface *ifa)
+{ ifa->update_link_lsa = 1; }
-#ifdef OSPFv2
- list *passwords;
-#endif
-#ifdef OSPFv3
- u8 instance_id;
-#endif
-};
+#define ospf_is_v2(X) OSPF_IS_V2
+#define ospf_is_v3(X) (!OSPF_IS_V2)
+/*
+static inline int ospf_is_v2(struct ospf_proto *p)
+{ return p->ospf2; }
+
+static inline int ospf_is_v3(struct ospf_proto *p)
+{ return ! p->ospf2; }
+*/
+static inline int ospf_get_version(struct ospf_proto *p)
+{ return ospf_is_v2(p) ? 2 : 3; }
-int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
- struct linpool *pool);
-struct ea_list *ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool);
-void ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs);
-void schedule_rt_lsa(struct ospf_area *oa);
-void schedule_rtcalc(struct proto_ospf *po);
-void schedule_net_lsa(struct ospf_iface *ifa);
+struct ospf_area *ospf_find_area(struct ospf_proto *p, u32 aid);
-struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
-static inline struct ospf_area *ospf_main_area(struct proto_ospf *po)
-{ return (po->areano == 1) ? HEAD(po->area_list) : po->backbone; }
+static inline struct ospf_area *ospf_main_area(struct ospf_proto *p)
+{ return (p->areano == 1) ? HEAD(p->area_list) : p->backbone; }
static inline int oa_is_stub(struct ospf_area *oa)
{ return (oa->options & (OPT_E | OPT_N)) == 0; }
+
static inline int oa_is_ext(struct ospf_area *oa)
{ return oa->options & OPT_E; }
+
static inline int oa_is_nssa(struct ospf_area *oa)
{ return oa->options & OPT_N; }
+void ospf_sh_neigh(struct proto *P, char *iff);
+void ospf_sh(struct proto *P);
+void ospf_sh_iface(struct proto *P, char *iff);
+void ospf_sh_state(struct proto *P, int verbose, int reachable);
-#ifdef OSPFv3
-void schedule_link_lsa(struct ospf_iface *ifa);
-#else
-static inline void schedule_link_lsa(struct ospf_iface *ifa UNUSED) {}
-#endif
+void ospf_sh_lsadb(struct lsadb_show_data *ld);
-void ospf_sh_neigh(struct proto *p, char *iff);
-void ospf_sh(struct proto *p);
-void ospf_sh_iface(struct proto *p, char *iff);
-void ospf_sh_state(struct proto *p, int verbose, int reachable);
+/* iface.c */
+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 ospf_proto *p, struct iface *what);
+void ospf_if_notify(struct proto *P, uint flags, struct iface *iface);
+void ospf_ifa_notify2(struct proto *P, uint flags, struct ifa *a);
+void ospf_ifa_notify3(struct proto *P, uint 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 ospf_proto *p, struct ospf_iface_patt *ip);
+void ospf_iface_remove(struct ospf_iface *ifa);
+void ospf_iface_shutdown(struct ospf_iface *ifa);
+int ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen);
+int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new);
+void ospf_reconfigure_ifaces(struct ospf_proto *p);
+void ospf_open_vlink_sk(struct ospf_proto *p);
+struct nbma_node *find_nbma_node_(list *nnl, ip_addr ip);
+
+static inline struct nbma_node * find_nbma_node(struct ospf_iface *ifa, ip_addr ip)
+{ return find_nbma_node_(&ifa->nbma_list, ip); }
+
+/* neighbor.c */
+struct ospf_neighbor *ospf_neighbor_new(struct ospf_iface *ifa);
+void ospf_neigh_sm(struct ospf_neighbor *n, int event);
+void ospf_dr_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_update_bfd(struct ospf_neighbor *n, int use_bfd);
+void ospf_sh_neigh_info(struct ospf_neighbor *n);
+
+/* packet.c */
+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(struct ospf_iface *ifa, ip_addr ip);
+void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
+void ospf_send_to_bdr(struct ospf_iface *ifa);
+
+static inline void ospf_send_to_all(struct ospf_iface *ifa)
+{ ospf_send_to(ifa, ifa->all_routers); }
+
+static inline void ospf_send_to_des(struct ospf_iface *ifa)
+{
+ if (ipa_nonzero(ifa->des_routers))
+ ospf_send_to(ifa, ifa->des_routers);
+ else
+ ospf_send_to_bdr(ifa);
+}
-#define SH_ROUTER_SELF 0xffffffff
+#define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0)
+#define DROP1(DSC) do { err_dsc = DSC; goto drop; } while(0)
+#define SKIP(DSC) do { err_dsc = DSC; goto skip; } while(0)
-struct lsadb_show_data {
- struct symbol *name; /* Protocol to request data from */
- u16 type; /* LSA Type, 0 -> all */
- u16 scope; /* Scope, 0 -> all, hack to handle link scope as 1 */
- u32 area; /* Specified for area scope */
- u32 lsid; /* LSA ID, 0 -> all */
- u32 router; /* Advertising router, 0 -> all */
-};
+static inline uint ospf_pkt_hdrlen(struct ospf_proto *p)
+{ return ospf_is_v2(p) ? (sizeof(struct ospf_packet) + sizeof(union ospf_auth)) : sizeof(struct ospf_packet); }
-void ospf_sh_lsadb(struct lsadb_show_data *ld);
+static inline void * ospf_tx_buffer(struct ospf_iface *ifa)
+{ return ifa->sk->tbuf; }
+/* hello.c */
+#define OHS_HELLO 0
+#define OHS_POLL 1
+#define OHS_SHUTDOWN 2
+
+void ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn);
+void ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr);
+
+/* dbdes.c */
+void ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n);
+void ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n);
+void ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
+
+/* lsreq.c */
+void ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n);
+void ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
+
+/* lsupd.c */
+void ospf_dump_lsahdr(struct ospf_proto *p, struct ospf_lsa_header *lsa_n);
+void ospf_dump_common(struct ospf_proto *p, struct ospf_packet *pkt);
+void ospf_lsa_lsrt_down_(struct top_hash_entry *en, struct ospf_neighbor *n, struct top_hash_entry *ret);
+void ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n);
+void ospf_flood_event(void *ptr);
+int ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from);
+int ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, struct ospf_neighbor *n);
+void ospf_rxmt_lsupd(struct ospf_proto *p, struct ospf_neighbor *n);
+void ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
+
+/* lsack.c */
+void ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int queue);
+void ospf_reset_lsack_queue(struct ospf_neighbor *n);
+void ospf_send_lsack(struct ospf_proto *p, struct ospf_neighbor *n, int queue);
+void ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
-#define EA_OSPF_METRIC1 EA_CODE(EAP_OSPF, 0)
-#define EA_OSPF_METRIC2 EA_CODE(EAP_OSPF, 1)
-#define EA_OSPF_TAG EA_CODE(EAP_OSPF, 2)
-#define EA_OSPF_ROUTER_ID EA_CODE(EAP_OSPF, 3)
#include "proto/ospf/rt.h"
-#include "proto/ospf/hello.h"
-#include "proto/ospf/packet.h"
-#include "proto/ospf/iface.h"
-#include "proto/ospf/neighbor.h"
#include "proto/ospf/topology.h"
-#include "proto/ospf/dbdes.h"
-#include "proto/ospf/lsreq.h"
-#include "proto/ospf/lsupd.h"
-#include "proto/ospf/lsack.h"
#include "proto/ospf/lsalib.h"
#endif /* _BIRD_OSPF_H_ */
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 1240b05c..fb63e61c 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -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,195 @@
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;
+ }
+ strncpy(auth->password, passwd->password, sizeof(auth->password));
- /* 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;
+ }
+
+ /* 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++;
- 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");
+ 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];
+ strncpy(password, passwd->password, sizeof(password));
+
+ 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)
+ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int len)
{
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
- struct password_item *pass = NULL, *ptmp;
- void *tail;
- char md5sum[OSPF_AUTH_CRYPT_SIZE];
- char password[OSPF_AUTH_CRYPT_SIZE];
- struct MD5Context ctxt;
+ struct ospf_proto *p = ifa->oa->po;
+ union ospf_auth *auth = (void *) (pkt + 1);
+ struct password_item *pass = NULL;
+ const char *err_dsc = NULL;
+ uint err_val = 0;
+ uint plen = ntohs(pkt->length);
+ u8 autype = pkt->autype;
- if (pkt->autype != htons(ifa->autype))
- {
- OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype));
- return 0;
- }
+ if (autype != ifa->autype)
+ DROP("authentication method mismatch", autype);
- 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));
-
- 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;
- }
+ case OSPF_AUTH_NONE:
+ return 1;
- 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;
- }
+ case OSPF_AUTH_SIMPLE:
+ pass = password_find(ifa->passwords, 1);
+ if (!pass)
+ DROP1("no password found");
- tail = ((void *)pkt) + ntohs(pkt->length);
+ if (!password_verify(pass, auth->password, sizeof(auth->password)))
+ DROP("wrong password", pass->id);
- 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;
- }
- }
+ return 1;
- if (!pass)
- {
- OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found");
- return 0;
- }
+ case OSPF_AUTH_CRYPT:
+ if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE)
+ DROP("invalid MD5 digest length", auth->md5.len);
- 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;
- }
+ if (plen + OSPF_AUTH_CRYPT_SIZE > len)
+ DROP("length mismatch", len);
- 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");
+ u32 rcv_csn = ntohl(auth->md5.csn);
+ if (n && (rcv_csn < n->csn))
+ // DROP("lower sequence number", rcv_csn);
+ {
+ /* We want to report both new and old CSN */
+ LOG_PKT_AUTH("Authentication failed for nbr %R on %s - "
+ "lower sequence number (rcv %u, old %u)",
+ n->rid, ifa->ifname, rcv_csn, n->csn);
return 0;
- }
-}
+ }
-#else
+ pass = password_find_by_id(ifa->passwords, auth->md5.keyid);
+ if (!pass)
+ DROP("no suitable password found", auth->md5.keyid);
-/* OSPFv3 authentication not yet supported */
+ void *tail = ((void *) pkt) + plen;
+ char passwd[OSPF_AUTH_CRYPT_SIZE];
+ char md5sum[OSPF_AUTH_CRYPT_SIZE];
-static inline void
-ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
-{ }
+ strncpy(passwd, pass->password, OSPF_AUTH_CRYPT_SIZE);
-static int
-ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
-{ return 1; }
-
-#endif
+ struct MD5Context ctxt;
+ MD5Init(&ctxt);
+ MD5Update(&ctxt, (char *) pkt, plen);
+ MD5Update(&ctxt, passwd, OSPF_AUTH_CRYPT_SIZE);
+ MD5Final(md5sum, &ctxt);
+
+ if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
+ DROP("wrong MD5 digest", pass->id);
+
+ if (n)
+ n->csn = rcv_csn;
+
+ return 1;
+
+ default:
+ bug("Unknown authentication type");
+ }
+drop:
+ LOG_PKT_AUTH("Authentication failed for nbr %R on %s - %s (%u)",
+ (n ? n->rid : ntohl(pkt->routerid)), ifa->ifname, err_dsc, err_val);
+
+ return 0;
+}
/**
* ospf_rx_hook
@@ -251,13 +215,10 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_
* non generic functions.
*/
int
-ospf_rx_hook(sock *sk, int size)
+ospf_rx_hook(sock *sk, int len)
{
- char *mesg = "OSPF: Bad packet from ";
-
- /* We want just packets from sk->iface. Unfortunately, on BSD we
- cannot filter out other packets at kernel level and we receive
- all packets on all sockets */
+ /* We want just packets from sk->iface. Unfortunately, on BSD we cannot filter
+ out other packets at kernel level and we receive all packets on all sockets */
if (sk->lifindex != sk->iface->index)
return 1;
@@ -266,71 +227,65 @@ 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;
+ const char *err_dsc = NULL;
+ uint err_val = 0;
- 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);
-
-#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;
+ dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers);
- /* 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
-
- /* Second, we check packet size, checksum, and the protocol version */
- struct ospf_packet *ps = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size);
+ 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;
- if (ps == NULL)
+ /* Ignore my own broadcast packets */
+ if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
+ return 1;
+ }
+ else
{
- log(L_ERR "%s%I - bad IP header", mesg, sk->faddr);
- return 1;
+ /* 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_PKT_WARN("Multicast packet received from non-link-local %I via %s",
+ sk->faddr, ifa->ifname);
}
+ /* Second, we check packet length, checksum, and the protocol version */
+ struct ospf_packet *pkt = (void *) sk_rx_buffer(sk, &len);
+
+
+ if (pkt == NULL)
+ DROP("bad IP header", len);
+
if (ifa->check_ttl && (sk->rcv_ttl < 255))
- {
- log(L_ERR "%s%I - TTL %d (< 255)", mesg, sk->faddr, sk->rcv_ttl);
- return 1;
- }
+ DROP("wrong TTL", sk->rcv_ttl);
- if ((unsigned) size < sizeof(struct ospf_packet))
- {
- log(L_ERR "%s%I - too short (%u bytes)", mesg, sk->faddr, size);
- return 1;
- }
+ if (len < sizeof(struct ospf_packet))
+ DROP("too short", len);
- uint plen = ntohs(ps->length);
+ if (pkt->version != ospf_get_version(p))
+ DROP("version mismatch", pkt->version);
+
+ 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);
- return 1;
- }
+ DROP("invalid length", plen);
if (sk->flags & SKF_TRUNCATED)
{
- log(L_WARN "%s%I - too large (%d/%d)", mesg, sk->faddr, plen, size);
-
/* If we have dynamic buffers and received truncated message, we expand RX buffer */
uint bs = plen + 256;
@@ -339,168 +294,149 @@ ospf_rx_hook(sock *sk, int size)
if (!ifa->cf->rx_buffer && (bs > sk->rbsize))
sk_set_rbsize(sk, bs);
- return 1;
+ DROP("truncated", plen);
}
- if (plen > size)
- {
- log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, plen, size);
- return 1;
- }
+ if (plen > len)
+ DROP("length mismatch", plen);
- if (ps->version != OSPF_VERSION)
+ if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT))
{
- log(L_ERR "%s%I - version %u", mesg, sk->faddr, ps->version);
- return 1;
- }
+ uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth);
+ uint blen = plen - hlen;
+ void *body = ((void *) pkt) + hlen;
-#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)))
- {
- log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
- return 1;
+ if (!ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
+ DROP1("invalid checksum");
}
-#endif
-
/* 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
- return 1;
+
+ /* It is real iface, source should be local (in OSPFv2) */
+ if (ospf_is_v2(p) && !src_local)
+ DROP1("strange source address");
+
+ goto found;
}
- else
+ else if ((areaid == 0) && !dst_mcast)
{
- /* Some vlink? */
- struct ospf_iface *iff = NULL;
+ /* Backbone area ID and possible vlink packet */
- WALK_LIST(iff, po->iface_list)
+ 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) &&
+ if ((iff->type == OSPF_IT_VLINK) &&
(iff->voa == ifa->oa) &&
-#ifdef OSPFv3
- (iff->instance_id == ps->instance_id) &&
-#endif
+ (iff->instance_id == instance_id) &&
(iff->vid == rid))
- {
- /* Vlink should be UP */
- if (iff->state != OSPF_IS_PTP)
- return 1;
-
- ifa = iff;
- goto found;
- }
+ {
+ /* Vlink should be UP */
+ if (iff->state != OSPF_IS_PTP)
+ return 1;
+
+ ifa = iff;
+ goto found;
+ }
}
-#ifdef OSPFv2
- log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr);
-#endif
+ /*
+ * 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
+ {
+ /* Non-matching area ID but cannot be vlink packet */
- found:
+ if (instance_id != ifa->instance_id)
+ return 1;
+
+ DROP("area mismatch", areaid);
+ }
+
+
+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)
- {
- log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr);
- return 1;
- }
+ if (rid == p->router_id)
+ DROP1("my own router ID");
if (rid == 0)
- {
- log(L_ERR "%s%I - router id = 0.0.0.0", mesg, sk->faddr);
- return 1;
- }
+ DROP1("zero router ID");
-#ifdef OSPFv2
- /* In OSPFv2, neighbors are identified by either IP or Router ID, base on network type */
+ /* In OSPFv2, neighbors are identified by either IP or Router ID, based 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);
+ OSPF_TRACE(D_PACKETS, "Non-HELLO packet received from unknown nbr %R on %s, src %I",
+ rid, ifa->ifname, sk->faddr);
return 1;
}
- if (!ospf_pkt_checkauth(n, ifa, ps, size))
- {
- log(L_ERR "%s%I - authentication failed", mesg, sk->faddr);
+ /* ospf_pkt_checkauth() has its own error logging */
+ if (ospf_is_v2(p) && !ospf_pkt_checkauth(n, ifa, pkt, len))
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);
- return 1;
+ DROP("invalid packet type", pkt->type);
};
return 1;
+
+drop:
+ LOG_PKT("Bad packet from %I via %s - %s (%u)",
+ sk->faddr, ifa->ifname, err_dsc, err_val);
+
+ return 1;
}
/*
@@ -508,7 +444,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 +453,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 +497,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);
-}
-
diff --git a/proto/ospf/packet.h b/proto/ospf/packet.h
deleted file mode 100644
index 4ba1f08c..00000000
--- a/proto/ospf/packet.h
+++ /dev/null
@@ -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_ */
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 2a879c05..b616c0d1 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -1,25 +1,19 @@
/*
- * BIRD -- OSPF
- *
- * (c) 2000--2004 Ondrej Filip <feela@network.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
+ * 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.
*/
#include "ospf.h"
-static void add_cand(list * l, struct top_hash_entry *en,
+static void add_cand(list * l, struct top_hash_entry *en,
struct top_hash_entry *par, u32 dist,
struct ospf_area *oa, int i);
-static void rt_sync(struct proto_ospf *po);
-
-/* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address)
- as index, so we need to encapsulate RID to IP address */
-#ifdef OSPFv2
-#define ipa_from_rid(x) _MI(x)
-#else /* OSPFv3 */
-#define ipa_from_rid(x) _MI(0,0,0,x)
-#endif
+static void rt_sync(struct ospf_proto *p);
static inline void reset_ri(ort *ort)
@@ -33,7 +27,7 @@ ospf_rt_initort(struct fib_node *fn)
ort *ri = (ort *) fn;
reset_ri(ri);
ri->old_rta = NULL;
- ri->fn.x0 = ri->fn.x1 = 0;
+ ri->fn.flags = 0;
}
static inline int
@@ -49,9 +43,9 @@ unresolved_vlink(ort *ort)
}
static inline struct mpnh *
-new_nexthop(struct proto_ospf *po, ip_addr gw, struct iface *iface, unsigned char weight)
+new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, unsigned char weight)
{
- struct mpnh *nh = lp_alloc(po->nhpool, sizeof(struct mpnh));
+ struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh));
nh->gw = gw;
nh->iface = iface;
nh->next = NULL;
@@ -60,9 +54,9 @@ new_nexthop(struct proto_ospf *po, ip_addr gw, struct iface *iface, unsigned cha
}
static inline struct mpnh *
-copy_nexthop(struct proto_ospf *po, const struct mpnh *src)
+copy_nexthop(struct ospf_proto *p, const struct mpnh *src)
{
- struct mpnh *nh = lp_alloc(po->nhpool, sizeof(struct mpnh));
+ struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh));
nh->gw = src->gw;
nh->iface = src->iface;
nh->next = NULL;
@@ -95,11 +89,11 @@ cmp_nhs(struct mpnh *s1, struct mpnh *s2)
}
static struct mpnh *
-merge_nexthops(struct proto_ospf *po, struct mpnh *s1, struct mpnh *s2, int r1, int r2)
+merge_nexthops(struct ospf_proto *p, struct mpnh *s1, struct mpnh *s2, int r1, int r2)
{
struct mpnh *root = NULL;
struct mpnh **n = &root;
- int count = po->ecmp;
+ int count = p->ecmp;
/*
* r1, r2 signalize whether we can reuse nexthops from s1, s2.
@@ -118,17 +112,17 @@ merge_nexthops(struct proto_ospf *po, struct mpnh *s1, struct mpnh *s2, int r1,
int cmp = cmp_nhs(s1, s2);
if (cmp < 0)
{
- *n = r1 ? s1 : copy_nexthop(po, s1);
+ *n = r1 ? s1 : copy_nexthop(p, s1);
s1 = s1->next;
}
else if (cmp > 0)
{
- *n = r2 ? s2 : copy_nexthop(po, s2);
+ *n = r2 ? s2 : copy_nexthop(p, s2);
s2 = s2->next;
}
else
{
- *n = r1 ? s1 : (r2 ? s2 : copy_nexthop(po, s1));
+ *n = r1 ? s1 : (r2 ? s2 : copy_nexthop(p, s1));
s1 = s1->next;
s2 = s2->next;
}
@@ -152,7 +146,7 @@ has_device_nexthops(const struct mpnh *n)
/* Replace device nexthops with nexthops to gw */
static struct mpnh *
-fix_device_nexthops(struct proto_ospf *po, const struct mpnh *n, ip_addr gw)
+fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw)
{
struct mpnh *root1 = NULL;
struct mpnh *root2 = NULL;
@@ -165,7 +159,7 @@ fix_device_nexthops(struct proto_ospf *po, const struct mpnh *n, ip_addr gw)
for (; n; n = n->next)
{
- struct mpnh *nn = new_nexthop(po, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight);
+ struct mpnh *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight);
if (ipa_zero(n->gw))
{
@@ -179,7 +173,7 @@ fix_device_nexthops(struct proto_ospf *po, const struct mpnh *n, ip_addr gw)
}
}
- return merge_nexthops(po, root1, root2, 1, 1);
+ return merge_nexthops(p, root1, root2, 1, 1);
}
@@ -235,7 +229,7 @@ orta_prefer_lsa(const orta *new, const orta *old)
* the old orta.
*/
static int
-orta_compare(const struct proto_ospf *po, const orta *new, const orta *old)
+orta_compare(const struct ospf_proto *p, const orta *new, const orta *old)
{
int r;
@@ -270,13 +264,13 @@ orta_compare(const struct proto_ospf *po, const orta *new, const orta *old)
return 1;
- if (po->ecmp)
+ if (p->ecmp)
return 0;
/* Prefer routes with higher Router ID, just to be more deterministic */
if (new->rid > old->rid)
return 1;
-
+
return -1;
}
@@ -286,14 +280,14 @@ orta_compare(const struct proto_ospf *po, const orta *new, const orta *old)
* than 0 if the new ASBR is less or more preferred than the old ASBR.
*/
static int
-orta_compare_asbr(const struct proto_ospf *po, const orta *new, const orta *old)
+orta_compare_asbr(const struct ospf_proto *p, const orta *new, const orta *old)
{
int r;
if (old->type == RTS_DUMMY)
return 1;
- if (!po->rfc1583)
+ if (!p->rfc1583)
{
r = epath_preferred(new) - epath_preferred(old);
if (r) return r;
@@ -316,7 +310,7 @@ orta_compare_asbr(const struct proto_ospf *po, const orta *new, const orta *old)
* than 0 if the new orta is less, equal or more preferred than the old orta.
*/
static int
-orta_compare_ext(const struct proto_ospf *po, const orta *new, const orta *old)
+orta_compare_ext(const struct ospf_proto *p, const orta *new, const orta *old)
{
int r;
@@ -335,7 +329,7 @@ orta_compare_ext(const struct proto_ospf *po, const orta *new, const orta *old)
}
/* 16.4 (6c) - if not RFC1583, prefer routes with preferred ASBR/next_hop */
- if (!po->rfc1583)
+ if (!p->rfc1583)
{
r = orta_pref(new) - orta_pref(old);
if (r) return r;
@@ -346,7 +340,7 @@ orta_compare_ext(const struct proto_ospf *po, const orta *new, const orta *old)
if (r) return r;
- if (po->ecmp && po->merge_external)
+ if (p->ecmp && p->merge_external)
return 0;
/*
@@ -369,13 +363,13 @@ ort_replace(ort *o, const orta *new)
}
static void
-ort_merge(struct proto_ospf *po, ort *o, const orta *new)
+ort_merge(struct ospf_proto *p, ort *o, const orta *new)
{
orta *old = &o->n;
if (old->nhs != new->nhs)
{
- old->nhs = merge_nexthops(po, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse);
+ old->nhs = merge_nexthops(p, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse);
old->nhs_reuse = 1;
}
@@ -384,13 +378,13 @@ ort_merge(struct proto_ospf *po, ort *o, const orta *new)
}
static void
-ort_merge_ext(struct proto_ospf *po, ort *o, const orta *new)
+ort_merge_ext(struct ospf_proto *p, ort *o, const orta *new)
{
orta *old = &o->n;
if (old->nhs != new->nhs)
{
- old->nhs = merge_nexthops(po, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse);
+ old->nhs = merge_nexthops(p, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse);
old->nhs_reuse = 1;
}
@@ -415,15 +409,15 @@ ort_merge_ext(struct proto_ospf *po, ort *o, const orta *new)
static inline void
-ri_install_net(struct proto_ospf *po, ip_addr prefix, int pxlen, const orta *new)
+ri_install_net(struct ospf_proto *p, ip_addr prefix, int pxlen, const orta *new)
{
- ort *old = (ort *) fib_get(&po->rtf, &prefix, pxlen);
- int cmp = orta_compare(po, new, &old->n);
+ ort *old = (ort *) fib_get(&p->rtf, &prefix, pxlen);
+ int cmp = orta_compare(p, new, &old->n);
if (cmp > 0)
ort_replace(old, new);
else if (cmp == 0)
- ort_merge(po, old, new);
+ ort_merge(p, old, new);
}
static inline void
@@ -440,51 +434,55 @@ ri_install_rt(struct ospf_area *oa, u32 rid, const orta *new)
}
static inline void
-ri_install_asbr(struct proto_ospf *po, ip_addr *addr, const orta *new)
+ri_install_asbr(struct ospf_proto *p, ip_addr *addr, const orta *new)
{
- ort *old = (ort *) fib_get(&po->backbone->rtr, addr, MAX_PREFIX_LENGTH);
- if (orta_compare_asbr(po, new, &old->n) > 0)
+ ort *old = (ort *) fib_get(&p->backbone->rtr, addr, MAX_PREFIX_LENGTH);
+ if (orta_compare_asbr(p, new, &old->n) > 0)
ort_replace(old, new);
}
static inline void
-ri_install_ext(struct proto_ospf *po, ip_addr prefix, int pxlen, const orta *new)
+ri_install_ext(struct ospf_proto *p, ip_addr prefix, int pxlen, const orta *new)
{
- ort *old = (ort *) fib_get(&po->rtf, &prefix, pxlen);
- int cmp = orta_compare_ext(po, new, &old->n);
+ ort *old = (ort *) fib_get(&p->rtf, &prefix, pxlen);
+ int cmp = orta_compare_ext(p, new, &old->n);
if (cmp > 0)
ort_replace(old, new);
else if (cmp == 0)
- ort_merge_ext(po, old, new);
+ ort_merge_ext(p, old, new);
}
static inline struct ospf_iface *
rt_pos_to_ifa(struct ospf_area *oa, int pos)
{
struct ospf_iface *ifa;
+
WALK_LIST(ifa, oa->po->iface_list)
if (ifa->oa == oa && pos >= ifa->rt_pos_beg && pos < ifa->rt_pos_end)
return ifa;
+
return NULL;
}
-#ifdef OSPFv3
static inline struct ospf_iface *
px_pos_to_ifa(struct ospf_area *oa, int pos)
{
struct ospf_iface *ifa;
+
WALK_LIST(ifa, oa->po->iface_list)
if (ifa->oa == oa && pos >= ifa->px_pos_beg && pos < ifa->px_pos_end)
return ifa;
+
return NULL;
}
-#endif
static void
add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en, int pos)
{
+ struct ospf_proto *p = oa->po;
+
orta nf = {
.type = RTS_OSPF,
.options = 0,
@@ -499,13 +497,13 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_
if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
{
log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
- oa->po->proto.name, en->lsa.type, en->lsa.id, en->lsa.rt);
+ p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
return;
}
if (en == oa->rt)
{
- /*
+ /*
* Local stub networks does not have proper iface in en->nhi
* (because they all have common top_hash_entry en).
* We have to find iface responsible for that stub network.
@@ -514,24 +512,117 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_
*/
struct ospf_iface *ifa;
-#ifdef OSPFv2
- ifa = rt_pos_to_ifa(oa, pos);
-#else /* OSPFv3 */
- ifa = px_pos_to_ifa(oa, pos);
-#endif
+ ifa = ospf_is_v2(p) ? rt_pos_to_ifa(oa, pos) : px_pos_to_ifa(oa, pos);
+ nf.nhs = ifa ? new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL;
+ }
- nf.nhs = ifa ? new_nexthop(oa->po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL;
+ ri_install_net(p, px, pxlen, &nf);
+}
+
+
+
+static inline void
+spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entry *act)
+{
+ struct ospf_lsa_rt *rt = act->lsa_body;
+ struct ospf_lsa_rt_walk rtl;
+ struct top_hash_entry *tmp;
+ ip_addr prefix;
+ int pxlen, i;
+
+ if (rt->options & OPT_RT_V)
+ oa->trcap = 1;
+
+ /*
+ * In OSPFv3, all routers are added to per-area routing
+ * tables. But we use it just for ASBRs and ABRs. For the
+ * purpose of the last step in SPF - prefix-LSA processing in
+ * spfa_process_prefixes(), we use information stored in LSA db.
+ */
+ if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B))
+ && (act->lsa.rt != p->router_id))
+ {
+ orta nf = {
+ .type = RTS_OSPF,
+ .options = rt->options,
+ .metric1 = act->dist,
+ .metric2 = LSINFINITY,
+ .tag = 0,
+ .rid = act->lsa.rt,
+ .oa = oa,
+ .nhs = act->nhs
+ };
+ ri_install_rt(oa, act->lsa.rt, &nf);
}
- ri_install_net(oa->po, px, pxlen, &nf);
+ /* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */
+ if (ospf_is_v3(p) && (act != oa->rt) && !(rt->options & OPT_R))
+ return;
+
+ /* Now process Rt links */
+ for (lsa_walk_rt_init(p, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++)
+ {
+ tmp = NULL;
+
+ switch (rtl.type)
+ {
+ case LSART_STUB:
+
+ /* Should not happen, LSART_STUB is not defined in OSPFv3 */
+ if (ospf_is_v3(p))
+ break;
+
+ /*
+ * RFC 2328 in 16.1. (2a) says to handle stub networks in an
+ * second phase after the SPF for an area is calculated. We get
+ * the same result by handing them here because add_network()
+ * will keep the best (not the first) found route.
+ */
+ prefix = ipa_from_u32(rtl.id & rtl.data);
+ pxlen = u32_masklen(rtl.data);
+ add_network(oa, prefix, pxlen, act->dist + rtl.metric, act, i);
+ break;
+
+ case LSART_NET:
+ tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif);
+ break;
+
+ case LSART_VLNK:
+ case LSART_PTP:
+ tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id);
+ break;
+ }
+
+ add_cand(&oa->cand, tmp, act, act->dist + rtl.metric, oa, i);
+ }
}
-#ifdef OSPFv3
-static void
-process_prefixes(struct ospf_area *oa)
+static inline void
+spfa_process_net(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entry *act)
+{
+ struct ospf_lsa_net *ln = act->lsa_body;
+ struct top_hash_entry *tmp;
+ ip_addr prefix;
+ int pxlen, i, cnt;
+
+ if (ospf_is_v2(p))
+ {
+ prefix = ipa_from_u32(act->lsa.id & ln->optx);
+ pxlen = u32_masklen(ln->optx);
+ add_network(oa, prefix, pxlen, act->dist, act, -1);
+ }
+
+ cnt = lsa_net_count(&act->lsa);
+ for (i = 0; i < cnt; i++)
+ {
+ tmp = ospf_hash_find_rt(p->gr, oa->areaid, ln->routers[i]);
+ add_cand(&oa->cand, tmp, act, act->dist, oa, -1);
+ }
+}
+
+static inline void
+spfa_process_prefixes(struct ospf_proto *p, struct ospf_area *oa)
{
- struct proto_ospf *po = oa->po;
- // struct proto *p = &po->proto;
struct top_hash_entry *en, *src;
struct ospf_lsa_prefix *px;
ip_addr pxa;
@@ -541,9 +632,9 @@ process_prefixes(struct ospf_area *oa)
u32 *buf;
int i;
- WALK_SLIST(en, po->lsal)
+ WALK_SLIST(en, p->lsal)
{
- if (en->lsa.type != LSA_T_PREFIX)
+ if (en->lsa_type != LSA_T_PREFIX)
continue;
if (en->domain != oa->areaid)
@@ -556,9 +647,9 @@ process_prefixes(struct ospf_area *oa)
/* For router prefix-LSA, we would like to find the first router-LSA */
if (px->ref_type == LSA_T_RT)
- src = ospf_hash_find_rt(po->gr, oa->areaid, px->ref_rt);
+ src = ospf_hash_find_rt(p->gr, oa->areaid, px->ref_rt);
else
- src = ospf_hash_find(po->gr, oa->areaid, px->ref_id, px->ref_rt, px->ref_type);
+ src = ospf_hash_find(p->gr, oa->areaid, px->ref_id, px->ref_rt, px->ref_type);
if (!src)
continue;
@@ -567,7 +658,7 @@ process_prefixes(struct ospf_area *oa)
if (src->color != INSPF)
continue;
- if ((src->lsa.type != LSA_T_RT) && (src->lsa.type != LSA_T_NET))
+ if ((src->lsa_type != LSA_T_RT) && (src->lsa_type != LSA_T_NET))
continue;
buf = px->rest;
@@ -586,84 +677,19 @@ process_prefixes(struct ospf_area *oa)
}
}
}
-#endif
-
-
-static void
-ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct top_hash_entry *en)
-{
- // struct proto *p = &oa->po->proto;
- struct proto_ospf *po = oa->po;
- ip_addr prefix UNUSED;
- int pxlen UNUSED, i;
-
- struct ospf_lsa_rt *rt = en->lsa_body;
- struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1);
-
- for (i = 0; i < lsa_rt_count(&en->lsa); i++)
- {
- struct ospf_lsa_rt_link *rtl = rr + i;
- struct top_hash_entry *tmp = NULL;
-
- DBG(" Working on link: %R (type: %u) ", rtl->id, rtl->type);
- switch (rtl->type)
- {
-#ifdef OSPFv2
- case LSART_STUB:
- /*
- * RFC 2328 in 16.1. (2a) says to handle stub networks in an
- * second phase after the SPF for an area is calculated. We get
- * the same result by handing them here because add_network()
- * will keep the best (not the first) found route.
- */
- prefix = ipa_from_u32(rtl->id & rtl->data);
- pxlen = ipa_mklen(ipa_from_u32(rtl->data));
- add_network(oa, prefix, pxlen, act->dist + rtl->metric, act, i);
- break;
-#endif
-
- case LSART_NET:
-#ifdef OSPFv2
- /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */
- tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id);
-#else /* OSPFv3 */
- tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET);
-#endif
- break;
-
- case LSART_VLNK:
- case LSART_PTP:
- tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id);
- break;
-
- default:
- log("Unknown link type in router lsa. (rid = %R)", act->lsa.id);
- break;
- }
-
- if (tmp)
- DBG("Going to add cand, Mydist: %u, Req: %u\n",
- tmp->dist, act->dist + rtl->metric);
- add_cand(&oa->cand, tmp, act, act->dist + rtl->metric, oa, i);
- }
-}
/* RFC 2328 16.1. calculating shortest paths for an area */
static void
ospf_rt_spfa(struct ospf_area *oa)
{
- struct proto *p = &oa->po->proto;
- struct proto_ospf *po = oa->po;
- struct ospf_lsa_rt *rt;
- struct ospf_lsa_net *ln;
- struct top_hash_entry *act, *tmp;
- ip_addr prefix UNUSED;
- int pxlen UNUSED;
- u32 i, *rts;
+ struct ospf_proto *p = oa->po;
+ struct top_hash_entry *act;
node *n;
if (oa->rt == NULL)
return;
+ if (oa->rt->lsa.age == LSA_MAXAGE)
+ return;
OSPF_TRACE(D_EVENTS, "Starting routing table calculation for area %R", oa->areaid);
@@ -677,7 +703,7 @@ ospf_rt_spfa(struct ospf_area *oa)
oa->rt->color = CANDIDATE;
add_head(&oa->cand, &oa->rt->cn);
DBG("RT LSA: rt: %R, id: %R, type: %u\n",
- oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa.type);
+ oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa_type);
while (!EMPTY_LIST(oa->cand))
{
@@ -686,89 +712,36 @@ ospf_rt_spfa(struct ospf_area *oa)
rem_node(n);
DBG("Working on LSA: rt: %R, id: %R, type: %u\n",
- act->lsa.rt, act->lsa.id, act->lsa.type);
+ act->lsa.rt, act->lsa.id, act->lsa_type);
act->color = INSPF;
- switch (act->lsa.type)
+ switch (act->lsa_type)
{
case LSA_T_RT:
- rt = (struct ospf_lsa_rt *) act->lsa_body;
- if (rt->options & OPT_RT_V)
- oa->trcap = 1;
-
- /*
- * In OSPFv3, all routers are added to per-area routing
- * tables. But we use it just for ASBRs and ABRs. For the
- * purpose of the last step in SPF - prefix-LSA processing in
- * process_prefixes(), we use information stored in LSA db.
- */
- if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B))
- && (act->lsa.rt != po->router_id))
- {
- orta nf = {
- .type = RTS_OSPF,
- .options = rt->options,
- .metric1 = act->dist,
- .metric2 = LSINFINITY,
- .tag = 0,
- .rid = act->lsa.rt,
- .oa = oa,
- .nhs = act->nhs
- };
- ri_install_rt(oa, act->lsa.rt, &nf);
- }
-
-#ifdef OSPFv2
- ospf_rt_spfa_rtlinks(oa, act, act);
-#else /* OSPFv3 */
- /* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */
- if ((act != oa->rt) && !(rt->options & OPT_R))
- break;
-
- for (tmp = ospf_hash_find_rt_first(po->gr, act->domain, act->lsa.rt);
- tmp; tmp = ospf_hash_find_rt_next(tmp))
- ospf_rt_spfa_rtlinks(oa, act, tmp);
-#endif
-
+ spfa_process_rt(p, oa, act);
break;
- case LSA_T_NET:
- ln = act->lsa_body;
-#ifdef OSPFv2
- prefix = ipa_and(ipa_from_u32(act->lsa.id), ln->netmask);
- pxlen = ipa_mklen(ln->netmask);
- add_network(oa, prefix, pxlen, act->dist, act, -1);
-#endif
-
- rts = (u32 *) (ln + 1);
- for (i = 0; i < lsa_net_count(&act->lsa); i++)
- {
- DBG(" Working on router %R ", rts[i]);
- tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]);
- if (tmp != NULL)
- DBG("Found :-)\n");
- else
- DBG("Not found!\n");
- add_cand(&oa->cand, tmp, act, act->dist, oa, -1);
- }
+ case LSA_T_NET:
+ spfa_process_net(p, oa, act);
break;
+
+ default:
+ log(L_WARN "%s: Unknown LSA type in SPF: %d", p->p.name, act->lsa_type);
}
}
-#ifdef OSPFv3
- process_prefixes(oa);
-#endif
+ if (ospf_is_v3(p))
+ spfa_process_prefixes(p, oa);
}
static int
link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par)
{
- u32 i, *rts;
- struct ospf_lsa_net *ln;
- struct ospf_lsa_rt *rt;
- struct ospf_lsa_rt_link *rtl, *rr;
+ struct ospf_proto *p = oa->po;
+ struct ospf_lsa_rt_walk rtl;
struct top_hash_entry *tmp;
- struct proto_ospf *po = oa->po;
+ struct ospf_lsa_net *ln;
+ u32 i, cnt;
if (!en || !par) return 0;
@@ -783,88 +756,79 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
it is set in process_prefixes() to any global addres in the area */
en->lb = IPA_NONE;
-#ifdef OSPFv3
en->lb_id = 0;
-#endif
- switch (en->lsa.type)
+
+ switch (en->lsa_type)
{
- case LSA_T_RT:
- rt = (struct ospf_lsa_rt *) en->lsa_body;
- rr = (struct ospf_lsa_rt_link *) (rt + 1);
- for (i = 0; i < lsa_rt_count(&en->lsa); i++)
+ case LSA_T_RT:
+ lsa_walk_rt_init(p, en, &rtl);
+ while (lsa_walk_rt(&rtl))
+ {
+ switch (rtl.type)
{
- rtl = (rr + i);
- switch (rtl->type)
+ case LSART_STUB:
+ break;
+
+ case LSART_NET:
+ tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif);
+ if (tmp == par)
{
- case LSART_STUB:
- break;
- case LSART_NET:
-#ifdef OSPFv2
- /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */
- tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id);
-#else /* OSPFv3 */
- tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET);
-#endif
- if (tmp == par)
- {
-#ifdef OSPFv2
- en->lb = ipa_from_u32(rtl->data);
-#else /* OSPFv3 */
- en->lb_id = rtl->lif;
-#endif
- return 1;
- }
-
- break;
- case LSART_VLNK:
- case LSART_PTP:
- /* Not necessary the same link, see RFC 2328 [23] */
- tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id);
- if (tmp == par)
- return 1;
-
- break;
- default:
- log(L_WARN "Unknown link type in router lsa. (rid = %R)", en->lsa.rt);
- break;
+ if (ospf_is_v2(p))
+ en->lb = ipa_from_u32(rtl.data);
+ else
+ en->lb_id = rtl.lif;
+
+ return 1;
}
- }
- break;
- case LSA_T_NET:
- ln = en->lsa_body;
- rts = (u32 *) (ln + 1);
- for (i = 0; i < lsa_net_count(&en->lsa); i++)
- {
- tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]);
+ break;
+
+ case LSART_VLNK:
+ case LSART_PTP:
+ /* Not necessary the same link, see RFC 2328 [23] */
+ tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id);
if (tmp == par)
- return 1;
+ return 1;
+ break;
}
- break;
- default:
- bug("Unknown lsa type %x.", en->lsa.type);
+ }
+ break;
+
+ case LSA_T_NET:
+ ln = en->lsa_body;
+ cnt = lsa_net_count(&en->lsa);
+ for (i = 0; i < cnt; i++)
+ {
+ tmp = ospf_hash_find_rt(p->gr, oa->areaid, ln->routers[i]);
+ if (tmp == par)
+ return 1;
+ }
+ break;
+
+ default:
+ log(L_WARN "%s: Unknown LSA type in SPF: %d", p->p.name, en->lsa_type);
}
return 0;
}
-
+
/* RFC 2328 16.2. calculating inter-area routes */
static void
ospf_rt_sum(struct ospf_area *oa)
{
- struct proto_ospf *po = oa->po;
- struct proto *p = &po->proto;
+ struct ospf_proto *p = oa->po;
struct top_hash_entry *en;
- ip_addr ip = IPA_NONE;
- u32 dst_rid = 0;
- u32 metric, options;
+ ip_addr ip, abrip;
+ u32 dst_rid, metric, options;
ort *abr;
int pxlen = -1, type = -1;
+ u8 pxopts;
+
OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid);
- WALK_SLIST(en, po->lsal)
+ WALK_SLIST(en, p->lsal)
{
- if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
+ if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET))
continue;
if (en->domain != oa->areaid)
@@ -875,55 +839,36 @@ ospf_rt_sum(struct ospf_area *oa)
continue;
/* 16.2. (2) */
- if (en->lsa.rt == po->router_id)
+ if (en->lsa.rt == p->router_id)
continue;
/* 16.2. (3) is handled later in ospf_rt_abr() by resetting such rt entry */
- if (en->lsa.type == LSA_T_SUM_NET)
+ if (en->lsa_type == LSA_T_SUM_NET)
{
-#ifdef OSPFv2
- struct ospf_lsa_sum *ls = en->lsa_body;
- ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
- pxlen = ipa_mklen(ls->netmask);
-#else /* OSPFv3 */
- u8 pxopts;
- u16 rest;
- struct ospf_lsa_sum_net *ls = en->lsa_body;
- lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest);
+ lsa_parse_sum_net(en, ospf_is_v2(p), &ip, &pxlen, &pxopts, &metric);
if (pxopts & OPT_PX_NU)
continue;
-#endif
if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
{
log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
- p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
+ p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
continue;
}
- metric = ls->metric & METRIC_MASK;
options = 0;
type = ORT_NET;
}
else /* LSA_T_SUM_RT */
{
-#ifdef OSPFv2
- struct ospf_lsa_sum *ls = en->lsa_body;
- dst_rid = en->lsa.id;
- options = 0;
-#else /* OSPFv3 */
- struct ospf_lsa_sum_rt *ls = en->lsa_body;
- dst_rid = ls->drid;
- options = ls->options & OPTIONS_MASK;
-#endif
-
+ lsa_parse_sum_rt(en, ospf_is_v2(p), &dst_rid, &metric, &options);
+
/* We don't want local router in ASBR routing table */
- if (dst_rid == po->router_id)
+ if (dst_rid == p->router_id)
continue;
- metric = ls->metric & METRIC_MASK;
options |= ORTA_ASBR;
type = ORT_ROUTER;
}
@@ -933,7 +878,7 @@ ospf_rt_sum(struct ospf_area *oa)
continue;
/* 16.2. (4) */
- ip_addr abrip = ipa_from_rid(en->lsa.rt);
+ abrip = ipa_from_rid(en->lsa.rt);
abr = (ort *) fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH);
if (!abr || !abr->n.type)
continue;
@@ -958,7 +903,7 @@ ospf_rt_sum(struct ospf_area *oa)
};
if (type == ORT_NET)
- ri_install_net(po, ip, pxlen, &nf);
+ ri_install_net(p, ip, pxlen, &nf);
else
ri_install_rt(oa, dst_rid, &nf);
}
@@ -968,20 +913,22 @@ ospf_rt_sum(struct ospf_area *oa)
static void
ospf_rt_sum_tr(struct ospf_area *oa)
{
- struct proto *p = &oa->po->proto;
- struct proto_ospf *po = oa->po;
- struct ospf_area *bb = po->backbone;
- ip_addr abrip;
+ struct ospf_proto *p = oa->po;
+ struct ospf_area *bb = p->backbone;
struct top_hash_entry *en;
- u32 dst_rid, metric;
- ort *re = NULL, *abr;
+ ort *re, *abr;
+ ip_addr ip, abrip;
+ u32 dst_rid, metric, options;
+ int pxlen;
+ u8 pxopts;
- if (!bb) return;
+ if (!bb)
+ return;
- WALK_SLIST(en, po->lsal)
+ WALK_SLIST(en, p->lsal)
{
- if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
+ if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET))
continue;
if (en->domain != oa->areaid)
@@ -992,55 +939,36 @@ ospf_rt_sum_tr(struct ospf_area *oa)
continue;
/* 16.3 (2) */
- if (en->lsa.rt == po->router_id)
+ if (en->lsa.rt == p->router_id)
continue;
- if (en->lsa.type == LSA_T_SUM_NET)
+ if (en->lsa_type == LSA_T_SUM_NET)
{
- ip_addr ip;
- int pxlen;
-#ifdef OSPFv2
- struct ospf_lsa_sum *ls = en->lsa_body;
- ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
- pxlen = ipa_mklen(ls->netmask);
-#else /* OSPFv3 */
- u8 pxopts;
- u16 rest;
- struct ospf_lsa_sum_net *ls = en->lsa_body;
- lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest);
+ lsa_parse_sum_net(en, ospf_is_v2(p), &ip, &pxlen, &pxopts, &metric);
if (pxopts & OPT_PX_NU)
continue;
-#endif
if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
{
log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
- p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
+ p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
continue;
}
- metric = ls->metric & METRIC_MASK;
- re = fib_find(&po->rtf, &ip, pxlen);
+ re = fib_find(&p->rtf, &ip, pxlen);
}
- else // en->lsa.type == LSA_T_SUM_RT
+ else // en->lsa_type == LSA_T_SUM_RT
{
-#ifdef OSPFv2
- struct ospf_lsa_sum *ls = en->lsa_body;
- dst_rid = en->lsa.id;
-#else /* OSPFv3 */
- struct ospf_lsa_sum_rt *ls = en->lsa_body;
- dst_rid = ls->drid;
-#endif
-
- metric = ls->metric & METRIC_MASK;
- ip_addr ip = ipa_from_rid(dst_rid);
+ lsa_parse_sum_rt(en, ospf_is_v2(p), &dst_rid, &metric, &options);
+
+ ip = ipa_from_rid(dst_rid);
re = fib_find(&bb->rtr, &ip, MAX_PREFIX_LENGTH);
}
- /* 16.3 (1b) */
- if (metric == LSINFINITY)
- continue;
+ /* 16.3 (1b) */
+ if (metric == LSINFINITY)
+ continue;
/* 16.3 (3) */
if (!re || !re->n.type)
@@ -1061,7 +989,7 @@ ospf_rt_sum_tr(struct ospf_area *oa)
metric = abr->n.metric1 + metric; /* IAC */
/* 16.3. (5) */
- if ((metric < re->n.metric1) ||
+ if ((metric < re->n.metric1) ||
((metric == re->n.metric1) && unresolved_vlink(re)))
{
/* We want to replace the next-hop even if the metric is equal
@@ -1147,7 +1075,7 @@ decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest)
struct area_net *anet = (struct area_net *)
fib_route(&nf->n.oa->net_fib, nf->fn.prefix, nf->fn.pxlen);
- /* Condensed area network found */
+ /* Condensed area network found */
if (anet)
return 0;
@@ -1156,20 +1084,19 @@ decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest)
/* RFC 2328 16.7. p1 - originate or flush summary LSAs */
static inline void
-check_sum_net_lsa(struct proto_ospf *po, ort *nf)
+check_sum_net_lsa(struct ospf_proto *p, ort *nf)
{
struct area_net *anet = NULL;
struct ospf_area *anet_oa = NULL;
- /* RT entry marked as area network */
- if (nf->fn.x0)
+ if (nf->area_net)
{
/* It is a default route for stub areas, handled entirely in ospf_rt_abr() */
if (nf->fn.pxlen == 0)
return;
/* Find that area network */
- WALK_LIST(anet_oa, po->area_list)
+ WALK_LIST(anet_oa, p->area_list)
{
anet = (struct area_net *) fib_find(&anet_oa->net_fib, &nf->fn.prefix, nf->fn.pxlen);
if (anet)
@@ -1178,104 +1105,70 @@ check_sum_net_lsa(struct proto_ospf *po, ort *nf)
}
struct ospf_area *oa;
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
{
if (anet && decide_anet_lsa(oa, anet, anet_oa))
- originate_sum_net_lsa(oa, &nf->fn, anet->metric);
+ ospf_originate_sum_net_lsa(p, oa, nf, anet->metric);
else if (decide_sum_lsa(oa, nf, ORT_NET))
- originate_sum_net_lsa(oa, &nf->fn, nf->n.metric1);
- else
- flush_sum_lsa(oa, &nf->fn, ORT_NET);
+ ospf_originate_sum_net_lsa(p, oa, nf, nf->n.metric1);
}
}
static inline void
-check_sum_rt_lsa(struct proto_ospf *po, ort *nf)
+check_sum_rt_lsa(struct ospf_proto *p, ort *nf)
{
struct ospf_area *oa;
- WALK_LIST(oa, po->area_list)
- {
+ WALK_LIST(oa, p->area_list)
if (decide_sum_lsa(oa, nf, ORT_ROUTER))
- originate_sum_rt_lsa(oa, &nf->fn, nf->n.metric1, nf->n.options);
- else
- flush_sum_lsa(oa, &nf->fn, ORT_ROUTER);
- }
+ ospf_originate_sum_rt_lsa(p, oa, nf, nf->n.metric1, nf->n.options);
}
static inline int
-decide_nssa_lsa(ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag)
+decide_nssa_lsa(struct ospf_proto *p, ort *nf, struct ospf_lsa_ext_local *rt)
{
struct ospf_area *oa = nf->n.oa;
struct top_hash_entry *en = nf->n.en;
- int propagate;
if (!rt_is_nssa(nf) || !oa->translate)
return 0;
- /* Condensed area network found */
+ /* Condensed area network found */
if (fib_route(&oa->enet_fib, nf->fn.prefix, nf->fn.pxlen))
return 0;
- if (!en || (en->lsa.type != LSA_T_NSSA))
+ if (!en || (en->lsa_type != LSA_T_NSSA))
return 0;
/* We do not store needed data in struct orta, we have to parse the LSA */
- struct ospf_lsa_ext *le = en->lsa_body;
-
-#ifdef OSPFv2
- *rt_fwaddr = le->fwaddr;
- *rt_tag = le->tag;
- propagate = en->lsa.options & OPT_P;
-#else /* OSPFv3 */
- u32 *buf = le->rest;
- u8 pxlen = (*buf >> 24);
- u8 pxopts = (*buf >> 16);
- buf += IPV6_PREFIX_WORDS(pxlen); /* Skip the IP prefix */
-
- if (pxopts & OPT_PX_NU)
- return 0;
-
- if (le->metric & LSA_EXT_FBIT)
- buf = lsa_get_ipv6_addr(buf, rt_fwaddr);
- else
- *rt_fwaddr = IPA_NONE;
-
- if (le->metric & LSA_EXT_TBIT)
- *rt_tag = *buf++;
- else
- *rt_tag = 0;
+ lsa_parse_ext(en, ospf_is_v2(p), rt);
- propagate = pxopts & OPT_PX_P;
-#endif
+ if (rt->pxopts & OPT_PX_NU)
+ return 0;
- if (!propagate || ipa_zero(*rt_fwaddr))
+ if (!rt->propagate || ipa_zero(rt->fwaddr))
return 0;
- *rt_metric = le->metric & (METRIC_MASK | LSA_EXT_EBIT);
return 1;
}
/* RFC 3103 3.2 - translating Type-7 LSAs into Type-5 LSAs */
static inline void
-check_nssa_lsa(struct proto_ospf *po, ort *nf)
+check_nssa_lsa(struct ospf_proto *p, ort *nf)
{
- struct fib_node *fn = &nf->fn;
struct area_net *anet = NULL;
struct ospf_area *oa = NULL;
- u32 rt_metric, rt_tag;
- ip_addr rt_fwaddr;
+ struct ospf_lsa_ext_local rt;
/* Do not translate LSA if there is already the external LSA from route export */
- if (fn->x1 == EXT_EXPORT)
+ if (nf->external_rte)
return;
- /* RT entry marked as area network */
- if (fn->x0)
+ if (nf->area_net)
{
/* Find that area network */
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
{
- anet = (struct area_net *) fib_find(&oa->enet_fib, &fn->prefix, fn->pxlen);
+ anet = (struct area_net *) fib_find(&oa->enet_fib, &nf->fn.prefix, nf->fn.pxlen);
if (anet)
break;
}
@@ -1283,59 +1176,57 @@ check_nssa_lsa(struct proto_ospf *po, ort *nf)
/* RFC 3103 3.2 (3) - originate the aggregated address range */
if (anet && anet->active && !anet->hidden && oa->translate)
- originate_ext_lsa(po->backbone, fn, EXT_NSSA, anet->metric, IPA_NONE, anet->tag, 0);
+ ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, anet->metric,
+ (anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0);
/* RFC 3103 3.2 (2) - originate the same network */
- else if (decide_nssa_lsa(nf, &rt_metric, &rt_fwaddr, &rt_tag))
- originate_ext_lsa(po->backbone, fn, EXT_NSSA, rt_metric, rt_fwaddr, rt_tag, 0);
-
- else if (fn->x1 == EXT_NSSA)
- flush_ext_lsa(po->backbone, fn, 0);
+ else if (decide_nssa_lsa(p, nf, &rt))
+ ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0);
}
/* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
static void
-ospf_check_vlinks(struct proto_ospf *po)
+ospf_check_vlinks(struct ospf_proto *p)
{
- struct proto *p = &po->proto;
-
struct ospf_iface *ifa;
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
{
if (ifa->type == OSPF_IT_VLINK)
{
struct top_hash_entry *tmp;
- tmp = ospf_hash_find_rt(po->gr, ifa->voa->areaid, ifa->vid);
+ tmp = ospf_hash_find_rt(p->gr, ifa->voa->areaid, ifa->vid);
if (tmp && (tmp->color == INSPF) && ipa_nonzero(tmp->lb) && tmp->nhs)
{
- struct ospf_iface *nhi = ospf_iface_find(po, tmp->nhs->iface);
+ struct ospf_iface *nhi = ospf_iface_find(p, tmp->nhs->iface);
- if ((ifa->state != OSPF_IS_PTP)
+ if ((ifa->state != OSPF_IS_PTP)
|| (ifa->vifa != nhi)
|| !ipa_equal(ifa->vip, tmp->lb))
- {
- OSPF_TRACE(D_EVENTS, "Vlink peer %R found", tmp->lsa.id);
- ospf_iface_sm(ifa, ISM_DOWN);
+ {
+ OSPF_TRACE(D_EVENTS, "Vlink peer %R found", ifa->vid);
+ ospf_iface_sm(ifa, ISM_DOWN);
ifa->vifa = nhi;
ifa->addr = nhi->addr;
ifa->cost = tmp->dist;
- ifa->vip = tmp->lb;
- ospf_iface_sm(ifa, ISM_UP);
- }
+ ifa->vip = tmp->lb;
+ ospf_iface_sm(ifa, ISM_UP);
+ }
else if ((ifa->state == OSPF_IS_PTP) && (ifa->cost != tmp->dist))
{
ifa->cost = tmp->dist;
- schedule_rt_lsa(po->backbone);
+
+ /* RFC 2328 12.4 Event 8 - vlink state change */
+ ospf_notify_rt_lsa(ifa->oa);
}
}
else
{
- if (ifa->state > OSPF_IS_DOWN)
- {
- OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", ifa->vid);
+ if (ifa->state > OSPF_IS_DOWN)
+ {
+ OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", ifa->vid);
ospf_iface_sm(ifa, ISM_DOWN);
- }
+ }
}
}
}
@@ -1344,13 +1235,13 @@ ospf_check_vlinks(struct proto_ospf *po)
/* Miscellaneous route processing that needs to be done by ABRs */
static void
-ospf_rt_abr1(struct proto_ospf *po)
+ospf_rt_abr1(struct ospf_proto *p)
{
struct area_net *anet;
ort *nf, *default_nf;
/* RFC 2328 G.3 - incomplete resolution of virtual next hops - routers */
- FIB_WALK(&po->backbone->rtr, nftmp)
+ FIB_WALK(&p->backbone->rtr, nftmp)
{
nf = (ort *) nftmp;
@@ -1360,7 +1251,7 @@ ospf_rt_abr1(struct proto_ospf *po)
FIB_WALK_END;
- FIB_WALK(&po->rtf, nftmp)
+ FIB_WALK(&p->rtf, nftmp)
{
nf = (ort *) nftmp;
@@ -1381,8 +1272,8 @@ ospf_rt_abr1(struct proto_ospf *po)
anet->active = 1;
/* Get a RT entry and mark it to know that it is an area network */
- ort *nfi = (ort *) fib_get(&po->rtf, &anet->fn.prefix, anet->fn.pxlen);
- nfi->fn.x0 = 1; /* mark and keep persistent, to have stable UID */
+ ort *nfi = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
+ nfi->area_net = 1;
/* 16.2. (3) */
if (nfi->n.type == RTS_OSPF_IA)
@@ -1397,18 +1288,16 @@ ospf_rt_abr1(struct proto_ospf *po)
FIB_WALK_END;
ip_addr addr = IPA_NONE;
- default_nf = (ort *) fib_get(&po->rtf, &addr, 0);
- default_nf->fn.x0 = 1; /* keep persistent */
+ default_nf = (ort *) fib_get(&p->rtf, &addr, 0);
+ default_nf->area_net = 1;
struct ospf_area *oa;
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
{
/* 12.4.3.1. - originate or flush default route for stub/NSSA areas */
if (oa_is_stub(oa) || (oa_is_nssa(oa) && !oa->ac->summary))
- originate_sum_net_lsa(oa, &default_nf->fn, oa->ac->default_cost);
- else
- flush_sum_lsa(oa, &default_nf->fn, ORT_NET);
+ ospf_originate_sum_net_lsa(p, oa, default_nf, oa->ac->default_cost);
/*
* Originate type-7 default route for NSSA areas
@@ -1420,10 +1309,8 @@ ospf_rt_abr1(struct proto_ospf *po)
*/
if (oa_is_nssa(oa) && oa->ac->default_nssa)
- originate_ext_lsa(oa, &default_nf->fn, 0, oa->ac->default_cost, IPA_NONE, 0, 0);
- else
- flush_ext_lsa(oa, &default_nf->fn, 1);
-
+ ospf_originate_ext_lsa(p, oa, default_nf, LSA_M_RTCALC, oa->ac->default_cost,
+ (oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0);
/* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
if (oa_is_ext(oa))
@@ -1432,7 +1319,7 @@ ospf_rt_abr1(struct proto_ospf *po)
{
nf = (ort *) nftmp;
if (nf->n.options & ORTA_ASBR)
- ri_install_asbr(po, &nf->fn.prefix, &nf->n);
+ ri_install_asbr(p, &nf->fn.prefix, &nf->n);
}
FIB_WALK_END;
}
@@ -1440,15 +1327,15 @@ ospf_rt_abr1(struct proto_ospf *po)
/* Originate or flush ASBR summary LSAs */
- FIB_WALK(&po->backbone->rtr, nftmp)
+ FIB_WALK(&p->backbone->rtr, nftmp)
{
- check_sum_rt_lsa(po, (ort *) nftmp);
+ check_sum_rt_lsa(p, (ort *) nftmp);
}
FIB_WALK_END;
/* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
- ospf_check_vlinks(po);
+ ospf_check_vlinks(p);
}
@@ -1456,16 +1343,16 @@ static void
translator_timer_hook(timer *timer)
{
struct ospf_area *oa = timer->data;
-
+
if (oa->translate != TRANS_WAIT)
return;
oa->translate = TRANS_OFF;
- schedule_rtcalc(oa->po);
+ ospf_schedule_rtcalc(oa->po);
}
static void
-ospf_rt_abr2(struct proto_ospf *po)
+ospf_rt_abr2(struct ospf_proto *p)
{
struct ospf_area *oa;
struct top_hash_entry *en;
@@ -1473,8 +1360,8 @@ ospf_rt_abr2(struct proto_ospf *po)
/* RFC 3103 3.1 - type-7 translator election */
- struct ospf_area *bb = po->backbone;
- WALK_LIST(oa, po->area_list)
+ struct ospf_area *bb = p->backbone;
+ WALK_LIST(oa, p->area_list)
if (oa_is_nssa(oa))
{
int translate = 1;
@@ -1492,13 +1379,13 @@ ospf_rt_abr2(struct proto_ospf *po)
if (!nf2 || !nf2->n.type || !(nf2->n.options & ORTA_ABR))
continue;
- en = ospf_hash_find_rt(po->gr, oa->areaid, nf->n.rid);
+ en = ospf_hash_find_rt(p->gr, oa->areaid, nf->n.rid);
if (!en || (en->color != INSPF))
continue;
struct ospf_lsa_rt *rt = en->lsa_body;
/* There is better candidate - Nt-bit or higher Router ID */
- if ((rt->options & OPT_RT_NT) || (po->router_id < nf->n.rid))
+ if ((rt->options & OPT_RT_NT) || (p->router_id < nf->n.rid))
{
translate = 0;
goto decided;
@@ -1518,7 +1405,7 @@ ospf_rt_abr2(struct proto_ospf *po)
if (!translate && (oa->translate == TRANS_ON))
{
if (oa->translator_timer == NULL)
- oa->translator_timer = tm_new_set(po->proto.pool, translator_timer_hook, oa, 0, 0);
+ oa->translator_timer = tm_new_set(p->p.pool, translator_timer_hook, oa, 0, 0);
/* Schedule the end of translation */
tm_start(oa->translator_timer, oa->ac->transint);
@@ -1528,7 +1415,7 @@ ospf_rt_abr2(struct proto_ospf *po)
/* Compute condensed external networks */
- FIB_WALK(&po->rtf, nftmp)
+ FIB_WALK(&p->rtf, nftmp)
{
nf = (ort *) nftmp;
if (rt_is_nssa(nf) && (nf->n.options & ORTA_PROP))
@@ -1543,12 +1430,12 @@ ospf_rt_abr2(struct proto_ospf *po)
anet->active = 1;
/* Get a RT entry and mark it to know that it is an area network */
- nf2 = (ort *) fib_get(&po->rtf, &anet->fn.prefix, anet->fn.pxlen);
- nf2->fn.x0 = 1;
+ nf2 = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
+ nf2->area_net = 1;
}
u32 metric = (nf->n.type == RTS_OSPF_EXT1) ?
- nf->n.metric1 : ((nf->n.metric2 + 1) | LSA_EXT_EBIT);
+ nf->n.metric1 : ((nf->n.metric2 + 1) | LSA_EXT3_EBIT);
if (anet->metric < metric)
anet->metric = metric;
@@ -1558,12 +1445,12 @@ ospf_rt_abr2(struct proto_ospf *po)
FIB_WALK_END;
- FIB_WALK(&po->rtf, nftmp)
+ FIB_WALK(&p->rtf, nftmp)
{
nf = (ort *) nftmp;
- check_sum_net_lsa(po, nf);
- check_nssa_lsa(po, nf);
+ check_sum_net_lsa(p, nf);
+ check_nssa_lsa(p, nf);
}
FIB_WALK_END;
}
@@ -1589,78 +1476,46 @@ ospf_fib_route(struct fib *f, ip_addr a, int len)
/* RFC 2328 16.4. calculating external routes */
static void
-ospf_ext_spf(struct proto_ospf *po)
+ospf_ext_spf(struct ospf_proto *p)
{
+ struct top_hash_entry *en;
+ struct ospf_lsa_ext_local rt;
ort *nf1, *nf2;
orta nfa = {};
- struct top_hash_entry *en;
- struct proto *p = &po->proto;
- struct ospf_lsa_ext *le;
- int pxlen, ebit, rt_fwaddr_valid, rt_propagate;
- ip_addr ip, rtid, rt_fwaddr;
- u32 br_metric, rt_metric, rt_tag;
+ ip_addr rtid;
+ u32 br_metric;
struct ospf_area *atmp;
OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes");
- WALK_SLIST(en, po->lsal)
+ WALK_SLIST(en, p->lsal)
{
/* 16.4. (1) */
- if ((en->lsa.type != LSA_T_EXT) && (en->lsa.type != LSA_T_NSSA))
+ if ((en->lsa_type != LSA_T_EXT) && (en->lsa_type != LSA_T_NSSA))
continue;
if (en->lsa.age == LSA_MAXAGE)
continue;
/* 16.4. (2) */
- if (en->lsa.rt == po->router_id)
+ if (en->lsa.rt == p->router_id)
continue;
DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
- p->name, en->lsa.id, en->lsa.rt, en->lsa.type);
+ p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type);
- le = en->lsa_body;
+ lsa_parse_ext(en, ospf_is_v2(p), &rt);
- rt_metric = le->metric & METRIC_MASK;
- ebit = le->metric & LSA_EXT_EBIT;
-
- if (rt_metric == LSINFINITY)
+ if (rt.metric == LSINFINITY)
continue;
-#ifdef OSPFv2
- ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask);
- pxlen = ipa_mklen(le->netmask);
- rt_fwaddr = le->fwaddr;
- rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE);
- rt_tag = le->tag;
- rt_propagate = en->lsa.options & OPT_P;
-#else /* OSPFv3 */
- u8 pxopts;
- u16 rest;
- u32 *buf = le->rest;
- buf = lsa_get_ipv6_prefix(buf, &ip, &pxlen, &pxopts, &rest);
-
- if (pxopts & OPT_PX_NU)
+ if (rt.pxopts & OPT_PX_NU)
continue;
- rt_fwaddr_valid = le->metric & LSA_EXT_FBIT;
- if (rt_fwaddr_valid)
- buf = lsa_get_ipv6_addr(buf, &rt_fwaddr);
- else
- rt_fwaddr = IPA_NONE;
-
- if (le->metric & LSA_EXT_TBIT)
- rt_tag = *buf++;
- else
- rt_tag = 0;
-
- rt_propagate = pxopts & OPT_PX_P;
-#endif
-
- if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
+ if (rt.pxlen < 0 || rt.pxlen > MAX_PREFIX_LENGTH)
{
log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
- p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
+ p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
continue;
}
@@ -1669,10 +1524,10 @@ ospf_ext_spf(struct proto_ospf *po)
/* If there are more areas, we already precomputed preferred ASBR
entries in ospf_rt_abr1() and stored them in the backbone
table. For NSSA, we examine the area to which the LSA is assigned */
- if (en->lsa.type == LSA_T_EXT)
- atmp = ospf_main_area(po);
+ if (en->lsa_type == LSA_T_EXT)
+ atmp = ospf_main_area(p);
else /* NSSA */
- atmp = ospf_find_area(po, en->domain);
+ atmp = ospf_find_area(p, en->domain);
if (!atmp)
continue; /* Should not happen */
@@ -1688,11 +1543,11 @@ ospf_ext_spf(struct proto_ospf *po)
/* 16.4. (3) NSSA - special rule for default routes */
/* ABR should use default only if P-bit is set and summaries are active */
- if ((en->lsa.type == LSA_T_NSSA) && ipa_zero(ip) && (pxlen == 0) &&
- (po->areano > 1) && !(rt_propagate && atmp->ac->summary))
+ if ((en->lsa_type == LSA_T_NSSA) && ipa_zero(rt.ip) && (rt.pxlen == 0) &&
+ (p->areano > 1) && !(rt.propagate && atmp->ac->summary))
continue;
- if (!rt_fwaddr_valid)
+ if (!rt.fbit)
{
nf2 = nf1;
nfa.nhs = nf1->n.nhs;
@@ -1700,11 +1555,11 @@ ospf_ext_spf(struct proto_ospf *po)
}
else
{
- nf2 = ospf_fib_route(&po->rtf, rt_fwaddr, MAX_PREFIX_LENGTH);
+ nf2 = ospf_fib_route(&p->rtf, rt.fwaddr, MAX_PREFIX_LENGTH);
if (!nf2)
continue;
- if (en->lsa.type == LSA_T_EXT)
+ if (en->lsa_type == LSA_T_EXT)
{
/* For ext routes, we accept intra-area or inter-area routes */
if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA))
@@ -1727,21 +1582,21 @@ ospf_ext_spf(struct proto_ospf *po)
/* Replace device nexthops with nexthops to forwarding address from LSA */
if (has_device_nexthops(nfa.nhs))
{
- nfa.nhs = fix_device_nexthops(po, nfa.nhs, rt_fwaddr);
+ nfa.nhs = fix_device_nexthops(p, nfa.nhs, rt.fwaddr);
nfa.nhs_reuse = 1;
}
}
- if (ebit)
+ if (rt.ebit)
{
nfa.type = RTS_OSPF_EXT2;
nfa.metric1 = br_metric;
- nfa.metric2 = rt_metric;
+ nfa.metric2 = rt.metric;
}
else
{
nfa.type = RTS_OSPF_EXT1;
- nfa.metric1 = br_metric + rt_metric;
+ nfa.metric1 = br_metric + rt.metric;
nfa.metric2 = LSINFINITY;
}
@@ -1750,25 +1605,25 @@ ospf_ext_spf(struct proto_ospf *po)
/* Whether the route is preferred in route selection according to 16.4.1 */
nfa.options = epath_preferred(&nf2->n) ? ORTA_PREF : 0;
- if (en->lsa.type == LSA_T_NSSA)
+ if (en->lsa_type == LSA_T_NSSA)
{
nfa.options |= ORTA_NSSA;
- if (rt_propagate)
+ if (rt.propagate)
nfa.options |= ORTA_PROP;
}
- nfa.tag = rt_tag;
+ nfa.tag = rt.tag;
nfa.rid = en->lsa.rt;
nfa.oa = atmp; /* undefined in RFC 2328 */
nfa.en = en; /* store LSA for later (NSSA processing) */
- ri_install_ext(po, ip, pxlen, &nfa);
+ ri_install_ext(p, rt.ip, rt.pxlen, &nfa);
}
}
/* Cleanup of routing tables and data */
void
-ospf_rt_reset(struct proto_ospf *po)
+ospf_rt_reset(struct ospf_proto *p)
{
struct ospf_area *oa;
struct top_hash_entry *en;
@@ -1776,24 +1631,27 @@ ospf_rt_reset(struct proto_ospf *po)
ort *ri;
/* Reset old routing table */
- FIB_WALK(&po->rtf, nftmp)
+ FIB_WALK(&p->rtf, nftmp)
{
ri = (ort *) nftmp;
- ri->fn.x0 = 0;
+ ri->area_net = 0;
reset_ri(ri);
}
FIB_WALK_END;
/* Reset SPF data in LSA db */
- WALK_SLIST(en, po->lsal)
+ WALK_SLIST(en, p->lsal)
{
en->color = OUTSPF;
en->dist = LSINFINITY;
en->nhs = NULL;
en->lb = IPA_NONE;
+
+ if (en->mode == LSA_M_RTCALC)
+ en->mode = LSA_M_STALE;
}
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
{
/* Reset ASBR routing tables */
FIB_WALK(&oa->rtr, nftmp)
@@ -1804,7 +1662,7 @@ ospf_rt_reset(struct proto_ospf *po)
FIB_WALK_END;
/* Reset condensed area networks */
- if (po->areano > 1)
+ if (p->areano > 1)
{
FIB_WALK(&oa->net_fib, nftmp)
{
@@ -1827,51 +1685,50 @@ ospf_rt_reset(struct proto_ospf *po)
/**
* ospf_rt_spf - calculate internal routes
- * @po: OSPF protocol
+ * @p: OSPF protocol instance
*
* Calculation of internal paths in an area is described in 16.1 of RFC 2328.
* It's based on Dijkstra's shortest path tree algorithms.
* This function is invoked from ospf_disp().
*/
void
-ospf_rt_spf(struct proto_ospf *po)
+ospf_rt_spf(struct ospf_proto *p)
{
- struct proto *p = &po->proto;
struct ospf_area *oa;
- if (po->areano == 0)
+ if (p->areano == 0)
return;
OSPF_TRACE(D_EVENTS, "Starting routing table calculation");
/* 16. (1) */
- ospf_rt_reset(po);
+ ospf_rt_reset(p);
/* 16. (2) */
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
ospf_rt_spfa(oa);
/* 16. (3) */
- ospf_rt_sum(ospf_main_area(po));
+ ospf_rt_sum(ospf_main_area(p));
/* 16. (4) */
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
if (oa->trcap && (oa->areaid != 0))
ospf_rt_sum_tr(oa);
- if (po->areano > 1)
- ospf_rt_abr1(po);
+ if (p->areano > 1)
+ ospf_rt_abr1(p);
/* 16. (5) */
- ospf_ext_spf(po);
+ ospf_ext_spf(p);
- if (po->areano > 1)
- ospf_rt_abr2(po);
+ if (p->areano > 1)
+ ospf_rt_abr2(p);
- rt_sync(po);
- lp_flush(po->nhpool);
-
- po->calcrt = 0;
+ rt_sync(p);
+ lp_flush(p->nhpool);
+
+ p->calcrt = 0;
}
@@ -1886,21 +1743,20 @@ static struct mpnh *
calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
struct top_hash_entry *par, int pos)
{
- // struct proto *p = &oa->po->proto;
- struct proto_ospf *po = oa->po;
+ struct ospf_proto *p = oa->po;
struct mpnh *pn = par->nhs;
struct ospf_iface *ifa;
u32 rid = en->lsa.rt;
/* 16.1.1. The next hop calculation */
DBG(" Next hop calculating for id: %R rt: %R type: %u\n",
- en->lsa.id, en->lsa.rt, en->lsa.type);
+ en->lsa.id, en->lsa.rt, en->lsa_type);
/* Usually, we inherit parent nexthops */
if (inherit_nexthops(pn))
return pn;
- /*
+ /*
* There are three cases:
* 1) en is a local network (and par is root)
* 2) en is a ptp or ptmp neighbor (and par is root)
@@ -1908,72 +1764,74 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
*/
/* The first case - local network */
- if ((en->lsa.type == LSA_T_NET) && (par == oa->rt))
+ if ((en->lsa_type == LSA_T_NET) && (par == oa->rt))
{
ifa = rt_pos_to_ifa(oa, pos);
if (!ifa)
return NULL;
- return new_nexthop(po, IPA_NONE, ifa->iface, ifa->ecmp_weight);
+ return new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight);
}
/* The second case - ptp or ptmp neighbor */
- if ((en->lsa.type == LSA_T_RT) && (par == oa->rt))
+ if ((en->lsa_type == LSA_T_RT) && (par == oa->rt))
{
ifa = rt_pos_to_ifa(oa, pos);
if (!ifa)
return NULL;
if (ifa->type == OSPF_IT_VLINK)
- return new_nexthop(po, IPA_NONE, NULL, 0);
+ return new_nexthop(p, IPA_NONE, NULL, 0);
struct ospf_neighbor *m = find_neigh(ifa, rid);
if (!m || (m->state != NEIGHBOR_FULL))
return NULL;
- return new_nexthop(po, m->ip, ifa->iface, ifa->ecmp_weight);
+ return new_nexthop(p, m->ip, ifa->iface, ifa->ecmp_weight);
}
/* The third case - bcast or nbma neighbor */
- if ((en->lsa.type == LSA_T_RT) && (par->lsa.type == LSA_T_NET))
+ if ((en->lsa_type == LSA_T_RT) && (par->lsa_type == LSA_T_NET))
{
/* par->nhi should be defined from parent's calc_next_hop() */
if (!pn)
goto bad;
-#ifdef OSPFv2
- /*
- * In this case, next-hop is the same as link-back, which is
- * already computed in link_back().
- */
- if (ipa_zero(en->lb))
- goto bad;
+ if (ospf_is_v2(p))
+ {
+ /*
+ * In this case, next-hop is the same as link-back, which is
+ * already computed in link_back().
+ */
+ if (ipa_zero(en->lb))
+ goto bad;
- return new_nexthop(po, en->lb, pn->iface, pn->weight);
+ return new_nexthop(p, en->lb, pn->iface, pn->weight);
+ }
+ else /* OSPFv3 */
+ {
+ /*
+ * Next-hop is taken from lladdr field of Link-LSA, en->lb_id
+ * is computed in link_back().
+ */
+ struct top_hash_entry *lhe;
+ lhe = ospf_hash_find(p->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
-#else /* OSPFv3 */
- /*
- * Next-hop is taken from lladdr field of Link-LSA, en->lb_id
- * is computed in link_back().
- */
- struct top_hash_entry *lhe;
- lhe = ospf_hash_find(po->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
+ if (!lhe)
+ return NULL;
- if (!lhe)
- return NULL;
+ struct ospf_lsa_link *llsa = lhe->lsa_body;
- struct ospf_lsa_link *llsa = lhe->lsa_body;
-
- if (ipa_zero(llsa->lladdr))
- return NULL;
+ if (ip6_zero(llsa->lladdr))
+ return NULL;
- return new_nexthop(po, llsa->lladdr, pn->iface, pn->weight);
-#endif
+ return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight);
+ }
}
bad:
/* Probably bug or some race condition, we log it */
- log(L_ERR "Unexpected case in next hop calculation");
+ log(L_ERR "%s: Unexpected case in next hop calculation", p->p.name);
return NULL;
}
@@ -1983,7 +1841,7 @@ static void
add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
u32 dist, struct ospf_area *oa, int pos)
{
- struct proto_ospf *po = oa->po;
+ struct ospf_proto *p = oa->po;
node *prev, *n;
int added = 0;
struct top_hash_entry *act;
@@ -1994,14 +1852,13 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
if (en->lsa.age == LSA_MAXAGE)
return;
-#ifdef OSPFv3
- if (en->lsa.type == LSA_T_RT)
- {
- struct ospf_lsa_rt *rt = en->lsa_body;
- if (!(rt->options & OPT_V6))
- return;
- }
-#endif
+ if (ospf_is_v3(p) && (en->lsa_type == LSA_T_RT))
+ {
+ /* In OSPFv3, check V6 flag */
+ struct ospf_lsa_rt *rt = en->lsa_body;
+ if (!(rt->options & OPT_V6))
+ return;
+ }
/* 16.1. (2c) */
if (en->color == INSPF)
@@ -2018,8 +1875,8 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
struct mpnh *nhs = calc_next_hop(oa, en, par, pos);
if (!nhs)
{
- log(L_WARN "Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)",
- en->lsa.type, en->lsa.id, en->lsa.rt);
+ log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)",
+ p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
return;
}
@@ -2042,18 +1899,18 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
*/
/* Keep old ones */
- if (!po->ecmp || nh_is_vlink(nhs) || (nhs == en->nhs))
+ if (!p->ecmp || nh_is_vlink(nhs) || (nhs == en->nhs))
return;
/* Merge old and new */
int new_reuse = (par->nhs != nhs);
- en->nhs = merge_nexthops(po, en->nhs, nhs, en->nhs_reuse, new_reuse);
+ en->nhs = merge_nexthops(p, en->nhs, nhs, en->nhs_reuse, new_reuse);
en->nhs_reuse = 1;
return;
}
DBG(" Adding candidate: rt: %R, id: %R, type: %u\n",
- en->lsa.rt, en->lsa.id, en->lsa.type);
+ en->lsa.rt, en->lsa.id, en->lsa_type);
if (en->color == CANDIDATE)
{ /* We found a shorter path */
@@ -2076,7 +1933,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
{
act = SKIP_BACK(struct top_hash_entry, cn, n);
if ((act->dist > dist) ||
- ((act->dist == dist) && (act->lsa.type == LSA_T_RT)))
+ ((act->dist == dist) && (act->lsa_type == LSA_T_RT)))
{
if (prev == NULL)
add_head(l, &en->cn);
@@ -2108,16 +1965,16 @@ ort_changed(ort *nf, rta *nr)
}
static void
-rt_sync(struct proto_ospf *po)
+rt_sync(struct ospf_proto *p)
{
- struct proto *p = &po->proto;
+ struct top_hash_entry *en;
struct fib_iterator fit;
- struct fib *fib = &po->rtf;
+ struct fib *fib = &p->rtf;
ort *nf;
struct ospf_area *oa;
/* This is used for forced reload of routes */
- int reload = (po->calcrt == 2);
+ int reload = (p->calcrt == 2);
OSPF_TRACE(D_EVENTS, "Starting routing table synchronisation");
@@ -2135,7 +1992,7 @@ again1:
for (nh = nf->n.nhs; nh; nh = nh->next)
if (ipa_nonzero(nh->gw))
{
- neighbor *ng = neigh_find2(p, &nh->gw, nh->iface, 0);
+ neighbor *ng = neigh_find2(&p->p, &nh->gw, nh->iface, 0);
if (!ng || (ng->scope == SCOPE_HOST))
{ reset_ri(nf); break; }
}
@@ -2148,7 +2005,7 @@ again1:
if (nf->n.type) /* Add the route */
{
rta a0 = {
- .src = p->main_source,
+ .src = p->p.main_source,
.source = nf->n.type,
.scope = SCOPE_UNIVERSE,
.cast = RTC_UNICAST
@@ -2173,7 +2030,7 @@ again1:
if (reload || ort_changed(nf, &a0))
{
- net *ne = net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
+ net *ne = net_get(p->p.table, nf->fn.prefix, nf->fn.pxlen);
rta *a = rta_lookup(&a0);
rte *e = rte_get_temp(a);
@@ -2185,11 +2042,11 @@ again1:
e->u.ospf.router_id = nf->old_rid = nf->n.rid;
e->pflags = 0;
e->net = ne;
- e->pref = p->preference;
+ e->pref = p->p.preference;
DBG("Mod rte type %d - %I/%d via %I on iface %s, met %d\n",
a0.source, nf->fn.prefix, nf->fn.pxlen, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1);
- rte_update(p, ne, e);
+ rte_update(&p->p, ne, e);
}
}
else if (nf->old_rta)
@@ -2198,12 +2055,12 @@ again1:
rta_free(nf->old_rta);
nf->old_rta = NULL;
- net *ne = net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
- rte_update(p, ne, NULL);
+ net *ne = net_get(p->p.table, nf->fn.prefix, nf->fn.pxlen);
+ rte_update(&p->p, ne, NULL);
}
- /* Remove unused rt entry. Entries with fn.x0 == 1 are persistent. */
- if (!nf->n.type && !nf->fn.x0 && !nf->fn.x1)
+ /* Remove unused rt entry, some special entries are persistent */
+ if (!nf->n.type && !nf->external_rte && !nf->area_net)
{
FIB_ITERATE_PUT(&fit, nftmp);
fib_delete(fib, nftmp);
@@ -2213,7 +2070,7 @@ again1:
FIB_ITERATE_END(nftmp);
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, p->area_list)
{
/* Cleanup ASBR hash tables */
FIB_ITERATE_INIT(&fit, &oa->rtr);
@@ -2231,4 +2088,9 @@ again2:
}
FIB_ITERATE_END(nftmp);
}
+
+ /* Cleanup stale LSAs */
+ WALK_SLIST(en, p->lsal)
+ if (en->mode == LSA_M_STALE)
+ ospf_flush_lsa(p, en);
}
diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h
index a11748fc..61936f3c 100644
--- a/proto/ospf/rt.h
+++ b/proto/ospf/rt.h
@@ -2,17 +2,18 @@
* 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.
- *
*/
#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
{
@@ -28,12 +29,17 @@ typedef struct orta
#define ORTA_ASBR OPT_RT_E
#define ORTA_ABR OPT_RT_B
/*
- * For ORT_NET routes, the field is almost unused with one
- * exception: ORTA_PREF for external routes means that the route is
- * preferred in AS external route selection according to 16.4.1. -
- * it is intra-area path using non-backbone area. In other words,
- * the forwarding address (or ASBR if forwarding address is zero) is
- * intra-area (type == RTS_OSPF) and its area is not a backbone.
+ * For ORT_NET routes, there are just several flags for external routes:
+ *
+ * ORTA_PREF for external routes means that the route is preferred in AS
+ * external route selection according to 16.4.1. - it is intra-area path using
+ * non-backbone area. In other words, the forwarding address (or ASBR if
+ * forwarding address is zero) is intra-area (type == RTS_OSPF) and its area
+ * is not a backbone.
+ *
+ * ORTA_NSSA means that the entry represents an NSSA route, and ORTA_PROP
+ * means that the NSSA route has propagate-bit set. These flags are used in
+ * NSSA translation.
*/
#define ORTA_PREF 0x80000000
#define ORTA_NSSA 0x40000000
@@ -54,31 +60,35 @@ orta;
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 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()).
+ * Most OSPF routing table entries are for computed OSPF routes, these have
+ * defined n.type. There are also few other cases: entries for configured area
+ * networks (these have area_net field set) and entries for external routes
+ * exported to OSPF (these have external_rte field set). These entries are
+ * kept even if they do not contain 'proper' rt entry. That is needed to keep
+ * allocated stable UID numbers (fn.uid), which are used as LSA IDs in OSPFv3
+ * (see fibnode_to_lsaid()) for related LSAs (network summary LSAs in the
+ * first case, external or NSSA LSAs in the second case). Entries for external
+ * routes also have a second purpose - to prevent NSSA translation of received
+ * NSSA routes if regular external routes were already originated for the same
+ * network (see 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
- * case other old_* values are not valid.
+ * 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 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;
+ u8 area_net;
}
ort;
static inline int rt_is_nssa(ort *nf)
{ return nf->n.options & ORTA_NSSA; }
-#define EXT_EXPORT 1
-#define EXT_NSSA 2
/*
* Invariants for structs top_hash_entry (nodes of LSA db)
@@ -90,7 +100,7 @@ static inline int rt_is_nssa(ort *nf)
* - beware, nhs is not valid after SPF calculation
*
* Invariants for structs orta nodes of fib tables po->rtf, oa->rtr:
- * - nodes may be invalid (fn.type == 0), in that case other invariants don't hold
+ * - nodes may be invalid (n.type == 0), in that case other invariants don't hold
* - n.metric1 may be at most a small multiple of LSINFINITY,
* therefore sums do not overflow
* - n.oa is always non-NULL
@@ -114,7 +124,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);
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 4af5afa5..0613d34d 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -3,6 +3,8 @@
*
* (c) 1999 Martin Mares <mj@ucw.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.
*/
@@ -12,6 +14,7 @@
#include "ospf.h"
+
#define HASH_DEF_ORDER 6
#define HASH_HI_MARK *4
#define HASH_HI_STEP 2
@@ -20,166 +23,625 @@
#define HASH_LO_STEP 2
#define HASH_LO_MIN 8
-void originate_prefix_rt_lsa(struct ospf_area *oa);
-void originate_prefix_net_lsa(struct ospf_iface *ifa);
-void flush_prefix_net_lsa(struct ospf_iface *ifa);
+static inline void * lsab_flush(struct ospf_proto *p);
+static inline void lsab_reset(struct ospf_proto *p);
+
-#ifdef OSPFv2
-#define ipa_to_rid(x) _I(x)
-#else /* OSPFv3 */
-#define ipa_to_rid(x) _I3(x)
-#endif
+/**
+ * ospf_install_lsa - install new LSA into database
+ * @p: OSPF protocol instance
+ * @lsa: LSA header
+ * @type: type of LSA
+ * @domain: domain of LSA
+ * @body: pointer to LSA body
+ *
+ * This function ensures installing new LSA received in LS update 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. This function is for received LSA only, locally originated LSAs are
+ * installed by ospf_originate_lsa().
+ *
+ * The LSA body in @body is expected to be mb_allocated by the caller and its
+ * ownership is transferred to the LSA entry structure.
+ */
+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 *en;
+ int change = 0;
+ en = ospf_hash_get(p->gr, domain, lsa->id, lsa->rt, type);
-#ifdef OSPFv2
-static inline u32
-fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
-{
- /* We have to map IP prefixes to u32 in such manner that resulting
- u32 interpreted as IP address is a member of given
- prefix. Therefore, /32 prefix have to be mapped on itself.
- All received prefixes have to be mapped on different u32s.
-
- We have an assumption that if there is nontrivial (non-/32)
- network prefix, then there is not /32 prefix for the first
- and the last IP address of the network (these are usually
- reserved, therefore it is not an important restriction).
- The network prefix is mapped to the first or the last
- IP address in the manner that disallow collisions - we
- use IP address that cannot be used by parent prefix.
-
- For example:
- 192.168.0.0/24 maps to 192.168.0.255
- 192.168.1.0/24 maps to 192.168.1.0
- because 192.168.0.0 and 192.168.1.255 might be used by
- 192.168.0.0/23 .
-
- This is not compatible with older RFC 1583, so we have an option
- to the RFC 1583 compatible assignment (that always uses the first
- address) which disallows subnetting.
-
- Appendig E of RFC 2328 suggests different algorithm, that tries
- to maximize both compatibility and subnetting. But as it is not
- possible to have both reliably and the suggested algorithm was
- unnecessary complicated and it does crazy things like changing
- LSA ID for a network because different network appeared, we
- choose a different way. */
-
- u32 id = _I(fn->prefix);
-
- if ((po->rfc1583) || (fn->pxlen == 0) || (fn->pxlen == 32))
- return id;
+ if (!SNODE_VALID(en))
+ s_add_tail(&p->lsal, SNODE en);
- if (id & (1 << (32 - fn->pxlen)))
- return id;
+ if ((en->lsa_body == NULL) || /* No old LSA */
+ (en->lsa.length != lsa->length) ||
+ (en->lsa.type_raw != lsa->type_raw) || /* Check for OSPFv2 options */
+ (en->lsa.age == LSA_MAXAGE) ||
+ (lsa->age == LSA_MAXAGE) ||
+ memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
+ change = 1;
+
+ if ((en->lsa.age == LSA_MAXAGE) && (lsa->age == LSA_MAXAGE))
+ change = 0;
+
+ mb_free(en->lsa_body);
+ en->lsa_body = body;
+ en->lsa = *lsa;
+ en->init_age = en->lsa.age;
+ en->inst_time = now;
+
+ /*
+ * We do not set en->mode. It is either default LSA_M_BASIC, or in a special
+ * case when en is local but flushed, there is postponed LSA, self-originated
+ * LSA is received and ospf_install_lsa() is called from ospf_advance_lse(),
+ * then we have en->mode from the postponed LSA origination.
+ */
+
+ OSPF_TRACE(D_EVENTS, "Installing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x, Age: %u",
+ en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
+
+ if (change)
+ ospf_schedule_rtcalc(p);
+
+ return en;
+}
+
+/**
+ * ospf_advance_lsa - handle received unexpected self-originated LSA
+ * @p: OSPF protocol instance
+ * @en: current LSA entry or NULL
+ * @lsa: new LSA header
+ * @type: type of LSA
+ * @domain: domain of LSA
+ * @body: pointer to LSA body
+ *
+ * This function handles received unexpected self-originated LSA (@lsa, @body)
+ * by either advancing sequence number of the local LSA instance (@en) and
+ * propagating it, or installing the received LSA and immediately flushing it
+ * (if there is no local LSA; i.e., @en is NULL or MaxAge).
+ *
+ * The LSA body in @body is expected to be mb_allocated by the caller and its
+ * ownership is transferred to the LSA entry structure or it is freed.
+ */
+void
+ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body)
+{
+ /* RFC 2328 13.4 */
+
+ if (en && (en->lsa.age < LSA_MAXAGE))
+ {
+ if (lsa->sn != LSA_MAXSEQNO)
+ {
+ /*
+ * We simply advance current LSA to have higher seqnum than received LSA.
+ * The received LSA is ignored and the advanced LSA is propagated instead.
+ *
+ * Although this is an origination of distinct LSA instance and therefore
+ * should be limited by MinLSInterval, we do not enforce it here. Fast
+ * reaction is needed and we are already limited by MinLSArrival.
+ */
+
+ mb_free(body);
+
+ en->lsa.sn = lsa->sn + 1;
+ en->lsa.age = 0;
+ en->init_age = 0;
+ en->inst_time = now;
+ lsasum_calculate(&en->lsa, en->lsa_body);
+
+ OSPF_TRACE(D_EVENTS, "Advancing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
+ en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
+ }
+ else
+ {
+ /*
+ * Received LSA has maximal sequence number, so we cannot simply override
+ * it. We have to install it to the database, immediately flush it to
+ * implement sequence number wrapping, and schedule our current LSA to be
+ * originated after the received instance is flushed.
+ */
+
+ if (en->next_lsa_body == NULL)
+ {
+ /* Schedule current LSA */
+ en->next_lsa_blen = en->lsa.length - sizeof(struct ospf_lsa_header);
+ en->next_lsa_body = en->lsa_body;
+ en->next_lsa_opts = ospf_is_v2(p) ? lsa_get_options(&en->lsa) : 0;
+ }
+ else
+ {
+ /* There is already scheduled LSA, so we just free current one */
+ mb_free(en->lsa_body);
+ }
+
+ en->lsa_body = body;
+ en->lsa = *lsa;
+ en->lsa.age = LSA_MAXAGE;
+ en->init_age = lsa->age;
+ en->inst_time = now;
+
+ OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
+ en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
+ OSPF_TRACE(D_EVENTS, "Postponing LSA: Type: %04x, Id: %R, Rt: %R",
+ en->lsa_type, en->lsa.id, en->lsa.rt);
+ }
+ }
else
- return id | ~u32_mkmask(fn->pxlen);
+ {
+ /*
+ * We do not have received LSA in the database. We have to flush the
+ * received LSA. It has to be installed in the database to secure
+ * retransmissions. Note that the received LSA may already be MaxAge.
+ * Also note that en->next_lsa_* may be defined.
+ */
+
+ lsa->age = LSA_MAXAGE;
+ en = ospf_install_lsa(p, lsa, type, domain, body);
+ }
+
+ /*
+ * We flood the updated LSA. Although in some cases the to-be-flooded LSA is
+ * the same as the received LSA, and therefore we should propagate it as
+ * regular received LSA (send the acknowledgement instead of the update to
+ * the neighbor we received it from), we cheat a bit here.
+ */
+
+ ospf_flood_lsa(p, en, NULL);
}
-#else /* OSPFv3 */
-static inline u32
-fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
+static int
+ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa_body, u16 lsa_blen, u16 lsa_opts)
{
+ /* Enforce MinLSInterval */
+ if ((en->init_age == 0) && en->inst_time && ((en->inst_time + MINLSINTERVAL) > now))
+ return 0;
+
+ /* Handle wrapping sequence number */
+ if (en->lsa.sn == LSA_MAXSEQNO)
+ {
+ /* Prepare to flush old LSA */
+ if (en->lsa.age != LSA_MAXAGE)
+ {
+ OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
+ en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
+
+ en->lsa.age = LSA_MAXAGE;
+ ospf_flood_lsa(p, en, NULL);
+ return 0;
+ }
+
+ /* Already flushing */
+ if ((p->padj != 0) || (en->ret_count != 0))
+ return 0;
+
+ /* Flush done, just clean up seqnum, lsa_body is freed below */
+ en->lsa.sn = LSA_ZEROSEQNO;
+ }
+
/*
- * In OSPFv3, it is simpler. There is not a requirement for
- * membership of the result in the input network, so we just use a
- * hash-based unique ID of a routing table entry for a route that
- * originated given LSA. For ext-LSA, it is an imported route in the
- * nest's routing table (p->table). For summary-LSA, it is a
- * 'source' route in the protocol internal routing table (po->rtf).
+ * lsa.type_raw is initialized by ospf_hash_get() to OSPFv3 LSA type.
+ * lsa_set_options() implicitly converts it to OSPFv2 LSA type, assuming that
+ * old type is just new type masked by 0xff. That is not universally true,
+ * but it holds for all OSPFv2 types currently supported by BIRD.
*/
- return fn->uid;
+
+ if (ospf_is_v2(p))
+ lsa_set_options(&en->lsa, lsa_opts);
+
+ mb_free(en->lsa_body);
+ en->lsa_body = lsa_body;
+ en->lsa.length = sizeof(struct ospf_lsa_header) + lsa_blen;
+ en->lsa.sn++;
+ en->lsa.age = 0;
+ en->init_age = 0;
+ en->inst_time = now;
+ lsasum_calculate(&en->lsa, en->lsa_body);
+
+ OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
+ en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
+
+ ospf_flood_lsa(p, en, NULL);
+
+ if (en->mode == LSA_M_BASIC)
+ ospf_schedule_rtcalc(p);
+
+ return 1;
}
-#endif
+/**
+ * ospf_originate_lsa - originate new LSA
+ * @p: OSPF protocol instance
+ * @lsa: New LSA specification
+ *
+ * This function prepares a new LSA, installs it into the LSA database and
+ * floods it. If the new LSA cannot be originated now (because the old instance
+ * was originated within MinLSInterval, or because the LSA seqnum is currently
+ * wrapping), the origination is instead scheduled for later. If the new LSA is
+ * equivalent to the current LSA, the origination is skipped. In all cases, the
+ * corresponding LSA entry is returned. The new LSA is based on the LSA
+ * specification (@lsa) and the LSA body from lsab buffer of @p, which is
+ * emptied after the call. The opposite of this function is ospf_flush_lsa().
+ */
+struct top_hash_entry *
+ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
+{
+ struct top_hash_entry *en;
+ void *lsa_body = p->lsab;
+ u16 lsa_blen = p->lsab_used;
+ u16 lsa_length = sizeof(struct ospf_lsa_header) + lsa_blen;
+
+ en = ospf_hash_get(p->gr, lsa->dom, lsa->id, p->router_id, lsa->type);
+ if (!SNODE_VALID(en))
+ s_add_tail(&p->lsal, SNODE en);
-static void *
-lsab_alloc(struct proto_ospf *po, unsigned size)
+ if (en->lsa_body == NULL)
+ en->nf = lsa->nf;
+
+ if (en->nf != lsa->nf)
+ {
+ log(L_ERR "%s: LSA ID collision for %I/%d",
+ p->p.name, lsa->nf->fn.prefix, lsa->nf->fn.pxlen);
+
+ en = NULL;
+ goto drop;
+ }
+
+ if (en->mode != lsa->mode)
+ en->mode = lsa->mode;
+
+ if (en->next_lsa_body)
+ {
+ /* Ignore the new LSA if it is the same as the scheduled one */
+ if ((lsa_blen == en->next_lsa_blen) &&
+ !memcmp(lsa_body, en->next_lsa_body, lsa_blen) &&
+ (!ospf_is_v2(p) || (lsa->opts == en->next_lsa_opts)))
+ goto drop;
+
+ /* Free scheduled LSA */
+ mb_free(en->next_lsa_body);
+ en->next_lsa_body = NULL;
+ en->next_lsa_blen = 0;
+ en->next_lsa_opts = 0;
+ }
+
+ /* Ignore the the new LSA if is the same as the current one */
+ if ((en->lsa.age < LSA_MAXAGE) &&
+ (lsa_length == en->lsa.length) &&
+ !memcmp(lsa_body, en->lsa_body, lsa_blen) &&
+ (!ospf_is_v2(p) || (lsa->opts == lsa_get_options(&en->lsa))))
+ goto drop;
+
+ lsa_body = lsab_flush(p);
+
+ if (! ospf_do_originate_lsa(p, en, lsa_body, lsa_blen, lsa->opts))
+ {
+ OSPF_TRACE(D_EVENTS, "Postponing LSA: Type: %04x, Id: %R, Rt: %R",
+ en->lsa_type, en->lsa.id, en->lsa.rt);
+
+ en->next_lsa_body = lsa_body;
+ en->next_lsa_blen = lsa_blen;
+ en->next_lsa_opts = lsa->opts;
+ }
+
+ return en;
+
+ drop:
+ lsab_reset(p);
+ return en;
+}
+
+static void
+ospf_originate_next_lsa(struct ospf_proto *p, struct top_hash_entry *en)
+{
+ /* Called by ospf_update_lsadb() to handle scheduled origination */
+
+ if (! ospf_do_originate_lsa(p, en, en->next_lsa_body, en->next_lsa_blen, en->next_lsa_opts))
+ return;
+
+ en->next_lsa_body = NULL;
+ en->next_lsa_blen = 0;
+ en->next_lsa_opts = 0;
+}
+
+static void
+ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
+{
+ /*
+ * Called by ospf_update_lsadb() for periodic LSA refresh.
+ *
+ * We know that lsa.age < LSA_MAXAGE and lsa.rt is our router ID. We can also
+ * assume that there is no scheduled LSA, because inst_time is deep in past,
+ * therefore ospf_originate_next_lsa() called before would either succeed or
+ * switched lsa.age to LSA_MAXAGE.
+ */
+
+ OSPF_TRACE(D_EVENTS, "Refreshing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
+ en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
+
+ ASSERT(en->next_lsa_body == NULL);
+
+ /* Handle wrapping sequence number */
+ if (en->lsa.sn == LSA_MAXSEQNO)
+ {
+ /* Copy LSA body as next LSA to get automatic origination after flush is finished */
+ en->next_lsa_blen = en->lsa.length - sizeof(struct ospf_lsa_header);
+ en->next_lsa_body = mb_alloc(p->p.pool, en->next_lsa_blen);
+ memcpy(en->next_lsa_body, en->lsa_body, en->next_lsa_blen);
+ en->next_lsa_opts = ospf_is_v2(p) ? lsa_get_options(&en->lsa) : 0;
+
+ en->lsa.age = LSA_MAXAGE;
+ ospf_flood_lsa(p, en, NULL);
+ return;
+ }
+
+ en->lsa.sn++;
+ en->lsa.age = 0;
+ en->init_age = 0;
+ en->inst_time = now;
+ lsasum_calculate(&en->lsa, en->lsa_body);
+ ospf_flood_lsa(p, en, NULL);
+}
+
+/**
+ * ospf_flush_lsa - flush LSA from OSPF domain
+ * @p: OSPF protocol instance
+ * @en: LSA entry to flush
+ *
+ * This function flushes @en from the OSPF domain by setting its age to
+ * %LSA_MAXAGE and flooding it. That also triggers subsequent events in LSA
+ * lifecycle leading to removal of the LSA from the LSA database (e.g. the LSA
+ * content is freed when flushing is acknowledged by neighbors). The function
+ * does nothing if the LSA is already being flushed. LSA entries are not
+ * immediately removed when being flushed, the caller may assume that @en still
+ * exists after the call. The function is the opposite of ospf_originate_lsa()
+ * and is supposed to do the right thing even in cases of postponed
+ * origination.
+ */
+void
+ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en)
{
- unsigned offset = po->lsab_used;
- po->lsab_used += size;
- if (po->lsab_used > po->lsab_size)
+ if (en->next_lsa_body)
+ {
+ mb_free(en->next_lsa_body);
+ en->next_lsa_body = NULL;
+ en->next_lsa_blen = 0;
+ en->next_lsa_opts = 0;
+ }
+
+ if (en->lsa.age == LSA_MAXAGE)
+ return;
+
+ OSPF_TRACE(D_EVENTS, "Flushing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
+ en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
+
+ en->lsa.age = LSA_MAXAGE;
+ ospf_flood_lsa(p, en, NULL);
+
+ if (en->mode == LSA_M_BASIC)
+ ospf_schedule_rtcalc(p);
+
+ en->mode = LSA_M_BASIC;
+}
+
+static void
+ospf_clear_lsa(struct ospf_proto *p, struct top_hash_entry *en)
+{
+ /*
+ * Called by ospf_update_lsadb() as part of LSA flushing process.
+ * Flushed LSA was acknowledged by neighbors and we can free its content.
+ * The log message is for 'remove' - we hide empty LSAs from users.
+ */
+
+ OSPF_TRACE(D_EVENTS, "Removing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
+ en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
+
+ if (en->lsa.sn == LSA_MAXSEQNO)
+ en->lsa.sn = LSA_ZEROSEQNO;
+
+ mb_free(en->lsa_body);
+ en->lsa_body = NULL;
+}
+
+static void
+ospf_remove_lsa(struct ospf_proto *p, struct top_hash_entry *en)
+{
+ /*
+ * Called by ospf_update_lsadb() as part of LSA flushing process.
+ * Both lsa_body and next_lsa_body are NULL.
+ */
+
+ s_rem_node(SNODE en);
+ ospf_hash_delete(p->gr, en);
+}
+
+/**
+ * ospf_update_lsadb - update LSA database
+ * @p: OSPF protocol instance
+ *
+ * This function is periodicaly invoked from ospf_disp(). It does some periodic
+ * or postponed processing related to LSA entries. It originates postponed LSAs
+ * scheduled by ospf_originate_lsa(), It continues in flushing processes started
+ * by ospf_flush_lsa(). It also periodically refreshs locally originated LSAs --
+ * when the current instance is older %LSREFRESHTIME, a new instance is originated.
+ * Finally, it also ages stored LSAs and flushes ones that reached %LSA_MAXAGE.
+ *
+ * The RFC 2328 says that a router should periodically check checksums of all
+ * stored LSAs to detect hardware problems. This is not implemented.
+ */
+void
+ospf_update_lsadb(struct ospf_proto *p)
+{
+ struct top_hash_entry *en, *nxt;
+ bird_clock_t real_age;
+
+ WALK_SLIST_DELSAFE(en, nxt, p->lsal)
+ {
+ if (en->next_lsa_body)
+ ospf_originate_next_lsa(p, en);
+
+ real_age = en->init_age + (now - en->inst_time);
+
+ if (en->lsa.age == LSA_MAXAGE)
+ {
+ if (en->lsa_body && (p->padj == 0) && (en->ret_count == 0))
+ ospf_clear_lsa(p, en);
+
+ if ((en->lsa_body == NULL) && (en->next_lsa_body == NULL) &&
+ ((en->lsa.rt != p->router_id) || (real_age >= LSA_MAXAGE)))
+ ospf_remove_lsa(p, en);
+
+ continue;
+ }
+
+ if ((en->lsa.rt == p->router_id) && (real_age >= LSREFRESHTIME))
+ {
+ ospf_refresh_lsa(p, en);
+ continue;
+ }
+
+ if (real_age >= LSA_MAXAGE)
{
- po->lsab_size = MAX(po->lsab_used, 2 * po->lsab_size);
- po->lsab = po->lsab ? mb_realloc(po->lsab, po->lsab_size):
- mb_alloc(po->proto.pool, po->lsab_size);
+ ospf_flush_lsa(p, en);
+ continue;
}
- return ((byte *) po->lsab) + offset;
+
+ en->lsa.age = real_age;
+ }
+}
+
+
+static inline u32
+ort_to_lsaid(struct ospf_proto *p, ort *nf)
+{
+ /*
+ * In OSPFv2, We have to map IP prefixes to u32 in such manner that resulting
+ * u32 interpreted as IP address is a member of given prefix. Therefore, /32
+ * prefix have to be mapped on itself. All received prefixes have to be
+ * mapped on different u32s.
+ *
+ * We have an assumption that if there is nontrivial (non-/32) network prefix,
+ * then there is not /32 prefix for the first and the last IP address of the
+ * network (these are usually reserved, therefore it is not an important
+ * restriction). The network prefix is mapped to the first or the last IP
+ * address in the manner that disallow collisions - we use the IP address that
+ * cannot be used by the parent prefix.
+ *
+ * For example:
+ * 192.168.0.0/24 maps to 192.168.0.255
+ * 192.168.1.0/24 maps to 192.168.1.0
+ * because 192.168.0.0 and 192.168.1.255 might be used by 192.168.0.0/23 .
+ *
+ * Appendig E of RFC 2328 suggests different algorithm, that tries to maximize
+ * both compatibility and subnetting. But as it is not possible to have both
+ * reliably and the suggested algorithm was unnecessary complicated and it
+ * does crazy things like changing LSA ID for a network because different
+ * network appeared, we choose a different way.
+ *
+ * In OSPFv3, it is simpler. There is not a requirement for membership of the
+ * result in the input network, so we just use a hash-based unique ID of a
+ * routing table entry for a route that originated given LSA. For ext-LSA, it
+ * is an imported route in the nest's routing table (p->table). For summary-LSA,
+ * it is a 'source' route in the protocol internal routing table (p->rtf).
+ */
+
+ if (ospf_is_v3(p))
+ return nf->fn.uid;
+
+ u32 id = ipa_to_u32(nf->fn.prefix);
+ int pxlen = nf->fn.pxlen;
+
+ if ((pxlen == 0) || (pxlen == 32))
+ return id;
+
+ if (id & (1 << (32 - pxlen)))
+ return id;
+ else
+ return id | ~u32_mkmask(pxlen);
+}
+
+
+static void *
+lsab_alloc(struct ospf_proto *p, uint size)
+{
+ uint offset = p->lsab_used;
+ p->lsab_used += size;
+ if (p->lsab_used > p->lsab_size)
+ {
+ p->lsab_size = MAX(p->lsab_used, 2 * p->lsab_size);
+ p->lsab = p->lsab ? mb_realloc(p->lsab, p->lsab_size):
+ mb_alloc(p->p.pool, p->lsab_size);
+ }
+ return ((byte *) p->lsab) + offset;
}
static inline void *
-lsab_allocz(struct proto_ospf *po, unsigned size)
+lsab_allocz(struct ospf_proto *p, uint size)
{
- void *r = lsab_alloc(po, size);
+ void *r = lsab_alloc(p, size);
bzero(r, size);
return r;
}
static inline void *
-lsab_flush(struct proto_ospf *po)
+lsab_flush(struct ospf_proto *p)
{
- void *r = mb_alloc(po->proto.pool, po->lsab_used);
- memcpy(r, po->lsab, po->lsab_used);
- po->lsab_used = 0;
+ void *r = mb_alloc(p->p.pool, p->lsab_used);
+ memcpy(r, p->lsab, p->lsab_used);
+ p->lsab_used = 0;
return r;
}
-static inline void *
-lsab_offset(struct proto_ospf *po, unsigned offset)
+static inline void
+lsab_reset(struct ospf_proto *p)
{
- return ((byte *) po->lsab) + offset;
+ p->lsab_used = 0;
}
static inline void *
-lsab_end(struct proto_ospf *po)
+lsab_offset(struct ospf_proto *p, uint offset)
{
- return ((byte *) po->lsab) + po->lsab_used;
+ return ((byte *) p->lsab) + offset;
}
-static s32
-get_seqnum(struct top_hash_entry *en)
+static inline void *
+lsab_end(struct ospf_proto *p)
{
- if (!en)
- return LSA_INITSEQNO;
-
- if (en->lsa.sn == LSA_MAXSEQNO)
- {
- log(L_WARN "OSPF: Premature origination of LSA (Type: %04x, Id: %R, Rt: %R)",
- en->lsa.type, en->lsa.id, en->lsa.rt);
- return LSA_INITSEQNO;
- }
-
- return en->lsa.sn + 1;
+ return ((byte *) p->lsab) + p->lsab_used;
}
+/*
+ * Router-LSA handling
+ * Type = LSA_T_RT
+ */
+
static int
configured_stubnet(struct ospf_area *oa, struct ifa *a)
{
- if (!oa->ac)
- return 0;
-
/* Does not work for IA_PEER addresses, but it is not called on these */
struct ospf_stubnet_config *sn;
WALK_LIST(sn, oa->ac->stubnet_list)
+ {
+ if (sn->summary)
{
- if (sn->summary)
- {
- if (ipa_in_net(a->prefix, sn->px.addr, sn->px.len) && (a->pxlen >= sn->px.len))
- return 1;
- }
- else
- {
- if (ipa_equal(a->prefix, sn->px.addr) && (a->pxlen == sn->px.len))
- return 1;
- }
+ if (ipa_in_net(a->prefix, sn->px.addr, sn->px.len) && (a->pxlen >= sn->px.len))
+ return 1;
}
+ else
+ {
+ if (ipa_equal(a->prefix, sn->px.addr) && (a->pxlen == sn->px.len))
+ return 1;
+ }
+ }
+
return 0;
}
-int
+static int
bcast_net_active(struct ospf_iface *ifa)
{
struct ospf_neighbor *neigh;
@@ -188,53 +650,66 @@ bcast_net_active(struct ospf_iface *ifa)
return 0;
WALK_LIST(neigh, ifa->neigh_list)
+ {
+ if (neigh->state == NEIGHBOR_FULL)
{
- if (neigh->state == NEIGHBOR_FULL)
- {
- if (neigh->rid == ifa->drid)
- return 1;
+ if (neigh->rid == ifa->drid)
+ return 1;
- if (ifa->state == OSPF_IS_DR)
- return 1;
- }
+ if (ifa->state == OSPF_IS_DR)
+ return 1;
}
+ }
return 0;
}
+static inline u32
+get_rt_options(struct ospf_proto *p, struct ospf_area *oa, int bitv)
+{
+ u32 opts = 0;
-#ifdef OSPFv2
+ if (p->areano > 1)
+ opts |= OPT_RT_B;
-static void *
-originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
-{
- struct proto_ospf *po = oa->po;
- struct ospf_iface *ifa;
- int i = 0, bitv = 0;
- struct ospf_lsa_rt *rt;
- struct ospf_lsa_rt_link *ln;
- struct ospf_neighbor *neigh;
+ if ((p->areano > 1) && oa_is_nssa(oa) && oa->ac->translator)
+ opts |= OPT_RT_NT;
- ASSERT(po->lsab_used == 0);
- rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt));
+ if (p->asbr && !oa_is_stub(oa))
+ opts |= OPT_RT_E;
- rt->options = 0;
+ if (bitv)
+ opts |= OPT_RT_V;
- if (po->areano > 1)
- rt->options |= OPT_RT_B;
+ return opts;
+}
- if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator)
- rt->options |= OPT_RT_NT;
+static inline void
+add_rt2_lsa_link(struct ospf_proto *p, u8 type, u32 id, u32 data, u16 metric)
+{
+ struct ospf_lsa_rt2_link *ln = lsab_alloc(p, sizeof(struct ospf_lsa_rt2_link));
+ ln->type = type;
+ ln->id = id;
+ ln->data = data;
+ ln->metric = metric;
+ ln->no_tos = 0;
+}
- if (po->ebit && !oa_is_stub(oa))
- rt->options |= OPT_RT_E;
+static void
+prepare_rt2_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
+{
+ struct ospf_iface *ifa;
+ int i = 0, bitv = 0;
+ struct ospf_neighbor *neigh;
- rt = NULL; /* buffer might be reallocated later */
+ ASSERT(p->lsab_used == 0);
+ lsab_allocz(p, sizeof(struct ospf_lsa_rt));
+ /* ospf_lsa_rt header will be filled later */
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
{
int net_lsa = 0;
- u32 link_cost = po->stub_router ? 0xffff : ifa->cost;
+ u32 link_cost = p->stub_router ? 0xffff : ifa->cost;
if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) &&
(!EMPTY_LIST(ifa->neigh_list)))
@@ -249,66 +724,47 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
ifa->rt_pos_beg = i;
- /* RFC2328 - 12.4.1.1-4 */
+ /* RFC 2328 - 12.4.1.1-4 */
switch (ifa->type)
- {
- case OSPF_IT_PTP:
- case OSPF_IT_PTMP:
- WALK_LIST(neigh, ifa->neigh_list)
- if (neigh->state == NEIGHBOR_FULL)
- {
- ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
- ln->type = LSART_PTP;
- ln->id = neigh->rid;
-
- /*
- * ln->data should be ifa->iface_id in case of no/ptp
- * address (ifa->addr->flags & IA_PEER) on PTP link (see
- * RFC 2328 12.4.1.1.), but the iface ID value has no use,
- * while using IP address even in this case is here for
- * compatibility with some broken implementations that use
- * this address as a next-hop.
- */
- ln->data = ipa_to_u32(ifa->addr->ip);
- ln->metric = link_cost;
- ln->padding = 0;
- i++;
- }
- break;
-
- case OSPF_IT_BCAST:
- case OSPF_IT_NBMA:
- if (bcast_net_active(ifa))
- {
- ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
- ln->type = LSART_NET;
- ln->id = ipa_to_u32(ifa->drip);
- ln->data = ipa_to_u32(ifa->addr->ip);
- ln->metric = link_cost;
- ln->padding = 0;
- i++;
- net_lsa = 1;
- }
- break;
-
- case OSPF_IT_VLINK:
- neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
- if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
+ {
+ case OSPF_IT_PTP:
+ case OSPF_IT_PTMP:
+ WALK_LIST(neigh, ifa->neigh_list)
+ if (neigh->state == NEIGHBOR_FULL)
{
- ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
- ln->type = LSART_VLNK;
- ln->id = neigh->rid;
- ln->data = ipa_to_u32(ifa->addr->ip);
- ln->metric = link_cost;
- ln->padding = 0;
+ /*
+ * ln->data should be ifa->iface_id in case of no/ptp
+ * address (ifa->addr->flags & IA_PEER) on PTP link (see
+ * RFC 2328 12.4.1.1.), but the iface ID value has no use,
+ * while using IP address even in this case is here for
+ * compatibility with some broken implementations that use
+ * this address as a next-hop.
+ */
+ add_rt2_lsa_link(p, LSART_PTP, neigh->rid, ipa_to_u32(ifa->addr->ip), link_cost);
i++;
- }
- break;
+ }
+ break;
- default:
- log("Unknown interface type %s", ifa->ifname);
- break;
+ case OSPF_IT_BCAST:
+ case OSPF_IT_NBMA:
+ if (bcast_net_active(ifa))
+ {
+ add_rt2_lsa_link(p, LSART_NET, ipa_to_u32(ifa->drip), ipa_to_u32(ifa->addr->ip), link_cost);
+ i++;
+ net_lsa = 1;
}
+ break;
+
+ case OSPF_IT_VLINK:
+ neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
+ if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
+ add_rt2_lsa_link(p, LSART_VLNK, neigh->rid, ipa_to_u32(ifa->addr->ip), link_cost), i++;
+ break;
+
+ default:
+ log(L_BUG "OSPF: Unknown interface type");
+ break;
+ }
ifa->rt_pos_end = i;
@@ -319,62 +775,32 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
configured_stubnet(oa, ifa->addr))
continue;
- ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
+ /* Host or network stub entry */
if ((ifa->addr->flags & IA_HOST) ||
(ifa->state == OSPF_IS_LOOP) ||
(ifa->type == OSPF_IT_PTMP))
- {
- /* Host stub entry */
- ln->type = LSART_STUB;
- ln->id = ipa_to_u32(ifa->addr->ip);
- ln->data = 0xffffffff;
- ln->metric = 0;
- ln->padding = 0;
- }
- else
- {
- /* Network stub entry */
- ln->type = LSART_STUB;
- ln->id = ipa_to_u32(ifa->addr->prefix);
- ln->data = ipa_to_u32(ipa_mkmask(ifa->addr->pxlen));
- ln->metric = ifa->cost;
- ln->padding = 0;
- }
+ add_rt2_lsa_link(p, LSART_STUB, ipa_to_u32(ifa->addr->ip), 0xffffffff, 0);
+ else
+ add_rt2_lsa_link(p, LSART_STUB, ipa_to_u32(ifa->addr->prefix), u32_mkmask(ifa->addr->pxlen), ifa->cost);
i++;
ifa->rt_pos_end = i;
}
struct ospf_stubnet_config *sn;
- if (oa->ac)
- WALK_LIST(sn, oa->ac->stubnet_list)
- if (!sn->hidden)
- {
- ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
- ln->type = LSART_STUB;
- ln->id = ipa_to_u32(sn->px.addr);
- ln->data = ipa_to_u32(ipa_mkmask(sn->px.len));
- ln->metric = sn->cost;
- ln->padding = 0;
- i++;
- }
-
- rt = po->lsab;
- rt->links = i;
-
- if (bitv)
- rt->options |= OPT_RT_V;
+ WALK_LIST(sn, oa->ac->stubnet_list)
+ if (!sn->hidden)
+ add_rt2_lsa_link(p, LSART_STUB, ipa_to_u32(sn->px.addr), u32_mkmask(sn->px.len), sn->cost), i++;
- *length = po->lsab_used + sizeof(struct ospf_lsa_header);
- return lsab_flush(po);
+ struct ospf_lsa_rt *rt = p->lsab;
+ /* Store number of links in lower half of options */
+ rt->options = get_rt_options(p, oa, bitv) | (u16) i;
}
-#else /* OSPFv3 */
-
-static void
-add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif, u32 id)
+static inline void
+add_rt3_lsa_link(struct ospf_proto *p, u8 type, struct ospf_iface *ifa, u32 nif, u32 id)
{
- struct ospf_lsa_rt_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
+ struct ospf_lsa_rt3_link *ln = lsab_alloc(p, sizeof(struct ospf_lsa_rt3_link));
ln->type = type;
ln->padding = 0;
ln->metric = ifa->cost;
@@ -383,33 +809,19 @@ add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif,
ln->id = id;
}
-static void *
-originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
+static void
+prepare_rt3_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
{
- struct proto_ospf *po = oa->po;
struct ospf_iface *ifa;
+ struct ospf_neighbor *neigh;
int bitv = 0;
int i = 0;
- struct ospf_lsa_rt *rt;
- struct ospf_neighbor *neigh;
-
- ASSERT(po->lsab_used == 0);
- rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt));
- rt->options = oa->options & OPTIONS_MASK;
+ ASSERT(p->lsab_used == 0);
+ lsab_allocz(p, sizeof(struct ospf_lsa_rt));
+ /* ospf_lsa_rt header will be filled later */
- if (po->areano > 1)
- rt->options |= OPT_RT_B;
-
- if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator)
- rt->options |= OPT_RT_NT;
-
- if (po->ebit && !oa_is_stub(oa))
- rt->options |= OPT_RT_E;
-
- rt = NULL; /* buffer might be reallocated later */
-
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
{
if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) &&
(!EMPTY_LIST(ifa->neigh_list)))
@@ -424,854 +836,556 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
ifa->rt_pos_beg = i;
- /* RFC5340 - 4.4.3.2 */
+ /* RFC 5340 - 4.4.3.2 */
switch (ifa->type)
- {
- case OSPF_IT_PTP:
- case OSPF_IT_PTMP:
- WALK_LIST(neigh, ifa->neigh_list)
- if (neigh->state == NEIGHBOR_FULL)
- add_lsa_rt_link(po, ifa, LSART_PTP, neigh->iface_id, neigh->rid), i++;
- break;
-
- case OSPF_IT_BCAST:
- case OSPF_IT_NBMA:
- if (bcast_net_active(ifa))
- add_lsa_rt_link(po, ifa, LSART_NET, ifa->dr_iface_id, ifa->drid), i++;
- break;
-
- case OSPF_IT_VLINK:
- neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
- if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
- add_lsa_rt_link(po, ifa, LSART_VLNK, neigh->iface_id, neigh->rid), i++;
- break;
-
- default:
- log("Unknown interface type %s", ifa->ifname);
- break;
- }
-
- ifa->rt_pos_end = i;
- }
-
- if (bitv)
{
- rt = po->lsab;
- rt->options |= OPT_RT_V;
- }
-
- *length = po->lsab_used + sizeof(struct ospf_lsa_header);
- return lsab_flush(po);
-}
-
-#endif
+ case OSPF_IT_PTP:
+ case OSPF_IT_PTMP:
+ WALK_LIST(neigh, ifa->neigh_list)
+ if (neigh->state == NEIGHBOR_FULL)
+ add_rt3_lsa_link(p, LSART_PTP, ifa, neigh->iface_id, neigh->rid), i++;
+ break;
-/**
- * originate_rt_lsa - build new instance of router LSA
- * @oa: ospf_area which is LSA built to
- *
- * It builds router LSA walking through all OSPF interfaces in
- * specified OSPF area. This function is mostly called from
- * area_disp(). Builds new LSA, increases sequence number (if old
- * instance exists) and sets age of LSA to zero.
- */
-void
-originate_rt_lsa(struct ospf_area *oa)
-{
- struct ospf_lsa_header lsa;
- struct proto_ospf *po = oa->po;
- struct proto *p = &po->proto;
- void *body;
+ case OSPF_IT_BCAST:
+ case OSPF_IT_NBMA:
+ if (bcast_net_active(ifa))
+ add_rt3_lsa_link(p, LSART_NET, ifa, ifa->dr_iface_id, ifa->drid), i++;
+ break;
- OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid);
+ case OSPF_IT_VLINK:
+ neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
+ if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
+ add_rt3_lsa_link(p, LSART_VLNK, ifa, neigh->iface_id, neigh->rid), i++;
+ break;
- lsa.age = 0;
- lsa.type = LSA_T_RT;
-
-#ifdef OSPFv2
- lsa.options = oa->options;
- lsa.id = po->router_id;
-#else /* OSPFv3 */
- lsa.id = 0;
-#endif
+ default:
+ log(L_BUG "OSPF: Unknown interface type");
+ break;
+ }
- lsa.rt = po->router_id;
- lsa.sn = get_seqnum(oa->rt);
- u32 dom = oa->areaid;
+ ifa->rt_pos_end = i;
+ }
- body = originate_rt_lsa_body(oa, &lsa.length);
- lsasum_calculate(&lsa, body);
- oa->rt = lsa_install_new(po, &lsa, dom, body);
- ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
+ struct ospf_lsa_rt *rt = p->lsab;
+ rt->options = get_rt_options(p, oa, bitv) | (oa->options & LSA_OPTIONS_MASK);
}
-void
-update_rt_lsa(struct ospf_area *oa)
+static void
+ospf_originate_rt_lsa(struct ospf_proto *p, struct ospf_area *oa)
{
- struct proto_ospf *po = oa->po;
+ struct ospf_new_lsa lsa = {
+ .type = LSA_T_RT,
+ .dom = oa->areaid,
+ .id = ospf_is_v2(p) ? p->router_id : 0,
+ .opts = oa->options
+ };
- if ((oa->rt) && ((oa->rt->inst_t + MINLSINTERVAL)) > now)
- return;
- /*
- * Tick is probably set to very low value. We cannot
- * originate new LSA before MINLSINTERVAL. We will
- * try to do it next tick.
- */
+ OSPF_TRACE(D_EVENTS, "Updating router state for area %R", oa->areaid);
- originate_rt_lsa(oa);
-#ifdef OSPFv3
- originate_prefix_rt_lsa(oa);
-#endif
+ if (ospf_is_v2(p))
+ prepare_rt2_lsa_body(p, oa);
+ else
+ prepare_rt3_lsa_body(p, oa);
- schedule_rtcalc(po);
- oa->origrt = 0;
+ oa->rt = ospf_originate_lsa(p, &lsa);
}
-static void *
-originate_net_lsa_body(struct ospf_iface *ifa, u16 *length,
- struct proto_ospf *po)
+
+/*
+ * Net-LSA handling
+ * Type = LSA_T_NET
+ */
+
+static void
+prepare_net2_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
{
- u16 i = 1;
- struct ospf_neighbor *n;
struct ospf_lsa_net *net;
+ struct ospf_neighbor *n;
int nodes = ifa->fadj + 1;
+ u16 i = 1;
- net = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_net)
- + nodes * sizeof(u32));
-
-#ifdef OSPFv2
- net->netmask = ipa_mkmask(ifa->addr->pxlen);
-#endif
-
-#ifdef OSPFv3
- /* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */
- struct top_hash_entry *en;
- u32 options = 0;
-#endif
+ ASSERT(p->lsab_used == 0);
+ net = lsab_alloc(p, sizeof(struct ospf_lsa_net) + 4 * nodes);
- net->routers[0] = po->router_id;
+ net->optx = u32_mkmask(ifa->addr->pxlen);
+ net->routers[0] = p->router_id;
WALK_LIST(n, ifa->neigh_list)
{
if (n->state == NEIGHBOR_FULL)
{
-#ifdef OSPFv3
- en = ospf_hash_find(po->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK);
- if (en)
- options |= ((struct ospf_lsa_link *) en->lsa_body)->options;
-#endif
-
net->routers[i] = n->rid;
i++;
}
}
ASSERT(i == nodes);
-
-#ifdef OSPFv3
- net->options = options & OPTIONS_MASK;
-#endif
-
- *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_net)
- + nodes * sizeof(u32);
- return net;
}
-
-/**
- * originate_net_lsa - originates of deletes network LSA
- * @ifa: interface which is LSA originated for
- *
- * Interface counts number of adjacent neighbors. If this number is
- * lower than one or interface is not in state %OSPF_IS_DR it deletes
- * and premature ages instance of network LSA for specified interface.
- * In other case, new instance of network LSA is originated.
- */
-void
-originate_net_lsa(struct ospf_iface *ifa)
+static void
+prepare_net3_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
{
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
- struct ospf_lsa_header lsa;
- u32 dom = ifa->oa->areaid;
-
- void *body;
-
- OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->ifname);
-
- lsa.age = 0;
- lsa.type = LSA_T_NET;
-
-#ifdef OSPFv2
- lsa.options = ifa->oa->options;
- lsa.id = ipa_to_u32(ifa->addr->ip);
-#else /* OSPFv3 */
- lsa.id = ifa->iface_id;
-#endif
+ struct ospf_lsa_net *net;
+ int nodes = ifa->fadj + 1;
+ u32 options = 0;
+ u16 i = 1;
- lsa.rt = po->router_id;
- lsa.sn = get_seqnum(ifa->net_lsa);
+ ASSERT(p->lsab_used == 0);
+ net = lsab_alloc(p, sizeof(struct ospf_lsa_net) + 4 * nodes);
- body = originate_net_lsa_body(ifa, &lsa.length, po);
- lsasum_calculate(&lsa, body);
- ifa->net_lsa = lsa_install_new(po, &lsa, dom, body);
- ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
-}
+ net->routers[0] = p->router_id;
-void
-flush_net_lsa(struct ospf_iface *ifa)
-{
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
- u32 dom = ifa->oa->areaid;
-
- if (ifa->net_lsa == NULL)
- return;
+ struct ospf_neighbor *n;
+ WALK_LIST(n, ifa->neigh_list)
+ {
+ if (n->state == NEIGHBOR_FULL)
+ {
+ /* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */
- OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s", ifa->ifname);
- ifa->net_lsa->lsa.sn += 1;
- ifa->net_lsa->lsa.age = LSA_MAXAGE;
- lsasum_calculate(&ifa->net_lsa->lsa, ifa->net_lsa->lsa_body);
- ospf_lsupd_flood(po, NULL, NULL, &ifa->net_lsa->lsa, dom, 0);
- flush_lsa(ifa->net_lsa, po);
- ifa->net_lsa = NULL;
-}
+ struct top_hash_entry *en =
+ ospf_hash_find(p->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK);
-void
-update_net_lsa(struct ospf_iface *ifa)
-{
- struct proto_ospf *po = ifa->oa->po;
-
- if (ifa->net_lsa && ((ifa->net_lsa->inst_t + MINLSINTERVAL) > now))
- return;
- /*
- * It's too early to originate new network LSA. We will
- * try to do it next tick
- */
+ if (en)
+ options |= ((struct ospf_lsa_link *) en->lsa_body)->options;
- if ((ifa->state != OSPF_IS_DR) || (ifa->fadj == 0))
- {
- flush_net_lsa(ifa);
-#ifdef OSPFv3
- flush_prefix_net_lsa(ifa);
-#endif
- }
- else
- {
- originate_net_lsa(ifa);
-#ifdef OSPFv3
- originate_prefix_net_lsa(ifa);
-#endif
+ net->routers[i] = n->rid;
+ i++;
}
+ }
+ ASSERT(i == nodes);
- schedule_rtcalc(po);
- ifa->orignet = 0;
+ net->optx = options & LSA_OPTIONS_MASK;
}
-#ifdef OSPFv2
-
-static inline void *
-originate_sum_lsa_body(struct proto_ospf *po, u16 *length, u32 mlen, u32 metric)
+static void
+ospf_originate_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
{
- struct ospf_lsa_sum *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum));
- *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum);
+ struct ospf_new_lsa lsa = {
+ .type = LSA_T_NET,
+ .dom = ifa->oa->areaid,
+ .id = ospf_is_v2(p) ? ipa_to_u32(ifa->addr->ip) : ifa->iface_id,
+ .opts = ifa->oa->options,
+ .ifa = ifa
+ };
- sum->netmask = ipa_mkmask(mlen);
- sum->metric = metric;
+ OSPF_TRACE(D_EVENTS, "Updating network state for %s (Id: %R)", ifa->ifname, lsa.id);
- return sum;
-}
-
-#define originate_sum_net_lsa_body(po,length,fn,metric) \
- originate_sum_lsa_body(po, length, (fn)->pxlen, metric)
-
-#define originate_sum_rt_lsa_body(po,length,drid,metric,options) \
- originate_sum_lsa_body(po, length, 0, metric)
-
-static inline int
-check_sum_net_lsaid_collision(struct fib_node *fn, struct top_hash_entry *en)
-{
- struct ospf_lsa_sum *sum = en->lsa_body;
- return fn->pxlen != ipa_mklen(sum->netmask);
-}
+ if (ospf_is_v2(p))
+ prepare_net2_lsa_body(p, ifa);
+ else
+ prepare_net3_lsa_body(p, ifa);
-static inline int
-check_sum_lsa_same(struct top_hash_entry *en, u32 metric)
-{
- /* Netmask already checked in check_sum_net_lsaid_collision() */
- struct ospf_lsa_sum *sum = en->lsa_body;
- return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric);
+ ifa->net_lsa = ospf_originate_lsa(p, &lsa);
}
-#define check_sum_net_lsa_same(en,metric) \
- check_sum_lsa_same(en, metric)
-
-#define check_sum_rt_lsa_same(en,drid,metric,options) \
- check_sum_lsa_same(en, metric)
+/*
+ * (Net|Rt)-summary-LSA handling
+ * (a.k.a. Inter-Area-(Prefix|Router)-LSA)
+ * Type = LSA_T_SUM_NET, LSA_T_SUM_RT
+ */
-#else /* OSPFv3 */
-
-static inline void *
-originate_sum_net_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, u32 metric)
+static inline void
+prepare_sum2_lsa_body(struct ospf_proto *p, uint pxlen, u32 metric)
{
- int size = sizeof(struct ospf_lsa_sum_net) + IPV6_PREFIX_SPACE(fn->pxlen);
- struct ospf_lsa_sum_net *sum = mb_alloc(po->proto.pool, size);
- *length = sizeof(struct ospf_lsa_header) + size;
+ struct ospf_lsa_sum2 *sum;
+ sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum2));
+ sum->netmask = u32_mkmask(pxlen);
sum->metric = metric;
- put_ipv6_prefix(sum->prefix, fn->prefix, fn->pxlen, 0, 0);
-
- return sum;
}
-static inline int
-check_sum_net_lsaid_collision(struct fib_node *fn, struct top_hash_entry *en)
+static inline void
+prepare_sum3_net_lsa_body(struct ospf_proto *p, ort *nf, u32 metric)
{
- struct ospf_lsa_sum_net *sum = en->lsa_body;
- ip_addr prefix;
- int pxlen;
- u8 pxopts;
- u16 rest;
-
- lsa_get_ipv6_prefix(sum->prefix, &prefix, &pxlen, &pxopts, &rest);
- return (fn->pxlen != pxlen) || !ipa_equal(fn->prefix, prefix);
-}
+ struct ospf_lsa_sum3_net *sum;
-static inline int
-check_sum_net_lsa_same(struct top_hash_entry *en, u32 metric)
-{
- /* Prefix already checked in check_sum_net_lsaid_collision() */
- struct ospf_lsa_sum_net *sum = en->lsa_body;
- return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric);
+ sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) + IPV6_PREFIX_SPACE(nf->fn.pxlen));
+ sum->metric = metric;
+ put_ipv6_prefix(sum->prefix, nf->fn.prefix, nf->fn.pxlen, 0, 0);
}
-static inline void *
-originate_sum_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options)
+static inline void
+prepare_sum3_rt_lsa_body(struct ospf_proto *p, u32 drid, u32 metric, u32 options)
{
- struct ospf_lsa_sum_rt *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum_rt));
- *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum_rt);
+ struct ospf_lsa_sum3_rt *sum;
+ sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_rt));
sum->options = options;
sum->metric = metric;
sum->drid = drid;
-
- return sum;
}
-static inline int
-check_sum_rt_lsa_same(struct top_hash_entry *en, u32 drid, u32 metric, u32 options)
-{
- struct ospf_lsa_sum_rt *sum = en->lsa_body;
- return (en->lsa.sn != LSA_MAXSEQNO) && (sum->options == options) &&
- (sum->metric == metric) && (sum->drid == drid);
-}
-
-#endif
-
void
-originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric)
-{
- struct proto_ospf *po = oa->po;
- struct proto *p = &po->proto;
- struct top_hash_entry *en;
- u32 dom = oa->areaid;
- struct ospf_lsa_header lsa;
- void *body;
-
- OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)",
- fn->prefix, fn->pxlen, metric);
-
- /* options argument is used in ORT_NET and OSPFv3 only */
- lsa.age = 0;
-#ifdef OSPFv2
- lsa.options = oa->options;
-#endif
- lsa.type = LSA_T_SUM_NET;
- lsa.id = fibnode_to_lsaid(po, fn);
- lsa.rt = po->router_id;
-
- if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL)
- {
- if (check_sum_net_lsaid_collision(fn, en))
- {
- log(L_ERR "%s: LSAID collision for %I/%d",
- p->name, fn->prefix, fn->pxlen);
- return;
- }
-
- if (check_sum_net_lsa_same(en, metric))
- return;
- }
- lsa.sn = get_seqnum(en);
-
- body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric);
- lsasum_calculate(&lsa, body);
- lsa_install_new(po, &lsa, dom, body);
- ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
-}
-
-void
-originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED)
-{
- struct proto_ospf *po = oa->po;
- struct proto *p = &po->proto;
- struct top_hash_entry *en;
- u32 dom = oa->areaid;
- u32 rid = ipa_to_rid(fn->prefix);
- struct ospf_lsa_header lsa;
- void *body;
-
- OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)",
- rid, metric);
-
- lsa.age = 0;
-#ifdef OSPFv2
- lsa.options = oa->options;
-#endif
- lsa.type = LSA_T_SUM_RT;
- /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */
- lsa.id = rid;
- lsa.rt = po->router_id;
-
- options &= OPTIONS_MASK;
- if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL)
- {
- if (check_sum_rt_lsa_same(en, lsa.id, metric, options))
- return;
- }
- lsa.sn = get_seqnum(en);
+ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric)
+{
+ struct ospf_new_lsa lsa = {
+ .type = LSA_T_SUM_NET,
+ .mode = LSA_M_RTCALC,
+ .dom = oa->areaid,
+ .id = ort_to_lsaid(p, nf),
+ .opts = oa->options,
+ .nf = nf
+ };
+
+ if (ospf_is_v2(p))
+ prepare_sum2_lsa_body(p, nf->fn.pxlen, metric);
+ else
+ prepare_sum3_net_lsa_body(p, nf, metric);
- body = originate_sum_rt_lsa_body(po, &lsa.length, lsa.id, metric, options);
- lsasum_calculate(&lsa, body);
- lsa_install_new(po, &lsa, dom, body);
- ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
+ ospf_originate_lsa(p, &lsa);
}
void
-flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type)
-{
- struct proto_ospf *po = oa->po;
- struct proto *p = &po->proto;
- struct top_hash_entry *en;
- struct ospf_lsa_header lsa;
-
- lsa.rt = po->router_id;
- if (type == ORT_NET)
- {
- lsa.id = fibnode_to_lsaid(po, fn);
- lsa.type = LSA_T_SUM_NET;
- }
+ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric, u32 options)
+{
+ struct ospf_new_lsa lsa = {
+ .type = LSA_T_SUM_RT,
+ .mode = LSA_M_RTCALC,
+ .dom = oa->areaid,
+ .id = ipa_to_rid(nf->fn.prefix), /* Router ID of ASBR, irrelevant for OSPFv3 */
+ .opts = oa->options
+ };
+
+ if (ospf_is_v2(p))
+ prepare_sum2_lsa_body(p, 0, metric);
else
- {
- /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */
- lsa.id = ipa_to_rid(fn->prefix);
- lsa.type = LSA_T_SUM_RT;
- }
-
- if ((en = ospf_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL)
- {
- OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%d)",
- en->lsa.id, en->lsa.type);
-
- if ((type == ORT_NET) && check_sum_net_lsaid_collision(fn, en))
- {
- log(L_ERR "%s: LSAID collision for %I/%d",
- p->name, fn->prefix, fn->pxlen);
- return;
- }
+ prepare_sum3_rt_lsa_body(p, lsa.id, metric, options & LSA_OPTIONS_MASK);
- struct ospf_lsa_sum *sum = en->lsa_body;
- en->lsa.age = LSA_MAXAGE;
- en->lsa.sn = LSA_MAXSEQNO;
- lsasum_calculate(&en->lsa, sum);
- ospf_lsupd_flood(po, NULL, NULL, &en->lsa, oa->areaid, 1);
- if (can_flush_lsa(po)) flush_lsa(en, po);
- }
+ ospf_originate_lsa(p, &lsa);
}
-#ifdef OSPFv2
-
-static inline void *
-originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
- u32 metric, ip_addr fwaddr, u32 tag, int pbit UNUSED)
-{
- struct ospf_lsa_ext *ext = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_ext));
- *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_ext);
-
- ext->metric = metric;
- ext->netmask = ipa_mkmask(fn->pxlen);
- ext->fwaddr = fwaddr;
- ext->tag = tag;
-
- return ext;
-}
/*
- * check_ext_lsa() combines functions of check_*_lsaid_collision() and
- * check_*_lsa_same(). 'en' is existing ext LSA, and rest parameters
- * are parameters of new ext route. Function returns -1 if there is
- * LSAID collision, returns 1 if the existing LSA is the same and
- * returns 0 otherwise (in that case, we need to originate a new LSA).
- *
- * Really, checking for the same parameters is not as important as in
- * summary LSA origination, because in most cases the duplicate
- * external route propagation would be stopped by the nest. But there
- * are still some cases (route reload, the same route propagated through
- * different protocol) so it is also done here.
+ * AS-external-LSA and NSSA-LSA handling
+ * Type = LSA_T_EXT, LSA_T_NSSA
*/
-static inline int
-check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag)
+static inline void
+prepare_ext2_lsa_body(struct ospf_proto *p, uint pxlen,
+ u32 metric, u32 ebit, ip_addr fwaddr, u32 tag)
{
- struct ospf_lsa_ext *ext = en->lsa_body;
+ struct ospf_lsa_ext2 *ext;
- /* LSAID collision */
- if (fn->pxlen != ipa_mklen(ext->netmask))
- return -1;
+ ext = lsab_allocz(p, sizeof(struct ospf_lsa_ext2));
+ ext->metric = metric & LSA_METRIC_MASK;
+ ext->netmask = u32_mkmask(pxlen);
+ ext->fwaddr = ipa_to_u32(fwaddr);
+ ext->tag = tag;
- return (en->lsa.sn != LSA_MAXSEQNO) && (ext->metric == metric) &&
- (ext->tag == tag) && ipa_equal(ext->fwaddr,fwaddr);
+ if (ebit)
+ ext->metric |= LSA_EXT2_EBIT;
}
-#else /* OSPFv3 */
-
-static inline void *
-originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
- u32 metric, ip_addr fwaddr, u32 tag, int pbit)
+static inline void
+prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
+ u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit)
{
- int size = sizeof(struct ospf_lsa_ext)
- + IPV6_PREFIX_SPACE(fn->pxlen)
+ struct ospf_lsa_ext3 *ext;
+ int bsize = sizeof(struct ospf_lsa_ext3)
+ + IPV6_PREFIX_SPACE(nf->fn.pxlen)
+ (ipa_nonzero(fwaddr) ? 16 : 0)
+ (tag ? 4 : 0);
- struct ospf_lsa_ext *ext = mb_alloc(po->proto.pool, size);
- *length = sizeof(struct ospf_lsa_header) + size;
+ ext = lsab_allocz(p, bsize);
+ ext->metric = metric & LSA_METRIC_MASK;
+ u32 *buf = ext->rest;
- ext->metric = metric;
+ buf = put_ipv6_prefix(buf, nf->fn.prefix, nf->fn.pxlen, pbit ? OPT_PX_P : 0, 0);
- u32 *buf = ext->rest;
- buf = put_ipv6_prefix(buf, fn->prefix, fn->pxlen, pbit ? OPT_PX_P : 0, 0);
+ if (ebit)
+ ext->metric |= LSA_EXT3_EBIT;
if (ipa_nonzero(fwaddr))
{
- ext->metric |= LSA_EXT_FBIT;
+ ext->metric |= LSA_EXT3_FBIT;
buf = put_ipv6_addr(buf, fwaddr);
}
if (tag)
{
- ext->metric |= LSA_EXT_TBIT;
+ ext->metric |= LSA_EXT3_TBIT;
*buf++ = tag;
}
-
- return ext;
}
-static inline int
-check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag)
-{
- struct ospf_lsa_ext *ext = en->lsa_body;
- ip_addr prefix;
- int pxlen;
- u8 pxopts;
- u16 rest;
+/**
+ * originate_ext_lsa - new route received from nest and filters
+ * @p: OSPF protocol instance
+ * @oa: ospf_area for which LSA is originated
+ * @nf: network prefix and mask
+ * @mode: the mode of the LSA (LSA_M_EXPORT or LSA_M_RTCALC)
+ * @metric: the metric of a route
+ * @ebit: E-bit for route metric (bool)
+ * @fwaddr: the forwarding address
+ * @tag: the route tag
+ * @pbit: P-bit for NSSA LSAs (bool), ignored for external LSAs
+ *
+ * If I receive a message that new route is installed, I try to originate an
+ * external LSA. If @oa is an NSSA area, NSSA-LSA is originated instead.
+ * @oa should not be a stub area. @src does not specify whether the LSA
+ * is external or NSSA, but it specifies the source of origination -
+ * the export from ospf_rt_notify(), or the NSSA-EXT translation.
+ */
+void
+ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode,
+ u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit)
+{
+ struct ospf_new_lsa lsa = {
+ .type = oa ? LSA_T_NSSA : LSA_T_EXT,
+ .mode = mode, /* LSA_M_EXPORT or LSA_M_RTCALC */
+ .dom = oa ? oa->areaid : 0,
+ .id = ort_to_lsaid(p, nf),
+ .opts = oa ? (pbit ? OPT_P : 0) : OPT_E,
+ .nf = nf
+ };
+
+ if (ospf_is_v2(p))
+ prepare_ext2_lsa_body(p, nf->fn.pxlen, metric, ebit, fwaddr, tag);
+ else
+ prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit);
- u32 *buf = lsa_get_ipv6_prefix(ext->rest, &prefix, &pxlen, &pxopts, &rest);
+ ospf_originate_lsa(p, &lsa);
+}
- /* LSAID collision */
- if ((fn->pxlen != pxlen) || !ipa_equal(fn->prefix, prefix))
- return -1;
+static struct top_hash_entry *
+ospf_hash_find_(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type);
- if (en->lsa.sn == LSA_MAXSEQNO)
- return 0;
+static void
+ospf_flush_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf)
+{
+ struct top_hash_entry *en;
- u32 rt_metric = ext->metric & METRIC_MASK;
- ip_addr rt_fwaddr = IPA_NONE;
- u32 rt_tag = 0;
+ u32 type = oa ? LSA_T_NSSA : LSA_T_EXT;
+ u32 dom = oa ? oa->areaid : 0;
+ u32 id = ort_to_lsaid(p, nf);
- if (ext->metric & LSA_EXT_FBIT)
- buf = lsa_get_ipv6_addr(buf, &rt_fwaddr);
+ en = ospf_hash_find_(p->gr, dom, id, p->router_id, type);
- if (ext->metric & LSA_EXT_TBIT)
- rt_tag = *buf++;
+ if (!en || (en->nf != nf))
+ return;
- return (rt_metric == metric) && ipa_equal(rt_fwaddr, fwaddr) && (rt_tag == tag);
+ ospf_flush_lsa(p, en);
}
+static inline int
+use_gw_for_fwaddr(struct ospf_proto *p, ip_addr gw, struct iface *iface)
+{
+ struct ospf_iface *ifa;
-#endif
+ if (ipa_zero(gw) || ipa_is_link_local(gw))
+ return 0;
+
+ WALK_LIST(ifa, p->iface_list)
+ if ((ifa->iface == iface) &&
+ (!ospf_is_v2(p) || ipa_in_net(gw, ifa->addr->prefix, ifa->addr->pxlen)))
+ return 1;
+
+ return 0;
+}
static inline ip_addr
-find_surrogate_fwaddr(struct ospf_area *oa)
+find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
{
- struct proto_ospf *po = oa->po;
struct ospf_iface *ifa;
struct ifa *a, *cur_addr = NULL;
int np, cur_np = 0;
- WALK_LIST(ifa, po->iface_list)
+ /* RFC 3101 2.3 - surrogate forwarding address selection */
+
+ WALK_LIST(ifa, p->iface_list)
{
if ((ifa->oa != oa) ||
(ifa->type == OSPF_IT_VLINK))
continue;
-#ifdef OSPFv2
- a = ifa->addr;
- if (a->flags & IA_PEER)
- continue;
-
- np = ((a->flags & IA_HOST) || ifa->stub) ? 2 : 1;
- if (np > cur_np)
+ if (ospf_is_v2(p))
{
- cur_addr = a;
- cur_np = np;
- }
-
-#else /* OSPFv3 */
- WALK_LIST(a, ifa->iface->addrs)
- {
- if ((a->flags & IA_SECONDARY) ||
- (a->flags & IA_PEER) ||
- (a->scope <= SCOPE_LINK))
+ a = ifa->addr;
+ if (a->flags & IA_PEER)
continue;
- np = ((a->flags & IA_HOST) || ifa->stub) ? 2 : 1;
+ np = (a->flags & IA_HOST) ? 3 : (ifa->stub ? 2 : 1);
if (np > cur_np)
{
cur_addr = a;
cur_np = np;
}
}
-#endif
+ else /* OSPFv3 */
+ {
+ WALK_LIST(a, ifa->iface->addrs)
+ {
+ if ((a->flags & IA_SECONDARY) ||
+ (a->flags & IA_PEER) ||
+ (a->scope <= SCOPE_LINK))
+ continue;
+
+ np = (a->flags & IA_HOST) ? 3 : (ifa->stub ? 2 : 1);
+ if (np > cur_np)
+ {
+ cur_addr = a;
+ cur_np = np;
+ }
+ }
+ }
}
return cur_addr ? cur_addr->ip : IPA_NONE;
}
-
-/**
- * originate_ext_lsa - new route received from nest and filters
- * @oa: ospf_area for which LSA is originated
- * @fn: network prefix and mask
- * @src: the source of origination of the LSA (EXT_EXPORT/EXT_NSSA)
- * @metric: the metric of a route
- * @fwaddr: the forwarding address
- * @tag: the route tag
- * @pbit: P-bit for NSSA LSAs, ignored for external LSAs
- *
- * If I receive a message that new route is installed, I try to originate an
- * external LSA. If @oa is an NSSA area, NSSA-LSA is originated instead.
- * @oa should not be a stub area. @src does not specify whether the LSA
- * is external or NSSA, but it specifies the source of origination -
- * the export from ospf_rt_notify(), or the NSSA-EXT translation.
- *
- * The function also sets flag ebit. If it's the first time, the new router lsa
- * origination is necessary.
- */
void
-originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src,
- u32 metric, ip_addr fwaddr, u32 tag, int pbit)
-{
- struct proto_ospf *po = oa->po;
- struct proto *p = &po->proto;
- struct ospf_lsa_header lsa;
- struct top_hash_entry *en = NULL;
- void *body;
- int nssa = oa_is_nssa(oa);
- u32 dom = nssa ? oa->areaid : 0;
-
- OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d",
- nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
-
- lsa.age = 0;
-#ifdef OSPFv2
- lsa.options = nssa ? (pbit ? OPT_P : 0) : OPT_E;
-#endif
- lsa.type = nssa ? LSA_T_NSSA : LSA_T_EXT;
- lsa.id = fibnode_to_lsaid(po, fn);
- lsa.rt = po->router_id;
-
- if (nssa && pbit && ipa_zero(fwaddr))
- {
- /* NSSA-LSA with P-bit set must have non-zero forwarding address */
+ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *ea)
+{
+ struct ospf_proto *p = (struct ospf_proto *) P;
+ struct ospf_area *oa = NULL; /* non-NULL for NSSA-LSA */
+ ort *nf;
- fwaddr = find_surrogate_fwaddr(oa);
- if (ipa_zero(fwaddr))
- {
- log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %I/%d",
- p->name, fn->prefix, fn->pxlen);
- return;
- }
- }
+ /*
+ * There are several posibilities:
+ * 1) router in regular area - originate external LSA with global scope
+ * 2) router in NSSA area - originate area-specific NSSA-LSA
+ * 3) router in stub area - cannot export routes
+ * 4) area border router - same as (1), it is attached to backbone
+ */
- if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL)
+ if ((p->areano == 1) && oa_is_nssa(HEAD(p->area_list)))
+ oa = HEAD(p->area_list);
+
+ if (!new)
{
- int rv = check_ext_lsa(en, fn, metric, fwaddr, tag);
- if (rv < 0)
- {
- log(L_ERR "%s: LSAID collision for %I/%d",
- p->name, fn->prefix, fn->pxlen);
- return;
- }
+ nf = (ort *) fib_find(&p->rtf, &n->n.prefix, n->n.pxlen);
- if (rv > 0)
+ if (!nf || !nf->external_rte)
return;
+
+ ospf_flush_ext_lsa(p, oa, nf);
+ nf->external_rte = 0;
+
+ /* Old external route might blocked some NSSA translation */
+ if ((p->areano > 1) && rt_is_nssa(nf) && nf->n.oa->translate)
+ ospf_schedule_rtcalc(p);
+
+ return;
}
- lsa.sn = get_seqnum(en);
- body = originate_ext_lsa_body(po, &lsa.length, fn, metric, fwaddr, tag, pbit);
- lsasum_calculate(&lsa, body);
+ ASSERT(p->asbr);
+
+ /* Get route attributes */
+ rta *a = new->attrs;
+ u32 m1 = ea_get_int(ea, EA_OSPF_METRIC1, LSINFINITY);
+ u32 m2 = ea_get_int(ea, EA_OSPF_METRIC2, 10000);
+ int ebit = (m1 == LSINFINITY);
+ u32 metric = ebit ? m2 : m1;
+ u32 tag = ea_get_int(ea, EA_OSPF_TAG, 0);
+ ip_addr fwd = IPA_NONE;
- if (src)
- fn->x1 = src;
- lsa_install_new(po, &lsa, dom, body);
- ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
+ if ((a->dest == RTD_ROUTER) && use_gw_for_fwaddr(p, a->gw, a->iface))
+ fwd = a->gw;
- if (po->ebit == 0)
+ /* NSSA-LSA with P-bit set must have non-zero forwarding address */
+ if (oa && ipa_zero(fwd))
{
- po->ebit = 1;
- WALK_LIST(oa, po->area_list)
+ fwd = find_surrogate_fwaddr(p, oa);
+
+ if (ipa_zero(fwd))
{
- schedule_rt_lsa(oa);
+ log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %I/%d",
+ p->p.name, n->n.prefix, n->n.pxlen);
+ return;
}
}
-}
-
-void
-flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int nssa)
-{
- struct proto_ospf *po = oa->po;
- struct proto *p = &po->proto;
- struct top_hash_entry *en;
- u32 dom = nssa ? oa->areaid : 0;
- u32 type = nssa ? LSA_T_NSSA : LSA_T_EXT;
- u32 lsaid = fibnode_to_lsaid(po, fn);
+ nf = (ort *) fib_get(&p->rtf, &n->n.prefix, n->n.pxlen);
+ ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1);
+ nf->external_rte = 1;
+}
- if (en = ospf_hash_find(po->gr, dom, lsaid, po->router_id, type))
- {
- OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d",
- nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
- if (check_ext_lsa(en, fn, 0, IPA_NONE, 0) < 0)
- {
- log(L_ERR "%s: LSAID collision for %I/%d",
- p->name, fn->prefix, fn->pxlen);
- return;
- }
+/*
+ * Link-LSA handling (assume OSPFv3)
+ * Type = LSA_T_LINK
+ */
- fn->x1 = 0;
- ospf_lsupd_flush_nlsa(po, en);
- }
+static inline void
+lsab_put_prefix(struct ospf_proto *p, ip_addr prefix, u32 pxlen, u32 cost)
+{
+ void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(pxlen));
+ u8 flags = (pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA;
+ put_ipv6_prefix(buf, prefix, pxlen, flags, cost);
}
-
-#ifdef OSPFv3
-
-static void *
-originate_link_lsa_body(struct ospf_iface *ifa, u16 *length)
+static void
+prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
{
- struct proto_ospf *po = ifa->oa->po;
struct ospf_lsa_link *ll;
int i = 0;
- u8 flags;
- ASSERT(po->lsab_used == 0);
- ll = lsab_allocz(po, sizeof(struct ospf_lsa_link));
+ ASSERT(p->lsab_used == 0);
+ ll = lsab_allocz(p, sizeof(struct ospf_lsa_link));
ll->options = ifa->oa->options | (ifa->priority << 24);
- ll->lladdr = ifa->addr->ip;
+ ll->lladdr = ipa_to_ip6(ifa->addr->ip);
ll = NULL; /* buffer might be reallocated later */
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
- {
- if ((a->flags & IA_SECONDARY) ||
- (a->scope < SCOPE_SITE))
- continue;
+ {
+ if ((a->flags & IA_SECONDARY) ||
+ (a->scope < SCOPE_SITE))
+ continue;
- flags = (a->pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA;
- put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(a->pxlen)),
- a->ip, a->pxlen, flags, 0);
- i++;
- }
+ lsab_put_prefix(p, a->prefix, a->pxlen, 0);
+ i++;
+ }
- ll = po->lsab;
+ ll = p->lsab;
ll->pxcount = i;
- *length = po->lsab_used + sizeof(struct ospf_lsa_header);
- return lsab_flush(po);
}
-void
-originate_link_lsa(struct ospf_iface *ifa)
+static void
+ospf_originate_link_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
{
- struct ospf_lsa_header lsa;
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
- void *body;
-
- /* Vlinks do not have link-LSAs */
- if (ifa->type == OSPF_IT_VLINK)
+ if (ospf_is_v2(p))
return;
- OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname);
+ struct ospf_new_lsa lsa = {
+ .type = LSA_T_LINK,
+ .dom = ifa->iface_id,
+ .id = ifa->iface_id,
+ .ifa = ifa
+ };
- lsa.age = 0;
- lsa.type = LSA_T_LINK;
- lsa.id = ifa->iface_id;
- lsa.rt = po->router_id;
- lsa.sn = get_seqnum(ifa->link_lsa);
- u32 dom = ifa->iface_id;
+ OSPF_TRACE(D_EVENTS, "Updating link state for %s (Id: %R)", ifa->ifname, lsa.id);
- body = originate_link_lsa_body(ifa, &lsa.length);
- lsasum_calculate(&lsa, body);
- ifa->link_lsa = lsa_install_new(po, &lsa, dom, body);
- ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
+ prepare_link_lsa_body(p, ifa);
- /* Just to be sure to not forget on our link LSA */
- if (ifa->state == OSPF_IS_DR)
- schedule_net_lsa(ifa);
+ ifa->link_lsa = ospf_originate_lsa(p, &lsa);
}
-void
-update_link_lsa(struct ospf_iface *ifa)
-{
- if (ifa->link_lsa && ((ifa->link_lsa->inst_t + MINLSINTERVAL) > now))
- return;
- /*
- * It's too early to originate new link LSA. We will
- * try to do it next tick
- */
- originate_link_lsa(ifa);
- ifa->origlink = 0;
-}
-static inline void
-lsa_put_prefix(struct proto_ospf *po, ip_addr prefix, u32 pxlen, u32 cost)
-{
- put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(pxlen)), prefix, pxlen,
- (pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA, cost);
-}
+/*
+ * Prefix-Rt-LSA handling (assume OSPFv3)
+ * Type = LSA_T_PREFIX, referred type = LSA_T_RT
+ */
-static void *
-originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
+static void
+prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
{
- struct proto_ospf *po = oa->po;
- struct ospf_config *cf = (struct ospf_config *) (po->proto.cf);
+ struct ospf_config *cf = (struct ospf_config *) (p->p.cf);
struct ospf_iface *ifa;
struct ospf_lsa_prefix *lp;
int host_addr = 0;
int net_lsa;
int i = 0;
- ASSERT(po->lsab_used == 0);
- lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix));
+ ASSERT(p->lsab_used == 0);
+ lp = lsab_allocz(p, sizeof(struct ospf_lsa_prefix));
lp->ref_type = LSA_T_RT;
lp->ref_id = 0;
- lp->ref_rt = po->router_id;
+ lp->ref_rt = p->router_id;
lp = NULL; /* buffer might be reallocated later */
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
{
if ((ifa->oa != oa) || (ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN))
continue;
@@ -1286,47 +1400,46 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
- {
- if ((a->flags & IA_SECONDARY) ||
- (a->flags & IA_PEER) ||
- (a->scope <= SCOPE_LINK))
- continue;
+ {
+ if ((a->flags & IA_SECONDARY) ||
+ (a->flags & IA_PEER) ||
+ (a->scope <= SCOPE_LINK))
+ continue;
- if (((a->pxlen < MAX_PREFIX_LENGTH) && net_lsa) ||
- configured_stubnet(oa, a))
- continue;
+ if (((a->pxlen < MAX_PREFIX_LENGTH) && net_lsa) ||
+ configured_stubnet(oa, a))
+ continue;
- if ((a->flags & IA_HOST) ||
- (ifa->state == OSPF_IS_LOOP) ||
- (ifa->type == OSPF_IT_PTMP))
- {
- lsa_put_prefix(po, a->ip, MAX_PREFIX_LENGTH, 0);
- host_addr = 1;
- }
- else
- lsa_put_prefix(po, a->prefix, a->pxlen, ifa->cost);
- i++;
+ if ((a->flags & IA_HOST) ||
+ (ifa->state == OSPF_IS_LOOP) ||
+ (ifa->type == OSPF_IT_PTMP))
+ {
+ lsab_put_prefix(p, a->ip, MAX_PREFIX_LENGTH, 0);
+ host_addr = 1;
}
+ else
+ lsab_put_prefix(p, a->prefix, a->pxlen, ifa->cost);
+ i++;
+ }
ifa->px_pos_end = i;
}
struct ospf_stubnet_config *sn;
- if (oa->ac)
- WALK_LIST(sn, oa->ac->stubnet_list)
- if (!sn->hidden)
- {
- lsa_put_prefix(po, sn->px.addr, sn->px.len, sn->cost);
- if (sn->px.len == MAX_PREFIX_LENGTH)
- host_addr = 1;
- i++;
- }
+ WALK_LIST(sn, oa->ac->stubnet_list)
+ if (!sn->hidden)
+ {
+ lsab_put_prefix(p, sn->px.addr, sn->px.len, sn->cost);
+ if (sn->px.len == MAX_PREFIX_LENGTH)
+ host_addr = 1;
+ i++;
+ }
/* If there are some configured vlinks, find some global address
(even from another area), which will be used as a vlink endpoint. */
if (!EMPTY_LIST(cf->vlink_list) && !host_addr)
{
- WALK_LIST(ifa, po->iface_list)
+ WALK_LIST(ifa, p->iface_list)
{
if ((ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN))
continue;
@@ -1338,7 +1451,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
continue;
/* Found some IP */
- lsa_put_prefix(po, a->ip, MAX_PREFIX_LENGTH, 0);
+ lsab_put_prefix(p, a->ip, MAX_PREFIX_LENGTH, 0);
i++;
goto done;
}
@@ -1346,36 +1459,33 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
}
done:
- lp = po->lsab;
+ lp = p->lsab;
lp->pxcount = i;
- *length = po->lsab_used + sizeof(struct ospf_lsa_header);
- return lsab_flush(po);
}
-void
-originate_prefix_rt_lsa(struct ospf_area *oa)
+static void
+ospf_originate_prefix_rt_lsa(struct ospf_proto *p, struct ospf_area *oa)
{
- struct proto_ospf *po = oa->po;
- struct proto *p = &po->proto;
- struct ospf_lsa_header lsa;
- void *body;
+ if (ospf_is_v2(p))
+ return;
- OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid);
+ struct ospf_new_lsa lsa = {
+ .type = LSA_T_PREFIX,
+ .dom = oa->areaid,
+ .id = 0
+ };
- lsa.age = 0;
- lsa.type = LSA_T_PREFIX;
- lsa.id = 0;
- lsa.rt = po->router_id;
- lsa.sn = get_seqnum(oa->pxr_lsa);
- u32 dom = oa->areaid;
+ prepare_prefix_rt_lsa_body(p, oa);
- body = originate_prefix_rt_lsa_body(oa, &lsa.length);
- lsasum_calculate(&lsa, body);
- oa->pxr_lsa = lsa_install_new(po, &lsa, dom, body);
- ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
+ ospf_originate_lsa(p, &lsa);
}
+/*
+ * Prefix-Net-LSA handling (assume OSPFv3)
+ * Type = LSA_T_PREFIX, referred type = LSA_T_NET
+ */
+
static inline int
prefix_space(u32 *buf)
{
@@ -1389,7 +1499,7 @@ prefix_same(u32 *b1, u32 *b2)
int pxl1 = *b1 >> 24;
int pxl2 = *b2 >> 24;
int pxs, i;
-
+
if (pxl1 != pxl2)
return 0;
@@ -1410,9 +1520,9 @@ prefix_advance(u32 *buf)
/* FIXME eliminate items with LA bit set? see 4.4.3.9 */
static void
-add_prefix(struct proto_ospf *po, u32 *px, int offset, int *pxc)
+add_prefix(struct ospf_proto *p, u32 *px, int offset, int *pxc)
{
- u32 *pxl = lsab_offset(po, offset);
+ u32 *pxl = lsab_offset(p, offset);
int i;
for (i = 0; i < *pxc; pxl = prefix_advance(pxl), i++)
if (prefix_same(px, pxl))
@@ -1422,19 +1532,18 @@ add_prefix(struct proto_ospf *po, u32 *px, int offset, int *pxc)
return;
}
- ASSERT(pxl == lsab_end(po));
+ ASSERT(pxl == lsab_end(p));
int pxspace = prefix_space(px);
- pxl = lsab_alloc(po, pxspace);
+ pxl = lsab_alloc(p, pxspace);
memcpy(pxl, px, pxspace);
*pxl &= 0xFFFF0000; /* Set metric to zero */
(*pxc)++;
}
static void
-add_link_lsa(struct proto_ospf *po, struct top_hash_entry *en, int offset, int *pxc)
+add_link_lsa(struct ospf_proto *p, struct ospf_lsa_link *ll, int offset, int *pxc)
{
- struct ospf_lsa_link *ll = en->lsa_body;
u32 *pxb = ll->rest;
int j;
@@ -1451,92 +1560,129 @@ add_link_lsa(struct proto_ospf *po, struct top_hash_entry *en, int offset, int *
if ((pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
continue;
- add_prefix(po, pxb, offset, pxc);
+ add_prefix(p, pxb, offset, pxc);
}
}
-
-
-static void *
-originate_prefix_net_lsa_body(struct ospf_iface *ifa, u16 *length)
+static void
+prepare_prefix_net_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
{
- struct proto_ospf *po = ifa->oa->po;
struct ospf_lsa_prefix *lp;
struct ospf_neighbor *n;
struct top_hash_entry *en;
int pxc, offset;
- ASSERT(po->lsab_used == 0);
- lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix));
+ ASSERT(p->lsab_used == 0);
+ lp = lsab_allocz(p, sizeof(struct ospf_lsa_prefix));
lp->ref_type = LSA_T_NET;
lp->ref_id = ifa->net_lsa->lsa.id;
- lp->ref_rt = po->router_id;
+ lp->ref_rt = p->router_id;
lp = NULL; /* buffer might be reallocated later */
pxc = 0;
- offset = po->lsab_used;
+ offset = p->lsab_used;
/* Find all Link LSAs associated with the link and merge their prefixes */
- if (ifa->link_lsa)
- add_link_lsa(po, ifa->link_lsa, offset, &pxc);
+ if (en = ifa->link_lsa)
+ add_link_lsa(p, en->next_lsa_body ?: en->lsa_body, offset, &pxc);
WALK_LIST(n, ifa->neigh_list)
if ((n->state == NEIGHBOR_FULL) &&
- (en = ospf_hash_find(po->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK)))
- add_link_lsa(po, en, offset, &pxc);
+ (en = ospf_hash_find(p->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK)))
+ add_link_lsa(p, en->lsa_body, offset, &pxc);
- lp = po->lsab;
+ lp = p->lsab;
lp->pxcount = pxc;
- *length = po->lsab_used + sizeof(struct ospf_lsa_header);
- return lsab_flush(po);
}
-void
-originate_prefix_net_lsa(struct ospf_iface *ifa)
+static void
+ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
{
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
- struct ospf_lsa_header lsa;
- void *body;
+ if (ospf_is_v2(p))
+ return;
- OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->ifname);
+ struct ospf_new_lsa lsa = {
+ .type = LSA_T_PREFIX,
+ .dom = ifa->oa->areaid,
+ .id = ifa->iface_id,
+ .ifa = ifa
+ };
- lsa.age = 0;
- lsa.type = LSA_T_PREFIX;
- lsa.id = ifa->iface_id;
- lsa.rt = po->router_id;
- lsa.sn = get_seqnum(ifa->pxn_lsa);
- u32 dom = ifa->oa->areaid;
+ prepare_prefix_net_lsa_body(p, ifa);
- body = originate_prefix_net_lsa_body(ifa, &lsa.length);
- lsasum_calculate(&lsa, body);
- ifa->pxn_lsa = lsa_install_new(po, &lsa, dom, body);
- ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
+ ifa->pxn_lsa = ospf_originate_lsa(p, &lsa);
}
+static inline int breaks_minlsinterval(struct top_hash_entry *en)
+{ return en && (en->lsa.age < LSA_MAXAGE) && ((en->inst_time + MINLSINTERVAL) > now); }
+
void
-flush_prefix_net_lsa(struct ospf_iface *ifa)
+ospf_update_topology(struct ospf_proto *p)
{
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
- struct top_hash_entry *en = ifa->pxn_lsa;
- u32 dom = ifa->oa->areaid;
+ struct ospf_area *oa;
+ struct ospf_iface *ifa;
- if (en == NULL)
- return;
+ WALK_LIST(oa, p->area_list)
+ {
+ if (oa->update_rt_lsa)
+ {
+ /*
+ * Generally, MinLSInterval is enforced in ospf_do_originate_lsa(), but
+ * origination of (prefix) router LSA is a special case. We do not want to
+ * prepare a new router LSA body and then postpone it in en->next_lsa_body
+ * for later origination, because there are side effects (updates of
+ * rt_pos_* and px_pos_* in ospf_iface structures) during that, which may
+ * confuse routing table calculation if executed after LSA body
+ * preparation but before final LSA origination (as rtcalc would use
+ * current rt_pos_* indexes but the old router LSA body).
+ *
+ * Here, we ensure that MinLSInterval is observed and we do not even try
+ * to originate these LSAs if it is not. Therefore, origination, when
+ * requested, will succeed unless there is also a seqnum wrapping, which
+ * is not a problem because in that case rtcalc is blocked by MaxAge.
+ */
+
+ if (breaks_minlsinterval(oa->rt) || breaks_minlsinterval(oa->pxr_lsa))
+ continue;
- OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s", ifa->ifname);
+ ospf_originate_rt_lsa(p, oa);
+ ospf_originate_prefix_rt_lsa(p, oa);
+ oa->update_rt_lsa = 0;
+ }
+ }
- en->lsa.sn += 1;
- en->lsa.age = LSA_MAXAGE;
- lsasum_calculate(&en->lsa, en->lsa_body);
- ospf_lsupd_flood(po, NULL, NULL, &en->lsa, dom, 0);
- flush_lsa(en, po);
- ifa->pxn_lsa = NULL;
-}
+ WALK_LIST(ifa, p->iface_list)
+ {
+ if (ifa->type == OSPF_IT_VLINK)
+ continue;
+ if (ifa->update_link_lsa)
+ {
+ if ((ifa->state > OSPF_IS_LOOP) && !ifa->link_lsa_suppression)
+ ospf_originate_link_lsa(p, ifa);
+ else
+ ospf_flush2_lsa(p, &ifa->link_lsa);
-#endif
+ ifa->update_link_lsa = 0;
+ }
+
+ if (ifa->update_net_lsa)
+ {
+ if ((ifa->state == OSPF_IS_DR) && (ifa->fadj > 0))
+ {
+ ospf_originate_net_lsa(p, ifa);
+ ospf_originate_prefix_net_lsa(p, ifa);
+ }
+ else
+ {
+ ospf_flush2_lsa(p, &ifa->net_lsa);
+ ospf_flush2_lsa(p, &ifa->pxn_lsa);
+ }
+
+ ifa->update_net_lsa = 0;
+ }
+ }
+}
static void
@@ -1574,7 +1720,7 @@ ospf_top_hash_u32(u32 a)
return a;
}
-static inline unsigned
+static uint
ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
{
/* In OSPFv2, we don't know Router ID when looking for network LSAs.
@@ -1582,14 +1728,8 @@ ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
In both cases, there is (usually) just one (or small number)
appropriate LSA, so we just clear unknown part of key. */
- return (
-#ifdef OSPFv2
- ((type == LSA_T_NET) ? 0 : ospf_top_hash_u32(rtrid)) +
- ospf_top_hash_u32(lsaid) +
-#else /* OSPFv3 */
- ospf_top_hash_u32(rtrid) +
- ((type == LSA_T_RT) ? 0 : ospf_top_hash_u32(lsaid)) +
-#endif
+ return (((f->ospf2 && (type == LSA_T_NET)) ? 0 : ospf_top_hash_u32(rtrid)) +
+ ((!f->ospf2 && (type == LSA_T_RT)) ? 0 : ospf_top_hash_u32(lsaid)) +
type + domain) & f->hash_mask;
/*
@@ -1600,13 +1740,15 @@ ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
/**
* ospf_top_new - allocated new topology database
- * @p: current instance of ospf
+ * @p: OSPF protocol instance
+ * @pool: pool for allocation
*
- * this dynamically hashed structure is often used for keeping lsas. mainly
- * its used in @ospf_area structure.
+ * This dynamically hashed structure is used for keeping LSAs. Mainly it is used
+ * for the LSA database of the OSPF protocol, but also for LSA retransmission
+ * and request lists of OSPF neighbors.
*/
struct top_graph *
-ospf_top_new(pool *pool)
+ospf_top_new(struct ospf_proto *p, pool *pool)
{
struct top_graph *f;
@@ -1617,6 +1759,7 @@ ospf_top_new(pool *pool)
ospf_top_ht_alloc(f);
f->hash_entries = 0;
f->hash_entries_min = 0;
+ f->ospf2 = ospf_is_v2(p);
return f;
}
@@ -1631,8 +1774,8 @@ ospf_top_free(struct top_graph *f)
static void
ospf_top_rehash(struct top_graph *f, int step)
{
- unsigned int oldn, oldh;
struct top_hash_entry **n, **oldt, **newt, *e, *x;
+ uint oldn, oldh;
oldn = f->hash_size;
oldt = f->hash_table;
@@ -1648,7 +1791,7 @@ ospf_top_rehash(struct top_graph *f, int step)
while (e)
{
x = e->next;
- n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type);
+ n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa_type);
e->next = *n;
*n = e;
e = x;
@@ -1657,124 +1800,94 @@ ospf_top_rehash(struct top_graph *f, int step)
ospf_top_ht_free(oldt);
}
-#ifdef OSPFv2
-
-u32
-ospf_lsa_domain(u32 type, struct ospf_iface *ifa)
-{
- return (type == LSA_T_EXT) ? 0 : ifa->oa->areaid;
-}
-
-#else /* OSPFv3 */
-
-u32
-ospf_lsa_domain(u32 type, struct ospf_iface *ifa)
-{
- switch (type & LSA_SCOPE_MASK)
- {
- case LSA_SCOPE_LINK:
- return ifa->iface_id;
-
- case LSA_SCOPE_AREA:
- return ifa->oa->areaid;
-
- case LSA_SCOPE_AS:
- default:
- return 0;
- }
-}
-
-#endif
-
-struct top_hash_entry *
-ospf_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h)
-{
- return ospf_hash_find(f, domain, h->id, h->rt, h->type);
-}
-
-struct top_hash_entry *
-ospf_hash_get_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h)
-{
- return ospf_hash_get(f, domain, h->id, h->rt, h->type);
-}
-
-struct top_hash_entry *
-ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
+static struct top_hash_entry *
+ospf_hash_find_(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
{
struct top_hash_entry *e;
e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)];
- while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->domain != domain))
+ while (e && (e->lsa.id != lsa || e->lsa.rt != rtr ||
+ e->lsa_type != type || e->domain != domain))
e = e->next;
return e;
}
-
-#ifdef OSPFv2
-
-/* In OSPFv2, sometimes we don't know Router ID when looking for network LSAs.
- There should be just one, so we find any match. */
struct top_hash_entry *
-ospf_hash_find_net(struct top_graph *f, u32 domain, u32 lsa)
+ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
{
- struct top_hash_entry *e;
- e = f->hash_table[ospf_top_hash(f, domain, lsa, 0, LSA_T_NET)];
-
- while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->domain != domain))
- e = e->next;
+ struct top_hash_entry *e = ospf_hash_find_(f, domain, lsa, rtr, type);
- return e;
+ /* Hide hash entry with empty lsa_body */
+ return (e && e->lsa_body) ? e : NULL;
}
-#endif
-
-
-#ifdef OSPFv3
-
-/* In OSPFv3, usually we don't know LSA ID when looking for router
- LSAs. We return matching LSA with smallest LSA ID. */
+/* In OSPFv2, lsa.id is the same as lsa.rt for router LSA. In OSPFv3, we don't know
+ lsa.id when looking for router LSAs. We return matching LSA with smallest lsa.id. */
struct top_hash_entry *
ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
{
struct top_hash_entry *rv = NULL;
struct top_hash_entry *e;
- e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)];
-
+ /* We can put rtr for lsa.id to hash fn, it is ignored in OSPFv3 */
+ e = f->hash_table[ospf_top_hash(f, domain, rtr, rtr, LSA_T_RT)];
+
while (e)
+ {
+ if (e->lsa.rt == rtr && e->lsa_type == LSA_T_RT && e->domain == domain && e->lsa_body)
{
- if (e->lsa.rt == rtr && e->lsa.type == LSA_T_RT && e->domain == domain)
- if (!rv || e->lsa.id < rv->lsa.id)
- rv = e;
- e = e->next;
+ if (f->ospf2 && (e->lsa.id == rtr))
+ return e;
+ if (!f->ospf2 && (!rv || e->lsa.id < rv->lsa.id))
+ rv = e;
}
+ e = e->next;
+ }
return rv;
}
+/*
+ * ospf_hash_find_rt3_first() and ospf_hash_find_rt3_next() are used exclusively
+ * for lsa_walk_rt_init(), lsa_walk_rt(), therefore they skip MaxAge entries.
+ */
static inline struct top_hash_entry *
-find_matching_rt(struct top_hash_entry *e, u32 domain, u32 rtr)
+find_matching_rt3(struct top_hash_entry *e, u32 domain, u32 rtr)
{
- while (e && (e->lsa.rt != rtr || e->lsa.type != LSA_T_RT || e->domain != domain))
+ while (e && (e->lsa.rt != rtr || e->lsa_type != LSA_T_RT ||
+ e->domain != domain || e->lsa.age == LSA_MAXAGE))
e = e->next;
return e;
}
struct top_hash_entry *
-ospf_hash_find_rt_first(struct top_graph *f, u32 domain, u32 rtr)
+ospf_hash_find_rt3_first(struct top_graph *f, u32 domain, u32 rtr)
{
struct top_hash_entry *e;
e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)];
- return find_matching_rt(e, domain, rtr);
+ return find_matching_rt3(e, domain, rtr);
}
struct top_hash_entry *
-ospf_hash_find_rt_next(struct top_hash_entry *e)
+ospf_hash_find_rt3_next(struct top_hash_entry *e)
{
- return find_matching_rt(e->next, e->domain, e->lsa.rt);
+ return find_matching_rt3(e->next, e->domain, e->lsa.rt);
}
-#endif
+/* In OSPFv2, we don't know Router ID when looking for network LSAs.
+ There should be just one, so we find any match. */
+struct top_hash_entry *
+ospf_hash_find_net2(struct top_graph *f, u32 domain, u32 id)
+{
+ struct top_hash_entry *e;
+ e = f->hash_table[ospf_top_hash(f, domain, id, 0, LSA_T_NET)];
+
+ while (e && (e->lsa.id != id || e->lsa_type != LSA_T_NET ||
+ e->domain != domain || e->lsa_body == NULL))
+ e = e->next;
+
+ return e;
+}
struct top_hash_entry *
@@ -1786,21 +1899,23 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type);
e = *ee;
- while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type || e->domain != domain))
+ while (e && (e->lsa.id != lsa || e->lsa.rt != rtr ||
+ e->lsa_type != type || e->domain != domain))
e = e->next;
if (e)
return e;
e = sl_alloc(f->hash_slab);
+ bzero(e, sizeof(struct top_hash_entry));
+
e->color = OUTSPF;
e->dist = LSINFINITY;
- e->nhs = NULL;
- e->lb = IPA_NONE;
+ e->lsa.type_raw = type;
e->lsa.id = lsa;
e->lsa.rt = rtr;
- e->lsa.type = type;
- e->lsa_body = NULL;
+ e->lsa.sn = LSA_ZEROSEQNO;
+ e->lsa_type = type;
e->domain = domain;
e->next = *ee;
*ee = e;
@@ -1812,8 +1927,8 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
void
ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e)
{
- struct top_hash_entry **ee = f->hash_table +
- ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type);
+ struct top_hash_entry **ee = f->hash_table +
+ ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa_type);
while (*ee)
{
@@ -1853,7 +1968,7 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p)
rr = (struct ospf_lsa_rt_link *) (rt + 1);
for (i = 0; i < lsa_rt_items(&he->lsa); i++)
- OSPF_TRACE(D_EVENTS, " - %1x %-1R %-1R %5u",
+ OSPF_TRACE(D_EVENTS, " - %1x %-1R %-1R %5u",
rr[i].type, rr[i].id, rr[i].data, rr[i].metric);
break;
@@ -1862,7 +1977,7 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p)
rts = (u32 *) (ln + 1);
for (i = 0; i < lsa_net_items(&he->lsa); i++)
- OSPF_TRACE(D_EVENTS, " - %-1R", rts[i]);
+ OSPF_TRACE(D_EVENTS, " - %-1R", rts[i]);
break;
default:
@@ -1873,7 +1988,7 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p)
void
ospf_top_dump(struct top_graph *f, struct proto *p)
{
- unsigned int i;
+ uint i;
OSPF_TRACE(D_EVENTS, "Hash entries: %d", f->hash_entries);
for (i = 0; i < f->hash_size; i++)
@@ -1884,30 +1999,3 @@ ospf_top_dump(struct top_graph *f, struct proto *p)
}
}
*/
-
-/* This is very inefficient, please don't call it often */
-
-/* I should also test for every LSA if it's in some link state
- * retransmission list for every neighbor. I will not test it.
- * It could happen that I'll receive some strange ls ack's.
- */
-
-int
-can_flush_lsa(struct proto_ospf *po)
-{
- struct ospf_iface *ifa;
- struct ospf_neighbor *n;
-
- WALK_LIST(ifa, po->iface_list)
- {
- WALK_LIST(n, ifa->neigh_list)
- {
- if ((n->state == NEIGHBOR_EXCHANGE) || (n->state == NEIGHBOR_LOADING))
- return 0;
-
- break;
- }
- }
-
- return 1;
-}
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index cb876487..e2d6c773 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.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.
*/
@@ -16,79 +18,204 @@ 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 (LSA_T_*) */
+ 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 mode; /* 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() */
};
+
+/* Prevents ospf_hash_find() to ignore the entry, for p->lsrqh and p->lsrth */
+#define LSA_BODY_DUMMY ((void *) 1)
+
+/*
+ * LSA entry life cycle
+ *
+ * LSA entries are created by ospf_originate_lsa() (for locally originated LSAs)
+ * or ospf_install_lsa() (for LSAs received from neighbors). A regular (like
+ * newly originated) LSA entry has defined lsa_body nad lsa.age < %LSA_MAXAGE.
+ * When the LSA is requested to be flushed by ospf_flush_lsa(), the lsa.age is
+ * set to %LSA_MAXAGE and flooded. Flush process is finished asynchronously,
+ * when (at least) flooding is acknowledged by neighbors. This is detected in
+ * ospf_update_lsadb(), then ospf_clear_lsa() is called to free the LSA body but
+ * the LSA entry is kept. Such LSA does not formally exist, we keep an empty
+ * entry (until regular timeout) to know inst_time and lsa.sn in the case of
+ * later reorigination. After the timeout, LSA is removed by ospf_remove_lsa().
+ *
+ * When LSA origination is requested (by ospf_originate_lsa()). but it is not
+ * possible to do that immediately (because of MinLSInterval or because the
+ * sequence number is wrapping), The new LSA is scheduled for later origination
+ * in next_lsa_* fields of the LSA entry. The later origination is handled by
+ * ospf_originate_next_lsa() called from ospf_update_lsadb(). We can see that
+ * both real origination and final flush is asynchronous to ospf_originate_lsa()
+ * and ospf_flush_lsa().
+ *
+ * LSA entry therefore could be in three basic states:
+ * R - regular (lsa.age < %LSA_MAXAGE, lsa_body != NULL)
+ * F - flushing (lsa.age == %LSA_MAXAGE, lsa_body != NULL)
+ * E - empty (lsa.age == %LSA_MAXAGE, lsa_body == NULL)
+ *
+ * And these states are doubled based on whether the next LSA is scheduled
+ * (next_lsa_body != NULL, -n suffix) or not (next_lsa_body == NULL). We also
+ * use X for a state of non-existentce. We have this basic state graph
+ * (transitions from any state to R are omitted for clarity):
+ *
+ * X --> R ---> F ---> E --> X
+ * | \ / | |
+ * | \/ | |
+ * | /\ | |
+ * | / \ | |
+ * Rn --> Fn --> En
+ *
+ * The transitions are:
+ *
+ * any state -> R - new LSA origination requested and executed
+ * R -> Rn, F -> Fn, E -> En - new LSA origination requested and postponed
+ * R -> Fn - new LSA origination requested, seqnum wrapping
+ * Rn,Fn,En -> R - postponed LSA finally originated
+ * R -> R - LSA refresh done
+ * R -> Fn - LSA refresh with seqnum wrapping
+ * R -> F, Rn -> Fn - LSA age timeout
+ * R,Rn,Fn -> F, En -> E - LSA flush requested
+ * F -> E, Fn -> En - LSA flush done (acknowledged)
+ * E -> X - LSA real age timeout (or immediate for received LSA)
+ *
+ * The 'origination requested' and 'flush requested' transitions are triggered
+ * and done by ospf_originate_lsa() and ospf_flush_lsa(), the rest is handled
+ * asynchronously by ospf_update_lsadb().
+ *
+ * The situation is significantly simpler for non-local (received) LSAs - there
+ * is no postponed origination and after flushing is done, LSAs are immediately
+ * removed, so it is just X -> R -> F -> X, or X -> F -> X (when MaxAge LSA is
+ * received).
+ *
+ * There are also some special cases related to handling of received unknown
+ * self-originated LSAs in ospf_advance_lsa():
+ * X -> F - LSA is received and immediately flushed
+ * R,Rn -> Fn - LSA with MaxSeqNo received and flushed, current LSA scheduled
+ */
+
+
+#define LSA_M_BASIC 0
+#define LSA_M_EXPORT 1
+#define LSA_M_RTCALC 2
+#define LSA_M_STALE 3
+
+/*
+ * LSA entry modes:
+ *
+ * LSA_M_BASIC - The LSA is explicitly originated using ospf_originate_lsa() and
+ * explicitly flushed using ospf_flush_lsa(). When the LSA is changed, the
+ * routing table calculation is scheduled. This is also the mode used for LSAs
+ * received from neighbors. Example: Router-LSAs, Network-LSAs.
+ *
+ * LSA_M_EXPORT - like LSA_M_BASIC, but the routing table calculation does not
+ * depend on the LSA. Therefore, the calculation is not scheduled when the LSA
+ * is changed. Example: AS-external-LSAs for exported routes.
+ *
+ * LSA_M_RTCALC - The LSA has to be requested using ospf_originate_lsa() during
+ * each routing table calculation, otherwise it is flushed automatically at the
+ * end of the calculation. The LSA is a result of the calculation and not a
+ * source for it. Therefore, the calculation is not scheduled when the LSA is
+ * changed. Example: Summary-LSAs.
+ *
+ * LSA_M_STALE - Temporary state for LSA_M_RTCALC that is not requested during
+ * the current routing table calculation.
+ *
+ *
+ * Note that we do not schedule the routing table calculation when the age of
+ * LSA_M_BASIC LSA is changed to MaxAge because of the sequence number wrapping,
+ * As it will be switched back to a regular one ASAP.
+ */
+
+
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;
+ u8 mode;
+ 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_graph *ospf_top_new(struct ospf_proto *p, pool *pool);
+void ospf_top_free(struct top_graph *f);
+
+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 mode, 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);
+struct top_hash_entry * ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr);
+struct top_hash_entry * ospf_hash_find_rt3_first(struct top_graph *f, u32 domain, u32 rtr);
+struct top_hash_entry * ospf_hash_find_rt3_next(struct top_hash_entry *e);
+
+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_rt(struct top_graph *f, u32 domain, u32 rtr)
+ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif)
{
- return ospf_hash_find(f, domain, rtr, rtr, LSA_T_RT);
+ return f->ospf2 ?
+ ospf_hash_find_net2(f, domain, id) :
+ ospf_hash_find(f, domain, nif, id, LSA_T_NET);
}
-#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
-
#endif /* _BIRD_OSPF_TOPOLOGY_H_ */