Replace mem_malloc call by memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the value). It will avoid potential fragmentation problems, use a counter to know how many times a group is used on an netif, and free it when all applications leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity check if LWIP_IGMP!=0).

This commit is contained in:
fbernon 2007-09-04 15:15:20 +00:00
parent d794357504
commit d4616a7fc6
7 changed files with 131 additions and 44 deletions

View File

@ -19,6 +19,14 @@ HISTORY
++ New features:
2007-09-04 Frédéric Bernon, Bill Florac
* igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by
memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the
value). It will avoid potential fragmentation problems, use a counter to know
how many times a group is used on an netif, and free it when all applications
leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity
check if LWIP_IGMP!=0).
2007-09-03 Frédéric Bernon
* igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement".
Initialize igmp_mac_filter to NULL in netif_add (this field should be set in

View File

@ -84,6 +84,9 @@
#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
#error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
#endif
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
#endif
#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
#endif

View File

@ -93,8 +93,7 @@ Steve Reynolds
#include "string.h"
/* IGMP support available? */
#if defined(LWIP_IGMP) && (LWIP_IGMP > 0)
#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
/*-----------------------------------------------------------------------------
* Globales
@ -133,10 +132,14 @@ igmp_start(struct netif *netif)
group = igmp_lookup_group(netif, &allsystems);
if (group != NULL) {
group->group_state = IDLE_MEMBER;
group->group_state = IGMP_GROUP_IDLE_MEMBER;
group->use++;
/* Allow the igmp messages at the MAC level */
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
ip_addr_debug_print(IGMP_DEBUG, &allsystems);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);
}
@ -192,16 +195,17 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
return group;
}
/* Group doesn't exist yet, create a new one. */
group = mem_malloc(sizeof(struct igmp_group));
/* Group doesn't exist yet, create a new one */
group = memp_malloc(MEMP_IGMP_GROUP);
if (group != NULL) {
group->interface = ifp;
ip_addr_set(&(group->group_address), addr);
group->timer = 0; /* Not running */
group->group_state = NON_MEMBER;
group->group_state = IGMP_GROUP_NON_MEMBER;
group->last_reporter_flag = 0;
group->use = 0;
group->next = igmp_group_list;
igmp_group_list = group;
}
@ -212,6 +216,39 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
return group;
}
/**
* Remove a group in the global igmp_group_list
*
* @param group the group to remove from the global igmp_group_list
* @return ERR_OK if group was removed from the list, an err_t otherwise
*/
err_t
igmp_remove_group(struct igmp_group *group)
{
err_t err = ERR_OK;
/* Is it the first group? */
if (igmp_group_list == group) {
igmp_group_list = group->next;
} else {
/* look for group further down the list */
struct igmp_group *tmpGroup;
for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
if (tmpGroup->next == group) {
tmpGroup->next = group->next;
break;
}
}
/* Group not found in the global igmp_group_list */
if (tmpGroup == NULL)
err = ERR_ARG;
}
/* free group */
memp_free(MEMP_IGMP_GROUP, group);
return err;
}
/**
* Called from ip_input() if a new IGMP packet is received.
*
@ -309,10 +346,10 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
IGMP_STATS_INC(igmp.report_rxed);
if (group->group_state == DELAYING_MEMBER) {
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
/* This is on a specific group we have already looked up */
group->timer = 0; /* stopped */
group->group_state = IDLE_MEMBER;
group->group_state = IGMP_GROUP_IDLE_MEMBER;
group->last_reporter_flag = 0;
}
break;
@ -343,6 +380,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
/* make sure it is multicast address */
LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
/* loop through netif's */
netif = netif_list;
@ -354,15 +392,19 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
if (group != NULL) {
/* This should create a new group, check the state to make sure */
if (group->group_state != NON_MEMBER) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state NON_MEMBER\n"));
if (group->group_state != IGMP_GROUP_NON_MEMBER) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
} else {
/* OK - it was new group */
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
if (netif->igmp_mac_filter != NULL) {
/* If first use of the group, allow the group at the MAC level */
if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
}
@ -372,8 +414,10 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
/* Need to work out where this timer comes from */
group->group_state = DELAYING_MEMBER;
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
}
/* Increment group use */
group->use++;
/* Join on this interface */
err = ERR_OK;
} else {
@ -406,6 +450,7 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
/* make sure it is multicast address */
LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
/* loop through netif's */
netif = netif_list;
@ -421,19 +466,32 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
if (group->last_reporter_flag) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
IGMP_STATS_INC(igmp.leave_sent);
igmp_send(group, IGMP_LEAVE_GROUP);
}
/* The block is not deleted since the group still exists and we may rejoin */
group->last_reporter_flag = 0;
group->group_state = NON_MEMBER;
group->timer = 0;
if (netif->igmp_mac_filter != NULL) {
netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
/* If there is no other use of the group */
if (group->use <= 1) {
/* If we are the last reporter for this group */
if (group->last_reporter_flag) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
IGMP_STATS_INC(igmp.leave_sent);
igmp_send(group, IGMP_LEAVE_GROUP);
}
/* Disable the group at the MAC level */
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
}
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
/* Free the group */
igmp_remove_group(group);
} else {
/* Decrement group use */
group->use--;
}
/* Leave on this interface */
err = ERR_OK;
@ -478,8 +536,8 @@ igmp_tmr(void)
void
igmp_timeout(struct igmp_group *group)
{
/* If the state is DELAYING_MEMBER then we send a report for this group */
if (group->group_state == DELAYING_MEMBER) {
/* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));
@ -524,9 +582,9 @@ igmp_stop_timer(struct igmp_group *group)
void
igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
{
if ((group->group_state == IDLE_MEMBER) || ((group->group_state == DELAYING_MEMBER) && (maxresp > group->timer))) {
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
igmp_start_timer(group, (maxresp)/2);
group->group_state = DELAYING_MEMBER;
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
}
}

View File

@ -44,6 +44,7 @@
#include "lwip/udp.h"
#include "lwip/raw.h"
#include "lwip/tcp.h"
#include "lwip/igmp.h"
#include "lwip/api.h"
#include "lwip/api_msg.h"
#include "lwip/tcpip.h"

View File

@ -36,9 +36,9 @@
#define __LWIP_IGMP_H__
#include "lwip/opt.h"
#include "lwip/inet.h"
/* IGMP support available? */
#if defined(LWIP_IGMP) && (LWIP_IGMP > 0)
#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
#ifdef __cplusplus
extern "C" {
@ -70,17 +70,17 @@ extern "C" {
#define IGMP_ADD_MAC_FILTER 1
/* Group membership states */
#define NON_MEMBER 0
#define DELAYING_MEMBER 1
#define IDLE_MEMBER 2
#define IGMP_GROUP_NON_MEMBER 0
#define IGMP_GROUP_DELAYING_MEMBER 1
#define IGMP_GROUP_IDLE_MEMBER 2
/*
* IGMP packet format.
*/
struct igmp_msg {
u8_t igmp_msgtype;
u8_t igmp_maxresp;
u16_t igmp_checksum;
u8_t igmp_msgtype;
u8_t igmp_maxresp;
u16_t igmp_checksum;
struct ip_addr igmp_group_address;
};
@ -98,11 +98,12 @@ struct igmp_msg {
struct igmp_group {
struct igmp_group *next;
struct netif *interface;
struct ip_addr group_address;
u8_t last_reporter_flag; /* signifies we were the last person to report */
u8_t group_state;
u16_t timer;
struct netif *interface;
struct ip_addr group_address;
u8_t last_reporter_flag; /* signifies we were the last person to report */
u8_t group_state;
u16_t timer;
u8_t use; /* counter of simultaneous uses */
};
@ -115,6 +116,8 @@ struct igmp_group *igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr);
struct igmp_group *igmp_lookup_group(struct netif *ifp, struct ip_addr *addr);
err_t igmp_remove_group(struct igmp_group *group);
void igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest);
err_t igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);
@ -125,7 +128,7 @@ void igmp_tmr(void);
void igmp_timeout( struct igmp_group *group);
void igmp_start_timer( struct igmp_group *group,u8_t max_time);
void igmp_start_timer( struct igmp_group *group, u8_t max_time);
void igmp_stop_timer( struct igmp_group *group);

View File

@ -53,6 +53,10 @@ LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg),
LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE")
#endif /* ARP_QUEUEING */
#if LWIP_IGMP
LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP")
#endif /* LWIP_IGMP */
#if NO_SYS==0
LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT")
#endif /* NO_SYS==0 */

View File

@ -221,6 +221,16 @@
#define MEMP_NUM_ARP_QUEUE 30
#endif
/**
* MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces
* can be members et the same time (one per netif - allsystems group -, plus one
* per netif membership).
* (requires the LWIP_IGMP option)
*/
#ifndef MEMP_NUM_IGMP_GROUP
#define MEMP_NUM_IGMP_GROUP 8
#endif
/**
* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.
* (requires NO_SYS==0)