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)
next prev 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