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.


More cleanup to avoid possible race
[palacios.git] / linux_module / iface-packet.c
1 /* 
2  * Palacios Raw Packet Interface Implementation
3  * (c) Lei Xia  2010
4  */
5  
6 #include <asm/uaccess.h>
7 #include <linux/inet.h>
8 #include <linux/kthread.h>
9 #include <linux/netdevice.h>
10 #include <linux/ip.h>
11 #include <linux/in.h>
12 #include <linux/string.h>
13 #include <linux/preempt.h>
14 #include <linux/sched.h>
15 #include <linux/if_packet.h>
16 #include <linux/errno.h>
17 #include <asm/msr.h>
18  
19 #include <interfaces/vmm_packet.h>
20 #include <palacios/vmm_ethernet.h>
21
22 #include "palacios.h"
23 #include "util-hashtable.h"
24 #include "linux-exts.h"
25 #include "vm.h"
26
27
28 /* there is one for each host nic */
29 struct raw_interface {
30     char eth_dev[126];  /* host nic name "eth0" ... */
31         
32     struct socket * raw_sock;
33     uint8_t inited;
34
35     struct list_head brdcast_recvers;
36     struct hashtable * mac_to_recver;
37
38     struct task_struct * recv_thread;
39
40     struct list_head node; 
41 };
42
43 struct palacios_packet_state{
44     spinlock_t lock;
45
46     struct list_head open_interfaces;
47 };
48
49 struct palacios_packet_state packet_state;
50
51 static inline uint_t hash_fn(addr_t hdr_ptr) {    
52     uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
53
54     return palacios_hash_buffer(hdr_buf, ETH_ALEN);
55 }
56
57 static inline int hash_eq(addr_t key1, addr_t key2) {   
58     return (memcmp((uint8_t *)key1, (uint8_t *)key2, ETH_ALEN) == 0);
59 }
60
61
62 static int 
63 recv_pkt(struct socket * raw_sock, unsigned char * pkt, unsigned int len) {
64     struct msghdr msg;
65     struct iovec iov;
66     mm_segment_t oldfs;
67     unsigned int size = 0;
68     
69     if (raw_sock == NULL) {
70         return -1;
71     }
72
73     iov.iov_base = pkt;
74     iov.iov_len = len;
75     
76     msg.msg_flags = 0;
77     msg.msg_name = NULL;
78     msg.msg_namelen = 0;
79     msg.msg_control = NULL;
80     msg.msg_controllen = 0;
81     msg.msg_iov = &iov;
82     msg.msg_iovlen = 1;
83     msg.msg_control = NULL;
84     
85     oldfs = get_fs();
86     set_fs(KERNEL_DS);
87     size = sock_recvmsg(raw_sock, &msg, len, msg.msg_flags);
88     set_fs(oldfs);
89     
90     return size;
91 }
92
93
94 static int 
95 init_socket(struct raw_interface * iface, const char * eth_dev){
96     int err;
97     struct sockaddr_ll sock_addr;
98     struct net_device * net_dev;
99
100     err = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &(iface->raw_sock)); 
101     if (err < 0) {
102         printk(KERN_WARNING "Could not create a PF_PACKET Socket, err %d\n", err);
103         return -1;
104     }
105
106     net_dev = dev_get_by_name(&init_net, eth_dev);
107     if(net_dev == NULL) {
108         printk(KERN_WARNING "Palacios Packet: Unable to get index for device %s\n", eth_dev);
109         sock_release(iface->raw_sock);
110         return -1;
111     }
112
113     memset(&sock_addr, 0, sizeof(sock_addr));
114     sock_addr.sll_family = PF_PACKET;
115     sock_addr.sll_protocol = htons(ETH_P_ALL);
116     sock_addr.sll_ifindex = net_dev->ifindex;
117
118     err = iface->raw_sock->ops->bind(iface->raw_sock, 
119                                      (struct sockaddr *)&sock_addr, 
120                                      sizeof(sock_addr));
121
122     if (err < 0){
123         printk(KERN_WARNING "Error binding raw packet to device %s, %d\n", eth_dev, err);
124         sock_release(iface->raw_sock);
125         
126         return -1;
127     }
128
129     printk(KERN_INFO "Bind a palacios raw packet interface to device %s, device index %d\n",
130            eth_dev, net_dev->ifindex);
131
132     return 0;
133 }
134
135
136 static inline int 
137 is_multicast_ethaddr(const unsigned char * addr)
138 {       
139     return (0x01 & addr[0]);
140 }
141
142 static inline int 
143 is_broadcast_ethaddr(const unsigned char * addr)
144 {
145     unsigned char ret = 0xff;
146     int i;
147         
148     for(i=0; i<ETH_ALEN; i++) {
149         ret &= addr[i];
150     }
151         
152     return (ret == 0xff);
153 }
154
155 static int packet_recv_thread( void * arg ) {
156     unsigned char * pkt;
157     int size;
158     struct v3_packet * recver_state;
159     struct raw_interface * iface = (struct raw_interface *)arg;
160
161     pkt = (unsigned char *)kmalloc(ETHERNET_PACKET_LEN, GFP_KERNEL);
162
163     printk("Palacios Raw Packet Bridge: Staring receiving on ethernet device %s\n", 
164            iface->eth_dev);
165
166     while (!kthread_should_stop()) {
167         size = recv_pkt(iface->raw_sock, pkt, ETHERNET_PACKET_LEN);
168         
169         if (size < 0) {
170             printk(KERN_WARNING "Palacios raw packet receive error, Server terminated\n");
171             break;
172         }
173
174         if(is_broadcast_ethaddr(pkt)) {
175             /* Broadcast */
176
177             list_for_each_entry(recver_state, &(iface->brdcast_recvers), node) {
178                 recver_state->input(recver_state, pkt, size);
179             }
180             
181         } else if(is_multicast_ethaddr(pkt)) {
182             /* MultiCast */
183
184         } else {
185             recver_state = (struct v3_packet *)palacios_htable_search(iface->mac_to_recver,
186                                                                       (addr_t)pkt);
187             if(recver_state != NULL) {
188                 recver_state->input(recver_state, pkt, size);
189             }
190         }
191     }
192     
193     return 0;
194 }
195
196
197 static int 
198 init_raw_interface(struct raw_interface * iface, const char * eth_dev){
199
200     memcpy(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN); 
201     if(init_socket(iface, eth_dev) !=0) {
202         printk("packet: fails to initiate raw socket\n");
203         return -1;
204     }
205     
206     
207     INIT_LIST_HEAD(&(iface->brdcast_recvers));
208     iface->mac_to_recver = palacios_create_htable(0, &hash_fn, &hash_eq);
209     iface->recv_thread = kthread_run(packet_recv_thread, (void *)iface, "bridge-recver");
210     
211     iface->inited = 1;
212     
213     return 0;
214 }
215
216 static void inline 
217 deinit_raw_interface(struct raw_interface * iface){
218     struct v3_packet * recver_state;
219
220     kthread_stop(iface->recv_thread);
221     sock_release(iface->raw_sock);
222     palacios_free_htable(iface->mac_to_recver,  0,  0);
223     
224     list_for_each_entry(recver_state, &(iface->brdcast_recvers), node) {
225         kfree(recver_state);
226     }
227 }
228
229
230 static inline struct raw_interface * 
231 find_interface(const char * eth_dev) {
232     struct raw_interface * iface;
233     
234     list_for_each_entry(iface, &(packet_state.open_interfaces), node) {
235         if (strncmp(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN) == 0) {
236             return iface;
237         }
238     }
239
240     return NULL;
241 }
242
243
244 static int
245 palacios_packet_connect(struct v3_packet * packet, 
246                         const char * host_nic, 
247                         void * host_vm_data) {
248     struct raw_interface * iface;
249     unsigned long flags;
250     
251     spin_lock_irqsave(&(packet_state.lock), flags);
252     iface = find_interface(host_nic);
253     spin_unlock_irqrestore(&(packet_state.lock),flags);
254
255     if(iface == NULL){
256         iface = (struct raw_interface *)kmalloc(sizeof(struct raw_interface), GFP_KERNEL);
257         if (!iface) { 
258             printk("Palacios Packet Interface: Fails to allocate interface\n");
259             return -1;
260         }
261         if(init_raw_interface(iface, host_nic) != 0) {
262             printk("Palacios Packet Interface: Fails to initiate an raw interface on device %s\n", host_nic);
263             kfree(iface);
264             return -1;
265         }
266         spin_lock_irqsave(&(packet_state.lock), flags); 
267         list_add(&(iface->node), &(packet_state.open_interfaces));
268         spin_unlock_irqrestore(&(packet_state.lock),flags);
269     }
270     
271     packet->host_packet_data = iface;
272     
273     list_add(&(packet->node), &(iface->brdcast_recvers));
274     palacios_htable_insert(iface->mac_to_recver, 
275                            (addr_t)packet->dev_mac, 
276                            (addr_t)packet);
277
278     printk(KERN_INFO "Packet: Add Receiver MAC to ethernet device %s: %2x:%2x:%2x:%2x:%2x:%2x\n", 
279            iface->eth_dev, 
280            packet->dev_mac[0], packet->dev_mac[1], 
281            packet->dev_mac[2], packet->dev_mac[3], 
282            packet->dev_mac[4], packet->dev_mac[5]);
283     
284     return 0;
285 }
286
287 static int
288 palacios_packet_send(struct v3_packet * packet, 
289                      unsigned char * pkt, 
290                      unsigned int len) {
291     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
292     struct msghdr msg;
293     struct iovec iov;
294     mm_segment_t oldfs;
295     int size = 0;
296         
297     if(iface->inited == 0 || 
298        iface->raw_sock == NULL){
299         printk("Palacios Packet Interface: Send fails due to inapproriate interface\n");
300         
301         return -1;
302     }
303         
304     iov.iov_base = (void *)pkt;
305     iov.iov_len = (__kernel_size_t)len;
306
307     msg.msg_iov = &iov;
308     msg.msg_iovlen = 1;
309     msg.msg_control = NULL;
310     msg.msg_controllen = 0;
311     msg.msg_name = NULL;
312     msg.msg_namelen = 0;
313     msg.msg_flags = 0;
314
315     oldfs = get_fs();
316     set_fs(KERNEL_DS);
317     size = sock_sendmsg(iface->raw_sock, &msg, len);
318     set_fs(oldfs);
319
320     return size;
321 }
322
323
324 static void
325 palacios_packet_close(struct v3_packet * packet) {
326     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
327     
328     list_del(&(packet->node));
329     palacios_htable_remove(iface->mac_to_recver, (addr_t)(packet->dev_mac), 0);
330     
331     packet->host_packet_data = NULL;
332 }
333
334
335 static struct v3_packet_hooks palacios_packet_hooks = {
336     .connect = palacios_packet_connect,
337     .send = palacios_packet_send,
338     .close = palacios_packet_close,
339 };
340
341 static int packet_init( void ) {
342     V3_Init_Packet(&palacios_packet_hooks);
343     
344     memset(&packet_state, 0, sizeof(struct palacios_packet_state));
345     spin_lock_init(&(packet_state.lock));
346     INIT_LIST_HEAD(&(packet_state.open_interfaces));
347     
348     // REGISTER GLOBAL CONTROL to add interfaces...
349
350     return 0;
351 }
352
353 static int packet_deinit( void ) {
354     struct raw_interface * iface;
355     
356     list_for_each_entry(iface, &(packet_state.open_interfaces), node) {
357         deinit_raw_interface(iface);
358         kfree(iface);
359     }
360     
361     return 0;
362 }
363
364 static struct linux_ext pkt_ext = {
365     .name = "PACKET_INTERFACE",
366     .init = packet_init,
367     .deinit = packet_deinit,
368     .guest_init = NULL,
369     .guest_deinit = NULL
370 };
371
372
373 register_extension(&pkt_ext);