summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/dvmrpd/dvmrpd.h4
-rw-r--r--usr.sbin/dvmrpd/parse.y3
-rw-r--r--usr.sbin/dvmrpd/rde.c4
-rw-r--r--usr.sbin/dvmrpd/rde.h29
-rw-r--r--usr.sbin/dvmrpd/rde_srt.c281
5 files changed, 299 insertions, 22 deletions
diff --git a/usr.sbin/dvmrpd/dvmrpd.h b/usr.sbin/dvmrpd/dvmrpd.h
index c34a3e5c045..335db3a787c 100644
--- a/usr.sbin/dvmrpd/dvmrpd.h
+++ b/usr.sbin/dvmrpd/dvmrpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dvmrpd.h,v 1.5 2006/12/03 20:14:37 michele Exp $ */
+/* $OpenBSD: dvmrpd.h,v 1.6 2007/03/21 19:33:48 michele Exp $ */
/*
* Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
@@ -188,6 +188,7 @@ struct mfc {
};
TAILQ_HEAD(rr_head, rr_entry);
+RB_HEAD(src_head, src_node);
struct iface {
LIST_ENTRY(iface) entry;
@@ -261,6 +262,7 @@ struct dvmrpd_conf {
#define DVMRPD_OPT_NOACTION 0x00000004
int maxdepth;
LIST_HEAD(, iface) iface_list;
+ struct src_head src_list;
int dvmrp_socket;
int mroute_socket;
int flags;
diff --git a/usr.sbin/dvmrpd/parse.y b/usr.sbin/dvmrpd/parse.y
index e5fcbd948e3..b521adad2a1 100644
--- a/usr.sbin/dvmrpd/parse.y
+++ b/usr.sbin/dvmrpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.3 2006/10/25 18:55:41 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.4 2007/03/21 19:33:48 michele Exp $ */
/*
* Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
@@ -631,6 +631,7 @@ parse_config(char *filename, int opts)
gettimeofday(&now, NULL);
conf->gen_id = now.tv_sec;
conf->opts = opts;
+ RB_INIT(&conf->src_list);
if (check_file_secrecy(fileno(fin), filename)) {
fclose(fin);
diff --git a/usr.sbin/dvmrpd/rde.c b/usr.sbin/dvmrpd/rde.c
index 5b3cc2dd0e1..af3823f9753 100644
--- a/usr.sbin/dvmrpd/rde.c
+++ b/usr.sbin/dvmrpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.4 2007/01/24 09:57:51 norby Exp $ */
+/* $OpenBSD: rde.c,v 1.5 2007/03/21 19:33:48 michele Exp $ */
/*
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
@@ -234,7 +234,7 @@ rde_dispatch_imsg(int fd, short event, void *bula)
if (imsg.hdr.peerid == 0)
connected = 1;
- if (rde_check_route(&rr, connected) == -1)
+ if (srt_check_route(&rr, connected) == -1)
log_debug("rde_dispatch_imsg: "
"packet malformed");
break;
diff --git a/usr.sbin/dvmrpd/rde.h b/usr.sbin/dvmrpd/rde.h
index ce8a01249ff..dd3f8f2e756 100644
--- a/usr.sbin/dvmrpd/rde.h
+++ b/usr.sbin/dvmrpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.2 2006/12/03 20:14:37 michele Exp $ */
+/* $OpenBSD: rde.h,v 1.3 2007/03/21 19:33:48 michele Exp $ */
/*
* Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
@@ -29,9 +29,9 @@
struct rt_node {
RB_ENTRY(rt_node) entry;
struct event expiration_timer;
+ u_int8_t ttls[MAXVIFS]; /* downstream vif(s) */
struct in_addr prefix;
struct in_addr nexthop;
- struct in_addr adv_rtr;
u_int32_t cost;
u_short ifindex; /* learned from this iface */
time_t uptime;
@@ -51,6 +51,25 @@ struct mfc_node {
time_t uptime;
};
+struct ds {
+ LIST_ENTRY(ds) entry;
+ struct in_addr addr;
+};
+
+struct adv_rtr {
+ struct in_addr addr;
+ u_int32_t metric;
+};
+
+struct src_node {
+ RB_ENTRY(src_node) entry;
+ struct in_addr origin;
+ struct in_addr mask;
+ struct adv_rtr adv_rtr[MAXVIFS];
+ u_int16_t ds_cnt[MAXVIFS];
+ LIST_HEAD(, ds) ds_list;
+};
+
/* rde.c */
pid_t rde(struct dvmrpd_conf *, int [2], int [2], int [2]);
int rde_imsg_compose_parent(int, pid_t, void *, u_int16_t);
@@ -78,6 +97,10 @@ int rt_remove(struct rt_node *);
void rt_clear(void);
void rt_snap(u_int32_t);
void rt_dump(pid_t);
-int rde_check_route(struct route_report *, int);
+
+int srt_check_route(struct route_report *, int);
+int src_compare(struct src_node *, struct src_node *);
+
+RB_PROTOTYPE(src_head, src_node, entry, src_compare);
#endif /* _RDE_H_ */
diff --git a/usr.sbin/dvmrpd/rde_srt.c b/usr.sbin/dvmrpd/rde_srt.c
index 8b09754df6c..2575252a77a 100644
--- a/usr.sbin/dvmrpd/rde_srt.c
+++ b/usr.sbin/dvmrpd/rde_srt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_srt.c,v 1.3 2007/01/29 13:38:59 michele Exp $ */
+/* $OpenBSD: rde_srt.c,v 1.4 2007/03/21 19:33:48 michele Exp $ */
/*
* Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
@@ -23,6 +23,7 @@
#include <arpa/inet.h>
#include <err.h>
#include <stdlib.h>
+#include <string.h>
#include "igmp.h"
#include "dvmrp.h"
@@ -37,10 +38,31 @@ void rt_invalidate(void);
void rt_expire_timer(int, short, void *);
int rt_start_expire_timer(struct rt_node *);
+void srt_set_upstream(struct rt_node *, u_int32_t);
+
+/* Designated forwarder */
+void srt_set_forwarder_self(struct src_node *, struct iface *,
+ struct rt_node *);
+void srt_update_ds_forwarders(struct src_node *, struct rt_node *,
+ struct iface *, u_int32_t);
+void srt_current_forwarder(struct src_node *, struct rt_node *,
+ struct iface *, u_int32_t, u_int32_t);
+
+void srt_add_ds(struct src_node *, struct rt_node *, u_int32_t,
+ u_int32_t);
+struct ds *srt_find_ds(struct src_node *, u_int32_t);
+void srt_delete_ds(struct src_node *, struct rt_node *, struct ds *,
+ struct iface *);
+struct src_node *srt_find_src(struct in_addr, struct in_addr);
+struct src_node *srt_add_src(struct in_addr, struct in_addr);
+void srt_delete_src(struct src_node *);
+
RB_HEAD(rt_tree, rt_node) rt;
RB_PROTOTYPE(rt_tree, rt_node, entry, rt_compare)
RB_GENERATE(rt_tree, rt_node, entry, rt_compare)
+RB_GENERATE(src_head, src_node, entry, src_compare);
+
extern struct dvmrpd_conf *rdeconf;
/* timers */
@@ -95,6 +117,20 @@ rt_compare(struct rt_node *a, struct rt_node *b)
return (0);
}
+int
+src_compare(struct src_node *a, struct src_node *b)
+{
+ if (ntohl(a->origin.s_addr) < ntohl(b->origin.s_addr))
+ return (-1);
+ if (ntohl(a->origin.s_addr) > ntohl(b->origin.s_addr))
+ return (1);
+ if (ntohl(a->mask.s_addr) < ntohl(b->mask.s_addr))
+ return (-1);
+ if (ntohl(a->mask.s_addr) > ntohl(b->mask.s_addr))
+ return (1);
+ return (0);
+}
+
struct rt_node *
rt_find(in_addr_t prefix, u_int8_t prefixlen)
{
@@ -111,6 +147,7 @@ rr_new_rt(struct route_report *rr, int adj_metric, int connected)
{
struct timespec now;
struct rt_node *rn;
+ int i;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -122,6 +159,10 @@ rr_new_rt(struct route_report *rr, int adj_metric, int connected)
rn->nexthop.s_addr = rr->nexthop.s_addr;
rn->cost = adj_metric;
rn->ifindex = rr->ifindex;
+
+ for (i = 0; i < MAXVIFS; i++)
+ rn->ttls[i] = 0;
+
rn->flags = F_DVMRPD_INSERTED;
rn->connected = connected;
rn->uptime = now.tv_sec;
@@ -215,7 +256,6 @@ rt_dump(pid_t pid)
rtctl.prefix.s_addr = r->prefix.s_addr;
rtctl.nexthop.s_addr = r->nexthop.s_addr;
- rtctl.adv_rtr.s_addr = r->adv_rtr.s_addr;
rtctl.cost = r->cost;
rtctl.flags = r->flags;
rtctl.prefixlen = r->prefixlen;
@@ -241,16 +281,20 @@ rt_update(struct rt_node *rn)
}
int
-rde_check_route(struct route_report *rr, int connected)
+srt_check_route(struct route_report *rr, int connected)
{
struct rt_node *rn;
struct iface *iface;
+ struct src_node *src;
+ struct ds *ds_nbr;
u_int32_t adj_metric;
- u_int32_t nbr_ip, nbr_report;
+ u_int32_t nbr_ip, nbr_report, ifindex;
if ((iface = if_find_index(rr->ifindex)) == NULL)
return (-1);
+ ifindex = iface->ifindex;
+
/* Interpret special case 0.0.0.0/8 as 0.0.0.0/0 */
if (rr->net.s_addr == 0)
rr->mask.s_addr = 0;
@@ -270,35 +314,242 @@ rde_check_route(struct route_report *rr, int connected)
if (adj_metric < INFINITY_METRIC) {
rn = rr_new_rt(rr, adj_metric, connected);
rt_insert(rn);
+ src = srt_add_src(rr->net, rr->mask);
}
return (0);
}
- nbr_ip = rr->nexthop.s_addr;
- nbr_report = rn->nexthop.s_addr;
+ nbr_ip = rn->nexthop.s_addr;
+ nbr_report = rr->nexthop.s_addr;
+
+ if ((src = srt_find_src(rr->net, rr->mask)) == NULL)
+ fatal("srt_check_route");
if (rr->metric < INFINITY_METRIC) {
- if (adj_metric > rn->cost) {
- if (nbr_ip == nbr_report) {
- rn->cost = adj_metric;
- }
+ /* If it is our current nexthop it cannot be a
+ * downstream router */
+ if (nbr_ip != nbr_report)
+ if ((ds_nbr = srt_find_ds(src, nbr_report)))
+ srt_delete_ds(src, rn, ds_nbr, iface);
+
+ if (adj_metric > rn->cost) {
+ if (nbr_ip == nbr_report)
+ rn->cost = adj_metric;
} else if (adj_metric < rn->cost) {
rn->cost = adj_metric;
- if (nbr_ip != nbr_report)
+ if (nbr_ip != nbr_report) {
rn->nexthop.s_addr = nbr_report;
+ srt_set_upstream(rn, ifindex);
+ }
+ /* We have a new best route to source, update the
+ * designated forwarders on downstream interfaces to
+ * reflect the new metric */
+ srt_update_ds_forwarders(src, rn, iface, nbr_report);
} else {
- if (nbr_report < nbr_ip)
+ if (nbr_report < nbr_ip) {
rn->nexthop.s_addr = nbr_report;
+ srt_set_upstream(rn, ifindex);
+ }
}
+ /* Update forwarder of current interface if necessary and
+ * refresh the route */
+ srt_current_forwarder(src, rn, iface, rr->metric, nbr_report);
rt_update(rn);
} else if (rr->metric == INFINITY_METRIC) {
+ if (nbr_report == src->adv_rtr[ifindex].addr.s_addr)
+ srt_set_forwarder_self(src, iface, rn);
+infinity:
if (nbr_ip == nbr_report) {
- rt_remove(rn);
- }
+ if (rn->cost < INFINITY_METRIC) {
+ rt_remove(rn);
+ srt_delete_src(src);
+ }
+ } else
+ if ((ds_nbr = srt_find_ds(src, nbr_report)))
+ srt_delete_ds(src, rn, ds_nbr, iface);
} else if (INFINITY_METRIC < rr->metric &&
rr->metric < 2 * INFINITY_METRIC) {
- /* XXX */
+ /* Neighbor is reporting his depenency for that source */
+ if (nbr_report == src->adv_rtr[ifindex].addr.s_addr)
+ srt_set_forwarder_self(src, iface, rn);
+
+ if (rn->ifindex == ifindex)
+ goto infinity;
+ else
+ if (srt_find_ds(src, nbr_report) == NULL)
+ srt_add_ds(src, rn, nbr_report, ifindex);
}
return (0);
}
+
+void
+srt_current_forwarder(struct src_node *src_node, struct rt_node *rn,
+ struct iface *iface, u_int32_t metric, u_int32_t nbr_report)
+{
+ if (nbr_report == src_node->adv_rtr[iface->ifindex].addr.s_addr) {
+ if (metric > rn->cost || (metric == rn->cost &&
+ iface->addr.s_addr < nbr_report)) {
+ src_node->adv_rtr[iface->ifindex].addr.s_addr =
+ iface->addr.s_addr;
+ src_node->adv_rtr[iface->ifindex].metric = rn->cost;
+
+ /* XXX: check if there are groups with this source */
+ if (group_list_empty(iface))
+ rn->ttls[iface->ifindex] = 1;
+ }
+ } else if (metric < src_node->adv_rtr[iface->ifindex].metric ||
+ (metric == src_node->adv_rtr[iface->ifindex].metric &&
+ nbr_report < src_node->adv_rtr[iface->ifindex].addr.s_addr)) {
+ if (src_node->adv_rtr[iface->ifindex].addr.s_addr ==
+ iface->addr.s_addr && !src_node->ds_cnt[iface->ifindex])
+ rn->ttls[iface->ifindex] = 0;
+
+ src_node->adv_rtr[iface->ifindex].addr.s_addr = nbr_report;
+ src_node->adv_rtr[iface->ifindex].metric = metric;
+ }
+}
+
+void
+srt_update_ds_forwarders(struct src_node *src_node, struct rt_node *rn,
+ struct iface *iface, u_int32_t nbr_report)
+{
+ struct iface *ifa;
+ int i;
+
+ for (i = 0; i < MAXVIFS; i++) {
+ if (src_node->adv_rtr[i].addr.s_addr &&
+ (rn->cost < src_node->adv_rtr[i].metric ||
+ (rn->cost == src_node->adv_rtr[i].metric &&
+ iface->addr.s_addr < nbr_report))) {
+ ifa = if_find_index(i);
+ src_node->adv_rtr[i].metric = rn->cost;
+ src_node->adv_rtr[i].addr.s_addr = iface->addr.s_addr;
+
+ /* XXX: check if there are groups with this source */
+ if (group_list_empty(ifa))
+ rn->ttls[i] = 1;
+ }
+ }
+}
+
+void
+srt_set_forwarder_self(struct src_node *src, struct iface *iface,
+ struct rt_node *rn)
+{
+ src->adv_rtr[iface->ifindex].addr.s_addr = iface->addr.s_addr;
+ src->adv_rtr[iface->ifindex].metric = rn->cost;
+
+ /* XXX: check if there are groups with this source */
+ if (group_list_empty(iface))
+ rn->ttls[iface->ifindex] = 1;
+}
+
+void
+srt_set_upstream(struct rt_node *rn, u_int32_t ifindex)
+{
+ if (rn->ifindex != ifindex) {
+ rn->ttls[rn->ifindex] = 1;
+ rn->ifindex = ifindex;
+ }
+}
+
+void
+srt_add_ds(struct src_node *src_node, struct rt_node *rn, u_int32_t nbr_report,
+ u_int32_t ifindex)
+{
+ struct ds *ds_nbr;
+
+ if ((ds_nbr = malloc(sizeof(struct ds))) == NULL)
+ fatal("srt_add_ds");
+
+ ds_nbr->addr.s_addr = nbr_report;
+
+ LIST_INSERT_HEAD(&src_node->ds_list, ds_nbr, entry);
+ src_node->ds_cnt[ifindex]++;
+ rn->ttls[ifindex] = 1;
+}
+
+struct ds *
+srt_find_ds(struct src_node *src_node, u_int32_t nbr_report)
+{
+ struct ds *ds_nbr;
+
+ LIST_FOREACH(ds_nbr, &src_node->ds_list, entry)
+ if (ds_nbr->addr.s_addr == nbr_report)
+ return (ds_nbr);
+
+ return (NULL);
+}
+
+void
+srt_delete_ds(struct src_node *src_node, struct rt_node *rn, struct ds *ds_nbr,
+ struct iface *iface)
+{
+ LIST_REMOVE(ds_nbr, entry);
+ free(ds_nbr);
+ src_node->ds_cnt[iface->ifindex]--;
+
+ /* XXX: check if there are group with this source */
+ if (!src_node->ds_cnt[iface->ifindex] && group_list_empty(iface))
+ rn->ttls[iface->ifindex] = 0;
+}
+
+struct src_node *
+srt_find_src(struct in_addr net, struct in_addr mask)
+{
+ struct src_node *src_node;
+
+ RB_FOREACH(src_node, src_head, &rdeconf->src_list)
+ if (src_node->origin.s_addr == net.s_addr &&
+ src_node->mask.s_addr == mask.s_addr)
+ return (src_node);
+
+ return (NULL);
+}
+
+struct src_node *
+srt_add_src(struct in_addr net, struct in_addr mask)
+{
+ struct src_node *src_node;
+ struct iface *iface;
+ u_int32_t i;
+
+ if ((src_node = malloc(sizeof(struct src_node))) == NULL)
+ fatal("srt_add_src");
+
+ src_node->origin.s_addr = net.s_addr;
+ src_node->mask.s_addr = mask.s_addr;
+
+ for (i = 0; i < MAXVIFS; i++) {
+ bzero(&src_node->adv_rtr[i], sizeof(struct adv_rtr));
+ src_node->ds_cnt[i] = 0;
+ }
+
+ LIST_FOREACH(iface, &rdeconf->iface_list, entry)
+ for (i = 0; i < MAXVIFS; i++)
+ if (iface->ifindex == i) {
+ src_node->adv_rtr[i].addr.s_addr =
+ iface->addr.s_addr;
+ break;
+ }
+
+ LIST_INIT(&src_node->ds_list);
+ RB_INSERT(src_head, &rdeconf->src_list, src_node);
+
+ return (src_node);
+}
+
+void
+srt_delete_src(struct src_node *src_node)
+{
+ struct ds *ds_nbr;
+
+ LIST_FOREACH(ds_nbr, &src_node->ds_list, entry) {
+ LIST_REMOVE(ds_nbr, entry);
+ free(ds_nbr);
+ }
+
+ RB_REMOVE(src_head, &rdeconf->src_list, src_node);
+ free(src_node);
+}