diff options
author | Michele Marchetto <michele@cvs.openbsd.org> | 2009-09-06 09:52:15 +0000 |
---|---|---|
committer | Michele Marchetto <michele@cvs.openbsd.org> | 2009-09-06 09:52:15 +0000 |
commit | 3facc6da357ea27fa205af3b8c1ea870e0af2a28 (patch) | |
tree | b233e737023af7b6604b978d7c59aa4f39ef52e2 | |
parent | f77080228e4c6c599926bf9750366c6b9f3021f9 (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.c | 5 | ||||
-rw-r--r-- | usr.sbin/dvmrpd/rde.h | 22 | ||||
-rw-r--r-- | usr.sbin/dvmrpd/rde_mfc.c | 149 | ||||
-rw-r--r-- | usr.sbin/dvmrpd/rde_srt.c | 3 |
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 *); |