aboutsummaryrefslogtreecommitdiffstats
path: root/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch
blob: 24aefcef267ecb948d664569941b50743387f9ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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;
+    }
+}
+