1 /*
2    ctdb protocol backward compatibility test
3 
4    Copyright (C) Amitay Isaacs  2017
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "replace.h"
21 #include "system/filesys.h"
22 
23 #include <assert.h>
24 
25 #include "protocol/protocol_basic.c"
26 #include "protocol/protocol_types.c"
27 #include "protocol/protocol_header.c"
28 #include "protocol/protocol_call.c"
29 #include "protocol/protocol_control.c"
30 #include "protocol/protocol_message.c"
31 #include "protocol/protocol_keepalive.c"
32 #include "protocol/protocol_tunnel.c"
33 
34 #include "tests/src/protocol_common.h"
35 #include "tests/src/protocol_common_ctdb.h"
36 
37 #define COMPAT_TEST_FUNC(NAME)		test_ ##NAME## _compat
38 #define OLD_LEN_FUNC(NAME)		NAME## _len_old
39 #define OLD_PUSH_FUNC(NAME)		NAME## _push_old
40 #define OLD_PULL_FUNC(NAME)		NAME## _pull_old
41 
42 #define COMPAT_CTDB1_TEST(TYPE, NAME)	\
43 static void COMPAT_TEST_FUNC(NAME)(void) \
44 { \
45 	TALLOC_CTX *mem_ctx; \
46 	uint8_t *buf1, *buf2; \
47 	TYPE p = { 0 }, p1, p2; \
48 	size_t buflen1, buflen2, np = 0; \
49 	int ret; \
50 \
51 	mem_ctx = talloc_new(NULL); \
52 	assert(mem_ctx != NULL); \
53 	FILL_FUNC(NAME)(&p); \
54 	buflen1 = LEN_FUNC(NAME)(&p); \
55 	buflen2 = OLD_LEN_FUNC(NAME)(&p); \
56 	assert(buflen1 == buflen2); \
57 	buf1 = talloc_zero_size(mem_ctx, buflen1); \
58 	assert(buf1 != NULL); \
59 	buf2 = talloc_zero_size(mem_ctx, buflen2); \
60 	assert(buf2 != NULL); \
61 	PUSH_FUNC(NAME)(&p, buf1, &np); \
62 	OLD_PUSH_FUNC(NAME)(&p, buf2); \
63 	assert(memcmp(buf1, buf2, buflen1) == 0); \
64 	ret = PULL_FUNC(NAME)(buf1, buflen1, &p1, &np); \
65 	assert(ret == 0); \
66 	ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, &p2); \
67 	assert(ret == 0); \
68 	VERIFY_FUNC(NAME)(&p1, &p2); \
69 	talloc_free(mem_ctx); \
70 }
71 
72 #define COMPAT_CTDB4_TEST(TYPE, NAME, OPER) \
73 static void COMPAT_TEST_FUNC(NAME)(void) \
74 { \
75 	TALLOC_CTX *mem_ctx; \
76 	uint8_t *buf1, *buf2; \
77 	struct ctdb_req_header h, h1, h2; \
78 	TYPE p = { 0 }, p1, p2; \
79 	size_t buflen1, buflen2; \
80 	int ret; \
81 \
82 	mem_ctx = talloc_new(NULL); \
83 	assert(mem_ctx != NULL); \
84 	fill_ctdb_req_header(&h); \
85 	FILL_FUNC(NAME)(mem_ctx, &p); \
86 	buflen1 = LEN_FUNC(NAME)(&h, &p); \
87 	buflen2 = OLD_LEN_FUNC(NAME)(&h, &p); \
88 	assert(buflen1 == buflen2); \
89 	buf1 = talloc_zero_size(mem_ctx, buflen1); \
90 	assert(buf1 != NULL); \
91 	buf2 = talloc_zero_size(mem_ctx, buflen2); \
92 	assert(buf2 != NULL); \
93 	ret = PUSH_FUNC(NAME)(&h, &p, buf1, &buflen1); \
94 	assert(ret == 0); \
95 	ret = OLD_PUSH_FUNC(NAME)(&h, &p, buf2, &buflen2); \
96 	assert(ret == 0); \
97 	assert(memcmp(buf1, buf2, buflen1) == 0); \
98 	ret = PULL_FUNC(NAME)(buf1, buflen1, &h1, mem_ctx, &p1); \
99 	assert(ret == 0); \
100 	ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, &h2, mem_ctx, &p2); \
101 	assert(ret == 0); \
102 	verify_ctdb_req_header(&h1, &h2); \
103 	VERIFY_FUNC(NAME)(&p1, &p2); \
104 	talloc_free(mem_ctx); \
105 }
106 
107 #define COMPAT_CTDB5_TEST(TYPE, NAME, OPER) \
108 static void COMPAT_TEST_FUNC(NAME)(uint32_t opcode) \
109 { \
110 	TALLOC_CTX *mem_ctx; \
111 	uint8_t *buf1, *buf2; \
112 	struct ctdb_req_header h, h1, h2; \
113 	TYPE p = { 0 }, p1, p2; \
114 	size_t buflen1, buflen2; \
115 	int ret; \
116 \
117 	mem_ctx = talloc_new(NULL); \
118 	assert(mem_ctx != NULL); \
119 	fill_ctdb_req_header(&h); \
120 	FILL_FUNC(NAME)(mem_ctx, &p, opcode); \
121 	buflen1 = LEN_FUNC(NAME)(&h, &p); \
122 	buflen2 = OLD_LEN_FUNC(NAME)(&h, &p); \
123 	assert(buflen1 == buflen2); \
124 	buf1 = talloc_zero_size(mem_ctx, buflen1); \
125 	assert(buf1 != NULL); \
126 	buf2 = talloc_zero_size(mem_ctx, buflen2); \
127 	assert(buf2 != NULL); \
128 	ret = PUSH_FUNC(NAME)(&h, &p, buf1, &buflen1); \
129 	assert(ret == 0); \
130 	ret = OLD_PUSH_FUNC(NAME)(&h, &p, buf2, &buflen2); \
131 	assert(ret == 0); \
132 	assert(memcmp(buf1, buf2, buflen1) == 0); \
133 	ret = PULL_FUNC(NAME)(buf1, buflen1, &h1, mem_ctx, &p1); \
134 	assert(ret == 0); \
135 	ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, &h2, mem_ctx, &p2); \
136 	assert(ret == 0); \
137 	verify_ctdb_req_header(&h1, &h2); \
138 	VERIFY_FUNC(NAME)(&p1, &p2); \
139 	talloc_free(mem_ctx); \
140 }
141 
142 #define COMPAT_CTDB6_TEST(TYPE, NAME, OPER) \
143 static void COMPAT_TEST_FUNC(NAME)(uint32_t opcode) \
144 { \
145 	TALLOC_CTX *mem_ctx; \
146 	uint8_t *buf1, *buf2; \
147 	struct ctdb_req_header h, h1, h2; \
148 	TYPE p = { 0 }, p1, p2; \
149 	size_t buflen1, buflen2; \
150 	int ret; \
151 \
152 	mem_ctx = talloc_new(NULL); \
153 	assert(mem_ctx != NULL); \
154 	fill_ctdb_req_header(&h); \
155 	FILL_FUNC(NAME)(mem_ctx, &p, opcode); \
156 	buflen1 = LEN_FUNC(NAME)(&h, &p); \
157 	buflen2 = OLD_LEN_FUNC(NAME)(&h, &p); \
158 	assert(buflen1 == buflen2); \
159 	buf1 = talloc_zero_size(mem_ctx, buflen1); \
160 	assert(buf1 != NULL); \
161 	buf2 = talloc_zero_size(mem_ctx, buflen2); \
162 	assert(buf2 != NULL); \
163 	ret = PUSH_FUNC(NAME)(&h, &p, buf1, &buflen1); \
164 	assert(ret == 0); \
165 	ret = OLD_PUSH_FUNC(NAME)(&h, &p, buf2, &buflen2); \
166 	assert(ret == 0); \
167 	assert(memcmp(buf1, buf2, buflen1) == 0); \
168 	ret = PULL_FUNC(NAME)(buf1, buflen1, opcode, &h1, mem_ctx, &p1); \
169 	assert(ret == 0); \
170 	ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, opcode, &h2, mem_ctx, &p2); \
171 	assert(ret == 0); \
172 	verify_ctdb_req_header(&h1, &h2); \
173 	VERIFY_FUNC(NAME)(&p1, &p2); \
174 	talloc_free(mem_ctx); \
175 }
176 
177 #define COMPAT_CTDB7_TEST(TYPE, NAME, OPER) \
178 static void COMPAT_TEST_FUNC(NAME)(uint64_t srvid) \
179 { \
180 	TALLOC_CTX *mem_ctx; \
181 	uint8_t *buf1, *buf2; \
182 	struct ctdb_req_header h, h1, h2; \
183 	TYPE p = { 0 }, p1, p2; \
184 	size_t buflen1, buflen2; \
185 	int ret; \
186 \
187 	mem_ctx = talloc_new(NULL); \
188 	assert(mem_ctx != NULL); \
189 	fill_ctdb_req_header(&h); \
190 	FILL_FUNC(NAME)(mem_ctx, &p, srvid); \
191 	buflen1 = LEN_FUNC(NAME)(&h, &p); \
192 	buflen2 = OLD_LEN_FUNC(NAME)(&h, &p); \
193 	assert(buflen1 == buflen2); \
194 	buf1 = talloc_zero_size(mem_ctx, buflen1); \
195 	assert(buf1 != NULL); \
196 	buf2 = talloc_zero_size(mem_ctx, buflen2); \
197 	assert(buf2 != NULL); \
198 	ret = PUSH_FUNC(NAME)(&h, &p, buf1, &buflen1); \
199 	assert(ret == 0); \
200 	ret = OLD_PUSH_FUNC(NAME)(&h, &p, buf2, &buflen2); \
201 	assert(ret == 0); \
202 	assert(memcmp(buf1, buf2, buflen1) == 0); \
203 	ret = PULL_FUNC(NAME)(buf1, buflen1, &h1, mem_ctx, &p1); \
204 	assert(ret == 0); \
205 	ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, &h2, mem_ctx, &p2); \
206 	assert(ret == 0); \
207 	verify_ctdb_req_header(&h1, &h2); \
208 	VERIFY_FUNC(NAME)(&p1, &p2); \
209 	talloc_free(mem_ctx); \
210 }
211 
212 
213 static size_t ctdb_req_header_len_old(struct ctdb_req_header *in)
214 {
215         return sizeof(struct ctdb_req_header);
216 }
217 
218 static void ctdb_req_header_push_old(struct ctdb_req_header *in, uint8_t *buf)
219 {
220         memcpy(buf, in, sizeof(struct ctdb_req_header));
221 }
222 
223 static int ctdb_req_header_pull_old(uint8_t *buf, size_t buflen,
224 				    struct ctdb_req_header *out)
225 {
226         if (buflen < sizeof(struct ctdb_req_header)) {
227                 return EMSGSIZE;
228         }
229 
230         memcpy(out, buf, sizeof(struct ctdb_req_header));
231         return 0;
232 }
233 
234 struct ctdb_req_call_wire {
235 	struct ctdb_req_header hdr;
236 	uint32_t flags;
237 	uint32_t db_id;
238 	uint32_t callid;
239 	uint32_t hopcount;
240 	uint32_t keylen;
241 	uint32_t calldatalen;
242 	uint8_t data[1]; /* key[] followed by calldata[] */
243 };
244 
245 static size_t ctdb_req_call_len_old(struct ctdb_req_header *h,
246 				    struct ctdb_req_call *c)
247 {
248 	return offsetof(struct ctdb_req_call_wire, data) +
249 		ctdb_tdb_data_len(&c->key) +
250 		ctdb_tdb_data_len(&c->calldata);
251 }
252 
253 static int ctdb_req_call_push_old(struct ctdb_req_header *h,
254 				  struct ctdb_req_call *c,
255 				  uint8_t *buf, size_t *buflen)
256 {
257 	struct ctdb_req_call_wire *wire =
258 		(struct ctdb_req_call_wire *)buf;
259 	size_t length, np;
260 
261 	if (c->key.dsize == 0) {
262 		return EINVAL;
263 	}
264 
265 	length = ctdb_req_call_len_old(h, c);
266 	if (*buflen < length) {
267 		*buflen = length;
268 		return EMSGSIZE;
269 	}
270 
271 	h->length = *buflen;
272 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
273 
274 	wire->flags = c->flags;
275 	wire->db_id = c->db_id;
276 	wire->callid = c->callid;
277 	wire->hopcount = c->hopcount;
278 	wire->keylen = ctdb_tdb_data_len(&c->key);
279 	wire->calldatalen = ctdb_tdb_data_len(&c->calldata);
280 	ctdb_tdb_data_push(&c->key, wire->data, &np);
281 	ctdb_tdb_data_push(&c->calldata, wire->data + wire->keylen, &np);
282 
283 	return 0;
284 }
285 
286 static int ctdb_req_call_pull_old(uint8_t *buf, size_t buflen,
287 				  struct ctdb_req_header *h,
288 				  TALLOC_CTX *mem_ctx,
289 				  struct ctdb_req_call *c)
290 {
291 	struct ctdb_req_call_wire *wire =
292 		(struct ctdb_req_call_wire *)buf;
293 	size_t length, np;
294 	int ret;
295 
296 	length = offsetof(struct ctdb_req_call_wire, data);
297 	if (buflen < length) {
298 		return EMSGSIZE;
299 	}
300 	if (wire->keylen > buflen || wire->calldatalen > buflen) {
301 		return EMSGSIZE;
302 	}
303 	if (length + wire->keylen < length) {
304 		return EMSGSIZE;
305 	}
306 	if (length + wire->keylen + wire->calldatalen < length) {
307 		return EMSGSIZE;
308 	}
309 	if (buflen < length + wire->keylen + wire->calldatalen) {
310 		return EMSGSIZE;
311 	}
312 
313 	if (h != NULL) {
314 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
315 					       h);
316 		if (ret != 0) {
317 			return ret;
318 		}
319 	}
320 
321 	c->flags = wire->flags;
322 	c->db_id = wire->db_id;
323 	c->callid = wire->callid;
324 	c->hopcount = wire->hopcount;
325 
326 	ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key,
327 				 &np);
328 	if (ret != 0) {
329 		return ret;
330 	}
331 
332 	ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->calldatalen,
333 				 mem_ctx, &c->calldata, &np);
334 	if (ret != 0) {
335 		return ret;
336 	}
337 
338 	return 0;
339 }
340 
341 struct ctdb_reply_call_wire {
342 	struct ctdb_req_header hdr;
343 	uint32_t status;
344 	uint32_t datalen;
345 	uint8_t  data[1];
346 };
347 
348 static size_t ctdb_reply_call_len_old(struct ctdb_req_header *h,
349 				      struct ctdb_reply_call *c)
350 {
351 	return offsetof(struct ctdb_reply_call_wire, data) +
352 		ctdb_tdb_data_len(&c->data);
353 }
354 
355 static int ctdb_reply_call_push_old(struct ctdb_req_header *h,
356 				    struct ctdb_reply_call *c,
357 				    uint8_t *buf, size_t *buflen)
358 {
359 	struct ctdb_reply_call_wire *wire =
360 		(struct ctdb_reply_call_wire *)buf;
361 	size_t length, np;
362 
363 	length = ctdb_reply_call_len_old(h, c);
364 	if (*buflen < length) {
365 		*buflen = length;
366 		return EMSGSIZE;
367 	}
368 
369 	h->length = *buflen;
370 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
371 
372 	wire->status = c->status;
373 	wire->datalen = ctdb_tdb_data_len(&c->data);
374 	ctdb_tdb_data_push(&c->data, wire->data, &np);
375 
376 	return 0;
377 }
378 
379 static int ctdb_reply_call_pull_old(uint8_t *buf, size_t buflen,
380 				    struct ctdb_req_header *h,
381 				    TALLOC_CTX *mem_ctx,
382 				    struct ctdb_reply_call *c)
383 {
384 	struct ctdb_reply_call_wire *wire =
385 		(struct ctdb_reply_call_wire *)buf;
386 	size_t length, np;
387 	int ret;
388 
389 	length = offsetof(struct ctdb_reply_call_wire, data);
390 	if (buflen < length) {
391 		return EMSGSIZE;
392 	}
393 	if (wire->datalen > buflen) {
394 		return EMSGSIZE;
395 	}
396 	if (length + wire->datalen < length) {
397 		return EMSGSIZE;
398 	}
399 	if (buflen < length + wire->datalen) {
400 		return EMSGSIZE;
401 	}
402 
403 	if (h != NULL) {
404 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
405 					       h);
406 		if (ret != 0) {
407 			return ret;
408 		}
409 	}
410 
411 	c->status = wire->status;
412 
413 	ret = ctdb_tdb_data_pull(wire->data, wire->datalen, mem_ctx, &c->data,
414 				 &np);
415 	if (ret != 0) {
416 		return ret;
417 	}
418 
419 	return 0;
420 }
421 
422 struct ctdb_reply_error_wire {
423 	struct ctdb_req_header hdr;
424 	uint32_t status;
425 	uint32_t msglen;
426 	uint8_t  msg[1];
427 };
428 
429 static size_t ctdb_reply_error_len_old(struct ctdb_req_header *h,
430 				       struct ctdb_reply_error *c)
431 {
432 	return offsetof(struct ctdb_reply_error_wire, msg) +
433 		ctdb_tdb_data_len(&c->msg);
434 }
435 
436 static int ctdb_reply_error_push_old(struct ctdb_req_header *h,
437 				     struct ctdb_reply_error *c,
438 				     uint8_t *buf, size_t *buflen)
439 {
440 	struct ctdb_reply_error_wire *wire =
441 		(struct ctdb_reply_error_wire *)buf;
442 	size_t length, np;
443 
444 	length = ctdb_reply_error_len_old(h, c);
445 	if (*buflen < length) {
446 		*buflen = length;
447 		return EMSGSIZE;
448 	}
449 
450 	h->length = *buflen;
451 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
452 
453 	wire->status = c->status;
454 	wire->msglen = ctdb_tdb_data_len(&c->msg);
455 	ctdb_tdb_data_push(&c->msg, wire->msg, &np);
456 
457 	return 0;
458 }
459 
460 static int ctdb_reply_error_pull_old(uint8_t *buf, size_t buflen,
461 				     struct ctdb_req_header *h,
462 				     TALLOC_CTX *mem_ctx,
463 				     struct ctdb_reply_error *c)
464 {
465 	struct ctdb_reply_error_wire *wire =
466 		(struct ctdb_reply_error_wire *)buf;
467 	size_t length, np;
468 	int ret;
469 
470 	length = offsetof(struct ctdb_reply_error_wire, msg);
471 	if (buflen < length) {
472 		return EMSGSIZE;
473 	}
474 	if (wire->msglen > buflen) {
475 		return EMSGSIZE;
476 	}
477 	if (length + wire->msglen < length) {
478 		return EMSGSIZE;
479 	}
480 	if (buflen < length + wire->msglen) {
481 		return EMSGSIZE;
482 	}
483 
484 	if (h != NULL) {
485 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
486 					       h);
487 		if (ret != 0) {
488 			return ret;
489 		}
490 	}
491 
492 	c->status = wire->status;
493 
494 	ret = ctdb_tdb_data_pull(wire->msg, wire->msglen, mem_ctx, &c->msg,
495 				 &np);
496 	if (ret != 0) {
497 		return ret;
498 	}
499 
500 	return 0;
501 }
502 
503 struct ctdb_req_dmaster_wire {
504 	struct ctdb_req_header hdr;
505 	uint32_t db_id;
506 	uint64_t rsn;
507 	uint32_t dmaster;
508 	uint32_t keylen;
509 	uint32_t datalen;
510 	uint8_t  data[1];
511 };
512 
513 static size_t ctdb_req_dmaster_len_old(struct ctdb_req_header *h,
514 				       struct ctdb_req_dmaster *c)
515 {
516 	return offsetof(struct ctdb_req_dmaster_wire, data) +
517 		ctdb_tdb_data_len(&c->key) + ctdb_tdb_data_len(&c->data);
518 }
519 
520 static int ctdb_req_dmaster_push_old(struct ctdb_req_header *h,
521 				     struct ctdb_req_dmaster *c,
522 				     uint8_t *buf, size_t *buflen)
523 {
524 	struct ctdb_req_dmaster_wire *wire =
525 		(struct ctdb_req_dmaster_wire *)buf;
526 	size_t length, np;
527 
528 	length = ctdb_req_dmaster_len_old(h, c);
529 	if (*buflen < length) {
530 		*buflen = length;
531 		return EMSGSIZE;
532 	}
533 
534 	h->length = *buflen;
535 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
536 
537 	wire->db_id = c->db_id;
538 	wire->rsn = c->rsn;
539 	wire->dmaster = c->dmaster;
540 	wire->keylen = ctdb_tdb_data_len(&c->key);
541 	wire->datalen = ctdb_tdb_data_len(&c->data);
542 	ctdb_tdb_data_push(&c->key, wire->data, &np);
543 	ctdb_tdb_data_push(&c->data, wire->data + wire->keylen, &np);
544 
545 	return 0;
546 }
547 
548 static int ctdb_req_dmaster_pull_old(uint8_t *buf, size_t buflen,
549 				     struct ctdb_req_header *h,
550 				     TALLOC_CTX *mem_ctx,
551 				     struct ctdb_req_dmaster *c)
552 {
553 	struct ctdb_req_dmaster_wire *wire =
554 		(struct ctdb_req_dmaster_wire *)buf;
555 	size_t length, np;
556 	int ret;
557 
558 	length = offsetof(struct ctdb_req_dmaster_wire, data);
559 	if (buflen < length) {
560 		return EMSGSIZE;
561 	}
562 	if (wire->keylen > buflen || wire->datalen > buflen) {
563 		return EMSGSIZE;
564 	}
565 	if (length + wire->keylen < length) {
566 		return EMSGSIZE;
567 	}
568 	if (length + wire->keylen + wire->datalen < length) {
569 		return EMSGSIZE;
570 	}
571 	if (buflen < length + wire->keylen + wire->datalen) {
572 		return EMSGSIZE;
573 	}
574 
575 	if (h != NULL) {
576 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
577 					       h);
578 		if (ret != 0) {
579 			return ret;
580 		}
581 	}
582 
583 	c->db_id = wire->db_id;
584 	c->rsn = wire->rsn;
585 	c->dmaster = wire->dmaster;
586 
587 	ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key,
588 				 &np);
589 	if (ret != 0) {
590 		return ret;
591 	}
592 
593 	ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->datalen,
594 				 mem_ctx, &c->data, &np);
595 	if (ret != 0) {
596 		return ret;
597 	}
598 
599 	return 0;
600 }
601 
602 struct ctdb_reply_dmaster_wire {
603 	struct ctdb_req_header hdr;
604 	uint32_t db_id;
605 	uint64_t rsn;
606 	uint32_t keylen;
607 	uint32_t datalen;
608 	uint8_t  data[1];
609 };
610 
611 static size_t ctdb_reply_dmaster_len_old(struct ctdb_req_header *h,
612 					 struct ctdb_reply_dmaster *c)
613 {
614 	return offsetof(struct ctdb_reply_dmaster_wire, data) +
615 		ctdb_tdb_data_len(&c->key) + ctdb_tdb_data_len(&c->data);
616 }
617 
618 static int ctdb_reply_dmaster_push_old(struct ctdb_req_header *h,
619 				       struct ctdb_reply_dmaster *c,
620 				       uint8_t *buf, size_t *buflen)
621 {
622 	struct ctdb_reply_dmaster_wire *wire =
623 		(struct ctdb_reply_dmaster_wire *)buf;
624 	size_t length, np;
625 
626 	length = ctdb_reply_dmaster_len_old(h, c);
627 	if (*buflen < length) {
628 		*buflen = length;
629 		return EMSGSIZE;
630 	}
631 
632 	h->length = *buflen;
633 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
634 
635 	wire->db_id = c->db_id;
636 	wire->rsn = c->rsn;
637 	wire->keylen = ctdb_tdb_data_len(&c->key);
638 	wire->datalen = ctdb_tdb_data_len(&c->data);
639 	ctdb_tdb_data_push(&c->key, wire->data, &np);
640 	ctdb_tdb_data_push(&c->data, wire->data + wire->keylen, &np);
641 
642 	return 0;
643 }
644 
645 static int ctdb_reply_dmaster_pull_old(uint8_t *buf, size_t buflen,
646 				       struct ctdb_req_header *h,
647 				       TALLOC_CTX *mem_ctx,
648 				       struct ctdb_reply_dmaster *c)
649 {
650 	struct ctdb_reply_dmaster_wire *wire =
651 		(struct ctdb_reply_dmaster_wire *)buf;
652 	size_t length, np;
653 	int ret;
654 
655 	length = offsetof(struct ctdb_reply_dmaster_wire, data);
656 	if (buflen < length) {
657 		return EMSGSIZE;
658 	}
659 	if (wire->keylen > buflen || wire->datalen > buflen) {
660 		return EMSGSIZE;
661 	}
662 	if (length + wire->keylen < length) {
663 		return EMSGSIZE;
664 	}
665 	if (length + wire->keylen + wire->datalen < length) {
666 		return EMSGSIZE;
667 	}
668 	if (buflen < length + wire->keylen + wire->datalen) {
669 		return EMSGSIZE;
670 	}
671 
672 	if (h != NULL) {
673 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
674 					       h);
675 		if (ret != 0) {
676 			return ret;
677 		}
678 	}
679 
680 	c->db_id = wire->db_id;
681 	c->rsn = wire->rsn;
682 
683 	ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key,
684 				 &np);
685 	if (ret != 0) {
686 		return ret;
687 	}
688 
689 	ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->datalen,
690 				 mem_ctx, &c->data, &np);
691 	if (ret != 0) {
692 		return ret;
693 	}
694 
695 	return 0;
696 }
697 
698 struct ctdb_req_control_wire {
699 	struct ctdb_req_header hdr;
700 	uint32_t opcode;
701 	uint32_t pad;
702 	uint64_t srvid;
703 	uint32_t client_id;
704 	uint32_t flags;
705 	uint32_t datalen;
706 	uint8_t data[1];
707 };
708 
709 static size_t ctdb_req_control_len_old(struct ctdb_req_header *h,
710 				       struct ctdb_req_control *c)
711 {
712 	return offsetof(struct ctdb_req_control_wire, data) +
713 		ctdb_req_control_data_len(&c->rdata);
714 }
715 
716 static int ctdb_req_control_push_old(struct ctdb_req_header *h,
717 				     struct ctdb_req_control *c,
718 				     uint8_t *buf, size_t *buflen)
719 {
720 	struct ctdb_req_control_wire *wire =
721 		(struct ctdb_req_control_wire *)buf;
722 	size_t length, np;
723 
724 	length = ctdb_req_control_len_old(h, c);
725 	if (*buflen < length) {
726 		*buflen = length;
727 		return EMSGSIZE;
728 	}
729 
730 	h->length = *buflen;
731 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
732 
733 	wire->opcode = c->opcode;
734 	wire->pad = c->pad;
735 	wire->srvid = c->srvid;
736 	wire->client_id = c->client_id;
737 	wire->flags = c->flags;
738 
739 	wire->datalen = ctdb_req_control_data_len(&c->rdata);
740 	ctdb_req_control_data_push(&c->rdata, wire->data, &np);
741 
742 	return 0;
743 }
744 
745 static int ctdb_req_control_pull_old(uint8_t *buf, size_t buflen,
746 				     struct ctdb_req_header *h,
747 				     TALLOC_CTX *mem_ctx,
748 				     struct ctdb_req_control *c)
749 {
750 	struct ctdb_req_control_wire *wire =
751 		(struct ctdb_req_control_wire *)buf;
752 	size_t length, np;
753 	int ret;
754 
755 	length = offsetof(struct ctdb_req_control_wire, data);
756 	if (buflen < length) {
757 		return EMSGSIZE;
758 	}
759 	if (wire->datalen > buflen) {
760 		return EMSGSIZE;
761 	}
762 	if (length + wire->datalen < length) {
763 		return EMSGSIZE;
764 	}
765 	if (buflen < length + wire->datalen) {
766 		return EMSGSIZE;
767 	}
768 
769 	if (h != NULL) {
770 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
771 					       h);
772 		if (ret != 0) {
773 			return ret;
774 		}
775 	}
776 
777 	c->opcode = wire->opcode;
778 	c->pad = wire->pad;
779 	c->srvid = wire->srvid;
780 	c->client_id = wire->client_id;
781 	c->flags = wire->flags;
782 
783 	ret = ctdb_req_control_data_pull(wire->data, wire->datalen,
784 					 c->opcode, mem_ctx, &c->rdata, &np);
785 	if (ret != 0) {
786 		return ret;
787 	}
788 
789 	return 0;
790 }
791 
792 struct ctdb_reply_control_wire {
793 	struct ctdb_req_header hdr;
794 	int32_t status;
795 	uint32_t datalen;
796 	uint32_t errorlen;
797 	uint8_t data[1];
798 };
799 
800 static size_t ctdb_reply_control_len_old(struct ctdb_req_header *h,
801 					 struct ctdb_reply_control *c)
802 {
803 	return offsetof(struct ctdb_reply_control_wire, data) +
804 		(c->status == 0 ?
805 			ctdb_reply_control_data_len(&c->rdata) :
806 			ctdb_string_len(&c->errmsg));
807 }
808 
809 static int ctdb_reply_control_push_old(struct ctdb_req_header *h,
810 				       struct ctdb_reply_control *c,
811 				       uint8_t *buf, size_t *buflen)
812 {
813 	struct ctdb_reply_control_wire *wire =
814 		(struct ctdb_reply_control_wire *)buf;
815 	size_t length, np;
816 
817 	length = ctdb_reply_control_len_old(h, c);
818 	if (*buflen < length) {
819 		*buflen = length;
820 		return EMSGSIZE;
821 	}
822 
823 	h->length = *buflen;
824 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
825 
826 	wire->status = c->status;
827 
828 	if (c->status == 0) {
829 		wire->datalen = ctdb_reply_control_data_len(&c->rdata);
830 		wire->errorlen = 0;
831 		ctdb_reply_control_data_push(&c->rdata, wire->data, &np);
832 	} else {
833 		wire->datalen = 0;
834 		wire->errorlen = ctdb_string_len(&c->errmsg);
835 		ctdb_string_push(&c->errmsg, wire->data + wire->datalen, &np);
836 	}
837 
838 	return 0;
839 }
840 
841 static int ctdb_reply_control_pull_old(uint8_t *buf, size_t buflen,
842 				       uint32_t opcode,
843 				       struct ctdb_req_header *h,
844 				       TALLOC_CTX *mem_ctx,
845 				       struct ctdb_reply_control *c)
846 {
847 	struct ctdb_reply_control_wire *wire =
848 		(struct ctdb_reply_control_wire *)buf;
849 	size_t length, np;
850 	int ret;
851 
852 	length = offsetof(struct ctdb_reply_control_wire, data);
853 	if (buflen < length) {
854 		return EMSGSIZE;
855 	}
856 	if (wire->datalen > buflen || wire->errorlen > buflen) {
857 		return EMSGSIZE;
858 	}
859 	if (length + wire->datalen < length) {
860 		return EMSGSIZE;
861 	}
862 	if (length + wire->datalen + wire->errorlen < length) {
863 		return EMSGSIZE;
864 	}
865 	if (buflen < length + wire->datalen + wire->errorlen) {
866 		return EMSGSIZE;
867 	}
868 
869 	if (h != NULL) {
870 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
871 					       h);
872 		if (ret != 0) {
873 			return ret;
874 		}
875 	}
876 
877 	c->status = wire->status;
878 
879 	if (c->status != -1) {
880 		ret = ctdb_reply_control_data_pull(wire->data, wire->datalen,
881 						   opcode, mem_ctx,
882 						   &c->rdata, &np);
883 		if (ret != 0) {
884 			return ret;
885 		}
886 	}
887 
888 	ret = ctdb_string_pull(wire->data + wire->datalen, wire->errorlen,
889 			       mem_ctx, &c->errmsg, &np);
890 	if (ret != 0) {
891 		return ret;
892 	}
893 
894 	return 0;
895 }
896 
897 struct ctdb_req_message_wire {
898 	struct ctdb_req_header hdr;
899 	uint64_t srvid;
900 	uint32_t datalen;
901 	uint8_t data[1];
902 };
903 
904 static size_t ctdb_req_message_len_old(struct ctdb_req_header *h,
905 				       struct ctdb_req_message *c)
906 {
907 	return offsetof(struct ctdb_req_message_wire, data) +
908 		ctdb_message_data_len(&c->data, c->srvid);
909 }
910 
911 static int ctdb_req_message_push_old(struct ctdb_req_header *h,
912 				     struct ctdb_req_message *c,
913 				     uint8_t *buf, size_t *buflen)
914 {
915 	struct ctdb_req_message_wire *wire =
916 		(struct ctdb_req_message_wire *)buf;
917 	size_t length, np;
918 
919 	length = ctdb_req_message_len_old(h, c);
920 	if (*buflen < length) {
921 		*buflen = length;
922 		return EMSGSIZE;
923 	}
924 
925 	h->length = *buflen;
926 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
927 
928 	wire->srvid = c->srvid;
929 	wire->datalen = ctdb_message_data_len(&c->data, c->srvid);
930 	ctdb_message_data_push(&c->data, c->srvid, wire->data, &np);
931 
932 	return 0;
933 }
934 
935 static int ctdb_req_message_pull_old(uint8_t *buf, size_t buflen,
936 				     struct ctdb_req_header *h,
937 				     TALLOC_CTX *mem_ctx,
938 				     struct ctdb_req_message *c)
939 {
940 	struct ctdb_req_message_wire *wire =
941 		(struct ctdb_req_message_wire *)buf;
942 	size_t length, np;
943 	int ret;
944 
945 	length = offsetof(struct ctdb_req_message_wire, data);
946 	if (buflen < length) {
947 		return EMSGSIZE;
948 	}
949 	if (wire->datalen > buflen) {
950 		return EMSGSIZE;
951 	}
952 	if (length + wire->datalen < length) {
953 		return EMSGSIZE;
954 	}
955 	if (buflen < length + wire->datalen) {
956 		return EMSGSIZE;
957 	}
958 
959 	if (h != NULL) {
960 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
961 					       h);
962 		if (ret != 0) {
963 			return ret;
964 		}
965 	}
966 
967 	c->srvid = wire->srvid;
968 	ret = ctdb_message_data_pull(wire->data, wire->datalen, wire->srvid,
969 				     mem_ctx, &c->data, &np);
970 	return ret;
971 }
972 
973 static size_t ctdb_req_message_data_len_old(struct ctdb_req_header *h,
974 					    struct ctdb_req_message_data *c)
975 {
976 	return offsetof(struct ctdb_req_message_wire, data) +
977 		ctdb_tdb_data_len(&c->data);
978 }
979 
980 static int ctdb_req_message_data_push_old(struct ctdb_req_header *h,
981 					  struct ctdb_req_message_data *c,
982 					  uint8_t *buf, size_t *buflen)
983 {
984 	struct ctdb_req_message_wire *wire =
985 		(struct ctdb_req_message_wire *)buf;
986 	size_t length, np;
987 
988 	length = ctdb_req_message_data_len_old(h, c);
989 	if (*buflen < length) {
990 		*buflen = length;
991 		return EMSGSIZE;
992 	}
993 
994 	h->length = *buflen;
995 	ctdb_req_header_push(h, (uint8_t *)&wire->hdr, &np);
996 
997 	wire->srvid = c->srvid;
998 	wire->datalen = ctdb_tdb_data_len(&c->data);
999 	ctdb_tdb_data_push(&c->data, wire->data, &np);
1000 
1001 	return 0;
1002 }
1003 
1004 static int ctdb_req_message_data_pull_old(uint8_t *buf, size_t buflen,
1005 					  struct ctdb_req_header *h,
1006 					  TALLOC_CTX *mem_ctx,
1007 					  struct ctdb_req_message_data *c)
1008 {
1009 	struct ctdb_req_message_wire *wire =
1010 		(struct ctdb_req_message_wire *)buf;
1011 	size_t length, np;
1012 	int ret;
1013 
1014 	length = offsetof(struct ctdb_req_message_wire, data);
1015 	if (buflen < length) {
1016 		return EMSGSIZE;
1017 	}
1018 	if (wire->datalen > buflen) {
1019 		return EMSGSIZE;
1020 	}
1021 	if (length + wire->datalen < length) {
1022 		return EMSGSIZE;
1023 	}
1024 	if (buflen < length + wire->datalen) {
1025 		return EMSGSIZE;
1026 	}
1027 
1028 	if (h != NULL) {
1029 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
1030 					       h);
1031 		if (ret != 0) {
1032 			return ret;
1033 		}
1034 	}
1035 
1036 	c->srvid = wire->srvid;
1037 
1038 	ret = ctdb_tdb_data_pull(wire->data, wire->datalen,
1039 				 mem_ctx, &c->data, &np);
1040 	if (ret != 0) {
1041 		return ret;
1042 	}
1043 
1044 	return 0;
1045 }
1046 
1047 struct ctdb_req_keepalive_wire {
1048 	struct ctdb_req_header hdr;
1049 	uint32_t version;
1050 	uint32_t uptime;
1051 };
1052 
1053 static size_t ctdb_req_keepalive_len_old(struct ctdb_req_header *h,
1054 					 struct ctdb_req_keepalive *c)
1055 {
1056 	return sizeof(struct ctdb_req_keepalive_wire);
1057 }
1058 
1059 static int ctdb_req_keepalive_push_old(struct ctdb_req_header *h,
1060 				       struct ctdb_req_keepalive *c,
1061 				       uint8_t *buf, size_t *buflen)
1062 {
1063 	struct ctdb_req_keepalive_wire *wire =
1064 		(struct ctdb_req_keepalive_wire *)buf;
1065 	size_t length;
1066 
1067 	length = ctdb_req_keepalive_len_old(h, c);
1068 	if (*buflen < length) {
1069 		*buflen = length;
1070 		return EMSGSIZE;
1071 	}
1072 
1073 	h->length = *buflen;
1074 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
1075 
1076 	wire->version = c->version;
1077 	wire->uptime = c->uptime;
1078 
1079 	return 0;
1080 }
1081 
1082 static int ctdb_req_keepalive_pull_old(uint8_t *buf, size_t buflen,
1083 				       struct ctdb_req_header *h,
1084 				       TALLOC_CTX *mem_ctx,
1085 				       struct ctdb_req_keepalive *c)
1086 {
1087 	struct ctdb_req_keepalive_wire *wire =
1088 		(struct ctdb_req_keepalive_wire *)buf;
1089 	size_t length;
1090 	int ret;
1091 
1092 	length = sizeof(struct ctdb_req_keepalive_wire);
1093 	if (buflen < length) {
1094 		return EMSGSIZE;
1095 	}
1096 
1097 	if (h != NULL) {
1098 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
1099 					       h);
1100 		if (ret != 0) {
1101 			return ret;
1102 		}
1103 	}
1104 
1105 	c->version = wire->version;
1106 	c->uptime = wire->uptime;
1107 
1108 	return 0;
1109 }
1110 
1111 struct ctdb_req_tunnel_wire {
1112 	struct ctdb_req_header hdr;
1113 	uint64_t tunnel_id;
1114 	uint32_t flags;
1115 	uint32_t datalen;
1116 	uint8_t data[1];
1117 };
1118 
1119 static size_t ctdb_req_tunnel_len_old(struct ctdb_req_header *h,
1120 				      struct ctdb_req_tunnel *c)
1121 {
1122 	return offsetof(struct ctdb_req_tunnel_wire, data) +
1123 		ctdb_tdb_data_len(&c->data);
1124 }
1125 
1126 static int ctdb_req_tunnel_push_old(struct ctdb_req_header *h,
1127 				    struct ctdb_req_tunnel *c,
1128 				    uint8_t *buf, size_t *buflen)
1129 {
1130 	struct ctdb_req_tunnel_wire *wire =
1131 		(struct ctdb_req_tunnel_wire *)buf;
1132 	size_t length, np;
1133 
1134 	length = ctdb_req_tunnel_len_old(h, c);
1135 	if (*buflen < length) {
1136 		*buflen = length;
1137 		return EMSGSIZE;
1138 	}
1139 
1140 	h->length = *buflen;
1141 	ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
1142 
1143 	wire->tunnel_id = c->tunnel_id;
1144 	wire->flags = c->flags;
1145 	wire->datalen = ctdb_tdb_data_len(&c->data);
1146 	ctdb_tdb_data_push(&c->data, wire->data, &np);
1147 
1148 	return 0;
1149 }
1150 
1151 static int ctdb_req_tunnel_pull_old(uint8_t *buf, size_t buflen,
1152 				    struct ctdb_req_header *h,
1153 				    TALLOC_CTX *mem_ctx,
1154 				    struct ctdb_req_tunnel *c)
1155 {
1156 	struct ctdb_req_tunnel_wire *wire =
1157 		(struct ctdb_req_tunnel_wire *)buf;
1158 	size_t length, np;
1159 	int ret;
1160 
1161 	length = offsetof(struct ctdb_req_tunnel_wire, data);
1162 	if (buflen < length) {
1163 		return EMSGSIZE;
1164 	}
1165 	if (wire->datalen > buflen) {
1166 		return EMSGSIZE;
1167 	}
1168 	if (length + wire->datalen < length) {
1169 		return EMSGSIZE;
1170 	}
1171 	if (buflen < length + wire->datalen) {
1172 		return EMSGSIZE;
1173 	}
1174 
1175 	if (h != NULL) {
1176 		ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
1177 					       h);
1178 		if (ret != 0) {
1179 			return ret;
1180 		}
1181 	}
1182 
1183 	c->tunnel_id = wire->tunnel_id;
1184 	c->flags = wire->flags;
1185 
1186 	ret = ctdb_tdb_data_pull(wire->data, wire->datalen, mem_ctx, &c->data,
1187 				 &np);
1188 	if (ret != 0) {
1189 		return ret;
1190 	}
1191 
1192 	return 0;
1193 }
1194 
1195 
1196 COMPAT_CTDB1_TEST(struct ctdb_req_header, ctdb_req_header);
1197 
1198 COMPAT_CTDB4_TEST(struct ctdb_req_call, ctdb_req_call, CTDB_REQ_CALL);
1199 COMPAT_CTDB4_TEST(struct ctdb_reply_call, ctdb_reply_call, CTDB_REPLY_CALL);
1200 COMPAT_CTDB4_TEST(struct ctdb_reply_error, ctdb_reply_error, CTDB_REPLY_ERROR);
1201 COMPAT_CTDB4_TEST(struct ctdb_req_dmaster, ctdb_req_dmaster, CTDB_REQ_DMASTER);
1202 COMPAT_CTDB4_TEST(struct ctdb_reply_dmaster, ctdb_reply_dmaster, CTDB_REPLY_DMASTER);
1203 
1204 COMPAT_CTDB5_TEST(struct ctdb_req_control, ctdb_req_control, CTDB_REQ_CONTROL);
1205 COMPAT_CTDB6_TEST(struct ctdb_reply_control, ctdb_reply_control, CTDB_REPLY_CONTROL);
1206 
1207 COMPAT_CTDB7_TEST(struct ctdb_req_message, ctdb_req_message, CTDB_REQ_MESSAGE);
1208 COMPAT_CTDB4_TEST(struct ctdb_req_message_data, ctdb_req_message_data, CTDB_REQ_MESSAGE);
1209 
1210 COMPAT_CTDB4_TEST(struct ctdb_req_keepalive, ctdb_req_keepalive, CTDB_REQ_KEEPALIVE);
1211 COMPAT_CTDB4_TEST(struct ctdb_req_tunnel, ctdb_req_tunnel, CTDB_REQ_TUNNEL);
1212 
1213 #define NUM_CONTROLS	151
1214 
1215 int main(int argc, char *argv[])
1216 {
1217 	uint32_t opcode;
1218 	uint64_t test_srvid[] = {
1219 		CTDB_SRVID_BANNING,
1220 		CTDB_SRVID_ELECTION,
1221 		CTDB_SRVID_RECONFIGURE,
1222 		CTDB_SRVID_RELEASE_IP,
1223 		CTDB_SRVID_TAKE_IP,
1224 		CTDB_SRVID_SET_NODE_FLAGS,
1225 		CTDB_SRVID_RECD_UPDATE_IP,
1226 		CTDB_SRVID_VACUUM_FETCH,
1227 		CTDB_SRVID_DETACH_DATABASE,
1228 		CTDB_SRVID_MEM_DUMP,
1229 		CTDB_SRVID_GETLOG,
1230 		CTDB_SRVID_CLEARLOG,
1231 		CTDB_SRVID_PUSH_NODE_FLAGS,
1232 		CTDB_SRVID_RELOAD_NODES,
1233 		CTDB_SRVID_TAKEOVER_RUN,
1234 		CTDB_SRVID_REBALANCE_NODE,
1235 		CTDB_SRVID_DISABLE_TAKEOVER_RUNS,
1236 		CTDB_SRVID_DISABLE_RECOVERIES,
1237 		CTDB_SRVID_DISABLE_IP_CHECK,
1238 	};
1239 	unsigned int i;
1240 
1241 	if (argc == 2) {
1242 		int seed = atoi(argv[1]);
1243 		srandom(seed);
1244 	}
1245 
1246 	COMPAT_TEST_FUNC(ctdb_req_header)();
1247 
1248 	COMPAT_TEST_FUNC(ctdb_req_call)();
1249 	COMPAT_TEST_FUNC(ctdb_reply_call)();
1250 	COMPAT_TEST_FUNC(ctdb_reply_error)();
1251 	COMPAT_TEST_FUNC(ctdb_req_dmaster)();
1252 	COMPAT_TEST_FUNC(ctdb_reply_dmaster)();
1253 
1254 	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
1255 		COMPAT_TEST_FUNC(ctdb_req_control)(opcode);
1256 	}
1257 	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
1258 		COMPAT_TEST_FUNC(ctdb_reply_control)(opcode);
1259 	}
1260 
1261 	for (i=0; i<ARRAY_SIZE(test_srvid); i++) {
1262 		COMPAT_TEST_FUNC(ctdb_req_message)(test_srvid[i]);
1263 	}
1264 	COMPAT_TEST_FUNC(ctdb_req_message_data)();
1265 
1266 	COMPAT_TEST_FUNC(ctdb_req_keepalive)();
1267 	COMPAT_TEST_FUNC(ctdb_req_tunnel)();
1268 
1269 	return 0;
1270 }
1271