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 0000000000..24aefcef26 --- /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; ++ } ++} ++