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-2026 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.6.0
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  //Attach TCP/IP stack context
125  context->netContext = settings->interface->netContext;
126 
127  //Save user settings
128  context->interface = settings->interface;
129  context->numPorts = settings->numPorts;
130  context->ports = settings->ports;
131  context->numGroups = settings->numGroups;
132  context->groups = settings->groups;
133  context->floodReports = settings->floodReports;
135  context->lastMemberQueryTime = settings->lastMemberQueryTime;
136 
137  //Loop through multicast groups
138  for(i = 0; i < context->numGroups; i++)
139  {
140  //The "No Members Present" state, when there are no hosts on the network
141  //which have sent reports for this multicast group is the initial state
142  //for all groups
144  }
145 
146  //Get exclusive access
147  netLock(context->netContext);
148  //Attach the IGMP snooping switch context to the network interface
149  interface->igmpSnoopingContext = context;
150  //Release exclusive access
151  netUnlock(context->netContext);
152 
153  //Successful initialization
154  return NO_ERROR;
155 }
156 
157 
158 /**
159  * @brief Start IGMP snooping switch
160  * @param[in] context Pointer to the IGMP snooping switch context
161  * @return Error code
162  **/
163 
165 {
166  //Make sure the IGMP snooping switch context is valid
167  if(context == NULL)
169 
170  //Debug message
171  TRACE_INFO("Starting IGMP snooping switch...\r\n");
172 
173  //Get exclusive access
174  netLock(context->netContext);
175 
176  //Enable IGMP monitoring
178 
179  //The IGMP snooping switch is now running
180  context->running = TRUE;
181 
182  //If a switch receives an unregistered packet, it must forward that packet
183  //on all ports to which an IGMP router is attached. A switch may default to
184  //forwarding unregistered packets on all ports (refer to RFC 4541, section
185  //2.1.2)
186  if(!context->floodUnknownMulticastPackets)
187  {
189  }
190  else
191  {
193  }
194 
195  //Release exclusive access
196  netUnlock(context->netContext);
197 
198  //Successful processing
199  return NO_ERROR;
200 }
201 
202 
203 /**
204  * @brief Stop IGMP snooping switch
205  * @param[in] context Pointer to the IGMP snooping switch context
206  * @return Error code
207  **/
208 
210 {
211  uint_t i;
212 
213  //Make sure the IGMP snooping switch context is valid
214  if(context == NULL)
216 
217  //Debug message
218  TRACE_INFO("Stopping IGMP snooping switch...\r\n");
219 
220  //Get exclusive access
221  netLock(context->netContext);
222 
223  //Disable IGMP monitoring
225  //Flood unregistered multicast traffic to all ports
227 
228  //Clear the list of multicast routers
229  for(i = 0; i < context->numPorts; i++)
230  {
231  context->ports[i].routerPresent = FALSE;
232  }
233 
234  //Clear the list of multicast groups
235  for(i = 0; i < context->numGroups; i++)
236  {
237  //Check whether there are hosts on the network which have sent reports
238  //for this multicast group
240  {
241  //Delete the corresponding entry
242  igmpSnoopingDeleteGroup(context, &context->groups[i]);
243  }
244  }
245 
246  //The IGMP snooping switch is not running anymore
247  context->running = FALSE;
248 
249  //Release exclusive access
250  netUnlock(context->netContext);
251 
252  //Successful processing
253  return NO_ERROR;
254 }
255 
256 
257 /**
258  * @brief IGMP snooping switch timer handler
259  * @param[in] context Pointer to the IGMP snooping switch context
260  **/
261 
263 {
264  uint_t i;
265  bool_t update;
266  uint32_t routerPorts;
267  IgmpSnoopingGroup *group;
268 
269  //Initialize flag
270  update = FALSE;
271 
272  //Check whether the IGMP snooping switch is running
273  if(context->running)
274  {
275  //A switch supporting IGMP snooping must maintain a list of multicast
276  //routers and the ports on which they are attached
277  for(i = 0; i < context->numPorts; i++)
278  {
279  //Check whether any IGMP router is attached to this port
280  if(context->ports[i].routerPresent)
281  {
282  //If the timer has expired, then the router is no longer present
283  if(netTimerExpired(&context->ports[i].timer))
284  {
285  //This port is no longer considered as a router port
286  context->ports[i].routerPresent = FALSE;
287  //The list of router ports has changed
288  update = TRUE;
289  }
290  }
291  }
292 
293  //The snooping switch must update its forwarding table when the list of
294  //router ports has changed
295  if(update)
296  {
297  //Loop through multicast groups
298  for(i = 0; i < context->numGroups; i++)
299  {
300  //Point to the current group
301  group = &context->groups[i];
302 
303  //Check whether there are hosts on the network which have sent reports
304  //for this multicast group
306  {
307  //Update the corresponding entry in forwarding table
308  igmpSnoopingUpdateStaticFdbEntry(context, group->addr);
309  }
310  }
311 
312  //Check whether unregistered packets should be forwarded to router
313  //ports only
314  if(!context->floodUnknownMulticastPackets)
315  {
316  //Retrieve the port map identifying router ports
317  routerPorts = igmpSnoopingGetRouterPorts(context);
318 
319  //Forward unknown multicast packets on all ports to which
320  //an IGMP router is attached
321  igmpSnoopingSetUnknownMcastFwdPorts(context, TRUE, routerPorts);
322  }
323  }
324 
325  //The snooping switch must not rely exclusively on the appearance of IGMP
326  //Group Leave announcements to determine when entries should be removed
327  //from the forwarding table. It should implement a membership timeout
328  //mechanism (refer to RFC 4541, section 2.1.1)
329  for(i = 0; i < context->numGroups; i++)
330  {
331  //Point to the current group
332  group = &context->groups[i];
333 
334  //Check whether there are hosts on the network which have sent reports
335  //for this multicast group
337  {
338  //Membership timeout?
339  if(netTimerExpired(&group->timer))
340  {
341  //If no reports are received after the response time of the last
342  //query expires, the group has no local members
343  igmpSnoopingDeleteGroup(context, group);
344  }
345  }
346  }
347  }
348 }
349 
350 
351 /**
352  * @brief Release IGMP snooping switch context
353  * @param[in] context Pointer to the IGMP snooping switch context
354  **/
355 
357 {
358  NetInterface *interface;
359 
360  //Make sure the IGMP snooping switch context is valid
361  if(context != NULL)
362  {
363  //Get exclusive access
364  netLock(context->netContext);
365 
366  //Point to the underlying network interface
367  interface = context->interface;
368  //Detach the IGMP snooping switch context from the network interface
369  interface->igmpSnoopingContext = NULL;
370 
371  //Release exclusive access
372  netUnlock(context->netContext);
373 
374  //Clear IGMP snooping switch context
375  osMemset(context, 0, sizeof(IgmpSnoopingContext));
376  }
377 }
378 
379 #endif
void netUnlock(NetContext *context)
Release exclusive access to the core of the TCP/IP stack.
Definition: net.c:319
int bool_t
Definition: compiler_port.h:63
bool_t floodReports
Flood IGMP report messages to all ports (not only to router ports)
Definition: igmp_snooping.h:98
void igmpSnoopingDeinit(IgmpSnoopingContext *context)
Release IGMP snooping switch context.
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:40
IGMP snooping settings.
Definition: igmp_snooping.h:92
#define TRACE_INFO(...)
Definition: debug.h:105
Ipv4Addr addr
Multicast group address.
Definition: igmp_snooping.h:81
bool_t running
Operational state of the IGMP snooping switch.
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
NetContext * netContext
TCP/IP stack context.
uint_t numGroups
Maximum number of multicast groups.
Definition: igmp_snooping.h:96
bool_t floodReports
Flood IGMP report messages to all ports (not only to router ports)
void netLock(NetContext *context)
Get exclusive access to the core of the TCP/IP stack.
Definition: net.c:307
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:57
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
systime_t lastMemberQueryTime
Leave latency.
bool_t netTimerExpired(NetTimer *timer)
Check whether the timer has expired.
Definition: net_misc.c:838
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
IgmpSnoopingGroup * groups
Multicast groups.
Definition: igmp_snooping.h:97