summaryrefslogtreecommitdiff
path: root/proto/ospf
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf')
-rw-r--r--proto/ospf/config.Y7
-rw-r--r--proto/ospf/iface.c25
-rw-r--r--proto/ospf/neighbor.c2
-rw-r--r--proto/ospf/ospf.c124
-rw-r--r--proto/ospf/ospf.h11
-rw-r--r--proto/ospf/rt.c233
-rw-r--r--proto/ospf/rt.h6
-rw-r--r--proto/ospf/topology.c27
-rw-r--r--proto/ospf/topology.h6
9 files changed, 224 insertions, 217 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 4b7d5a36..bc3df8db 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -190,7 +190,7 @@ ospf_check_auth(void)
CF_DECLS
-CF_KEYWORDS(OSPF, V2, V3, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
+CF_KEYWORDS(OSPF, V2, V3)
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)
@@ -505,11 +505,6 @@ ospf_iface:
ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
;
-dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC1); } ;
-dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC2); } ;
-dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_TAG); } ;
-dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_OSPF_ROUTER_ID); } ;
-
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
CF_CLI(SHOW OSPF, optproto, [<name>], [[Show information about OSPF protocol]])
{ PROTO_WALK_CMD($3, &proto_ospf, p) ospf_sh(p); };
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 87e3d95e..0aa7fa00 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -136,7 +136,7 @@ ospf_sk_open(struct ospf_iface *ifa)
sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0);
sk->ttl = ifa->cf->ttl_security ? 255 : 1;
- if (sk_open(sk) < 0)
+ if (sk_open(sk, p->p.loop) < 0)
goto err;
/* 12 is an offset of the checksum in an OSPFv3 packet */
@@ -220,7 +220,7 @@ ospf_open_vlink_sk(struct ospf_proto *p)
sk->data = (void *) p;
sk->flags = 0;
- if (sk_open(sk) < 0)
+ if (sk_open(sk, p->p.loop) < 0)
goto err;
/* 12 is an offset of the checksum in an OSPFv3 packet */
@@ -484,9 +484,9 @@ ospf_iface_find(struct ospf_proto *p, struct iface *what)
}
static void
-ospf_iface_add(struct object_lock *lock)
+ospf_iface_add(void *_ifa)
{
- struct ospf_iface *ifa = lock->data;
+ struct ospf_iface *ifa = _ifa;
struct ospf_proto *p = ifa->oa->po;
/* Open socket if interface is not stub */
@@ -668,8 +668,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
lock->port = OSPF_PROTO;
lock->inst = ifa->instance_id;
lock->iface = iface;
- lock->data = ifa;
- lock->hook = ospf_iface_add;
+ lock->event = (event) {
+ .hook = ospf_iface_add,
+ .data = ifa,
+ };
+ lock->target = &global_event_list;
olock_acquire(lock);
}
@@ -1222,12 +1225,11 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
static void
ospf_reconfigure_ifaces2(struct ospf_proto *p)
{
- struct iface *iface;
struct ifa *a;
- WALK_LIST(iface, iface_list)
+ IFACE_WALK(iface)
{
- if (p->p.vrf_set && p->p.vrf != iface->master)
+ if (p->p.vrf && p->p.vrf != iface->master)
continue;
if (! (iface->flags & IF_UP))
@@ -1271,12 +1273,11 @@ ospf_reconfigure_ifaces2(struct ospf_proto *p)
static void
ospf_reconfigure_ifaces3(struct ospf_proto *p)
{
- struct iface *iface;
struct ifa *a;
- WALK_LIST(iface, iface_list)
+ IFACE_WALK(iface)
{
- if (p->p.vrf_set && p->p.vrf != iface->master)
+ if (p->p.vrf && p->p.vrf != iface->master)
continue;
if (! (iface->flags & IF_UP))
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index ca369819..b0fdc42f 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -777,7 +777,7 @@ ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd)
if (use_bfd && !n->bfd_req)
n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip,
n->ifa->iface, p->p.vrf,
- ospf_neigh_bfd_hook, n, NULL);
+ ospf_neigh_bfd_hook, n, p->p.loop, NULL);
if (!use_bfd && n->bfd_req)
{
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index ad4b2d14..896bf5a3 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -106,11 +106,12 @@
#include <stdlib.h>
#include "ospf.h"
+#include "lib/macro.h"
-static int ospf_preexport(struct channel *P, rte *new);
+static int ospf_preexport(struct channel *C, rte *new);
static void ospf_reload_routes(struct channel *C);
-static int ospf_rte_better(struct rte *new, struct rte *old);
-static u32 ospf_rte_igp_metric(struct rte *rt);
+static int ospf_rte_better(const rte *new, const rte *old);
+static u32 ospf_rte_igp_metric(const rte *rt);
static void ospf_disp(timer *timer);
@@ -370,39 +371,42 @@ ospf_init(struct proto_config *CF)
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
P->rt_notify = ospf_rt_notify;
- P->if_notify = ospf_if_notify;
- P->ifa_notify = cf->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
+ P->iface_sub.if_notify = ospf_if_notify;
+ P->iface_sub.ifa_notify = cf->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
P->preexport = ospf_preexport;
P->reload_routes = ospf_reload_routes;
P->feed_begin = ospf_feed_begin;
P->feed_end = ospf_feed_end;
- P->rte_better = ospf_rte_better;
- P->rte_igp_metric = ospf_rte_igp_metric;
+
+ P->sources.class = &ospf_rte_owner_class;
return P;
}
/* If new is better return 1 */
static int
-ospf_rte_better(struct rte *new, struct rte *old)
+ospf_rte_better(const rte *new, const rte *old)
{
- u32 new_metric1 = ea_get_int(new->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
+ u32 new_metric1 = ea_get_int(new->attrs, &ea_ospf_metric1, LSINFINITY);
if (new_metric1 == LSINFINITY)
return 0;
- if(new->attrs->source < old->attrs->source) return 1;
- if(new->attrs->source > old->attrs->source) return 0;
+ u32 ns = rt_get_source_attr(new);
+ u32 os = rt_get_source_attr(old);
+
+ if (ns < os) return 1;
+ if (ns > os) return 0;
- if(new->attrs->source == RTS_OSPF_EXT2)
+ if (ns == RTS_OSPF_EXT2)
{
- u32 old_metric2 = ea_get_int(old->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY);
- u32 new_metric2 = ea_get_int(new->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY);
- if(new_metric2 < old_metric2) return 1;
- if(new_metric2 > old_metric2) return 0;
+ u32 old_metric2 = ea_get_int(old->attrs, &ea_ospf_metric2, LSINFINITY);
+ u32 new_metric2 = ea_get_int(new->attrs, &ea_ospf_metric2, LSINFINITY);
+ if (new_metric2 < old_metric2) return 1;
+ if (new_metric2 > old_metric2) return 0;
}
- u32 old_metric1 = ea_get_int(old->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
+ u32 old_metric1 = ea_get_int(old->attrs, &ea_ospf_metric1, LSINFINITY);
if (new_metric1 < old_metric1)
return 1;
@@ -410,12 +414,12 @@ ospf_rte_better(struct rte *new, struct rte *old)
}
static u32
-ospf_rte_igp_metric(struct rte *rt)
+ospf_rte_igp_metric(const rte *rt)
{
- if (rt->attrs->source == RTS_OSPF_EXT2)
+ if (rt_get_source_attr(rt) == RTS_OSPF_EXT2)
return IGP_METRIC_UNKNOWN;
- return ea_get_int(rt->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
+ return ea_get_int(rt->attrs, &ea_ospf_metric1, LSINFINITY);
}
void
@@ -488,7 +492,7 @@ ospf_preexport(struct channel *C, rte *e)
struct ospf_area *oa = ospf_main_area(p);
/* Reject our own routes */
- if (e->src->proto == &p->p)
+ if (e->sender == C->in_req.hook)
return -1;
/* Do not export routes to stub areas */
@@ -531,7 +535,7 @@ ospf_shutdown(struct proto *P)
/* Cleanup locked rta entries */
FIB_WALK(&p->rtf, ort, nf)
{
- rta_free(nf->old_rta);
+ ea_free(nf->old_ea);
}
FIB_WALK_END;
@@ -566,11 +570,12 @@ ospf_get_status(struct proto *P, byte * buf)
}
static void
-ospf_get_route_info(rte * rte, byte * buf)
+ospf_get_route_info(const rte * rte, byte * buf)
{
char *type = "<bug>";
- switch (rte->attrs->source)
+ uint source = rt_get_source_attr(rte);
+ switch (source)
{
case RTS_OSPF:
type = "I";
@@ -587,42 +592,26 @@ ospf_get_route_info(rte * rte, byte * buf)
}
buf += bsprintf(buf, " %s", type);
- buf += bsprintf(buf, " (%d/%d", rte->attrs->pref, ea_get_int(rte->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY));
- if (rte->attrs->source == RTS_OSPF_EXT2)
- buf += bsprintf(buf, "/%d", ea_get_int(rte->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY));
+ buf += bsprintf(buf, " (%d/%d", rt_get_preference(rte), ea_get_int(rte->attrs, &ea_ospf_metric1, LSINFINITY));
+ if (source == RTS_OSPF_EXT2)
+ buf += bsprintf(buf, "/%d", ea_get_int(rte->attrs, &ea_ospf_metric2, LSINFINITY));
buf += bsprintf(buf, ")");
- if (rte->attrs->source == RTS_OSPF_EXT1 || rte->attrs->source == RTS_OSPF_EXT2)
+ if (source == RTS_OSPF_EXT1 || source == RTS_OSPF_EXT2)
{
- eattr *ea = ea_find(rte->attrs->eattrs, EA_OSPF_TAG);
+ eattr *ea = ea_find(rte->attrs, &ea_ospf_tag);
if (ea && (ea->u.data > 0))
buf += bsprintf(buf, " [%x]", ea->u.data);
}
- eattr *ea = ea_find(rte->attrs->eattrs, EA_OSPF_ROUTER_ID);
+ eattr *ea = ea_find(rte->attrs, &ea_ospf_router_id);
if (ea)
buf += bsprintf(buf, " [%R]", ea->u.data);
}
-static int
-ospf_get_attr(const eattr * a, byte * buf, int buflen UNUSED)
+static void
+ospf_tag_format(const eattr * a, byte * buf, uint buflen)
{
- switch (a->id)
- {
- case EA_OSPF_METRIC1:
- bsprintf(buf, "metric1");
- return GA_NAME;
- case EA_OSPF_METRIC2:
- bsprintf(buf, "metric2");
- return GA_NAME;
- case EA_OSPF_TAG:
- bsprintf(buf, "tag: 0x%08x", a->u.data);
- return GA_FULL;
- case EA_OSPF_ROUTER_ID:
- bsprintf(buf, "router_id");
- return GA_NAME;
- default:
- return GA_UNKNOWN;
- }
+ bsnprintf(buf, buflen, "0x%08x", a->u.data);
}
static void
@@ -1517,10 +1506,15 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
}
+struct rte_owner_class ospf_rte_owner_class = {
+ .get_route_info = ospf_get_route_info,
+ .rte_better = ospf_rte_better,
+ .rte_igp_metric = ospf_rte_igp_metric,
+};
+
struct protocol proto_ospf = {
.name = "OSPF",
.template = "ospf%d",
- .class = PROTOCOL_OSPF,
.preference = DEF_PREF_OSPF,
.channel_mask = NB_IP,
.proto_size = sizeof(struct ospf_proto),
@@ -1531,12 +1525,38 @@ struct protocol proto_ospf = {
.shutdown = ospf_shutdown,
.reconfigure = ospf_reconfigure,
.get_status = ospf_get_status,
- .get_attr = ospf_get_attr,
- .get_route_info = ospf_get_route_info
+};
+
+struct ea_class ea_ospf_metric1 = {
+ .name = "ospf_metric1",
+ .type = T_INT,
+};
+
+struct ea_class ea_ospf_metric2 = {
+ .name = "ospf_metric2",
+ .type = T_INT,
+};
+
+struct ea_class ea_ospf_tag = {
+ .name = "ospf_tag",
+ .type = T_INT,
+ .format = ospf_tag_format,
+};
+
+struct ea_class ea_ospf_router_id = {
+ .name = "ospf_router_id",
+ .type = T_QUAD,
};
void
ospf_build(void)
{
proto_build(&proto_ospf);
+
+ EA_REGISTER_ALL(
+ &ea_ospf_metric1,
+ &ea_ospf_metric2,
+ &ea_ospf_tag,
+ &ea_ospf_router_id
+ );
}
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 3e704ae8..3477ba5a 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -22,7 +22,7 @@
#include "lib/resource.h"
#include "nest/protocol.h"
#include "nest/iface.h"
-#include "nest/route.h"
+#include "nest/rt.h"
#include "nest/cli.h"
#include "nest/locks.h"
#include "nest/bfd.h"
@@ -939,12 +939,7 @@ struct lsadb_show_data {
u32 router; /* Advertising router, 0 -> all */
};
-
-#define EA_OSPF_METRIC1 EA_CODE(PROTOCOL_OSPF, 0)
-#define EA_OSPF_METRIC2 EA_CODE(PROTOCOL_OSPF, 1)
-#define EA_OSPF_TAG EA_CODE(PROTOCOL_OSPF, 2)
-#define EA_OSPF_ROUTER_ID EA_CODE(PROTOCOL_OSPF, 3)
-
+extern struct ea_class ea_ospf_metric1, ea_ospf_metric2, ea_ospf_tag, ea_ospf_router_id;
/*
* For regular networks, neighbor address must match network prefix.
@@ -1007,6 +1002,8 @@ void ospf_sh_state(struct proto *P, int verbose, int reachable);
void ospf_sh_lsadb(struct lsadb_show_data *ld);
+extern struct rte_owner_class ospf_rte_owner_class;
+
/* iface.c */
void ospf_iface_chstate(struct ospf_iface *ifa, u8 state);
void ospf_iface_sm(struct ospf_iface *ifa, int event);
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 471bb586..69c2907d 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -28,24 +28,30 @@ nh_is_vlink(struct nexthop *nhs)
static inline int
unresolved_vlink(ort *ort)
{
- return ort->n.nhs && nh_is_vlink(ort->n.nhs);
+ return ort->n.nhs && nh_is_vlink(&ort->n.nhs->nh);
}
-static inline struct nexthop *
+static inline struct nexthop_adata *
new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight)
{
- struct nexthop *nh = lp_allocz(p->nhpool, sizeof(struct nexthop));
- nh->gw = gw;
- nh->iface = iface;
- nh->weight = weight;
- return nh;
+ struct nexthop_adata *nhad = lp_alloc(p->nhpool, sizeof(struct nexthop_adata));
+ *nhad = (struct nexthop_adata) {
+ .ad = { .length = sizeof *nhad - sizeof nhad->ad, },
+ .nh = {
+ .gw = gw,
+ .iface = iface,
+ .weight = weight,
+ },
+ };
+
+ return nhad;
}
/* Returns true if there are device nexthops in n */
static inline int
-has_device_nexthops(const struct nexthop *n)
+has_device_nexthops(struct nexthop_adata *nhad)
{
- for (; n; n = n->next)
+ NEXTHOP_WALK(n, nhad)
if (ipa_zero(n->gw))
return 1;
@@ -53,38 +59,22 @@ has_device_nexthops(const struct nexthop *n)
}
/* Replace device nexthops with nexthops to gw */
-static struct nexthop *
-fix_device_nexthops(struct ospf_proto *p, const struct nexthop *n, ip_addr gw)
+static struct nexthop_adata *
+fix_device_nexthops(struct ospf_proto *p, struct nexthop_adata *old, ip_addr gw)
{
- 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);
-
- /* This is a bit tricky. We cannot just copy the list and update n->gw,
- because the list should stay sorted, so we create two lists, one with new
- gateways and one with old ones, and then merge them. */
-
- for (; n; n = n->next)
{
- struct nexthop *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight);
+ struct nexthop_adata *new = (struct nexthop_adata *) lp_store_adata(p->nhpool, old->ad.data, old->ad.length);
+ new->nh.gw = gw;
+ return new;
+ }
+ struct nexthop_adata *tmp = (struct nexthop_adata *) tmp_copy_adata(&old->ad);
+ NEXTHOP_WALK(n, tmp)
if (ipa_zero(n->gw))
- {
- *nn1 = nn;
- nn1 = &(nn->next);
- }
- else
- {
- *nn2 = nn;
- nn2 = &(nn->next);
- }
- }
+ n->gw = gw;
- return nexthop_merge(root1, root2, 1, 1, p->ecmp, p->nhpool);
+ return nexthop_sort(tmp, p->nhpool);
}
@@ -169,9 +159,9 @@ orta_compare(const struct ospf_proto *p, const orta *new, const orta *old)
return -1;
if (!new->nhs)
return 1;
- if (nh_is_vlink(new->nhs))
+ if (nh_is_vlink(&new->nhs->nh))
return -1;
- if (nh_is_vlink(old->nhs))
+ if (nh_is_vlink(&old->nhs->nh))
return 1;
@@ -279,11 +269,7 @@ ort_merge(struct ospf_proto *p, ort *o, const orta *new)
orta *old = &o->n;
if (old->nhs != new->nhs)
- {
- old->nhs = nexthop_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
- p->ecmp, p->nhpool);
- old->nhs_reuse = 1;
- }
+ old->nhs = nexthop_merge(old->nhs, new->nhs, p->ecmp, p->nhpool);
if (old->rid < new->rid)
old->rid = new->rid;
@@ -295,11 +281,7 @@ ort_merge_ext(struct ospf_proto *p, ort *o, const orta *new)
orta *old = &o->n;
if (old->nhs != new->nhs)
- {
- old->nhs = nexthop_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
- p->ecmp, p->nhpool);
- old->nhs_reuse = 1;
- }
+ old->nhs = nexthop_merge(old->nhs, new->nhs, p->ecmp, p->nhpool);
if (old->tag != new->tag)
old->tag = 0;
@@ -1165,7 +1147,7 @@ ospf_check_vlinks(struct ospf_proto *p)
if (tmp && (tmp->color == INSPF) && ipa_nonzero(tmp->lb) && tmp->nhs)
{
- struct ospf_iface *nhi = ospf_iface_find(p, tmp->nhs->iface);
+ struct ospf_iface *nhi = ospf_iface_find(p, tmp->nhs->nh.iface);
if ((ifa->state != OSPF_IS_PTP)
|| (ifa->vifa != nhi)
@@ -1579,10 +1561,7 @@ ospf_ext_spf(struct ospf_proto *p)
/* Replace device nexthops with nexthops to forwarding address from LSA */
if (has_device_nexthops(nfa.nhs))
- {
nfa.nhs = fix_device_nexthops(p, nfa.nhs, rt.fwaddr);
- nfa.nhs_reuse = 1;
- }
}
if (rt.ebit)
@@ -1726,10 +1705,10 @@ ospf_rt_spf(struct ospf_proto *p)
static inline int
-inherit_nexthops(struct nexthop *pn)
+inherit_nexthops(struct nexthop_adata *pn)
{
/* Proper nexthops (with defined GW) or dummy vlink nexthops (without iface) */
- return pn && (ipa_nonzero(pn->gw) || !pn->iface);
+ return pn && (ipa_nonzero(pn->nh.gw) || !pn->nh.iface);
}
static inline ip_addr
@@ -1744,12 +1723,12 @@ link_lsa_lladdr(struct ospf_proto *p, struct top_hash_entry *en)
return ospf_is_ip4(p) ? ipa_from_ip4(ospf3_6to4(ll)) : ipa_from_ip6(ll);
}
-static struct nexthop *
+static struct nexthop_adata *
calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
struct top_hash_entry *par, int pos, uint data, uint lif, uint nif)
{
struct ospf_proto *p = oa->po;
- struct nexthop *pn = par->nhs;
+ struct nexthop_adata *pn = par->nhs;
struct top_hash_entry *link = NULL;
struct ospf_iface *ifa = NULL;
ip_addr nh = IPA_NONE;
@@ -1827,10 +1806,10 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
return NULL;
}
- struct nexthop *nhs = new_nexthop(p, nh, ifa->iface, ifa->ecmp_weight);
+ struct nexthop_adata *nhs = new_nexthop(p, nh, ifa->iface, ifa->ecmp_weight);
if (ifa->addr->flags & IA_HOST)
- nhs->flags = RNF_ONLINK;
+ nhs->nh.flags = RNF_ONLINK;
return nhs;
}
@@ -1851,7 +1830,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
if (ipa_zero(en->lb))
goto bad;
- return new_nexthop(p, en->lb, pn->iface, pn->weight);
+ return new_nexthop(p, en->lb, pn->nh.iface, pn->nh.weight);
}
else /* OSPFv3 */
{
@@ -1859,7 +1838,7 @@ 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().
*/
- link = ospf_hash_find(p->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
+ link = ospf_hash_find(p->gr, pn->nh.iface->index, en->lb_id, rid, LSA_T_LINK);
if (!link)
return NULL;
@@ -1867,7 +1846,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
if (ipa_zero(nh))
return NULL;
- return new_nexthop(p, nh, pn->iface, pn->weight);
+ return new_nexthop(p, nh, pn->nh.iface, pn->nh.weight);
}
}
@@ -1914,7 +1893,7 @@ add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
if (!link_back(oa, en, par, lif, nif))
return;
- struct nexthop *nhs = calc_next_hop(oa, en, par, pos, data, lif, nif);
+ struct nexthop_adata *nhs = calc_next_hop(oa, en, par, pos, data, lif, nif);
if (!nhs)
{
log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)",
@@ -1923,7 +1902,7 @@ add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
}
/* If en->dist > 0, we know that en->color == CANDIDATE and en->nhs is defined. */
- if ((dist == en->dist) && !nh_is_vlink(en->nhs))
+ if ((dist == en->dist) && !nh_is_vlink(&en->nhs->nh))
{
/*
* For multipath, we should merge nexthops. We merge regular nexthops only.
@@ -1947,13 +1926,11 @@ add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
*/
/* Keep old ones */
- if (!p->ecmp || nh_is_vlink(nhs) || (nhs == en->nhs))
+ if (!p->ecmp || nh_is_vlink(&nhs->nh) || (nhs == en->nhs))
return;
/* Merge old and new */
- int new_reuse = (par->nhs != nhs);
- en->nhs = nexthop_merge(en->nhs, nhs, en->nhs_reuse, new_reuse, p->ecmp, p->nhpool);
- en->nhs_reuse = 1;
+ en->nhs = nexthop_merge(en->nhs, nhs, p->ecmp, p->nhpool);
return;
}
@@ -1967,7 +1944,6 @@ add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
en->nhs = nhs;
en->dist = dist;
en->color = CANDIDATE;
- en->nhs_reuse = (par->nhs != nhs);
prev = NULL;
@@ -2001,14 +1977,34 @@ add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
}
static inline int
-ort_changed(ort *nf, rta *nr)
+ort_changed(ort *nf, ea_list *nr)
{
- rta *or = nf->old_rta;
- return !or ||
+ ea_list *or = nf->old_ea;
+
+ if (!or ||
(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) ||
- !nexthop_same(&(nr->nh), &(or->nh));
+ (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid))
+ return 1;
+
+ eattr *nhea_n = ea_find(nr, &ea_gen_nexthop);
+ eattr *nhea_o = ea_find(or, &ea_gen_nexthop);
+ if (!nhea_n != !nhea_o)
+ return 1;
+
+ if (nhea_n && nhea_o)
+ {
+ struct nexthop_adata *nhad_n = (struct nexthop_adata *) nhea_n->u.ptr;
+ struct nexthop_adata *nhad_o = (struct nexthop_adata *) nhea_o->u.ptr;
+
+ if (!nexthop_same(nhad_n, nhad_o))
+ return 1;
+ }
+
+ if ( ea_get_int(nr, &ea_gen_source, 0)
+ != ea_get_int(or, &ea_gen_source, 0))
+ return 1;
+
+ return 0;
}
static void
@@ -2030,10 +2026,9 @@ again1:
FIB_ITERATE_START(fib, &fit, ort, nf)
{
/* Sanity check of next-hop addresses, failure should not happen */
- if (nf->n.type)
+ if (nf->n.type && nf->n.nhs)
{
- struct nexthop *nh;
- for (nh = nf->n.nhs; nh; nh = nh->next)
+ NEXTHOP_WALK(nh, nf->n.nhs)
if (ipa_nonzero(nh->gw))
{
neighbor *nbr = neigh_find(&p->p, nh->gw, nh->iface,
@@ -2052,68 +2047,69 @@ again1:
if (nf->n.type) /* Add the route */
{
- rta a0 = {
- .source = nf->n.type,
- .scope = SCOPE_UNIVERSE,
- .dest = RTD_UNICAST,
- .nh = *(nf->n.nhs),
- .pref = p->p.main_channel->preference,
- };
-
- if (reload || ort_changed(nf, &a0))
- {
- a0.eattrs = alloca(sizeof(ea_list) + 4 * sizeof(eattr));
- memset(a0.eattrs, 0, sizeof(ea_list));
+ struct {
+ ea_list l;
+ eattr a[7];
+ } eattrs;
+
+ eattrs.l = (ea_list) {};
+
+ eattrs.a[eattrs.l.count++] =
+ EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, p->p.main_channel->preference);
+ eattrs.a[eattrs.l.count++] =
+ EA_LITERAL_EMBEDDED(&ea_gen_source, 0, nf->n.type);
+
+ eattrs.a[eattrs.l.count++] =
+ EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, &nf->n.nhs->ad);
+
+ if (reload || ort_changed(nf, &eattrs.l))
+ {
nf->old_metric1 = nf->n.metric1;
nf->old_metric2 = nf->n.metric2;
nf->old_tag = nf->n.tag;
nf->old_rid = nf->n.rid;
- a0.eattrs->attrs[a0.eattrs->count++] = (eattr) {
- .id = EA_OSPF_METRIC1,
- .type = EAF_TYPE_INT,
- .u.data = nf->n.metric1,
- };
+ eattrs.a[eattrs.l.count++] =
+ EA_LITERAL_EMBEDDED(&ea_ospf_metric1, 0, nf->n.metric1);
if (nf->n.type == RTS_OSPF_EXT2)
- a0.eattrs->attrs[a0.eattrs->count++] = (eattr) {
- .id = EA_OSPF_METRIC2,
- .type = EAF_TYPE_INT,
- .u.data = nf->n.metric2,
- };
+ eattrs.a[eattrs.l.count++] =
+ EA_LITERAL_EMBEDDED(&ea_ospf_metric2, 0, nf->n.metric2);
if ((nf->n.type == RTS_OSPF_EXT1) || (nf->n.type == RTS_OSPF_EXT2))
- a0.eattrs->attrs[a0.eattrs->count++] = (eattr) {
- .id = EA_OSPF_TAG,
- .type = EAF_TYPE_INT,
- .u.data = nf->n.tag,
- };
-
- a0.eattrs->attrs[a0.eattrs->count++] = (eattr) {
- .id = EA_OSPF_ROUTER_ID,
- .type = EAF_TYPE_ROUTER_ID,
- .u.data = nf->n.rid,
- };
+ eattrs.a[eattrs.l.count++] =
+ EA_LITERAL_EMBEDDED(&ea_ospf_tag, 0, nf->n.tag);
+
+ eattrs.a[eattrs.l.count++] =
+ EA_LITERAL_EMBEDDED(&ea_ospf_router_id, 0, nf->n.rid);
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a, p->p.main_source);
+ ASSERT_DIE(ARRAY_SIZE(eattrs.a) >= eattrs.l.count);
- rta_free(nf->old_rta);
- nf->old_rta = rta_clone(a);
+ ea_list *eal = ea_lookup(&eattrs.l, 0);
+ ea_free(nf->old_ea);
+ nf->old_ea = eal;
+ rte e0 = {
+ .attrs = eal,
+ .src = p->p.main_source,
+ };
+
+ /*
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);
+ */
+
+ rte_update(p->p.main_channel, nf->fn.addr, &e0, p->p.main_source);
}
}
- else if (nf->old_rta)
+ else if (nf->old_ea)
{
/* Remove the route */
- rta_free(nf->old_rta);
- nf->old_rta = NULL;
+ rta_free(nf->old_ea);
+ nf->old_ea = NULL;
- rte_update(&p->p, nf->fn.addr, NULL);
+ rte_update(p->p.main_channel, nf->fn.addr, NULL, p->p.main_source);
}
/* Remove unused rt entry, some special entries are persistent */
@@ -2129,7 +2125,6 @@ again1:
}
FIB_ITERATE_END;
-
WALK_LIST(oa, p->area_list)
{
/* Cleanup ASBR hash tables */
diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h
index 094e125b..88eefef9 100644
--- a/proto/ospf/rt.h
+++ b/proto/ospf/rt.h
@@ -18,8 +18,6 @@
typedef struct orta
{
u8 type; /* RTS_OSPF_* */
- u8 nhs_reuse; /* Whether nhs nodes can be reused during merging.
- See a note in rt.c:add_cand() */
u32 options;
/*
* For ORT_ROUTER routes, options field are router-LSA style
@@ -53,7 +51,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 nexthop *nhs; /* Next hops computed during SPF */
+ struct nexthop_adata *nhs; /* Next hops computed during SPF */
struct top_hash_entry *en; /* LSA responsible for this orta */
}
orta;
@@ -80,7 +78,7 @@ typedef struct ort
*/
orta n;
u32 old_metric1, old_metric2, old_tag, old_rid;
- rta *old_rta;
+ ea_list *old_ea;
u32 lsa_id;
u8 external_rte;
u8 area_net;
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 9fe68264..85bce03d 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -1300,7 +1300,7 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
}
void
-ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED)
+ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rte *new, const rte *old UNUSED)
{
struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_area *oa = NULL; /* non-NULL for NSSA-LSA */
@@ -1319,7 +1319,7 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
if (!new)
{
- nf = fib_find(&p->rtf, n->n.addr);
+ nf = fib_find(&p->rtf, n);
if (!nf || !nf->external_rte)
return;
@@ -1337,23 +1337,23 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
ASSERT(p->asbr);
/* Get route attributes */
- rta *a = new->attrs;
- eattr *m1a = ea_find(a->eattrs, EA_OSPF_METRIC1);
- eattr *m2a = ea_find(a->eattrs, EA_OSPF_METRIC2);
+ ea_list *a = new->attrs;
+ eattr *m1a = ea_find(a, &ea_ospf_metric1);
+ eattr *m2a = ea_find(a, &ea_ospf_metric2);
uint m1 = m1a ? m1a->u.data : 0;
uint m2 = m2a ? m2a->u.data : 10000;
if (m1 > LSINFINITY)
{
log(L_WARN "%s: Invalid ospf_metric1 value %u for route %N",
- p->p.name, m1, n->n.addr);
+ p->p.name, m1, n);
m1 = LSINFINITY;
}
if (m2 > LSINFINITY)
{
log(L_WARN "%s: Invalid ospf_metric2 value %u for route %N",
- p->p.name, m2, n->n.addr);
+ p->p.name, m2, n);
m2 = LSINFINITY;
}
@@ -1363,11 +1363,14 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
uint ebit = m2a || !m1a;
uint metric = ebit ? m2 : m1;
- uint tag = ea_get_int(a->eattrs, EA_OSPF_TAG, 0);
+ uint tag = ea_get_int(a, &ea_ospf_tag, 0);
ip_addr fwd = IPA_NONE;
- if ((a->dest == RTD_UNICAST) && use_gw_for_fwaddr(p, a->nh.gw, a->nh.iface))
- fwd = a->nh.gw;
+ eattr *nhea = ea_find(a, &ea_gen_nexthop);
+ struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
+ if (NEXTHOP_IS_REACHABLE(nhad))
+ if (use_gw_for_fwaddr(p, nhad->nh.gw, nhad->nh.iface))
+ fwd = nhad->nh.gw;
/* NSSA-LSA with P-bit set must have non-zero forwarding address */
if (oa && ipa_zero(fwd))
@@ -1377,12 +1380,12 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
if (ipa_zero(fwd))
{
log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %N",
- p->p.name, n->n.addr);
+ p->p.name, n);
return;
}
}
- nf = fib_get(&p->rtf, n->n.addr);
+ nf = fib_get(&p->rtf, n);
ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1, p->vpn_pe);
nf->external_rte = 1;
}
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index 535d1f1b..3c92b431 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.h
@@ -28,7 +28,7 @@ struct top_hash_entry
u16 next_lsa_opts; /* For postponed LSA origination */
btime inst_time; /* Time of installation into DB */
struct ort *nf; /* Reference fibnode for sum and ext LSAs, NULL for otherwise */
- struct nexthop *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
+ struct nexthop_adata *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 */
@@ -39,8 +39,6 @@ struct top_hash_entry
#define CANDIDATE 1
#define INSPF 2
u8 mode; /* LSA generated during RT calculation (LSA_RTCALC or LSA_STALE)*/
- u8 nhs_reuse; /* Whether nhs nodes can be reused during merging.
- See a note in rt.c:add_cand() */
};
@@ -200,7 +198,7 @@ void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 d
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, int dn);
void ospf_originate_gr_lsa(struct ospf_proto *p, struct ospf_iface *ifa);
-void ospf_rt_notify(struct proto *P, struct channel *ch, net *n, rte *new, rte *old);
+void ospf_rt_notify(struct proto *P, struct channel *ch, const net_addr *n, rte *new, const rte *old);
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);