You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
5.2 KiB
154 lines
5.2 KiB
--- a/src/igmpproxy.h
|
|
+++ b/src/igmpproxy.h
|
|
@@ -251,6 +251,7 @@ int activateRoute(uint32_t group, uint32
|
|
void ageActiveRoutes();
|
|
void setRouteLastMemberMode(uint32_t group);
|
|
int lastMemberGroupAge(uint32_t group);
|
|
+int interfaceInRoute(int32_t group, int Ix);
|
|
|
|
/* request.c
|
|
*/
|
|
--- a/src/request.c
|
|
+++ b/src/request.c
|
|
@@ -41,10 +41,10 @@
|
|
|
|
// Prototypes...
|
|
void sendGroupSpecificMemberQuery(void *argument);
|
|
-
|
|
+
|
|
typedef struct {
|
|
uint32_t group;
|
|
- uint32_t vifAddr;
|
|
+ // uint32_t vifAddr;
|
|
short started;
|
|
} GroupVifDesc;
|
|
|
|
@@ -142,7 +142,7 @@ void acceptLeaveMessage(uint32_t src, ui
|
|
|
|
// Call the group spesific membership querier...
|
|
gvDesc->group = group;
|
|
- gvDesc->vifAddr = sourceVif->InAdr.s_addr;
|
|
+ // gvDesc->vifAddr = sourceVif->InAdr.s_addr;
|
|
gvDesc->started = 0;
|
|
|
|
sendGroupSpecificMemberQuery(gvDesc);
|
|
@@ -159,6 +159,9 @@ void acceptLeaveMessage(uint32_t src, ui
|
|
*/
|
|
void sendGroupSpecificMemberQuery(void *argument) {
|
|
struct Config *conf = getCommonConfig();
|
|
+ struct IfDesc *Dp;
|
|
+ struct RouteTable *croute;
|
|
+ int Ix;
|
|
|
|
// Cast argument to correct type...
|
|
GroupVifDesc *gvDesc = (GroupVifDesc*) argument;
|
|
@@ -166,22 +169,38 @@ void sendGroupSpecificMemberQuery(void *
|
|
if(gvDesc->started) {
|
|
// If aging returns false, we don't do any further action...
|
|
if(!lastMemberGroupAge(gvDesc->group)) {
|
|
+ // FIXME: Should we free gvDesc here?
|
|
return;
|
|
}
|
|
} else {
|
|
gvDesc->started = 1;
|
|
}
|
|
|
|
- // Send a group specific membership query...
|
|
- sendIgmp(gvDesc->vifAddr, gvDesc->group,
|
|
- IGMP_MEMBERSHIP_QUERY,
|
|
- conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
|
|
- gvDesc->group, 0);
|
|
-
|
|
- my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
|
|
- inetFmt(gvDesc->vifAddr,s1), inetFmt(gvDesc->group,s2),
|
|
- conf->lastMemberQueryInterval);
|
|
-
|
|
+ /**
|
|
+ * FIXME: This loops through all interfaces the group is active on an sends queries.
|
|
+ * It might be better to send only a query on the interface the leave was accepted on and remove only that interface from the route.
|
|
+ */
|
|
+
|
|
+ // Loop through all downstream interfaces
|
|
+ for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
|
|
+ if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
|
|
+ if(Dp->state == IF_STATE_DOWNSTREAM) {
|
|
+ // Is that interface used in the group?
|
|
+ if (interfaceInRoute(gvDesc->group ,Dp->index)) {
|
|
+
|
|
+ // Send a group specific membership query...
|
|
+ sendIgmp(Dp->InAdr.s_addr, gvDesc->group,
|
|
+ IGMP_MEMBERSHIP_QUERY,
|
|
+ conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
|
|
+ gvDesc->group, 0);
|
|
+
|
|
+ my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
|
|
+ inetFmt(Dp->InAdr.s_addr,s1), inetFmt(gvDesc->group,s2),
|
|
+ conf->lastMemberQueryInterval);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
// Set timeout for next round...
|
|
timer_setTimer(conf->lastMemberQueryInterval, sendGroupSpecificMemberQuery, gvDesc);
|
|
|
|
--- a/src/rttable.c
|
|
+++ b/src/rttable.c
|
|
@@ -428,6 +428,25 @@ void ageActiveRoutes() {
|
|
}
|
|
|
|
/**
|
|
+* Counts the number of interfaces a given route is active on
|
|
+*/
|
|
+int numberOfInterfaces(struct RouteTable *croute) {
|
|
+ int Ix;
|
|
+ struct IfDesc *Dp;
|
|
+ int result = 0;
|
|
+ // Loop through all interfaces
|
|
+ for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
|
|
+ // If the interface is used by the route, increase counter
|
|
+ if(BIT_TST(croute->vifBits, Dp->index)) {
|
|
+ result++;
|
|
+ }
|
|
+ }
|
|
+ my_log(LOG_DEBUG, 0, "counted %d interfaces", result);
|
|
+ return result;
|
|
+}
|
|
+
|
|
+
|
|
+/**
|
|
* Should be called when a leave message is recieved, to
|
|
* mark a route for the last member probe state.
|
|
*/
|
|
@@ -439,8 +458,11 @@ void setRouteLastMemberMode(uint32_t gro
|
|
if(croute!=NULL) {
|
|
// Check for fast leave mode...
|
|
if(croute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) {
|
|
- // Send a leave message right away..
|
|
- sendJoinLeaveUpstream(croute, 0);
|
|
+ // 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);
|
|
+ sendJoinLeaveUpstream(croute, 0);
|
|
+ }
|
|
}
|
|
// Set the routingstate to Last member check...
|
|
croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER;
|
|
@@ -677,3 +699,18 @@ void logRouteTable(char *header) {
|
|
|
|
my_log(LOG_DEBUG, 0, "-----------------------------------------------------");
|
|
}
|
|
+
|
|
+/**
|
|
+* Returns true when the given group belongs to the given interface
|
|
+*/
|
|
+int interfaceInRoute(int32_t group, int Ix) {
|
|
+ struct RouteTable* croute;
|
|
+ croute = findRoute(group);
|
|
+ if (croute != NULL) {
|
|
+ my_log(LOG_DEBUG, 0, "Interface id %d is in group $d", Ix, group);
|
|
+ return BIT_TST(croute->vifBits, Ix);
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
|