Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: tarantool-patches@freelists.org
Cc: kostja@tarantool.org
Subject: [tarantool-patches] [PATCH 3/6] test: introduce swim packet filter by destination address
Date: Wed, 24 Apr 2019 17:36:17 +0300	[thread overview]
Message-ID: <d71d08ba37fe427f6f8a309899410984a30b06fa.1556116199.git.v.shpilevoy@tarantool.org> (raw)
In-Reply-To: <cover.1556116199.git.v.shpilevoy@tarantool.org>

The filter is going to be used to test the SWIM suspicion
component. The destination filter will break certain network
channels, and the suspicion component shall withstand that.

Part of #3234
---
 test/unit/swim_test_transport.c |  10 +--
 test/unit/swim_test_transport.h |   6 +-
 test/unit/swim_test_utils.c     | 114 +++++++++++++++++++++++++++++++-
 test/unit/swim_test_utils.h     |  11 +++
 4 files changed, 133 insertions(+), 8 deletions(-)

diff --git a/test/unit/swim_test_transport.c b/test/unit/swim_test_transport.c
index 513274c2c..c4a1dd774 100644
--- a/test/unit/swim_test_transport.c
+++ b/test/unit/swim_test_transport.c
@@ -238,14 +238,16 @@ swim_fd_close(struct swim_fd *fd)
  * Check all the packet filters if any wants to drop @a p packet.
  * @a dir parameter says direction. Values are the same as for
  * standard in/out descriptors: 0 for input, 1 for output.
