add chaos_calmer branch
[15.05/openwrt.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 +