]> git.proxmox.com Git - mirror_ovs.git/blame - tests/test-conntrack.c
tests: Refactor the iptables accept rule.
[mirror_ovs.git] / tests / test-conntrack.c
CommitLineData
8cb14626 1/*
7a36af87 2 * Copyright (c) 2015, 2017 Nicira, Inc.
8cb14626
DDP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18#include "conntrack.h"
19
20#include "dp-packet.h"
21#include "fatal-signal.h"
22#include "flow.h"
23#include "netdev.h"
24#include "ovs-thread.h"
25#include "ovstest.h"
b4124903 26#include "pcap-file.h"
8cb14626
DDP
27#include "timeval.h"
28
29static const char payload[] = "50540000000a50540000000908004500001c0000000000"
30 "11a4cd0a0101010a0101020001000200080000";
31
32static struct dp_packet_batch *
66e4ad8a 33prepare_packets(size_t n, bool change, unsigned tid, ovs_be16 *dl_type)
8cb14626
DDP
34{
35 struct dp_packet_batch *pkt_batch = xzalloc(sizeof *pkt_batch);
36 struct flow flow;
37 size_t i;
38
39 ovs_assert(n <= ARRAY_SIZE(pkt_batch->packets));
40
41 dp_packet_batch_init(pkt_batch);
8cb14626
DDP
42 for (i = 0; i < n; i++) {
43 struct udp_header *udp;
44 struct dp_packet *pkt = dp_packet_new(sizeof payload/2);
45
46 dp_packet_put_hex(pkt, payload, NULL);
47 flow_extract(pkt, &flow);
48
49 udp = dp_packet_l4(pkt);
50 udp->udp_src = htons(ntohs(udp->udp_src) + tid);
51
52 if (change) {
53 udp->udp_dst = htons(ntohs(udp->udp_dst) + i);
54 }
55
72c84bc2 56 dp_packet_batch_add(pkt_batch, pkt);
66e4ad8a 57 *dl_type = flow.dl_type;
8cb14626
DDP
58 }
59
60 return pkt_batch;
61}
62
63static void
64destroy_packets(struct dp_packet_batch *pkt_batch)
65{
66 dp_packet_delete_batch(pkt_batch, true);
67 free(pkt_batch);
68}
69
70struct thread_aux {
71 pthread_t thread;
72 unsigned tid;
73};
74
57593fd2 75static struct conntrack *ct;
8cb14626
DDP
76static unsigned long n_threads, n_pkts, batch_size;
77static bool change_conn = false;
78static struct ovs_barrier barrier;
79
80static void *
81ct_thread_main(void *aux_)
82{
83 struct thread_aux *aux = aux_;
84 struct dp_packet_batch *pkt_batch;
66e4ad8a 85 ovs_be16 dl_type;
8cb14626 86 size_t i;
94053e66 87 long long now = time_msec();
8cb14626 88
66e4ad8a 89 pkt_batch = prepare_packets(batch_size, change_conn, aux->tid, &dl_type);
8cb14626
DDP
90 ovs_barrier_block(&barrier);
91 for (i = 0; i < n_pkts; i += batch_size) {
57593fd2 92 conntrack_execute(ct, pkt_batch, dl_type, false, true, 0, NULL, NULL,
2078901a 93 0, 0, NULL, NULL, now, 0);
8cb14626
DDP
94 }
95 ovs_barrier_block(&barrier);
96 destroy_packets(pkt_batch);
97
98 return NULL;
99}
100
101static void
102test_benchmark(struct ovs_cmdl_context *ctx)
103{
104 struct thread_aux *threads;
105 long long start;
106 unsigned i;
107
108 fatal_signal_init();
109
110 /* Parse arguments */
111 n_threads = strtoul(ctx->argv[1], NULL, 0);
112 if (!n_threads) {
113 ovs_fatal(0, "n_threads must be at least one");
114 }
115 n_pkts = strtoul(ctx->argv[2], NULL, 0);
116 batch_size = strtoul(ctx->argv[3], NULL, 0);
117 if (batch_size == 0 || batch_size > NETDEV_MAX_BURST) {
118 ovs_fatal(0, "batch_size must be between 1 and NETDEV_MAX_BURST(%u)",
119 NETDEV_MAX_BURST);
120 }
121 if (ctx->argc > 4) {
122 change_conn = strtoul(ctx->argv[4], NULL, 0);
123 }
124
125 threads = xcalloc(n_threads, sizeof *threads);
126 ovs_barrier_init(&barrier, n_threads + 1);
57593fd2 127 ct = conntrack_init();
8cb14626
DDP
128
129 /* Create threads */
130 for (i = 0; i < n_threads; i++) {
131 threads[i].tid = i;
132 threads[i].thread = ovs_thread_create("ct_thread", ct_thread_main,
133 &threads[i]);
134 }
135 /* Starts the work inside the threads */
136 ovs_barrier_block(&barrier);
137 start = time_msec();
138
139 /* Wait for the threads to finish the work */
140 ovs_barrier_block(&barrier);
141 printf("conntrack: %5lld ms\n", time_msec() - start);
142
143 for (i = 0; i < n_threads; i++) {
144 xpthread_join(threads[i].thread, NULL);
145 }
146
57593fd2 147 conntrack_destroy(ct);
8cb14626
DDP
148 ovs_barrier_destroy(&barrier);
149 free(threads);
150}
b4124903 151
66e4ad8a 152static void
396d492c 153pcap_batch_execute_conntrack(struct conntrack *ct_,
66e4ad8a
DDP
154 struct dp_packet_batch *pkt_batch)
155{
66e4ad8a
DDP
156 struct dp_packet_batch new_batch;
157 ovs_be16 dl_type = htons(0);
94053e66 158 long long now = time_msec();
66e4ad8a
DDP
159
160 dp_packet_batch_init(&new_batch);
161
162 /* pkt_batch contains packets with different 'dl_type'. We have to
163 * call conntrack_execute() on packets with the same 'dl_type'. */
72c84bc2 164 struct dp_packet *packet;
e883448e 165 DP_PACKET_BATCH_FOR_EACH (i, packet, pkt_batch) {
66e4ad8a
DDP
166 struct flow flow;
167
168 /* This also initializes the l3 and l4 pointers. */
72c84bc2 169 flow_extract(packet, &flow);
66e4ad8a 170
72c84bc2 171 if (dp_packet_batch_is_empty(&new_batch)) {
66e4ad8a
DDP
172 dl_type = flow.dl_type;
173 }
174
175 if (flow.dl_type != dl_type) {
396d492c 176 conntrack_execute(ct_, &new_batch, dl_type, false, true, 0,
2078901a 177 NULL, NULL, 0, 0, NULL, NULL, now, 0);
66e4ad8a
DDP
178 dp_packet_batch_init(&new_batch);
179 }
1270b6e5 180 dp_packet_batch_add(&new_batch, packet);
66e4ad8a
DDP
181 }
182
72c84bc2 183 if (!dp_packet_batch_is_empty(&new_batch)) {
396d492c 184 conntrack_execute(ct_, &new_batch, dl_type, false, true, 0, NULL, NULL,
2078901a 185 0, 0, NULL, NULL, now, 0);
66e4ad8a
DDP
186 }
187
188}
189
b4124903
DDP
190static void
191test_pcap(struct ovs_cmdl_context *ctx)
192{
396d492c 193 size_t total_count, batch_size_;
b6e840ae 194 struct pcap_file *pcap;
72c84bc2 195 int err = 0;
b4124903
DDP
196
197 pcap = ovs_pcap_open(ctx->argv[1], "rb");
198 if (!pcap) {
199 return;
200 }
201
396d492c 202 batch_size_ = 1;
b4124903 203 if (ctx->argc > 2) {
396d492c
JP
204 batch_size_ = strtoul(ctx->argv[2], NULL, 0);
205 if (batch_size_ == 0 || batch_size_ > NETDEV_MAX_BURST) {
b4124903
DDP
206 ovs_fatal(0,
207 "batch_size must be between 1 and NETDEV_MAX_BURST(%u)",
208 NETDEV_MAX_BURST);
209 }
210 }
211
212 fatal_signal_init();
213
57593fd2 214 ct = conntrack_init();
b4124903 215 total_count = 0;
5b4db7b5 216 for (;;) {
72c84bc2
AZ
217 struct dp_packet *packet;
218 struct dp_packet_batch pkt_batch_;
219 struct dp_packet_batch *batch = &pkt_batch_;
b4124903 220
72c84bc2 221 dp_packet_batch_init(batch);
396d492c 222 for (int i = 0; i < batch_size_; i++) {
5b4db7b5
BP
223 err = ovs_pcap_read(pcap, &packet, NULL);
224 if (err) {
225 break;
226 }
227 dp_packet_batch_add(batch, packet);
228 }
1270b6e5 229 if (dp_packet_batch_is_empty(batch)) {
b4124903
DDP
230 break;
231 }
57593fd2 232 pcap_batch_execute_conntrack(ct, batch);
b4124903 233
e883448e 234 DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
b4124903 235 struct ds ds = DS_EMPTY_INITIALIZER;
b4124903
DDP
236
237 total_count++;
238
72c84bc2 239 format_flags(&ds, ct_state_to_string, packet->md.ct_state, '|');
b4124903
DDP
240 printf("%"PRIuSIZE": %s\n", total_count, ds_cstr(&ds));
241
242 ds_destroy(&ds);
243 }
244
72c84bc2 245 dp_packet_delete_batch(batch, true);
b4124903 246 }
57593fd2 247 conntrack_destroy(ct);
b6e840ae 248 ovs_pcap_close(pcap);
b4124903 249}
8cb14626
DDP
250\f
251static const struct ovs_cmdl_command commands[] = {
252 /* Connection tracker tests. */
253 /* Starts 'n_threads' threads. Each thread will send 'n_pkts' packets to
254 * the connection tracker, 'batch_size' per call. If 'change_connection'
255 * is '1', each packet in a batch will have a different source and
256 * destination port */
257 {"benchmark", "n_threads n_pkts batch_size [change_connection]", 3, 4,
1f4a7252 258 test_benchmark, OVS_RO},
b4124903
DDP
259 /* Reads packets from 'file' and sends them to the connection tracker,
260 * 'batch_size' (1 by default) per call, with the commit flag set.
261 * Prints the ct_state of each packet. */
1f4a7252 262 {"pcap", "file [batch_size]", 1, 2, test_pcap, OVS_RO},
8cb14626 263
1f4a7252 264 {NULL, NULL, 0, 0, NULL, OVS_RO},
8cb14626
DDP
265};
266
267static void
268test_conntrack_main(int argc, char *argv[])
269{
270 struct ovs_cmdl_context ctx = {
271 .argc = argc - 1,
272 .argv = argv + 1,
273 };
274 set_program_name(argv[0]);
275 ovs_cmdl_run_command(&ctx, commands);
276}
277
278OVSTEST_REGISTER("test-conntrack", test_conntrack_main);