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.


c03d628a508d2734f6517aa0b2ef6e0d2b6295a9
[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 ifreq if_req;
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     memset(&if_req, 0, sizeof(if_req));
107     strncpy(if_req.ifr_name, eth_dev, sizeof(if_req.ifr_name));
108
109     err = iface->raw_sock->ops->ioctl(iface->raw_sock, SIOCGIFINDEX, (long)&if_req);
110     if (err < 0){
111         printk(KERN_WARNING "Palacios Packet: Unable to get index for device %s, error %d\n", 
112                if_req.ifr_name, err);
113
114         sock_release(iface->raw_sock);
115         return -1;
116     }
117
118     memset(&sock_addr, 0, sizeof(sock_addr));
119     sock_addr.sll_family = PF_PACKET;
120     sock_addr.sll_protocol = htons(ETH_P_ALL);
121     sock_addr.sll_ifindex = if_req.ifr_ifindex;
122
123     err = iface->raw_sock->ops->bind(iface->raw_sock, 
124                                      (struct sockaddr *)&sock_addr, 
125                                      sizeof(sock_addr));
126
127     if (err < 0){
128         printk(KERN_WARNING "Error binding raw packet to device %s, %d\n", eth_dev, err);
129         sock_release(iface->raw_sock);
130         
131         return -1;
132     }
133
134     printk(KERN_INFO "Bind a palacios raw packet interface to device %s, device index %d\n",
135            if_req.ifr_name, if_req.ifr_ifindex);
136
137     return 0;
138 }
139
140
141 static inline int 
142 is_multicast_ethaddr(const unsigned char * addr)
143 {       
144     return (0x01 & addr[0]);
145 }
146
147 static inline int 
148 is_broadcast_ethaddr(const unsigned char * addr)
149 {
150     unsigned char ret = 0xff;
151     int i;
152         
153     for(i=0; i<ETH_ALEN; i++) {
154         ret &= addr[i];
155     }
156         
157     return (ret == 0xff);
158 }
159
160 static int packet_recv_thread( void * arg ) {
161     unsigned char * pkt;
162     int size;
163     struct v3_packet * recver_state;
164     struct raw_interface * iface = (struct raw_interface *)arg;
165
166     pkt = (unsigned char *)kmalloc(ETHERNET_PACKET_LEN, GFP_KERNEL);
167
168     printk("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             printk(KERN_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         printk("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;
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(recver_state, &(iface->brdcast_recvers), node) {
230         kfree(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     spin_lock_irqsave(&(packet_state.lock), flags);
257     
258     iface = find_interface(host_nic);
259     if(iface == NULL){
260         iface = (struct raw_interface *)kmalloc(sizeof(struct raw_interface), GFP_KERNEL);
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             spin_unlock_irqrestore(&(packet_state.lock), flags);
265             
266             return -1;
267         }
268         
269         list_add(&(iface->node), &(packet_state.open_interfaces));
270     }
271     
272     spin_unlock_irqrestore(&(packet_state.lock), flags);
273     
274     packet->host_packet_data = iface;
275     
276     list_add(&(packet->node), &(iface->brdcast_recvers));
277     palacios_htable_insert(iface->mac_to_recver, 
278                            (addr_t)packet->dev_mac, 
279                            (addr_t)packet);
280
281     printk(KERN_INFO "Packet: Add Receiver MAC to ethernet device %s: %2x:%2x:%2x:%2x:%2x:%2x\n", 
282            iface->eth_dev, 
283            packet->dev_mac[0], packet->dev_mac[1], 
284            packet->dev_mac[2], packet->dev_mac[3], 
285            packet->dev_mac[4], packet->dev_mac[5]);
286     
287     return 0;
288 }
289
290 static int
291 palacios_packet_send(struct v3_packet * packet, 
292                      unsigned char * pkt, 
293                      unsigned int len) {
294     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
295     struct msghdr msg;
296     struct iovec iov;
297     mm_segment_t oldfs;
298     int size = 0;
299         
300     if(iface->inited == 0 || 
301        iface->raw_sock == NULL){
302         printk("Palacios Packet Interface: Send fails due to inapproriate interface\n");
303         
304         return -1;
305     }
306         
307     iov.iov_base = (void *)pkt;
308     iov.iov_len = (__kernel_size_t)len;
309
310     msg.msg_iov = &iov;
311     msg.msg_iovlen = 1;
312     msg.msg_control = NULL;
313     msg.msg_controllen = 0;
314     msg.msg_name = NULL;
315     msg.msg_namelen = 0;
316     msg.msg_flags = 0;
317
318     oldfs = get_fs();
319     set_fs(KERNEL_DS);
320     size = sock_sendmsg(iface->raw_sock, &msg, len);
321     set_fs(oldfs);
322
323     return size;
324 }
325
326
327 static void
328 palacios_packet_close(struct v3_packet * packet) {
329     struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
330     
331     list_del(&(packet->node));
332     palacios_htable_remove(iface->mac_to_recver, (addr_t)(packet->dev_mac), 0);
333     
334     packet->host_packet_data = NULL;
335 }
336
337
338 static struct v3_packet_hooks palacios_packet_hooks = {
339     .connect = palacios_packet_connect,
340     .send = palacios_packet_send,
341     .close = palacios_packet_close,
342 };
343
344 static int packet_init( void ) {
345     V3_Init_Packet(&palacios_packet_hooks);
346     
347     memset(&packet_state, 0, sizeof(struct palacios_packet_state));
348     spin_lock_init(&(packet_state.lock));
349     INIT_LIST_HEAD(&(packet_state.open_interfaces));
350     
351     // REGISTER GLOBAL CONTROL to add interfaces...
352
353     return 0;
354 }
355
356 static int packet_deinit( void ) {
357     struct raw_interface * iface;
358     
359     list_for_each_entry(iface, &(packet_state.open_interfaces), node) {
360         deinit_raw_interface(iface);
361         kfree(iface);
362     }
363     
364     return 0;
365 }
366
367 static struct linux_ext pkt_ext = {
368     .name = "PACKET_INTERFACE",
369     .init = packet_init,
370     .deinit = packet_deinit,
371     .guest_init = NULL,
372     .guest_deinit = NULL
373 };
374
375
376 register_extension(&pkt_ext);