igmp_snooping.c
Go to the documentation of this file.
1 /**
2  * @file igmp_snooping.c
3  * @brief IGMP snooping switch
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * In the case of IP multicast traffic, an IGMP snooping switch provides the
30  * benefit of conserving bandwidth on those segments of the network where no
31  * node has expressed interest in receiving packets addressed to the group
32  * address. Refer to the following RFCs for complete details:
33  * - RFC 1112: Host Extensions for IP Multicasting
34  * - RFC 2236: Internet Group Management Protocol, Version 2
35  * - RFC 3376: Internet Group Management Protocol, Version 3
36  * - RFC 4541: Considerations for IGMP and MLD Snooping Switches
37  *
38  * @author Oryx Embedded SARL (www.oryx-embedded.com)
39  * @version 2.4.4
40  **/
41 
42 //Switch to the appropriate trace level
43 #define TRACE_LEVEL IGMP_TRACE_LEVEL
44 
45 //Dependencies
46 #include "core/net.h"
47 #include "ipv4/ipv4.h"
48 #include "ipv4/ipv4_misc.h"
49 #include "igmp/igmp_snooping.h"
51 #include "debug.h"
52 
53 //Check TCP/IP stack configuration
54 #if (IPV4_SUPPORT == ENABLED && IGMP_SNOOPING_SUPPORT == ENABLED)
55 
56 
57 /**
58  * @brief Initialize settings with default values
59  * @param[out] settings Structure that contains IGMP snooping settings
60  **/
61 
63 {
64  //Primary interface on an attached network
65  settings->interface = NULL;
66 
67  //Nnumber of ports
68  settings->numPorts = 0;
69  //Ports
70  settings->ports = NULL;
71 
72  //Maximum number of multicast groups
73  settings->numGroups = 0;
74  //Multicast groups
75  settings->groups = NULL;
76 
77  //Flood IGMP report messages to all ports (not only to router ports)
78  settings->floodReports = FALSE;
79  //Flood unregistered multicast traffic to all ports
81 
82  //Leave latency
84 }
85 
86 
87 /**
88  * @brief IGMP snooping switch initialization
89  * @param[in] context Pointer to the IGMP snooping switch context
90  * @param[in] settings IGMP snooping specific settings
91  * @return Error code
92  **/
93 
95  const IgmpSnoopingSettings *settings)
96 {
97  uint_t i;
98  NetInterface *interface;
99 
100  //Debug message
101  TRACE_INFO("Initializing IGMP snooping switch...\r\n");
102 
103  //Ensure the parameters are valid
104  if(context == NULL || settings == NULL)
106 
107  //The IGMP router must be bound to a valid interface
108  if(settings->interface == NULL)
110 
111  //Sanity check
112  if(settings->numPorts < 1 || settings->ports == NULL)
114 
115  if(settings->numGroups < 1 || settings->groups == NULL)
117 
118  //Point to the underlying network interface
119  interface = settings->interface;
120 
121  //Clear the IGMP snooping switch context
122  osMemset(context, 0, sizeof(IgmpSnoopingContext));
123 
124  //Initialize IGMP snooping switch context
125  context->interface = settings->interface;
126  context->numPorts = settings->numPorts;
127  context->ports = settings->ports;
128  context->numGroups = settings->numGroups;
129  context->groups = settings->groups;
130  context->floodReports = settings->floodReports;
132  context->lastMemberQueryTime = settings->lastMemberQueryTime;
133 
134  //Loop through multicast groups
135  for(i = 0; i < context->numGroups; i++)
136  {
137  //The "No Members Present" state, when there are no hosts on the network
138  //which have sent reports for this multicast group is the initial state
139  //for all groups
141  }
142 
143  //Attach the IGMP snooping switch context to the network interface
144  interface->igmpSnoopingContext = context;
145 
146  //Successful initialization
147  return NO_ERROR;
148 }
149 
150 
151 /**
152  * @brief Start IGMP snooping switch
153  * @param[in] context Pointer to the IGMP snooping switch context
154  * @return Error code
155  **/
156 
158 {
159  //Make sure the IGMP snooping switch context is valid
160  if(context == NULL)
162 
163  //Debug message
164  TRACE_INFO("Starting IGMP snooping switch...\r\n");
165 
166  //Get exclusive access
168 
169  //Enable IGMP monitoring
171 
172  //The IGMP snooping switch is now running
173  context->running = TRUE;
174 
175  //If a switch receives an unregistered packet, it must forward that packet
176  //on all ports to which an IGMP router is attached. A switch may default to
177  //forwarding unregistered packets on all ports (refer to RFC 4541, section
178  //2.1.2)
179  if(!context->floodUnknownMulticastPackets)
180  {
182  }
183  else
184  {
186  }
187 
188  //Release exclusive access
190 
191  //Successful processing
192  return NO_ERROR;
193 }
194 
195 
196 /**
197  * @brief Stop IGMP snooping switch
198  * @param[in] context Pointer to the IGMP snooping switch context
199  * @return Error code
200  **/
201 
203 {
204  uint_t i;
205 
206  //Make sure the IGMP snooping switch context is valid
207  if(context == NULL)
209 
210  //Debug message
211  TRACE_INFO("Stopping IGMP snooping switch...\r\n");
212 
213  //Get exclusive access
215 
216  //Disable IGMP monitoring
218  //Flood unregistered multicast traffic to all ports
220 
221  //Clear the list of multicast routers
222  for(i = 0; i < context->numPorts; i++)
223  {
224  context->ports[i].routerPresent = FALSE;
225  }
226 
227  //Clear the list of multicast groups
228  for(i = 0; i < context->numGroups; i++)
229  {
230  //Check whether there are hosts on the network which have sent reports
231  //for this multicast group
233  {
234  //Delete the corresponding entry
235  igmpSnoopingDeleteGroup(context, &context->groups[i]);
236  }
237  }
238 
239  //The IGMP snooping switch is not running anymore
240  context->running = FALSE;
241 
242  //Release exclusive access
244 
245  //Successful processing
246  return NO_ERROR;
247 }
248 
249 
250 /**
251  * @brief IGMP snooping switch timer handler
252  * @param[in] context Pointer to the IGMP snooping switch context
253  **/
254 
256 {
257  uint_t i;
258  bool_t update;
259  uint32_t routerPorts;
260  IgmpSnoopingGroup *group;
261 
262  //Initialize flag
263  update = FALSE;
264 
265  //Check whether the IGMP snooping switch is running
266  if(context->running)
267  {
268  //A switch supporting IGMP snooping must maintain a list of multicast
269  //routers and the ports on which they are attached
270  for(i = 0; i < context->numPorts; i++)
271  {
272  //Check whether any IGMP router is attached to this port
273  if(context->ports[i].routerPresent)
274  {
275  //If the timer has expired, then the router is no longer present
276  if(netTimerExpired(&context->ports[i].timer))
277  {
278  //This port is no longer considered as a router port
279  context->ports[i].routerPresent = FALSE;
280  //The list of router ports has changed
281  update = TRUE;
282  }
283  }
284  }
285 
286  //The snooping switch must update its forwarding table when the list of
287  //router ports has changed
288  if(update)
289  {
290  //Loop through multicast groups
291  for(i = 0; i < context->numGroups; i++)
292  {
293  //Point to the current group
294  group = &context->groups[i];
295 
296  //Check whether there are hosts on the network which have sent reports
297  //for this multicast group
299  {
300  //Update the corresponding entry in forwarding table
301  igmpSnoopingUpdateStaticFdbEntry(context, group->addr);
302  }
303  }
304 
305  //Check whether unregistered packets should be forwarded to router
306  //ports only
307  if(!context->floodUnknownMulticastPackets)
308  {
309  //Retrieve the port map identifying router ports
310  routerPorts = igmpSnoopingGetRouterPorts(context);
311 
312  //Forward unknown multicast packets on all ports to which
313  //an IGMP router is attached
314  igmpSnoopingSetUnknownMcastFwdPorts(context, TRUE, routerPorts);
315  }
316  }
317 
318  //The snooping switch must not rely exclusively on the appearance of IGMP
319  //Group Leave announcements to determine when entries should be removed
320  //from the forwarding table. It should implement a membership timeout
321  //mechanism (refer to RFC 4541, section 2.1.1)
322  for(i = 0; i < context->numGroups; i++)
323  {
324  //Point to the current group
325  group = &context->groups[i];
326 
327  //Check whether there are hosts on the network which have sent reports
328  //for this multicast group
330  {
331  //Membership timeout?
332  if(netTimerExpired(&group->timer))
333  {
334  //If no reports are received after the response time of the last
335  //query expires, the group has no local members
336  igmpSnoopingDeleteGroup(context, group);
337  }
338  }
339  }
340  }
341 }
342 
343 #endif
int bool_t
Definition: compiler_port.h:53
#define netMutex
Definition: net_legacy.h:195
bool_t floodReports
Flood IGMP report messages to all ports (not only to router ports)
Definition: igmp_snooping.h:98
void igmpSnoopingSetUnknownMcastFwdPorts(IgmpSnoopingContext *context, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
#define TRUE
Definition: os_port.h:50
error_t igmpSnoopingStop(IgmpSnoopingContext *context)
Stop IGMP snooping switch.
void igmpSnoopingGetDefaultSettings(IgmpSnoopingSettings *settings)
Initialize settings with default values.
Definition: igmp_snooping.c:62
uint_t numPorts
Number of ports.
Definition: igmp_snooping.h:94
uint32_t igmpSnoopingGetRouterPorts(IgmpSnoopingContext *context)
void igmpSnoopingTick(IgmpSnoopingContext *context)
IGMP snooping switch timer handler.
#define IGMP_LAST_MEMBER_QUERY_TIME
Definition: igmp_common.h:102
IGMP snooping switch.
error_t igmpSnoopingStart(IgmpSnoopingContext *context)
Start IGMP snooping switch.
void igmpSnoopingUpdateStaticFdbEntry(IgmpSnoopingContext *context, Ipv4Addr groupAddr)
Update a entry of the static MAC table.
IgmpSnoopingGroupState state
Multicast group state.
Definition: igmp_snooping.h:80
void igmpSnoopingDeleteGroup(IgmpSnoopingContext *context, IgmpSnoopingGroup *group)
Delete a multicast group.
IgmpSnoopingPort * ports
Ports.
Definition: igmp_snooping.h:95
systime_t lastMemberQueryTime
Leave latency.
uint_t numPorts
Number of ports.
Helper functions for IPv4.
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t igmpSnoopingInit(IgmpSnoopingContext *context, const IgmpSnoopingSettings *settings)
IGMP snooping switch initialization.
Definition: igmp_snooping.c:94
error_t
Error codes.
Definition: error.h:43
@ IGMP_SNOOPING_GROUP_STATE_NO_MEMBERS_PRESENT
Definition: igmp_snooping.h:57
NetInterface * interface
The primary interface on an attached network.
bool_t floodUnknownMulticastPackets
Flood unregistered multicast traffic to all ports.
IgmpSnoopingGroup * groups
Multicast groups.
#define NetInterface
Definition: net.h:36
IGMP snooping settings.
Definition: igmp_snooping.h:92
#define TRACE_INFO(...)
Definition: debug.h:95
Ipv4Addr addr
Multicast group address.
Definition: igmp_snooping.h:81
void igmpSnoopingEnableMonitoring(IgmpSnoopingContext *context, bool_t enable)
Enable IGMP monitoring.
uint_t numGroups
Maximum number of multicast groups.
NetInterface * interface
Underlying network interface.
Definition: igmp_snooping.h:93
uint_t numGroups
Maximum number of multicast groups.
Definition: igmp_snooping.h:96
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
bool_t floodReports
Flood IGMP report messages to all ports (not only to router ports)
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
bool_t floodUnknownMulticastPackets
Flood unregistered multicast traffic to all ports.
Definition: igmp_snooping.h:99
IgmpSnoopingPort * ports
Ports.
IPv4 (Internet Protocol Version 4)
Helper functions for IGMP snooping switch.
Multicast group.
Definition: igmp_snooping.h:79
IGMP snooping switch context.
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
TCP/IP stack core.
systime_t lastMemberQueryTime
Leave latency.
bool_t netTimerExpired(NetTimer *timer)
Check whether the timer has expired.
Definition: net_misc.c:806
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
IgmpSnoopingGroup * groups
Multicast groups.
Definition: igmp_snooping.h:97