openbsd-ports/net/igmpproxy/patches/patch-rttable_c
sthen 99d5e52b90 igmpproxy is a simple multicast routing daemon which uses IGMP
forwarding to dynamically route multicast traffic.  Routing is done
by defining an "upstream" interface on which the daemon acts as a
normal Multicast client, and one or more "downstream" interfaces
that serves clients on the destination networks. This is useful in
situations where other dynamic multicast routers cannot be used.

from markus with small adjustments.
ok markus
2008-02-08 19:30:51 +00:00

387 lines
14 KiB
Plaintext

$OpenBSD: patch-rttable_c,v 1.1.1.1 2008/02/08 19:30:52 sthen Exp $
--- rttable.c.orig Sat Aug 20 13:46:20 2005
+++ rttable.c Mon Nov 19 12:56:50 2007
@@ -38,15 +38,22 @@
*/
#include "defs.h"
+#include <sys/queue.h>
/**
* Routing table structure definition. Double linked list...
*/
+struct Origin {
+ TAILQ_ENTRY(Origin) next;
+ uint32 originAddr;
+ int flood;
+ uint32 pktcnt;
+};
+
struct RouteTable {
struct RouteTable *nextroute; // Pointer to the next group in line.
struct RouteTable *prevroute; // Pointer to the previous group in line.
uint32 group; // The group to route
- uint32 originAddr; // The origin adress (only set on activated routes)
uint32 vifBits; // Bits representing recieving VIFs.
// Keeps the upstream membership state...
@@ -56,6 +63,7 @@ struct RouteTable {
uint32 ageVifBits; // Bits representing aging VIFs.
int ageValue; // Downcounter for death.
int ageActivity; // Records any acitivity that notes there are still listeners.
+ TAILQ_HEAD(originhead, Origin) originList; // The origin adresses (non-empty on activated routes)
};
@@ -65,19 +73,17 @@ static struct RouteTable *routing_table;
// Prototypes
void logRouteTable(char *header);
int internAgeRoute(struct RouteTable* croute);
+int internUpdateKernelRoute(struct RouteTable *route, int activate, struct Origin *o);
-// Socket for sending join or leave requests.
-int mcGroupSock = 0;
-
/**
* Function for retrieving the Multicast Group socket.
*/
int getMcGroupSock() {
- if( ! mcGroupSock ) {
- mcGroupSock = openUdpSocket( INADDR_ANY, 0 );;
+ if (MRouterFD < 0) {
+ log(LOG_ERR, errno, "no MRouterFD.");
}
- return mcGroupSock;
+ return MRouterFD;
}
/**
@@ -91,7 +97,7 @@ void initRouteTable() {
routing_table = NULL;
// Join the all routers group on downstream vifs...
- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) {
+ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) {
// If this is a downstream vif, we should join the All routers group...
if( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) && Dp->state == IF_STATE_DOWNSTREAM) {
IF_DEBUG log(LOG_DEBUG, 0, "Joining all-routers group %s on vif %s",
@@ -160,6 +166,7 @@ void sendJoinLeaveUpstream(struct RouteTable* route, i
*/
void clearAllRoutes() {
struct RouteTable *croute, *remainroute;
+ struct Origin *o;
// Loop through all routes...
for(croute = routing_table; croute; croute = remainroute) {
@@ -171,7 +178,7 @@ void clearAllRoutes() {
inetFmt(croute->group, s1));
// Uninstall current route
- if(!internUpdateKernelRoute(croute, 0)) {
+ if(!internUpdateKernelRoute(croute, 0, NULL)) {
log(LOG_WARNING, 0, "The removal from Kernel failed.");
}
@@ -179,6 +186,10 @@ void clearAllRoutes() {
sendJoinLeaveUpstream(croute, 0);
// Clear memory, and set pointer to next route...
+ while ((o = TAILQ_FIRST(&croute->originList))) {
+ TAILQ_REMOVE(&croute->originList, o, next);
+ free(o);
+ }
free(croute);
}
routing_table = NULL;
@@ -212,7 +223,6 @@ int insertRoute(uint32 group, int ifx) {
struct Config *conf = getCommonConfig();
struct RouteTable* croute;
- int result = 1;
// Sanitycheck the group adress...
if( ! IN_MULTICAST( ntohl(group) )) {
@@ -241,7 +251,8 @@ int insertRoute(uint32 group, int ifx) {
newroute = (struct RouteTable*)malloc(sizeof(struct RouteTable));
// Insert the route desc and clear all pointers...
newroute->group = group;
- newroute->originAddr = 0;
+ TAILQ_INIT(&newroute->originList);
+
newroute->nextroute = NULL;
newroute->prevroute = NULL;
@@ -325,10 +336,10 @@ int insertRoute(uint32 group, int ifx) {
inetFmt(croute->group, s1), ifx);
// If the route is active, it must be reloaded into the Kernel..
- if(croute->originAddr != 0) {
+ if(!TAILQ_EMPTY(&croute->originList)) {
// Update route in kernel...
- if(!internUpdateKernelRoute(croute, 1)) {
+ if(!internUpdateKernelRoute(croute, 1, NULL)) {
log(LOG_WARNING, 0, "The insertion into Kernel failed.");
return 0;
}
@@ -351,7 +362,7 @@ int insertRoute(uint32 group, int ifx) {
* activated, it's reinstalled in the kernel. If
* the route is activated, no originAddr is needed.
*/
-int activateRoute(uint32 group, uint32 originAddr) {
+int activateRoute(uint32 group, uint32 originAddr, int downIf) {
struct RouteTable* croute;
int result = 0;
@@ -369,21 +380,42 @@ int activateRoute(uint32 group, uint32 originAddr) {
}
if(croute != NULL) {
+ struct Origin *o = NULL;
+ int found = 0;
+
// If the origin address is set, update the route data.
- if(originAddr > 0) {
- if(croute->originAddr > 0 && croute->originAddr!=originAddr) {
- log(LOG_WARNING, 0, "The origin for route %s changed from %s to %s",
- inetFmt(croute->group, s1),
- inetFmt(croute->originAddr, s2),
- inetFmt(originAddr, s3));
- }
- croute->originAddr = originAddr;
- }
+ if(originAddr > 0) {
- // Only update kernel table if there are listeners !
- if(croute->vifBits > 0) {
- result = internUpdateKernelRoute(croute, 1);
- }
+ TAILQ_FOREACH(o, &croute->originList, next) {
+ log(LOG_INFO, 0, "Origin for route %s have %s, new %s",
+ inetFmt(croute->group, s1),
+ inetFmt(o->originAddr, s2),
+ inetFmt(originAddr, s3));
+ if (o->originAddr==originAddr) {
+ found++;
+ break;
+ }
+ }
+ if (!found) {
+ log(LOG_NOTICE, 0, "New origin for route %s is %s, flood %d",
+ inetFmt(croute->group, s1),
+ inetFmt(originAddr, s3), downIf);
+ o = malloc(sizeof(*o));
+ o->originAddr = originAddr;
+ o->flood = downIf;
+ o->pktcnt = 0;
+ TAILQ_INSERT_TAIL(&croute->originList, o, next);
+ } else {
+ log(LOG_INFO, 0, "Have origin for route %s at %s, pktcnt %d",
+ inetFmt(croute->group, s1),
+ inetFmt(o->originAddr, s3),
+ o->pktcnt);
+ }
+ }
+
+ // Only update kernel table if there are listeners, but flood upstream!
+ if(croute->vifBits > 0 || downIf >= 0)
+ result = internUpdateKernelRoute(croute, 1, o);
}
IF_DEBUG logRouteTable("Activate Route");
@@ -443,7 +475,6 @@ void setRouteLastMemberMode(uint32 group) {
* route is not found, or not in this state, 0 is returned.
*/
int lastMemberGroupAge(uint32 group) {
- struct Config *conf = getCommonConfig();
struct RouteTable *croute;
croute = findRoute(group);
@@ -463,6 +494,7 @@ int lastMemberGroupAge(uint32 group) {
*/
int removeRoute(struct RouteTable* croute) {
struct Config *conf = getCommonConfig();
+ struct Origin *o;
int result = 1;
// If croute is null, no routes was found.
@@ -477,7 +509,7 @@ int removeRoute(struct RouteTable* croute) {
//BIT_ZERO(croute->vifBits);
// Uninstall current route from kernel
- if(!internUpdateKernelRoute(croute, 0)) {
+ if(!internUpdateKernelRoute(croute, 0, NULL)) {
log(LOG_WARNING, 0, "The removal from Kernel failed.");
result = 0;
}
@@ -503,7 +535,12 @@ int removeRoute(struct RouteTable* croute) {
croute->nextroute->prevroute = croute->prevroute;
}
}
+
// Free the memory, and set the route to NULL...
+ while ((o = TAILQ_FIRST(&croute->originList))) {
+ TAILQ_REMOVE(&croute->originList, o, next);
+ free(o);
+ }
free(croute);
croute = NULL;
@@ -551,6 +588,36 @@ int internAgeRoute(struct RouteTable* croute) {
}
}
+ {
+ struct Origin *o, *nxt;
+ struct sioc_sg_req sg_req;
+
+ sg_req.grp.s_addr = croute->group;
+ for (o = TAILQ_FIRST(&croute->originList); o; o = nxt) {
+ nxt = TAILQ_NEXT(o, next);
+ sg_req.src.s_addr = o->originAddr;
+ if (ioctl(MRouterFD, SIOCGETSGCNT, (char *)&sg_req) < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "age_table_entry: SIOCGETSGCNT failing for",
+ inetFmt(o->originAddr, s1),
+ inetFmt(croute->group, s2));
+ /* Make sure it gets deleted below */
+ sg_req.pktcnt = o->pktcnt;
+ }
+ log(LOG_DEBUG, 0, "Aging Origin %s Dst %s PktCnt %d -> %d",
+ inetFmt(o->originAddr, s1), inetFmt(croute->group, s2),
+ o->pktcnt, sg_req.pktcnt);
+ if (sg_req.pktcnt == o->pktcnt) {
+ /* no traffic, remove from kernel cache */
+ internUpdateKernelRoute(croute, 0, o);
+ TAILQ_REMOVE(&croute->originList, o, next);
+ free(o);
+ } else {
+ o->pktcnt = sg_req.pktcnt;
+ }
+ }
+ }
+
// If the aging counter has reached zero, its time for updating...
if(croute->ageValue == 0) {
// Check for activity in the aging process,
@@ -560,7 +627,7 @@ int internAgeRoute(struct RouteTable* croute) {
inetFmt(croute->group,s1));
// Just update the routing settings in kernel...
- internUpdateKernelRoute(croute, 1);
+ internUpdateKernelRoute(croute, 1, NULL);
// We append the activity counter to the age, and continue...
croute->ageValue = croute->ageActivity;
@@ -586,34 +653,58 @@ int internAgeRoute(struct RouteTable* croute) {
/**
* Updates the Kernel routing table. If activate is 1, the route
* is (re-)activated. If activate is false, the route is removed.
+* if 'origin' is given, only the route with 'origin' will be
+* updated, otherwise all MFC routes for the group will updated.
*/
-int internUpdateKernelRoute(struct RouteTable *route, int activate) {
+int internUpdateKernelRoute(struct RouteTable *route, int activate, struct Origin *origin) {
struct MRouteDesc mrDesc;
struct IfDesc *Dp;
unsigned Ix;
+ struct Origin *o;
- if(route->originAddr>0) {
+ if (TAILQ_EMPTY(&route->originList)) {
+ log(LOG_NOTICE, 0, "Route is not active. No kernel updates done.");
+ return 1;
+ }
+ TAILQ_FOREACH(o, &route->originList, next) {
+ if (origin && origin != o)
+ continue;
// Build route descriptor from table entry...
// Set the source address and group address...
mrDesc.McAdr.s_addr = route->group;
- mrDesc.OriginAdr.s_addr = route->originAddr;
+ mrDesc.OriginAdr.s_addr = o->originAddr;
// clear output interfaces
memset( mrDesc.TtlVc, 0, sizeof( mrDesc.TtlVc ) );
- IF_DEBUG log(LOG_DEBUG, 0, "Vif bits : 0x%08x", route->vifBits);
+ IF_DEBUG log(LOG_DEBUG, 0, "Origin %s Vif bits : 0x%08x", inetFmt(o->originAddr, s1), route->vifBits);
// Set the TTL's for the route descriptor...
- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) {
- if(Dp->state == IF_STATE_UPSTREAM) {
- //IF_DEBUG log(LOG_DEBUG, 0, "Identified VIF #%d as upstream.", Dp->index);
- mrDesc.InVif = Dp->index;
- }
- else if(BIT_TST(route->vifBits, Dp->index)) {
- IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for Vif %d to %d", Dp->index, Dp->threshold);
- mrDesc.TtlVc[ Dp->index ] = Dp->threshold;
- }
+ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) {
+ if (o->flood >= 0) {
+ if(Ix == o->flood) {
+ IF_DEBUG log(LOG_DEBUG, 0, "Identified Input VIF #%d as DOWNSTREAM.", Dp->index);
+ mrDesc.InVif = Dp->index;
+ }
+ else if(Dp->state == IF_STATE_UPSTREAM) {
+ IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for UPSTREAM Vif %d to %d", Dp->index, Dp->threshold);
+ mrDesc.TtlVc[ Dp->index ] = Dp->threshold;
+ }
+ else if(BIT_TST(route->vifBits, Dp->index)) {
+ IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for DOWNSTREAM Vif %d to %d", Dp->index, Dp->threshold);
+ mrDesc.TtlVc[ Dp->index ] = Dp->threshold;
+ }
+ } else {
+ if(Dp->state == IF_STATE_UPSTREAM) {
+ IF_DEBUG log(LOG_DEBUG, 0, "Identified VIF #%d as upstream.", Dp->index);
+ mrDesc.InVif = Dp->index;
+ }
+ else if(BIT_TST(route->vifBits, Dp->index)) {
+ IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for Vif %d to %d", Dp->index, Dp->threshold);
+ mrDesc.TtlVc[ Dp->index ] = Dp->threshold;
+ }
+ }
}
// Do the actual Kernel route update...
@@ -625,9 +716,6 @@ int internUpdateKernelRoute(struct RouteTable *route,
// Delete the route from Kernel...
delMRoute( &mrDesc );
}
-
- } else {
- log(LOG_NOTICE, 0, "Route is not active. No kernel updates done.");
}
return 1;
@@ -647,16 +735,17 @@ void logRouteTable(char *header) {
log(LOG_DEBUG, 0, "No routes in table...");
} else {
do {
- /*
- log(LOG_DEBUG, 0, "#%d: Src: %s, Dst: %s, Age:%d, St: %s, Prev: 0x%08x, T: 0x%08x, Next: 0x%08x",
- rcount, inetFmt(croute->originAddr, s1), inetFmt(croute->group, s2),
- croute->ageValue,(croute->originAddr>0?"A":"I"),
- croute->prevroute, croute, croute->nextroute);
- */
- log(LOG_DEBUG, 0, "#%d: Src: %s, Dst: %s, Age:%d, St: %s, OutVifs: 0x%08x",
- rcount, inetFmt(croute->originAddr, s1), inetFmt(croute->group, s2),
- croute->ageValue,(croute->originAddr>0?"A":"I"),
- croute->vifBits);
+ log(LOG_DEBUG, 0, "#%d: Dst: %s, Age:%d, St: %s, OutVifs: 0x%08x",
+ rcount, inetFmt(croute->group, s2),
+ croute->ageValue,(TAILQ_EMPTY(&croute->originList)?"I":"A"),
+ croute->vifBits);
+ {
+ struct Origin *o;
+ TAILQ_FOREACH(o, &croute->originList, next) {
+ log(LOG_DEBUG, 0, "#%d: Origin: %s floodIf %d pktcnt %d",
+ rcount, inetFmt(o->originAddr, s1), o->flood, o->pktcnt);
+ }
+ }
croute = croute->nextroute;