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.


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