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.


6ec4de0a1d9278e88cea38a9364de63d024e1b95
[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         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         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         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     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 *)palacios_alloc(ETHERNET_PACKET_LEN);
162     
163     if (!pkt) {
164         ERROR("Unable to allocate packet in vnet receive thread\n");
165         return -1;
166     }
167
168     INFO("Palacios Raw Packet Bridge: Staring receiving on ethernet device %s\n", 
169            iface->eth_dev);
170
171     while (!kthread_should_stop()) {
172         size = recv_pkt(iface->raw_sock, pkt, ETHERNET_PACKET_LEN);
173         
174         if (size < 0) {
175             WARNING("Palacios raw packet receive error, Server terminated\n");
176             break;
177         }
178
179         if(is_broadcast_ethaddr(pkt)) {
180             /* Broadcast */
181
182             list_for_each_entry(recver_state, &(iface->brdcast_recvers), node) {
183                 recver_state->input(recver_state, pkt, size);
184             }
185             
186         } else if(is_multicast_ethaddr(pkt)) {
187             /* MultiCast */
188
189         } else {
190             recver_state = (struct v3_packet *)palacios_htable_search(iface->mac_to_recver,
191                                                                       (addr_t)pkt);
192             if(recver_state != NULL) {
193                 recver_state->input(recver_state, pkt, size);
194             }
195         }
196     }
197     
198     return 0;
199 }
200
201
202 static int 
203 init_raw_interface(struct raw_interface * iface, const char * eth_dev){
204
205     memcpy(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN); 
206     if(init_socket(iface, eth_dev) !=0) {
207         WARNING("packet: fails to initiate raw socket\n");
208         return -1;
209     }
210     
211     
212     INIT_LIST_HEAD(&(iface->brdcast_recvers));
213     iface->mac_to_recver = palacios_create_htable(0, &hash_fn, &hash_eq);
214     iface->recv_thread = kthread_run(packet_recv_thread, (void *)iface, "bridge-recver");
215     
216     iface->inited = 1;
217     
218     return 0;
219 }
220
221 static void inline 
222 deinit_raw_interface(struct raw_interface * iface){
223     struct v3_packet * recver_state, * tmp_state;
224
225     kthread_stop(iface->recv_thread);
226     sock_release(iface->raw_sock);
227     palacios_free_htable(iface->mac_to_recver,  0,  0);
228     
229     list_for_each_entry_safe(recver_state, tmp_state, &(iface->brdcast_recvers), node) {
230         palacios_free(recver_state);
231     }
232 }
233
234
235 static inline struct raw_interface * 
236 find_interface(const char * eth_dev) {
237     struct raw_interface * iface;
238     
239     list_for_each_entry(iface, &(packet_state.open_interfaces), node) {
240         if (strncmp(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN) == 0) {
241             return iface;
242         }
243     }
244
245     return NULL;
246 }
247
248
249 static int
250 palacios_packet_connect(struct v3_packet * packet, 
251                         const char * host_nic, 
252                         void * host_vm_data) {
253     struct raw_interface * iface;
254     unsigned long flags;
255     
256     palacios_spinlock_lock_irqsave(&(packet_state.lock), flags);
257     iface = find_interface(host_nic);
258     palacios_spinlock_unlock_irqrestore(&(packet_state.lock),flags);
259
260     if(iface == NULL){
261         iface = (struct raw_interface *)palacios_alloc(sizeof(struct raw_interface));
262         if (!iface) { 
263             ERROR("Palacios Packet Interface: Fails to allocate interface\n");
264             return -1;
265         }
266         if(init_raw_interface(iface, host_nic) != 0) {
267             ERROR("Palacios Packet Interface: Fails to initiate an raw interface on device %s\n", host_nic);
268             palacios_free(iface);
269             return -1;
270         }
271         palacios_spinlock_lock_irqsave(&(packet_state.lock), flags);    
272         list_add(&(iface->node), &(packet_state.open_interfaces));
273         palacios_spinlock_unlock_irqrestore(&(packet_state.lock),flags);
274     }
275     
276     packet->host_packet_data = iface;
277     
278     list_add(&(packet->node), &(iface->brdcast_recvers));
279     palacios_htable_insert(iface->mac_to_recver, 
280                            (addr_t)packet->dev_mac, 
281                            (addr_t)packet);
282
283     INFO("Packet: Add Receiver MAC to ethernet device %s: %2x:%2x:%2x:%2x:%2x:%2x\n", 
284            iface->eth_dev, 
285            packet->dev_mac[0], packet->dev_mac[1], 
286            packet->dev_mac[2], packet->dev_mac[3], 
287            packet->dev_mac[4], packet->dev_mac[5]);
288     
289     return 0;
290 }
291
292 static int
293 palacios_packet_send(struct v3_packet * packet, 
294                      unsigned char * pkt, 
295                      unsigned int len) {
296     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
297     struct msghdr msg;
298     struct iovec iov;
299     mm_segment_t oldfs;
300     int size = 0;
301         
302     if(iface->inited == 0 || 
303        iface->raw_sock == NULL){
304         ERROR("Palacios Packet Interface: Send fails due to inapproriate interface\n");
305         return -1;
306     }
307         
308     iov.iov_base = (void *)pkt;
309     iov.iov_len = (__kernel_size_t)len;
310
311     msg.msg_iov = &iov;
312     msg.msg_iovlen = 1;
313     msg.msg_control = NULL;
314     msg.msg_controllen = 0;
315     msg.msg_name = NULL;
316     msg.msg_namelen = 0;
317     msg.msg_flags = 0;
318
319     oldfs = get_fs();
320     set_fs(KERNEL_DS);
321     size = sock_sendmsg(iface->raw_sock, &msg, len);
322     set_fs(oldfs);
323
324     return size;
325 }
326
327
328 static void
329 palacios_packet_close(struct v3_packet * packet) {
330     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
331     
332     list_del(&(packet->node));
333     palacios_htable_remove(iface->mac_to_recver, (addr_t)(packet->dev_mac), 0);
334     
335     packet->host_packet_data = NULL;
336 }
337
338
339 static struct v3_packet_hooks palacios_packet_hooks = {
340     .connect = palacios_packet_connect,
341     .send = palacios_packet_send,
342     .close = palacios_packet_close,
343 };
344
345 static int packet_init( void ) {
346     V3_Init_Packet(&palacios_packet_hooks);
347     
348     memset(&packet_state, 0, sizeof(struct palacios_packet_state));
349     palacios_spinlock_init(&(packet_state.lock));
350     INIT_LIST_HEAD(&(packet_state.open_interfaces));
351     
352     // REGISTER GLOBAL CONTROL to add interfaces...
353
354     return 0;
355 }
356
357 static int packet_deinit( void ) {
358     struct raw_interface * iface, * tmp;
359     
360     list_for_each_entry_safe(iface, tmp, &(packet_state.open_interfaces), node) {
361         deinit_raw_interface(iface);
362         palacios_free(iface);
363     }
364
365     palacios_spinlock_deinit(&(packet_state.lock));
366     
367     return 0;
368 }
369
370 static struct linux_ext pkt_ext = {
371     .name = "PACKET_INTERFACE",
372     .init = packet_init,
373     .deinit = packet_deinit,
374     .guest_init = NULL,
375     .guest_deinit = NULL
376 };
377
378
379 register_extension(&pkt_ext);