xref: /kvmtool/net/uip/udp.c (revision d9da915bb5dba957360731fa024e57b55c2ca7ef)
1dd7a270bSAsias He #include "kvm/uip.h"
2dd7a270bSAsias He 
3dd7a270bSAsias He #include <linux/virtio_net.h>
4dd7a270bSAsias He #include <linux/kernel.h>
5dd7a270bSAsias He #include <linux/list.h>
6dd7a270bSAsias He #include <sys/socket.h>
7dd7a270bSAsias He #include <sys/epoll.h>
8dd7a270bSAsias He #include <fcntl.h>
9dd7a270bSAsias He 
10dd7a270bSAsias He #define UIP_UDP_MAX_EVENTS 1000
11dd7a270bSAsias He 
12dd7a270bSAsias He static struct uip_udp_socket *uip_udp_socket_find(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport)
13dd7a270bSAsias He {
14dd7a270bSAsias He 	struct list_head *sk_head;
15dd7a270bSAsias He 	struct uip_udp_socket *sk;
16dd7a270bSAsias He 	pthread_mutex_t *sk_lock;
17dd7a270bSAsias He 	struct epoll_event ev;
18dd7a270bSAsias He 	int flags;
19dd7a270bSAsias He 	int ret;
20dd7a270bSAsias He 
21dd7a270bSAsias He 	sk_head = &arg->info->udp_socket_head;
22dd7a270bSAsias He 	sk_lock = &arg->info->udp_socket_lock;
23dd7a270bSAsias He 
24dd7a270bSAsias He 	/*
25dd7a270bSAsias He 	 * Find existing sk
26dd7a270bSAsias He 	 */
27dd7a270bSAsias He 	mutex_lock(sk_lock);
28dd7a270bSAsias He 	list_for_each_entry(sk, sk_head, list) {
29dd7a270bSAsias He 		if (sk->sip == sip && sk->dip == dip && sk->sport == sport && sk->dport == dport) {
30dd7a270bSAsias He 			mutex_unlock(sk_lock);
31dd7a270bSAsias He 			return sk;
32dd7a270bSAsias He 		}
33dd7a270bSAsias He 	}
34dd7a270bSAsias He 	mutex_unlock(sk_lock);
35dd7a270bSAsias He 
36dd7a270bSAsias He 	/*
37dd7a270bSAsias He 	 * Allocate new one
38dd7a270bSAsias He 	 */
39dd7a270bSAsias He 	sk = malloc(sizeof(*sk));
40dd7a270bSAsias He 	memset(sk, 0, sizeof(*sk));
41dd7a270bSAsias He 
42dd7a270bSAsias He 	sk->lock = sk_lock;
43dd7a270bSAsias He 
44dd7a270bSAsias He 	sk->fd = socket(AF_INET, SOCK_DGRAM, 0);
45dd7a270bSAsias He 	if (sk->fd < 0)
46dd7a270bSAsias He 		goto out;
47dd7a270bSAsias He 
48dd7a270bSAsias He 	/*
49dd7a270bSAsias He 	 * Set non-blocking
50dd7a270bSAsias He 	 */
51dd7a270bSAsias He 	flags = fcntl(sk->fd, F_GETFL, 0);
52dd7a270bSAsias He 	flags |= O_NONBLOCK;
53dd7a270bSAsias He 	fcntl(sk->fd, F_SETFL, flags);
54dd7a270bSAsias He 
55dd7a270bSAsias He 	/*
56dd7a270bSAsias He 	 * Add sk->fd to epoll_wait
57dd7a270bSAsias He 	 */
58dd7a270bSAsias He 	ev.events	= EPOLLIN;
59dd7a270bSAsias He 	ev.data.fd	= sk->fd;
60dd7a270bSAsias He 	ev.data.ptr	= sk;
61dd7a270bSAsias He 	if (arg->info->udp_epollfd <= 0)
62dd7a270bSAsias He 		arg->info->udp_epollfd = epoll_create(UIP_UDP_MAX_EVENTS);
63dd7a270bSAsias He 	ret = epoll_ctl(arg->info->udp_epollfd, EPOLL_CTL_ADD, sk->fd, &ev);
64dd7a270bSAsias He 	if (ret == -1)
65dd7a270bSAsias He 		pr_warning("epoll_ctl error");
66dd7a270bSAsias He 
67dd7a270bSAsias He 	sk->addr.sin_family	 = AF_INET;
68dd7a270bSAsias He 	sk->addr.sin_addr.s_addr = dip;
69dd7a270bSAsias He 	sk->addr.sin_port	 = dport;
70dd7a270bSAsias He 
71dd7a270bSAsias He 	sk->sip			 = sip;
72dd7a270bSAsias He 	sk->dip			 = dip;
73dd7a270bSAsias He 	sk->sport		 = sport;
74dd7a270bSAsias He 	sk->dport		 = dport;
75dd7a270bSAsias He 
76dd7a270bSAsias He 	mutex_lock(sk_lock);
77dd7a270bSAsias He 	list_add_tail(&sk->list, sk_head);
78dd7a270bSAsias He 	mutex_unlock(sk_lock);
79dd7a270bSAsias He 
80dd7a270bSAsias He 	return sk;
81dd7a270bSAsias He 
82dd7a270bSAsias He out:
83dd7a270bSAsias He 	free(sk);
84dd7a270bSAsias He 	return NULL;
85dd7a270bSAsias He }
86dd7a270bSAsias He 
87dd7a270bSAsias He static int uip_udp_socket_send(struct uip_udp_socket *sk, struct uip_udp *udp)
88dd7a270bSAsias He {
89dd7a270bSAsias He 	int len;
90dd7a270bSAsias He 	int ret;
91dd7a270bSAsias He 
92dd7a270bSAsias He 	len = ntohs(udp->len) - uip_udp_hdrlen(udp);
93dd7a270bSAsias He 
94dd7a270bSAsias He 	ret = sendto(sk->fd, udp->payload, len, 0, (struct sockaddr *)&sk->addr, sizeof(sk->addr));
95dd7a270bSAsias He 	if (ret != len)
96dd7a270bSAsias He 		return -1;
97dd7a270bSAsias He 
98dd7a270bSAsias He 	return 0;
99dd7a270bSAsias He }
100dd7a270bSAsias He 
101*d9da915bSAsias He int uip_udp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8* payload, int payload_len)
102dd7a270bSAsias He {
103dd7a270bSAsias He 	struct uip_eth *eth2;
104dd7a270bSAsias He 	struct uip_udp *udp2;
105dd7a270bSAsias He 	struct uip_ip *ip2;
106dd7a270bSAsias He 
107dd7a270bSAsias He 	/*
108dd7a270bSAsias He 	 * Cook a ethernet frame
109dd7a270bSAsias He 	 */
110dd7a270bSAsias He 	udp2		= (struct uip_udp *)(buf->eth);
111dd7a270bSAsias He 	eth2		= (struct uip_eth *)buf->eth;
112dd7a270bSAsias He 	ip2		= (struct uip_ip *)(buf->eth);
113dd7a270bSAsias He 
114dd7a270bSAsias He 	eth2->src	= info->host_mac;
115dd7a270bSAsias He 	eth2->dst	= info->guest_mac;
116dd7a270bSAsias He 	eth2->type	= htons(UIP_ETH_P_IP);
117dd7a270bSAsias He 
118dd7a270bSAsias He 	ip2->vhl	= UIP_IP_VER_4 | UIP_IP_HDR_LEN;
119dd7a270bSAsias He 	ip2->tos	= 0;
120dd7a270bSAsias He 	ip2->id		= 0;
121dd7a270bSAsias He 	ip2->flgfrag	= 0;
122dd7a270bSAsias He 	ip2->ttl	= UIP_IP_TTL;
123dd7a270bSAsias He 	ip2->proto	= UIP_IP_P_UDP;
124dd7a270bSAsias He 	ip2->csum	= 0;
125*d9da915bSAsias He 
126dd7a270bSAsias He 	ip2->sip	= sk->dip;
127dd7a270bSAsias He 	ip2->dip	= sk->sip;
128dd7a270bSAsias He 	udp2->sport	= sk->dport;
129dd7a270bSAsias He 	udp2->dport	= sk->sport;
130*d9da915bSAsias He 
131*d9da915bSAsias He 	udp2->len	= htons(payload_len + uip_udp_hdrlen(udp2));
132dd7a270bSAsias He 	udp2->csum	= 0;
133dd7a270bSAsias He 
134*d9da915bSAsias He 	if (payload)
135*d9da915bSAsias He 		memcpy(udp2->payload, payload, payload_len);
136dd7a270bSAsias He 
137dd7a270bSAsias He 	ip2->len	= udp2->len + htons(uip_ip_hdrlen(ip2));
138dd7a270bSAsias He 	ip2->csum	= uip_csum_ip(ip2);
139dd7a270bSAsias He 	udp2->csum	= uip_csum_udp(udp2);
140dd7a270bSAsias He 
141dd7a270bSAsias He 	/*
142dd7a270bSAsias He 	 * virtio_net_hdr
143dd7a270bSAsias He 	 */
144dd7a270bSAsias He 	buf->vnet_len	= sizeof(struct virtio_net_hdr);
145dd7a270bSAsias He 	memset(buf->vnet, 0, buf->vnet_len);
146dd7a270bSAsias He 
147dd7a270bSAsias He 	buf->eth_len	= ntohs(ip2->len) + uip_eth_hdrlen(&ip2->eth);
148dd7a270bSAsias He 
149*d9da915bSAsias He 	return 0;
150*d9da915bSAsias He }
151*d9da915bSAsias He 
152*d9da915bSAsias He static void *uip_udp_socket_thread(void *p)
153*d9da915bSAsias He {
154*d9da915bSAsias He 	struct epoll_event events[UIP_UDP_MAX_EVENTS];
155*d9da915bSAsias He 	struct uip_udp_socket *sk;
156*d9da915bSAsias He 	struct uip_info *info;
157*d9da915bSAsias He 	struct uip_buf *buf;
158*d9da915bSAsias He 	int payload_len;
159*d9da915bSAsias He 	u8 *payload;
160*d9da915bSAsias He 	int nfds;
161*d9da915bSAsias He 	int i;
162*d9da915bSAsias He 
163*d9da915bSAsias He 	info = p;
164*d9da915bSAsias He 
165*d9da915bSAsias He 	do {
166*d9da915bSAsias He 		payload = malloc(UIP_MAX_UDP_PAYLOAD);
167*d9da915bSAsias He 	} while (!payload);
168*d9da915bSAsias He 
169*d9da915bSAsias He 	while (1) {
170*d9da915bSAsias He 		nfds = epoll_wait(info->udp_epollfd, events, UIP_UDP_MAX_EVENTS, -1);
171*d9da915bSAsias He 
172*d9da915bSAsias He 		if (nfds == -1)
173*d9da915bSAsias He 			continue;
174*d9da915bSAsias He 
175*d9da915bSAsias He 		for (i = 0; i < nfds; i++) {
176*d9da915bSAsias He 
177*d9da915bSAsias He 			sk = events[i].data.ptr;
178*d9da915bSAsias He 			payload_len = recvfrom(sk->fd, payload, UIP_MAX_UDP_PAYLOAD, 0, NULL, NULL);
179*d9da915bSAsias He 			if (payload_len < 0)
180*d9da915bSAsias He 				continue;
181*d9da915bSAsias He 
182*d9da915bSAsias He 			/*
183*d9da915bSAsias He 			 * Get free buffer to send data to guest
184*d9da915bSAsias He 			 */
185*d9da915bSAsias He 			buf		= uip_buf_get_free(info);
186*d9da915bSAsias He 
187*d9da915bSAsias He 			uip_udp_make_pkg(info, sk, buf, payload, payload_len);
188*d9da915bSAsias He 
189dd7a270bSAsias He 			/*
190dd7a270bSAsias He 			 * Send data received from socket to guest
191dd7a270bSAsias He 			 */
192dd7a270bSAsias He 			uip_buf_set_used(info, buf);
193dd7a270bSAsias He 		}
194dd7a270bSAsias He 	}
195dd7a270bSAsias He 
196dd7a270bSAsias He 	free(payload);
197dd7a270bSAsias He 	pthread_exit(NULL);
198dd7a270bSAsias He 	return NULL;
199dd7a270bSAsias He }
200dd7a270bSAsias He 
201dd7a270bSAsias He int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg)
202dd7a270bSAsias He {
203dd7a270bSAsias He 	struct uip_udp_socket *sk;
204dd7a270bSAsias He 	struct uip_info *info;
205dd7a270bSAsias He 	struct uip_udp *udp;
206dd7a270bSAsias He 	struct uip_ip *ip;
207dd7a270bSAsias He 	int ret;
208dd7a270bSAsias He 
209dd7a270bSAsias He 	udp	= (struct uip_udp *)(arg->eth);
210dd7a270bSAsias He 	ip	= (struct uip_ip *)(arg->eth);
211dd7a270bSAsias He 	info	= arg->info;
212dd7a270bSAsias He 
213dd7a270bSAsias He 	/*
214dd7a270bSAsias He 	 * Find socket we have allocated before, otherwise allocate one
215dd7a270bSAsias He 	 */
216dd7a270bSAsias He 	sk = uip_udp_socket_find(arg, ip->sip, ip->dip, udp->sport, udp->dport);
217dd7a270bSAsias He 	if (!sk)
218dd7a270bSAsias He 		return -1;
219dd7a270bSAsias He 
220dd7a270bSAsias He 	/*
221dd7a270bSAsias He 	 * Send out UDP data to remote host
222dd7a270bSAsias He 	 */
223dd7a270bSAsias He 	ret = uip_udp_socket_send(sk, udp);
224dd7a270bSAsias He 	if (ret)
225dd7a270bSAsias He 		return -1;
226dd7a270bSAsias He 
227dd7a270bSAsias He 	if (!info->udp_thread)
228dd7a270bSAsias He 		pthread_create(&info->udp_thread, NULL, uip_udp_socket_thread, (void *)info);
229dd7a270bSAsias He 
230dd7a270bSAsias He 	return 0;
231dd7a270bSAsias He }
232