2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2011, Lei Xia <lxia@northwestern.edu>
11 * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * This is free software. You are permitted to use, redistribute,
15 * and modify it under the terms of the GNU General Public License
16 * Version 2 (GPLv2). The accompanying COPYING file contains the
17 * full text of the license.
19 /* Palacios VNET Host Bridge */
21 #include <linux/spinlock.h>
22 #include <linux/seq_file.h>
23 #include <linux/proc_fs.h>
24 #include <asm/uaccess.h>
25 #include <linux/inet.h>
26 #include <linux/kthread.h>
28 #include <linux/netdevice.h>
31 #include <linux/net.h>
32 #include <linux/string.h>
33 #include <linux/preempt.h>
34 #include <linux/sched.h>
37 #include <vnet/vnet.h>
38 #include <vnet/vnet_hashtable.h>
39 #include "palacios-vnet.h"
41 #define VNET_SERVER_PORT 9000
48 struct sockaddr_in sock_addr;
49 vnet_brg_proto_t sock_proto;
51 struct nic_statistics stats;
55 struct list_head node;
59 struct vnet_brg_state {
64 struct list_head link_list;
65 struct hashtable *ip2link;
69 struct socket * serv_sock;
70 struct sockaddr_in serv_addr;
71 vnet_brg_proto_t serv_proto;
73 struct task_struct * serv_thread;
75 void * brg_data; /* private data from vnet_core */
77 struct vnet_brg_stats stats;
81 static struct vnet_brg_state vnet_brg_s;
84 int vnet_brg_stats(struct vnet_brg_stats * stats){
85 memcpy(stats, &(vnet_brg_s.stats), sizeof(*stats));
90 static inline struct vnet_link * _link_by_ip(uint32_t ip) {
91 return (struct vnet_link *)vnet_htable_search(vnet_brg_s.ip2link, (addr_t)&ip);
94 static inline struct vnet_link * _link_by_idx(int idx) {
95 struct vnet_link * link = NULL;
97 list_for_each_entry(link, &(vnet_brg_s.link_list), node) {
99 if (link->idx == idx) {
107 static void _delete_link(struct vnet_link * link){
110 link->sock->ops->release(link->sock);
112 spin_lock_irqsave(&(vnet_brg_s.lock), flags);
113 list_del(&(link->node));
114 vnet_htable_remove(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), 0);
115 vnet_brg_s.num_links --;
116 spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
118 printk("VNET Bridge: Link deleted, ip 0x%x, port: %d, idx: %d\n",
127 void vnet_brg_delete_link(uint32_t idx){
128 struct vnet_link * link = _link_by_idx(idx);
135 static void deinit_links_list(void){
136 struct vnet_link * link;
138 list_for_each_entry(link, &(vnet_brg_s.link_list), node) {
143 static uint32_t _create_link(struct vnet_link * link) {
148 switch(link->sock_proto){
150 protocol = IPPROTO_UDP;
153 protocol = IPPROTO_TCP;
157 printk("Unsupported VNET Server Protocol\n");
161 if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &link->sock)) < 0) {
162 printk("Could not create socket for VNET Link, error %d\n", err);
166 memset(&link->sock_addr, 0, sizeof(struct sockaddr));
168 link->sock_addr.sin_family = AF_INET;
169 link->sock_addr.sin_addr.s_addr = link->dst_ip;
170 link->sock_addr.sin_port = htons(link->dst_port);
172 if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0) < 0)) {
173 printk("Could not connect to remote VNET Server, error %d\n", err);
177 spin_lock_irqsave(&(vnet_brg_s.lock), flags);
178 list_add(&(link->node), &(vnet_brg_s.link_list));
179 vnet_brg_s.num_links ++;
180 link->idx = ++ vnet_brg_s.link_idx;
181 vnet_htable_insert(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), (addr_t)link);
182 spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
184 printk("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n",
189 ((link->sock_proto==UDP)?"UDP":"TCP"));
195 uint32_t vnet_brg_add_link(uint32_t ip, uint16_t port, vnet_brg_proto_t proto){
196 struct vnet_link * new_link = NULL;
199 new_link = kmalloc(sizeof(struct vnet_link), GFP_KERNEL);
203 memset(new_link, 0, sizeof(struct vnet_link));
205 new_link->dst_ip = ip;
206 new_link->dst_port = port;
207 new_link->sock_proto = proto;
209 idx = _create_link(new_link);
211 printk("Could not create link\n");
220 int vnet_brg_link_stats(uint32_t link_idx, struct nic_statistics * stats){
221 struct vnet_link * link;
223 link = _link_by_idx(link_idx);
228 memcpy(stats, &(link->stats), sizeof(*stats));
235 _udp_send(struct socket * sock,
236 struct sockaddr_in * addr,
237 unsigned char * buf, int len) {
244 if (sock->sk == NULL) {
253 msg.msg_namelen = sizeof(struct sockaddr_in);
254 msg.msg_control = NULL;
255 msg.msg_controllen = 0;
258 msg.msg_control = NULL;
262 size = sock_sendmsg(sock, &msg, len);
271 _udp_recv(struct socket * sock,
272 struct sockaddr_in * addr,
273 unsigned char * buf, int len) {
279 if (sock->sk == NULL) {
288 msg.msg_namelen = sizeof(struct sockaddr_in);
289 msg.msg_control = NULL;
290 msg.msg_controllen = 0;
293 msg.msg_control = NULL;
297 size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
304 /* send packets to VNET core */
306 send_to_palacios(unsigned char * buf,
309 struct v3_vnet_pkt pkt;
311 pkt.src_type = LINK_EDGE;
312 pkt.src_id = link_id;
313 memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
317 printk("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n",
318 pkt.size, pkt.src_id, pkt.src_type);
320 print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt.data, pkt.size, 0);
324 vnet_brg_s.stats.pkt_to_vmm ++;
326 return v3_vnet_send_pkt(&pkt, NULL, 1);
330 /* send packet to extern network */
332 bridge_send_pkt(struct v3_vm_info * vm,
333 struct v3_vnet_pkt * pkt,
334 void * private_data) {
335 struct vnet_link * link;
338 printk("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n",
342 print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt->data, pkt->size, 0);
346 vnet_brg_s.stats.pkt_from_vmm ++;
348 link = _link_by_idx(pkt->dst_id);
350 switch(link->sock_proto){
352 _udp_send(link->sock, &(link->sock_addr), pkt->data, pkt->size);
353 vnet_brg_s.stats.pkt_to_phy ++;
356 vnet_brg_s.stats.pkt_to_phy ++;
360 printk("VNET Server: Invalid Link Protocol\n");
361 vnet_brg_s.stats.pkt_drop_vmm ++;
363 link->stats.tx_bytes += pkt->size;
364 link->stats.tx_pkts ++;
366 printk("VNET Bridge Linux Host: wrong dst link, idx: %d, discards the packet\n", pkt->dst_id);
367 vnet_brg_s.stats.pkt_drop_vmm ++;
374 static int init_vnet_serv(void) {
378 switch(vnet_brg_s.serv_proto){
380 protocol = IPPROTO_UDP;
383 protocol = IPPROTO_TCP;
387 printk("Unsupported VNET Server Protocol\n");
391 if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &vnet_brg_s.serv_sock)) < 0) {
392 printk("Could not create VNET server socket, error: %d\n", err);
396 memset(&vnet_brg_s.serv_addr, 0, sizeof(struct sockaddr));
398 vnet_brg_s.serv_addr.sin_family = AF_INET;
399 vnet_brg_s.serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
400 vnet_brg_s.serv_addr.sin_port = htons(VNET_SERVER_PORT);
402 if ((err = vnet_brg_s.serv_sock->ops->bind(vnet_brg_s.serv_sock, (struct sockaddr *)&(vnet_brg_s.serv_addr), sizeof(struct sockaddr))) < 0) {
403 printk("Could not bind VNET server socket to port %d, error: %d\n", VNET_SERVER_PORT, err);
407 printk("VNET server bind to port: %d\n", VNET_SERVER_PORT);
409 if(vnet_brg_s.serv_proto == TCP){
410 if((err = vnet_brg_s.serv_sock->ops->listen(vnet_brg_s.serv_sock, 32)) < 0){
411 printk("VNET Server error listening on port %d, error %d\n", VNET_SERVER_PORT, err);
419 static int _udp_server(void * arg) {
421 struct sockaddr_in pkt_addr;
422 struct vnet_link * link = NULL;
425 printk("Palacios VNET Bridge: UDP receiving server ..... \n");
427 pkt = kmalloc(MAX_PACKET_LEN, GFP_KERNEL);
428 while (!kthread_should_stop()) {
430 len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN);
432 printk("Receive error: Could not get packet, error %d\n", len);
436 link = _link_by_ip(pkt_addr.sin_addr.s_addr);
438 printk("VNET Server: No VNET Link match the src IP\n");
439 vnet_brg_s.stats.pkt_drop_phy ++;
443 vnet_brg_s.stats.pkt_from_phy ++;
444 link->stats.rx_bytes += len;
445 link->stats.rx_pkts ++;
447 send_to_palacios(pkt, len, link->idx);
456 static int _rx_server(void * arg) {
458 if(vnet_brg_s.serv_proto == UDP){
460 }else if(vnet_brg_s.serv_proto == TCP) {
461 //accept new connection
462 //use select to receive pkt from physical network
463 //or create new kthread to handle each connection?
465 printk ("VNET Server: Unsupported Protocol\n");
472 static inline unsigned int hash_fn(addr_t hdr_ptr) {
473 return vnet_hash_buffer((uint8_t *)hdr_ptr, sizeof(uint32_t));
476 static inline int hash_eq(addr_t key1, addr_t key2) {
477 return (memcmp((uint8_t *)key1, (uint8_t *)key2, sizeof(uint32_t)) == 0);
481 int vnet_bridge_init(void) {
482 struct v3_vnet_bridge_ops bridge_ops;
484 if(vnet_brg_s.status != 0) {
487 vnet_brg_s.status = 1;
489 memset(&vnet_brg_s, 0, sizeof(struct vnet_brg_state));
491 INIT_LIST_HEAD(&(vnet_brg_s.link_list));
492 spin_lock_init(&(vnet_brg_s.lock));
494 vnet_brg_s.serv_proto = UDP;
496 vnet_brg_s.ip2link = vnet_create_htable(10, hash_fn, hash_eq);
497 if(vnet_brg_s.ip2link == NULL){
498 printk("Failure to initiate VNET link hashtable\n");
502 if(init_vnet_serv() < 0){
503 printk("Failure to initiate VNET server\n");
507 vnet_brg_s.serv_thread = kthread_run(_rx_server, NULL, "vnet-server");
509 bridge_ops.input = bridge_send_pkt;
510 bridge_ops.poll = NULL;
512 if( v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL) < 0){
513 printk("VNET LNX Bridge: Fails to register bridge to VNET core");
516 printk("VNET Linux Bridge initiated\n");
522 void vnet_bridge_deinit(void){
524 v3_vnet_del_bridge(HOST_LNX_BRIDGE);
526 kthread_stop(vnet_brg_s.serv_thread);
527 vnet_brg_s.serv_sock->ops->release(vnet_brg_s.serv_sock);
531 vnet_free_htable(vnet_brg_s.ip2link, 0, 0);
533 vnet_brg_s.status = 0;