summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Marchetto <michele@cvs.openbsd.org>2009-09-06 09:52:15 +0000
committerMichele Marchetto <michele@cvs.openbsd.org>2009-09-06 09:52:15 +0000
commit3facc6da357ea27fa205af3b8c1ea870e0af2a28 (patch)
treeb233e737023af7b6604b978d7c59aa4f39ef52e2
parentf77080228e4c6c599926bf9750366c6b9f3021f9 (diff)
When dvmrpd receives a prune, it must checks if every downstream member
on that interfaces has already sent prunes. If so (and there are no local groups) removes the interface from the downstream list. ok claudio@
-rw-r--r--usr.sbin/dvmrpd/rde.c5
-rw-r--r--usr.sbin/dvmrpd/rde.h22
-rw-r--r--usr.sbin/dvmrpd/rde_mfc.c149
-rw-r--r--usr.sbin/dvmrpd/rde_srt.c3
4 files changed, 170 insertions, 9 deletions
diff --git a/usr.sbin/dvmrpd/rde.c b/usr.sbin/dvmrpd/rde.c
index 97000ff082a..301bb443410 100644
--- a/usr.sbin/dvmrpd/rde.c
+++ b/usr.sbin/dvmrpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.20 2009/06/06 07:52:04 pyr Exp $ */
+/* $OpenBSD: rde.c,v 1.21 2009/09/06 09:52:14 michele Exp $ */
/*
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
@@ -303,14 +303,15 @@ rde_dispatch_imsg(int fd, short event, void *bula)
fatalx("invalid size of OE request");
memcpy(&nm, imsg.data, sizeof(nm));
- srt_expire_nbr(nm.address, nm.ifindex);
+ srt_expire_nbr(nm.address, nm.ifindex);
break;
case IMSG_RECV_PRUNE:
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(p))
fatalx("invalid size of OE request");
memcpy(&p, imsg.data, sizeof(p));
+ mfc_recv_prune(&p);
break;
default:
log_debug("rde_dispatch_msg: unexpected imsg %d",
diff --git a/usr.sbin/dvmrpd/rde.h b/usr.sbin/dvmrpd/rde.h
index aea9a2c04e2..659319494c3 100644
--- a/usr.sbin/dvmrpd/rde.h
+++ b/usr.sbin/dvmrpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.15 2009/04/16 20:11:12 michele Exp $ */
+/* $OpenBSD: rde.h,v 1.16 2009/09/06 09:52:14 michele Exp $ */
/*
* Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
@@ -57,15 +57,29 @@ struct rt_node {
u_int8_t connected;
};
+struct prune_node {
+ LIST_ENTRY(prune_node) entry;
+ struct event lifetime_timer;
+
+ struct mfc_node *parent; /* back ptr to mfc_node */
+
+ struct in_addr nbr;
+ unsigned int ifindex;
+};
+
struct mfc_node {
RB_ENTRY(mfc_node) entry;
struct event expiration_timer;
struct event prune_timer;
+
+ LIST_HEAD(, prune_node) prune_list;
+
struct in_addr origin;
struct in_addr group;
time_t uptime;
- u_short ifindex; /* incoming vif */
- u_int8_t ttls[MAXVIFS]; /* outgoing vif(s) */
+ u_short ifindex; /* incoming vif */
+ u_int8_t ttls[MAXVIFS]; /* outgoing vif(s) */
+ u_int8_t prune_cnt[MAXVIFS];
};
/* downstream neighbor per source */
@@ -96,6 +110,7 @@ void mfc_delete(struct mfc *);
struct rt_node *mfc_find_origin(struct in_addr);
void mfc_update_source(struct rt_node *);
int mfc_check_members(struct rt_node *, struct iface *);
+void mfc_recv_prune(struct prune *);
/* rde_srt.c */
void rt_init(void);
@@ -113,6 +128,7 @@ struct rt_node *rt_match_origin(in_addr_t);
int srt_check_route(struct route_report *, int);
int src_compare(struct src_node *, struct src_node *);
+struct ds_nbr *srt_find_ds(struct rt_node *, u_int32_t);
void srt_expire_nbr(struct in_addr, unsigned int);
void srt_check_downstream_ifaces(struct rt_node *, struct iface *);
diff --git a/usr.sbin/dvmrpd/rde_mfc.c b/usr.sbin/dvmrpd/rde_mfc.c
index 69e1e29fb90..a36e378916a 100644
--- a/usr.sbin/dvmrpd/rde_mfc.c
+++ b/usr.sbin/dvmrpd/rde_mfc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_mfc.c,v 1.6 2009/07/13 18:58:46 michele Exp $ */
+/* $OpenBSD: rde_mfc.c,v 1.7 2009/09/06 09:52:14 michele Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -35,7 +35,16 @@
/* multicast forwarding cache */
-void mfc_send_prune(struct rt_node *, struct mfc_node *);
+void mfc_send_prune(struct rt_node *, struct mfc_node *);
+void mfc_add_prune(struct mfc_node *, struct prune *);
+struct prune_node *mfc_find_prune(struct mfc_node *, struct prune *);
+void mfc_delete_prune(struct mfc_node *,
+ struct prune_node *);
+
+int prune_compare(struct mfc_node *, struct rt_node *, int);
+void prune_expire_timer(int, short, void *);
+int mfc_reset_prune_expire_timer(struct prune_node *);
+
void mfc_expire_timer(int, short, void *);
int mfc_start_expire_timer(struct mfc_node *);
@@ -371,3 +380,139 @@ mfc_check_members(struct rt_node *rn, struct iface *iface)
return (0);
}
+
+void
+mfc_recv_prune(struct prune *p)
+{
+ struct rt_node *rn;
+ struct mfc_node *mn;
+ struct prune_node *pn;
+ struct iface *iface;
+ struct mfc m;
+
+ iface = if_find_index(p->ifindex);
+ if (iface == NULL) {
+ log_debug("mfc_recv_prune: unknown interface");
+ return;
+ }
+
+ rn = rt_match_origin(p->origin.s_addr);
+ if (rn == NULL) {
+ log_debug("mfc_recv_prune: no information for %s\n",
+ inet_ntoa(p->origin));
+ return;
+ }
+
+ if (srt_find_ds(rn, p->nexthop.s_addr) == NULL) {
+ log_debug("mfc_recv_prune: prune received from a "
+ "non downstream neighbor\n");
+ return;
+ }
+
+ mn = mfc_find(p->origin.s_addr, p->group.s_addr);
+ if (mn) {
+ log_debug("mfc_recv_prune: no information for %s\n",
+ inet_ntoa(p->origin));
+ return;
+ }
+
+ pn = mfc_find_prune(mn, p);
+ if (pn == NULL) {
+ mfc_add_prune(mn, p);
+ if (prune_compare(mn, rn, p->ifindex) &&
+ !rde_group_list_find(iface, p->group)) {
+ mn->ttls[p->ifindex] = 0;
+
+ m.ifindex = p->ifindex;
+ m.origin.s_addr = p->origin.s_addr;
+ m.group.s_addr = p->group.s_addr;
+ mfc_update(&m);
+ }
+ } else
+ mfc_reset_prune_expire_timer(pn);
+}
+
+void
+mfc_add_prune(struct mfc_node *mn, struct prune *p)
+{
+ struct prune_node *pn;
+ struct timeval tv;
+
+ pn = calloc(1, sizeof(struct prune));
+ if (pn == NULL)
+ fatal("prune_add");
+
+ timerclear(&tv);
+ tv.tv_sec = MAX_PRUNE_LIFETIME;
+
+ pn->nbr.s_addr = p->nexthop.s_addr;
+ pn->ifindex = p->ifindex;
+ pn->parent = mn;
+
+ evtimer_set(&pn->lifetime_timer, prune_expire_timer, pn);
+ evtimer_add(&pn->lifetime_timer, &tv);
+
+ LIST_INSERT_HEAD(&mn->prune_list, pn, entry);
+
+ mn->prune_cnt[p->ifindex]++;
+}
+
+struct prune_node *
+mfc_find_prune(struct mfc_node *mn, struct prune *p)
+{
+ struct prune_node *pn;
+
+ LIST_FOREACH(pn, &mn->prune_list, entry) {
+ if (p->nexthop.s_addr == pn->nbr.s_addr)
+ return (pn);
+ }
+
+ return (NULL);
+}
+
+void
+mfc_delete_prune(struct mfc_node *mn, struct prune_node *pn)
+{
+ unsigned int ifindex = pn->ifindex;
+
+ if (evtimer_pending(&pn->lifetime_timer, NULL))
+ if (evtimer_del(&pn->lifetime_timer) == -1)
+ fatal("mfc_delete_prune");
+
+ LIST_REMOVE(pn, entry);
+ free(pn);
+ mn->prune_cnt[ifindex]--;
+}
+
+int
+prune_compare(struct mfc_node *mn, struct rt_node *rn, int ifindex)
+{
+ if (mn->prune_cnt[ifindex] == rn->ds_cnt[ifindex])
+ return (1);
+
+ return (0);
+}
+
+int
+mfc_reset_prune_expire_timer(struct prune_node *pn)
+{
+ struct timeval tv;
+
+ timerclear(&tv);
+ tv.tv_sec = MAX_PRUNE_LIFETIME;
+
+ return (evtimer_add(&pn->lifetime_timer, &tv));
+}
+
+void
+prune_expire_timer(int fd, short event, void *arg)
+{
+ struct prune_node *pn = arg;
+
+ LIST_REMOVE(pn, entry);
+
+ pn->parent->prune_cnt[pn->ifindex]--;
+ pn->parent->ttls[pn->ifindex] = 1;
+
+ free(pn);
+}
diff --git a/usr.sbin/dvmrpd/rde_srt.c b/usr.sbin/dvmrpd/rde_srt.c
index 3f1243d4011..9b8de2a99f6 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.23 2009/05/20 16:10:04 michele Exp $ */
+/* $OpenBSD: rde_srt.c,v 1.24 2009/09/06 09:52:14 michele Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -52,7 +52,6 @@ void srt_current_forwarder(struct rt_node *, struct iface *,
/* Downstream neighbors */
void srt_add_ds(struct rt_node *, u_int32_t, u_int32_t);
-struct ds_nbr *srt_find_ds(struct rt_node *, u_int32_t);
void srt_delete_ds(struct rt_node *, struct ds_nbr *,
struct iface *);