igmpproxy: Multiple downlink interfaces fix.
[openwrt/svn-archive/archive.git] / package / network / services / igmpproxy / patches / 250-fix_multiple_downlink_interfaces.patch
1 --- a/src/igmpproxy.h
2 +++ b/src/igmpproxy.h
3 @@ -251,6 +251,7 @@ int activateRoute(uint32_t group, uint32
4 void ageActiveRoutes();
5 void setRouteLastMemberMode(uint32_t group);
6 int lastMemberGroupAge(uint32_t group);
7 +int interfaceInRoute(int32_t group, int Ix);
8
9 /* request.c
10 */
11 --- a/src/request.c
12 +++ b/src/request.c
13 @@ -41,10 +41,10 @@
14
15 // Prototypes...
16 void sendGroupSpecificMemberQuery(void *argument);
17 -
18 +
19 typedef struct {
20 uint32_t group;
21 - uint32_t vifAddr;
22 + // uint32_t vifAddr;
23 short started;
24 } GroupVifDesc;
25
26 @@ -142,7 +142,7 @@ void acceptLeaveMessage(uint32_t src, ui
27
28 // Call the group spesific membership querier...
29 gvDesc->group = group;
30 - gvDesc->vifAddr = sourceVif->InAdr.s_addr;
31 + // gvDesc->vifAddr = sourceVif->InAdr.s_addr;
32 gvDesc->started = 0;
33
34 sendGroupSpecificMemberQuery(gvDesc);
35 @@ -159,6 +159,9 @@ void acceptLeaveMessage(uint32_t src, ui
36 */
37 void sendGroupSpecificMemberQuery(void *argument) {
38 struct Config *conf = getCommonConfig();
39 + struct IfDesc *Dp;
40 + struct RouteTable *croute;
41 + int Ix;
42
43 // Cast argument to correct type...
44 GroupVifDesc *gvDesc = (GroupVifDesc*) argument;
45 @@ -166,22 +169,38 @@ void sendGroupSpecificMemberQuery(void *
46 if(gvDesc->started) {
47 // If aging returns false, we don't do any further action...
48 if(!lastMemberGroupAge(gvDesc->group)) {
49 + // FIXME: Should we free gvDesc here?
50 return;
51 }
52 } else {
53 gvDesc->started = 1;
54 }
55
56 - // Send a group specific membership query...
57 - sendIgmp(gvDesc->vifAddr, gvDesc->group,
58 - IGMP_MEMBERSHIP_QUERY,
59 - conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
60 - gvDesc->group, 0);
61 -
62 - my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
63 - inetFmt(gvDesc->vifAddr,s1), inetFmt(gvDesc->group,s2),
64 - conf->lastMemberQueryInterval);
65 -
66 + /**
67 + * FIXME: This loops through all interfaces the group is active on an sends queries.
68 + * 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.
69 + */
70 +
71 + // Loop through all downstream interfaces
72 + for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
73 + if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
74 + if(Dp->state == IF_STATE_DOWNSTREAM) {
75 + // Is that interface used in the group?
76 + if (interfaceInRoute(gvDesc->group ,Dp->index)) {
77 +
78 + // Send a group specific membership query...
79 + sendIgmp(Dp->InAdr.s_addr, gvDesc->group,
80 + IGMP_MEMBERSHIP_QUERY,
81 + conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
82 + gvDesc->group, 0);
83 +
84 + my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
85 + inetFmt(Dp->InAdr.s_addr,s1), inetFmt(gvDesc->group,s2),
86 + conf->lastMemberQueryInterval);
87 + }
88 + }
89 + }
90 + }
91 // Set timeout for next round...
92 timer_setTimer(conf->lastMemberQueryInterval, sendGroupSpecificMemberQuery, gvDesc);
93
94 --- a/src/rttable.c
95 +++ b/src/rttable.c
96 @@ -428,6 +428,25 @@ void ageActiveRoutes() {
97 }
98
99 /**
100 +* Counts the number of interfaces a given route is active on
101 +*/
102 +int numberOfInterfaces(struct RouteTable *croute) {
103 + int Ix;
104 + struct IfDesc *Dp;
105 + int result = 0;
106 + // Loop through all interfaces
107 + for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
108 + // If the interface is used by the route, increase counter
109 + if(BIT_TST(croute->vifBits, Dp->index)) {
110 + result++;
111 + }
112 + }
113 + my_log(LOG_DEBUG, 0, "counted %d interfaces", result);
114 + return result;
115 +}
116 +
117 +
118 +/**
119 * Should be called when a leave message is recieved, to
120 * mark a route for the last member probe state.
121 */
122 @@ -439,8 +458,11 @@ void setRouteLastMemberMode(uint32_t gro
123 if(croute!=NULL) {
124 // Check for fast leave mode...
125 if(croute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) {
126 - // Send a leave message right away..
127 - sendJoinLeaveUpstream(croute, 0);
128 + // Send a leave message right away only when the route has been active on only one interface
129 + if (numberOfInterfaces(croute) <= 1) {
130 + my_log(LOG_DEBUG, 0, "Leaving group %d now", group);
131 + sendJoinLeaveUpstream(croute, 0);
132 + }
133 }
134 // Set the routingstate to Last member check...
135 croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER;
136 @@ -677,3 +699,18 @@ void logRouteTable(char *header) {
137
138 my_log(LOG_DEBUG, 0, "-----------------------------------------------------");
139 }
140 +
141 +/**
142 +* Returns true when the given group belongs to the given interface
143 +*/
144 +int interfaceInRoute(int32_t group, int Ix) {
145 + struct RouteTable* croute;
146 + croute = findRoute(group);
147 + if (croute != NULL) {
148 + my_log(LOG_DEBUG, 0, "Interface id %d is in group $d", Ix, group);
149 + return BIT_TST(croute->vifBits, Ix);
150 + } else {
151 + return 0;
152 + }
153 +}
154 +