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 Linux 3.19+ kernel compatability fixes
[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 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
82     msg.msg_iov = &iov;
83     msg.msg_iovlen = 1;
84 #else
85     iov_iter_init(&(msg.msg_iter),WRITE,&iov,1,0);
86 #endif
87     msg.msg_control = NULL;
88     
89     oldfs = get_fs();
90     set_fs(KERNEL_DS);
91     size = sock_recvmsg(raw_sock, &msg, len, msg.msg_flags);
92     set_fs(oldfs);
93     
94     return size;
95 }
96
97
98 static int 
99 init_socket(struct raw_interface * iface, const char * eth_dev){
100     int err;
101     struct sockaddr_ll sock_addr;
102     struct net_device * net_dev;
103
104     err = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &(iface->raw_sock)); 
105     if (err < 0) {
106         WARNING("Could not create a PF_PACKET Socket, err %d\n", err);
107         return -1;
108     }
109
110     net_dev = dev_get_by_name(&init_net, eth_dev);
111     if(net_dev == NULL) {
112         WARNING("Palacios Packet: Unable to get index for device %s\n", eth_dev);
113         sock_release(iface->raw_sock);
114         return -1;
115     }
116
117     memset(&sock_addr, 0, sizeof(sock_addr));
118     sock_addr.sll_family = PF_PACKET;
119     sock_addr.sll_protocol = htons(ETH_P_ALL);
120     sock_addr.sll_ifindex = net_dev->ifindex;
121
122     err = iface->raw_sock->ops->bind(iface->raw_sock, 
123                                      (struct sockaddr *)&sock_addr, 
124                                      sizeof(sock_addr));
125
126     if (err < 0){
127         WARNING("Error binding raw packet to device %s, %d\n", eth_dev, err);
128         sock_release(iface->raw_sock);
129         
130         return -1;
131     }
132
133     INFO("Bind a palacios raw packet interface to device %s, device index %d\n",
134            eth_dev, net_dev->ifindex);
135
136     return 0;
137 }
138
139
140 static inline int 
141 is_multicast_ethaddr(const unsigned char * addr)
142 {       
143     return (0x01 & addr[0]);
144 }
145
146 static inline int 
147 is_broadcast_ethaddr(const unsigned char * addr)
148 {
149     unsigned char ret = 0xff;
150     int i;
151         
152     for(i=0; i<ETH_ALEN; i++) {
153         ret &= addr[i];
154     }
155         
156     return (ret == 0xff);
157 }
158
159 static int packet_recv_thread( void * arg ) {
160     unsigned char * pkt;
161     int size;
162     struct v3_packet * recver_state;
163     struct raw_interface * iface = (struct raw_interface *)arg;
164
165     pkt = (unsigned char *)palacios_alloc(ETHERNET_PACKET_LEN);
166     
167     if (!pkt) {
168         ERROR("Unable to allocate packet in vnet receive thread\n");
169         return -1;
170     }
171
172     INFO("Palacios Raw Packet Bridge: Staring receiving on ethernet device %s\n", 
173            iface->eth_dev);
174
175     while (!kthread_should_stop()) {
176         size = recv_pkt(iface->raw_sock, pkt, ETHERNET_PACKET_LEN);
177         
178         if (size < 0) {
179             WARNING("Palacios raw packet receive error, Server terminated\n");
180             break;
181         }
182
183         if(is_broadcast_ethaddr(pkt)) {
184             /* Broadcast */
185
186             list_for_each_entry(recver_state, &(iface->brdcast_recvers), node) {
187                 recver_state->input(recver_state, pkt, size);
188             }
189             
190         } else if(is_multicast_ethaddr(pkt)) {
191             /* MultiCast */
192
193         } else {
194             recver_state = (struct v3_packet *)palacios_htable_search(iface->mac_to_recver,
195                                                                       (addr_t)pkt);
196             if(recver_state != NULL) {
197                 recver_state->input(recver_state, pkt, size);
198             }
199         }
200     }
201     
202     return 0;
203 }
204
205
206 static int 
207 init_raw_interface(struct raw_interface * iface, const char * eth_dev){
208
209     memcpy(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN); 
210     if(init_socket(iface, eth_dev) !=0) {
211         WARNING("packet: fails to initiate raw socket\n");
212         return -1;
213     }
214     
215     
216     INIT_LIST_HEAD(&(iface->brdcast_recvers));
217     iface->mac_to_recver = palacios_create_htable(0, &hash_fn, &hash_eq);
218     iface->recv_thread = kthread_run(packet_recv_thread, (void *)iface, "bridge-recver");
219     
220     iface->inited = 1;
221     
222     return 0;
223 }
224
225 static void inline 
226 deinit_raw_interface(struct raw_interface * iface){
227     struct v3_packet * recver_state, * tmp_state;
228
229     kthread_stop(iface->recv_thread);
230     sock_release(iface->raw_sock);
231     palacios_free_htable(iface->mac_to_recver,  0,  0);
232     
233     list_for_each_entry_safe(recver_state, tmp_state, &(iface->brdcast_recvers), node) {
234         palacios_free(recver_state);
235     }
236 }
237
238
239 static inline struct raw_interface * 
240 find_interface(const char * eth_dev) {
241     struct raw_interface * iface;
242     
243     list_for_each_entry(iface, &(packet_state.open_interfaces), node) {
244         if (strncmp(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN) == 0) {
245             return iface;
246         }
247     }
248
249     return NULL;
250 }
251
252
253 static int
254 palacios_packet_connect(struct v3_packet * packet, 
255                         const char * host_nic, 
256                         void * host_vm_data) {
257     struct raw_interface * iface;
258     unsigned long flags;
259     
260     palacios_spinlock_lock_irqsave(&(packet_state.lock), flags);
261     iface = find_interface(host_nic);
262     palacios_spinlock_unlock_irqrestore(&(packet_state.lock),flags);
263
264     if(iface == NULL){
265         iface = (struct raw_interface *)palacios_alloc(sizeof(struct raw_interface));
266         if (!iface) { 
267             ERROR("Palacios Packet Interface: Fails to allocate interface\n");
268             return -1;
269         }
270         if(init_raw_interface(iface, host_nic) != 0) {
271             ERROR("Palacios Packet Interface: Fails to initiate an raw interface on device %s\n", host_nic);
272             palacios_free(iface);
273             return -1;
274         }
275         palacios_spinlock_lock_irqsave(&(packet_state.lock), flags);    
276         list_add(&(iface->node), &(packet_state.open_interfaces));
277         palacios_spinlock_unlock_irqrestore(&(packet_state.lock),flags);
278     }
279     
280     packet->host_packet_data = iface;
281     
282     list_add(&(packet->node), &(iface->brdcast_recvers));
283     palacios_htable_insert(iface->mac_to_recver, 
284                            (addr_t)packet->dev_mac, 
285                            (addr_t)packet);
286
287     INFO("Packet: Add Receiver MAC to ethernet device %s: %2x:%2x:%2x:%2x:%2x:%2x\n", 
288            iface->eth_dev, 
289            packet->dev_mac[0], packet->dev_mac[1], 
290            packet->dev_mac[2], packet->dev_mac[3], 
291            packet->dev_mac[4], packet->dev_mac[5]);
292     
293     return 0;
294 }
295
296 static int
297 palacios_packet_send(struct v3_packet * packet, 
298                      unsigned char * pkt, 
299                      unsigned int len) {
300     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
301     struct msghdr msg;
302     struct iovec iov;
303     mm_segment_t oldfs;
304     int size = 0;
305         
306     if(iface->inited == 0 || 
307        iface->raw_sock == NULL){
308         ERROR("Palacios Packet Interface: Send fails due to inapproriate interface\n");
309         return -1;
310     }
311         
312     iov.iov_base = (void *)pkt;
313     iov.iov_len = (__kernel_size_t)len;
314
315 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
316     msg.msg_iov = &iov;
317     msg.msg_iovlen = 1;
318 #else
319     iov_iter_init(&(msg.msg_iter),WRITE,&iov,1,0);
320 #endif
321     msg.msg_control = NULL;
322     msg.msg_controllen = 0;
323     msg.msg_name = NULL;
324     msg.msg_namelen = 0;
325     msg.msg_flags = 0;
326
327     oldfs = get_fs();
328     set_fs(KERNEL_DS);
329     size = sock_sendmsg(iface->raw_sock, &msg, len);
330     set_fs(oldfs);
331
332     return size;
333 }
334
335
336 static void
337 palacios_packet_close(struct v3_packet * packet) {
338     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
339     
340     list_del(&(packet->node));
341     palacios_htable_remove(iface->mac_to_recver, (addr_t)(packet->dev_mac), 0);
342     
343     packet->host_packet_data = NULL;
344 }
345
346
347 static struct v3_packet_hooks palacios_packet_hooks = {
348     .connect = palacios_packet_connect,
349     .send = palacios_packet_send,
350     .close = palacios_packet_close,
351 };
352
353 static int packet_init( void ) {
354     V3_Init_Packet(&palacios_packet_hooks);
355     
356     memset(&packet_state, 0, sizeof(struct palacios_packet_state));
357     palacios_spinlock_init(&(packet_state.lock));
358     INIT_LIST_HEAD(&(packet_state.open_interfaces));
359     
360     // REGISTER GLOBAL CONTROL to add interfaces...
361
362     return 0;
363 }
364
365 static int packet_deinit( void ) {
366     struct raw_interface * iface, * tmp;
367     
368     list_for_each_entry_safe(iface, tmp, &(packet_state.open_interfaces), node) {
369         deinit_raw_interface(iface);
370         palacios_free(iface);
371     }
372
373     palacios_spinlock_deinit(&(packet_state.lock));
374     
375     return 0;
376 }
377
378 static struct linux_ext pkt_ext = {
379     .name = "PACKET_INTERFACE",
380     .init = packet_init,
381     .deinit = packet_deinit,
382     .guest_init = NULL,
383     .guest_deinit = NULL
384 };
385
386
387 register_extension(&pkt_ext);