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.


Changed memory allocation to avoid possible deadlock (GFP_KERNEL while lock held)
[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     
253     iface = find_interface(host_nic);
254     if(iface == NULL){
255         iface = (struct raw_interface *)kmalloc(sizeof(struct raw_interface), GFP_ATOMIC);
256         if (!iface) { 
257             printk("Palacios Packet Interface: Fails to allocate interface\n");
258             return -1;
259         }
260         if(init_raw_interface(iface, host_nic) != 0) {
261             printk("Palacios Packet Interface: Fails to initiate an raw interface on device %s\n", host_nic);
262             kfree(iface);
263             spin_unlock_irqrestore(&(packet_state.lock), flags);
264             
265             return -1;
266         }
267         
268         list_add(&(iface->node), &(packet_state.open_interfaces));
269     }
270     
271     spin_unlock_irqrestore(&(packet_state.lock), flags);
272     
273     packet->host_packet_data = iface;
274     
275     list_add(&(packet->node), &(iface->brdcast_recvers));
276     palacios_htable_insert(iface->mac_to_recver, 
277                            (addr_t)packet->dev_mac, 
278                            (addr_t)packet);
279
280     printk(KERN_INFO "Packet: Add Receiver MAC to ethernet device %s: %2x:%2x:%2x:%2x:%2x:%2x\n", 
281            iface->eth_dev, 
282            packet->dev_mac[0], packet->dev_mac[1], 
283            packet->dev_mac[2], packet->dev_mac[3], 
284            packet->dev_mac[4], packet->dev_mac[5]);
285     
286     return 0;
287 }
288
289 static int
290 palacios_packet_send(struct v3_packet * packet, 
291                      unsigned char * pkt, 
292                      unsigned int len) {
293     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
294     struct msghdr msg;
295     struct iovec iov;
296     mm_segment_t oldfs;
297     int size = 0;
298         
299     if(iface->inited == 0 || 
300        iface->raw_sock == NULL){
301         printk("Palacios Packet Interface: Send fails due to inapproriate interface\n");
302         
303         return -1;
304     }
305         
306     iov.iov_base = (void *)pkt;
307     iov.iov_len = (__kernel_size_t)len;
308
309     msg.msg_iov = &iov;
310     msg.msg_iovlen = 1;
311     msg.msg_control = NULL;
312     msg.msg_controllen = 0;
313     msg.msg_name = NULL;
314     msg.msg_namelen = 0;
315     msg.msg_flags = 0;
316
317     oldfs = get_fs();
318     set_fs(KERNEL_DS);
319     size = sock_sendmsg(iface->raw_sock, &msg, len);
320     set_fs(oldfs);
321
322     return size;
323 }
324
325
326 static void
327 palacios_packet_close(struct v3_packet * packet) {
328     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
329     
330     list_del(&(packet->node));
331     palacios_htable_remove(iface->mac_to_recver, (addr_t)(packet->dev_mac), 0);
332     
333     packet->host_packet_data = NULL;
334 }
335
336
337 static struct v3_packet_hooks palacios_packet_hooks = {
338     .connect = palacios_packet_connect,
339     .send = palacios_packet_send,
340     .close = palacios_packet_close,
341 };
342
343 static int packet_init( void ) {
344     V3_Init_Packet(&palacios_packet_hooks);
345     
346     memset(&packet_state, 0, sizeof(struct palacios_packet_state));
347     spin_lock_init(&(packet_state.lock));
348     INIT_LIST_HEAD(&(packet_state.open_interfaces));
349     
350     // REGISTER GLOBAL CONTROL to add interfaces...
351
352     return 0;
353 }
354
355 static int packet_deinit( void ) {
356     struct raw_interface * iface;
357     
358     list_for_each_entry(iface, &(packet_state.open_interfaces), node) {
359         deinit_raw_interface(iface);
360         kfree(iface);
361     }
362     
363     return 0;
364 }
365
366 static struct linux_ext pkt_ext = {
367     .name = "PACKET_INTERFACE",
368     .init = packet_init,
369     .deinit = packet_deinit,
370     .guest_init = NULL,
371     .guest_deinit = NULL
372 };
373
374
375 register_extension(&pkt_ext);