summaryrefslogtreecommitdiff
path: root/proto/ospf
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf')
-rw-r--r--proto/ospf/Makefile9
-rw-r--r--proto/ospf/config.Y139
-rw-r--r--proto/ospf/dbdes.c6
-rw-r--r--proto/ospf/hello.c29
-rw-r--r--proto/ospf/iface.c75
-rw-r--r--proto/ospf/lsalib.c32
-rw-r--r--proto/ospf/lsalib.h9
-rw-r--r--proto/ospf/lsupd.c6
-rw-r--r--proto/ospf/neighbor.c40
-rw-r--r--proto/ospf/ospf.c174
-rw-r--r--proto/ospf/ospf.h207
-rw-r--r--proto/ospf/packet.c23
-rw-r--r--proto/ospf/rt.c512
-rw-r--r--proto/ospf/rt.h6
-rw-r--r--proto/ospf/topology.c163
-rw-r--r--proto/ospf/topology.h8
16 files changed, 811 insertions, 627 deletions
diff --git a/proto/ospf/Makefile b/proto/ospf/Makefile
index f90222cf..39e74f71 100644
--- a/proto/ospf/Makefile
+++ b/proto/ospf/Makefile
@@ -1,5 +1,6 @@
-source=ospf.c topology.c packet.c hello.c neighbor.c iface.c dbdes.c lsreq.c lsupd.c lsack.c lsalib.c rt.c
-root-rel=../../
-dir-name=proto/ospf
+src := dbdes.c hello.c iface.c lsack.c lsalib.c lsreq.c lsupd.c neighbor.c ospf.c packet.c rt.c topology.c
+obj := $(src-o-files)
+$(all-daemon)
+$(cf-local)
-include ../../Rules
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 7b35b191..98ddf5d0 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -78,14 +78,66 @@ static void
ospf_proto_finish(void)
{
struct ospf_config *cf = OSPF_CFG;
+ struct ospf_area_config *ac;
+ struct ospf_iface_patt *ic;
+
+ /* Define default channel */
+ if (EMPTY_LIST(this_proto->channels))
+ {
+ this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
+ channel_config_new(NULL, this_proto->net_type, this_proto);
+ }
+
+ /* Propagate global instance ID to interfaces */
+ if (cf->instance_id_set)
+ {
+ WALK_LIST(ac, cf->area_list)
+ WALK_LIST(ic, ac->patt_list)
+ if (!ic->instance_id_set)
+ { ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
+
+ WALK_LIST(ic, cf->vlink_list)
+ if (!ic->instance_id_set)
+ { ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
+ }
+
+ if (ospf_cfg_is_v3())
+ {
+ uint ipv4 = (this_proto->net_type == NET_IP4);
+ uint base = (ipv4 ? 64 : 0) + (cf->af_mc ? 32 : 0);
+
+ /* RFC 5838 - OSPFv3-AF */
+ if (cf->af_ext)
+ {
+ /* RFC 5838 2.1 - instance IDs based on AFs */
+ WALK_LIST(ac, cf->area_list)
+ WALK_LIST(ic, ac->patt_list)
+ {
+ if (!ic->instance_id_set)
+ ic->instance_id = base;
+ else if (ic->instance_id >= 128)
+ log(L_WARN "Instance ID %d from unassigned/private range", ic->instance_id);
+ else if ((ic->instance_id < base) || (ic->instance_id >= (base + 32)))
+ cf_error("Instance ID %d invalid for given channel type", ic->instance_id);
+ }
+
+ /* RFC 5838 2.8 - vlinks limited to IPv6 unicast */
+ if ((ipv4 || cf->af_mc) && !EMPTY_LIST(cf->vlink_list))
+ cf_error("Vlinks not supported in AFs other than IPv6 unicast");
+ }
+ else
+ {
+ if (ipv4 || cf->af_mc)
+ cf_error("Different channel type");
+ }
+ }
if (EMPTY_LIST(cf->area_list))
- cf_error( "No configured areas in OSPF");
+ cf_error("No configured areas in OSPF");
int areano = 0;
int backbone = 0;
int nssa = 0;
- struct ospf_area_config *ac;
WALK_LIST(ac, cf->area_list)
{
areano++;
@@ -98,7 +150,7 @@ ospf_proto_finish(void)
cf->abr = areano > 1;
/* Route export or NSSA translation (RFC 3101 3.1) */
- cf->asbr = (this_proto->out_filter != FILTER_REJECT) || (nssa && cf->abr);
+ cf->asbr = (proto_cf_main_channel(this_proto)->out_filter != FILTER_REJECT) || (nssa && cf->abr);
if (cf->abr && !backbone)
{
@@ -122,7 +174,7 @@ static inline void
ospf_check_defcost(int cost)
{
if ((cost <= 0) || (cost >= LSINFINITY))
- cf_error("Default cost must be in range 1-%d", LSINFINITY-1);
+ cf_error("Default cost must be in range 1-%u", LSINFINITY-1);
}
static inline void
@@ -135,8 +187,8 @@ ospf_check_auth(void)
CF_DECLS
-CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
-CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, COST2, RETRANSMIT)
+CF_KEYWORDS(OSPF, V2, V3, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
+CF_KEYWORDS(AREA, NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, COST2, RETRANSMIT)
CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST, DEFAULT)
CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP)
CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC, TTL, SECURITY)
@@ -144,39 +196,67 @@ 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, LSA, SUPPRESSION)
+CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838)
-%type <t> opttext
%type <ld> lsadb_args
-%type <i> nbma_eligible
+%type <i> ospf_variant ospf_af_mc nbma_eligible
+%type <cc> ospf_channel_start ospf_channel
CF_GRAMMAR
CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } )
-ospf_proto_start: proto_start OSPF {
- this_proto = proto_config_new(&proto_ospf, $1);
- init_list(&OSPF_CFG->area_list);
- init_list(&OSPF_CFG->vlink_list);
- OSPF_CFG->tick = OSPF_DEFAULT_TICK;
- OSPF_CFG->ospf2 = OSPF_IS_V2;
- }
+ospf_variant:
+ OSPF { $$ = 1; }
+ | OSPF V2 { $$ = 1; }
+ | OSPF V3 { $$ = 0; }
;
+ospf_proto_start: proto_start ospf_variant
+{
+ this_proto = proto_config_new(&proto_ospf, $1);
+ this_proto->net_type = $2 ? NET_IP4 : 0;
+
+ init_list(&OSPF_CFG->area_list);
+ init_list(&OSPF_CFG->vlink_list);
+ OSPF_CFG->tick = OSPF_DEFAULT_TICK;
+ OSPF_CFG->ospf2 = $2;
+ OSPF_CFG->af_ext = !$2;
+};
+
ospf_proto:
ospf_proto_start proto_name '{'
| ospf_proto ospf_proto_item ';'
;
+ospf_af_mc:
+ { $$ = 0; }
+ | MULTICAST { $$ = 1; }
+ ;
+
+/* We redefine proto_channel to add multicast flag */
+ospf_channel_start: net_type ospf_af_mc
+{
+ $$ = this_channel = channel_config_new(NULL, $1, this_proto);
+
+ /* Save the multicast flag */
+ if (this_channel == proto_cf_main_channel(this_proto))
+ OSPF_CFG->af_mc = $2;
+};
+
+ospf_channel: ospf_channel_start channel_opt_list channel_end;
+
ospf_proto_item:
proto_item
+ | ospf_channel { this_proto->net_type = $1->net_type; }
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
+ | RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3()) cf_error("RFC5838 option requires OSPFv3"); }
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
- | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
+ | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
| 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"); }
+ | 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; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
| ospf_area
;
@@ -226,10 +306,10 @@ ospf_stubnet:
;
ospf_stubnet_start:
- prefix {
+ net_ip {
this_stubnet = cfg_allocz(sizeof(struct ospf_stubnet_config));
add_tail(&this_area->stubnet_list, NODE this_stubnet);
- this_stubnet->px = $1;
+ this_stubnet->prefix = $1;
this_stubnet->cost = COST_D;
}
;
@@ -281,7 +361,6 @@ ospf_vlink_start: VIRTUAL LINK idval
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->type = OSPF_IT_VLINK;
- OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list);
reset_passwords();
}
@@ -306,7 +385,7 @@ ospf_iface_item:
| 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"); }
+ | PRIORITY expr { OSPF_PATT->priority = $2 ; if ($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; }
@@ -325,7 +404,6 @@ ospf_iface_item:
| TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
| 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 { ospf_check_auth(); }
;
@@ -336,12 +414,11 @@ pref_list:
pref_item: pref_base pref_opt ';' ;
-pref_base: prefix
+pref_base: net_ip
{
this_pref = cfg_allocz(sizeof(struct area_net_config));
add_tail(this_nets, NODE this_pref);
- this_pref->px.addr = $1.addr;
- this_pref->px.len = $1.len;
+ this_pref->prefix = $1;
}
;
@@ -383,7 +460,6 @@ ospf_iface_start:
OSPF_PATT->priority = PRIORITY_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->type = OSPF_IT_UNDEF;
- OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->ptp_netmask = 2; /* not specified */
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
@@ -394,7 +470,7 @@ ospf_iface_start:
ospf_instance_id:
/* empty */
- | INSTANCE expr { OSPF_PATT->instance_id = $2; if (($2<0) || ($2>255)) cf_error("Instance ID must be in range 0-255"); }
+ | INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
;
ospf_iface_patt_list:
@@ -415,11 +491,6 @@ ospf_iface:
ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
;
-opttext:
- TEXT
- | /* empty */ { $$ = NULL; }
- ;
-
CF_ADDTO(dynamic_attr, OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_METRIC1); })
CF_ADDTO(dynamic_attr, OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_METRIC2); })
CF_ADDTO(dynamic_attr, OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_TAG); })
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c
index d6904343..f211935f 100644
--- a/proto/ospf/dbdes.c
+++ b/proto/ospf/dbdes.c
@@ -39,7 +39,7 @@ struct ospf_dbdes3_packet
static inline uint
-ospf_dbdes_hdrlen(struct ospf_proto *p UNUSED4 UNUSED6)
+ospf_dbdes_hdrlen(struct ospf_proto *p)
{
return ospf_is_v2(p) ?
sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
@@ -356,7 +356,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
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) &&
+ if (((rcv_imms & DBDES_IMMS) == DBDES_IMMS) &&
(n->rid > p->router_id) &&
(plen == ospf_dbdes_hdrlen(p)))
{
@@ -428,7 +428,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
}
ospf_send_dbdes(p, n);
- tm_start(n->dbdes_timer, n->ifa->rxmtint);
+ tm_start(n->dbdes_timer, n->ifa->rxmtint S);
}
else
{
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index e00487dc..e706ea0f 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -32,10 +32,7 @@ struct ospf_hello3_packet
struct ospf_packet hdr;
u32 iface_id;
- u8 priority;
- u8 options3;
- u8 options2;
- u8 options;
+ u32 options;
u16 helloint;
u16 deadint;
u32 dr;
@@ -74,7 +71,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
ps->netmask = 0;
else
- ps->netmask = htonl(u32_mkmask(ifa->addr->pxlen));
+ ps->netmask = htonl(u32_mkmask(ifa->addr->prefix.pxlen));
ps->helloint = ntohs(ifa->helloint);
ps->options = ifa->oa->options;
@@ -91,10 +88,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
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->options = ntohl(ifa->oa->options | (ifa->priority << 24));
ps->helloint = ntohs(ifa->helloint);
ps->deadint = htons(ifa->deadint);
ps->dr = htonl(ifa->drid);
@@ -190,7 +184,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
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;
+ uint rcv_options, rcv_priority;
+ uint loc_options = ifa->oa->options;
u32 *neighbors;
u32 neigh_count;
uint plen, i, err_val = 0;
@@ -198,7 +193,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
/* RFC 2328 10.5 */
/*
- * We may not yet havethe associate neighbor, so we use Router ID from the
+ * We may not yet have the 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);
@@ -227,7 +222,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
if ((ifa->type != OSPF_IT_VLINK) &&
(ifa->type != OSPF_IT_PTP) &&
- ((uint) pxlen != ifa->addr->pxlen))
+ ((uint) pxlen != ifa->addr->prefix.pxlen))
DROP("prefix length mismatch", pxlen);
neighbors = ps->neighbors;
@@ -245,8 +240,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
rcv_deadint = ntohs(ps->deadint);
rcv_dr = ntohl(ps->dr);
rcv_bdr = ntohl(ps->bdr);
- rcv_options = ps->options;
- rcv_priority = ps->priority;
+ rcv_options = ntohl(ps->options) & 0x00FFFFFF;
+ rcv_priority = ntohl(ps->options) >> 24;
neighbors = ps->neighbors;
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
@@ -259,9 +254,13 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
DROP("dead interval mismatch", rcv_deadint);
/* Check whether bits E, N match */
- if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N))
+ if ((rcv_options ^ loc_options) & (OPT_E | OPT_N))
DROP("area type mismatch", rcv_options);
+ /* RFC 5838 2.4 - AF-bit check unless on IPv6 unicast */
+ if ((loc_options & OPT_AF) && !(loc_options & OPT_V6) && !(rcv_options & OPT_AF))
+ DROP("AF-bit mismatch", rcv_options);
+
/* Check consistency of existing neighbor entry */
if (n)
{
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 280fa4c1..29d21a07 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -55,7 +55,9 @@ ifa_tx_length(struct ospf_iface *ifa)
static inline uint
ifa_tx_hdrlen(struct ospf_iface *ifa)
{
- uint hlen = SIZE_OF_IP_HEADER;
+ struct ospf_proto *p = ifa->oa->po;
+
+ uint hlen = ospf_is_v2(p) ? IP4_HEADER_LENGTH : IP6_HEADER_LENGTH;
/* Relevant just for OSPFv2 */
if (ifa->autype == OSPF_AUTH_CRYPT)
@@ -115,6 +117,7 @@ ospf_sk_open(struct ospf_iface *ifa)
sock *sk = sk_new(ifa->pool);
sk->type = SK_IP;
+ sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
sk->dport = OSPF_PROTO;
sk->saddr = ifa->addr->ip;
sk->iface = ifa->iface;
@@ -199,6 +202,7 @@ ospf_open_vlink_sk(struct ospf_proto *p)
{
sock *sk = sk_new(p->p.pool);
sk->type = SK_IP;
+ sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
sk->dport = OSPF_PROTO;
/* FIXME: configurable tos/priority ? */
@@ -244,8 +248,8 @@ ospf_iface_down(struct ospf_iface *ifa)
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);
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (%N) from area %R",
+ ifa->ifname, &ifa->addr->prefix, ifa->oa->areaid);
/* First of all kill all the related vlinks */
WALK_LIST(iff, p->iface_list)
@@ -392,15 +396,15 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
{
ospf_iface_chstate(ifa, OSPF_IS_WAITING);
if (ifa->wait_timer)
- tm_start(ifa->wait_timer, ifa->waitint);
+ tm_start(ifa->wait_timer, ifa->waitint S);
}
}
if (ifa->hello_timer)
- tm_start(ifa->hello_timer, ifa->helloint);
+ tm_start(ifa->hello_timer, ifa->helloint S);
if (ifa->poll_timer)
- tm_start(ifa->poll_timer, ifa->pollint);
+ tm_start(ifa->poll_timer, ifa->pollint S);
ospf_send_hello(ifa, OHS_HELLO, NULL);
}
@@ -490,13 +494,13 @@ ospf_iface_add(struct object_lock *lock)
if (! ifa->stub)
{
- ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
+ ifa->hello_timer = tm_new_init(ifa->pool, hello_timer_hook, ifa, ifa->helloint S, 0);
if (ifa->type == OSPF_IT_NBMA)
- ifa->poll_timer = tm_new_set(ifa->pool, poll_timer_hook, ifa, 0, ifa->pollint);
+ ifa->poll_timer = tm_new_init(ifa->pool, poll_timer_hook, ifa, ifa->pollint S, 0);
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->wait_timer = tm_new_init(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 *));
@@ -530,15 +534,6 @@ ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
if (addr->iface->flags & IF_LOOPBACK)
return 1;
- /*
- * For compatibility reasons on BSD systems, we force OSPF
- * interfaces with non-primary IP prefixes to be stub.
- */
-#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
- if (!ip->bsd_secondary && !(addr->flags & IA_PRIMARY))
- return 1;
-#endif
-
return ip->stub;
}
@@ -557,8 +552,8 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
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);
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (%N) to area %R",
+ iface->name, &addr->prefix, oa->areaid);
pool = rp_new(p->p.pool, "OSPF Interface");
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
@@ -596,6 +591,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
if (ip->ptp_netmask < 2)
ifa->ptp_netmask = ip->ptp_netmask;
+ ifa->drip = ifa->bdrip = ospf_is_v2(p) ? IPA_NONE4 : IPA_NONE6;
ifa->type = ospf_iface_classify(ip->type, addr);
@@ -635,7 +631,7 @@ 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 */
- if (ospf_is_v2(p) && !ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
+ if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &addr->prefix))
continue;
if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
@@ -648,7 +644,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
add_tail(&oa->po->iface_list, NODE ifa);
struct object_lock *lock = olock_new(pool);
- lock->addr = ospf_is_v2(p) ? ifa->addr->prefix : IPA_NONE;
+ lock->addr = ospf_is_v2(p) ? ipa_from_ip4(net4_prefix(&ifa->addr->prefix)) : IPA_NONE;
lock->type = OBJLOCK_IP;
lock->port = OSPF_PROTO;
lock->inst = ifa->instance_id;
@@ -707,7 +703,7 @@ ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip)
add_tail(&p->iface_list, NODE ifa);
- ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
+ ifa->hello_timer = tm_new_init(ifa->pool, hello_timer_hook, ifa, ifa->helloint S, 0);
ifa->flood_queue_size = ifa_flood_queue_size(ifa);
ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *));
@@ -719,10 +715,10 @@ ospf_iface_change_timer(timer *tm, uint val)
if (!tm)
return;
- tm->recurrent = val;
+ tm->recurrent = val S;
- if (tm->expires)
- tm_start(tm, val);
+ if (tm_active(tm))
+ tm_start(tm, val S);
}
static inline void
@@ -805,8 +801,8 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ifname, ifa->waitint, new->waitint);
ifa->waitint = new->waitint;
- if (ifa->wait_timer && ifa->wait_timer->expires)
- tm_start(ifa->wait_timer, ifa->waitint);
+ if (ifa->wait_timer && tm_active(ifa->wait_timer))
+ tm_start(ifa->wait_timer, ifa->waitint S);
}
/* DEAD TIMER */
@@ -898,7 +894,7 @@ 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() */
- if (ospf_is_v2(p) && !ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
+ if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &ifa->addr->prefix))
continue;
if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
@@ -1085,6 +1081,9 @@ ospf_ifa_notify2(struct proto *P, uint flags, struct ifa *a)
{
struct ospf_proto *p = (struct ospf_proto *) P;
+ if (a->prefix.type != NET_IP4)
+ return;
+
if (a->flags & IA_SECONDARY)
return;
@@ -1124,6 +1123,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
other addresses are used for link-LSA. */
if (a->scope == SCOPE_LINK)
{
+ if (a->prefix.type != NET_IP6)
+ return;
+
if (flags & IF_CHANGE_UP)
{
struct ospf_mip_walk s = { .iface = a->iface };
@@ -1141,6 +1143,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
}
else
{
+ if (a->prefix.type != ospf_get_af(p))
+ return;
+
struct ospf_iface *ifa;
WALK_LIST(ifa, p->iface_list)
if (ifa->iface == a->iface)
@@ -1166,6 +1171,9 @@ ospf_reconfigure_ifaces2(struct ospf_proto *p)
WALK_LIST(a, iface->addrs)
{
+ if (a->prefix.type != NET_IP4)
+ continue;
+
if (a->flags & IA_SECONDARY)
continue;
@@ -1184,8 +1192,8 @@ ospf_reconfigure_ifaces2(struct ospf_proto *p)
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);
+ log(L_INFO "%s: Restarting interface %s (%N) in area %R",
+ p->p.name, ifa->ifname, &a->prefix, s.oa->areaid);
ospf_iface_shutdown(ifa);
ospf_iface_remove(ifa);
}
@@ -1209,6 +1217,9 @@ ospf_reconfigure_ifaces3(struct ospf_proto *p)
WALK_LIST(a, iface->addrs)
{
+ if (a->prefix.type != NET_IP6)
+ continue;
+
if (a->flags & IA_SECONDARY)
continue;
@@ -1340,7 +1351,7 @@ ospf_iface_info(struct ospf_iface *ifa)
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);
+ cli_msg(-1015, "Interface %s (%N)", ifa->ifname, &ifa->addr->prefix);
cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c
index cb7b186a..fbfd8d29 100644
--- a/proto/ospf/lsalib.c
+++ b/proto/ospf/lsalib.c
@@ -280,21 +280,19 @@ 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)
+lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, 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);
+ net_fill_ip4(net, ip4_from_u32(en->lsa.id & ls->netmask), 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);
+ ospf3_get_prefix(ls->prefix, af, net, pxopts, NULL);
*metric = ls->metric & LSA_METRIC_MASK;
}
}
@@ -319,13 +317,14 @@ lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u
}
void
-lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt)
+lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, 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);
+ net_fill_ip4(&rt->net,
+ ip4_from_u32(en->lsa.id & ext->netmask),
+ u32_masklen(ext->netmask));
rt->pxopts = 0;
rt->metric = ext->metric & LSA_METRIC_MASK;
rt->ebit = ext->metric & LSA_EXT2_EBIT;
@@ -339,14 +338,13 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *r
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);
+ u32 *buf = ospf3_get_prefix(ext->rest, af, &rt->net, &rt->pxopts, NULL);
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);
+ buf = ospf3_get_addr(buf, af, &rt->fwaddr);
else
rt->fwaddr = IPA_NONE;
@@ -452,7 +450,7 @@ lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *bod
return 0;
u8 pxl = pxlen(body->prefix);
- if (pxl > MAX_PREFIX_LENGTH)
+ if (pxl > IP6_MAX_PREFIX_LENGTH)
return 0;
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) +
@@ -491,11 +489,11 @@ lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
return 0;
u8 pxl = pxlen(body->rest);
- if (pxl > MAX_PREFIX_LENGTH)
+ if (pxl > IP6_MAX_PREFIX_LENGTH)
return 0;
int len = IPV6_PREFIX_SPACE(pxl);
- if (body->metric & LSA_EXT3_FBIT) // forwardinf address
+ if (body->metric & LSA_EXT3_FBIT) // forwarding address
len += 16;
if (body->metric & LSA_EXT3_TBIT) // route tag
len += 4;
@@ -520,7 +518,7 @@ lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, uint offset, u8 *p
return 0;
u8 pxl = pxlen((u32 *) (pbuf + offset));
- if (pxl > MAX_PREFIX_LENGTH)
+ if (pxl > IP6_MAX_PREFIX_LENGTH)
return 0;
offset += IPV6_PREFIX_SPACE(pxl);
@@ -554,8 +552,8 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
/**
* lsa_validate - check whether given LSA is valid
* @lsa: LSA header
- * @lsa_type: one of %LSA_T_xxx
- * @ospf2: %true means OSPF version 2, %false means OSPF version 3
+ * @lsa_type: internal LSA type (%LSA_T_xxx)
+ * @ospf2: %true for OSPFv2, %false for OSPFv3
* @body: pointer to LSA body
*
* Checks internal structure of given LSA body (minimal length,
diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h
index 638b3525..fca7faec 100644
--- a/proto/ospf/lsalib.h
+++ b/proto/ospf/lsalib.h
@@ -41,7 +41,7 @@ void lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *do
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 UNUSED4 UNUSED6)
+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; }
@@ -55,9 +55,12 @@ u16 lsa_verify_checksum(const void *lsa_n, int lsa_len);
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);
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_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, 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);
+void lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt);
int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
+static inline btime lsa_inst_age(struct top_hash_entry *en)
+{ return current_time() - en->inst_time; }
+
#endif /* _BIRD_OSPF_LSALIB_H_ */
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index 157d9628..a98c9098 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -137,7 +137,7 @@ ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n)
ret->lsa_body = LSA_BODY_DUMMY;
if (!tm_active(n->lsrt_timer))
- tm_start(n->lsrt_timer, n->ifa->rxmtint);
+ tm_start(n->lsrt_timer, n->ifa->rxmtint S);
}
void
@@ -572,7 +572,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
{
/* 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 (en && (lsa_inst_age(en) < MINLSARRIVAL))
{
OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival");
continue;
@@ -700,7 +700,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
if (!EMPTY_SLIST(n->lsrql) && (n->lsrqi == SHEAD(n->lsrql)))
{
ospf_send_lsreq(p, n);
- tm_start(n->lsrq_timer, n->ifa->rxmtint);
+ tm_start(n->lsrq_timer, n->ifa->rxmtint S);
}
return;
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index 9fe3c028..f2d3505e 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -94,11 +94,11 @@ ospf_neighbor_new(struct ospf_iface *ifa)
init_list(&n->ackl[ACKL_DIRECT]);
init_list(&n->ackl[ACKL_DELAY]);
- 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);
+ n->inactim = tm_new_init(pool, inactivity_timer_hook, n, 0, 0);
+ n->dbdes_timer = tm_new_init(pool, dbdes_timer_hook, n, ifa->rxmtint S, 0);
+ n->lsrq_timer = tm_new_init(pool, lsrq_timer_hook, n, ifa->rxmtint S, 0);
+ n->lsrt_timer = tm_new_init(pool, lsrt_timer_hook, n, ifa->rxmtint S, 0);
+ n->ackd_timer = tm_new_init(pool, ackd_timer_hook, n, ifa->rxmtint S / 2, 0);
return (n);
}
@@ -186,7 +186,7 @@ ospf_neigh_chstate(struct ospf_neighbor *n, u8 state)
n->myimms = DBDES_IMMS;
tm_start(n->dbdes_timer, 0);
- tm_start(n->ackd_timer, ifa->rxmtint / 2);
+ tm_start(n->ackd_timer, ifa->rxmtint S / 2);
}
if (state > NEIGHBOR_EXSTART)
@@ -231,7 +231,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
ospf_neigh_chstate(n, NEIGHBOR_INIT);
/* Restart inactivity timer */
- tm_start(n->inactim, n->ifa->deadint);
+ tm_start(n->inactim, n->ifa->deadint S);
break;
case INM_2WAYREC:
@@ -359,7 +359,7 @@ can_do_adj(struct ospf_neighbor *n)
}
-static inline u32 neigh_get_id(struct ospf_proto *p UNUSED4 UNUSED6, struct ospf_neighbor *n)
+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 *
@@ -507,13 +507,14 @@ ospf_dr_election(struct ospf_iface *ifa)
u32 old_drid = ifa->drid;
u32 old_bdrid = ifa->bdrid;
+ ip_addr none = ospf_is_v2(p) ? IPA_NONE4 : IPA_NONE6;
ifa->drid = ndr ? ndr->rid : 0;
- ifa->drip = ndr ? ndr->ip : IPA_NONE;
+ ifa->drip = ndr ? ndr->ip : none;
ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
ifa->bdrid = nbdr ? nbdr->rid : 0;
- ifa->bdrip = nbdr ? nbdr->ip : IPA_NONE;
+ ifa->bdrip = nbdr ? nbdr->ip : none;
DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid);
@@ -650,20 +651,6 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
{
struct ospf_iface *ifa = n->ifa;
char *pos = "PtP ";
- char etime[6];
- int exp, sec, min;
-
- exp = n->inactim->expires - now;
- sec = exp % 60;
- min = exp / 60;
- if (min > 59)
- {
- bsprintf(etime, "-Inf-");
- }
- else
- {
- bsprintf(etime, "%02u:%02u", min, sec);
- }
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
{
@@ -675,6 +662,7 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
pos = "Other";
}
- 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);
+ cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%7t\t%-10s %-1I",
+ n->rid, n->priority, ospf_ns_names[n->state], pos,
+ tm_remains(n->inactim), ifa->ifname, n->ip);
}
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index d5d5d354..3ebebdaa 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -92,8 +92,10 @@
* - 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
+ * - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
+ * - RFC 5838 - OSPFv3 Support of Address Families
+ * - RFC 6549 - OSPFv2 Multi-Instance Extensions
+ * - RFC 6987 - OSPF Stub Router Advertisement
*/
#include <stdlib.h>
@@ -102,18 +104,11 @@
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 void ospf_reload_routes(struct channel *C);
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);
-static void
-ospf_area_initfib(struct fib_node *fn)
-{
- struct area_net *an = (struct area_net *) fn;
- an->hidden = 0;
- an->active = 0;
-}
static void
add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
@@ -122,23 +117,35 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
struct area_net_config *anc;
struct area_net *an;
- 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);
+ fib_init(&oa->net_fib, p->p.pool, ospf_get_af(p),
+ sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
+ fib_init(&oa->enet_fib, p->p.pool, ospf_get_af(p),
+ sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
WALK_LIST(anc, ac->net_list)
{
- an = (struct area_net *) fib_get(&oa->net_fib, &anc->px.addr, anc->px.len);
+ an = fib_get(&oa->net_fib, &anc->prefix);
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 = fib_get(&oa->enet_fib, &anc->prefix);
an->hidden = anc->hidden;
an->tag = anc->tag;
}
}
+static inline uint
+ospf_opts(struct ospf_proto *p)
+{
+ if (ospf_is_v2(p))
+ return 0;
+
+ return ((ospf_is_ip6(p) && !p->af_mc) ? OPT_V6 : 0) |
+ (!p->stub_router ? OPT_R : 0) | (p->af_ext ? OPT_AF : 0);
+}
+
static void
ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
{
@@ -154,16 +161,13 @@ ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
oa->areaid = ac->areaid;
oa->rt = NULL;
oa->po = p;
- fib_init(&oa->rtr, p->p.pool, sizeof(ort), 0, ospf_rt_initort);
+ fib_init(&oa->rtr, p->p.pool, NET_IP4, sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
add_area_nets(oa, ac);
if (oa->areaid == 0)
p->backbone = oa;
- if (ospf_is_v2(p))
- oa->options = ac->type;
- else
- oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
+ oa->options = ac->type | ospf_opts(p);
ospf_notify_rt_lsa(oa);
}
@@ -229,21 +233,25 @@ ospf_start(struct proto *P)
p->router_id = proto_get_router_id(P->cf);
p->ospf2 = c->ospf2;
+ p->af_ext = c->af_ext;
+ p->af_mc = c->af_mc;
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->disp_timer = tm_new_init(P->pool, ospf_disp, p, p->tick S, 0);
+ tm_start(p->disp_timer, 100 MS);
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));
+ p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop));
init_list(&(p->iface_list));
init_list(&(p->area_list));
- fib_init(&p->rtf, P->pool, sizeof(ort), 0, ospf_rt_initort);
+ fib_init(&p->rtf, P->pool, ospf_get_af(p), sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
+ if (ospf_is_v3(p))
+ idm_init(&p->idm, P->pool, 16);
p->areano = 0;
p->gr = ospf_top_new(p, P->pool);
s_init_list(&(p->lsal));
@@ -299,15 +307,16 @@ ospf_dump(struct proto *P)
}
static struct proto *
-ospf_init(struct proto_config *c)
+ospf_init(struct proto_config *CF)
{
- struct ospf_config *oc = (struct ospf_config *) c;
- struct proto *P = proto_new(c, sizeof(struct ospf_proto));
+ struct ospf_config *cf = (struct ospf_config *) CF;
+ struct proto *P = proto_new(CF);
+
+ P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
- 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->ifa_notify = cf->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;
@@ -391,17 +400,16 @@ ospf_schedule_rtcalc(struct ospf_proto *p)
p->calcrt = 1;
}
-static int
-ospf_reload_routes(struct proto *P)
+static void
+ospf_reload_routes(struct channel *C)
{
- struct ospf_proto *p = (struct ospf_proto *) P;
+ struct ospf_proto *p = (struct ospf_proto *) C->proto;
- if (p->calcrt != 2)
- OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation with route reload");
+ if (p->calcrt == 2)
+ return;
+ OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation with route reload");
p->calcrt = 2;
-
- return 1;
}
@@ -506,9 +514,9 @@ ospf_shutdown(struct proto *P)
ospf_iface_shutdown(ifa);
/* Cleanup locked rta entries */
- FIB_WALK(&p->rtf, nftmp)
+ FIB_WALK(&p->rtf, ort, nf)
{
- rta_free(((ort *) nftmp)->old_rta);
+ rta_free(nf->old_rta);
}
FIB_WALK_END;
@@ -603,11 +611,7 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
struct ospf_iface *ifa;
oa->ac = nac;
-
- if (ospf_is_v2(p))
- oa->options = nac->type;
- else
- oa->options = nac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
+ oa->options = nac->type | ospf_opts(p);
if (nac->type != oac->type)
{
@@ -639,17 +643,20 @@ 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 *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_config *new = (struct ospf_config *) CF;
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) != p->router_id)
+ if (proto_get_router_id(CF) != p->router_id)
+ return 0;
+
+ if (p->ospf2 != new->ospf2)
return 0;
if (p->rfc1583 != new->rfc1583)
@@ -658,13 +665,19 @@ ospf_reconfigure(struct proto *P, struct proto_config *c)
if (old->abr != new->abr)
return 0;
+ if ((p->af_ext != new->af_ext) || (p->af_mc != new->af_mc))
+ return 0;
+
+ if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
+ return 0;
+
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);
+ p->disp_timer->recurrent = p->tick S;
+ tm_start(p->disp_timer, 100 MS);
/* Mark all areas and ifaces */
WALK_LIST(oa, p->area_list)
@@ -746,7 +759,6 @@ ospf_sh(struct proto *P)
struct ospf_iface *ifa;
struct ospf_neighbor *n;
int ifano, nno, adjno, firstfib;
- struct area_net *anet;
if (p->p.proto_state != PS_UP)
{
@@ -795,29 +807,27 @@ ospf_sh(struct proto *P)
cli_msg(-1014, "\t\tNumber of adjacent neighbors:\t%u", adjno);
firstfib = 1;
- FIB_WALK(&oa->net_fib, nftmp)
+ FIB_WALK(&oa->net_fib, struct area_net, anet)
{
- anet = (struct area_net *) nftmp;
if(firstfib)
{
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,
+ cli_msg(-1014, "\t\t\t%1N\t%s\t%s", anet->fn.addr,
anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
}
FIB_WALK_END;
firstfib = 1;
- FIB_WALK(&oa->enet_fib, nftmp)
+ FIB_WALK(&oa->enet_fib, struct area_net, anet)
{
- anet = (struct area_net *) nftmp;
if(firstfib)
{
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,
+ cli_msg(-1014, "\t\t\t%1N\t%s\t%s", anet->fn.addr,
anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
}
FIB_WALK_END;
@@ -1072,15 +1082,14 @@ show_lsa_network(struct top_hash_entry *he, int ospf2)
}
static inline void
-show_lsa_sum_net(struct top_hash_entry *he, int ospf2)
+show_lsa_sum_net(struct top_hash_entry *he, int ospf2, int af)
{
- ip_addr ip;
- int pxlen;
+ net_addr net;
u8 pxopts;
u32 metric;
- lsa_parse_sum_net(he, ospf2, &ip, &pxlen, &pxopts, &metric);
- cli_msg(-1016, "\t\txnetwork %I/%d metric %u", ip, pxlen, metric);
+ lsa_parse_sum_net(he, ospf2, af, &net, &pxopts, &metric);
+ cli_msg(-1016, "\t\txnetwork %N metric %u", &net, metric);
}
static inline void
@@ -1096,16 +1105,16 @@ show_lsa_sum_rt(struct top_hash_entry *he, int ospf2)
static inline void
-show_lsa_external(struct top_hash_entry *he, int ospf2)
+show_lsa_external(struct top_hash_entry *he, int ospf2, int af)
{
struct ospf_lsa_ext_local rt;
- char str_via[STD_ADDRESS_P_LENGTH + 8] = "";
+ char str_via[IPA_MAX_TEXT_LENGTH + 8] = "";
char str_tag[16] = "";
if (he->lsa_type == LSA_T_EXT)
he->domain = 0; /* Unmark the LSA */
- lsa_parse_ext(he, ospf2, &rt);
+ lsa_parse_ext(he, ospf2, af, &rt);
if (rt.fbit)
bsprintf(str_via, " via %I", rt.fwaddr);
@@ -1113,19 +1122,15 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
if (rt.tag)
bsprintf(str_tag, " tag %08x", rt.tag);
- cli_msg(-1016, "\t\t%s %I/%d metric%s %u%s%s",
+ cli_msg(-1016, "\t\t%s %N metric%s %u%s%s",
(he->lsa_type == LSA_T_NSSA) ? "nssa-ext" : "external",
- rt.ip, rt.pxlen, rt.ebit ? "2" : "", rt.metric, str_via, str_tag);
+ &rt.net, rt.ebit ? "2" : "", rt.metric, str_via, str_tag);
}
static inline void
-show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
+show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode, int af)
{
struct ospf_lsa_prefix *px = he->lsa_body;
- ip_addr pxa;
- int pxlen;
- u8 pxopts;
- u16 metric;
u32 *buf;
int i;
@@ -1141,14 +1146,18 @@ show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
buf = px->rest;
for (i = 0; i < px->pxcount; i++)
- {
- buf = lsa_get_ipv6_prefix(buf, &pxa, &pxlen, &pxopts, &metric);
+ {
+ net_addr net;
+ u8 pxopts;
+ u16 metric;
- if (px->ref_type == LSA_T_RT)
- cli_msg(-1016, "\t\tstubnet %I/%d metric %u", pxa, pxlen, metric);
- else
- cli_msg(-1016, "\t\taddress %I/%d", pxa, pxlen);
- }
+ buf = ospf3_get_prefix(buf, af, &net, &pxopts, &metric);
+
+ if (px->ref_type == LSA_T_RT)
+ cli_msg(-1016, "\t\tstubnet %N metric %u", &net, metric);
+ else
+ cli_msg(-1016, "\t\taddress %N", &net);
+ }
}
void
@@ -1156,6 +1165,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
{
struct ospf_proto *p = (struct ospf_proto *) P;
int ospf2 = ospf_is_v2(p);
+ int af = ospf_get_af(p);
uint i, ix, j1, jx;
u32 last_area = 0xFFFFFFFF;
@@ -1276,7 +1286,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
case LSA_T_SUM_NET:
if (cnode->lsa_type == LSA_T_RT)
- show_lsa_sum_net(he, ospf2);
+ show_lsa_sum_net(he, ospf2, af);
break;
case LSA_T_SUM_RT:
@@ -1286,11 +1296,11 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
case LSA_T_EXT:
case LSA_T_NSSA:
- show_lsa_external(he, ospf2);
+ show_lsa_external(he, ospf2, af);
break;
case LSA_T_PREFIX:
- show_lsa_prefix(he, cnode);
+ show_lsa_prefix(he, cnode, af);
break;
}
@@ -1304,7 +1314,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
ix++;
while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
- show_lsa_external(hex[ix++], ospf2);
+ show_lsa_external(hex[ix++], ospf2, af);
cnode = NULL;
}
@@ -1338,7 +1348,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
last_rt = he->lsa.rt;
}
- show_lsa_external(he, ospf2);
+ show_lsa_external(he, ospf2, af);
}
}
@@ -1468,6 +1478,8 @@ struct protocol proto_ospf = {
.template = "ospf%d",
.attr_class = EAP_OSPF,
.preference = DEF_PREF_OSPF,
+ .channel_mask = NB_IP,
+ .proto_size = sizeof(struct ospf_proto),
.config_size = sizeof(struct ospf_config),
.init = ospf_init,
.dump = ospf_dump,
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 81c610d5..54eeb74c 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -14,7 +14,7 @@
#include "nest/bird.h"
#include "lib/checksum.h"
-#include "lib/ip.h"
+#include "lib/idm.h"
#include "lib/lists.h"
#include "lib/slists.h"
#include "lib/socket.h"
@@ -37,14 +37,6 @@
#endif
-#ifdef IPV6
-#define OSPF_IS_V2 0
-#else
-#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)
@@ -66,16 +58,16 @@
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) \
+ do { if (! p->log_lsa_tbf.drop) \
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 LSREFRESHTIME 1800 /* 30 minutes */
+#define MINLSINTERVAL (5 S_)
+#define MINLSARRIVAL (1 S_)
+#define LSINFINITY 0xffffff
#define OSPF_DEFAULT_TICK 1
#define OSPF_DEFAULT_STUB_COST 1000
@@ -87,16 +79,18 @@
#define OSPF_VLINK_ID_OFFSET 0x80000000
-
struct ospf_config
{
struct proto_config c;
uint tick;
u8 ospf2;
+ u8 af_ext;
+ u8 af_mc;
u8 rfc1583;
u8 stub_router;
u8 merge_external;
u8 instance_id;
+ u8 instance_id_set;
u8 abr;
u8 asbr;
int ecmp;
@@ -125,24 +119,24 @@ struct ospf_area_config
struct area_net_config
{
node n;
- struct prefix px;
+ net_addr prefix;
u32 tag;
u8 hidden;
};
struct area_net
{
- struct fib_node fn;
u32 metric; /* With possible LSA_EXT3_EBIT for NSSA area nets */
u32 tag;
u8 hidden;
u8 active;
+ struct fib_node fn;
};
struct ospf_stubnet_config
{
node n;
- struct prefix px;
+ net_addr prefix;
u32 cost;
u8 hidden;
u8 summary;
@@ -177,9 +171,9 @@ struct ospf_iface_patt
int tx_priority;
u16 tx_length;
u16 rx_buffer;
-
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
u8 instance_id;
+ u8 instance_id_set;
u8 autype; /* OSPF_AUTH_*, not really used in OSPFv3 */
u8 strictnbma;
u8 check_link;
@@ -189,7 +183,6 @@ struct ospf_iface_patt
u8 ptp_netmask; /* bool + 2 for unspecified */
u8 ttl_security; /* bool + 2 for TX only */
u8 bfd;
- u8 bsd_secondary;
list *passwords;
};
@@ -220,12 +213,15 @@ struct ospf_proto
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 idm idm; /* OSPFv3 LSA ID map */
+ u8 ospf2; /* OSPF v2 or v3 */
+ u8 af_ext; /* OSPFv3-AF extension */
+ u8 af_mc; /* OSPFv3-AF multicast */
+ u8 rfc1583; /* RFC1583 compatibility */
+ u8 stub_router; /* Do not forward transit traffic */
+ u8 merge_external; /* Should i merge external routes? */
+ u8 asbr; /* May i originate any ext/NSSA lsa? */
+ u8 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 */
@@ -273,10 +269,10 @@ struct ospf_iface
sock *sk; /* IP socket */
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 */
- u32 pollint; /* Poll interval */
- u32 deadint; /* after "deadint" missing hellos is router dead */
+ u32 waitint; /* Number of seconds before changing state from wait */
+ u32 rxmtint; /* Number of seconds between LSA retransmissions */
+ u32 pollint; /* Poll interval in seconds */
+ u32 deadint; /* After deadint seconds without hellos is router dead */
u32 iface_id; /* Interface ID (iface->index or new value for vlinks) */
u32 vid; /* ID of peer of virtual link */
ip_addr vip; /* IP of peer of virtual link */
@@ -287,8 +283,8 @@ struct ospf_iface
interface. LSAs contained in the update */
u16 helloint; /* number of seconds between hello sending */
list *passwords;
- u32 csn; /* Last used crypt seq number */
- bird_clock_t csn_use; /* Last time when packet with that CSN was sent */
+ u32 csn; /* Last used crypt seq number */
+ btime csn_use; /* Last time when packet with that CSN was sent */
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 */
@@ -458,14 +454,15 @@ struct ospf_neighbor
/* 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 */
+#define OPT_V6 0x0001 /* OSPFv3, LSA relevant for IPv6 routing calculation */
+#define OPT_E 0x0002 /* Related to AS-external LSAs */
+#define OPT_MC 0x0004 /* Related to MOSPF, not used and obsolete */
+#define OPT_N 0x0008 /* Related to NSSA */
+#define OPT_P 0x0008 /* OSPFv2, flags P and N share position, see NSSA RFC */
+#define OPT_EA 0x0010 /* OSPFv2, external attributes, not used and obsolete */
+#define OPT_R 0x0010 /* OSPFv3, originator is active router */
+#define OPT_DC 0x0020 /* Related to demand circuits, not used */
+#define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
#define OPT_RT_B (0x01 << 24)
@@ -682,8 +679,8 @@ struct ospf_lsa_ext3
struct ospf_lsa_ext_local
{
- ip_addr ip, fwaddr;
- int pxlen;
+ net_addr net;
+ ip_addr fwaddr;
u32 metric, ebit, fbit, tag, propagate;
u8 pxopts;
};
@@ -721,73 +718,102 @@ lsa_net_count(struct ospf_lsa_header *lsa)
/* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address)
as index, so we need to encapsulate RID to IP address */
-#define ipa_from_rid(x) ipa_from_u32(x)
-#define ipa_to_rid(x) ipa_to_u32(x)
+#define net_from_rid(x) NET_ADDR_IP4(ip4_from_u32(x), IP4_MAX_PREFIX_LENGTH)
+#define rid_from_net(x) ip4_to_u32(((net_addr_ip4 *) x)->prefix)
#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 int
+ospf_valid_prefix(net_addr *n)
+{
+ /*
+ * In OSPFv2, prefix is stored as netmask; ip4_masklen() returns 255 for
+ * invalid one. But OSPFv3-AF may receive IPv4 net with 32 < pxlen < 128.
+ */
+ uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
+ return n->pxlen <= max;
+}
+
+/*
+ * In OSPFv3-AF (RFC 5835), IPv4 address is encoded by just placing it in the
+ * first 32 bits of IPv6 address and setting remaining bits to zero. Likewise
+ * for IPv4 prefix, where remaining bits do not matter. We use following
+ * functions to convert between IPv4 and IPv4-in-IPv6 representations:
+ */
+
+static inline ip4_addr ospf3_6to4(ip6_addr a)
+{ return _MI4(_I0(a)); }
+
+static inline ip6_addr ospf3_4to6(ip4_addr a)
+{ return _MI6(_I(a), 0, 0, 0); }
+
static inline u32 *
-lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest)
+ospf3_get_prefix(u32 *buf, int af, net_addr *n, u8 *pxopts, u16 *rest)
{
- u8 pxl = (*buf >> 24);
- *pxopts = (*buf >> 16);
- *rest = *buf;
- *pxlen = pxl;
+ ip6_addr px = IP6_NONE;
+ uint pxlen = (*buf >> 24);
+ *pxopts = (*buf >> 16) & 0xff;
+ if (rest) *rest = *buf & 0xffff;
buf++;
- *addr = IPA_NONE;
-
-#ifdef IPV6
- if (pxl > 0)
- _I0(*addr) = *buf++;
- if (pxl > 32)
- _I1(*addr) = *buf++;
- if (pxl > 64)
- _I2(*addr) = *buf++;
- if (pxl > 96)
- _I3(*addr) = *buf++;
+ if (pxlen > 0)
+ _I0(px) = *buf++;
+ if (pxlen > 32)
+ _I1(px) = *buf++;
+ if (pxlen > 64)
+ _I2(px) = *buf++;
+ if (pxlen > 96)
+ _I3(px) = *buf++;
/* Clean up remaining bits */
- if (pxl < 128)
- addr->addr[pxl / 32] &= u32_mkmask(pxl % 32);
-#endif
+ if (pxlen < 128)
+ px.addr[pxlen / 32] &= u32_mkmask(pxlen % 32);
+
+ if (af == NET_IP4)
+ net_fill_ip4(n, ospf3_6to4(px), pxlen);
+ else
+ net_fill_ip6(n, px, pxlen);
return buf;
}
static inline u32 *
-lsa_get_ipv6_addr(u32 *buf, ip_addr *addr)
+ospf3_put_prefix(u32 *buf, net_addr *n, u8 pxopts, u16 rest)
{
- *addr = *(ip_addr *) buf;
- return buf + 4;
-}
+ ip6_addr px = (n->type == NET_IP4) ? ospf3_4to6(net4_prefix(n)) : net6_prefix(n);
+ uint pxlen = n->pxlen;
-static inline u32 *
-put_ipv6_prefix(u32 *buf, ip_addr addr UNUSED4, u8 pxlen UNUSED4, u8 pxopts UNUSED4, u16 lh UNUSED4)
-{
-#ifdef IPV6
- *buf++ = ((pxlen << 24) | (pxopts << 16) | lh);
+ *buf++ = ((pxlen << 24) | (pxopts << 16) | rest);
if (pxlen > 0)
- *buf++ = _I0(addr);
+ *buf++ = _I0(px);
if (pxlen > 32)
- *buf++ = _I1(addr);
+ *buf++ = _I1(px);
if (pxlen > 64)
- *buf++ = _I2(addr);
+ *buf++ = _I2(px);
if (pxlen > 96)
- *buf++ = _I3(addr);
-#endif
+ *buf++ = _I3(px);
+
return buf;
}
static inline u32 *
-put_ipv6_addr(u32 *buf, ip_addr addr)
+ospf3_get_addr(u32 *buf, int af, ip_addr *addr)
{
- *(ip_addr *) buf = addr;
+ ip6_addr a;
+ memcpy(&a, buf, 16);
+ *addr = (af == NET_IP4) ? ipa_from_ip4(ospf3_6to4(a)) : ipa_from_ip6(a);
+ return buf + 4;
+}
+
+static inline u32 *
+ospf3_put_addr(u32 *buf, ip_addr addr)
+{
+ ip6_addr a = ipa_is_ip4(addr) ? ospf3_4to6(ipa_to_ip4(addr)) : ipa_to_ip6(addr);
+ memcpy(buf, &a, 16);
return buf + 4;
}
@@ -831,19 +857,24 @@ static inline void ospf_notify_net_lsa(struct ospf_iface *ifa)
static inline void ospf_notify_link_lsa(struct ospf_iface *ifa)
{ ifa->update_link_lsa = 1; }
-
-#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 UNUSED4 UNUSED6)
+
+static inline int ospf_get_version(struct ospf_proto *p)
{ return ospf_is_v2(p) ? 2 : 3; }
+static inline int ospf_is_ip4(struct ospf_proto *p)
+{ return p->p.net_type == NET_IP4; }
+
+static inline int ospf_is_ip6(struct ospf_proto *p)
+{ return p->p.net_type == NET_IP6; }
+
+static inline int ospf_get_af(struct ospf_proto *p)
+{ return p->p.net_type; }
+
struct ospf_area *ospf_find_area(struct ospf_proto *p, u32 aid);
static inline struct ospf_area *ospf_main_area(struct ospf_proto *p)
@@ -925,7 +956,7 @@ static inline void ospf_send_to_des(struct ospf_iface *ifa)
#define SKIP(DSC) do { err_dsc = DSC; goto skip; } while(0)
#endif
-static inline uint ospf_pkt_hdrlen(struct ospf_proto *p UNUSED4 UNUSED6)
+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); }
static inline void * ospf_tx_buffer(struct ospf_iface *ifa)
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 6b6a97a4..38d7a75f 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -77,16 +77,16 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
reboot when system does not have independent RTC? */
if (!ifa->csn)
{
- ifa->csn = (u32) now;
- ifa->csn_use = now;
+ ifa->csn = (u32) (current_real_time() TO_S);
+ ifa->csn_use = current_time();
}
/* 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)
+ if ((current_time() - ifa->csn_use) > 1 S)
ifa->csn++;
- ifa->csn_use = now;
+ ifa->csn_use = current_time();
uint auth_len = mac_type_length(pass->alg);
byte *auth_tail = ((byte *) pkt + *plen);
@@ -203,7 +203,7 @@ drop:
/**
* ospf_rx_hook
* @sk: socket we received the packet.
- * @len: size of the packet
+ * @len: length of the packet
*
* This is the entry point for messages from neighbors. Many checks (like
* authentication, checksums, size) are done before the packet is passed to
@@ -231,7 +231,7 @@ ospf_rx_hook(sock *sk, uint len)
return 1;
int src_local, dst_local, dst_mcast;
- src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
+ src_local = ipa_in_netX(sk->faddr, &ifa->addr->prefix);
dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers);
@@ -270,9 +270,6 @@ ospf_rx_hook(sock *sk, uint len)
if (pkt == NULL)
DROP("bad IP header", len);
- if (ifa->check_ttl && (sk->rcv_ttl < 255))
- DROP("wrong TTL", sk->rcv_ttl);
-
if (len < sizeof(struct ospf_packet))
DROP("too short", len);
@@ -379,6 +376,10 @@ found:
if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0))
return 1;
+ /* TTL check must be done after instance dispatch */
+ if (ifa->check_ttl && (sk->rcv_ttl < 255))
+ DROP("wrong TTL", sk->rcv_ttl);
+
if (rid == p->router_id)
DROP1("my own router ID");
@@ -491,8 +492,8 @@ ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
void
ospf_send_to_bdr(struct ospf_iface *ifa)
{
- if (ipa_nonzero(ifa->drip))
+ if (ipa_nonzero2(ifa->drip))
ospf_send_to(ifa, ifa->drip);
- if (ipa_nonzero(ifa->bdrip))
+ if (ipa_nonzero2(ifa->bdrip))
ospf_send_to(ifa, ifa->bdrip);
}
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 368e3d05..c0fe218a 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -10,9 +10,7 @@
#include "ospf.h"
-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 add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par, u32 dist, int i, uint lif, uint nif);
static void rt_sync(struct ospf_proto *p);
@@ -21,17 +19,8 @@ static inline void reset_ri(ort *ort)
bzero(&ort->n, sizeof(orta));
}
-void
-ospf_rt_initort(struct fib_node *fn)
-{
- ort *ri = (ort *) fn;
- reset_ri(ri);
- ri->old_rta = NULL;
- ri->fn.flags = 0;
-}
-
static inline int
-nh_is_vlink(struct mpnh *nhs)
+nh_is_vlink(struct nexthop *nhs)
{
return !nhs->iface;
}
@@ -42,20 +31,19 @@ unresolved_vlink(ort *ort)
return ort->n.nhs && nh_is_vlink(ort->n.nhs);
}
-static inline struct mpnh *
+static inline struct nexthop *
new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight)
{
- struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh));
+ struct nexthop *nh = lp_allocz(p->nhpool, sizeof(struct nexthop));
nh->gw = gw;
nh->iface = iface;
- nh->next = NULL;
nh->weight = weight;
return nh;
}
/* Returns true if there are device nexthops in n */
static inline int
-has_device_nexthops(const struct mpnh *n)
+has_device_nexthops(const struct nexthop *n)
{
for (; n; n = n->next)
if (ipa_zero(n->gw))
@@ -65,13 +53,13 @@ has_device_nexthops(const struct mpnh *n)
}
/* Replace device nexthops with nexthops to gw */
-static struct mpnh *
-fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw)
+static struct nexthop *
+fix_device_nexthops(struct ospf_proto *p, const struct nexthop *n, ip_addr gw)
{
- struct mpnh *root1 = NULL;
- struct mpnh *root2 = NULL;
- struct mpnh **nn1 = &root1;
- struct mpnh **nn2 = &root2;
+ struct nexthop *root1 = NULL;
+ struct nexthop *root2 = NULL;
+ struct nexthop **nn1 = &root1;
+ struct nexthop **nn2 = &root2;
if (!p->ecmp)
return new_nexthop(p, gw, n->iface, n->weight);
@@ -82,7 +70,7 @@ fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw)
for (; n; n = n->next)
{
- struct mpnh *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight);
+ struct nexthop *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight);
if (ipa_zero(n->gw))
{
@@ -96,7 +84,7 @@ fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw)
}
}
- return mpnh_merge(root1, root2, 1, 1, p->ecmp, p->nhpool);
+ return nexthop_merge(root1, root2, 1, 1, p->ecmp, p->nhpool);
}
@@ -292,7 +280,7 @@ ort_merge(struct ospf_proto *p, ort *o, const orta *new)
if (old->nhs != new->nhs)
{
- old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
+ old->nhs = nexthop_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
p->ecmp, p->nhpool);
old->nhs_reuse = 1;
}
@@ -308,7 +296,7 @@ ort_merge_ext(struct ospf_proto *p, ort *o, const orta *new)
if (old->nhs != new->nhs)
{
- old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
+ old->nhs = nexthop_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
p->ecmp, p->nhpool);
old->nhs_reuse = 1;
}
@@ -334,9 +322,9 @@ ort_merge_ext(struct ospf_proto *p, ort *o, const orta *new)
static inline void
-ri_install_net(struct ospf_proto *p, ip_addr prefix, int pxlen, const orta *new)
+ri_install_net(struct ospf_proto *p, net_addr *net, const orta *new)
{
- ort *old = (ort *) fib_get(&p->rtf, &prefix, pxlen);
+ ort *old = fib_get(&p->rtf, net);
int cmp = orta_compare(p, new, &old->n);
if (cmp > 0)
@@ -348,8 +336,8 @@ ri_install_net(struct ospf_proto *p, ip_addr prefix, int pxlen, const orta *new)
static inline void
ri_install_rt(struct ospf_area *oa, u32 rid, const orta *new)
{
- ip_addr addr = ipa_from_rid(rid);
- ort *old = (ort *) fib_get(&oa->rtr, &addr, MAX_PREFIX_LENGTH);
+ net_addr_ip4 nrid = net_from_rid(rid);
+ ort *old = fib_get(&oa->rtr, (net_addr *) &nrid);
int cmp = orta_compare(oa->po, new, &old->n);
if (cmp > 0)
@@ -359,17 +347,19 @@ ri_install_rt(struct ospf_area *oa, u32 rid, const orta *new)
}
static inline void
-ri_install_asbr(struct ospf_proto *p, ip_addr *addr, const orta *new)
+ri_install_asbr(struct ospf_proto *p, u32 rid, const orta *new)
{
- ort *old = (ort *) fib_get(&p->backbone->rtr, addr, MAX_PREFIX_LENGTH);
+ net_addr_ip4 nrid = net_from_rid(rid);
+ ort *old = fib_get(&p->backbone->rtr, (net_addr *) &nrid);
+
if (orta_compare_asbr(p, new, &old->n) > 0)
ort_replace(old, new);
}
static inline void
-ri_install_ext(struct ospf_proto *p, ip_addr prefix, int pxlen, const orta *new)
+ri_install_ext(struct ospf_proto *p, net_addr *net, const orta *new)
{
- ort *old = (ort *) fib_get(&p->rtf, &prefix, pxlen);
+ ort *old = fib_get(&p->rtf, net);
int cmp = orta_compare_ext(p, new, &old->n);
if (cmp > 0)
@@ -404,7 +394,7 @@ px_pos_to_ifa(struct ospf_area *oa, int pos)
static void
-add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en, int pos)
+add_network(struct ospf_area *oa, net_addr *net, int metric, struct top_hash_entry *en, int pos)
{
struct ospf_proto *p = oa->po;
@@ -419,7 +409,7 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_
.nhs = en->nhs
};
- if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
+ if (!ospf_valid_prefix(net))
{
log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
@@ -440,7 +430,7 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_
nf.nhs = ifa ? new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL;
}
- ri_install_net(p, px, pxlen, &nf);
+ ri_install_net(p, net, &nf);
}
@@ -451,8 +441,7 @@ spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entr
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;
+ int i;
if (rt->options & OPT_RT_V)
oa->trcap = 1;
@@ -502,9 +491,10 @@ spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entr
* 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);
+ net_addr_ip4 net =
+ NET_ADDR_IP4(ip4_from_u32(rtl.id & rtl.data), u32_masklen(rtl.data));
+
+ add_network(oa, (net_addr *) &net, act->dist + rtl.metric, act, i);
break;
case LSART_NET:
@@ -517,7 +507,7 @@ spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entr
break;
}
- add_cand(&oa->cand, tmp, act, act->dist + rtl.metric, oa, i);
+ add_cand(oa, tmp, act, act->dist + rtl.metric, i, rtl.lif, rtl.nif);
}
}
@@ -526,21 +516,21 @@ spfa_process_net(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_ent
{
struct ospf_lsa_net *ln = act->lsa_body;
struct top_hash_entry *tmp;
- ip_addr prefix;
- int pxlen, i, cnt;
+ int 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);
+ net_addr_ip4 net =
+ NET_ADDR_IP4(ip4_from_u32(act->lsa.id & ln->optx), u32_masklen(ln->optx));
+
+ add_network(oa, (net_addr *) &net, 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);
+ add_cand(oa, tmp, act, act->dist, -1, 0, 0);
}
}
@@ -549,10 +539,6 @@ spfa_process_prefixes(struct ospf_proto *p, struct ospf_area *oa)
{
struct top_hash_entry *en, *src;
struct ospf_lsa_prefix *px;
- ip_addr pxa;
- int pxlen;
- u8 pxopts;
- u16 metric;
u32 *buf;
int i;
@@ -587,18 +573,22 @@ spfa_process_prefixes(struct ospf_proto *p, struct ospf_area *oa)
buf = px->rest;
for (i = 0; i < px->pxcount; i++)
- {
- buf = lsa_get_ipv6_prefix(buf, &pxa, &pxlen, &pxopts, &metric);
+ {
+ net_addr net;
+ u8 pxopts;
+ u16 metric;
- if (pxopts & OPT_PX_NU)
- continue;
+ buf = ospf3_get_prefix(buf, ospf_get_af(p), &net, &pxopts, &metric);
- /* Store the first global address to use it later as a vlink endpoint */
- if ((pxopts & OPT_PX_LA) && ipa_zero(src->lb))
- src->lb = pxa;
+ if (pxopts & OPT_PX_NU)
+ continue;
- add_network(oa, pxa, pxlen, src->dist + metric, src, i);
- }
+ /* Store the first global address to use it later as a vlink endpoint */
+ if ((pxopts & OPT_PX_LA) && (net.type == NET_IP6) && ipa_zero(src->lb))
+ src->lb = ipa_from_ip6(net6_prefix(&net));
+
+ add_network(oa, &net, src->dist + metric, src, i);
+ }
}
}
@@ -659,7 +649,8 @@ ospf_rt_spfa(struct ospf_area *oa)
}
static int
-link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par)
+link_back(struct ospf_area *oa, struct top_hash_entry *en,
+ struct top_hash_entry *par, uint lif, uint nif)
{
struct ospf_proto *p = oa->po;
struct ospf_lsa_rt_walk rtl;
@@ -697,6 +688,10 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif);
if (tmp == par)
{
+ /*
+ * Note that there may be multiple matching Rt-fields if router 'en'
+ * have multiple interfaces to net 'par'. Perhaps we should do ECMP.
+ */
if (ospf_is_v2(p))
en->lb = ipa_from_u32(rtl.data);
else
@@ -708,7 +703,13 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
case LSART_VLNK:
case LSART_PTP:
- /* Not necessary the same link, see RFC 2328 [23] */
+ /*
+ * For OSPFv2, not necessary the same link, see RFC 2328 [23].
+ * For OSPFv3, we verify that by comparing nif and lif fields.
+ */
+ if (ospf_is_v3(p) && ((rtl.lif != nif) || (rtl.nif != lif)))
+ break;
+
tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id);
if (tmp == par)
return 1;
@@ -741,13 +742,12 @@ ospf_rt_sum(struct ospf_area *oa)
{
struct ospf_proto *p = oa->po;
struct top_hash_entry *en;
- ip_addr ip, abrip;
+ net_addr net;
u32 dst_rid, metric, options;
ort *abr;
- int pxlen = -1, type = -1;
+ int type;
u8 pxopts;
-
OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid);
WALK_SLIST(en, p->lsal)
@@ -770,18 +770,18 @@ ospf_rt_sum(struct ospf_area *oa)
if (en->lsa_type == LSA_T_SUM_NET)
{
- lsa_parse_sum_net(en, ospf_is_v2(p), &ip, &pxlen, &pxopts, &metric);
-
- if (pxopts & OPT_PX_NU)
- continue;
+ lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
- if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
+ if (!ospf_valid_prefix(&net))
{
log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
continue;
}
+ if (pxopts & OPT_PX_NU)
+ continue;
+
options = 0;
type = ORT_NET;
}
@@ -802,8 +802,8 @@ ospf_rt_sum(struct ospf_area *oa)
continue;
/* 16.2. (4) */
- abrip = ipa_from_rid(en->lsa.rt);
- abr = (ort *) fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH);
+ net_addr_ip4 nrid = net_from_rid(en->lsa.rt);
+ abr = fib_find(&oa->rtr, (net_addr *) &nrid);
if (!abr || !abr->n.type)
continue;
@@ -827,7 +827,7 @@ ospf_rt_sum(struct ospf_area *oa)
};
if (type == ORT_NET)
- ri_install_net(p, ip, pxlen, &nf);
+ ri_install_net(p, &net, &nf);
else
ri_install_rt(oa, dst_rid, &nf);
}
@@ -841,11 +841,7 @@ ospf_rt_sum_tr(struct ospf_area *oa)
struct ospf_area *bb = p->backbone;
struct top_hash_entry *en;
ort *re, *abr;
- ip_addr ip, abrip;
- u32 dst_rid, metric, options;
- int pxlen;
- u8 pxopts;
-
+ u32 metric;
if (!bb)
return;
@@ -868,26 +864,31 @@ ospf_rt_sum_tr(struct ospf_area *oa)
if (en->lsa_type == LSA_T_SUM_NET)
{
- lsa_parse_sum_net(en, ospf_is_v2(p), &ip, &pxlen, &pxopts, &metric);
+ net_addr net;
+ u8 pxopts;
- if (pxopts & OPT_PX_NU)
- continue;
+ lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
- if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
+ if (!ospf_valid_prefix(&net))
{
log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
continue;
}
- re = fib_find(&p->rtf, &ip, pxlen);
+ if (pxopts & OPT_PX_NU)
+ continue;
+
+ re = fib_find(&p->rtf, &net);
}
else // en->lsa_type == LSA_T_SUM_RT
{
+ u32 dst_rid, options;
+
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);
+ net_addr_ip4 nrid = net_from_rid(dst_rid);
+ re = fib_find(&bb->rtr, (net_addr *) &nrid);
}
/* 16.3 (1b) */
@@ -905,8 +906,8 @@ ospf_rt_sum_tr(struct ospf_area *oa)
continue;
/* 16.3. (4) */
- abrip = ipa_from_rid(en->lsa.rt);
- abr = fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH);
+ net_addr_ip4 nrid = net_from_rid(en->lsa.rt);
+ abr = fib_find(&oa->rtr, (net_addr *) &nrid);
if (!abr || !abr->n.type)
continue;
@@ -997,7 +998,7 @@ decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest)
return 1;
struct area_net *anet = (struct area_net *)
- fib_route(&nf->n.oa->net_fib, nf->fn.prefix, nf->fn.pxlen);
+ fib_route(&nf->n.oa->net_fib, nf->fn.addr);
/* Condensed area network found */
if (anet)
@@ -1016,13 +1017,13 @@ check_sum_net_lsa(struct ospf_proto *p, ort *nf)
if (nf->area_net)
{
/* It is a default route for stub areas, handled entirely in ospf_rt_abr() */
- if (nf->fn.pxlen == 0)
+ if (nf->fn.addr->pxlen == 0)
return;
/* Find that area network */
WALK_LIST(anet_oa, p->area_list)
{
- anet = (struct area_net *) fib_find(&anet_oa->net_fib, &nf->fn.prefix, nf->fn.pxlen);
+ anet = fib_find(&anet_oa->net_fib, nf->fn.addr);
if (anet)
break;
}
@@ -1041,14 +1042,16 @@ check_sum_net_lsa(struct ospf_proto *p, ort *nf)
static inline void
check_sum_rt_lsa(struct ospf_proto *p, ort *nf)
{
+ u32 rid = rid_from_net(nf->fn.addr);
+
struct ospf_area *oa;
WALK_LIST(oa, p->area_list)
if (decide_sum_lsa(oa, nf, ORT_ROUTER))
- ospf_originate_sum_rt_lsa(p, oa, nf, nf->n.metric1, nf->n.options);
+ ospf_originate_sum_rt_lsa(p, oa, rid, nf->n.metric1, nf->n.options);
}
static inline int
-decide_nssa_lsa(struct ospf_proto *p UNUSED4 UNUSED6, ort *nf, struct ospf_lsa_ext_local *rt)
+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;
@@ -1057,14 +1060,14 @@ decide_nssa_lsa(struct ospf_proto *p UNUSED4 UNUSED6, ort *nf, struct ospf_lsa_e
return 0;
/* Condensed area network found */
- if (fib_route(&oa->enet_fib, nf->fn.prefix, nf->fn.pxlen))
+ if (fib_route(&oa->enet_fib, nf->fn.addr))
return 0;
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 */
- lsa_parse_ext(en, ospf_is_v2(p), rt);
+ lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), rt);
if (rt->pxopts & OPT_PX_NU)
return 0;
@@ -1092,7 +1095,7 @@ check_nssa_lsa(struct ospf_proto *p, ort *nf)
/* Find that area network */
WALK_LIST(oa, p->area_list)
{
- anet = (struct area_net *) fib_find(&oa->enet_fib, &nf->fn.prefix, nf->fn.pxlen);
+ anet = fib_find(&oa->enet_fib, nf->fn.addr);
if (anet)
break;
}
@@ -1162,24 +1165,20 @@ static void
ospf_rt_abr1(struct ospf_proto *p)
{
struct area_net *anet;
- ort *nf, *default_nf;
+ ort *default_nf;
+ net_addr default_net;
/* RFC 2328 G.3 - incomplete resolution of virtual next hops - routers */
- FIB_WALK(&p->backbone->rtr, nftmp)
+ FIB_WALK(&p->backbone->rtr, ort, nf)
{
- nf = (ort *) nftmp;
-
if (nf->n.type && unresolved_vlink(nf))
reset_ri(nf);
}
FIB_WALK_END;
- FIB_WALK(&p->rtf, nftmp)
+ FIB_WALK(&p->rtf, ort, nf)
{
- nf = (ort *) nftmp;
-
-
/* RFC 2328 G.3 - incomplete resolution of virtual next hops - networks */
if (nf->n.type && unresolved_vlink(nf))
reset_ri(nf);
@@ -1188,7 +1187,7 @@ ospf_rt_abr1(struct ospf_proto *p)
/* Compute condensed area networks */
if (nf->n.type == RTS_OSPF)
{
- anet = (struct area_net *) fib_route(&nf->n.oa->net_fib, nf->fn.prefix, nf->fn.pxlen);
+ anet = (struct area_net *) fib_route(&nf->n.oa->net_fib, nf->fn.addr);
if (anet)
{
if (!anet->active)
@@ -1196,7 +1195,7 @@ ospf_rt_abr1(struct ospf_proto *p)
anet->active = 1;
/* Get a RT entry and mark it to know that it is an area network */
- ort *nfi = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
+ ort *nfi = fib_get(&p->rtf, anet->fn.addr);
nfi->area_net = 1;
/* 16.2. (3) */
@@ -1211,8 +1210,13 @@ ospf_rt_abr1(struct ospf_proto *p)
}
FIB_WALK_END;
- ip_addr addr = IPA_NONE;
- default_nf = (ort *) fib_get(&p->rtf, &addr, 0);
+
+ if (ospf_is_v2(p))
+ net_fill_ip4(&default_net, IP4_NONE, 0);
+ else
+ net_fill_ip6(&default_net, IP6_NONE, 0);
+
+ default_nf = fib_get(&p->rtf, &default_net);
default_nf->area_net = 1;
struct ospf_area *oa;
@@ -1239,11 +1243,10 @@ ospf_rt_abr1(struct ospf_proto *p)
/* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
if (oa_is_ext(oa))
{
- FIB_WALK(&oa->rtr, nftmp)
+ FIB_WALK(&oa->rtr, ort, nf)
{
- nf = (ort *) nftmp;
if (nf->n.options & ORTA_ASBR)
- ri_install_asbr(p, &nf->fn.prefix, &nf->n);
+ ri_install_asbr(p, rid_from_net(nf->fn.addr), &nf->n);
}
FIB_WALK_END;
}
@@ -1251,9 +1254,9 @@ ospf_rt_abr1(struct ospf_proto *p)
/* Originate or flush ASBR summary LSAs */
- FIB_WALK(&p->backbone->rtr, nftmp)
+ FIB_WALK(&p->backbone->rtr, ort, nf)
{
- check_sum_rt_lsa(p, (ort *) nftmp);
+ check_sum_rt_lsa(p, nf);
}
FIB_WALK_END;
@@ -1280,8 +1283,6 @@ ospf_rt_abr2(struct ospf_proto *p)
{
struct ospf_area *oa;
struct top_hash_entry *en;
- ort *nf, *nf2;
-
/* RFC 3103 3.1 - type-7 translator election */
struct ospf_area *bb = p->backbone;
@@ -1293,13 +1294,12 @@ ospf_rt_abr2(struct ospf_proto *p)
if (oa->ac->translator)
goto decided;
- FIB_WALK(&oa->rtr, nftmp)
+ FIB_WALK(&oa->rtr, ort, nf)
{
- nf = (ort *) nftmp;
if (!nf->n.type || !(nf->n.options & ORTA_ABR))
continue;
- nf2 = fib_find(&bb->rtr, &nf->fn.prefix, MAX_PREFIX_LENGTH);
+ ort *nf2 = fib_find(&bb->rtr, nf->fn.addr);
if (!nf2 || !nf2->n.type || !(nf2->n.options & ORTA_ABR))
continue;
@@ -1329,23 +1329,21 @@ ospf_rt_abr2(struct ospf_proto *p)
if (!translate && (oa->translate == TRANS_ON))
{
if (oa->translator_timer == NULL)
- oa->translator_timer = tm_new_set(p->p.pool, translator_timer_hook, oa, 0, 0);
+ oa->translator_timer = tm_new_init(p->p.pool, translator_timer_hook, oa, 0, 0);
/* Schedule the end of translation */
- tm_start(oa->translator_timer, oa->ac->transint);
+ tm_start(oa->translator_timer, oa->ac->transint S);
oa->translate = TRANS_WAIT;
}
}
/* Compute condensed external networks */
- FIB_WALK(&p->rtf, nftmp)
+ FIB_WALK(&p->rtf, ort, nf)
{
- nf = (ort *) nftmp;
if (rt_is_nssa(nf) && (nf->n.options & ORTA_PROP))
{
- struct area_net *anet = (struct area_net *)
- fib_route(&nf->n.oa->enet_fib, nf->fn.prefix, nf->fn.pxlen);
+ struct area_net *anet = fib_route(&nf->n.oa->enet_fib, nf->fn.addr);
if (anet)
{
@@ -1354,7 +1352,7 @@ ospf_rt_abr2(struct ospf_proto *p)
anet->active = 1;
/* Get a RT entry and mark it to know that it is an area network */
- nf2 = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
+ ort *nf2 = fib_get(&p->rtf, anet->fn.addr);
nf2->area_net = 1;
}
@@ -1369,10 +1367,8 @@ ospf_rt_abr2(struct ospf_proto *p)
FIB_WALK_END;
- FIB_WALK(&p->rtf, nftmp)
+ FIB_WALK(&p->rtf, ort, nf)
{
- nf = (ort *) nftmp;
-
check_sum_net_lsa(p, nf);
check_nssa_lsa(p, nf);
}
@@ -1382,22 +1378,57 @@ ospf_rt_abr2(struct ospf_proto *p)
/* Like fib_route(), but ignores dummy rt entries */
static void *
-ospf_fib_route(struct fib *f, ip_addr a, int len)
+ospf_fib_route_ip4(struct fib *f, ip4_addr a, int len)
+{
+ net_addr_ip4 net = NET_ADDR_IP4(a, len);
+ ort *nf;
+
+loop:
+ nf = fib_find(f, (net_addr *) &net);
+ if (nf && nf->n.type)
+ return nf;
+
+ if (net.pxlen > 0)
+ {
+ net.pxlen--;
+ ip4_clrbit(&net.prefix, net.pxlen);
+ goto loop;
+ }
+
+ return NULL;
+}
+
+static void *
+ospf_fib_route_ip6(struct fib *f, ip6_addr a, int len)
{
- ip_addr a0;
+ net_addr_ip6 net = NET_ADDR_IP6(a, len);
ort *nf;
- while (len >= 0)
+loop:
+ nf = fib_find(f, (net_addr *) &net);
+ if (nf && nf->n.type)
+ return nf;
+
+ if (net.pxlen > 0)
{
- a0 = ipa_and(a, ipa_mkmask(len));
- nf = fib_find(f, &a0, len);
- if (nf && nf->n.type)
- return nf;
- len--;
+ net.pxlen--;
+ ip6_clrbit(&net.prefix, net.pxlen);
+ goto loop;
}
+
return NULL;
}
+static void *
+ospf_fib_route(struct fib *f, ip_addr a)
+{
+ if (f->addr_type == NET_IP4)
+ return ospf_fib_route_ip4(f, ipa_to_ip4(a), IP4_MAX_PREFIX_LENGTH);
+ else
+ return ospf_fib_route_ip6(f, ipa_to_ip6(a), IP6_MAX_PREFIX_LENGTH);
+}
+
+
/* RFC 2328 16.4. calculating external routes */
static void
ospf_ext_spf(struct ospf_proto *p)
@@ -1405,7 +1436,6 @@ ospf_ext_spf(struct ospf_proto *p)
struct top_hash_entry *en;
struct ospf_lsa_ext_local rt;
ort *nf1, *nf2;
- ip_addr rtid;
u32 br_metric;
struct ospf_area *atmp;
@@ -1429,21 +1459,20 @@ ospf_ext_spf(struct ospf_proto *p)
DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type);
- lsa_parse_ext(en, ospf_is_v2(p), &rt);
-
- if (rt.metric == LSINFINITY)
- continue;
+ lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), &rt);
- if (rt.pxopts & OPT_PX_NU)
- continue;
-
- if (rt.pxlen < 0 || rt.pxlen > MAX_PREFIX_LENGTH)
+ if (!ospf_valid_prefix(&rt.net))
{
log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
continue;
}
+ if (rt.metric == LSINFINITY)
+ continue;
+
+ if (rt.pxopts & OPT_PX_NU)
+ continue;
/* 16.4. (3) */
/* If there are more areas, we already precomputed preferred ASBR
@@ -1457,8 +1486,8 @@ ospf_ext_spf(struct ospf_proto *p)
if (!atmp)
continue; /* Should not happen */
- rtid = ipa_from_rid(en->lsa.rt);
- nf1 = fib_find(&atmp->rtr, &rtid, MAX_PREFIX_LENGTH);
+ net_addr_ip4 nrid = net_from_rid(en->lsa.rt);
+ nf1 = fib_find(&atmp->rtr, (net_addr *) &nrid);
if (!nf1 || !nf1->n.type)
continue; /* No AS boundary router found */
@@ -1468,7 +1497,7 @@ ospf_ext_spf(struct ospf_proto *p)
/* 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(rt.ip) && (rt.pxlen == 0) &&
+ if ((en->lsa_type == LSA_T_NSSA) && (rt.net.pxlen == 0) &&
(p->areano > 1) && !(rt.propagate && atmp->ac->summary))
continue;
@@ -1480,7 +1509,7 @@ ospf_ext_spf(struct ospf_proto *p)
}
else
{
- nf2 = ospf_fib_route(&p->rtf, rt.fwaddr, MAX_PREFIX_LENGTH);
+ nf2 = ospf_fib_route(&p->rtf, rt.fwaddr);
if (!nf2)
continue;
@@ -1542,7 +1571,7 @@ ospf_ext_spf(struct ospf_proto *p)
nfa.oa = atmp; /* undefined in RFC 2328 */
nfa.en = en; /* store LSA for later (NSSA processing) */
- ri_install_ext(p, rt.ip, rt.pxlen, &nfa);
+ ri_install_ext(p, &rt.net, &nfa);
}
}
@@ -1552,13 +1581,10 @@ ospf_rt_reset(struct ospf_proto *p)
{
struct ospf_area *oa;
struct top_hash_entry *en;
- struct area_net *anet;
- ort *ri;
/* Reset old routing table */
- FIB_WALK(&p->rtf, nftmp)
+ FIB_WALK(&p->rtf, ort, ri)
{
- ri = (ort *) nftmp;
ri->area_net = 0;
ri->keep = 0;
reset_ri(ri);
@@ -1580,9 +1606,8 @@ ospf_rt_reset(struct ospf_proto *p)
WALK_LIST(oa, p->area_list)
{
/* Reset ASBR routing tables */
- FIB_WALK(&oa->rtr, nftmp)
+ FIB_WALK(&oa->rtr, ort, ri)
{
- ri = (ort *) nftmp;
reset_ri(ri);
}
FIB_WALK_END;
@@ -1590,17 +1615,15 @@ ospf_rt_reset(struct ospf_proto *p)
/* Reset condensed area networks */
if (p->areano > 1)
{
- FIB_WALK(&oa->net_fib, nftmp)
+ FIB_WALK(&oa->net_fib, struct area_net, anet)
{
- anet = (struct area_net *) nftmp;
anet->active = 0;
anet->metric = 0;
}
FIB_WALK_END;
- FIB_WALK(&oa->enet_fib, nftmp)
+ FIB_WALK(&oa->enet_fib, struct area_net, anet)
{
- anet = (struct area_net *) nftmp;
anet->active = 0;
anet->metric = 0;
}
@@ -1659,19 +1682,33 @@ ospf_rt_spf(struct ospf_proto *p)
static inline int
-inherit_nexthops(struct mpnh *pn)
+inherit_nexthops(struct nexthop *pn)
{
/* Proper nexthops (with defined GW) or dummy vlink nexthops (without iface) */
return pn && (ipa_nonzero(pn->gw) || !pn->iface);
}
-static struct mpnh *
+static inline ip_addr
+link_lsa_lladdr(struct ospf_proto *p, struct top_hash_entry *en)
+{
+ struct ospf_lsa_link *link_lsa = en->lsa_body;
+ ip6_addr ll = link_lsa->lladdr;
+
+ if (ip6_zero(ll))
+ return IPA_NONE;
+
+ return ospf_is_ip4(p) ? ipa_from_ip4(ospf3_6to4(ll)) : ipa_from_ip6(ll);
+}
+
+static struct nexthop *
calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
- struct top_hash_entry *par, int pos)
+ struct top_hash_entry *par, int pos, uint lif, uint nif)
{
struct ospf_proto *p = oa->po;
- struct mpnh *pn = par->nhs;
- struct ospf_iface *ifa;
+ struct nexthop *pn = par->nhs;
+ struct top_hash_entry *link = NULL;
+ struct ospf_iface *ifa = NULL;
+ ip_addr nh = IPA_NONE;
u32 rid = en->lsa.rt;
/* 16.1.1. The next hop calculation */
@@ -1696,6 +1733,9 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
if (!ifa)
return NULL;
+ if (ospf_is_v3(p) && (ifa->iface_id != lif))
+ log(L_WARN "%s: Inconsistent interface ID %u/%u", p->p.name, ifa->iface_id, lif);
+
return new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight);
}
@@ -1706,14 +1746,44 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
if (!ifa)
return NULL;
+ if (ospf_is_v3(p) && (ifa->iface_id != lif))
+ log(L_WARN "%s: Inconsistent interface ID %u/%u", p->p.name, ifa->iface_id, lif);
+
if (ifa->type == OSPF_IT_VLINK)
return new_nexthop(p, IPA_NONE, NULL, 0);
- struct ospf_neighbor *m = find_neigh(ifa, rid);
- if (!m || (m->state != NEIGHBOR_FULL))
- return NULL;
+ /* FIXME: On physical PtP links we may skip next-hop altogether */
+
+ if (ospf_is_v2(p) || ospf_is_ip6(p))
+ {
+ /*
+ * In this case, next-hop is a source address from neighbor's packets.
+ * That is necessary for OSPFv2 and practical for OSPFv3 (as it works even
+ * if neighbor uses LinkLSASuppression), but does not work with OSPFv3-AF
+ * on IPv4 topology, where src is IPv6 but next-hop should be IPv4.
+ */
+ struct ospf_neighbor *m = find_neigh(ifa, rid);
+ if (!m || (m->state != NEIGHBOR_FULL))
+ return NULL;
+
+ nh = m->ip;
+ }
+ else
+ {
+ /*
+ * Next-hop is taken from lladdr field of Link-LSA, based on Neighbor
+ * Iface ID (nif) field in our Router-LSA, which is just nbr->iface_id.
+ */
+ link = ospf_hash_find(p->gr, ifa->iface_id, nif, rid, LSA_T_LINK);
+ if (!link)
+ return NULL;
+
+ nh = link_lsa_lladdr(p, link);
+ if (ipa_zero(nh))
+ return NULL;
+ }
- return new_nexthop(p, m->ip, ifa->iface, ifa->ecmp_weight);
+ return new_nexthop(p, nh, ifa->iface, ifa->ecmp_weight);
}
/* The third case - bcast or nbma neighbor */
@@ -1740,18 +1810,15 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
* 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);
-
- if (!lhe)
+ link = ospf_hash_find(p->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
+ if (!link)
return NULL;
- struct ospf_lsa_link *llsa = lhe->lsa_body;
-
- if (ip6_zero(llsa->lladdr))
+ nh = link_lsa_lladdr(p, link);
+ if (ipa_zero(nh))
return NULL;
- return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight);
+ return new_nexthop(p, nh, pn->iface, pn->weight);
}
}
@@ -1764,8 +1831,8 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
/* Add LSA into list of candidates in Dijkstra's algorithm */
static void
-add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
- u32 dist, struct ospf_area *oa, int pos)
+add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par,
+ u32 dist, int pos, uint lif, uint nif)
{
struct ospf_proto *p = oa->po;
node *prev, *n;
@@ -1778,9 +1845,9 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
if (en->lsa.age == LSA_MAXAGE)
return;
- if (ospf_is_v3(p) && (en->lsa_type == LSA_T_RT))
+ if (ospf_is_v3(p) && (oa->options & OPT_V6) && (en->lsa_type == LSA_T_RT))
{
- /* In OSPFv3, check V6 flag */
+ /* In OSPFv3 IPv6 unicast, check V6 flag */
struct ospf_lsa_rt *rt = en->lsa_body;
if (!(rt->options & OPT_V6))
return;
@@ -1795,10 +1862,10 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
return;
/* We should check whether there is a reverse link from en to par, */
- if (!link_back(oa, en, par))
+ if (!link_back(oa, en, par, lif, nif))
return;
- struct mpnh *nhs = calc_next_hop(oa, en, par, pos);
+ struct nexthop *nhs = calc_next_hop(oa, en, par, pos, lif, nif);
if (!nhs)
{
log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)",
@@ -1836,7 +1903,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
/* Merge old and new */
int new_reuse = (par->nhs != nhs);
- en->nhs = mpnh_merge(en->nhs, nhs, en->nhs_reuse, new_reuse, p->ecmp, p->nhpool);
+ en->nhs = nexthop_merge(en->nhs, nhs, en->nhs_reuse, new_reuse, p->ecmp, p->nhpool);
en->nhs_reuse = 1;
return;
}
@@ -1855,20 +1922,20 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
prev = NULL;
- if (EMPTY_LIST(*l))
+ if (EMPTY_LIST(oa->cand))
{
- add_head(l, &en->cn);
+ add_head(&oa->cand, &en->cn);
}
else
{
- WALK_LIST(n, *l)
+ WALK_LIST(n, oa->cand)
{
act = SKIP_BACK(struct top_hash_entry, cn, n);
if ((act->dist > dist) ||
((act->dist == dist) && (act->lsa_type == LSA_T_RT)))
{
if (prev == NULL)
- add_head(l, &en->cn);
+ add_head(&oa->cand, &en->cn);
else
insert_node(&en->cn, prev);
added = 1;
@@ -1879,7 +1946,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
if (!added)
{
- add_tail(l, &en->cn);
+ add_tail(&oa->cand, &en->cn);
}
}
}
@@ -1892,8 +1959,7 @@ ort_changed(ort *nf, rta *nr)
(nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) ||
(nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) ||
(nr->source != or->source) || (nr->dest != or->dest) ||
- (nr->iface != or->iface) || !ipa_equal(nr->gw, or->gw) ||
- !mpnh_same(nr->nexthops, or->nexthops);
+ !nexthop_same(&(nr->nh), &(or->nh));
}
static void
@@ -1902,25 +1968,22 @@ rt_sync(struct ospf_proto *p)
struct top_hash_entry *en;
struct fib_iterator fit;
struct fib *fib = &p->rtf;
- ort *nf;
struct ospf_area *oa;
/* This is used for forced reload of routes */
int reload = (p->calcrt == 2);
- OSPF_TRACE(D_EVENTS, "Starting routing table synchronisation");
+ OSPF_TRACE(D_EVENTS, "Starting routing table synchronization");
DBG("Now syncing my rt table with nest's\n");
FIB_ITERATE_INIT(&fit, fib);
again1:
- FIB_ITERATE_START(fib, &fit, nftmp)
+ FIB_ITERATE_START(fib, &fit, ort, nf)
{
- nf = (ort *) nftmp;
-
/* Sanity check of next-hop addresses, failure should not happen */
if (nf->n.type)
{
- struct mpnh *nh;
+ struct nexthop *nh;
for (nh = nf->n.nhs; nh; nh = nh->next)
if (ipa_nonzero(nh->gw))
{
@@ -1943,29 +2006,12 @@ again1:
.src = p->p.main_source,
.source = nf->n.type,
.scope = SCOPE_UNIVERSE,
- .cast = RTC_UNICAST
+ .dest = RTD_UNICAST,
+ .nh = *(nf->n.nhs),
};
- if (nf->n.nhs->next)
- {
- a0.dest = RTD_MULTIPATH;
- a0.nexthops = nf->n.nhs;
- }
- else if (ipa_nonzero(nf->n.nhs->gw))
- {
- a0.dest = RTD_ROUTER;
- a0.iface = nf->n.nhs->iface;
- a0.gw = nf->n.nhs->gw;
- }
- else
- {
- a0.dest = RTD_DEVICE;
- a0.iface = nf->n.nhs->iface;
- }
-
if (reload || ort_changed(nf, &a0))
{
- net *ne = net_get(p->p.table, nf->fn.prefix, nf->fn.pxlen);
rta *a = rta_lookup(&a0);
rte *e = rte_get_temp(a);
@@ -1976,12 +2022,10 @@ again1:
e->u.ospf.tag = nf->old_tag = nf->n.tag;
e->u.ospf.router_id = nf->old_rid = nf->n.rid;
e->pflags = 0;
- e->net = ne;
- 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->p, ne, e);
+ DBG("Mod rte type %d - %N via %I on iface %s, met %d\n",
+ a0.source, nf->fn.addr, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1);
+ rte_update(&p->p, nf->fn.addr, e);
}
}
else if (nf->old_rta)
@@ -1990,19 +2034,21 @@ again1:
rta_free(nf->old_rta);
nf->old_rta = NULL;
- net *ne = net_get(p->p.table, nf->fn.prefix, nf->fn.pxlen);
- rte_update(&p->p, ne, NULL);
+ rte_update(&p->p, nf->fn.addr, NULL);
}
/* Remove unused rt entry, some special entries are persistent */
if (!nf->n.type && !nf->external_rte && !nf->area_net && !nf->keep)
{
- FIB_ITERATE_PUT(&fit, nftmp);
- fib_delete(fib, nftmp);
+ if (nf->lsa_id)
+ idm_free(&p->idm, nf->lsa_id);
+
+ FIB_ITERATE_PUT(&fit);
+ fib_delete(fib, nf);
goto again1;
}
}
- FIB_ITERATE_END(nftmp);
+ FIB_ITERATE_END;
WALK_LIST(oa, p->area_list)
@@ -2010,18 +2056,16 @@ again1:
/* Cleanup ASBR hash tables */
FIB_ITERATE_INIT(&fit, &oa->rtr);
again2:
- FIB_ITERATE_START(&oa->rtr, &fit, nftmp)
+ FIB_ITERATE_START(&oa->rtr, &fit, ort, nf)
{
- nf = (ort *) nftmp;
-
if (!nf->n.type)
{
- FIB_ITERATE_PUT(&fit, nftmp);
- fib_delete(&oa->rtr, nftmp);
+ FIB_ITERATE_PUT(&fit);
+ fib_delete(&oa->rtr, nf);
goto again2;
}
}
- FIB_ITERATE_END(nftmp);
+ FIB_ITERATE_END;
}
/* Cleanup stale LSAs */
diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h
index 73b28375..589d2bc5 100644
--- a/proto/ospf/rt.h
+++ b/proto/ospf/rt.h
@@ -53,7 +53,7 @@ typedef struct orta
struct ospf_area *oa;
struct ospf_area *voa; /* Used when route is replaced in ospf_rt_sum_tr(),
NULL otherwise */
- struct mpnh *nhs; /* Next hops computed during SPF */
+ struct nexthop *nhs; /* Next hops computed during SPF */
struct top_hash_entry *en; /* LSA responsible for this orta */
}
orta;
@@ -78,13 +78,15 @@ typedef struct ort
* 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;
+ u32 lsa_id;
u8 external_rte;
u8 area_net;
u8 keep;
+
+ struct fib_node fn;
}
ort;
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 341eff87..717c8280 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -70,7 +70,7 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3
en->lsa_body = body;
en->lsa = *lsa;
en->init_age = en->lsa.age;
- en->inst_time = now;
+ en->inst_time = current_time();
/*
* We do not set en->mode. It is either default LSA_M_BASIC, or in a special
@@ -128,7 +128,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
en->lsa.sn = lsa->sn + 1;
en->lsa.age = 0;
en->init_age = 0;
- en->inst_time = now;
+ en->inst_time = current_time();
lsa_generate_checksum(&en->lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Advancing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
@@ -160,7 +160,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
en->lsa = *lsa;
en->lsa.age = LSA_MAXAGE;
en->init_age = lsa->age;
- en->inst_time = now;
+ en->inst_time = current_time();
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);
@@ -196,7 +196,7 @@ 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))
+ if (!en->init_age && en->inst_time && (lsa_inst_age(en) < MINLSINTERVAL))
return 0;
/* Handle wrapping sequence number */
@@ -237,7 +237,7 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
en->lsa.sn++;
en->lsa.age = 0;
en->init_age = 0;
- en->inst_time = now;
+ en->inst_time = current_time();
lsa_generate_checksum(&en->lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
@@ -283,8 +283,8 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
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);
+ log(L_ERR "%s: LSA ID collision for %N",
+ p->p.name, lsa->nf->fn.addr);
en = NULL;
goto drop;
@@ -381,7 +381,7 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
en->lsa.sn++;
en->lsa.age = 0;
en->init_age = 0;
- en->inst_time = now;
+ en->inst_time = current_time();
lsa_generate_checksum(&en->lsa, en->lsa_body);
ospf_flood_lsa(p, en, NULL);
}
@@ -476,14 +476,15 @@ void
ospf_update_lsadb(struct ospf_proto *p)
{
struct top_hash_entry *en, *nxt;
- bird_clock_t real_age;
+ btime now_ = current_time();
+ int 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);
+ real_age = en->init_age + (now_ - en->inst_time) TO_S;
if (en->lsa.age == LSA_MAXAGE)
{
@@ -514,14 +515,14 @@ ospf_update_lsadb(struct ospf_proto *p)
}
-static inline u32
-ort_to_lsaid(struct ospf_proto *p UNUSED4 UNUSED6, ort *nf)
+static 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.
+ * prefix has 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
@@ -542,17 +543,21 @@ ort_to_lsaid(struct ospf_proto *p UNUSED4 UNUSED6, ort *nf)
* 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).
+ * result in the input network, so we just allocate a unique ID from ID map
+ * and store it in nf->lsa_id for further reference.
*/
if (ospf_is_v3(p))
- return nf->fn.uid;
+ {
+ if (!nf->lsa_id)
+ nf->lsa_id = idm_alloc(&p->idm);
- u32 id = ipa_to_u32(nf->fn.prefix);
- int pxlen = nf->fn.pxlen;
+ return nf->lsa_id;
+ }
+
+ net_addr_ip4 *net = (void *) nf->fn.addr;
+ u32 id = ip4_to_u32(net->prefix);
+ int pxlen = net->pxlen;
if ((pxlen == 0) || (pxlen == 32))
return id;
@@ -628,12 +633,12 @@ configured_stubnet(struct ospf_area *oa, struct ifa *a)
{
if (sn->summary)
{
- if (ipa_in_net(a->prefix, sn->px.addr, sn->px.len) && (a->pxlen >= sn->px.len))
+ if (net_in_netX(&a->prefix, &sn->prefix))
return 1;
}
else
{
- if (ipa_equal(a->prefix, sn->px.addr) && (a->pxlen == sn->px.len))
+ if (net_equal(&a->prefix, &sn->prefix))
return 1;
}
}
@@ -781,7 +786,8 @@ prepare_rt2_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
(ifa->type == OSPF_IT_PTMP))
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);
+ add_rt2_lsa_link(p, LSART_STUB, ip4_to_u32(net4_prefix(&ifa->addr->prefix)),
+ u32_mkmask(net4_pxlen(&ifa->addr->prefix)), ifa->cost);
i++;
ifa->rt_pos_end = i;
@@ -790,7 +796,8 @@ prepare_rt2_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
struct ospf_stubnet_config *sn;
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++;
+ add_rt2_lsa_link(p, LSART_STUB, ip4_to_u32(net4_prefix(&sn->prefix)),
+ u32_mkmask(net4_pxlen(&sn->prefix)), sn->cost), i++;
struct ospf_lsa_rt *rt = p->lsab;
/* Store number of links in lower half of options */
@@ -907,7 +914,7 @@ prepare_net2_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
ASSERT(p->lsab_used == 0);
net = lsab_alloc(p, sizeof(struct ospf_lsa_net) + 4 * nodes);
- net->optx = u32_mkmask(ifa->addr->pxlen);
+ net->optx = u32_mkmask(ifa->addr->prefix.pxlen);
net->routers[0] = p->router_id;
WALK_LIST(n, ifa->neigh_list)
@@ -999,9 +1006,10 @@ prepare_sum3_net_lsa_body(struct ospf_proto *p, ort *nf, u32 metric)
{
struct ospf_lsa_sum3_net *sum;
- sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) + IPV6_PREFIX_SPACE(nf->fn.pxlen));
+ sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) +
+ IPV6_PREFIX_SPACE(nf->fn.addr->pxlen));
sum->metric = metric;
- put_ipv6_prefix(sum->prefix, nf->fn.prefix, nf->fn.pxlen, 0, 0);
+ ospf3_put_prefix(sum->prefix, nf->fn.addr, 0, 0);
}
static inline void
@@ -1028,7 +1036,7 @@ ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf,
};
if (ospf_is_v2(p))
- prepare_sum2_lsa_body(p, nf->fn.pxlen, metric);
+ prepare_sum2_lsa_body(p, nf->fn.addr->pxlen, metric);
else
prepare_sum3_net_lsa_body(p, nf, metric);
@@ -1036,20 +1044,20 @@ ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf,
}
void
-ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric, u32 options)
+ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 drid, 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 */
+ .id = drid, /* Router ID of ASBR, irrelevant for OSPFv3 */
.opts = oa->options
};
if (ospf_is_v2(p))
prepare_sum2_lsa_body(p, 0, metric);
else
- prepare_sum3_rt_lsa_body(p, lsa.id, metric, options & LSA_OPTIONS_MASK);
+ prepare_sum3_rt_lsa_body(p, drid, metric, options & LSA_OPTIONS_MASK);
ospf_originate_lsa(p, &lsa);
}
@@ -1082,7 +1090,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
{
struct ospf_lsa_ext3 *ext;
int bsize = sizeof(struct ospf_lsa_ext3)
- + IPV6_PREFIX_SPACE(nf->fn.pxlen)
+ + IPV6_PREFIX_SPACE(nf->fn.addr->pxlen)
+ (ipa_nonzero(fwaddr) ? 16 : 0)
+ (tag ? 4 : 0);
@@ -1090,7 +1098,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
ext->metric = metric & LSA_METRIC_MASK;
u32 *buf = ext->rest;
- buf = put_ipv6_prefix(buf, nf->fn.prefix, nf->fn.pxlen, pbit ? OPT_PX_P : 0, 0);
+ buf = ospf3_put_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0);
if (ebit)
ext->metric |= LSA_EXT3_EBIT;
@@ -1098,7 +1106,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
if (ipa_nonzero(fwaddr))
{
ext->metric |= LSA_EXT3_FBIT;
- buf = put_ipv6_addr(buf, fwaddr);
+ buf = ospf3_put_addr(buf, fwaddr);
}
if (tag)
@@ -1140,7 +1148,7 @@ ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 m
};
if (ospf_is_v2(p))
- prepare_ext2_lsa_body(p, nf->fn.pxlen, metric, ebit, fwaddr, tag);
+ prepare_ext2_lsa_body(p, nf->fn.addr->pxlen, metric, ebit, fwaddr, tag);
else
prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit);
@@ -1177,7 +1185,7 @@ use_gw_for_fwaddr(struct ospf_proto *p, ip_addr gw, struct iface *iface)
WALK_LIST(ifa, p->iface_list)
if ((ifa->iface == iface) &&
- (!ospf_is_v2(p) || ipa_in_net(gw, ifa->addr->prefix, ifa->addr->pxlen)))
+ (!ospf_is_v2(p) || ipa_in_netX(gw, &ifa->addr->prefix)))
return 1;
return 0;
@@ -1215,7 +1223,8 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
{
WALK_LIST(a, ifa->iface->addrs)
{
- if ((a->flags & IA_SECONDARY) ||
+ if ((a->prefix.type != ospf_get_af(p)) ||
+ (a->flags & IA_SECONDARY) ||
(a->flags & IA_PEER) ||
(a->scope <= SCOPE_LINK))
continue;
@@ -1234,7 +1243,7 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
}
void
-ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *ea)
+ospf_rt_notify(struct proto *P, struct channel *ch 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 */
@@ -1253,7 +1262,7 @@ ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
if (!new)
{
- nf = (ort *) fib_find(&p->rtf, &n->n.prefix, n->n.pxlen);
+ nf = fib_find(&p->rtf, n->n.addr);
if (!nf || !nf->external_rte)
return;
@@ -1280,8 +1289,8 @@ ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
ip_addr fwd = IPA_NONE;
- if ((a->dest == RTD_ROUTER) && use_gw_for_fwaddr(p, a->gw, a->iface))
- fwd = a->gw;
+ if ((a->dest == RTD_UNICAST) && use_gw_for_fwaddr(p, a->nh.gw, a->nh.iface))
+ fwd = a->nh.gw;
/* NSSA-LSA with P-bit set must have non-zero forwarding address */
if (oa && ipa_zero(fwd))
@@ -1290,13 +1299,13 @@ ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
if (ipa_zero(fwd))
{
- log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %I/%d",
- p->p.name, n->n.prefix, n->n.pxlen);
+ log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %N",
+ p->p.name, n->n.addr);
return;
}
}
- nf = (ort *) fib_get(&p->rtf, &n->n.prefix, n->n.pxlen);
+ nf = fib_get(&p->rtf, n->n.addr);
ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1);
nf->external_rte = 1;
}
@@ -1308,38 +1317,47 @@ ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
*/
static inline void
-lsab_put_prefix(struct ospf_proto *p, ip_addr prefix, u32 pxlen, u32 cost)
+lsab_put_prefix(struct ospf_proto *p, net_addr *n, 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);
+ void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net_pxlen(n)));
+ uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
+ u8 flags = (net_pxlen(n) < max) ? 0 : OPT_PX_LA;
+ ospf3_put_prefix(buf, n, flags, cost);
}
static void
prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
{
- struct ospf_lsa_link *ll;
+ ip_addr nh = ospf_is_ip4(p) ? IPA_NONE : ifa->addr->ip;
int i = 0;
+ /* Preallocating space for header */
ASSERT(p->lsab_used == 0);
- ll = lsab_allocz(p, sizeof(struct ospf_lsa_link));
- ll->options = ifa->oa->options | (ifa->priority << 24);
- ll->lladdr = ipa_to_ip6(ifa->addr->ip);
- ll = NULL; /* buffer might be reallocated later */
+ lsab_allocz(p, sizeof(struct ospf_lsa_link));
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
{
- if ((a->flags & IA_SECONDARY) ||
- (a->scope < SCOPE_SITE))
+ if ((a->prefix.type != ospf_get_af(p)) ||
+ (a->flags & IA_SECONDARY) ||
+ (a->scope <= SCOPE_LINK))
continue;
- lsab_put_prefix(p, a->prefix, a->pxlen, 0);
+ if (ospf_is_ip4(p) && ipa_zero(nh))
+ nh = a->ip;
+
+ lsab_put_prefix(p, &a->prefix, 0);
i++;
}
- ll = p->lsab;
+ /* Filling the preallocated header */
+ struct ospf_lsa_link *ll = p->lsab;
+ ll->options = ifa->oa->options | (ifa->priority << 24);
+ ll->lladdr = ospf_is_ip4(p) ? ospf3_4to6(ipa_to_ip4(nh)) : ipa_to_ip6(nh);
ll->pxcount = i;
+
+ if (ipa_zero(nh))
+ log(L_ERR "%s: Cannot find next hop address for %s", p->p.name, ifa->ifname);
}
static void
@@ -1401,12 +1419,13 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
{
- if ((a->flags & IA_SECONDARY) ||
+ if ((a->prefix.type != ospf_get_af(p)) ||
+ (a->flags & IA_SECONDARY) ||
(a->flags & IA_PEER) ||
(a->scope <= SCOPE_LINK))
continue;
- if (((a->pxlen < MAX_PREFIX_LENGTH) && net_lsa) ||
+ if (((a->prefix.pxlen < IP6_MAX_PREFIX_LENGTH) && net_lsa) ||
configured_stubnet(oa, a))
continue;
@@ -1414,11 +1433,12 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
(ifa->state == OSPF_IS_LOOP) ||
(ifa->type == OSPF_IT_PTMP))
{
- lsab_put_prefix(p, a->ip, MAX_PREFIX_LENGTH, 0);
+ net_addr_ip6 net = NET_ADDR_IP6(a->ip, IP6_MAX_PREFIX_LENGTH);
+ lsab_put_prefix(p, (net_addr *) &net, 0);
host_addr = 1;
}
else
- lsab_put_prefix(p, a->prefix, a->pxlen, ifa->cost);
+ lsab_put_prefix(p, &a->prefix, ifa->cost);
i++;
}
@@ -1429,15 +1449,15 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
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)
+ lsab_put_prefix(p, &sn->prefix, sn->cost);
+ if (sn->prefix.pxlen == IP6_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)
+ if (!EMPTY_LIST(cf->vlink_list) && !host_addr && ospf_is_ip6(p))
{
WALK_LIST(ifa, p->iface_list)
{
@@ -1447,11 +1467,14 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
{
- if ((a->flags & IA_SECONDARY) || (a->scope <= SCOPE_LINK))
+ if ((a->prefix.type != NET_IP6) ||
+ (a->flags & IA_SECONDARY) ||
+ (a->scope <= SCOPE_LINK))
continue;
/* Found some IP */
- lsab_put_prefix(p, a->ip, MAX_PREFIX_LENGTH, 0);
+ net_addr_ip6 net = NET_ADDR_IP6(a->ip, IP6_MAX_PREFIX_LENGTH);
+ lsab_put_prefix(p, (net_addr *) &net, 0);
i++;
goto done;
}
@@ -1557,7 +1580,7 @@ add_link_lsa(struct ospf_proto *p, struct ospf_lsa_link *ll, int offset, int *px
continue;
/* Skip link-local prefixes */
- if ((pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
+ if (ospf_is_ip6(p) && (pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
continue;
add_prefix(p, pxb, offset, pxc);
@@ -1614,7 +1637,7 @@ ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
}
static inline int breaks_minlsinterval(struct top_hash_entry *en)
-{ return en && (en->lsa.age < LSA_MAXAGE) && ((en->inst_time + MINLSINTERVAL) > now); }
+{ return en && (en->lsa.age < LSA_MAXAGE) && (lsa_inst_age(en) < MINLSINTERVAL); }
void
ospf_update_topology(struct ospf_proto *p)
@@ -1748,7 +1771,7 @@ ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
* and request lists of OSPF neighbors.
*/
struct top_graph *
-ospf_top_new(struct ospf_proto *p UNUSED4 UNUSED6, pool *pool)
+ospf_top_new(struct ospf_proto *p, pool *pool)
{
struct top_graph *f;
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index 5652ced0..ac87334b 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.h
@@ -26,9 +26,9 @@ struct top_hash_entry
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 */
+ btime inst_time; /* Time of installation into DB */
struct ort *nf; /* Reference fibnode for sum and ext LSAs, NULL for otherwise */
- struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
+ struct nexthop *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 */
u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
u32 dist; /* Distance from the root */
@@ -185,10 +185,10 @@ static inline void ospf_flush2_lsa(struct ospf_proto *p, struct top_hash_entry *
{ 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_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 drid, 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_rt_notify(struct proto *P, struct channel *ch, 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);