|
|
@@ -0,0 +1,154 @@
|
|
|
+--- 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;
|
|
|
++ }
|
|
|
++}
|
|
|
++
|