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 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; 17*d3476f7dSSasha 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 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 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 */ 145dd7a270bSAsias He buf->vnet_len = sizeof(struct virtio_net_hdr); 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 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; 167d9da915bSAsias He 168d9da915bSAsias He do { 169d9da915bSAsias He payload = malloc(UIP_MAX_UDP_PAYLOAD); 170d9da915bSAsias He } while (!payload); 171d9da915bSAsias He 172d9da915bSAsias He while (1) { 173d9da915bSAsias He nfds = epoll_wait(info->udp_epollfd, events, UIP_UDP_MAX_EVENTS, -1); 174d9da915bSAsias He 175d9da915bSAsias He if (nfds == -1) 176d9da915bSAsias He continue; 177d9da915bSAsias He 178d9da915bSAsias He for (i = 0; i < nfds; i++) { 179d9da915bSAsias He 180d9da915bSAsias He sk = events[i].data.ptr; 181d9da915bSAsias He payload_len = recvfrom(sk->fd, payload, UIP_MAX_UDP_PAYLOAD, 0, NULL, NULL); 182d9da915bSAsias He if (payload_len < 0) 183d9da915bSAsias He continue; 184d9da915bSAsias He 185d9da915bSAsias He /* 186d9da915bSAsias He * Get free buffer to send data to guest 187d9da915bSAsias He */ 188d9da915bSAsias He buf = uip_buf_get_free(info); 189d9da915bSAsias He 190d9da915bSAsias He uip_udp_make_pkg(info, sk, buf, payload, payload_len); 191d9da915bSAsias He 192dd7a270bSAsias He /* 193dd7a270bSAsias He * Send data received from socket to guest 194dd7a270bSAsias He */ 195dd7a270bSAsias He uip_buf_set_used(info, buf); 196dd7a270bSAsias He } 197dd7a270bSAsias He } 198dd7a270bSAsias He 199dd7a270bSAsias He free(payload); 200dd7a270bSAsias He pthread_exit(NULL); 201dd7a270bSAsias He return NULL; 202dd7a270bSAsias He } 203dd7a270bSAsias He 204dd7a270bSAsias He int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg) 205dd7a270bSAsias He { 206dd7a270bSAsias He struct uip_udp_socket *sk; 207dd7a270bSAsias He struct uip_info *info; 208dd7a270bSAsias He struct uip_udp *udp; 209dd7a270bSAsias He struct uip_ip *ip; 210dd7a270bSAsias He int ret; 211dd7a270bSAsias He 212dd7a270bSAsias He udp = (struct uip_udp *)(arg->eth); 213dd7a270bSAsias He ip = (struct uip_ip *)(arg->eth); 214dd7a270bSAsias He info = arg->info; 215dd7a270bSAsias He 21641b13f6aSAsias He if (uip_udp_is_dhcp(udp)) { 21741b13f6aSAsias He uip_tx_do_ipv4_udp_dhcp(arg); 21841b13f6aSAsias He return 0; 21941b13f6aSAsias He } 22041b13f6aSAsias He 221dd7a270bSAsias He /* 222dd7a270bSAsias He * Find socket we have allocated before, otherwise allocate one 223dd7a270bSAsias He */ 224dd7a270bSAsias He sk = uip_udp_socket_find(arg, ip->sip, ip->dip, udp->sport, udp->dport); 225dd7a270bSAsias He if (!sk) 226dd7a270bSAsias He return -1; 227dd7a270bSAsias He 228dd7a270bSAsias He /* 229dd7a270bSAsias He * Send out UDP data to remote host 230dd7a270bSAsias He */ 231dd7a270bSAsias He ret = uip_udp_socket_send(sk, udp); 232dd7a270bSAsias He if (ret) 233dd7a270bSAsias He return -1; 234dd7a270bSAsias He 235dd7a270bSAsias He if (!info->udp_thread) 236dd7a270bSAsias He pthread_create(&info->udp_thread, NULL, uip_udp_socket_thread, (void *)info); 237dd7a270bSAsias He 238dd7a270bSAsias He return 0; 239dd7a270bSAsias He } 240