aboutsummaryrefslogtreecommitdiffstats
path: root/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch')
-rw-r--r--package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch154
1 files changed, 154 insertions, 0 deletions
diff --git a/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch b/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch
new file mode 100644
index 0000000..24aefce
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch
@@ -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;
++ }
++}
++