Welcome to mirror list, hosted at ThFree Co, Russian Federation.

netlink00.c « transition « zdtm « test - github.com/checkpoint-restore/criu.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c9b2303e8141cd1c63851c1b9bbbc62262314841 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/* Description: testcase for netlink sockets migration.
 * e.g.
 *  ip rule show
 *  ip rule add
 *  ip rule show
 *  ip rule del
 * in a loop
 */
#include <asm/types.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <linux/netlink.h>
#include <string.h>
#include <linux/rtnetlink.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include "zdtmtst.h"

#undef DEBUG
//#define DEBUG

const char *test_doc    = "Netlink socket loop";
const char *test_author = "Andrew Vagin (avagin@parallels.com)";

//buffer to hold the RTNETLINK request
struct {
	struct nlmsghdr	nl;
	struct rtmsg	rt;
	char		buf[8192];
} req;

// variables used for
// socket communications
int fd;
struct sockaddr_nl la;
struct sockaddr_nl pa;
struct msghdr msg;
struct iovec iov;
int rtn;
// buffer to hold the RTNETLINK reply(ies)
char buf[8192];
char dsts[24] = "192.168.0.255";
int pn = 32;//network prefix

// RTNETLINK message pointers & lengths
// used when processing messages
struct nlmsghdr *nlp;
int nll;
struct rtmsg *rtp;
int rtl;
struct rtattr *rtap;

int send_request();
int recv_reply();
int form_request_add();
int form_request_del();
int read_reply();
typedef int (*cmd_t)();
#define CMD_NUM 2
cmd_t cmd[CMD_NUM]={form_request_add, form_request_del};


int main(int argc, char *argv[])
{
	int i;

	test_init(argc, argv);

	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (fd<0){
		pr_perror("socket");
		goto out;
	}
	// setup local address & bind using
	// this address
	bzero(&la, sizeof(la));
	la.nl_family = AF_NETLINK;
	la.nl_pid = getpid();
	if (bind(fd, (struct sockaddr*) &la, sizeof(la))){
		pr_perror("bind failed");
		goto out;
	}
	//Preparation:
	form_request_del();
	send_request();
	recv_reply();

	test_daemon();

	while (test_go()){
		for (i=0; i < CMD_NUM; i++){
			cmd[i]();
			if (send_request() < 0){
				fail("send_request failed");
				goto out;
			};
			if (recv_reply() < 0){
				fail("RTNETLINK answers: %m");
				goto out;
			};

#ifdef DEBUG
			if (read_reply() < 0){
				fail("read_reply failed");
				goto out;
			}
#endif
		}
	}

	pass();

out:
	return 0;
}

int send_request()
{
	// create the remote address
	// to communicate
	bzero(&pa, sizeof(pa));
	pa.nl_family = AF_NETLINK;
	// initialize & create the struct msghdr supplied
	// to the sendmsg() function
	bzero(&msg, sizeof(msg));
	msg.msg_name = (void *) &pa;
	msg.msg_namelen = sizeof(pa);
	// place the pointer & size of the RTNETLINK
	// message in the struct msghdr
	iov.iov_base = (void *) &req.nl;
	iov.iov_len = req.nl.nlmsg_len;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	// send the RTNETLINK message to kernel
	rtn = sendmsg(fd, &msg, 0);
	if (rtn<0){
		pr_perror("sendmsg failed");
		return -1;
	}
	return 0;
}
int recv_reply()
{
	char *p;
	// initialize the socket read buffer
	bzero(buf, sizeof(buf));
	p = buf;
	nll = 0;
	// read from the socket until the NLMSG_DONE is
	// returned in the type of the RTNETLINK message
	// or if it was a monitoring socket
	while(1) {
		rtn = recv(fd, p, sizeof(buf) - nll, 0);
		if (rtn < 0) {
			pr_perror("recv failed");
			return -1;
		}

		if (rtn == 0) {
			pr_err("EOF on netlink\n");
			return -1;
		}

		nlp = (struct nlmsghdr *) p;
		if(nlp->nlmsg_type == NLMSG_DONE)
			return 0;
		if (nlp->nlmsg_type == NLMSG_ERROR) {
			struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlp);
			errno=-err->error;
			if (errno) {
				return -1;
			}
			return 0;
		}
		// increment the buffer pointer to place
		// next message
		p += rtn;
		// increment the total size by the size of
		// the last received message
		nll += rtn;
		if((la.nl_groups & RTMGRP_IPV4_ROUTE)
				== RTMGRP_IPV4_ROUTE)
			break;
	}
	return 0;
}

