#include <linux/sched.h>
#include <asm/msr.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+
#include <vnet/vnet.h>
#include <vnet/vnet_hashtable.h>
#include "palacios-vnet.h"
#include "palacios.h"
+
+
#define VNET_SERVER_PORT 9000
+#define VNET_ADAPTIVE_BRIDGE 1 // set this to one to have bridge go to sleep if there nothing to do...
+#define VNET_NOPROGRESS_LIMIT 1000 // ... after this many iterations
+#define VNET_YIELD_TIME_USEC 1000 // ... and go to sleep for this long
+
struct vnet_link {
uint32_t dst_ip;
uint16_t dst_port;
static void _delete_link(struct vnet_link * link){
- unsigned long flags;
+ unsigned long flags = 0;
link->sock->ops->release(link->sock);
- spin_lock_irqsave(&(vnet_brg_s.lock), flags);
+ palacios_spinlock_lock_irqsave(&(vnet_brg_s.lock), flags);
list_del(&(link->node));
vnet_htable_remove(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), 0);
vnet_brg_s.num_links --;
- spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(vnet_brg_s.lock), flags);
INFO("VNET Bridge: Link deleted, ip 0x%x, port: %d, idx: %d\n",
link->dst_ip,
link->dst_port,
link->idx);
- kfree(link);
+ palacios_free(link);
link = NULL;
}
}
static void deinit_links_list(void){
- struct vnet_link * link, * tmp_link;
+ struct vnet_link * link = NULL, * tmp_link = NULL;
list_for_each_entry_safe(link, tmp_link, &(vnet_brg_s.link_list), node) {
_delete_link(link);
return -1;
}
+ if (link->sock_proto == UDP) {
+ // no UDP checksumming
+ lock_sock(link->sock->sk);
+ link->sock->sk->sk_no_check = 1;
+ release_sock(link->sock->sk);
+ }
+
memset(&link->sock_addr, 0, sizeof(struct sockaddr));
link->sock_addr.sin_family = AF_INET;
link->sock_addr.sin_addr.s_addr = link->dst_ip;
link->sock_addr.sin_port = htons(link->dst_port);
- if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0) < 0)) {
+
+ if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0)) < 0) {
WARNING("Could not connect to remote VNET Server, error %d\n", err);
return -1;
}
- spin_lock_irqsave(&(vnet_brg_s.lock), flags);
+
+ palacios_spinlock_lock_irqsave(&(vnet_brg_s.lock), flags);
list_add(&(link->node), &(vnet_brg_s.link_list));
vnet_brg_s.num_links ++;
link->idx = ++ vnet_brg_s.link_idx;
vnet_htable_insert(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), (addr_t)link);
- spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(vnet_brg_s.lock), flags);
INFO("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n",
link->dst_ip,
struct vnet_link * new_link = NULL;
uint32_t idx;
- new_link = kmalloc(sizeof(struct vnet_link), GFP_KERNEL);
+ new_link = palacios_alloc(sizeof(struct vnet_link));
if (!new_link) {
return -1;
}
idx = _create_link(new_link);
if (idx < 0) {
WARNING("Could not create link\n");
- kfree(new_link);
+ palacios_free(new_link);
return -1;
}
iov.iov_base = buf;
iov.iov_len = len;
- msg.msg_flags = 0;
+ msg.msg_flags = MSG_NOSIGNAL;
msg.msg_name = addr;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
static int
_udp_recv(struct socket * sock,
- struct sockaddr_in * addr,
- unsigned char * buf, int len) {
+ struct sockaddr_in * addr,
+ unsigned char * buf, int len, int nonblocking) {
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
iov.iov_base = buf;
iov.iov_len = len;
- msg.msg_flags = 0;
+ msg.msg_flags = MSG_NOSIGNAL | (nonblocking ? MSG_DONTWAIT : 0);
msg.msg_name = addr;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
int len,
int link_id){
struct v3_vnet_pkt pkt;
+ memset(&pkt,0,sizeof(struct v3_vnet_pkt));
pkt.size = len;
+ pkt.dst_type = LINK_NOSET;
pkt.src_type = LINK_EDGE;
pkt.src_id = link_id;
memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
bridge_send_pkt(struct v3_vm_info * vm,
struct v3_vnet_pkt * pkt,
void * private_data) {
- struct vnet_link * link;
+ struct vnet_link * link = NULL;
if(net_debug >= 2){
DEBUG("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n",
link->stats.tx_bytes += pkt->size;
link->stats.tx_pkts ++;
} else {
- INFO("VNET Bridge Linux Host: wrong dst link, idx: %d, discards the packet\n", pkt->dst_id);
+ INFO("VNET Bridge Linux Host: wrong dst link, idx: %d, discarding the packet\n", pkt->dst_id);
vnet_brg_s.stats.pkt_drop_vmm ++;
}
return -1;
}
+ if (vnet_brg_s.serv_proto == UDP) {
+ // No UDP checksumming is done
+ lock_sock(vnet_brg_s.serv_sock->sk);
+ vnet_brg_s.serv_sock->sk->sk_no_check = 1;
+ release_sock(vnet_brg_s.serv_sock->sk);
+ }
+
memset(&vnet_brg_s.serv_addr, 0, sizeof(struct sockaddr));
vnet_brg_s.serv_addr.sin_family = AF_INET;
}
}
+
+
return 0;
}
struct sockaddr_in pkt_addr;
struct vnet_link * link = NULL;
int len;
+ uint64_t noprogress_count;
INFO("Palacios VNET Bridge: UDP receiving server ..... \n");
- pkt = kmalloc(MAX_PACKET_LEN, GFP_KERNEL);
+ pkt = palacios_alloc(MAX_PACKET_LEN);
+
+ if (!pkt) {
+ ERROR("Unable to allocate packet in VNET UDP Server\n");
+ return -1;
+ }
+
+
+ noprogress_count=0;
+
while (!kthread_should_stop()) {
+
+ // This is a NONBLOCKING receive
+ // If we block here, we will never detect that this thread
+ // is being signaled to stop, plus we might go uninterrupted on this core
+ // blocking out access to other threads - leave this NONBLOCKING
+ // unless you know what you are doing
+ len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN, 1);
+
+
+ // If it would have blocked, we have no packet, and so
+ // we will give other threads on this core a chance
+ if (len==-EAGAIN || len==-EWOULDBLOCK || len==-EINTR) {
+
+ // avoid rollover in the counter out of paranoia
+ if (! ((noprogress_count + 1) < noprogress_count)) {
+ noprogress_count++;
+ }
+
+ // adaptively select yielding strategy depending on
+ // whether we are making progress
+ if ((!VNET_ADAPTIVE_BRIDGE) || (noprogress_count < VNET_NOPROGRESS_LIMIT)) {
+ // Likely making progress, do fast yield so we
+ // come back immediately if there is no other action
+ palacios_yield_cpu();
+ } else {
+ // Likely not making progress, do potentially slow
+ // yield - we won't come back for until VNET_YIELD_TIME_USEC has passed
+ palacios_sleep_cpu(VNET_YIELD_TIME_USEC);
+ }
+
+ continue;
+ }
- len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN);
+
+ // Something interesting has happened, therefore progress!
+ noprogress_count=0;
+
+
if(len < 0) {
WARNING("Receive error: Could not get packet, error %d\n", len);
continue;
}
link = _link_by_ip(pkt_addr.sin_addr.s_addr);
+
if (link == NULL){
- WARNING("VNET Server: No VNET Link match the src IP\n");
+ WARNING("VNET Server: No VNET Link matches the src IP\n");
vnet_brg_s.stats.pkt_drop_phy ++;
continue;
}
send_to_palacios(pkt, len, link->idx);
}
- kfree(pkt);
+ INFO("VNET Server: UDP thread exiting\n");
+
+ palacios_free(pkt);
return 0;
}
//accept new connection
//use select to receive pkt from physical network
//or create new kthread to handle each connection?
+ WARNING("VNET Server: TCP is not currently supported\n");
+ return -1;
}else {
WARNING ("VNET Server: Unsupported Protocol\n");
return -1;
memset(&vnet_brg_s, 0, sizeof(struct vnet_brg_state));
INIT_LIST_HEAD(&(vnet_brg_s.link_list));
- spin_lock_init(&(vnet_brg_s.lock));
+ palacios_spinlock_init(&(vnet_brg_s.lock));
vnet_brg_s.serv_proto = UDP;
void vnet_bridge_deinit(void){
+ INFO("VNET LNX Bridge Deinit Started\n");
+
v3_vnet_del_bridge(HOST_LNX_BRIDGE);
+ //DEBUG("Stopping bridge service thread\n");
+
kthread_stop(vnet_brg_s.serv_thread);
+
+ //DEBUG("Releasing bridee service socket\n");
+
vnet_brg_s.serv_sock->ops->release(vnet_brg_s.serv_sock);
+ //DEBUG("Deiniting bridge links\n");
+
deinit_links_list();
+ //DEBUG("Freeing bridge hash tables\n");
+
vnet_free_htable(vnet_brg_s.ip2link, 0, 0);
vnet_brg_s.status = 0;
+
+ palacios_spinlock_deinit(&(vnet_brg_s.lock));
+
+ INFO("VNET LNX Bridge Deinit Finished\n");
}