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