int read_reply()
{
	//string to hold content of the route
	// table (i.e. one entry)
	char dsts[24], gws[24], ifs[16], ms[24];
	// outer loop: loops thru all the NETLINK
	// headers that also include the route entry
	// header
	nlp = (struct nlmsghdr *) buf;
	for(; NLMSG_OK(nlp, nll); nlp = NLMSG_NEXT(nlp, nll))
	{
		// get route entry header
		rtp = (struct rtmsg *) NLMSG_DATA(nlp);
		// we are only concerned about the
		// main route table
		if(rtp->rtm_table != RT_TABLE_MAIN)
			continue;
		// init all the strings
		bzero(dsts, sizeof(dsts));
		bzero(gws, sizeof(gws));
		bzero(ifs, sizeof(ifs));
		bzero(ms, sizeof(ms));
		// inner loop: loop thru all the attributes of
		// one route entry
		rtap = (struct rtattr *) RTM_RTA(rtp);
		rtl = RTM_PAYLOAD(nlp);
		for( ; RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap,rtl))
		{
			switch(rtap->rta_type)
			{
				// destination IPv4 address
				case RTA_DST:
					inet_ntop(AF_INET, RTA_DATA(rtap),
							dsts, 24);
					break;
					// next hop IPv4 address
				case RTA_GATEWAY:
					inet_ntop(AF_INET, RTA_DATA(rtap),
							gws, 24);
					break;
					// unique ID associated with the network
					// interface
				case RTA_OIF:
					sprintf(ifs, "%d",
							*((int *) RTA_DATA(rtap)));
				default:
					break;
			}
		}
		sprintf(ms, "%d", rtp->rtm_dst_len);
		test_msg("dst %s/%s gw %s if %s\n",
				dsts, ms, gws, ifs);
	}
	return 0;
}

#define NLMSG_TAIL(nmsg) \
        ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))

int form_request_del()
{
	bzero(&req, sizeof(req));
	req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));

	rtap = NLMSG_TAIL(&req.nl);
	rtap->rta_type = RTA_DST;
	rtap->rta_len = RTA_LENGTH(4);
	inet_pton(AF_INET, dsts,
			((char *)rtap) + sizeof(struct rtattr));
	req.nl.nlmsg_len = NLMSG_ALIGN(req.nl.nlmsg_len) + RTA_ALIGN(rtap->rta_len);
	req.nl.nlmsg_flags = NLM_F_CREATE | NLM_F_ACK | NLM_F_REQUEST;
	req.nl.nlmsg_type = RTM_DELROUTE;
	req.rt.rtm_family = AF_INET;
	req.rt.rtm_table = RT_TABLE_MAIN;
	req.rt.rtm_protocol = RTPROT_STATIC;
	req.rt.rtm_scope = RT_SCOPE_UNIVERSE;
	req.rt.rtm_type = RTN_UNICAST;
	req.rt.rtm_dst_len = pn;
	return 0;
}

int form_request_add()
{
	int ifcn = 1; //interface number

	bzero(&req, sizeof(req));
	req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	rtap = NLMSG_TAIL(&req.nl);
	rtap->rta_type = RTA_DST;
	rtap->rta_len = RTA_LENGTH(4);
	inet_pton(AF_INET, dsts,
			((char *)rtap) + sizeof(struct rtattr));
	req.nl.nlmsg_len = NLMSG_ALIGN(req.nl.nlmsg_len) + RTA_ALIGN(rtap->rta_len);

	rtap = NLMSG_TAIL(&req.nl);
	rtap->rta_type = RTA_OIF;//Output interface index
	rtap->rta_len = RTA_LENGTH(sizeof(int));
	memcpy(((char *)rtap) + sizeof(struct rtattr),
			&ifcn, sizeof(int));

	req.nl.nlmsg_len = NLMSG_ALIGN(req.nl.nlmsg_len) + RTA_ALIGN(rtap->rta_len);
	req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
	req.nl.nlmsg_type = RTM_NEWROUTE;

	req.rt.rtm_family = AF_INET;
	req.rt.rtm_table = RT_TABLE_MAIN;
	req.rt.rtm_protocol = RTPROT_STATIC;
	req.rt.rtm_scope = RT_SCOPE_UNIVERSE;
	req.rt.rtm_type = RTN_UNICAST;
	req.rt.rtm_dst_len = pn;
	return 0;
}