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 v3vee copyright info
[palacios.git] / linux_module / iface-packet.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) 2011, Lei Xia <lxia@northwestern.edu>
11  * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
12  * All rights reserved.
13  *
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.
18  */
19 /* 
20  * Palacios Raw Packet Interface Implementation
21  */
22 #include <asm/uaccess.h>
23 #include <linux/inet.h>
24 #include <linux/kthread.h>
25 #include <linux/netdevice.h>
26 #include <linux/ip.h>
27 #include <linux/in.h>
28 #include <linux/string.h>
29 #include <linux/preempt.h>
30 #include <linux/sched.h>
31 #include <linux/if_packet.h>
32 #include <linux/errno.h>
33 #include <asm/msr.h>
34  
35 #include <interfaces/vmm_packet.h>
36 #include <palacios/vmm_host_events.h>
37 #include <vnet/vnet.h>
38
39
40 #define __V3VEE__
41 #include <palacios/vmm_hashtable.h>
42 #include <palacios/vmm_ethernet.h>
43 #undef __V3VEE__
44
45 #include "palacios.h"
46 #include "linux-exts.h"
47
48 struct palacios_packet_state {
49     struct socket * raw_sock;
50     uint8_t inited;
51         
52     struct hashtable * mac_vm_cache;
53     struct task_struct * server_thread;
54 };
55
56 static struct palacios_packet_state packet_state;
57
58 static inline uint_t hash_fn(addr_t hdr_ptr) {    
59     uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
60
61     return v3_hash_buffer(hdr_buf, ETH_ALEN);
62 }
63
64 static inline int hash_eq(addr_t key1, addr_t key2) {   
65     return (memcmp((uint8_t *)key1, (uint8_t *)key2, ETH_ALEN) == 0);
66 }
67
68
69 static int palacios_packet_add_recver(const char * mac, 
70                                         struct v3_vm_info * vm){
71     char * key;
72
73     key = (char *)kmalloc(ETH_ALEN, GFP_KERNEL);                                        
74     memcpy(key, mac, ETH_ALEN);    
75
76     if (v3_htable_insert(packet_state.mac_vm_cache, (addr_t)key, (addr_t)vm) == 0) {
77         printk("Palacios Packet: Failed to insert new mac entry to the hash table\n");
78         return -1;
79     }
80
81     printk("Packet: Add MAC: %2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
82     
83     return 0;
84 }
85
86 static int palacios_packet_del_recver(const char * mac,
87                                       struct v3_vm_info * vm){
88
89     return 0;
90 }
91
92 static int init_raw_socket(const char * eth_dev){
93     int err;
94     struct sockaddr_ll sock_addr;
95     struct ifreq if_req;
96     int dev_idx;
97
98     err = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &(packet_state.raw_sock)); 
99
100     if (err < 0) {
101         printk(KERN_WARNING "Could not create a PF_PACKET Socket, err %d\n", err);
102         return -1;
103     }
104
105     if (eth_dev == NULL){
106         eth_dev = "eth0"; /* default "eth0" */
107     }
108
109     memset(&if_req, 0, sizeof(if_req));
110     strncpy(if_req.ifr_name, eth_dev, IFNAMSIZ);  //sizeof(if_req.ifr_name));
111
112     err = packet_state.raw_sock->ops->ioctl(packet_state.raw_sock, SIOCGIFINDEX, (long)&if_req);
113
114     if (err < 0){
115         printk(KERN_WARNING "Palacios Packet: Unable to get index for device %s, error %d\n", 
116                if_req.ifr_name, err);
117         dev_idx = 2; /* match ALL  2:"eth0" */
118     } else {
119         dev_idx = if_req.ifr_ifindex;
120     }
121
122     printk(KERN_INFO "Palacios Packet: bind to device index: %d\n", dev_idx);
123
124     memset(&sock_addr, 0, sizeof(sock_addr));
125     sock_addr.sll_family = PF_PACKET;
126     sock_addr.sll_protocol = htons(ETH_P_ALL);
127     sock_addr.sll_ifindex = dev_idx;
128
129     err = packet_state.raw_sock->ops->bind(packet_state.raw_sock, 
130                                            (struct sockaddr *)&sock_addr, 
131                                            sizeof(sock_addr));
132
133     if (err < 0){
134         printk(KERN_WARNING "Error binding raw packet to device %s, %d\n", eth_dev, err);
135         return -1;
136     }
137
138     printk(KERN_INFO "Bind palacios raw packet interface to device %s\n", eth_dev);
139
140     return 0;
141 }
142
143
144 static int
145 palacios_packet_send(const char * pkt, unsigned int len, void * private_data) {
146     struct msghdr msg;
147     struct iovec iov;
148     mm_segment_t oldfs;
149     int size = 0;       
150         
151     iov.iov_base = (void *)pkt;
152     iov.iov_len = (__kernel_size_t)len;
153
154     msg.msg_iov = &iov;
155     msg.msg_iovlen = 1;
156     msg.msg_control = NULL;
157     msg.msg_controllen = 0;
158     msg.msg_name = NULL;
159     msg.msg_namelen = 0;
160     msg.msg_flags = 0;
161
162     oldfs = get_fs();
163     set_fs(KERNEL_DS);
164     size = sock_sendmsg(packet_state.raw_sock, &msg, len);
165     set_fs(oldfs);
166
167
168     return size;
169 }
170
171
172 static struct v3_packet_hooks palacios_packet_hooks = {
173     .send       = palacios_packet_send,
174     .add_recver = palacios_packet_add_recver,
175     .del_recver = palacios_packet_del_recver,
176 };
177
178
179 static int 
180 recv_pkt(char * pkt, int len) {
181     struct msghdr msg;
182     struct iovec iov;
183     mm_segment_t oldfs;
184     int size = 0;
185     
186     if (packet_state.raw_sock == NULL) {
187         return -1;
188     }
189
190     iov.iov_base = pkt;
191     iov.iov_len = len;
192     
193     msg.msg_flags = 0;
194     msg.msg_name = NULL;
195     msg.msg_namelen = 0;
196     msg.msg_control = NULL;
197     msg.msg_controllen = 0;
198     msg.msg_iov = &iov;
199     msg.msg_iovlen = 1;
200     msg.msg_control = NULL;
201     
202     oldfs = get_fs();
203     set_fs(KERNEL_DS);
204     size = sock_recvmsg(packet_state.raw_sock, &msg, len, msg.msg_flags);
205     set_fs(oldfs);
206     
207     return size;
208 }
209
210
211 static void
212 send_raw_packet_to_palacios(char * pkt,
213                                int len,
214                                struct v3_vm_info * vm) {
215     struct v3_packet_event event;
216     char data[ETHERNET_PACKET_LEN];
217
218     /* one memory copy */
219     memcpy(data, pkt, len);
220     event.pkt = data;
221     event.size = len;
222         
223     v3_deliver_packet_event(vm, &event);
224 }
225
226 static int packet_server(void * arg) {
227     char pkt[ETHERNET_PACKET_LEN];
228     int size;
229     struct v3_vm_info *vm;
230
231     printk("Palacios Raw Packet Bridge: Staring receiving server\n");
232
233     while (!kthread_should_stop()) {
234         size = recv_pkt(pkt, ETHERNET_PACKET_LEN);
235
236         if (size < 0) {
237             printk(KERN_WARNING "Palacios raw packet receive error, Server terminated\n");
238             break;
239         }
240
241
242         /* if VNET is enabled, send to VNET */
243         // ...
244
245
246         /* if it is broadcast or multicase packet */
247         // ...
248
249
250         vm = (struct v3_vm_info *)v3_htable_search(packet_state.mac_vm_cache, (addr_t)pkt);
251
252         if (vm != NULL){
253             printk("Find destinated VM 0x%p\n", vm);
254             send_raw_packet_to_palacios(pkt, size, vm);
255         }
256     }
257
258     return 0;
259 }
260
261
262 static int packet_init( void ) {
263
264     const char * eth_dev = NULL;
265
266     if (packet_state.inited == 0){
267         packet_state.inited = 1;
268
269         if (init_raw_socket(eth_dev) == -1){
270             printk("Error to initiate palacios packet interface\n");
271             return -1;
272         }
273         
274         V3_Init_Packet(&palacios_packet_hooks);
275
276         packet_state.mac_vm_cache = v3_create_htable(0, &hash_fn, &hash_eq);
277
278         packet_state.server_thread = kthread_run(packet_server, NULL, "raw-packet-server");
279     }
280         
281
282     // REGISTER GLOBAL CONTROL to add interfaces...
283
284     return 0;
285 }
286
287 static int packet_deinit( void ) {
288
289
290     kthread_stop(packet_state.server_thread);
291     packet_state.raw_sock->ops->release(packet_state.raw_sock);
292     v3_free_htable(packet_state.mac_vm_cache, 0, 1);
293     packet_state.inited = 0;
294
295     return 0;
296 }
297
298
299
300 static struct linux_ext pkt_ext = {
301     .name = "PACKET_INTERFACE",
302     .init = packet_init,
303     .deinit = packet_deinit,
304     .guest_init = NULL,
305     .guest_deinit = NULL
306 };
307
308
309 register_extension(&pkt_ext);