ports/net/igmpproxy/patches/patch-src_rttable_c

535 lines
20 KiB
Text

Index: src/rttable.c
--- src/rttable.c.orig
+++ src/rttable.c
@@ -39,17 +39,23 @@
*/
#include "igmpproxy.h"
+#include <sys/queue.h>
+#include <sys/tree.h>
#define MAX_ORIGINS 4
/**
* Routing table structure definition. Double linked list...
*/
+struct Origin {
+ TAILQ_ENTRY(Origin) next;
+ uint32_t originAddr;
+ int flood;
+ uint32_t pktcnt;
+};
struct RouteTable {
- struct RouteTable *nextroute; // Pointer to the next group in line.
- struct RouteTable *prevroute; // Pointer to the previous group in line.
+ RB_ENTRY(RouteTable) entry;
uint32_t group; // The group to route
- uint32_t originAddrs[MAX_ORIGINS]; // The origin adresses (only set on activated routes)
uint32_t vifBits; // Bits representing recieving VIFs.
// Keeps the upstream membership state...
@@ -60,22 +66,54 @@ struct RouteTable {
uint32_t 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)
// Keeps downstream hosts information
uint32_t downstreamHostsHashSeed;
uint8_t downstreamHostsHashTable[];
};
+RB_HEAD(rtabletree, RouteTable) routing_table =
+ RB_INITIALIZER(&routing_table);
-
-// Keeper for the routing table...
-static struct RouteTable *routing_table;
-
// Prototypes
void logRouteTable(const char *header);
int internAgeRoute(struct RouteTable *croute);
-int internUpdateKernelRoute(struct RouteTable *route, int activate);
+int internUpdateKernelRoute(struct RouteTable *route, int activate, struct Origin *);
+int rtable_cmp(struct RouteTable *, struct RouteTable *);
+struct RouteTable *rtable_add(struct RouteTable *);
+void rtable_remove(struct RouteTable *);
+RB_GENERATE(rtabletree, RouteTable, entry, rtable_cmp);
+int
+rtable_cmp(struct RouteTable *rt, struct RouteTable *rtn)
+{
+ if (rt->group < rtn->group)
+ return (-1);
+
+ return (rt->group > rtn->group);
+}
+
+struct RouteTable *
+rtable_add(struct RouteTable *rt)
+{
+ return (RB_INSERT(rtabletree, &routing_table, rt));
+}
+
+void
+rtable_remove(struct RouteTable *rt)
+{
+ struct Origin *o;
+
+ while ((o = TAILQ_FIRST(&rt->originList))) {
+ TAILQ_REMOVE(&rt->originList, o, next);
+ free(o);
+ }
+
+ RB_REMOVE(rtabletree, &routing_table, rt);
+ free(rt);
+}
+
/**
* Functions for downstream hosts hash table
*/
@@ -120,9 +158,6 @@ void initRouteTable(void) {
unsigned Ix;
struct IfDesc *Dp;
- // Clear routing table...
- routing_table = NULL;
-
// Join the all routers group on downstream vifs...
for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
// If this is a downstream vif, we should join the All routers group...
@@ -220,29 +255,24 @@ static void sendJoinLeaveUpstream(struct RouteTable* r
* Clear all routes from routing table, and alerts Leaves upstream.
*/
void clearAllRoutes(void) {
- struct RouteTable *croute, *remainroute;
+ struct RouteTable *croute;
// Loop through all routes...
- for(croute = routing_table; croute; croute = remainroute) {
-
- remainroute = croute->nextroute;
-
+ while ((croute = RB_ROOT(&routing_table)) != NULL) {
// Log the cleanup in debugmode...
my_log(LOG_DEBUG, 0, "Removing route entry for %s",
inetFmt(croute->group, s1));
// Uninstall current route
- if(!internUpdateKernelRoute(croute, 0)) {
+ if(!internUpdateKernelRoute(croute, 0, NULL)) {
my_log(LOG_WARNING, 0, "The removal from Kernel failed.");
}
// Send Leave message upstream.
sendJoinLeaveUpstream(croute, 0);
- // Clear memory, and set pointer to next route...
- free(croute);
+ rtable_remove(croute);
}
- routing_table = NULL;
// Send a notice that the routing table is empty...
my_log(LOG_NOTICE, 0, "All routes removed. Routing table is empty.");
@@ -253,15 +283,10 @@ void clearAllRoutes(void) {
* Route Descriptor.
*/
static struct RouteTable *findRoute(uint32_t group) {
- struct RouteTable* croute;
+ struct RouteTable key;
- for(croute = routing_table; croute; croute = croute->nextroute) {
- if(croute->group == group) {
- return croute;
- }
- }
-
- return NULL;
+ key.group = group;
+ return (RB_FIND(rtabletree, &routing_table, &key));
}
/**
@@ -300,10 +325,8 @@ int insertRoute(uint32_t group, int ifx, uint32_t src)
newroute = (struct RouteTable*)malloc(sizeof(struct RouteTable) + (conf->fastUpstreamLeave ? conf->downstreamHostsHashTableSize : 0));
// Insert the route desc and clear all pointers...
newroute->group = group;
- memset(newroute->originAddrs, 0, MAX_ORIGINS * sizeof(newroute->originAddrs[0]));
- newroute->nextroute = NULL;
- newroute->prevroute = NULL;
newroute->upstrVif = -1;
+ TAILQ_INIT(&newroute->originList);
if(conf->fastUpstreamLeave) {
// Init downstream hosts bit hash table
@@ -328,54 +351,13 @@ int insertRoute(uint32_t group, int ifx, uint32_t src)
BIT_SET(newroute->vifBits, ifx);
}
- // Check if there is a table already....
- if(routing_table == NULL) {
- // No location set, so insert in on the table top.
- routing_table = newroute;
- my_log(LOG_DEBUG, 0, "No routes in table. Insert at beginning.");
- } else {
-
- my_log(LOG_DEBUG, 0, "Found existing routes. Find insert location.");
-
- // Check if the route could be inserted at the beginning...
- if(routing_table->group > group) {
- my_log(LOG_DEBUG, 0, "Inserting at beginning, before route %s",inetFmt(routing_table->group,s1));
-
- // Insert at beginning...
- newroute->nextroute = routing_table;
- newroute->prevroute = NULL;
- routing_table = newroute;
-
- // If the route has a next node, the previous pointer must be updated.
- if(newroute->nextroute != NULL) {
- newroute->nextroute->prevroute = newroute;
- }
-
- } else {
-
- // Find the location which is closest to the route.
- for( croute = routing_table; croute->nextroute != NULL; croute = croute->nextroute ) {
- // Find insert position.
- if(croute->nextroute->group > group) {
- break;
- }
- }
-
- my_log(LOG_DEBUG, 0, "Inserting after route %s",inetFmt(croute->group,s1));
-
- // Insert after current...
- newroute->nextroute = croute->nextroute;
- newroute->prevroute = croute;
- if(croute->nextroute != NULL) {
- croute->nextroute->prevroute = newroute;
- }
- croute->nextroute = newroute;
- }
+ if ((croute = rtable_add(newroute)) != NULL)
+ free(newroute);
+ else {
+ // Set the new route as the current...
+ croute = newroute;
}
- // Set the new route as the current...
- croute = newroute;
-
// Log the cleanup in debugmode...
my_log(LOG_INFO, 0, "Inserted route table entry for %s on VIF #%d",
inetFmt(croute->group, s1),ifx);
@@ -398,7 +380,7 @@ int insertRoute(uint32_t group, int ifx, uint32_t src)
inetFmt(croute->group, s1), ifx);
// Update route in kernel...
- if(!internUpdateKernelRoute(croute, 1)) {
+ if(!internUpdateKernelRoute(croute, 1, NULL)) {
my_log(LOG_WARNING, 0, "The insertion into Kernel failed.");
return 0;
}
@@ -420,7 +402,7 @@ int insertRoute(uint32_t group, int ifx, uint32_t src)
* activated, it's reinstalled in the kernel. If
* the route is activated, no originAddr is needed.
*/
-int activateRoute(uint32_t group, uint32_t originAddr, int upstrVif) {
+int activateRoute(uint32_t group, uint32_t originAddr, int downIf) {
struct RouteTable* croute;
int result = 0;
@@ -439,43 +421,37 @@ int activateRoute(uint32_t group, uint32_t originAddr,
}
if(croute != NULL) {
+ struct Origin *o = NULL;
+ int found = 0;
+
// If the origin address is set, update the route data.
if(originAddr > 0) {
- // find this origin, or an unused slot
- int i;
- for (i = 0; i < MAX_ORIGINS; i++) {
- // unused slots are at the bottom, so we can't miss this origin
- if (croute->originAddrs[i] == originAddr || croute->originAddrs[i] == 0) {
+ TAILQ_FOREACH(o, &croute->originList, next) {
+ my_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 (i == MAX_ORIGINS) {
- i = MAX_ORIGINS - 1;
-
- my_log(LOG_WARNING, 0, "Too many origins for route %s; replacing %s with %s",
+ if (!found) {
+ my_log(LOG_NOTICE, 0, "New origin for route %s is %s, flood %d",
inetFmt(croute->group, s1),
- inetFmt(croute->originAddrs[i], s2),
- inetFmt(originAddr, s3));
+ 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 {
+ my_log(LOG_INFO, 0, "Have origin for route %s at %s, pktcnt %d",
+ inetFmt(croute->group, s1),
+ inetFmt(o->originAddr, s3),
+ o->pktcnt);
}
-
- // set origin
- croute->originAddrs[i] = originAddr;
-
- // move it to the top
- while (i > 0) {
- uint32_t t = croute->originAddrs[i - 1];
- croute->originAddrs[i - 1] = croute->originAddrs[i];
- croute->originAddrs[i] = t;
- i--;
- }
}
- croute->upstrVif = upstrVif;
-
- // Only update kernel table if there are listeners !
- if(croute->vifBits > 0) {
- result = internUpdateKernelRoute(croute, 1);
- }
}
logRouteTable("Activate Route");
@@ -492,12 +468,7 @@ void ageActiveRoutes(void) {
my_log(LOG_DEBUG, 0, "Aging routes in table.");
- // Scan all routes...
- for( croute = routing_table; croute != NULL; croute = nroute ) {
-
- // Keep the next route (since current route may be removed)...
- nroute = croute->nextroute;
-
+ RB_FOREACH_SAFE(croute, rtabletree, &routing_table, nroute) {
// Run the aging round algorithm.
if(croute->upstrState != ROUTESTATE_CHECK_LAST_MEMBER) {
// Only age routes if Last member probe is not active...
@@ -609,7 +580,7 @@ static int removeRoute(struct RouteTable* croute) {
//BIT_ZERO(croute->vifBits);
// Uninstall current route from kernel
- if(!internUpdateKernelRoute(croute, 0)) {
+ if(!internUpdateKernelRoute(croute, 0, NULL)) {
my_log(LOG_WARNING, 0, "The removal from Kernel failed.");
result = 0;
}
@@ -621,24 +592,8 @@ static int removeRoute(struct RouteTable* croute) {
sendJoinLeaveUpstream(croute, 0);
}
- // Update pointers...
- if(croute->prevroute == NULL) {
- // Topmost node...
- if(croute->nextroute != NULL) {
- croute->nextroute->prevroute = NULL;
- }
- routing_table = croute->nextroute;
+ rtable_remove(croute);
- } else {
- croute->prevroute->nextroute = croute->nextroute;
- if(croute->nextroute != NULL) {
- croute->nextroute->prevroute = croute->prevroute;
- }
- }
- // Free the memory, and set the route to NULL...
- free(croute);
- croute = NULL;
-
logRouteTable("Remove route");
return result;
@@ -683,6 +638,37 @@ 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) {
+ my_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;
+ }
+ my_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,
@@ -692,7 +678,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;
@@ -718,39 +704,61 @@ 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;
- int i;
+ struct Origin *o;
- for (i = 0; i < MAX_ORIGINS; i++) {
- if (route->originAddrs[i] == 0 || route->upstrVif == -1) {
+ if (TAILQ_EMPTY(&route->originList)) {
+ my_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->originAddrs[i];
+ mrDesc.OriginAdr.s_addr = o->originAddr;
// clear output interfaces
memset( mrDesc.TtlVc, 0, sizeof( mrDesc.TtlVc ) );
- my_log(LOG_DEBUG, 0, "Vif bits : 0x%08x", route->vifBits);
+ my_log(LOG_DEBUG, 0, "Origin %s Vif bits : 0x%08x", inetFmt(o->originAddr, s1), route->vifBits);
mrDesc.InVif = route->upstrVif;
// Set the TTL's for the route descriptor...
- for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
- if(Dp->state == IF_STATE_UPSTREAM) {
- continue;
+ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) {
+ if (o->flood >= 0) {
+ if(Ix == o->flood) {
+ my_log(LOG_DEBUG, 0, "Identified Input VIF #%d as DOWNSTREAM.", Dp->index);
+ mrDesc.InVif = Dp->index;
+ }
+ else if(Dp->state == IF_STATE_UPSTREAM) {
+ my_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)) {
+ my_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) {
+ my_log(LOG_DEBUG, 0, "Identified VIF #%d as upstream.", Dp->index);
+ mrDesc.InVif = Dp->index;
+ }
+ else if(BIT_TST(route->vifBits, Dp->index)) {
+ my_log(LOG_DEBUG, 0, "Setting TTL for Vif %d to %d", Dp->index, Dp->threshold);
+ mrDesc.TtlVc[ Dp->index ] = Dp->threshold;
+ }
}
- else if(BIT_TST(route->vifBits, Dp->index)) {
- my_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...
@@ -772,7 +780,7 @@ int internUpdateKernelRoute(struct RouteTable *route,
*/
void logRouteTable(const char *header) {
struct Config *conf = getCommonConfig();
- struct RouteTable *croute = routing_table;
+ struct RouteTable *croute = RB_ROOT(&routing_table);
unsigned rcount = 0;
my_log(LOG_DEBUG, 0, "");
@@ -781,30 +789,22 @@ void logRouteTable(const char *header) {
if(croute==NULL) {
my_log(LOG_DEBUG, 0, "No routes in table...");
} else {
- do {
- char st = 'I';
- char src[MAX_ORIGINS * 30 + 1];
- src[0] = '\0';
- int i;
-
- for (i = 0; i < MAX_ORIGINS; i++) {
- if (croute->originAddrs[i] == 0) {
- continue;
- }
- st = 'A';
- sprintf(src + strlen(src), "Src%d: %s, ", i, inetFmt(croute->originAddrs[i], s1));
- }
-
- my_log(LOG_DEBUG, 0, "#%d: %sDst: %s, Age:%d, St: %c, OutVifs: 0x%08x, dHosts: %s",
- rcount, src, inetFmt(croute->group, s2),
- croute->ageValue, st,
+ RB_FOREACH(croute, rtabletree, &routing_table) {
+ my_log(LOG_DEBUG, 0, "#%d: Dst: %s, Age:%d, St: %s, OutVifs: 0x%08x, dHosts: %s",
+ rcount, inetFmt(croute->group, s2),
+ croute->ageValue,
+ (TAILQ_EMPTY(&croute->originList) ? "I":"A"),
croute->vifBits,
!conf->fastUpstreamLeave ? "not tracked" : testNoDownstreamHost(conf, croute) ? "no" : "yes");
-
- croute = croute->nextroute;
-
+ {
+ struct Origin *o;
+ TAILQ_FOREACH(o, &croute->originList, next) {
+ my_log(LOG_DEBUG, 0, "#%d: Origin: %s floodIf %d pktcnt %d",
+ rcount, inetFmt(o->originAddr, s1), o->flood, o->pktcnt);
+ }
+ }
rcount++;
- } while ( croute != NULL );
+ }
}
my_log(LOG_DEBUG, 0, "-----------------------------------------------------");