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.


c4f727217913690d35c1cdb834ab71a8315c4ed1
[palacios.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
45     int link_idx;
46
47     struct list_head node;
48 };
49
50 struct vnet_brg_state {
51     uint32_t num_links; 
52     struct list_head link_list;
53
54     int serv_sock;
55     sock_type_t serv_sock_type;
56     int serv_port;
57
58     v3_lock_t lock;
59
60     unsigned long pkt_sent, pkt_recv, pkt_drop;
61 };
62
63
64 static int vnet_lnxbrg_reset(struct vnet_brg_state * state) {
65     memset(state, 0, sizeof(struct vnet_brg_state));
66
67     state->num_links = 0;
68     state->serv_sock = -1;
69     state->serv_port = vnet_udp_port;
70     state->serv_sock_type = SOCK_UDP;
71
72     if(v3_lock_init(&(state->lock)) < 0){
73         PrintError("VNET Linux Bridge: error to initiate vnet lock\n");
74     }
75
76     return 0;
77 }
78
79
80 struct vnet_link * link_by_ip(struct vnet_brg_state * state, uint32_t ip) {
81     struct vnet_link * link = NULL;
82
83     list_for_each_entry(link, &(state->link_list), node) {
84         if (link->dst_ip == ip) {
85             return link;
86         }
87     }
88
89     return NULL;
90 }
91
92 struct vnet_link * link_by_idx(struct vnet_brg_state * state, int idx) {
93     struct vnet_link * link = NULL;
94
95     list_for_each_entry(link, &(state->link_list), node) {
96         if (link->link_idx == idx) {
97             return link;
98         }
99     }
100     return NULL;
101 }
102
103 static int
104 udp_send(int sockid, uint32_t dst_ip, 
105                         uint16_t dst_port, uchar_t * pkt, 
106                         uint16_t len){
107     if(dst_ip > 0 && dst_port > 0){
108         return V3_SendTo_IP(sockid, dst_ip, dst_port, pkt, len);
109     }
110
111     return V3_Send(sockid, pkt, len);
112 }
113
114
115 static int 
116 udp_recv(int sockid, uint32_t * src_ip, 
117                         uint16_t * src_port, uchar_t *buf, 
118                         uint16_t len) {
119
120     return V3_Recv(sockid, buf, len);
121 }
122
123
124
125 static int 
126 brg_send(       struct v3_vm_info * vm,  
127                         struct v3_vnet_pkt * vnet_pkt, 
128                         void * private_data){
129     struct vnet_brg_state * state = (struct vnet_brg_state *)private_data;
130     struct vnet_link * link = NULL;
131         
132     #ifdef CONFIG_DEBUG_VNET_LNX_BRIGE
133     {
134         PrintDebug("vnet_brg_send... pkt size: %d, link: %d, struct len: %d\n",
135                         vnet_pkt->size,
136                         vnet_pkt->dst_id,
137                         sizeof(struct v3_vnet_pkt));
138     }
139     #endif
140
141     state->pkt_recv ++;
142     link = link_by_idx(state, vnet_pkt->dst_id);
143     if (link != NULL) {
144         if(link->type == SOCK_UDP){
145             udp_send(link->socket, 0, 0, vnet_pkt->data, vnet_pkt->size);
146             state->pkt_sent ++;
147         }else {
148             PrintError("VNET Linux Bridge: wrong link type\n"); 
149             return -1;
150         }
151     } else {
152         PrintDebug("VNET Linux Bridge: wrong dst link, idx: %d, discards the packet\n", vnet_pkt->dst_id);
153         state->pkt_drop ++;
154     }
155
156     return 0;
157 }
158
159
160 static int init_serv(struct vnet_brg_state * state) {
161     int sock, err;
162
163     if(state->serv_sock_type == SOCK_UDP){
164         sock = V3_Create_UDP_Socket();
165         if (sock < 0) {
166             PrintError("Could not create socket, Initiate VNET server error\n");
167             return -1;
168         }
169
170         err = V3_Bind_Socket(sock, state->serv_port);
171         if(err < 0){
172             PrintError("Error to bind VNET Linux bridge receiving UDP socket\n");
173             return -1;
174         }
175         state->serv_sock = sock;
176     }
177
178     return 0;
179 }
180
181 static int vnet_server(void * arg) {
182     struct v3_vnet_pkt pkt;
183     struct vnet_link *link;
184     struct vnet_brg_state * state = (struct vnet_brg_state *)arg;
185     uchar_t buf[ETHERNET_MTU];
186     uint32_t ip = 0;
187     uint16_t port = 0;
188     int len;
189
190     while (1) {
191         len = udp_recv(state->serv_sock, &ip, &port, buf, ETHERNET_MTU);
192         if(len < 0) {
193             PrintError("VNET Linux Bridge: receive error\n");
194             continue;
195         }
196
197         link = link_by_ip(state, ip);
198         if (link != NULL) {
199             pkt.src_id= link->link_idx;
200         }
201         else { 
202             pkt.src_id= -1;
203         }
204
205         pkt.size = len;
206         pkt.src_type = LINK_EDGE;
207         memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
208         pkt.data = buf;
209         
210         #ifdef CONFIG_DEBUG_VNET_LNX_BRIGE
211         {
212             PrintDebug("VNET Linux Bridge: recv pkt size: %d, pkt src_id: %d\n", 
213                         len,  pkt.src_id);
214             v3_hexdump(buf, len, NULL, 0);
215         }
216         #endif
217
218         v3_vnet_send_pkt(&pkt, NULL);
219         
220         state->pkt_recv ++;
221     }
222
223     return 0;
224 }
225
226
227 static int vnet_lnxbrg_init() {
228     struct v3_vnet_bridge_ops brg_ops;
229     struct vnet_brg_state * state;
230         
231     state = (struct vnet_brg_state *)V3_Malloc(sizeof(struct vnet_brg_state));
232     V3_ASSERT(state != NULL);
233
234     vnet_lnxbrg_reset(state);
235
236     brg_ops.input = brg_send;
237
238     v3_vnet_add_bridge(NULL, &brg_ops, state);
239
240     init_serv(state);
241     V3_CREATE_THREAD(vnet_server, state, "VNET_LNX_BRIDGE");
242
243     PrintDebug("VNET Linux Bridge initiated\n");
244
245     return 0;
246 }
247
248
249 device_register("LNX_VNET_BRIDGE", vnet_lnxbrg_init)