diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2007-11-27 11:29:35 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2007-11-27 11:29:35 +0000 |
commit | 46b3cdc6bb6bf33b0c4e39472b98f8cb224ebbdc (patch) | |
tree | 0aed944affe4303faea8f6f36b2f625a1d5d9f50 | |
parent | 8159ded805fca63dccb4cfb60ebd609f9039d19d (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.c | 3 | ||||
-rw-r--r-- | usr.sbin/ospf6d/neighbor.c | 3 | ||||
-rw-r--r-- | usr.sbin/ospf6d/ospf6.h | 51 | ||||
-rw-r--r-- | usr.sbin/ospf6d/ospf6d.h | 4 | ||||
-rw-r--r-- | usr.sbin/ospf6d/ospfe.c | 3 | ||||
-rw-r--r-- | usr.sbin/ospf6d/rde.c | 12 | ||||
-rw-r--r-- | usr.sbin/ospf6d/rde.h | 4 | ||||
-rw-r--r-- | usr.sbin/ospf6d/rde_lsdb.c | 156 |
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); +} + |