summaryrefslogtreecommitdiff
path: root/cleopatre/application
diff options
context:
space:
mode:
authorYacine Belkadi2011-03-11 17:35:33 +0100
committerYacine Belkadi2011-03-25 12:01:15 +0100
commit55932d12e74886e8c7079a5b2cf658a4eff0fb2a (patch)
tree99ef4412a1ebf7b380736a90b934c59ffdff5df4 /cleopatre/application
parentf5fa9857bec6fe203c2f009132d71242bea42180 (diff)
cleo/app/igmp_snoopd: update mcast file and warn plcd only on change, refs #2368
Now, igmp_snoopd only writes a new multicast info file if there really is a change. And it only warns plcd if there is a change.
Diffstat (limited to 'cleopatre/application')
-rw-r--r--cleopatre/application/igmp_snoopd/inc/internal.h42
-rw-r--r--cleopatre/application/igmp_snoopd/inc/write_file.h22
-rw-r--r--cleopatre/application/igmp_snoopd/src/main.c27
-rw-r--r--cleopatre/application/igmp_snoopd/src/write_file.c320
4 files changed, 329 insertions, 82 deletions
diff --git a/cleopatre/application/igmp_snoopd/inc/internal.h b/cleopatre/application/igmp_snoopd/inc/internal.h
index f0617a7bb8..da0afc8af2 100644
--- a/cleopatre/application/igmp_snoopd/inc/internal.h
+++ b/cleopatre/application/igmp_snoopd/inc/internal.h
@@ -3,9 +3,17 @@
#include <net/ethernet.h>
+#include "libspid.h"
+
#include "data_struct.h"
#include "igmp_common.h"
+/* Maximum number of multicast groups */
+#define MCAST_GROUP_MAX_NB 12
+
+/* Maxium number of members in a multicast group */
+#define MCAST_MEMBER_MAX_NB 1
+
/** IGMP V3 metrics */
struct v3_metrics
{
@@ -28,6 +36,30 @@ struct v3_metrics
duration_sec_t other_querier_present_interval;
};
+/** An entry in the multicast info. An entry represents information about
+ * a groups and its members. */
+struct multicast_info_entry
+{
+ /** The group MAC address. */
+ unsigned char group_mac_addr[LIBSPID_MAC_BIN_LEN];
+
+ /** The number of members in the group. */
+ size_t member_count;
+
+ /** The addresses of the members in the group. */
+ unsigned char members_mac_addr[MCAST_MEMBER_MAX_NB][LIBSPID_MAC_BIN_LEN];
+};
+
+/** The content of the multicast info. */
+struct multicast_info
+{
+ /** The number of entries (groups). */
+ size_t entry_count;
+
+ /** The entries. */
+ struct multicast_info_entry entries[MCAST_GROUP_MAX_NB];
+};
+
/** The context */
struct context
{
@@ -36,6 +68,9 @@ struct context
/** The IGMP v3 metrics. */
struct v3_metrics metrics;
+
+ /** The last multicast info entries written to a file. */
+ struct multicast_info *multicast_info;
};
/**
@@ -45,6 +80,12 @@ struct context
void init_v3 (struct v3_metrics *metrics);
/**
+ * Initialize a multicast_info structure.
+ * \param mcast_info The structure to initialize.
+ */
+void init_multicast_info (struct multicast_info *mcast_info);
+
+/**
* Process a v1 query.
*/
void process_v1_query ();
@@ -104,4 +145,3 @@ void del_inactive (struct context *ctx);
void dump_info_v3 (const struct v3_metrics *metrics);
#endif /* INTERNAL_H */
-
diff --git a/cleopatre/application/igmp_snoopd/inc/write_file.h b/cleopatre/application/igmp_snoopd/inc/write_file.h
index fefd370131..9cf7cbeceb 100644
--- a/cleopatre/application/igmp_snoopd/inc/write_file.h
+++ b/cleopatre/application/igmp_snoopd/inc/write_file.h
@@ -2,12 +2,28 @@
#define WRITE_FILE_H
#include "data_struct.h"
+#include "internal.h"
/**
- * Write the list of groups and members to a file.
- * \param path The file to write to.
+ * Update the content of the multicast info. During the process, compare
+ * with previous content to determine whether the info changed and the file
+ * needs to be updated if necessary.
+ * \param mcast_info The previous multicast info that will be
+ * used to detect changes and will eventually be updated.
* \param groups_head The head of the group list.
+ * \return true, if the file needs to be updated because the multicast info
+ * changed.
+ * false, if the file doesn't need to be updated because the multicast
+ * info didn't change since the previous time.
+ */
+bool update_multicast_info (struct multicast_info **multicast_info,
+ const struct list_head_groups *groups_head);
+/**
+ * Write the multicast info to the file.
+ * \param path The file to write to.
+ * \param mcast_info The multicast info to use to write the file.
+ * Passing NULL, writes an empty file.
*/
-void write_to_file (const char *path, const struct list_head_groups *groups_head);
+void write_to_file (const char *path, struct multicast_info *mcast_info);
#endif /* WRITE_FILE_H */
diff --git a/cleopatre/application/igmp_snoopd/src/main.c b/cleopatre/application/igmp_snoopd/src/main.c
index f7ffe0c573..ce12a56341 100644
--- a/cleopatre/application/igmp_snoopd/src/main.c
+++ b/cleopatre/application/igmp_snoopd/src/main.c
@@ -241,6 +241,8 @@ init (struct context *ctx)
LIST_INIT (&ctx->groups_head);
init_v3 (&ctx->metrics);
+
+ ctx->multicast_info = NULL;
}
/**
@@ -259,7 +261,7 @@ dump (const struct context *ctx)
* \param ctx The context.
*/
static void
-igmp_snooping (const char *ifname, const char *output_file, struct context *ctx)
+igmp_snooping (const char *ifname, const char *mcast_info_file, struct context *ctx)
{
int sockfd = create_and_bind_socket (ifname);
if (sockfd == -1)
@@ -282,13 +284,28 @@ igmp_snooping (const char *ifname, const char *output_file, struct context *ctx)
{
del_inactive (ctx);
dump (ctx);
- write_to_file (output_file, &ctx->groups_head);
- libspid_error_t status = libspid_system_file_update_warn (getpid (), output_file);
- if (status != LIBSPID_SUCCESS)
+
+ bool should_update_mcast_info_file
+ = update_multicast_info (&ctx->multicast_info, &ctx->groups_head);
+
+ if (should_update_mcast_info_file)
+ {
+ write_to_file (mcast_info_file, ctx->multicast_info);
+ libspid_error_t status = libspid_system_file_update_warn (getpid (), mcast_info_file);
+ if (status != LIBSPID_SUCCESS)
+ {
+ log_error ("libspid_system_file_update_warn: %d", status);
+ }
+ }
+ else
{
- log_error ("libspid_system_file_update_warn: %d", status);
+ log_debug ("no need to update multicast file");
}
}
+ else
+ {
+ log_debug ("packet was not of interest");
+ }
}
}
diff --git a/cleopatre/application/igmp_snoopd/src/write_file.c b/cleopatre/application/igmp_snoopd/src/write_file.c
index c6cb39e9ff..e03ffc2e5a 100644
--- a/cleopatre/application/igmp_snoopd/src/write_file.c
+++ b/cleopatre/application/igmp_snoopd/src/write_file.c
@@ -1,7 +1,6 @@
#include "write_file.h"
#include <errno.h>
-#include <net/ethernet.h>
#include <stdlib.h>
#include <string.h>
@@ -10,19 +9,24 @@
#include "igmp_common.h"
#include "utils.h"
-/** When multiple groups have the same mapped Ethernet MAC address,
- * the list below is used to create a union of their members. */
+/** A member of the union list. */
struct union_member
{
+ /* A member. */
const struct group_member *member;
+
+ /** List management. */
LIST_ENTRY (union_member) union_members;
};
+/** When multiple groups have the same mapped Ethernet MAC address,
+ * the list below is used to create a union of their members. */
struct union_list
{
/** List management. */
LIST_HEAD (list_head_union_members, union_member) head;
+ /** The number of members in the union. */
unsigned int member_count;
};
@@ -39,21 +43,21 @@ union_init_list (struct union_list *u_list)
/**
* Add a group_member to the union list.
- * The union list is sorted by eth_addr to allow faster processing
- * when trying to insert a group_member that is already present in the list.
+ * The union list is sorted by eth_addr, just like the list of members
+ * in a group.
+ *
* \param u_list The union list.
* \param member The member to insert into the union list.
*/
static void
-union_add_member (struct union_list *u_list,
- const struct group_member *member)
+union_add_member (struct union_list *u_list, const struct group_member *member)
{
struct union_member *prev_u_member = NULL;
-
struct union_member *u_member = NULL;
LIST_FOREACH (u_member, &u_list->head, union_members)
{
- int memcmp_result = memcmp (member->eth_addr, u_member->member->eth_addr, ETH_ALEN);
+ int memcmp_result
+ = memcmp (member->eth_addr, u_member->member->eth_addr, ETH_ALEN);
if (memcmp_result == 0)
{
@@ -87,21 +91,242 @@ union_add_member (struct union_list *u_list,
/**
* Add a list of group_members to the union list.
* \param u_list The union list.
- * \param members_head The head of the member list.
+ * \param grp The group containing the members to add.
*/
static void
union_add_members (struct union_list *u_list,
- const struct list_head_members *members_head)
+ const struct group *grp)
{
struct group_member *member;
- LIST_FOREACH (member, members_head, members)
+ LIST_FOREACH (member, &grp->members_head, members)
{
union_add_member (u_list, member);
}
}
+/**
+ * Fill the members part in the multicast info entry.
+ * \param entry The entry to update.
+ * \param grp The group, to retrieve its members.
+ */
+static void
+fill_entry_members (struct multicast_info_entry *entry,
+ const struct group *grp)
+{
+ unsigned int member_idx = 0;
+ struct group_member *member;
+ LIST_FOREACH (member, &grp->members_head, members)
+ {
+ memcpy (entry->members_mac_addr[member_idx], member->eth_addr,
+ LIBSPID_MAC_BIN_LEN);
+
+ member_idx++;
+ }
+
+ entry->member_count = member_idx;
+}
+
+/**
+ * Fill the members part in the multicast info entry, using the union list.
+ * \param entry The entry to update.
+ * \param u_list The union list.
+ */
+static void
+fill_entry_members_from_union (struct multicast_info_entry *entry,
+ struct union_list *u_list)
+{
+ /* Iterate through the union list to write the members.
+ * The union list is deleted in the process */
+
+ unsigned int member_idx = 0;
+ struct union_member *u_member = LIST_FIRST (&u_list->head);
+ while (u_member)
+ {
+ memcpy (entry->members_mac_addr[member_idx],
+ u_member->member->eth_addr,
+ LIBSPID_MAC_BIN_LEN);
+
+ struct union_member *bak = u_member;
+ u_member = LIST_NEXT (u_member, union_members);
+ free(bak);
+
+ member_idx++;
+ }
+
+ union_init_list (u_list);
+
+ entry->member_count = member_idx;
+}
+
+/**
+ * Fill a multicast info entry.
+ * \param entry The entry to fill.
+ * \param grp The group to use to fill the entry.
+ * \param u_list The union list to use (eventually) to fill the entry.
+ * \return 0, on success.
+ * -1, if there were too many members.
+ */
+static int
+fill_entry (struct multicast_info_entry *entry,
+ const struct group *grp,
+ struct union_list *u_list)
+{
+ if (u_list->member_count == 0)
+ {
+ /* The multicast IP address of the current group doesn't map to
+ * the Ethernet MAC address of another group.
+ * We can write the members directly. */
+
+ if (grp->member_count <= MCAST_MEMBER_MAX_NB)
+ {
+ fill_entry_members (entry, grp);
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ /* Add the members of the last group */
+ union_add_members (u_list, grp);
+
+ if (u_list->member_count <= MCAST_MEMBER_MAX_NB)
+ {
+ fill_entry_members_from_union (entry, u_list);
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ /* Now that members are copied and ok, copy the MAC address of the group */
+ memcpy (entry->group_mac_addr, grp->mapped_eth_addr, LIBSPID_MAC_BIN_LEN);
+
+ return 0;
+}
+
+/**
+ * Fill the multicast info.
+ * \param multicast_info The multicast info to fill.
+ * \param groups_head The head of the group list to use.
+ */
+static void
+fill_multicast_info (struct multicast_info *multicast_info,
+ const struct list_head_groups *groups_head)
+{
+ /* We cannot just copy directly the data from groups_head
+ * because some groups map to the same Ethernet MAC address.
+ * For those groups, we have to first create a union of their members. */
+
+ /* Union list of members */
+ struct union_list u_list;
+ union_init_list (&u_list);
+
+ unsigned int grp_idx = 0;
+ struct group *grp = LIST_FIRST (groups_head);
+ while (grp && (grp_idx < MCAST_GROUP_MAX_NB))
+ {
+ struct group *next_grp = LIST_NEXT (grp, groups);
+
+ if (next_grp
+ && CMP_MCAST_ETH_ADDR (grp->mapped_eth_addr,
+ next_grp->mapped_eth_addr) == 0)
+ {
+ /* The next group's multicast IP address maps to the same Ethernet
+ * MAC address as the one for the current group. We cannot write
+ * the members yet, we have first to create a union of the members. */
+
+ union_add_members (&u_list, grp);
+ }
+ else
+ {
+ /* This group is the last of a series of groups that share the same
+ * mapped_eth_addr, or it is the only group with that MAC address.
+ * So we can generate the entry. */
+
+ int ret = fill_entry (&multicast_info->entries[grp_idx], grp, &u_list);
+
+ if (ret == 0)
+ {
+ grp_idx++;
+ }
+ else if (ret == -1)
+ {
+ log_debug ("too many members");
+ }
+ }
+
+ grp = next_grp;
+ }
+
+ multicast_info->entry_count = grp_idx;
+
+ if ((grp_idx == MCAST_GROUP_MAX_NB) && grp != NULL)
+ {
+ log_debug ("too many groups");
+ }
+}
+
+bool
+update_multicast_info (struct multicast_info **multicast_info,
+ const struct list_head_groups *groups_head)
+{
+ struct multicast_info *new_multicast_info =
+ malloc (sizeof (struct multicast_info));
+
+ if (new_multicast_info == NULL)
+ {
+ log_error ("malloc error");
+
+ if (*multicast_info != NULL)
+ {
+ free (*multicast_info);
+ *multicast_info = NULL;
+ }
+
+ return true;
+ }
+
+ /* memset() to ensure correctness of memcmp() */
+ memset (new_multicast_info, 0, sizeof (struct multicast_info));
+
+ fill_multicast_info (new_multicast_info, groups_head);
+
+ if ((*multicast_info == NULL)
+ || (memcmp (*multicast_info, new_multicast_info,
+ sizeof (struct multicast_info)) != 0))
+ {
+ free (*multicast_info);
+ *multicast_info = new_multicast_info;
+ return true;
+ }
+ else
+ {
+ free (new_multicast_info);
+ return false;
+ }
+}
+
+/**
+ * Write the MAC address to the file in string format.
+ * \param fp The file stream.
+ * \param mac_bin The MAC address in binary format.
+ */
+static void
+write_mac_to_file (FILE *fp, const unsigned char *mac_bin)
+{
+ char mac_str[LIBSPID_MAC_STR_LEN];
+ libspid_error_t status;
+
+ status = libspid_mac_bin_to_str (mac_bin, mac_str);
+ assert(status == LIBSPID_SUCCESS);
+ fprintf (fp, "%s%s", mac_str, LIBSPID_MCAST_INFO_DELIMITER);
+}
+
void
-write_to_file (const char *path, const struct list_head_groups *groups_head)
+write_to_file (const char *path, struct multicast_info *mcast_info)
{
/* The new group and members info must not be partially visible.
* The file must be written atomically.
@@ -118,7 +343,7 @@ write_to_file (const char *path, const struct list_head_groups *groups_head)
return;
}
- FILE * fp;
+ FILE *fp;
fp = fdopen (fd, "w");
if (fp == NULL)
{
@@ -126,74 +351,23 @@ write_to_file (const char *path, const struct list_head_groups *groups_head)
return;
}
- /* We cannot just write directly the data from groups_head
- * because some groups map to the same Ethernet MAC address.
- * For those groups, we have to first create a union of their members. */
-
- /* Union list of members */
- struct union_list u_list;
- union_init_list (&u_list);
-
- struct group *grp = LIST_FIRST (groups_head);
- while (grp)
+ if (mcast_info != NULL)
{
- struct group *next_grp = LIST_NEXT (grp, groups);
- if (next_grp && CMP_MCAST_ETH_ADDR (grp->mapped_eth_addr, next_grp->mapped_eth_addr) == 0)
- {
- /* The next group's multicast IP address maps to the same Ethernet MAC address
- * as the one for the current group. We cannot write the members yet,
- * we have first to create a union of the members. */
- union_add_members (&u_list, &grp->members_head);
- }
- else
+ unsigned grp_idx;
+ for (grp_idx = 0; grp_idx < mcast_info->entry_count; grp_idx++)
{
- char mac_str[LIBSPID_MAC_STR_LEN];
- libspid_error_t status;
+ const struct multicast_info_entry *entry = &mcast_info->entries[grp_idx];
- status = libspid_mac_bin_to_str (grp->mapped_eth_addr, mac_str);
- assert(status == LIBSPID_SUCCESS);
- fprintf (fp, "%s%s", mac_str, LIBSPID_MCAST_INFO_DELIMITER);
+ write_mac_to_file (fp, entry->group_mac_addr);
- if (LIST_EMPTY (&u_list.head))
+ unsigned int member_idx;
+ for (member_idx = 0; member_idx < entry->member_count; member_idx++)
{
- /* This group's multicast IP address doesn't map to the Ethernet MAC address
- * of another group. We can write it's members immediately. */
- struct group_member *member;
- LIST_FOREACH (member, &grp->members_head, members)
- {
- status = libspid_mac_bin_to_str (member->eth_addr, mac_str);
- assert(status == LIBSPID_SUCCESS);
- fprintf (fp, "%s%s", mac_str, LIBSPID_MCAST_INFO_DELIMITER);
- }
- }
- else
- {
- /* This group is the last of a series of groups that share the same mapped_eth_addr.
- * We add its members to the union list then write this union list. */
- union_add_members (&u_list, &grp->members_head);
-
- /* We have been creating a union of members and we're done.
- * Now, we write the members (and delete the elements of the union list as we go). */
- struct union_member *u_member = LIST_FIRST (&u_list.head);
- while (u_member)
- {
- status = libspid_mac_bin_to_str (u_member->member->eth_addr, mac_str);
- assert(status == LIBSPID_SUCCESS);
- fprintf (fp, "%s%s", mac_str, LIBSPID_MCAST_INFO_DELIMITER);
-
- struct union_member *bak = u_member;
-
- u_member = LIST_NEXT (u_member, union_members);
- free (bak);
- }
-
- union_init_list (&u_list);
+ write_mac_to_file (fp, entry->members_mac_addr[member_idx]);
}
fprintf (fp, "\n");
}
-
- grp = next_grp;
}
if (fclose (fp) != 0)