[OpenWrt-Devel] [PATCH] [package] igmpproxy: Multiple downlink interfaces fix.
Erik Tews
erik at datenzone.de
Mon Mar 16 20:26:49 EDT 2015
from Erik Tews <erik at datenzone.de>
This patch has two effects. First, the quickleave feature/behaviour is
disabled for all groups that are used on more than one interface. The
idea of quickleave is to leave a group fast and later figure out whether
there is still somebody interested in that group. For groups used on
more than one interface, it is already known that there is still
somebody interested in that group.
Second, when a leave is received for a group that is used on more than
one interface, igmpproxy sends queries on all interface to discover
remeining listeners for that group. Previously these queries were only
send on the interface the leave was received on, so that listeners on
the other interfaces were not discovered and the group might be left on
the upstream router incorrectly.
This patch can be improved by sending the queries only on the interface
the leave was received on and adapting the algorithm in
internAgeRoute(...) in rttable.c in a way that only one interface is
actually processed and all other interfaces of the route are silently
assumed to be still active.
Signed-off-by: Erik Tews <erik at datenzone.de>
---
This patch has also been submitted to the upstream maintainer:
https://sourceforge.net/p/igmpproxy/patches/9/
It is also available to pull for the upstream maintainer on github:
https://github.com/eriktews/igmpproxy/commit/f0b483a2a02574c1e0ffde68b227c8c8bd689a7e
You can also pull it for OpenWRT from github:
https://github.com/eriktews/openwrt/commit/f3209741ae830b2345be5edc0e3f4ee175aca0ee
I also opened a ticket https://dev.openwrt.org/ticket/19148 which
references this patch for the 14.07 release.
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;
++ }
++}
++
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/openwrt-devel/attachments/20150317/a926c39e/attachment.sig>
-------------- next part --------------
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list