summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2007-11-27 11:29:35 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2007-11-27 11:29:35 +0000
commit46b3cdc6bb6bf33b0c4e39472b98f8cb224ebbdc (patch)
tree0aed944affe4303faea8f6f36b2f625a1d5d9f50
parent8159ded805fca63dccb4cfb60ebd609f9039d19d (diff)
Monster diff to bring us a bit on track again.
a) implement all (or at least most) lsa_check() cases. b) classify the LSA scope correctly and add a per interface lsa_tree for the link local stuff. c) implement a function to parse a prefix. There is still a lot missing currently link local LSA are added to the interface tree but nothing can access them (lsa_find() and a few friends need some changes). OK norby@
-rw-r--r--usr.sbin/ospf6d/interface.c3
-rw-r--r--usr.sbin/ospf6d/neighbor.c3
-rw-r--r--usr.sbin/ospf6d/ospf6.h51
-rw-r--r--usr.sbin/ospf6d/ospf6d.h4
-rw-r--r--usr.sbin/ospf6d/ospfe.c3
-rw-r--r--usr.sbin/ospf6d/rde.c12
-rw-r--r--usr.sbin/ospf6d/rde.h4
-rw-r--r--usr.sbin/ospf6d/rde_lsdb.c156
8 files changed, 197 insertions, 39 deletions
diff --git a/usr.sbin/ospf6d/interface.c b/usr.sbin/ospf6d/interface.c
index 8e57b57ee02..a527d88a72f 100644
--- a/usr.sbin/ospf6d/interface.c
+++ b/usr.sbin/ospf6d/interface.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: interface.c,v 1.6 2007/11/24 16:35:16 claudio Exp $ */
+/* $OpenBSD: interface.c,v 1.7 2007/11/27 11:29:34 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -167,6 +167,7 @@ if_new(struct kif *kif, struct kif_addr *ka)
LIST_INIT(&iface->nbr_list);
TAILQ_INIT(&iface->ls_ack_list);
+ RB_INIT(&iface->lsa_tree);
if (kif == NULL) {
iface->type = IF_TYPE_VIRTUALLINK;
diff --git a/usr.sbin/ospf6d/neighbor.c b/usr.sbin/ospf6d/neighbor.c
index efd7182e879..8352803c0ef 100644
--- a/usr.sbin/ospf6d/neighbor.c
+++ b/usr.sbin/ospf6d/neighbor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: neighbor.c,v 1.3 2007/10/11 20:20:44 claudio Exp $ */
+/* $OpenBSD: neighbor.c,v 1.4 2007/11/27 11:29:34 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -314,6 +314,7 @@ nbr_new(u_int32_t nbr_id, struct iface *iface, int self)
bzero(&rn, sizeof(rn));
rn.id.s_addr = nbr->id.s_addr;
rn.area_id.s_addr = nbr->iface->area->id.s_addr;
+ rn.ifindex = nbr->iface->ifindex;
rn.state = nbr->state;
rn.self = self;
ospfe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn,
diff --git a/usr.sbin/ospf6d/ospf6.h b/usr.sbin/ospf6d/ospf6.h
index 2a5deb5f77f..8cc63bc9f25 100644
--- a/usr.sbin/ospf6d/ospf6.h
+++ b/usr.sbin/ospf6d/ospf6.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospf6.h,v 1.7 2007/10/16 21:58:17 claudio Exp $ */
+/* $OpenBSD: ospf6.h,v 1.8 2007/11/27 11:29:34 claudio Exp $ */
/*
* Copyright (c) 2004, 2005, 2007 Esben Norby <norby@openbsd.org>
@@ -162,6 +162,18 @@ struct ls_upd_hdr {
#define LSA_TYPE_INTRA_A_PREFIX 0x2009
#define LSA_TYPE_EXTERNAL 0x4005
+#define LSA_TYPE_FLAG_U 0x8000
+#define LSA_TYPE_FLAG_S2 0x4000
+#define LSA_TYPE_FLAG_S1 0x2000
+#define LSA_TYPE_SCOPE_MASK 0x6000
+
+#define LSA_IS_SCOPE_LLOCAL(x) \
+ (((x) & LSA_TYPE_SCOPE_MASK) == 0)
+#define LSA_IS_SCOPE_AREA(x) \
+ (((x) & LSA_TYPE_SCOPE_MASK) == LSA_TYPE_FLAG_S1)
+#define LSA_IS_SCOPE_AS(x) \
+ (((x) & LSA_TYPE_SCOPE_MASK) == LSA_TYPE_FLAG_S2)
+
#define LINK_TYPE_POINTTOPOINT 1
#define LINK_TYPE_TRANSIT_NET 2
#define LINK_TYPE_RESERVED 3
@@ -176,6 +188,13 @@ struct ls_upd_hdr {
#define OSPF_RTR_V 0x04
#define OSPF_RTR_W 0x08
+struct lsa_prefix {
+ struct in6_addr prefix;
+ u_int16_t metric;
+ u_int8_t prefixlen;
+ u_int8_t options;
+};
+
struct lsa_rtr {
u_int32_t opts; /* 8bit flags + 24bits options */
};
@@ -198,9 +217,15 @@ struct lsa_net_link {
u_int32_t att_rtr;
};
-struct lsa_sum {
- u_int32_t mask;
+struct lsa_prefix_sum {
u_int32_t metric; /* only lower 24 bit */
+ /* + one prefix */
+};
+
+struct lsa_rtr_sum {
+ u_int32_t options; /* lower 24bit options */
+ u_int32_t metric; /* only lower 24 bit */
+ u_int32_t dest_rtr_id;
};
struct lsa_asext {
@@ -210,6 +235,21 @@ struct lsa_asext {
u_int32_t ext_tag;
};
+struct lsa_link {
+ u_int32_t options; /* rtr pri & 24bit options */
+ struct in6_addr lladdr;
+ u_int32_t numprefix;
+ /* + numprefix prefix */
+};
+
+struct lsa_intra_prefix {
+ u_int16_t numprefix;
+ u_int16_t ref_type;
+ u_int32_t ref_lsid;
+ u_int32_t ref_adv_rtr;
+ /* + numprefix prefix */
+};
+
struct lsa_hdr {
u_int16_t age;
u_int16_t type;
@@ -227,8 +267,11 @@ struct lsa {
union {
struct lsa_rtr rtr;
struct lsa_net net;
- struct lsa_sum sum;
+ struct lsa_prefix_sum pref_sum;
+ struct lsa_rtr_sum rtr_sum;
struct lsa_asext asext;
+ struct lsa_link link;
+ struct lsa_intra_prefix pref_intra;
} data;
};
diff --git a/usr.sbin/ospf6d/ospf6d.h b/usr.sbin/ospf6d/ospf6d.h
index d4f36f46720..f8904428ca4 100644
--- a/usr.sbin/ospf6d/ospf6d.h
+++ b/usr.sbin/ospf6d/ospf6d.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospf6d.h,v 1.9 2007/10/16 08:41:56 claudio Exp $ */
+/* $OpenBSD: ospf6d.h,v 1.10 2007/11/27 11:29:34 claudio Exp $ */
/*
* Copyright (c) 2004, 2007 Esben Norby <norby@openbsd.org>
@@ -314,6 +314,8 @@ struct iface {
LIST_HEAD(, nbr) nbr_list;
struct lsa_head ls_ack_list;
+ struct lsa_tree lsa_tree; /* LSA with link local scope */
+
char name[IF_NAMESIZE];
char demote_group[IFNAMSIZ];
struct in6_addr addr;
diff --git a/usr.sbin/ospf6d/ospfe.c b/usr.sbin/ospf6d/ospfe.c
index c27701cf6d1..bf33527b445 100644
--- a/usr.sbin/ospf6d/ospfe.c
+++ b/usr.sbin/ospf6d/ospfe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospfe.c,v 1.5 2007/10/13 13:21:56 claudio Exp $ */
+/* $OpenBSD: ospfe.c,v 1.6 2007/11/27 11:29:34 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -343,6 +343,7 @@ ospfe_dispatch_main(int fd, short event, void *bula)
LIST_INIT(&niface->nbr_list);
TAILQ_INIT(&niface->ls_ack_list);
+ RB_INIT(&niface->lsa_tree);
niface->area = narea;
LIST_INSERT_HEAD(&narea->iface_list, niface, entry);
diff --git a/usr.sbin/ospf6d/rde.c b/usr.sbin/ospf6d/rde.c
index 0a31b46022d..88f63289cb1 100644
--- a/usr.sbin/ospf6d/rde.c
+++ b/usr.sbin/ospf6d/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.7 2007/10/17 07:16:02 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.8 2007/11/27 11:29:34 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
@@ -675,6 +675,7 @@ rde_dispatch_parent(int fd, short event, void *bula)
LIST_INIT(&niface->nbr_list);
TAILQ_INIT(&niface->ls_ack_list);
+ RB_INIT(&niface->lsa_tree);
niface->area = narea;
LIST_INSERT_HEAD(&narea->iface_list, niface, entry);
@@ -865,18 +866,27 @@ rde_nbr_new(u_int32_t peerid, struct rde_nbr *new)
struct rde_nbr_head *head;
struct rde_nbr *nbr;
struct area *area;
+ struct iface *iface;
if (rde_nbr_find(peerid))
return (NULL);
if ((area = area_find(rdeconf, new->area_id)) == NULL)
fatalx("rde_nbr_new: unknown area");
+ LIST_FOREACH(iface, &area->iface_list, entry) {
+ if (iface->ifindex == new->ifindex)
+ break;
+ }
+ if (iface == NULL)
+ fatalx("rde_nbr_new: unknown interface");
+
if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
fatal("rde_nbr_new");
memcpy(nbr, new, sizeof(*nbr));
nbr->peerid = peerid;
nbr->area = area;
+ nbr->iface = iface;
TAILQ_INIT(&nbr->req_list);
diff --git a/usr.sbin/ospf6d/rde.h b/usr.sbin/ospf6d/rde.h
index d1a1f745a58..6796b087d30 100644
--- a/usr.sbin/ospf6d/rde.h
+++ b/usr.sbin/ospf6d/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.3 2007/10/16 12:05:52 norby Exp $ */
+/* $OpenBSD: rde.h,v 1.4 2007/11/27 11:29:34 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -67,7 +67,9 @@ struct rde_nbr {
struct in_addr area_id;
TAILQ_HEAD(, rde_req_entry) req_list;
struct area *area;
+ struct iface *iface;
u_int32_t peerid; /* unique ID in DB */
+ unsigned int ifindex;
int state;
int self;
};
diff --git a/usr.sbin/ospf6d/rde_lsdb.c b/usr.sbin/ospf6d/rde_lsdb.c
index b8a0a95e749..c78e7719c9c 100644
--- a/usr.sbin/ospf6d/rde_lsdb.c
+++ b/usr.sbin/ospf6d/rde_lsdb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_lsdb.c,v 1.6 2007/11/24 16:42:58 claudio Exp $ */
+/* $OpenBSD: rde_lsdb.c,v 1.7 2007/11/27 11:29:34 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
@@ -29,10 +29,12 @@
struct vertex *vertex_get(struct lsa *, struct rde_nbr *);
-int lsa_router_check(struct lsa *, u_int16_t);
+int lsa_link_check(struct lsa *, u_int16_t);
+int lsa_intra_a_pref_check(struct lsa *, u_int16_t);
void lsa_timeout(int, short, void *);
void lsa_refresh(struct vertex *);
int lsa_equal(struct lsa *, struct lsa *);
+int lsa_get_prefix(void *, u_int16_t, struct lsa_prefix *);
RB_GENERATE(lsa_tree, vertex, entry, lsa_compare)
@@ -187,34 +189,59 @@ lsa_check(struct rde_nbr *nbr, struct lsa *lsa, u_int16_t len)
switch (ntohs(lsa->hdr.type)) {
case LSA_TYPE_LINK:
- /* XXX */
+ if (!lsa_link_check(lsa, len))
+ return (0);
break;
case LSA_TYPE_ROUTER:
- if (!lsa_router_check(lsa, len))
+ if (len < sizeof(lsa->hdr) + sizeof(struct lsa_rtr)) {
+ log_warnx("lsa_check: bad LSA rtr packet");
+ return (0);
+ }
+ len -= sizeof(lsa->hdr) + sizeof(struct lsa_rtr);
+ if (len % sizeof(struct lsa_rtr_link)) {
+ log_warnx("lsa_check: bad LSA rtr packet");
return (0);
+ }
break;
case LSA_TYPE_NETWORK:
if ((len % sizeof(u_int32_t)) ||
len < sizeof(lsa->hdr) + sizeof(u_int32_t)) {
- log_warnx("lsa_check: bad LSA network packet");
return (0);
}
break;
case LSA_TYPE_INTER_A_PREFIX:
+ if (len < sizeof(lsa->hdr) + sizeof(lsa->data.pref_sum)) {
+ log_warnx("lsa_check: bad LSA prefix summary packet");
+ return (0);
+ }
+ metric = ntohl(lsa->data.pref_sum.metric);
+ if (metric & ~LSA_METRIC_MASK) {
+ log_warnx("lsa_check: bad LSA summary metric");
+ return (0);
+ }
+ if (lsa_get_prefix(((char *)lsa) + sizeof(lsa->hdr) +
+ sizeof(lsa->data.pref_sum),
+ len - sizeof(lsa->hdr) + sizeof(lsa->data.pref_sum),
+ NULL) == -1) {
+ log_warnx("lsa_check: "
+ "invalid LSA prefix summary packet");
+ return (0);
+ }
+ break;
case LSA_TYPE_INTER_A_ROUTER:
- if ((len % sizeof(u_int32_t)) ||
- len < sizeof(lsa->hdr) + sizeof(lsa->data.sum)) {
- log_warnx("lsa_check: bad LSA summary packet");
+ if (len < sizeof(lsa->hdr) + sizeof(lsa->data.rtr_sum)) {
+ log_warnx("lsa_check: bad LSA router summary packet");
return (0);
}
- metric = ntohl(lsa->data.sum.metric);
+ metric = ntohl(lsa->data.rtr_sum.metric);
if (metric & ~LSA_METRIC_MASK) {
log_warnx("lsa_check: bad LSA summary metric");
return (0);
}
break;
case LSA_TYPE_INTRA_A_PREFIX:
- /* XXX */
+ if (!lsa_intra_a_pref_check(lsa, len))
+ return (0);
break;
case LSA_TYPE_EXTERNAL:
if ((len % (3 * sizeof(u_int32_t))) ||
@@ -232,7 +259,7 @@ lsa_check(struct rde_nbr *nbr, struct lsa *lsa, u_int16_t len)
return (0);
break;
default:
- log_warnx("lsa_check: unknown type %u", ntohs(lsa->hdr.type));
+ log_warnx("lsa_check: unknown type %x", ntohs(lsa->hdr.type));
return (0);
}
@@ -253,34 +280,67 @@ lsa_check(struct rde_nbr *nbr, struct lsa *lsa, u_int16_t len)
}
int
-lsa_router_check(struct lsa *lsa, u_int16_t len)
+lsa_link_check(struct lsa *lsa, u_int16_t len)
{
- struct lsa_rtr_link *rtr_link;
char *buf = (char *)lsa;
- u_int16_t i, off, nlinks;
+ struct lsa_link *llink;
+ u_int32_t i, off, npref;
+ int rv;
- off = sizeof(lsa->hdr) + sizeof(struct lsa_rtr);
+ llink = (struct lsa_link *)(buf + sizeof(lsa->hdr));
+ off = sizeof(lsa->hdr) + sizeof(struct lsa_link);
if (off > len) {
- log_warnx("lsa_check: invalid LSA router packet");
+ log_warnx("lsa_link_check: invalid LSA link packet, "
+ "short header");
return (0);
}
- nlinks = (len - off) / 16; /* XXX way to go ? */
-
- for (i = 0; i < nlinks; i++) {
- rtr_link = (struct lsa_rtr_link *)(buf + off);
- off += sizeof(struct lsa_rtr_link);
+ len -= off;
+ npref = ntohl(llink->numprefix);
- if (off > len) {
- log_warnx("lsa_check: invalid LSA router packet");
+ for (i = 0; i < npref; i++) {
+ rv = lsa_get_prefix(buf + off, len, NULL);
+ if (rv == -1) {
+ log_warnx("lsa_link_check: invalid LSA link packet");
return (0);
}
+ off += rv;
+ len -= rv;
}
- if (i != nlinks) {
- log_warnx("lsa_check: invalid LSA router packet");
+ return (1);
+}
+
+int
+lsa_intra_a_pref_check(struct lsa *lsa, u_int16_t len)
+{
+ char *buf = (char *)lsa;
+ struct lsa_intra_prefix *iap;
+ u_int32_t i, off, npref;
+ int rv;
+
+ iap = (struct lsa_intra_prefix *)(buf + sizeof(lsa->hdr));
+ off = sizeof(lsa->hdr) + sizeof(struct lsa_intra_prefix);
+ if (off > len) {
+ log_warnx("lsa_intra_a_pref_check: "
+ "invalid LSA intra area prefix packet, short header");
return (0);
}
+
+ len -= off;
+ npref = ntohl(iap->numprefix);
+
+ for (i = 0; i < npref; i++) {
+ rv = lsa_get_prefix(buf + off, len, NULL);
+ if (rv == -1) {
+ log_warnx("lsa_intra_a_pref_check: "
+ "invalid LSA intra area prefix packet");
+ return (0);
+ }
+ off += rv;
+ len -= rv;
+ }
+
return (1);
}
@@ -343,10 +403,14 @@ lsa_add(struct rde_nbr *nbr, struct lsa *lsa)
struct vertex *new, *old;
struct timeval tv, now, res;
- if (ntohs(lsa->hdr.type) == LSA_TYPE_EXTERNAL)
+ if (LSA_IS_SCOPE_AS(ntohs(lsa->hdr.type)))
tree = &asext_tree;
- else
+ else if (LSA_IS_SCOPE_AREA(ntohs(lsa->hdr.type)))
tree = &nbr->area->lsa_tree;
+ else if (LSA_IS_SCOPE_LLOCAL(ntohs(lsa->hdr.type)))
+ tree = &nbr->iface->lsa_tree;
+ else
+ fatalx("unknown scope type");
new = vertex_get(lsa, nbr);
old = RB_INSERT(lsa_tree, tree, new);
@@ -516,12 +580,13 @@ lsa_snap(struct area *area, u_int32_t peerid)
if (v->deleted)
continue;
lsa_age(v);
- if (ntohs(v->lsa->hdr.age) >= MAX_AGE)
+ if (ntohs(v->lsa->hdr.age) >= MAX_AGE) {
rde_imsg_compose_ospfe(IMSG_LS_UPD, peerid,
0, &v->lsa->hdr, ntohs(v->lsa->hdr.len));
- else
+ } else {
rde_imsg_compose_ospfe(IMSG_DB_SNAPSHOT, peerid,
0, &v->lsa->hdr, sizeof(struct lsa_hdr));
+ }
}
if (tree != &area->lsa_tree)
break;
@@ -740,3 +805,36 @@ lsa_equal(struct lsa *a, struct lsa *b)
return (1);
}
+int
+lsa_get_prefix(void *buf, u_int16_t len, struct lsa_prefix *p)
+{
+ u_int32_t *buf32 = buf;
+ u_int32_t *addr = NULL;
+ u_int8_t prefixlen;
+
+ if (len < sizeof(u_int32_t))
+ return (-1);
+
+ prefixlen = ntohl(*buf32) >> 24;
+
+ if (p) {
+ bzero(p, sizeof(*p));
+ p->prefixlen = prefixlen;
+ p->options = (ntohl(*buf32) >> 16) & 0xff;
+ p->metric = *buf32 & 0xffff;
+ addr = (u_int32_t *)&p->prefix;
+ }
+ buf32++;
+ len -= sizeof(u_int32_t);
+
+ for (; ((prefixlen + 31) / 32) > 0; prefixlen -= 32) {
+ if (len < sizeof(u_int32_t))
+ return (-1);
+ if (addr)
+ *addr++ = *buf32++;
+ len -= sizeof(u_int32_t);
+ }
+
+ return (len);
+}
+