summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2015-11-22 13:09:11 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2015-11-22 13:09:11 +0000
commit133a1308b1d2e18611a184d0b42336639cadb06d (patch)
tree4b3c0b7c15cddafdc92075e137627d95655a1893 /usr.sbin
parent7ced6c1796420a2a7af7561e238ea2f55322fe69 (diff)
Improve ABR support especially for self-originated stub networks.
This seems to solve the last issues people reported when using ospfd in multiple areas. OK sthen@ prodding by deraadt@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/ospfd/area.c29
-rw-r--r--usr.sbin/ospfd/interface.c6
-rw-r--r--usr.sbin/ospfd/neighbor.c3
-rw-r--r--usr.sbin/ospfd/ospfd.h6
-rw-r--r--usr.sbin/ospfd/ospfe.c4
-rw-r--r--usr.sbin/ospfd/rde.c41
-rw-r--r--usr.sbin/ospfd/rde_lsdb.c6
-rw-r--r--usr.sbin/ospfd/rde_spf.c45
8 files changed, 84 insertions, 56 deletions
diff --git a/usr.sbin/ospfd/area.c b/usr.sbin/ospfd/area.c
index f5f4acf7091..f1def2aaf23 100644
--- a/usr.sbin/ospfd/area.c
+++ b/usr.sbin/ospfd/area.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: area.c,v 1.9 2009/01/07 21:16:36 claudio Exp $ */
+/* $OpenBSD: area.c,v 1.10 2015/11/22 13:09:10 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -94,19 +94,24 @@ area_find(struct ospfd_conf *conf, struct in_addr area_id)
}
void
-area_track(struct area *area, int state)
+area_track(struct area *area)
{
- int old = area->active;
-
- if (state & NBR_STA_FULL)
- area->active++;
- else if (area->active == 0)
- fatalx("area_track: area already inactive");
- else
- area->active--;
+ int old = area->active;
+ struct iface *iface;
+
+ area->active = 0;
+ LIST_FOREACH(iface, &area->iface_list, entry) {
+ if (iface->state & IF_STA_DOWN)
+ continue;
+ area->active = 1;
+ break;
+ }
- if (area->active == 0 || old == 0)
+ if (area->active != old) {
+ ospfe_imsg_compose_rde(IMSG_AREA_CHANGE, area->id.s_addr, 0,
+ &area->active, sizeof(area->active));
ospfe_demote_area(area, old == 0);
+ }
}
int
@@ -116,7 +121,7 @@ area_border_router(struct ospfd_conf *conf)
int active = 0;
LIST_FOREACH(area, &conf->area_list, entry)
- if (area->active > 0)
+ if (area->active)
active++;
return (active > 1);
diff --git a/usr.sbin/ospfd/interface.c b/usr.sbin/ospfd/interface.c
index 1c8fca2f388..069da3d5b47 100644
--- a/usr.sbin/ospfd/interface.c
+++ b/usr.sbin/ospfd/interface.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: interface.c,v 1.79 2015/09/27 17:31:50 stsp Exp $ */
+/* $OpenBSD: interface.c,v 1.80 2015/11/22 13:09:10 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -136,8 +136,10 @@ if_fsm(struct iface *iface, enum iface_event event)
if (new_state != 0)
iface->state = new_state;
- if (iface->state != old_state)
+ if (iface->state != old_state) {
+ area_track(iface->area);
orig_rtr_lsa(iface->area);
+ }
if (old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT) &&
(iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0)
diff --git a/usr.sbin/ospfd/neighbor.c b/usr.sbin/ospfd/neighbor.c
index 2679dc4a8e2..cb85fdede62 100644
--- a/usr.sbin/ospfd/neighbor.c
+++ b/usr.sbin/ospfd/neighbor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: neighbor.c,v 1.46 2013/01/17 10:07:56 markus Exp $ */
+/* $OpenBSD: neighbor.c,v 1.47 2015/11/22 13:09:10 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -204,7 +204,6 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event)
* neighbor changed from/to FULL
* originate new rtr and net LSA
*/
- area_track(nbr->iface->area, nbr->state);
orig_rtr_lsa(nbr->iface->area);
if (nbr->iface->state & IF_STA_DR)
orig_net_lsa(nbr->iface);
diff --git a/usr.sbin/ospfd/ospfd.h b/usr.sbin/ospfd/ospfd.h
index 7205a65d731..a225fd6830d 100644
--- a/usr.sbin/ospfd/ospfd.h
+++ b/usr.sbin/ospfd/ospfd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospfd.h,v 1.92 2015/09/27 17:31:50 stsp Exp $ */
+/* $OpenBSD: ospfd.h,v 1.93 2015/11/22 13:09:10 claudio Exp $ */
/*
* Copyright (c) 2004 Esben Norby <norby@openbsd.org>
@@ -104,6 +104,7 @@ enum imsg_type {
IMSG_NEIGHBOR_CAPA,
IMSG_NETWORK_ADD,
IMSG_NETWORK_DEL,
+ IMSG_AREA_CHANGE,
IMSG_DD,
IMSG_DD_END,
IMSG_DD_BADLSA,
@@ -499,6 +500,7 @@ struct ctl_rt {
enum dst_type d_type;
u_int8_t flags;
u_int8_t prefixlen;
+ u_int8_t connected;
};
struct ctl_sum {
@@ -530,7 +532,7 @@ struct demote_msg {
struct area *area_new(void);
int area_del(struct area *);
struct area *area_find(struct ospfd_conf *, struct in_addr);
-void area_track(struct area *, int);
+void area_track(struct area *);
int area_border_router(struct ospfd_conf *);
u_int8_t area_ospf_options(struct area *);
diff --git a/usr.sbin/ospfd/ospfe.c b/usr.sbin/ospfd/ospfe.c
index b3c7ac26c9d..03fc2556f11 100644
--- a/usr.sbin/ospfd/ospfe.c
+++ b/usr.sbin/ospfd/ospfe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospfe.c,v 1.91 2015/09/27 17:31:50 stsp Exp $ */
+/* $OpenBSD: ospfe.c,v 1.92 2015/11/22 13:09:10 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -996,9 +996,9 @@ orig_rtr_lsa(struct area *area)
oeconf->border = border;
orig_rtr_lsa_all(area);
}
-
if (oeconf->border)
lsa_rtr.flags |= OSPF_RTR_B;
+
/* TODO set V flag if a active virtual link ends here and the
* area is the transit area for this link. */
if (virtual)
diff --git a/usr.sbin/ospfd/rde.c b/usr.sbin/ospfd/rde.c
index 844bd5c6542..4c63fcfc230 100644
--- a/usr.sbin/ospfd/rde.c
+++ b/usr.sbin/ospfd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.97 2015/03/14 02:22:09 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.98 2015/11/22 13:09:10 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
@@ -298,11 +298,6 @@ rde_dispatch_imsg(int fd, short event, void *bula)
if (nbr == NULL)
break;
- if (state != nbr->state &&
- (nbr->state & NBR_STA_FULL ||
- state & NBR_STA_FULL))
- area_track(nbr->area, state);
-
nbr->state = state;
if (nbr->state & NBR_STA_FULL)
rde_req_list_free(nbr);
@@ -315,6 +310,19 @@ rde_dispatch_imsg(int fd, short event, void *bula)
break;
nbr->capa_options = *(u_int8_t *)imsg.data;
break;
+ case IMSG_AREA_CHANGE:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(state))
+ fatalx("invalid size of OE request");
+
+ LIST_FOREACH(area, &rdeconf->area_list, entry) {
+ if (area->id.s_addr == imsg.hdr.peerid)
+ break;
+ }
+ if (area == NULL)
+ break;
+ memcpy(&state, imsg.data, sizeof(state));
+ area->active = state;
+ break;
case IMSG_DB_SNAPSHOT:
nbr = rde_nbr_find(imsg.hdr.peerid);
if (nbr == NULL)
@@ -771,6 +779,9 @@ rde_send_change_kroute(struct rt_node *r)
TAILQ_FOREACH(rn, &r->nexthop, entry) {
if (rn->invalid)
continue;
+ if (rn->connected)
+ /* skip self-originated routes */
+ continue;
krcount++;
bzero(&kr, sizeof(kr));
@@ -780,8 +791,12 @@ rde_send_change_kroute(struct rt_node *r)
kr.ext_tag = r->ext_tag;
imsg_add(wbuf, &kr, sizeof(kr));
}
- if (krcount == 0)
- fatalx("rde_send_change_kroute: no valid nexthop found");
+ if (krcount == 0) {
+ /* no valid nexthop or self originated, so remove */
+ ibuf_free(wbuf);
+ rde_send_delete_kroute(r);
+ return;
+ }
imsg_close(&iev_main->ibuf, wbuf);
imsg_event_add(iev_main);
}
@@ -1352,6 +1367,9 @@ rde_summary_update(struct rt_node *rte, struct area *area)
/* first check if we actually need to announce this route */
if (!(rte->d_type == DT_NET || rte->flags & OSPF_RTR_E))
return;
+ /* route is invalid, lsa_remove_invalid_sums() will do the cleanup */
+ if (rte->cost >= LS_INFINITY)
+ return;
/* never create summaries for as-ext LSA */
if (rte->p_type == PT_TYPE1_EXT || rte->p_type == PT_TYPE2_EXT)
return;
@@ -1363,16 +1381,17 @@ rde_summary_update(struct rt_node *rte, struct area *area)
return;
/* nexthop check, nexthop part of area -> no summary */
TAILQ_FOREACH(rn, &rte->nexthop, entry) {
+ if (rn->invalid)
+ continue;
nr = rt_lookup(DT_NET, rn->nexthop.s_addr);
if (nr && nr->area.s_addr == area->id.s_addr)
continue;
break;
}
- if (rn == NULL) /* all nexthops belong to this area */
+ if (rn == NULL)
+ /* all nexthops belong to this area or are invalid */
return;
- if (rte->cost >= LS_INFINITY)
- return;
/* TODO AS border router specific checks */
/* TODO inter-area network route stuff */
/* TODO intra-area stuff -- condense LSA ??? */
diff --git a/usr.sbin/ospfd/rde_lsdb.c b/usr.sbin/ospfd/rde_lsdb.c
index 115eb44ab93..c64b1d95f71 100644
--- a/usr.sbin/ospfd/rde_lsdb.c
+++ b/usr.sbin/ospfd/rde_lsdb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_lsdb.c,v 1.49 2013/08/14 20:16:09 claudio Exp $ */
+/* $OpenBSD: rde_lsdb.c,v 1.50 2015/11/22 13:09:10 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
@@ -119,10 +119,6 @@ vertex_nexthop_add(struct vertex *dst, struct vertex *parent, u_int32_t nexthop)
{
struct v_nexthop *vn;
- if (nexthop == 0)
- /* invalid nexthop, skip it */
- return;
-
if ((vn = calloc(1, sizeof(*vn))) == NULL)
fatal("vertex_nexthop_add");
diff --git a/usr.sbin/ospfd/rde_spf.c b/usr.sbin/ospfd/rde_spf.c
index b79ba30506f..736f2e57577 100644
--- a/usr.sbin/ospfd/rde_spf.c
+++ b/usr.sbin/ospfd/rde_spf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_spf.c,v 1.75 2012/09/18 18:58:56 bluhm Exp $ */
+/* $OpenBSD: rde_spf.c,v 1.76 2015/11/22 13:09:10 claudio Exp $ */
/*
* Copyright (c) 2005 Esben Norby <norby@openbsd.org>
@@ -22,6 +22,7 @@
#include <arpa/inet.h>
#include <err.h>
#include <stdlib.h>
+#include <string.h>
#include "ospfd.h"
#include "ospf.h"
@@ -64,14 +65,19 @@ spf_calc(struct area *area)
/* initialize SPF tree */
if ((v = spf_root = lsa_find_area(area, LSA_TYPE_ROUTER,
- rde_router_id(), rde_router_id())) == NULL)
+ rde_router_id(), rde_router_id())) == NULL) {
/* empty area because no interface is active */
return;
+ }
area->transit = 0;
spf_root->cost = 0;
w = NULL;
+ /* make sure the spf root has a nexthop */
+ vertex_nexthop_clear(spf_root);
+ vertex_nexthop_add(spf_root, spf_root, 0);
+
/* calculate SPF tree */
do {
/* loop links */
@@ -159,8 +165,7 @@ spf_calc(struct area *area)
} while (v != NULL);
/* spf_dump(area); */
- log_debug("spf_calc: area %s calculated",
- inet_ntoa(area->id));
+ log_debug("spf_calc: area %s calculated", inet_ntoa(area->id));
area->num_spf_calc++;
start_spf_timer();
@@ -182,7 +187,7 @@ rt_calc(struct vertex *v, struct area *area, struct ospfd_conf *conf)
switch (v->type) {
case LSA_TYPE_ROUTER:
/* stub networks */
- if (v->cost >= LS_INFINITY || TAILQ_EMPTY(&v->nexthop))
+ if (v->cost >= LS_INFINITY)
return;
for (i = 0; i < lsa_num_links(v); i++) {
@@ -211,7 +216,7 @@ rt_calc(struct vertex *v, struct area *area, struct ospfd_conf *conf)
adv_rtr, PT_INTRA_AREA, DT_RTR, v->lsa->data.rtr.flags, 0);
break;
case LSA_TYPE_NETWORK:
- if (v->cost >= LS_INFINITY || TAILQ_EMPTY(&v->nexthop))
+ if (v->cost >= LS_INFINITY)
return;
addr.s_addr = htonl(v->ls_id) & v->lsa->data.net.mask;
@@ -245,7 +250,7 @@ rt_calc(struct vertex *v, struct area *area, struct ospfd_conf *conf)
v->cost = w->cost +
(ntohl(v->lsa->data.sum.metric) & LSA_METRIC_MASK);
- if (v->cost >= LS_INFINITY || TAILQ_EMPTY(&v->nexthop))
+ if (v->cost >= LS_INFINITY)
return;
adv_rtr.s_addr = htonl(v->adv_rtr);
@@ -751,7 +756,7 @@ rt_nexthop_add(struct rt_node *r, struct v_nexthead *vnh, u_int8_t type,
rn->adv_rtr.s_addr = adv_rtr.s_addr;
rn->connected = (type == LSA_TYPE_NETWORK &&
- vn->prev == spf_root);
+ vn->prev == spf_root) || (vn->nexthop.s_addr == 0);
rn->invalid = 0;
r->invalid = 0;
@@ -768,7 +773,7 @@ rt_nexthop_add(struct rt_node *r, struct v_nexthead *vnh, u_int8_t type,
rn->adv_rtr.s_addr = adv_rtr.s_addr;
rn->uptime = now.tv_sec;
rn->connected = (type == LSA_TYPE_NETWORK &&
- vn->prev == spf_root);
+ vn->prev == spf_root) || (vn->nexthop.s_addr == 0);
rn->invalid = 0;
r->invalid = 0;
@@ -823,20 +828,23 @@ rt_dump(struct in_addr area, pid_t pid, u_int8_t r_type)
fatalx("rt_dump: invalid RIB type");
}
+ bzero(&rtctl, sizeof(rtctl));
+ rtctl.prefix.s_addr = r->prefix.s_addr;
+ rtctl.area.s_addr = r->area.s_addr;
+ rtctl.cost = r->cost;
+ rtctl.cost2 = r->cost2;
+ rtctl.p_type = r->p_type;
+ rtctl.d_type = r->d_type;
+ rtctl.flags = r->flags;
+ rtctl.prefixlen = r->prefixlen;
+
TAILQ_FOREACH(rn, &r->nexthop, entry) {
if (rn->invalid)
continue;
- rtctl.prefix.s_addr = r->prefix.s_addr;
+ rtctl.connected = rn->connected;
rtctl.nexthop.s_addr = rn->nexthop.s_addr;
- rtctl.area.s_addr = r->area.s_addr;
rtctl.adv_rtr.s_addr = rn->adv_rtr.s_addr;
- rtctl.cost = r->cost;
- rtctl.cost2 = r->cost2;
- rtctl.p_type = r->p_type;
- rtctl.d_type = r->d_type;
- rtctl.flags = r->flags;
- rtctl.prefixlen = r->prefixlen;
rtctl.uptime = now.tv_sec - rn->uptime;
rde_imsg_compose_ospfe(IMSG_CTL_SHOW_RIB, 0, pid,
@@ -855,9 +863,6 @@ rt_update(struct in_addr prefix, u_int8_t prefixlen, struct v_nexthead *vnh,
struct rt_nexthop *rn;
int better = 0, equal = 0;
- if (vnh == NULL || TAILQ_EMPTY(vnh)) /* XXX remove */
- fatalx("rt_update: invalid nexthop");
-
if ((rte = rt_find(prefix.s_addr, prefixlen, d_type)) == NULL) {
if ((rte = calloc(1, sizeof(struct rt_node))) == NULL)
fatal("rt_update");