Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


add VNET bridge for Linux Host
[palacios-OLD.git] / palacios / src / devices / lnx_vnet_brg.c
1 /* 
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2010, Lei Xia <lxia@cs.northwestern.edu>
11  * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Lei Xia <lxia@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19  
20  /* VNET backend bridge for Linux host
21  */
22 #include <palacios/vmm.h>
23 #include <palacios/vmm_dev_mgr.h>
24 #include <palacios/vm_guest_mem.h>
25 #include <palacios/vmm_vnet.h>
26 #include <palacios/vmm_sprintf.h>
27 #include <palacios/vmm_socket.h>
28
29 #ifndef CONFIG_DEBUG_VNET_LNX_BRIGE
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34 typedef enum {SOCK_UDP, SOCK_TCP, SOCK_OTHER} sock_type_t; 
35
36 const uint16_t vnet_udp_port = 20003;
37
38 struct vnet_link {
39     uint32_t dst_ip;
40     uint16_t dst_port;
41     
42     int socket;
43     sock_type_t type;
44     int link_idx;
45
46     struct list_head node;
47 };
48
49 struct vnet_brg_state {
50     uint32_t num_links; 
51
52     struct list_head link_list;
53
54     int serv_sock;
55     sock_type_t serv_sock_type;
56     int serv_port;
57     
58     /* The thread recving pkts from sockets. */
59     int serv_thread;
60
61     v3_lock_t lock;
62
63     unsigned long pkt_sent, pkt_recv, pkt_drop;
64 };
65
66 static struct vnet_brg_state lnxbrg_state;
67
68 static int vnet_lnxbrg_reset(struct vnet_brg_state * state) {
69     memset(state, 0, sizeof(struct vnet_brg_state));
70
71     state->num_links = 0;
72     state->serv_sock = -1;
73     state->serv_port = vnet_udp_port;
74     state->serv_sock_type = SOCK_UDP;
75
76     if(v3_lock_init(&(state->lock)) < 0){
77         PrintError("VNET Linux Bridge: error to initiate vnet lock\n");
78     }
79
80     return 0;
81 }
82
83
84 struct vnet_link * link_by_ip(struct vnet_brg_state * state, uint32_t ip) {
85     struct vnet_link * link = NULL;
86
87     list_for_each_entry(link, &(state->link_list), node) {
88         if (link->dst_ip == ip) {
89             return link;
90         }
91     }
92
93     return NULL;
94 }
95
96 struct vnet_link * link_by_idx(struct vnet_brg_state * state, int idx) {
97     struct vnet_link * link = NULL;
98
99     list_for_each_entry(link, &(state->link_list), node) {
100         if (link->link_idx == idx) {
101             return link;
102         }
103     }
104     return NULL;
105 }
106
107 static int
108 udp_send(int sockid, uint32_t dst_ip, 
109                         uint16_t dst_port, uchar_t * pkt, 
110                         uint16_t len){
111     if(dst_ip > 0 && dst_port > 0){
112         return V3_SendTo_IP(sockid, dst_ip, dst_port, pkt, len);
113     }
114
115     return V3_Send(sockid, pkt, len);
116 }
117
118
119 static int 
120 udp_recv(int sockid, uint32_t * src_ip, 
121                         uint16_t * src_port, uchar_t *buf, 
122                         uint16_t len) {
123
124     return V3_Recv(sockid, buf, len);
125 }
126
127
128
129 static int 
130 brg_send(struct vnet_brg_state * state,
131                         struct v3_vm_info * vm,  
132                         struct v3_vnet_pkt * vnet_pkt, 
133                         void * private_data){
134     struct vnet_link * link = NULL;
135         
136     #ifdef CONFIG_DEBUG_VNET_LNX_BRIGE
137     {
138         PrintDebug("vnet_brg_send... pkt size: %d, link: %d, struct len: %d\n",
139                         vnet_pkt->size,
140                         vnet_pkt->dst_id,
141                         sizeof(struct v3_vnet_pkt));
142     }
143     #endif
144
145     state->pkt_recv ++;
146     link = link_by_idx(vnet_pkt->dst_id);
147     if (link != NULL) {
148         if(link->type == SOCK_TCP){
149                 
150         }else if(link->type == SOCK_UDP){
151             udp_send(link->socket, 0, 0, vnet_pkt->data, vnet_pkt->size);
152             state->pkt_sent ++;
153         }else {
154             PrintError("VNET Linux Bridge: wrong link type\n"); 
155             return -1;
156         }
157     } else {
158         PrintDebug("VNET Linux Bridge: wrong dst link, idx: %d, discards the packet\n", vnet_pkt->dst_id);
159         state->pkt_drop ++;
160     }
161
162     return 0;
163 }
164
165
166 static int init_serv(struct vnet_brg_state * state) {
167     int sock, err;
168
169     if(state->serv_sock_type == SOCK_UDP){
170         sock = V3_Create_UDP_Socket();
171         if (sock < 0) {
172             PrintError("Could not create socket, Initiate VNET server error\n");
173             return -1;
174         }
175
176         err = V3_Bind_Socket(sock, state->serv_port);
177         if(err < 0){
178             PrintError("Error to bind VNET Linux bridge receiving UDP socket\n");
179             return -1;
180         }
181         state->serv_sock = sock;
182     }
183
184     return 0;
185 }
186
187 static int vnet_server(void * arg) {
188     struct v3_vnet_pkt pkt;
189     struct vnet_link *link;
190     struct vnet_brg_state * state = (struct vnet_brg_state *)arg;
191     uchar_t buf[ETHERNET_MTU];
192     uint32_t ip = 0;
193     uint16_t port = 0;
194     int len;
195
196     while (1) {
197         len = udp_recv(state->serv_sock, &ip, &port, buf, ETHERNET_MTU);
198         if(len < 0) {
199             PrintError("VNET Linux Bridge: receive error\n");
200             continue;
201         }
202
203         link = link_by_ip(ip);
204         if (link != NULL) {
205             pkt.src_id= link->link_idx;
206         }
207         else { 
208             pkt.src_id= -1;
209         }
210
211         pkt.size = len;
212         pkt.src_type = LINK_EDGE;
213         memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
214         pkt.data = buf;
215         
216         #ifdef CONFIG_DEBUG_VNET_LNX_BRIGE
217         {
218             PrintDebug("VNET Linux Bridge: recv pkt size: %d, pkt src_id: %d\n", 
219                         len,  pkt.src_id);
220             v3_hexdump(buf, len, NULL, 0);
221         }
222         #endif
223
224         v3_vnet_send_pkt(&pkt, NULL);
225         
226         state->pkt_recv ++;
227     }
228
229     return 0;
230 }
231
232
233 static int vnet_lnxbrg_init() {
234     struct v3_vnet_bridge_ops brg_ops;
235     struct vnet_brg_state * state;
236         
237     state = (struct vnet_brg_state *)V3_Malloc(sizeof(struct vnet_brg_state));
238     V3_ASSERT(state != NULL);
239
240     vnet_lnxbrg_reset(state);
241
242     brg_ops.input = brg_send;
243
244     v3_vnet_add_bridge(NULL, &brg_ops, state);
245
246     init_serv();
247     V3_CREATE_THREAD(vnet_server, state, "VNET_LNX_BRIDGE");
248
249     PrintDebug("VNET Linux Bridge initiated\n");
250
251     return 0;
252 }
253
254
255 device_register("LNX_VNET_BRIDGE", vnet_lnxbrg_init)