[lnst] README: Adding some documentation for multicast
by Jiří Pírko
commit 0f462b80da24b008d04cae71adabdc829693bb4f
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu May 3 11:28:32 2012 +0200
README: Adding some documentation for multicast
New readme file for multicast test tools that documents
behavior of various setups and what can be tested with them.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
test_tools/multicast/README | 120 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 120 insertions(+), 0 deletions(-)
---
diff --git a/test_tools/multicast/README b/test_tools/multicast/README
new file mode 100644
index 0000000..b067721
--- /dev/null
+++ b/test_tools/multicast/README
@@ -0,0 +1,120 @@
+Multicast Testing Tools
+=======================
+
+This is a set of test setups and scripts for multicast testing in Linux kernel.
+There are generaly four types of ready-to-use testing tools included in this
+package and also a library you can use to build your own setup for testing.
+
+
+Structure
+---------
+
+The structure is following:
+
+* **client/** - contains client setups (generaly programs that send data)
+* **offline/** - here goes all tests, that are performed offline
+* **scripts/** - helper scripts in bash/python
+* **server/** - setups of servers (programs that receive)
+* *igmp\_utils.h* - sending IGMP packets over IPPROTO\_RAW socket
+* *multicast\_utils.h* - sending/receiving IPv4 multicast
+* *parameters.h* - parsing options
+* *sockopt\_utils.h* - offline conformance testing of socket options
+
+
+Setups
+------
+
+### Parameters ###
+
+Execution of each test setup can be controled via a set of options. These
+parameters are passed to the setup through CLI arguments. There are long and
+short version for each option.
+
+
+### Test Results ###
+
+Each test setup returns results in the following format for easy parsing:
+
+ name="value"
+ packets_transfered=5
+
+Double-quotes around the value are optional.
+
+
+### Clients ###
+
+* **recv\_block\_source** - Join multicast group for some time, start blocking
+ the sender with `IP_BLOCK_SOURCE`. Finaly unblock the source using
+ `IP_UNBLOCK_SOURCE`.
+
+ Returns `packets_received` - number of packets, that correctly arrived and
+ `packets_received_while_blocking` - number of packets received while the
+ source was blocked (which should always be zero).
+
+* **recv\_membership** - Join multicast group and leave in the middle of
+ ongoing communication.
+
+ Returns `packets_received` -- number of correctly received packets and
+ `packets_received_after_drop` -- number of packets received after leaving
+ the multicast group.
+
+* **recv\_simple** - Simple setup that joins multicast group and listens
+ for data.
+
+ Returns `packets_received`.
+
+* **recv\_source\_membership** - Same as the **recv\_membership** setup, only
+ for source specific multicast.
+
+
+### Servers ###
+
+* **send\_simple** - This setup allows you to emitt multicast packets
+ with specific parameters to some multicast group. Run with -h option
+ in order to find out all controlalble parameters of this setup.
+
+ Returns `packets_sent` - number of packets passed to network.
+
+* **send\_igmp\_query** - This setup is able to send IP datagrams with IGMP
+ queries of all versions. It uses RAW sockets so it must be run with
+ super-user priviledges.
+
+ Returns nothing.
+
+
+### Offline ###
+
+* **sockopt\_block\_source** - `IP_BLOCK_SOURCE` and `IP_UNBLOCK_SOURCE`
+ offline conformance tests
+
+ Returns list of passed tests.
+
+* **sockopt\_if** - `IP_MULTICAST_IF` conformance test
+
+ Returns list of passed tests.
+
+* **sockopt\_loop** - `IP_MULTICAST_LOOP` conformance test
+
+ Returns list of passed tests.
+
+* **sockopt\_membership** - `IP_ADD_MEMBERSHIP` and `IP_DROP_MEMBERSHIP`
+ conformance test
+
+ Returns list of passed tests.
+
+* **sockopt\_source\_membership** - `IP_ADD_SOURCE_MEMBERSHIP` and
+ `IP_DROP_SOURCE_MEMBERSHIP` conformance test
+
+ Returns list of passed tests.
+
+* **sockopt\_ttl** - `IP_MULTICAST_TTL` conformance test
+
+ Returns list of passed tests.
+
+
+Author
+------
+
+Radek Pazdera ([rpazdera@redhat.com](mailto:rpazdera@redhat.com))
+
+This was developed as part of LNST framework.
11 years, 12 months
[lnst] igmp: Adding setup for sending IGMP queries
by Jiří Pírko
commit b1c8521214090b55c89332bcc020d42227f4a544
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu May 3 11:23:57 2012 +0200
igmp: Adding setup for sending IGMP queries
This commit adds a completely new setup into multicast test tools:
send_igmp_query
It's capable of sending IGMP queries of any version with various
parameters (even malformed ones).
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
test_tools/multicast/Makefile | 2 +-
test_tools/multicast/client/send_igmp_query.c | 168 ++++++++++++++++++++++++
test_tools/multicast/igmp_utils.h | 167 ++++++++++++++++++++++++
test_tools/multicast/parameters.h | 173 ++++++++++++++++++++++---
4 files changed, 490 insertions(+), 20 deletions(-)
---
diff --git a/test_tools/multicast/Makefile b/test_tools/multicast/Makefile
index e09746c..90b0a83 100644
--- a/test_tools/multicast/Makefile
+++ b/test_tools/multicast/Makefile
@@ -2,7 +2,7 @@ CC=gcc
TOOLS_DIR=.
CFLAGS=-Wall -Wextra -I$(TOOLS_DIR)
-SENDERS=send_simple
+SENDERS=send_simple send_igmp_query
RECEIVERS=recv_simple recv_membership recv_source_membership recv_block_source
OFFLINE=sockopt_loop sockopt_ttl sockopt_if sockopt_membership sockopt_source_membership sockopt_block_source max_groups
diff --git a/test_tools/multicast/client/send_igmp_query.c b/test_tools/multicast/client/send_igmp_query.c
new file mode 100644
index 0000000..de5e608
--- /dev/null
+++ b/test_tools/multicast/client/send_igmp_query.c
@@ -0,0 +1,168 @@
+/*
+ * send_igmp_query.c - igmp querier simulator
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "igmp_utils.h"
+
+void general_query(int sockfd, struct in_addr saddr)
+{
+ int len = sizeof(struct iphdr) + sizeof(struct ipopts)
+ + sizeof(struct igmphdr);
+
+ unsigned char *buffer = malloc(len);
+ if (buffer == NULL) {
+ perror("malloc()");
+ exit(EXIT_FAILURE);
+ }
+
+ struct iphdr *ip_header = (struct iphdr *) buffer;
+
+ struct ipopts *ip_options = (struct ipopts *)(buffer + sizeof(struct iphdr));
+
+ struct igmphdr *igmp_header;
+ igmp_header = (struct igmphdr *) (buffer + sizeof(struct iphdr)
+ + sizeof(struct ipopts));
+
+ struct in_addr daddr;
+ inet_aton("224.0.0.1", &daddr);
+ ip_header_init(ip_header, saddr, daddr);
+ ip_options_init(ip_options);
+
+ igmp_header->type = IGMP_HOST_MEMBERSHIP_QUERY;
+ igmp_header->code = 0;
+
+ /* IGMPv1 general query */
+ igmp_header->group = 0;
+
+ igmp_header->csum = 0;
+ igmp_header->csum = checksum((unsigned short *) igmp_header,
+ sizeof(struct igmphdr));
+ send_ip_frame(sockfd, daddr, buffer, len);
+ free(buffer);
+}
+
+void group_specific_query(int sockfd, struct in_addr saddr,
+ struct in_addr daddr,struct in_addr group,
+ int max_resp_time)
+{
+ int len = sizeof(struct iphdr) + sizeof(struct ipopts)
+ + sizeof(struct igmphdr);
+
+ unsigned char *buffer = malloc(len);
+ if (buffer == NULL) {
+ perror("malloc()");
+ exit(EXIT_FAILURE);
+ }
+
+ struct iphdr *ip_header = (struct iphdr *) buffer;
+
+ struct ipopts *ip_options = (struct ipopts *)(buffer + sizeof(struct iphdr));
+
+ struct igmphdr *igmp_header;
+ igmp_header = (struct igmphdr *) (buffer + sizeof(struct iphdr)
+ + sizeof(struct ipopts));
+
+ ip_header_init(ip_header, saddr, daddr);
+ ip_options_init(ip_options);
+
+ igmp_header->type = IGMP_HOST_MEMBERSHIP_QUERY;
+ igmp_header->code = max_resp_time;
+
+ igmp_header->group = group.s_addr;
+
+ igmp_header->csum = 0;
+ igmp_header->csum = checksum((unsigned short *) igmp_header,
+ sizeof(struct igmphdr));
+
+ send_ip_frame(sockfd, daddr, buffer, len);
+ free(buffer);
+}
+
+void group_and_source_specific_query(int sockfd, struct in_addr saddr,
+ struct in_addr daddr, struct in_addr group,
+ struct in_addr *sources, int num_sources,
+ int max_resp_time)
+{
+ int len = sizeof(struct iphdr) + sizeof(struct ipopts)
+ + sizeof(struct igmpv3_query) + num_sources*sizeof(__be32);
+
+ unsigned char *buffer = malloc(len);
+ if (buffer == NULL) {
+ perror("malloc()");
+ exit(EXIT_FAILURE);
+ }
+
+ struct iphdr *ip_header = (struct iphdr *) buffer;
+
+ struct ipopts *ip_options = (struct ipopts *)(buffer + sizeof(struct iphdr));
+
+ struct igmpv3_query *igmp_header;
+ igmp_header = (struct igmpv3_query *) (buffer + sizeof(struct iphdr)
+ + sizeof(struct ipopts));
+
+ ip_header_init(ip_header, saddr, daddr);
+ ip_options_init(ip_options);
+
+ igmp_header->type = IGMP_HOST_MEMBERSHIP_QUERY;
+ igmp_header->code = max_resp_time;
+
+ igmp_header->group = group.s_addr;
+
+ int i;
+ for (i = 0; i < num_sources; i++)
+ igmp_header->srcs[i] = sources[i].s_addr;
+
+ igmp_header->csum = 0;
+ igmp_header->csum = checksum((unsigned short *) igmp_header,
+ sizeof(struct igmpv3_query) +
+ num_sources*sizeof(__be32));
+
+ send_ip_frame(sockfd, daddr, buffer, len);
+ free(buffer);
+}
+
+int main(int argc, char** argv)
+{
+ struct parameters params;
+ parse_args(argc, argv, ¶ms);
+
+ int sockfd = init_raw_socket(params.interface);
+
+ switch(params.query_type) {
+ case IGMP_GENERAL_QUERY:
+ general_query(sockfd, params.interface);
+ break;
+ case IGMP_GROUP_SPECIFIC_QUERY:
+ group_specific_query(sockfd, params.interface,
+ params.destaddr, params.multiaddr,
+ params.max_resp_time);
+ break;
+ case IGMP_GROUP_AND_SOURCE_SPECIFIC_QUERY:
+ group_and_source_specific_query(sockfd,params.interface,
+ params.destaddr, params.multiaddr,
+ ¶ms.sourceaddr, 1,
+ params.max_resp_time);
+
+ break;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/test_tools/multicast/igmp_utils.h b/test_tools/multicast/igmp_utils.h
new file mode 100644
index 0000000..901d01f
--- /dev/null
+++ b/test_tools/multicast/igmp_utils.h
@@ -0,0 +1,167 @@
+/*
+ * igmp_utils.h - tools for sending/receiving IGMP packets
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __IGMP_UTILS_H__
+#define __IGMP_UTILS_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <signal.h>
+#include <time.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <netinet/ip.h>
+#include <linux/igmp.h>
+
+#define IGMP
+#include "parameters.h"
+
+int __verbosity = 0;
+
+/* Verbose print */
+#ifndef printv
+#define printv(args...) \
+ if (__verbosity > 0) \
+ { \
+ printf(args); \
+ fflush(stdout); \
+ }
+#endif
+
+struct ipopt_ra {
+ u_char type;
+ u_char length;
+ uint16_t data;
+};
+
+struct ipopts {
+ struct ipopt_ra ra;
+};
+
+unsigned short checksum(unsigned short *addr, int len)
+{
+ register int nleft = len;
+ register int sum = 0;
+ u_short answer = 0;
+
+ while (nleft > 1) {
+ sum += *addr++;
+ nleft -= 2;
+ }
+
+
+ if (nleft == 1) {
+ *(u_char *)(&answer) = *(u_char *)addr;
+ sum += answer;
+ }
+
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ answer = ~sum;
+ return(answer);
+}
+
+void ip_header_init(struct iphdr *iph, struct in_addr saddr,
+ struct in_addr daddr)
+{
+ iph->version = 4;
+ iph->ihl = 6;
+ iph->tos = 0xc0;
+ iph->id = htons(0);
+ iph->frag_off = htons(0b0100000000000000); /* DF */
+ iph->ttl = 1;
+ iph->protocol = IPPROTO_IGMP;
+
+ iph->saddr = saddr.s_addr;
+ iph->daddr = daddr.s_addr;
+}
+
+void ip_options_init(struct ipopts *options)
+{
+ options->ra.type = 0x94;
+ options->ra.length = 4;
+ options->ra.data = 0;
+}
+
+void send_ip_frame(int sockfd, struct in_addr daddr,
+ unsigned char* buffer, size_t len)
+{
+ struct sockaddr_in servaddr;
+ bzero(&servaddr, sizeof(struct sockaddr_in));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr = daddr;
+
+ int bytes_sent = sendto(sockfd, buffer, len, 0, (struct sockaddr *)&servaddr,
+ sizeof(struct sockaddr_in));
+ if (bytes_sent < 0) {
+ perror("sendto()");
+ exit(EXIT_FAILURE);
+ }
+
+ FILE *fp;
+ fp=fopen("deeebg", "wb");
+ fwrite(buffer, sizeof(char), len, fp);
+}
+
+int init_raw_socket(struct in_addr interface)
+{
+ int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (sockfd < 0) {
+ perror("socket()");
+ exit(EXIT_FAILURE);
+ }
+
+ struct sockaddr_in addr;
+ bzero(&addr, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_addr = interface;
+
+ int result = bind(sockfd, (struct sockaddr *)&addr,
+ sizeof(struct sockaddr_in));
+
+ if (result < 0) {
+ perror("bind()");
+ exit(EXIT_FAILURE);
+ }
+
+ return sockfd;
+}
+
+/** Close a socket */
+void free_socket(int sockfd)
+{
+ close(sockfd);
+}
+
+
+#endif
diff --git a/test_tools/multicast/parameters.h b/test_tools/multicast/parameters.h
index 6a313ec..a9fda9d 100644
--- a/test_tools/multicast/parameters.h
+++ b/test_tools/multicast/parameters.h
@@ -20,6 +20,9 @@
* 02110-1301, USA.
*/
+#ifndef __PARAMETERS_H__
+#define __PARAMETERS_H__
+
#include <stdio.h>
#include <string.h>
#include <errno.h>
@@ -37,6 +40,14 @@
extern int __verbosity;
+#ifdef IGMP
+enum __igmp_query_types {
+ IGMP_GENERAL_QUERY = 1,
+ IGMP_GROUP_SPECIFIC_QUERY = 2,
+ IGMP_GROUP_AND_SOURCE_SPECIFIC_QUERY = 3
+};
+#endif
+
/** Structure that carries test parameters */
struct parameters
{
@@ -46,7 +57,7 @@ struct parameters
short port;
struct in_addr interface;
-#ifdef RECEIVE
+#if defined(RECEIVE) || defined(IGMP)
struct in_addr sourceaddr;
#endif
@@ -55,6 +66,12 @@ struct parameters
int ttl;
int loop;
#endif
+
+#ifdef IGMP
+ short query_type;
+ struct in_addr destaddr;
+ int max_resp_time;
+#endif
};
/** Initialize parameters struct with default values. */
@@ -64,7 +81,8 @@ void default_parameters(struct parameters* params)
params->port = 0;
memset(¶ms->multiaddr, 0, sizeof(struct in_addr));
memset(¶ms->interface, 0, sizeof(struct in_addr));
-#ifdef RECEIVE
+
+#if defined(RECEIVE) || defined(IGMP)
memset(¶ms->sourceaddr, 0, sizeof(struct in_addr));
#endif
@@ -73,36 +91,118 @@ void default_parameters(struct parameters* params)
params->ttl = 1;
params->loop = 1;
#endif
+
+#ifdef IGMP
+ params->query_type = IGMP_GENERAL_QUERY;
+ memset(¶ms->destaddr, 0, sizeof(struct in_addr));
+ params->max_resp_time = 10;
+#endif
+}
+
+void usage(char *program_name, int retval)
+{
+ printf("usage: %s\n", program_name);
+ printf(" -h | --help print this\n");
+ printf(" -i | --interface a.b.c.d local interface to use for communication\n");
+ printf(" -v | --verbose print additional information during the runtime\n");
+
+ printf("\n");
+
+ printf(" -d | --duration x test duration\n");
+
+#ifdef SEND
+ printf(" -f | --delay x delay between messages\n");
+#endif
+
+ printf("\n");
+
+ printf(" -a | --address a.b.c.d multicast group address\n");
+
+#if defined(SEND) || defined(IGMP)
+ printf(" -s | --source_address a.b.c.d source address\n");
+#endif
+
+#ifdef IGMP
+ printf(" -z | --dest_address a.b.c.d destination address\n");
+#endif
+
+#if defined(SEND) || defined(RECEIVE)
+ printf(" -p | --port x port number\n");
+#endif
+
+ printf("\n");
+
+#ifdef IGMP
+ printf(" -q | --query_type query type\n");
+ printf(" -r | --max_resp_time x maximum response time\n");
+#endif
+
+#ifdef SEND
+ printf(" -t | --ttl x time to live for IP packet\n");
+ printf(" -l | --loop x loopback multicast communication\n");
+#endif
+
+ exit(retval);
}
/** Generic function for parsing arguments */
void parse_args(int argc, char** argv, struct parameters* args)
{
#ifdef SEND
- static const char* opts = "d:a:p:i:f:l:t:v";
+ #define __send_opts "f:t:l:p:"
+#else
+ #define __send_opts ""
+#endif
+
+#if defined(RECEIVE) || defined(IGMP)
+ #define __recv_opts "s:p:"
+#else
+ #define __recv_opts ""
+#endif
+
+#ifdef IGMP
+ #define __igmp_opts "q:z:r:"
+#else
+ #define __igmp_opts ""
#endif
-#ifdef RECEIVE
- static const char* opts = "d:a:p:s:i:v";
+#ifdef IGMP
+ int dest_was_set = 0;
#endif
+ static const char* opts = "d:a:i:v" __send_opts __recv_opts
+ __igmp_opts;
+
+
static struct option long_options[] =
{
- {"duration", required_argument, NULL, 'd'},
- {"multicast_address", required_argument, NULL, 'a'},
- {"port", required_argument, NULL, 'p'},
- {"interface", required_argument, NULL, 'i'},
- {"verbose", no_argument, NULL, 'v'},
-#ifdef RECEIVE
- {"source_address", required_argument, NULL, 's'},
+ {"help", required_argument, NULL, 'h'},
+ {"interface", required_argument, NULL, 'i'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"duration", required_argument, NULL, 'd'},
+ {"multicast_address", required_argument, NULL, 'a'},
+
+#if defined(RECEIVE) || defined(IGMP)
+ {"source_address", required_argument, NULL, 's'},
#endif
#ifdef SEND
- {"delay", required_argument, NULL, 'f'},
- {"ttl", required_argument, NULL, 't'},
- {"loop", required_argument, NULL, 'l'},
+ {"delay", required_argument, NULL, 'f'},
+ {"ttl", required_argument, NULL, 't'},
+ {"loop", required_argument, NULL, 'l'},
#endif
- {0, 0, NULL, 0}
+
+#if defined(SEND) || defined(RECEIVE)
+ {"port", required_argument, NULL, 'p'},
+#endif
+
+#ifdef IGMP
+ {"query_type", required_argument, NULL, 'q'},
+ {"dest_address", required_argument, NULL, 'z'},
+ {"max_resp_time", required_argument, NULL, 'r'},
+
+#endif
+ {0, 0, NULL, 0}
};
default_parameters(args);
@@ -121,13 +221,16 @@ void parse_args(int argc, char** argv, struct parameters* args)
case 'p':
args->port = atoi(optarg);
break;
+ case 'h':
+ usage(argv[1], EXIT_SUCCESS);
+ break;
case 'i':
inet_pton(AF_INET, optarg, &(args->interface));
break;
case 'v':
__verbosity = 1;
break;
-#ifdef RECEIVE
+#if defined(RECEIVE) || defined(IGMP)
case 's':
inet_pton(AF_INET, optarg, &(args->sourceaddr));
break;
@@ -144,9 +247,41 @@ void parse_args(int argc, char** argv, struct parameters* args)
args->loop = atoi(optarg);
break;
#endif
+
+#ifdef IGMP
+ case 'q':
+ args->query_type = atoi(optarg);
+ /*if (strcmp(optarg, "general") == 0) {
+ args->query_type = IGMP_GENERAL_QUERY;
+ } else if (strcmp(optarg, "group_specific") == 0) {
+ args->query_type = IGMP_GROUP_SPECIFIC_QUERY;
+ } else if (strcmp(optarg, "group_and_source_specific") == 0) {
+ args->query_type = IGMP_GROUP_AND_SOURCE_SPECIFIC_QUERY;
+ } else {
+ fprintf(stderr, "%s: undefined query type\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }*/
+ break;
+ case 'z':
+ inet_pton(AF_INET, optarg, &(args->destaddr));
+ dest_was_set = 1;
+ break;
+ case 'r':
+ args->max_resp_time = atoi(optarg);
+ break;
+#endif
default: /* '?' */
- printf("%s: invalid test options\n", argv[0]);
- exit(EXIT_FAILURE);
+ fprintf(stderr, "%s: invalid test options\n", argv[0]);
+ usage(argv[0], EXIT_FAILURE);
}
}
+
+#ifdef IGMP
+ if (!dest_was_set)
+ args->destaddr = args->multiaddr;
+#endif
+
}
+
+#endif
11 years, 12 months
[lnst] multicast: Adding max_groups testcase
by Jiří Pírko
commit 84b4fca14e67517a14e936d261588b741d3e21d3
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu May 3 11:23:56 2012 +0200
multicast: Adding max_groups testcase
This commit introduces test case for testing/discovering the
maximum allowed multicast groups that host can join. The
test is single host, offline.
* test setup: max_groups.c
* cmd sequence: max_groups.xml
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
.../cmd_sequences/multicast/max_groups.xml | 25 +++++++++
test_tools/multicast/Makefile | 2 +-
test_tools/multicast/offline/max_groups.c | 58 ++++++++++++++++++++
3 files changed, 84 insertions(+), 1 deletions(-)
---
diff --git a/example_recipes/cmd_sequences/multicast/max_groups.xml b/example_recipes/cmd_sequences/multicast/max_groups.xml
new file mode 100644
index 0000000..2141678
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/max_groups.xml
@@ -0,0 +1,25 @@
+<!-- Offline maximum number of groups test -->
+<!-- Requires: 1 host with one interface -->
+
+<command_sequence>
+ <!-- With a specific interface -->
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="max_groups" />
+ <option name="interface" value="{$host1if1}" />
+ <option name="condition" value="max_groups > 0" />
+ </options>
+ </command>
+
+ <!-- Change default max_memberhsips -->
+ <command type="exec" value="echo '5' > /proc/sys/net/ipv4/igmp_max_memberships" machine_id="1" />
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="max_groups" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ <option name="condition" value="max_groups == 5" />
+ </options>
+ </command>
+ <command type="exec" value="echo '20' > /proc/sys/net/ipv4/igmp_max_memberships" machine_id="1" />
+
+</command_sequence>
diff --git a/test_tools/multicast/Makefile b/test_tools/multicast/Makefile
index 00fb179..e09746c 100644
--- a/test_tools/multicast/Makefile
+++ b/test_tools/multicast/Makefile
@@ -4,7 +4,7 @@ CFLAGS=-Wall -Wextra -I$(TOOLS_DIR)
SENDERS=send_simple
RECEIVERS=recv_simple recv_membership recv_source_membership recv_block_source
-OFFLINE=sockopt_loop sockopt_ttl sockopt_if sockopt_membership sockopt_source_membership sockopt_block_source
+OFFLINE=sockopt_loop sockopt_ttl sockopt_if sockopt_membership sockopt_source_membership sockopt_block_source max_groups
all: $(SENDERS) $(RECEIVERS) $(OFFLINE)
diff --git a/test_tools/multicast/offline/max_groups.c b/test_tools/multicast/offline/max_groups.c
new file mode 100644
index 0000000..d7cbfc2
--- /dev/null
+++ b/test_tools/multicast/offline/max_groups.c
@@ -0,0 +1,58 @@
+/*
+ * max_groups.c - discover the limit of maximum allowed groups
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define RECEIVE
+#include "multicast_utils.h"
+
+int main(int argc, char** argv)
+{
+ struct parameters params;
+ parse_args(argc, argv, ¶ms);
+
+ int sockfd = init_in_socket(params.multiaddr, params.port);
+
+ struct ip_mreq mreq;
+ struct in_addr multiaddr;
+ int groups = 0;
+ multiaddr.s_addr = 0xe1000001;
+ mreq.imr_interface = params.interface;
+
+ do {
+ mreq.imr_multiaddr.s_addr = htonl(multiaddr.s_addr);
+ if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &(mreq), sizeof(mreq)) < 0) {
+ if (errno == ENOBUFS)
+ break;
+
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ multiaddr.s_addr++;
+ groups++;
+ } while(1);
+
+
+ printf("max_groups=%d\n", groups);
+
+ return EXIT_SUCCESS;
+}
11 years, 12 months
[lnst] multicast: Adding block_source.xml test case
by Jiří Pírko
commit 5f0a8c69bc96d60af33ebac1db454db47f0e10b5
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu May 3 11:23:55 2012 +0200
multicast: Adding block_source.xml test case
This test case covers blocking multicast sources in source specific
multicast in kernel.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
.../cmd_sequences/multicast/block_source.xml | 78 ++++++++++++++++++
test_tools/multicast/Makefile | 4 +-
.../multicast/offline/sockopt_block_source.c | 83 ++++++++++++++++++++
test_tools/multicast/server/recv_block_source.c | 76 ++++++++++++++++++
4 files changed, 239 insertions(+), 2 deletions(-)
---
diff --git a/example_recipes/cmd_sequences/multicast/block_source.xml b/example_recipes/cmd_sequences/multicast/block_source.xml
new file mode 100644
index 0000000..a9a3712
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/block_source.xml
@@ -0,0 +1,78 @@
+<!-- IP_BLOCK/UNBLOCK_SOURCE test -->
+<!-- Requires: 2 hosts with one interface each -->
+<!-- NOTICE: IGMP packets must be forwarded through the network!
+ In kvm/libvirt environment, iptables on host must be off or
+ configured to forward igmp traffic through the bridge -->
+
+<command_sequence>
+ <!-- IP_BLOCK/UNBLOCK_SOURCE sockopt conformance test -->
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="sockopt_block_source" />
+ <option name="condition" value="status == 'pass'" />
+ </options>
+ </command>
+
+ <!-- Block source in the middle of ongoing communication -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+ <command type="exec" machine_id="2" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_block_source" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][2]['netconfig'][1]['addresses'][0]" />
+ <option type="recipe_eval" name="source" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received > 0" />
+ <option name="condition" value="packets_received_while_blocking == 0" />
+ </options>
+ </command>
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- Nonexistent source -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+ <command type="exec" machine_id="2" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_block_source" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][2]['netconfig'][1]['addresses'][0]" />
+ <option name="source" value="127.0.0.200" />
+
+ <option name="condition" value="packets_received > 0" />
+ <option name="condition" value="packets_received_while_blocking > 0" />
+ </options>
+ </command>
+ <command type="wait" machine_id="1" value="1" />
+
+</command_sequence>
diff --git a/test_tools/multicast/Makefile b/test_tools/multicast/Makefile
index 9eb8fe9..00fb179 100644
--- a/test_tools/multicast/Makefile
+++ b/test_tools/multicast/Makefile
@@ -3,8 +3,8 @@ TOOLS_DIR=.
CFLAGS=-Wall -Wextra -I$(TOOLS_DIR)
SENDERS=send_simple
-RECEIVERS=recv_simple recv_membership recv_source_membership
-OFFLINE=sockopt_loop sockopt_ttl sockopt_if sockopt_membership sockopt_source_membership
+RECEIVERS=recv_simple recv_membership recv_source_membership recv_block_source
+OFFLINE=sockopt_loop sockopt_ttl sockopt_if sockopt_membership sockopt_source_membership sockopt_block_source
all: $(SENDERS) $(RECEIVERS) $(OFFLINE)
diff --git a/test_tools/multicast/offline/sockopt_block_source.c b/test_tools/multicast/offline/sockopt_block_source.c
new file mode 100644
index 0000000..f79bb48
--- /dev/null
+++ b/test_tools/multicast/offline/sockopt_block_source.c
@@ -0,0 +1,83 @@
+/*
+ * sockopt_block_source.c - IP_BLOCK/UNBLOCK_SOURCE socket option test
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "sockopt_utils.h"
+
+
+void test_block_source()
+{
+ struct ip_mreq_source mreq;
+
+ mreq.imr_multiaddr.s_addr = 0x0100007f;
+ mreq.imr_interface.s_addr = 0x0100007f;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_BLOCK_SOURCE Bad multicast address",
+ IP_BLOCK_SOURCE, &mreq, sizeof(mreq), EINVAL);
+
+
+ mreq.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreq.imr_interface.s_addr = 0xffffffff;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_BLOCK_SOURCE Bad interface",
+ IP_BLOCK_SOURCE, &mreq, sizeof(mreq), ENODEV);
+
+
+ test_setsockopt_error("IP_BLOCK_SOURCE Bad optlen",
+ IP_BLOCK_SOURCE, &mreq, 2, EINVAL);
+}
+
+void test_unblock_source()
+{
+ struct ip_mreq_source mreq;
+
+ mreq.imr_multiaddr.s_addr = 0x0100007f;
+ mreq.imr_interface.s_addr = 0x0100007f;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_UNBLOCK_SOURCE Bad multicast address",
+ IP_UNBLOCK_SOURCE, &mreq, sizeof(mreq), EINVAL);
+
+ mreq.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreq.imr_interface.s_addr = 0x0100007f;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_UNBLOCK_SOURCE Not a member",
+ IP_UNBLOCK_SOURCE, &mreq, sizeof(mreq), EINVAL);
+
+ mreq.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreq.imr_interface.s_addr = 0xffffffff;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_UNBLOCK_SOURCE No device found",
+ IP_UNBLOCK_SOURCE, &mreq, sizeof(mreq), ENODEV);
+
+ test_setsockopt_error("IP_UNBLOCK_SOURCE Bad optlen",
+ IP_UNBLOCK_SOURCE, &mreq, 5, EINVAL);
+}
+
+int main()
+{
+ initialize();
+
+ test_block_source();
+ test_unblock_source();
+
+ report_and_exit();
+ return 0;
+}
diff --git a/test_tools/multicast/server/recv_block_source.c b/test_tools/multicast/server/recv_block_source.c
new file mode 100644
index 0000000..6e2f462
--- /dev/null
+++ b/test_tools/multicast/server/recv_block_source.c
@@ -0,0 +1,76 @@
+/*
+ * recv_block_source.c - Join multicast group and then block and
+ * unblock specific sources
+ *
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define RECEIVE
+#include "multicast_utils.h"
+
+int main(int argc, char** argv)
+{
+ struct parameters params;
+ parse_args(argc, argv, ¶ms);
+
+ int sockfd = init_in_socket(params.multiaddr, params.port);
+
+ int num_recv = 0;
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr = params.multiaddr;
+ mreq.imr_interface = params.interface;
+
+ struct ip_mreq_source mreqs;
+ mreqs.imr_multiaddr = params.multiaddr;
+ mreqs.imr_interface = params.interface;
+ mreqs.imr_sourceaddr = params.sourceaddr;
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &(mreq), sizeof(mreq)) < 0)
+ {
+ perror("setsockopt");
+ return -1;
+ }
+
+ num_recv = wait_for_data(sockfd, params.duration/3, 0);
+ printf("packets_received=%d\n", num_recv);
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_BLOCK_SOURCE,
+ &(mreqs), sizeof(mreqs)) < 0)
+ {
+ perror("setsockopt");
+ return -1;
+ }
+
+ num_recv = wait_for_data(sockfd, params.duration/3, 0);
+ printf("packets_received_while_blocking=%d\n", num_recv);
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_UNBLOCK_SOURCE,
+ &(mreqs), sizeof(mreqs)) < 0)
+ {
+ perror("setsockopt");
+ return -1;
+ }
+
+ num_recv = wait_for_data(sockfd, params.duration/3, 0);
+ printf("packets_received=%d\n", num_recv);
+
+ return EXIT_SUCCESS;
+}
11 years, 12 months
[lnst] multicast: New test case source_membership.xml
by Jiří Pírko
commit 56fbe9e4228416b290bd5243607c97f5cc988d6a
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu May 3 11:23:54 2012 +0200
multicast: New test case source_membership.xml
Adding new testcase for source specific multicast inferface:
IP_ADD_SOURCE_MEMBERSHIP
IP_DROP_SOURCE_MEMBERSIP
There is one new offline conformance test and one new server
setup.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Tests/TestMulticast.py | 2 +-
.../cmd_sequences/multicast/source_membership.xml | 83 +++++++++++++++++++
test_tools/multicast/Makefile | 4 +-
.../multicast/offline/sockopt_source_membership.c | 85 ++++++++++++++++++++
.../multicast/server/recv_source_membership.c | 63 +++++++++++++++
5 files changed, 234 insertions(+), 3 deletions(-)
---
diff --git a/Tests/TestMulticast.py b/Tests/TestMulticast.py
index c757bca..4710f89 100644
--- a/Tests/TestMulticast.py
+++ b/Tests/TestMulticast.py
@@ -53,7 +53,7 @@ class TestMulticast(TestGeneric):
opts["delay"] = self.get_opt("delay")
# receiver-specific
- opts["source"] = self._remove_mask(self.get_opt("source"))
+ opts["source_address"] = self._remove_mask(self.get_opt("source"))
cmd = "./{0} ".format(setup)
diff --git a/example_recipes/cmd_sequences/multicast/source_membership.xml b/example_recipes/cmd_sequences/multicast/source_membership.xml
new file mode 100644
index 0000000..aeb525b
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/source_membership.xml
@@ -0,0 +1,83 @@
+<!-- IP_ADD/DROP_SOURCE_MEMBERSHIP test -->
+<!-- Requires: 2 hosts
+ - [1] with one interface
+ - [2] with one interface
+ - -->
+<!-- NOTICE: IGMP packets must be forwarded through the network!
+ In kvm/libvirt environment, iptables on host must be off or
+ configured to forward igmp traffic through the bridge -->
+
+<command_sequence>
+ <!-- IP_ADD/DROP_MEMBERSHIP sockopt conformance test -->
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="sockopt_source_membership" />
+ <option name="condition" value="status == 'pass'" />
+ </options>
+ </command>
+
+ <!-- This simple test case verifies that if one side leaves multicast group
+ - in the middle of ongoing communication, no further packets are delivered
+ - to the process. -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+ <command type="exec" machine_id="2" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_source_membership" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][2]['netconfig'][1]['addresses'][0]" />
+ <option type="recipe_eval" name="source" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received > 0" />
+ <option name="condition" value="packets_received_after_drop == 0" />
+ </options>
+ </command>
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- Nonexistent source -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+ <command type="exec" machine_id="2" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_source_membership" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][2]['netconfig'][1]['addresses'][0]" />
+ <option name="source" value="127.0.0.200" />
+
+ <option name="condition" value="packets_received == 0" />
+ <option name="condition" value="packets_received_after_drop == 0" />
+ </options>
+ </command>
+ <command type="wait" machine_id="1" value="1" />
+
+</command_sequence>
diff --git a/test_tools/multicast/Makefile b/test_tools/multicast/Makefile
index 68a5406..9eb8fe9 100644
--- a/test_tools/multicast/Makefile
+++ b/test_tools/multicast/Makefile
@@ -3,8 +3,8 @@ TOOLS_DIR=.
CFLAGS=-Wall -Wextra -I$(TOOLS_DIR)
SENDERS=send_simple
-RECEIVERS=recv_simple recv_membership
-OFFLINE=sockopt_loop sockopt_ttl sockopt_if sockopt_membership
+RECEIVERS=recv_simple recv_membership recv_source_membership
+OFFLINE=sockopt_loop sockopt_ttl sockopt_if sockopt_membership sockopt_source_membership
all: $(SENDERS) $(RECEIVERS) $(OFFLINE)
diff --git a/test_tools/multicast/offline/sockopt_source_membership.c b/test_tools/multicast/offline/sockopt_source_membership.c
new file mode 100644
index 0000000..a43b43c
--- /dev/null
+++ b/test_tools/multicast/offline/sockopt_source_membership.c
@@ -0,0 +1,85 @@
+/*
+ * sockopt_source_membership.c - IP_ADD/DROP_SOURCE_MEMBERSHIP socket
+ * option test
+ *
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "sockopt_utils.h"
+
+
+void test_add_source_membership()
+{
+ struct ip_mreq_source mreq;
+
+ mreq.imr_multiaddr.s_addr = 0x0100007f;
+ mreq.imr_interface.s_addr = 0x0100007f;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_ADD_SOURCE_MEMBERSHIP Bad multicast address",
+ IP_ADD_SOURCE_MEMBERSHIP, &mreq, sizeof(mreq), EINVAL);
+
+
+ mreq.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreq.imr_interface.s_addr = 0xffffffff;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_ADD_SOURCE_MEMBERSHIP Bad interface",
+ IP_ADD_SOURCE_MEMBERSHIP, &mreq, sizeof(mreq), ENODEV);
+
+
+ test_setsockopt_error("IP_ADD_SOURCE_MEMBERSHIP Bad optlen",
+ IP_ADD_SOURCE_MEMBERSHIP, &mreq, 2, EINVAL);
+}
+
+void test_drop_source_membership()
+{
+ struct ip_mreq_source mreq;
+
+ mreq.imr_multiaddr.s_addr = 0x0100007f;
+ mreq.imr_interface.s_addr = 0x0100007f;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_DROP_SOURCE_MEMBERSHIP Bad multicast address",
+ IP_DROP_SOURCE_MEMBERSHIP, &mreq, sizeof(mreq), EINVAL);
+
+ mreq.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreq.imr_interface.s_addr = 0x0100007f;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_DROP_SOURCE_MEMBERSHIP Not a member",
+ IP_DROP_SOURCE_MEMBERSHIP, &mreq, sizeof(mreq), EINVAL);
+
+ mreq.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreq.imr_interface.s_addr = 0xffffffff;
+ mreq.imr_sourceaddr.s_addr = 0x12345678;
+ test_setsockopt_error("IP_DROP_SOURCE_MEMBERSHIP No device found",
+ IP_DROP_SOURCE_MEMBERSHIP, &mreq, sizeof(mreq), ENODEV);
+
+ test_setsockopt_error("IP_DROP_SOURCE_MEMBERSHIP Bad optlen",
+ IP_DROP_SOURCE_MEMBERSHIP, &mreq, 5, EINVAL);
+}
+
+int main()
+{
+ initialize();
+
+ test_add_source_membership();
+ test_drop_source_membership();
+
+ report_and_exit();
+ return 0;
+}
diff --git a/test_tools/multicast/server/recv_source_membership.c b/test_tools/multicast/server/recv_source_membership.c
new file mode 100644
index 0000000..88d546d
--- /dev/null
+++ b/test_tools/multicast/server/recv_source_membership.c
@@ -0,0 +1,63 @@
+/*
+ * recv_drop_membership.c - Join multicast group only for a specific
+ * source and then leave it in the middle of
+ * ongoing communication
+ *
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define RECEIVE
+#include "multicast_utils.h"
+
+int main(int argc, char** argv)
+{
+ struct parameters params;
+ parse_args(argc, argv, ¶ms);
+
+ int sockfd = init_in_socket(params.multiaddr, params.port);
+
+ int num_recv = 0;
+ struct ip_mreq_source mreq;
+ mreq.imr_multiaddr = params.multiaddr;
+ mreq.imr_interface = params.interface;
+ mreq.imr_sourceaddr = params.sourceaddr;
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
+ &(mreq), sizeof(mreq)) < 0)
+ {
+ perror("setsockopt");
+ return -1;
+ }
+
+ num_recv = wait_for_data(sockfd, params.duration/2, 0);
+ printf("packets_received=%d\n", num_recv);
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,
+ &(mreq), sizeof(mreq)) < 0)
+ {
+ perror("setsockopt");
+ return -1;
+ }
+
+ num_recv = wait_for_data(sockfd, params.duration/2, 0);
+ printf("packets_received_after_drop=%d\n", num_recv);
+
+ return EXIT_SUCCESS;
+}
11 years, 12 months
[lnst] multicast: New test case membership.xml
by Jiří Pírko
commit fa55487985affac7a369313e8ac4d1dc4a92a984
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu May 3 11:23:53 2012 +0200
multicast: New test case membership.xml
Adding new testcase `membership.xml' with the necessary setup and
offline conformance tests for sockopt ADD/DROP_MEMBERSHIP interface.
This simple test case verifies that if one side leaves multicast group
in the middle of ongoing communication, no further packets are delivered
to the process.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
.../cmd_sequences/multicast/membership.xml | 48 ++++++++++++
test_tools/multicast/Makefile | 4 +-
test_tools/multicast/offline/sockopt_membership.c | 78 ++++++++++++++++++++
test_tools/multicast/server/recv_membership.c | 62 ++++++++++++++++
4 files changed, 190 insertions(+), 2 deletions(-)
---
diff --git a/example_recipes/cmd_sequences/multicast/membership.xml b/example_recipes/cmd_sequences/multicast/membership.xml
new file mode 100644
index 0000000..fd9c166
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/membership.xml
@@ -0,0 +1,48 @@
+<!-- IP_ADD/DROP_MEMBERSHIP test -->
+<!-- Requires: 2 hosts
+ - [1] with one interface
+ - [2] with one interface
+ - -->
+
+<command_sequence>
+ <!-- IP_ADD/DROP_MEMBERSHIP sockopt conformance test -->
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="sockopt_membership" />
+ <option name="condition" value="status == 'pass'" />
+ </options>
+ </command>
+
+ <!-- This simple test case verifies that if one side leaves multicast group
+ - in the middle of ongoing communication, no further packets are delivered
+ - to the process. -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+ <command type="exec" machine_id="2" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_membership" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][2]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received > 0" />
+ <option name="condition" value="packets_received_after_drop == 0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+</command_sequence>
diff --git a/test_tools/multicast/Makefile b/test_tools/multicast/Makefile
index 47af8f5..68a5406 100644
--- a/test_tools/multicast/Makefile
+++ b/test_tools/multicast/Makefile
@@ -3,8 +3,8 @@ TOOLS_DIR=.
CFLAGS=-Wall -Wextra -I$(TOOLS_DIR)
SENDERS=send_simple
-RECEIVERS=recv_simple
-OFFLINE=sockopt_loop sockopt_ttl sockopt_if
+RECEIVERS=recv_simple recv_membership
+OFFLINE=sockopt_loop sockopt_ttl sockopt_if sockopt_membership
all: $(SENDERS) $(RECEIVERS) $(OFFLINE)
diff --git a/test_tools/multicast/offline/sockopt_membership.c b/test_tools/multicast/offline/sockopt_membership.c
new file mode 100644
index 0000000..b8612f7
--- /dev/null
+++ b/test_tools/multicast/offline/sockopt_membership.c
@@ -0,0 +1,78 @@
+/*
+ * sockopt_membership.c - IP_ADD/DROP_MEMBERSHIP socket option test
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "sockopt_utils.h"
+
+
+void test_add_membership()
+{
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = 0x0100007f;
+ struct ip_mreqn mreqn;
+
+ test_setsockopt_error("IP_ADD_MEMBERSHIP Bad multicast address",
+ IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq), EINVAL);
+
+ test_setsockopt_error("IP_ADD_MEMBERSHIP Bad optlen",
+ IP_ADD_MEMBERSHIP, &mreq, 5, EINVAL);
+
+ mreqn.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreqn.imr_address.s_addr = 0xffffffff;
+ mreqn.imr_ifindex = 500;
+ test_setsockopt_error("IP_ADD_MEMBERSHIP No device found",
+ IP_ADD_MEMBERSHIP, &mreqn, sizeof(mreqn), ENODEV);
+}
+
+void test_drop_membership()
+{
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = 0x0100007f;
+ mreq.imr_interface.s_addr = 0x0100007f;
+ struct ip_mreqn mreqn;
+
+ test_setsockopt_error("IP_DROP_MEMBERSHIP Bad optlen",
+ IP_DROP_MEMBERSHIP, &mreq, 5, EINVAL);
+ test_setsockopt_error("IP_DROP_MEMBERSHIP Bad multicast address",
+ IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq), EADDRNOTAVAIL);
+
+ mreq.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreq.imr_interface.s_addr = 0x0100007f;
+ test_setsockopt_error("IP_DROP_MEMBERSHIP Not a member",
+ IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq), EADDRNOTAVAIL);
+
+ mreqn.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreqn.imr_address.s_addr = 0xffffffff;
+ mreqn.imr_ifindex = 500;
+ test_setsockopt_error("IP_DROP_MEMBERSHIP No device found",
+ IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn), ENODEV);
+}
+
+int main()
+{
+ initialize();
+
+ test_add_membership();
+ test_drop_membership();
+
+ report_and_exit();
+ return 0;
+}
diff --git a/test_tools/multicast/server/recv_membership.c b/test_tools/multicast/server/recv_membership.c
new file mode 100644
index 0000000..018226b
--- /dev/null
+++ b/test_tools/multicast/server/recv_membership.c
@@ -0,0 +1,62 @@
+/*
+ * recv_membership.c - Join multicast group and leave it
+ * in the middle of communication
+ *
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define RECEIVE
+#include "multicast_utils.h"
+
+int main(int argc, char** argv)
+{
+ struct parameters params;
+ parse_args(argc, argv, ¶ms);
+
+ int sockfd = init_in_socket(params.multiaddr, params.port);
+
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr = params.multiaddr;
+ mreq.imr_interface = params.interface;
+
+ int num_recv = 0;
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &(mreq), sizeof(mreq)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ num_recv = wait_for_data(sockfd, params.duration/2, 0);
+
+ printf("packets_received=%d\n", num_recv);
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ &(mreq), sizeof(mreq)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ num_recv = wait_for_data(sockfd, params.duration/2, 0);
+
+ printf("packets_received_after_drop=%d\n", num_recv);
+
+ return EXIT_SUCCESS;
+}
11 years, 12 months
[lnst] NetTestParse.py: Conversion of attributes
by Jiří Pírko
commit 0e5f00ea372a5c37d449997e1f77906e4bcddc93
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu May 3 11:18:32 2012 +0200
NetTestParse.py: Conversion of attributes
DOM parser returns unicode strings, but LNST works with
traditional strings. It's necessary to convert unicode strings
for consistency.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
NetTest/NetTestParse.py | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
---
diff --git a/NetTest/NetTestParse.py b/NetTest/NetTestParse.py
index 10ff4fc..c1493b5 100644
--- a/NetTest/NetTestParse.py
+++ b/NetTest/NetTestParse.py
@@ -251,10 +251,10 @@ class NetTestParse:
num_attributes = node.attributes.length
while(i < num_attributes):
attr = node.attributes.item(i)
- attr.value = self._expand_string(attr.value, recipe_eval)
+ attr.value = self._expand_string(str(attr.value), recipe_eval)
i += 1
elif node.nodeType == node.TEXT_NODE:
- node.data = self._expand_string(node.data, recipe_eval)
+ node.data = self._expand_string(str(node.data), recipe_eval)
for child in node.childNodes:
self._expand(child, recipe_eval)
11 years, 12 months
Packet Assert Proposal
by Radek Pazdera
Hi,
I did a series of tests for LNST lately where I needed to check whether
packets
with some properties left or arrived to some interface. The usual way of
doing
this is to run tcpdump with some filter, grep the results for the required
properties and see if you get something.
I thought it might be useful to be able to do this natively in LNST.
Maybe crate
new command type like this:
<command type="packet_assert" timeout="10" bg_id="5">
<option name="interface" value="192.168.1.100" />
<option name="filter" value="igmp" />
<option name="grep_for" value="igmp query v{$igmp_version}" />
<option name="grep_for" value="> {$multiaddr}" />
<option name="min_count" value="5" />
</command>
Do you think it's a good idea or should I do it some other way/not do
things like
this at all?
We could discuss it together with the previous sysctl proposal if you're
interested.
Thank you,
Radek Pazdera
11 years, 12 months