summaryrefslogtreecommitdiff
path: root/usr.sbin/ospfd
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2005-04-12 09:55:00 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2005-04-12 09:55:00 +0000
commit6b4b64159e389c13ae22556f749cd2d103f28244 (patch)
tree9dbba619914322f3d16f2e05b3764371d59085b2 /usr.sbin/ospfd
parentc1405cb6b63a5233eeb1ca7db8fc6d64eaa8d531 (diff)
Support for self originated AS-external LSA.
With "redistribute (static|connected|default|none)" it is possible to tell ospfd which external routes should be announced. Connected routes will be announced only if there is no corresponding interface configured, in that case the prefix is not external. Adding and removing of announced prefixes are done automaticaly. OK norby@
Diffstat (limited to 'usr.sbin/ospfd')
-rw-r--r--usr.sbin/ospfd/kroute.c38
-rw-r--r--usr.sbin/ospfd/neighbor.c22
-rw-r--r--usr.sbin/ospfd/ospfd.conf.521
-rw-r--r--usr.sbin/ospfd/ospfd.h21
-rw-r--r--usr.sbin/ospfd/ospfe.c28
-rw-r--r--usr.sbin/ospfd/ospfe.h3
-rw-r--r--usr.sbin/ospfd/parse.y24
-rw-r--r--usr.sbin/ospfd/rde.c260
-rw-r--r--usr.sbin/ospfd/rde.h8
9 files changed, 397 insertions, 28 deletions
diff --git a/usr.sbin/ospfd/kroute.c b/usr.sbin/ospfd/kroute.c
index 12d5eb196ae..5e6b9afe006 100644
--- a/usr.sbin/ospfd/kroute.c
+++ b/usr.sbin/ospfd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.13 2005/03/31 19:32:10 norby Exp $ */
+/* $OpenBSD: kroute.c,v 1.14 2005/04/12 09:54:59 claudio Exp $ */
/*
* Copyright (c) 2004 Esben Norby <norby@openbsd.org>
@@ -61,6 +61,7 @@ struct kif_node {
struct kif k;
};
+void kr_redistribute(int, struct kroute *);
int kroute_compare(struct kroute_node *, struct kroute_node *);
int kif_compare(struct kif_node *, struct kif_node *);
@@ -324,6 +325,28 @@ kr_ifinfo(char *ifname, pid_t pid)
main_imsg_compose_ospfe(IMSG_CTL_END, pid, NULL, 0);
}
+void
+kr_redistribute(int type, struct kroute *kr)
+{
+ u_int32_t a;
+
+ /*
+ * We consider the loopback net, multicast and experimental addresses
+ * as not redistributable.
+ */
+ a = ntohl(kr->prefix.s_addr);
+ if (IN_MULTICAST(a) || IN_BADCLASS(a) ||
+ (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
+ return;
+ /*
+ * Consider networks with nexthop loopback as not redistributable.
+ */
+ if (kr->nexthop.s_addr == htonl(INADDR_LOOPBACK))
+ return;
+
+ main_imsg_compose_rde(type, 0, kr, sizeof(struct kroute));
+}
+
/* rb-tree compare */
int
kroute_compare(struct kroute_node *a, struct kroute_node *b)
@@ -367,6 +390,9 @@ kroute_insert(struct kroute_node *kr)
return (-1);
}
+ if (kr->r.flags & F_KERNEL)
+ kr_redistribute(IMSG_NETWORK_ADD, &kr->r);
+
return (0);
}
@@ -379,6 +405,9 @@ kroute_remove(struct kroute_node *kr)
return (-1);
}
+ if (kr->r.flags & F_KERNEL)
+ kr_redistribute(IMSG_NETWORK_DEL, &kr->r);
+
free(kr);
return (0);
}
@@ -730,6 +759,8 @@ fetchtable(void)
else
kr->r.prefixlen =
prefixlen_classful(kr->r.prefix.s_addr);
+ if (rtm->rtm_flags & RTF_STATIC)
+ kr->r.flags |= F_STATIC;
break;
default:
free(kr);
@@ -894,6 +925,8 @@ dispatch_rtmsg(void)
else
prefixlen =
prefixlen_classful(prefix.s_addr);
+ if (rtm->rtm_flags & RTF_STATIC)
+ flags |= F_STATIC;
break;
default:
continue;
@@ -927,6 +960,9 @@ dispatch_rtmsg(void)
if (kr->r.flags & F_KERNEL) {
kr->r.nexthop.s_addr = nexthop.s_addr;
kr->r.flags = flags;
+ /* just readd, the RDE will care */
+ kr_redistribute(IMSG_NETWORK_ADD,
+ &kr->r);
}
} else if (rtm->rtm_type == RTM_CHANGE) {
log_warnx("change req for %s/%u: not "
diff --git a/usr.sbin/ospfd/neighbor.c b/usr.sbin/ospfd/neighbor.c
index c7847167297..4eddf908738 100644
--- a/usr.sbin/ospfd/neighbor.c
+++ b/usr.sbin/ospfd/neighbor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: neighbor.c,v 1.14 2005/03/31 19:32:10 norby Exp $ */
+/* $OpenBSD: neighbor.c,v 1.15 2005/04/12 09:54:59 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -50,7 +50,7 @@ struct nbr_table {
#define NBR_HASH(x) \
&nbrtable.hashtbl[(x) & nbrtable.hashmask]
-u_int32_t peercnt;
+u_int32_t peercnt = NBR_CNTSTART;
struct {
int state;
@@ -230,6 +230,8 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event)
void
nbr_init(u_int32_t hashsize)
{
+ struct nbr_head *head;
+ struct nbr *nbr;
u_int32_t hs, i;
for (hs = 1; hs < hashsize; hs <<= 1)
@@ -242,13 +244,27 @@ nbr_init(u_int32_t hashsize)
LIST_INIT(&nbrtable.hashtbl[i]);
nbrtable.hashmask = hs - 1;
+
+ /* allocate a dummy neighbor used for self originated AS ext routes */
+ if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
+ fatal("nbr_init");
+
+ nbr->id.s_addr = ospfe_router_id();
+ nbr->state = NBR_STA_DOWN;
+ nbr->peerid = NBR_IDSELF;
+ head = NBR_HASH(nbr->peerid);
+ LIST_INSERT_HEAD(head, nbr, hash);
+
+ TAILQ_INIT(&nbr->ls_retrans_list);
+ TAILQ_INIT(&nbr->db_sum_list);
+ TAILQ_INIT(&nbr->ls_req_list);
}
struct nbr *
nbr_new(u_int32_t nbr_id, struct iface *iface, int self)
{
struct nbr_head *head;
- struct nbr *nbr = NULL;
+ struct nbr *nbr;
struct rde_nbr rn;
if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
diff --git a/usr.sbin/ospfd/ospfd.conf.5 b/usr.sbin/ospfd/ospfd.conf.5
index 1dfe93c8c1b..dfd9949b782 100644
--- a/usr.sbin/ospfd/ospfd.conf.5
+++ b/usr.sbin/ospfd/ospfd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ospfd.conf.5,v 1.7 2005/03/31 19:32:10 norby Exp $
+.\" $OpenBSD: ospfd.conf.5,v 1.8 2005/04/12 09:54:59 claudio Exp $
.\"
.\" Copyright (c) 2005 Esben Norby <norby@openbsd.org>
.\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -86,6 +86,25 @@ do not update the Forward Information Base, a.k.a. the kernel
routing table.
The default is
.Ic yes .
+.It Xo
+.Ic redistribute
+.Sm off
+.Po Ic static Ns \&| Ns Ic connected Ns \&| Ns
+.Ic default Ns \&| Ns Ic none Pc
+.Sm on
+.Xc
+If set to
+.Ar connected ,
+routes to directly attached networks will be announced over OSPF.
+If set to
+.Ar static ,
+static routes will be announced over OSPF.
+If set to
+.Ar default ,
+the default route will be announced over OSPF.
+The default setting is
+.Ar none .
+In this case no additional routes will be announced over OSPF.
.It Ic router-id Ar address
Set the router ID; if not specified, the lowest IP address of the router
will be used.
diff --git a/usr.sbin/ospfd/ospfd.h b/usr.sbin/ospfd/ospfd.h
index ee51a7d6ba3..be45a1e3889 100644
--- a/usr.sbin/ospfd/ospfd.h
+++ b/usr.sbin/ospfd/ospfd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospfd.h,v 1.25 2005/04/05 13:01:22 claudio Exp $ */
+/* $OpenBSD: ospfd.h,v 1.26 2005/04/12 09:54:59 claudio Exp $ */
/*
* Copyright (c) 2004 Esben Norby <norby@openbsd.org>
@@ -36,6 +36,9 @@
#define NBR_HASHSIZE 128
#define LSA_HASHSIZE 512
+#define NBR_IDSELF 1
+#define NBR_CNTSTART (NBR_IDSELF + 1)
+
#define READ_BUF_SIZE 65535
#define PKG_DEF_SIZE 512 /* compromise */
#define RT_BUF_SIZE 16384
@@ -50,6 +53,10 @@
#define F_STATIC 0x0020
#define F_LONGER 0x0040
+#define REDISTRIBUTE_STATIC 0x01
+#define REDISTRIBUTE_CONNECTED 0x02
+#define REDISTRIBUTE_DEFAULT 0x04
+
/* buffer */
struct buf {
TAILQ_ENTRY(buf) entry;
@@ -109,6 +116,8 @@ enum imsg_type {
IMSG_NEIGHBOR_UP,
IMSG_NEIGHBOR_DOWN,
IMSG_NEIGHBOR_CHANGE,
+ IMSG_NETWORK_ADD,
+ IMSG_NETWORK_DEL,
IMSG_DD,
IMSG_DD_END,
IMSG_DB_SNAPSHOT,
@@ -322,19 +331,21 @@ struct ospfd_conf {
struct event ev;
struct event spf_timer;
struct in_addr rtr_id;
+ struct lsa_tree lsa_tree;
+ LIST_HEAD(, area) area_list;
+ LIST_HEAD(, vertex) cand_list;
+
u_int32_t opts;
#define OSPFD_OPT_VERBOSE 0x00000001
#define OSPFD_OPT_VERBOSE2 0x00000002
#define OSPFD_OPT_NOACTION 0x00000004
- int maxdepth;
- LIST_HEAD(, area) area_list;
- LIST_HEAD(, vertex) cand_list;
- struct lsa_tree lsa_tree;
u_int32_t spf_delay;
u_int32_t spf_hold_time;
int spf_state;
+ int maxdepth;
int ospf_socket;
int flags;
+ int redistribute_flags;
int options; /* OSPF options */
u_int8_t rfc1583compat;
};
diff --git a/usr.sbin/ospfd/ospfe.c b/usr.sbin/ospfd/ospfe.c
index e334e279303..4fd7e4818d0 100644
--- a/usr.sbin/ospfd/ospfe.c
+++ b/usr.sbin/ospfd/ospfe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospfe.c,v 1.13 2005/03/15 22:03:56 claudio Exp $ */
+/* $OpenBSD: ospfe.c,v 1.14 2005/04/12 09:54:59 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -429,11 +429,16 @@ ospfe_dispatch_rde(int fd, short event, void *bula)
le = ls_req_list_get(nbr, &lsa_hdr);
if (!(nbr->state & NBR_STA_FULL) && le != NULL) {
ls_req_list_free(nbr, le);
- /* XXX no need to ack requested lsa */
+ /*
+ * XXX no need to ack requested lsa
+ * the problem is that the RFC is very
+ * unclear about this.
+ */
noack = 1;
}
- if (!noack && nbr->iface->self != nbr) {
+ if (!noack && nbr->iface != NULL &&
+ nbr->iface->self != nbr) {
if (!(nbr->iface->state & IF_STA_BACKUP) ||
nbr->iface->dr == nbr) {
/* delayed ack */
@@ -474,7 +479,7 @@ ospfe_dispatch_rde(int fd, short event, void *bula)
if (ntohs(age) >= MAX_AGE) {
/* add to retransmit list */
ref = lsa_cache_add(imsg.data, l);
- ls_retrans_list_add(nbr, imsg.data); /* XXX */
+ ls_retrans_list_add(nbr, imsg.data);
lsa_cache_put(ref, nbr);
}
@@ -699,7 +704,16 @@ orig_rtr_lsa(struct area *area)
}
/* LSA router header */
- lsa_rtr.flags = oeconf->flags; /* XXX */
+ lsa_rtr.flags = 0;
+ /*
+ * Set the E bit as soon as an as-ext lsa may be redistributed, only
+ * setting it in case we redistribute something is not worth the fuss.
+ */
+ if (oeconf->redistribute_flags && (oeconf->options & OSPF_OPTION_E))
+ lsa_rtr.flags |= OSPF_RTR_E;
+ /* TODO if activly connected to more than one area set B flag */
+ /* TODO set V flag if a active virtual link ends here and the
+ * area is the tranist area for this link. */
lsa_rtr.dummy = 0;
lsa_rtr.nlinks = htons(num_links);
memcpy(buf_seek(buf, sizeof(lsa_hdr), sizeof(lsa_rtr)),
@@ -707,7 +721,7 @@ orig_rtr_lsa(struct area *area)
/* LSA header */
lsa_hdr.age = htons(DEFAULT_AGE);
- lsa_hdr.opts = oeconf->options; /* XXX */
+ lsa_hdr.opts = oeconf->options; /* XXX */
lsa_hdr.type = LSA_TYPE_ROUTER;
lsa_hdr.ls_id = oeconf->rtr_id.s_addr;
lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
@@ -773,7 +787,7 @@ orig_net_lsa(struct iface *iface)
else
lsa_hdr.age = htons(MAX_AGE);
- lsa_hdr.opts = oeconf->options; /* XXX */
+ lsa_hdr.opts = oeconf->options; /* XXX */
lsa_hdr.type = LSA_TYPE_NETWORK;
lsa_hdr.ls_id = iface->addr.s_addr;
lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
diff --git a/usr.sbin/ospfd/ospfe.h b/usr.sbin/ospfd/ospfe.h
index 3aa2d80235d..ffa4adc43a7 100644
--- a/usr.sbin/ospfd/ospfe.h
+++ b/usr.sbin/ospfd/ospfe.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospfe.h,v 1.11 2005/04/05 13:01:22 claudio Exp $ */
+/* $OpenBSD: ospfe.h,v 1.12 2005/04/12 09:54:59 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -246,7 +246,6 @@ void ls_retrans_list_clr(struct nbr *);
int ls_retrans_list_empty(struct nbr *);
void ls_retrans_timer(int, short, void *);
-
void lsa_cache_init(u_int32_t);
struct lsa_ref *lsa_cache_add(void *, u_int16_t);
struct lsa_ref *lsa_cache_get(struct lsa_hdr *);
diff --git a/usr.sbin/ospfd/parse.y b/usr.sbin/ospfd/parse.y
index 53c5f98c569..8ce4c533125 100644
--- a/usr.sbin/ospfd/parse.y
+++ b/usr.sbin/ospfd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.12 2005/04/06 20:21:08 norby Exp $ */
+/* $OpenBSD: parse.y,v 1.13 2005/04/12 09:54:59 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -97,7 +97,7 @@ typedef struct {
%}
-%token AREA INTERFACE ROUTERID FIBUPDATE
+%token AREA INTERFACE ROUTERID FIBUPDATE REDISTRIBUTE
%token SPFDELAY SPFHOLDTIME
%token AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID
%token METRIC PASSIVE
@@ -231,6 +231,25 @@ conf_main : METRIC number {
else
conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE;
}
+ | REDISTRIBUTE STRING {
+ if (!strcmp($2, "static"))
+ conf->redistribute_flags |=
+ REDISTRIBUTE_STATIC;
+ else if (!strcmp($2, "connected"))
+ conf->redistribute_flags |=
+ REDISTRIBUTE_CONNECTED;
+ else if (!strcmp($2, "default"))
+ conf->redistribute_flags |=
+ REDISTRIBUTE_DEFAULT;
+ else if (!strcmp($2, "none"))
+ conf->redistribute_flags = 0;
+ else {
+ yyerror("unknown redistribute type");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
| SPFDELAY number {
if ($2 < MIN_SPF_DELAY || $2 > MAX_SPF_DELAY) {
yyerror("spf-delay out of range "
@@ -524,6 +543,7 @@ lookup(char *s)
{"interface", INTERFACE},
{"metric", METRIC},
{"passive", PASSIVE},
+ {"redistribute", REDISTRIBUTE},
{"retransmit-interval", RETRANSMITINTERVAL},
{"router-dead-time", ROUTERDEADTIME},
{"router-id", ROUTERID},
diff --git a/usr.sbin/ospfd/rde.c b/usr.sbin/ospfd/rde.c
index acbff688b2d..7caa67025f1 100644
--- a/usr.sbin/ospfd/rde.c
+++ b/usr.sbin/ospfd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.11 2005/04/06 09:27:28 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.12 2005/04/12 09:54:59 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
@@ -41,6 +41,8 @@
void rde_sig_handler(int sig, short, void *);
void rde_shutdown(void);
void rde_dispatch_imsg(int, short, void *);
+void rde_dispatch_parent(int, short, void *);
+
void rde_send_summary(pid_t);
void rde_send_summary_area(struct area *, pid_t);
void rde_nbr_init(u_int32_t);
@@ -48,10 +50,15 @@ struct rde_nbr *rde_nbr_find(u_int32_t);
struct rde_nbr *rde_nbr_new(u_int32_t, struct rde_nbr *);
void rde_nbr_del(struct rde_nbr *);
+int rde_redistribute(struct kroute *);
+struct lsa *rde_asext_get(struct kroute *);
+struct lsa *rde_asext_put(struct kroute *);
+
volatile sig_atomic_t rde_quit = 0;
struct ospfd_conf *rdeconf = NULL;
struct imsgbuf *ibuf_ospfe;
struct imsgbuf *ibuf_main;
+struct rde_nbr *nbrself;
void
rde_sig_handler(int sig, short event, void *arg)
@@ -89,7 +96,7 @@ rde(struct ospfd_conf *xconf, int pipe_parent2rde[2], int pipe_ospfe2rde[2],
return (pid);
}
- rdeconf = xconf;
+ rdeconf = xconf; /* XXX my not be replaced because of the lsa_tree */
if ((pw = getpwnam(OSPFD_USER)) == NULL)
fatal("getpwnam");
@@ -130,7 +137,7 @@ rde(struct ospfd_conf *xconf, int pipe_parent2rde[2], int pipe_ospfe2rde[2],
(ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
fatal(NULL);
imsg_init(ibuf_ospfe, pipe_ospfe2rde[1], rde_dispatch_imsg);
- imsg_init(ibuf_main, pipe_parent2rde[1], rde_dispatch_imsg);
+ imsg_init(ibuf_main, pipe_parent2rde[1], rde_dispatch_parent);
/* setup event handler */
ibuf_ospfe->events = EV_READ;
@@ -385,11 +392,11 @@ rde_dispatch_imsg(int fd, short event, void *bula)
imsg_compose(ibuf_ospfe, IMSG_LS_FLOOD,
v->nbr->peerid, 0, -1,
v->lsa, ntohs(v->lsa->hdr.len));
- /* TODO LSA on req list -> BadLSReq */
/* start spf_timer */
log_debug("rde_dispatch_imsg: start spf_timer");
start_spf_timer(rdeconf);
+ /* TODO LSA on req list -> BadLSReq */
} else if (r < 0) {
/* new LSA older than DB */
if (ntohl(db_hdr->seq_num) == MAX_SEQ_NUM &&
@@ -424,8 +431,10 @@ rde_dispatch_imsg(int fd, short event, void *bula)
fatalx("invalid size of OE request");
memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
- if (rde_nbr_loading(nbr->area))
+ if (rde_nbr_loading(nbr->area)) {
+ log_debug("IMSG_LS_MAXAGE still loading");
break;
+ }
v = lsa_find(nbr->area, lsa_hdr.type, lsa_hdr.ls_id,
lsa_hdr.adv_rtr);
@@ -499,6 +508,81 @@ rde_dispatch_imsg(int fd, short event, void *bula)
imsg_event_add(ibuf);
}
+void
+rde_dispatch_parent(int fd, short event, void *bula)
+{
+ struct imsgbuf *ibuf = bula;
+ struct imsg imsg;
+ struct lsa *lsa;
+ struct vertex *v;
+ struct kroute kr;
+ int n;
+
+ switch (event) {
+ case EV_READ:
+ if ((n = imsg_read(ibuf)) == -1)
+ fatal("imsg_read error");
+ if (n == 0) /* connection closed */
+ fatalx("pipe closed");
+ break;
+ case EV_WRITE:
+ if (msgbuf_write(&ibuf->w) == -1)
+ fatal("msgbuf_write");
+ imsg_event_add(ibuf);
+ return;
+ default:
+ fatalx("unknown event");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("rde_dispatch_parent: imsg_read error");
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_NETWORK_ADD:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
+ log_warnx("rde_dispatch: wrong imsg len");
+ break;
+ }
+ memcpy(&kr, imsg.data, sizeof(kr));
+
+ log_debug("rde: new announced net %s/%d",
+ inet_ntoa(kr.prefix), kr.prefixlen);
+ if ((lsa = rde_asext_get(&kr)) != NULL) {
+ v = lsa_find(NULL, lsa->hdr.type,
+ lsa->hdr.ls_id, lsa->hdr.adv_rtr);
+
+ lsa_merge(nbrself, lsa, v);
+ }
+ break;
+ case IMSG_NETWORK_DEL:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
+ log_warnx("rde_dispatch: wrong imsg len");
+ break;
+ }
+ memcpy(&kr, imsg.data, sizeof(kr));
+
+ log_debug("rde: removing announced net %s/%d",
+ inet_ntoa(kr.prefix), kr.prefixlen);
+ if ((lsa = rde_asext_put(&kr)) != NULL) {
+ v = lsa_find(NULL, lsa->hdr.type,
+ lsa->hdr.ls_id, lsa->hdr.adv_rtr);
+
+ lsa_merge(nbrself, lsa, v);
+ }
+ break;
+ default:
+ log_debug("rde_dispatch_parent: unexpected imsg %d",
+ imsg.hdr.type);
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ imsg_event_add(ibuf);
+}
+
u_int32_t
rde_router_id(void)
{
@@ -598,7 +682,8 @@ struct nbr_table {
void
rde_nbr_init(u_int32_t hashsize)
{
- u_int32_t hs, i;
+ struct rde_nbr_head *head;
+ u_int32_t hs, i;
for (hs = 1; hs < hashsize; hs <<= 1)
;
@@ -610,6 +695,16 @@ rde_nbr_init(u_int32_t hashsize)
LIST_INIT(&rdenbrtable.hashtbl[i]);
rdenbrtable.hashmask = hs - 1;
+
+ if ((nbrself = calloc(1, sizeof(*nbrself))) == NULL)
+ fatal("rde_nbr_init");
+
+ nbrself->id.s_addr = rde_router_id();
+ nbrself->peerid = NBR_IDSELF;
+ nbrself->state = NBR_STA_DOWN;
+ nbrself->self = 1;
+ head = RDE_NBR_HASH(NBR_IDSELF);
+ LIST_INSERT_HEAD(head, nbrself, hash);
}
struct rde_nbr *
@@ -695,3 +790,156 @@ rde_nbr_self(struct area *area)
return (NULL);
}
+/*
+ * as-external LSA handling
+ */
+LIST_HEAD(, rde_asext) rde_asext_list;
+
+struct lsa *orig_asext_lsa(struct kroute *, u_int16_t);
+
+
+int
+rde_redistribute(struct kroute *kr)
+{
+ struct area *area;
+ struct iface *iface;
+ int rv = 0;
+
+ if (!(kr->flags & F_KERNEL))
+ return (0);
+
+ if ((rdeconf->options & OSPF_OPTION_E) == 0)
+ return (0);
+
+ if ((rdeconf->redistribute_flags & REDISTRIBUTE_DEFAULT) &&
+ (kr->prefix.s_addr == INADDR_ANY && kr->prefixlen == 0))
+ return (1);
+
+ /* only allow 0.0.0.0/0 if REDISTRIBUTE_DEFAULT */
+ if (kr->prefix.s_addr == INADDR_ANY && kr->prefixlen == 0)
+ return (0);
+
+ if ((rdeconf->redistribute_flags & REDISTRIBUTE_STATIC) &&
+ (kr->flags & F_STATIC))
+ rv = 1;
+ if ((rdeconf->redistribute_flags & REDISTRIBUTE_CONNECTED) &&
+ (kr->flags & F_CONNECTED))
+ rv = 1;
+
+ LIST_FOREACH(area, &rdeconf->area_list, entry)
+ LIST_FOREACH(iface, &area->iface_list, entry) {
+ log_debug("rde_redistribute: iface %s/%d",
+ inet_ntoa(iface->addr),
+ mask2prefixlen(iface->mask.s_addr));
+ if ((iface->addr.s_addr & iface->mask.s_addr) ==
+ kr->prefix.s_addr && iface->mask.s_addr ==
+ prefixlen2mask(kr->prefixlen))
+ rv = 0; /* already announced as net LSA */
+ }
+ log_debug("rde_redistribute: prefix %s/%d used %d",
+ inet_ntoa(kr->prefix), kr->prefixlen, rv);
+ return (rv);
+}
+
+struct lsa *
+rde_asext_get(struct kroute *kr)
+{
+ struct rde_asext *ae;
+ int wasused;
+
+ LIST_FOREACH(ae, &rde_asext_list, entry)
+ if (kr->prefix.s_addr == ae->kr.prefix.s_addr &&
+ kr->prefixlen == ae->kr.prefixlen)
+ break;
+
+ if (ae == NULL) {
+ if ((ae = calloc(1, sizeof(*ae))) == NULL)
+ fatal("rde_asext_get");
+ LIST_INSERT_HEAD(&rde_asext_list, ae, entry);
+ }
+
+ memcpy(&ae->kr, kr, sizeof(ae->kr));
+
+ wasused = ae->used;
+ ae->used = rde_redistribute(kr);
+
+ if (ae->used)
+ /* update of seqnum is done by lsa_merge */
+ return (orig_asext_lsa(kr, DEFAULT_AGE));
+ else if (wasused)
+ /* lsa_merge will take care of removing the lsa from the db */
+ return (orig_asext_lsa(kr, MAX_AGE));
+ else
+ /* not in lsdb, superseded by a net lsa */
+ return (NULL);
+}
+
+struct lsa *
+rde_asext_put(struct kroute *kr)
+{
+ struct rde_asext *ae;
+ int used;
+
+ LIST_FOREACH(ae, &rde_asext_list, entry)
+ if (kr->prefix.s_addr == ae->kr.prefix.s_addr &&
+ kr->prefixlen == ae->kr.prefixlen) {
+ LIST_REMOVE(ae, entry);
+ used = ae->used;
+ free(ae);
+ if (used)
+ return (orig_asext_lsa(kr, MAX_AGE));
+ break;
+ }
+ return (NULL);
+}
+
+struct lsa *
+orig_asext_lsa(struct kroute *kr, u_int16_t age)
+{
+ struct lsa *lsa;
+ size_t len;
+
+ len = sizeof(struct lsa_hdr) + sizeof(struct lsa_asext);
+ if ((lsa = calloc(1, len)) == NULL)
+ fatal("rde_asext_new");
+
+ log_debug("orig_asext_lsa: %s/%d age %d",
+ inet_ntoa(kr->prefix), kr->prefixlen, age);
+
+ /* LSA header */
+ lsa->hdr.age = htons(age);
+ lsa->hdr.opts = rdeconf->options; /* XXX not updated */
+ lsa->hdr.type = LSA_TYPE_EXTERNAL;
+ lsa->hdr.adv_rtr = rdeconf->rtr_id.s_addr;
+ lsa->hdr.seq_num = htonl(INIT_SEQ_NUM);
+ lsa->hdr.len = htons(len);
+
+ /* prefix and mask */
+ /*
+ * TODO ls_id must be unique, for overlapping routes this may
+ * not be true. In this case it a hack needs to be done to
+ * make the ls_id unique.
+ */
+ lsa->hdr.ls_id = kr->prefix.s_addr;
+ lsa->data.asext.mask = prefixlen2mask(kr->prefixlen);
+
+ /*
+ * nexthop -- on connected routes we are the nexthop,
+ * on all other cases we announce the true nexthop.
+ */
+ if (kr->flags & F_CONNECTED)
+ lsa->data.asext.fw_addr = 0;
+ else
+ lsa->data.asext.fw_addr = kr->nexthop.s_addr;
+
+ lsa->data.asext.metric = htonl(/* LSA_ASEXT_E_FLAG | */ 100);
+ /* XXX until now there is no metric */
+ lsa->data.asext.ext_tag = 0;
+
+ lsa->hdr.ls_chksum = 0;
+ lsa->hdr.ls_chksum =
+ htons(iso_cksum(lsa, len, LS_CKSUM_OFFSET));
+
+ return (lsa);
+}
+
diff --git a/usr.sbin/ospfd/rde.h b/usr.sbin/ospfd/rde.h
index 99e10ea0730..cb8562708b1 100644
--- a/usr.sbin/ospfd/rde.h
+++ b/usr.sbin/ospfd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.8 2005/03/22 22:13:48 norby Exp $ */
+/* $OpenBSD: rde.h,v 1.9 2005/04/12 09:54:59 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -55,6 +55,12 @@ struct rde_nbr {
int self;
};
+struct rde_asext {
+ LIST_ENTRY(rde_asext) entry;
+ struct kroute kr;
+ int used;
+};
+
struct rt_node {
RB_ENTRY(rt_node) entry;
struct in_addr prefix;