]> git.proxmox.com Git - ovs.git/blame - tests/test-conntrack.c
Fix ovs-dpctl-top by removing 3 wrong hunks in py3-compat.patch.
[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;
79a5251a 85 struct dp_packet *pkt;
66e4ad8a 86 ovs_be16 dl_type;
8cb14626 87 size_t i;
94053e66 88 long long now = time_msec();
8cb14626 89
66e4ad8a 90 pkt_batch = prepare_packets(batch_size, change_conn, aux->tid, &dl_type);
8cb14626
DDP
91 ovs_barrier_block(&barrier);
92 for (i = 0; i < n_pkts; i += batch_size) {
57593fd2 93 conntrack_execute(ct, pkt_batch, dl_type, false, true, 0, NULL, NULL,
2078901a 94 0, 0, NULL, NULL, now, 0);
79a5251a
IM
95 DP_PACKET_BATCH_FOR_EACH (j, pkt, pkt_batch) {
96 pkt_metadata_init_conn(&pkt->md);
97 }
8cb14626
DDP
98 }
99 ovs_barrier_block(&barrier);
100 destroy_packets(pkt_batch);
101
102 return NULL;
103}
104
105static void
106test_benchmark(struct ovs_cmdl_context *ctx)
107{
108 struct thread_aux *threads;
109 long long start;
110 unsigned i;
111
112 fatal_signal_init();
113
114 /* Parse arguments */
115 n_threads = strtoul(ctx->argv[1], NULL, 0);
116 if (!n_threads) {
117 ovs_fatal(0, "n_threads must be at least one");
118 }
119 n_pkts = strtoul(ctx->argv[2], NULL, 0);
120 batch_size = strtoul(ctx->argv[3], NULL, 0);
121 if (batch_size == 0 || batch_size > NETDEV_MAX_BURST) {
122 ovs_fatal(0, "batch_size must be between 1 and NETDEV_MAX_BURST(%u)",
123 NETDEV_MAX_BURST);
124 }
125 if (ctx->argc > 4) {
126 change_conn = strtoul(ctx->argv[4], NULL, 0);
127 }
128
129 threads = xcalloc(n_threads, sizeof *threads);
130 ovs_barrier_init(&barrier, n_threads + 1);
57593fd2 131 ct = conntrack_init();
8cb14626
DDP
132
133 /* Create threads */
134 for (i = 0; i < n_threads; i++) {
135 threads[i].tid = i;
136 threads[i].thread = ovs_thread_create("ct_thread", ct_thread_main,
137 &threads[i]);
138 }
139 /* Starts the work inside the threads */
140 ovs_barrier_block(&barrier);
141 start = time_msec();
142
143 /* Wait for the threads to finish the work */
144 ovs_barrier_block(&barrier);
145 printf("conntrack: %5lld ms\n", time_msec() - start);
146
147 for (i = 0; i < n_threads; i++) {
148 xpthread_join(threads[i].thread, NULL);
149 }
150
57593fd2 151 conntrack_destroy(ct);
8cb14626
DDP
152 ovs_barrier_destroy(&barrier);
153 free(threads);
154}
b4124903 155
66e4ad8a 156static void
396d492c 157pcap_batch_execute_conntrack(struct conntrack *ct_,
66e4ad8a
DDP
158 struct dp_packet_batch *pkt_batch)
159{
66e4ad8a
DDP
160 struct dp_packet_batch new_batch;
161 ovs_be16 dl_type = htons(0);
94053e66 162 long long now = time_msec();
66e4ad8a
DDP
163
164 dp_packet_batch_init(&new_batch);
165
166 /* pkt_batch contains packets with different 'dl_type'. We have to
167 * call conntrack_execute() on packets with the same 'dl_type'. */
72c84bc2 168 struct dp_packet *packet;
e883448e 169 DP_PACKET_BATCH_FOR_EACH (i, packet, pkt_batch) {
66e4ad8a
DDP
170 struct flow flow;
171
172 /* This also initializes the l3 and l4 pointers. */
72c84bc2 173 flow_extract(packet, &flow);
66e4ad8a 174
72c84bc2 175 if (dp_packet_batch_is_empty(&new_batch)) {
66e4ad8a
DDP
176 dl_type = flow.dl_type;
177 }
178
179 if (flow.dl_type != dl_type) {
396d492c 180 conntrack_execute(ct_, &new_batch, dl_type, false, true, 0,
2078901a 181 NULL, NULL, 0, 0, NULL, NULL, now, 0);
66e4ad8a
DDP
182 dp_packet_batch_init(&new_batch);
183 }
1270b6e5 184 dp_packet_batch_add(&new_batch, packet);
66e4ad8a
DDP
185 }
186
72c84bc2 187 if (!dp_packet_batch_is_empty(&new_batch)) {
396d492c 188 conntrack_execute(ct_, &new_batch, dl_type, false, true, 0, NULL, NULL,
2078901a 189 0, 0, NULL, NULL, now, 0);
66e4ad8a
DDP
190 }
191
192}
193
b4124903
DDP
194static void
195test_pcap(struct ovs_cmdl_context *ctx)
196{
396d492c 197 size_t total_count, batch_size_;
b6e840ae 198 struct pcap_file *pcap;
72c84bc2 199 int err = 0;
b4124903
DDP
200
201 pcap = ovs_pcap_open(ctx->argv[1], "rb");
202 if (!pcap) {
203 return;
204 }
205
396d492c 206 batch_size_ = 1;
b4124903 207 if (ctx->argc > 2) {
396d492c
JP
208 batch_size_ = strtoul(ctx->argv[2], NULL, 0);
209 if (batch_size_ == 0 || batch_size_ > NETDEV_MAX_BURST) {
b4124903
DDP
210 ovs_fatal(0,
211 "batch_size must be between 1 and NETDEV_MAX_BURST(%u)",
212 NETDEV_MAX_BURST);
213 }
214 }
215
216 fatal_signal_init();
217
57593fd2 218 ct = conntrack_init();
b4124903 219 total_count = 0;
5b4db7b5 220 for (;;) {
72c84bc2
AZ
221 struct dp_packet *packet;
222 struct dp_packet_batch pkt_batch_;
223 struct dp_packet_batch *batch = &pkt_batch_;
b4124903 224
72c84bc2 225 dp_packet_batch_init(batch);
396d492c 226 for (int i = 0; i < batch_size_; i++) {
5b4db7b5
BP
227 err = ovs_pcap_read(pcap, &packet, NULL);
228 if (err) {
229 break;
230 }
231 dp_packet_batch_add(batch, packet);
232 }
1270b6e5 233 if (dp_packet_batch_is_empty(batch)) {
b4124903
DDP
234 break;
235 }
57593fd2 236 pcap_batch_execute_conntrack(ct, batch);
b4124903 237
e883448e 238 DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
b4124903 239 struct ds ds = DS_EMPTY_INITIALIZER;
b4124903
DDP
240
241 total_count++;
242
72c84bc2 243 format_flags(&ds, ct_state_to_string, packet->md.ct_state, '|');
b4124903
DDP
244 printf("%"PRIuSIZE": %s\n", total_count, ds_cstr(&ds));
245
246 ds_destroy(&ds);
247 }
248
72c84bc2 249 dp_packet_delete_batch(batch, true);
b4124903 250 }
57593fd2 251 conntrack_destroy(ct);
b6e840ae 252 ovs_pcap_close(pcap);
b4124903 253}
8cb14626
DDP
254\f
255static const struct ovs_cmdl_command commands[] = {
256 /* Connection tracker tests. */
257 /* Starts 'n_threads' threads. Each thread will send 'n_pkts' packets to
258 * the connection tracker, 'batch_size' per call. If 'change_connection'
259 * is '1', each packet in a batch will have a different source and
260 * destination port */
261 {"benchmark", "n_threads n_pkts batch_size [change_connection]", 3, 4,
1f4a7252 262 test_benchmark, OVS_RO},
b4124903
DDP
263 /* Reads packets from 'file' and sends them to the connection tracker,
264 * 'batch_size' (1 by default) per call, with the commit flag set.
265 * Prints the ct_state of each packet. */
1f4a7252 266 {"pcap", "file [batch_size]", 1, 2, test_pcap, OVS_RO},
8cb14626 267
1f4a7252 268 {NULL, NULL, 0, 0, NULL, OVS_RO},
8cb14626
DDP
269};
270
271static void
272test_conntrack_main(int argc, char *argv[])
273{
274 struct ovs_cmdl_context ctx = {
275 .argc = argc - 1,
276 .argv = argv + 1,
277 };
278 set_program_name(argv[0]);
279 ovs_cmdl_run_command(&ctx, commands);
280}
281
282OVSTEST_REGISTER("test-conntrack", test_conntrack_main);