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.


moved vnet to extension framework
[palacios.git] / linux_module / palacios-packet.c
1 /* 
2  * Palacios Raw Packet 
3  * (c) Lei Xia, 2010
4  */
5 #include <asm/uaccess.h>
6 #include <linux/inet.h>
7 #include <linux/kthread.h>
8 #include <linux/netdevice.h>
9 #include <linux/ip.h>
10 #include <linux/in.h>
11 #include <linux/string.h>
12 #include <linux/preempt.h>
13 #include <linux/sched.h>
14 #include <linux/if_packet.h>
15 #include <linux/errno.h>
16 #include <asm/msr.h>
17  
18 #include <interfaces/vmm_packet.h>
19 #include <palacios/vmm_host_events.h>
20 #include <vnet/vnet.h>
21
22
23 #define __V3VEE__
24 #include <palacios/vmm_hashtable.h>
25 #include <palacios/vmm_ethernet.h>
26 #undef __V3VEE__
27
28 #include "palacios.h"
29 #include "linux-exts.h"
30 struct palacios_packet_state {
31     struct socket * raw_sock;
32     uint8_t inited;
33         
34     struct hashtable * mac_vm_cache;
35     struct task_struct * server_thread;
36 };
37
38 static struct palacios_packet_state packet_state;
39
40 static inline uint_t hash_fn(addr_t hdr_ptr) {    
41     uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
42
43     return v3_hash_buffer(hdr_buf, ETH_ALEN);
44 }
45
46 static inline int hash_eq(addr_t key1, addr_t key2) {   
47     return (memcmp((uint8_t *)key1, (uint8_t *)key2, ETH_ALEN) == 0);
48 }
49
50
51 static int palacios_packet_add_recver(const char * mac, 
52                                         struct v3_vm_info * vm){
53     char * key;
54
55     key = (char *)kmalloc(ETH_ALEN, GFP_KERNEL);                                        
56     memcpy(key, mac, ETH_ALEN);    
57
58     if (v3_htable_insert(packet_state.mac_vm_cache, (addr_t)key, (addr_t)vm) == 0) {
59         printk("Palacios Packet: Failed to insert new mac entry to the hash table\n");
60         return -1;
61     }
62
63     printk("Packet: Add MAC: %2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
64     
65     return 0;
66 }
67
68 static int palacios_packet_del_recver(const char * mac,
69                                         struct v3_vm_info * vm){
70
71     return 0;
72 }
73
74 static int init_raw_socket (const char * eth_dev){
75     int err;
76     struct sockaddr_ll sock_addr;
77     struct ifreq if_req;
78     int dev_idx;
79
80     err = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &(packet_state.raw_sock)); 
81     if (err < 0) {
82         printk(KERN_WARNING "Could not create a PF_PACKET Socket, err %d\n", err);
83         return -1;
84     }
85
86     if(eth_dev == NULL){
87         eth_dev = "eth0"; /* default "eth0" */
88     }
89
90     memset(&if_req, 0, sizeof(if_req));
91     strncpy(if_req.ifr_name, eth_dev, IFNAMSIZ);  //sizeof(if_req.ifr_name));
92     err = packet_state.raw_sock->ops->ioctl(packet_state.raw_sock, SIOCGIFINDEX, (long)&if_req);
93     if(err < 0){
94         printk(KERN_WARNING "Palacios Packet: Unable to get index for device %s, error %d\n", if_req.ifr_name, err);
95         dev_idx = 2; /* match ALL  2:"eth0" */
96     }
97     else{
98         dev_idx = if_req.ifr_ifindex;
99     }
100
101     printk(KERN_INFO "Palacios Packet: bind to device index: %d\n", dev_idx);
102
103     memset(&sock_addr, 0, sizeof(sock_addr));
104     sock_addr.sll_family = PF_PACKET;
105     sock_addr.sll_protocol = htons(ETH_P_ALL);
106     sock_addr.sll_ifindex = dev_idx;
107
108     err = packet_state.raw_sock->ops->bind(packet_state.raw_sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
109     if (err < 0){
110         printk(KERN_WARNING "Error binding raw packet to device %s, %d\n", eth_dev, err);
111         return -1;
112     }
113
114     printk(KERN_INFO "Bind palacios raw packet interface to device %s\n", eth_dev);
115
116     return 0;
117 }
118
119
120 static int
121 palacios_packet_send(const char * pkt, unsigned int len, void * private_data) {
122     struct msghdr msg;
123     struct iovec iov;
124     mm_segment_t oldfs;
125     int size = 0;       
126         
127     iov.iov_base = (void *)pkt;
128     iov.iov_len = (__kernel_size_t)len;
129
130     msg.msg_iov = &iov;
131     msg.msg_iovlen = 1;
132     msg.msg_control = NULL;
133     msg.msg_controllen = 0;
134     msg.msg_name = NULL;
135     msg.msg_namelen = 0;
136     msg.msg_flags = 0;
137
138     oldfs = get_fs();
139     set_fs(KERNEL_DS);
140     size = sock_sendmsg(packet_state.raw_sock, &msg, len);
141     set_fs(oldfs);
142
143
144     return size;
145 }
146
147
148 static struct v3_packet_hooks palacios_packet_hooks = {
149     .send       = palacios_packet_send,
150     .add_recver = palacios_packet_add_recver,
151     .del_recver = palacios_packet_del_recver,
152 };
153
154
155 static int 
156 recv_pkt(char * pkt, int len) {
157     struct msghdr msg;
158     struct iovec iov;
159     mm_segment_t oldfs;
160     int size = 0;
161     
162     if (packet_state.raw_sock == NULL) {
163         return -1;
164     }
165
166     iov.iov_base = pkt;
167     iov.iov_len = len;
168     
169     msg.msg_flags = 0;
170     msg.msg_name = NULL;
171     msg.msg_namelen = 0;
172     msg.msg_control = NULL;
173     msg.msg_controllen = 0;
174     msg.msg_iov = &iov;
175     msg.msg_iovlen = 1;
176     msg.msg_control = NULL;
177     
178     oldfs = get_fs();
179     set_fs(KERNEL_DS);
180     size = sock_recvmsg(packet_state.raw_sock, &msg, len, msg.msg_flags);
181     set_fs(oldfs);
182     
183     return size;
184 }
185
186
187 static void
188 send_raw_packet_to_palacios(char * pkt,
189                                int len,
190                                struct v3_vm_info * vm) {
191     struct v3_packet_event event;
192     char data[ETHERNET_PACKET_LEN];
193
194     /* one memory copy */
195     memcpy(data, pkt, len);
196     event.pkt = data;
197     event.size = len;
198         
199     v3_deliver_packet_event(vm, &event);
200 }
201
202 static int packet_server(void * arg) {
203     char pkt[ETHERNET_PACKET_LEN];
204     int size;
205     struct v3_vm_info *vm;
206
207     printk("Palacios Raw Packet Bridge: Staring receiving server\n");
208
209     while (!kthread_should_stop()) {
210         size = recv_pkt(pkt, ETHERNET_PACKET_LEN);
211         if (size < 0) {
212             printk(KERN_WARNING "Palacios raw packet receive error, Server terminated\n");
213             break;
214         }
215
216
217         /* if VNET is enabled, send to VNET */
218         // ...
219
220
221         /* if it is broadcast or multicase packet */
222         // ...
223
224
225         vm = (struct v3_vm_info *)v3_htable_search(packet_state.mac_vm_cache, (addr_t)pkt);
226         if(vm != NULL){
227             printk("Find destinated VM 0x%p\n", vm);
228             send_raw_packet_to_palacios(pkt, size, vm);
229         }
230     }
231
232     return 0;
233 }
234
235
236 static int packet_init( void ) {
237
238     const char * eth_dev = NULL;
239
240     if(packet_state.inited == 0){
241         packet_state.inited = 1;
242
243         if(init_raw_socket(eth_dev) == -1){
244             printk("Error to initiate palacios packet interface\n");
245             return -1;
246         }
247         
248         V3_Init_Packet(&palacios_packet_hooks);
249
250         packet_state.mac_vm_cache = v3_create_htable(0, &hash_fn, &hash_eq);
251
252         packet_state.server_thread = kthread_run(packet_server, NULL, "raw-packet-server");
253     }
254         
255
256     // REGISTER GLOBAL CONTROL to add devices...
257
258     return 0;
259 }
260
261 static int packet_deinit( void ) {
262
263
264     kthread_stop(packet_state.server_thread);
265     packet_state.raw_sock->ops->release(packet_state.raw_sock);
266     v3_free_htable(packet_state.mac_vm_cache, 0, 1);
267     packet_state.inited = 0;
268
269     return 0;
270 }
271
272
273
274 static struct linux_ext pkt_ext = {
275     .name = "PACKET_INTERFACE",
276     .init = packet_init,
277     .deinit = packet_deinit,
278     .guest_init = NULL,
279     .guest_deinit = NULL
280 };
281
282
283 register_extension(&pkt_ext);