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.


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