+ * @a peer_fd says sender/receiver file descriptor depending on
+ * @a dir.
  */
 static inline bool
 swim_fd_test_if_drop(struct swim_fd *fd, const struct swim_test_packet *p,
-		     int dir)
+		     int dir, int peer_fd)
 {
 	struct swim_fd_filter *f;
 	rlist_foreach_entry(f, &fd->filters, in_filters) {
-		if (f->check(p->data, p->size, f->udata, dir))
+		if (f->check(p->data, p->size, f->udata, dir, peer_fd))
 			return true;
 	}
 	return false;
@@ -380,8 +382,8 @@ static inline void
 swim_move_packet(struct swim_fd *src, struct swim_fd *dst,
 		 struct swim_test_packet *p)
 {
-	if (dst->is_opened && !swim_fd_test_if_drop(dst, p, 0) &&
-	    !swim_fd_test_if_drop(src, p, 1))
+	if (dst->is_opened && !swim_fd_test_if_drop(dst, p, 0, src->evfd) &&
+	    !swim_fd_test_if_drop(src, p, 1, dst->evfd))
 		rlist_add_tail_entry(&dst->recv_queue, p, in_queue);
 	else
 		swim_test_packet_delete(p);
diff --git a/test/unit/swim_test_transport.h b/test/unit/swim_test_transport.h
index a66cf2d81..6235278d0 100644
--- a/test/unit/swim_test_transport.h
+++ b/test/unit/swim_test_transport.h
@@ -45,10 +45,12 @@ struct ev_loop;
  * arbitrary user data, and should return true, if the packet
  * should be dropped. False otherwise. Direction is said via
  * @a dir parameter. 0 means incoming packet, 1 means outgoing
- * packet, just like standard IO descriptors.
+ * packet, just like standard IO descriptors. Via @a peer_fd
+ * parameter a sender/receiver descriptor number is passed
+ * depending on @a dir.
  */
 typedef bool (*swim_test_filter_check_f)(const char *data, int size,
-					 void *udata, int dir);
+					 void *udata, int dir, int peer_fd);
 
 /**
  * Until there are no new IO events, feed EV_WRITE event to all
diff --git a/test/unit/swim_test_utils.c b/test/unit/swim_test_utils.c
index 0beeab65d..de1bef6e7 100644
--- a/test/unit/swim_test_utils.c
+++ b/test/unit/swim_test_utils.c
@@ -80,6 +80,67 @@ swim_drop_components_create(struct swim_drop_components *dc, const int *keys,
 	dc->key_count = key_count;
 }
 
+/** Packet filter to drop packets with specified destinations. */
+struct swim_drop_channel {
+	/**
+	 * An array of file descriptors to drop messages sent to
+	 * them.
+	 */
+	int *drop_fd;
+	/** Length of @a drop_fd. */
+	int drop_fd_size;
+	/** Capacity of @a drop_fd. */
+	int drop_fd_cap;
+};
+
+/** Initialize drop channel packet filter. */
+static inline void
+swim_drop_channel_create(struct swim_drop_channel *dc)
+{
+	dc->drop_fd = NULL;
+	dc->drop_fd_size = 0;
+	dc->drop_fd_cap = 0;
+}
+
+/**
+ * Set @a new_fd file descriptor into @a dc drop channel packet
+ * filter in place of @a old_fd descriptor. Just like dup2()
+ * system call.
+ * @retval 0 Success.
+ * @retval -1 @a old_fd is not found.
+ */
+static inline int
+swim_drop_channel_dup_fd(const struct swim_drop_channel *dc, int new_fd,
+			 int old_fd)
+{
+	for (int i = 0; i < dc->drop_fd_size; ++i) {
+		if (dc->drop_fd[i] == old_fd) {
+			dc->drop_fd[i] = new_fd;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+/** Add @a fd to @a dc drop channel packet filter. */
+static inline void
+swim_drop_channel_add_fd(struct swim_drop_channel *dc, int fd)
+{
+	if (swim_drop_channel_dup_fd(dc, fd, -1) == 0)
+		return;
+	dc->drop_fd_cap += dc->drop_fd_cap + 1;
+	int new_bsize = dc->drop_fd_cap * sizeof(int);
+	dc->drop_fd = (int *) realloc(dc->drop_fd, new_bsize);
+	dc->drop_fd[dc->drop_fd_size++] = fd;
+}
+
+/** Destroy drop channel packet filter. */
+static inline void
+swim_drop_channel_destroy(struct swim_drop_channel *dc)
+{
+	free(dc->drop_fd);
+}
+
 /**
  * SWIM cluster node and its UUID. UUID is stored separately
  * because sometimes a test wants to drop a SWIM instance, but
@@ -104,6 +165,8 @@ struct swim_node {
 	 * Filter to drop packets with specified SWIM components.
 	 */
 	struct swim_drop_components drop_components;
+	/** Filter to drop packets with specified destinations. */
+	struct swim_drop_channel drop_channel;
 };
 
 /**
@@ -144,6 +207,7 @@ swim_node_create(struct swim_node *n, int id)
 
 	swim_drop_rate_create(&n->drop_rate, 0, false, false);
 	swim_drop_components_create(&n->drop_components, NULL, 0);
+	swim_drop_channel_create(&n->drop_channel);
 }
 
 struct swim_cluster *
@@ -191,6 +255,7 @@ swim_cluster_delete(struct swim_cluster *cluster)
 	for (int i = 0; i < cluster->size; ++i) {
 		if (cluster->node[i].swim != NULL)
 			swim_delete(cluster->node[i].swim);
+		swim_drop_channel_destroy(&cluster->node[i].drop_channel);
 	}
 	free(cluster->node);
 	free(cluster);
@@ -347,10 +412,12 @@ swim_drop_rate_new(double rate, bool is_for_in, bool is_for_out)
  * A packet filter dropping a packet with a certain probability.
  */
 static bool
-swim_filter_drop_rate(const char *data, int size, void *udata, int dir)
+swim_filter_drop_rate(const char *data, int size, void *udata, int dir,
+		      int peer_fd)
 {
 	(void) data;
 	(void) size;
+	(void) peer_fd;
 	struct swim_drop_rate *dr = (struct swim_drop_rate *) udata;
 	if ((dir == 0 && !dr->is_for_in) || (dir == 1 && !dr->is_for_out))
 		return false;
@@ -397,10 +464,12 @@ swim_cluster_set_drop_in(struct swim_cluster *cluster, int i, double value)
  * Check if a packet contains any of the components to filter out.
  */
 static bool
-swim_filter_drop_component(const char *data, int size, void *udata, int dir)
+swim_filter_drop_component(const char *data, int size, void *udata, int dir,
+			   int peer_fd)
 {
 	(void) size;
 	(void) dir;
+	(void) peer_fd;
 	struct swim_drop_components *dc = (struct swim_drop_components *) udata;
 	/* Skip meta. */
 	mp_next(&data);
@@ -433,6 +502,47 @@ swim_cluster_drop_components(struct swim_cluster *cluster, int i,
 				       &n->drop_components);
 }
 
+/**
+ * Check if the packet sender should drop a packet outgoing to
+ * @a peer_fd file descriptor.
+ */
+static bool
+swim_filter_drop_channel(const char *data, int size, void *udata, int dir,
+			 int peer_fd)
+{
+	(void) data;
+	(void) size;
+	if (dir != 1)
+		return false;
+	struct swim_drop_channel *dc = (struct swim_drop_channel *) udata;
+	/*
+	 * Fullscan is totally ok - there are no more than 2-3
+	 * blocks simultaneously in the tests.
+	 */
+	for (int i = 0; i < dc->drop_fd_size; ++i) {
+		if (dc->drop_fd[i] == peer_fd)
+			return true;
+	}
+	return false;
+}
+
+void
+swim_cluster_set_drop_channel(struct swim_cluster *cluster, int from_id,
+			      int to_id, bool value)
+{
+	int to_fd = swim_fd(swim_cluster_member(cluster, to_id));
+	struct swim_node *from_node = swim_cluster_node(cluster, from_id);
+	struct swim_drop_channel *dc = &from_node->drop_channel;
+	if (! value) {
+		swim_drop_channel_dup_fd(dc, -1, to_fd);
+		return;
+	}
+	swim_drop_channel_add_fd(dc, to_fd);
+	swim_test_transport_add_filter(swim_fd(from_node->swim),
+				       swim_filter_drop_channel,
+				       &from_node->drop_channel);
+}
+
 /** Check if @a s1 knows every member of @a s2's table. */
 static inline bool
 swim1_contains_swim2(struct swim *s1, struct swim *s2)
diff --git a/test/unit/swim_test_utils.h b/test/unit/swim_test_utils.h
index 145af9b1f..c78894820 100644
--- a/test/unit/swim_test_utils.h
+++ b/test/unit/swim_test_utils.h
@@ -118,6 +118,17 @@ void
 swim_cluster_drop_components(struct swim_cluster *cluster, int i,
 			     const int *keys, int key_count);
 
+/**
+ * When @a value is true, break a one direction network link
+ * between @a to_id and @a from_id SWIM instances. It is a pure
+ * network block, the member tables are not touched. All the
+ * packets trying to go directly from @a from_id to @a to_id are
+ * dropped. When @a value is false, the channel is restored.
+ */
+void
+swim_cluster_set_drop_channel(struct swim_cluster *cluster, int from_id,
+			      int to_id, bool value);
+
 /**
  * Explicitly add a member of id @a from_id to a member of id
  * @a to_id.
-- 
2.20.1 (Apple Git-117)

  parent reply	other threads:[~2019-04-24 14:36 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-24 14:36 [tarantool-patches] [PATCH 0/6] swim suspicion Vladislav Shpilevoy
2019-04-24 14:36 ` [tarantool-patches] [PATCH 1/6] test: rename swim_cluster_node to swim_cluster_member Vladislav Shpilevoy
2019-04-24 16:37   ` [tarantool-patches] " Konstantin Osipov
2019-04-24 14:36 ` [tarantool-patches] [PATCH 2/6] test: remove swim packet filter destructors Vladislav Shpilevoy
2019-04-24 16:37   ` [tarantool-patches] " Konstantin Osipov
2019-04-24 14:36 ` Vladislav Shpilevoy [this message]
2019-04-24 16:38   ` [tarantool-patches] Re: [PATCH 3/6] test: introduce swim packet filter by destination address Konstantin Osipov
2019-04-24 14:36 ` [tarantool-patches] [PATCH 4/6] swim: wrap sio_strfaddr() Vladislav Shpilevoy
2019-04-24 16:40   ` [tarantool-patches] " Konstantin Osipov
2019-04-24 20:23     ` Vladislav Shpilevoy
2019-04-25 10:34       ` Konstantin Osipov
2019-04-25 13:50         ` Vladislav Shpilevoy
2019-04-24 14:36 ` [tarantool-patches] [PATCH 5/6] swim: introduce routing Vladislav Shpilevoy
2019-04-24 16:46   ` [tarantool-patches] " Konstantin Osipov
2019-04-24 20:25     ` Vladislav Shpilevoy
2019-04-25 10:39       ` Konstantin Osipov
2019-04-25 13:50         ` Vladislav Shpilevoy
2019-04-25 13:57           ` Konstantin Osipov
2019-04-24 14:36 ` [tarantool-patches] [PATCH 6/6] swim: introduce suspicion Vladislav Shpilevoy
2019-04-24 17:01   ` [tarantool-patches] " Konstantin Osipov
2019-04-24 20:28     ` Vladislav Shpilevoy
2019-04-25 10:42       ` Konstantin Osipov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d71d08ba37fe427f6f8a309899410984a30b06fa.1556116199.git.v.shpilevoy@tarantool.org \
    --to=v.shpilevoy@tarantool.org \
    --cc=kostja@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --subject='Re: [tarantool-patches] [PATCH 3/6] test: introduce swim packet filter by destination address' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox