Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/igmpproxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,10 @@ int leaveMcGroup( int UdpSock, struct IfDesc *IfDp, uint32_t mcastaddr );
*/
void initRouteTable(void);
void clearAllRoutes(void);
int insertRoute(uint32_t group, int ifx);
int insertRoute(uint32_t group, int ifx, uint32_t src);
int activateRoute(uint32_t group, uint32_t originAddr, int upstrVif);
void ageActiveRoutes(void);
void setRouteLastMemberMode(uint32_t group);
void setRouteLastMemberMode(uint32_t group, uint32_t src);
int lastMemberGroupAge(uint32_t group);
int interfaceInRoute(int32_t group, int Ix);
int getMcGroupSock(void);
Expand Down
6 changes: 3 additions & 3 deletions src/request.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void acceptGroupReport(uint32_t src, uint32_t group) {
// If we don't have a whitelist we insertRoute and done
if(sourceVif->allowedgroups == NULL)
{
insertRoute(group, sourceVif->index);
insertRoute(group, sourceVif->index, src);
return;
}
// Check if this Request is legit on this interface
Expand All @@ -95,7 +95,7 @@ void acceptGroupReport(uint32_t src, uint32_t group) {
if((group & sn->subnet_mask) == sn->subnet_addr)
{
// The membership report was OK... Insert it into the route table..
insertRoute(group, sourceVif->index);
insertRoute(group, sourceVif->index, src);
return;
}
my_log(LOG_INFO, 0, "The group address %s may not be requested from this interface. Ignoring.", inetFmt(group, s1));
Expand Down Expand Up @@ -138,7 +138,7 @@ void acceptLeaveMessage(uint32_t src, uint32_t group) {
gvDesc = (GroupVifDesc*) malloc(sizeof(GroupVifDesc));

// Tell the route table that we are checking for remaining members...
setRouteLastMemberMode(group);
setRouteLastMemberMode(group, src);

// Call the group spesific membership querier...
gvDesc->group = group;
Expand Down
119 changes: 107 additions & 12 deletions src/rttable.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ 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.

// Keeps downstream hosts information
uint32_t *dwnstrHosts; // The downstream hosts the route is active for
int dwnstrHostsCapacity; // Current capacity of the downstream hosts array
int dwnstrHostsSize; // Current size of the downstream hosts array
};


Expand Down Expand Up @@ -216,6 +221,66 @@ void clearAllRoutes(void) {
my_log(LOG_NOTICE, 0, "All routes removed. Routing table is empty.");
}

/**
* Function which return the number of active dowsnstream hosts
*/
int countDownstreamHosts(struct RouteTable *croute) {
int result = 0;

for (int i = 0; i < croute->dwnstrHostsCapacity; i++) {
if(croute->dwnstrHosts[i] != 0) {
result++;
}
}
return result;
}

/**
* Function to find first downstream host slot
*/
size_t findFreeDownstreamSlot(struct RouteTable *croute) {
for (size_t i = 0; i < (size_t)croute->dwnstrHostsCapacity; i++) {
if(croute->dwnstrHosts[i] == 0) {
return i;
}
}
return (size_t)0;
}

/**
* Function to find downstream slot for host
*/
size_t findDownstreamSlot(struct RouteTable *croute, uint32_t dstrHost) {
for (size_t i = 0; i < (size_t)croute->dwnstrHostsCapacity; i++) {
if(croute->dwnstrHosts[i] == dstrHost) {
return i;
}
}
return (size_t)-1;
}

/**
* Function to add downstream hosts to route
*/
void addDownStreamHost(struct RouteTable *croute, uint32_t dstrHost){
croute->dwnstrHostsSize = croute->dwnstrHostsSize + 1;

if(croute->dwnstrHostsSize > croute->dwnstrHostsCapacity){
int newcapacity = croute->dwnstrHostsCapacity * 2;

uint32_t* newptr = (uint32_t*)realloc(croute->dwnstrHosts, newcapacity * sizeof(uint32_t));
if(newptr == NULL) {
croute->dwnstrHostsSize = croute->dwnstrHostsSize - 1;
my_log(LOG_WARNING, 0, "Failed to realloc dwnstrHosts, quickleave last host tracking may not work properly");
} else {
croute->dwnstrHosts = newptr;
croute->dwnstrHostsCapacity = newcapacity;
}
}
size_t idx = findFreeDownstreamSlot(croute);
croute->dwnstrHosts[idx] = dstrHost;
}

/**
* Private access function to find a route from a given
* Route Descriptor.
Expand All @@ -237,7 +302,7 @@ static struct RouteTable *findRoute(uint32_t group) {
* If the route already exists, the existing route
* is updated...
*/
int insertRoute(uint32_t group, int ifx) {
int insertRoute(uint32_t group, int ifx, uint32_t src) {

struct Config *conf = getCommonConfig();
struct RouteTable* croute;
Expand Down Expand Up @@ -274,6 +339,16 @@ int insertRoute(uint32_t group, int ifx) {
newroute->prevroute = NULL;
newroute->upstrVif = -1;

// Init downstream hosts dynamic array
newroute->dwnstrHostsSize = 0;
newroute->dwnstrHostsCapacity = 2;
newroute->dwnstrHosts = malloc(2 * sizeof(uint32_t));

// Add downstream hosts
if(conf->fastUpstreamLeave) {
addDownStreamHost(newroute, src);
}

// The group is not joined initially.
newroute->upstrState = ROUTESTATE_NOTJOINED;

Expand Down Expand Up @@ -349,6 +424,13 @@ int insertRoute(uint32_t group, int ifx) {
// Register the VIF activity for the aging routine
BIT_SET(croute->ageVifBits, ifx);

// Register dwnstrHosts for host tracking if fastleave is enabled
if(conf->fastUpstreamLeave) {
if(findDownstreamSlot(croute, src) == (size_t)-1){
addDownStreamHost(croute, src);
}
}

// Log the cleanup in debugmode...
my_log(LOG_INFO, 0, "Updated route entry for %s on VIF #%d",
inetFmt(croute->group, s1), ifx);
Expand Down Expand Up @@ -388,7 +470,7 @@ int activateRoute(uint32_t group, uint32_t originAddr, int upstrVif) {
inetFmt(group, s1),inetFmt(originAddr, s2));

// Insert route, but no interfaces have yet requested it downstream.
insertRoute(group, -1);
insertRoute(group, -1, 0);

// Retrieve the route from table...
croute = findRoute(group);
Expand Down Expand Up @@ -485,26 +567,39 @@ int numberOfInterfaces(struct RouteTable *croute) {
* Should be called when a leave message is received, to
* mark a route for the last member probe state.
*/
void setRouteLastMemberMode(uint32_t group) {
void setRouteLastMemberMode(uint32_t group, uint32_t src) {
struct Config *conf = getCommonConfig();
struct RouteTable *croute;

croute = findRoute(group);
if(croute!=NULL) {
// Check for fast leave mode...
if(croute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) {
// Send a leave message right away only when the route has been active on only one interface
if (numberOfInterfaces(croute) <= 1) {
my_log(LOG_DEBUG, 0, "Leaving group %d now", group);

// Remove downstreamhost from route
size_t hostIdx = findDownstreamSlot(croute, src);
if(hostIdx != (size_t)-1){
croute->dwnstrHosts[hostIdx] = 0;
croute->dwnstrHostsSize = croute->dwnstrHostsSize - 1;
}

// Send a leave message right away but only when the route is not active anymore on any downstream host
if (countDownstreamHosts(croute) < 1) {
my_log(LOG_DEBUG, 0, "Fastleave is enabled and this was the last downstream host, leaving group %s now", inetFmt(croute->group, s1));
sendJoinLeaveUpstream(croute, 0);
} else {
my_log(LOG_DEBUG, 0, "Fast leave enabled but there are still %d downstream hosts left, not leaving group %s", countDownstreamHosts(croute), inetFmt(croute->group, s1));
}

}

// Set the routingstate to Last member check...
croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER;
// Set the routingstate to last member check if we have no known downstream host left or if fast leave mode is disabled...
if(countDownstreamHosts(croute) < 1 || !conf->fastUpstreamLeave) {
croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER;

// Set the count value for expiring... (-1 since first aging)
croute->ageValue = conf->lastMemberQueryCount;
// Set the count value for expiring... (-1 since first aging)
croute->ageValue = conf->lastMemberQueryCount;
}
}
}

Expand Down Expand Up @@ -732,10 +827,10 @@ void logRouteTable(const char *header) {
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",
my_log(LOG_DEBUG, 0, "#%d: %sDst: %s, Age:%d, St: %c, OutVifs: 0x%08x, dHosts: %d",
rcount, src, inetFmt(croute->group, s2),
croute->ageValue, st,
croute->vifBits);
croute->vifBits, countDownstreamHosts(croute));

croute = croute->nextroute;

Expand Down