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.


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