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