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 palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
[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 #define __V3VEE__
23 #include <palacios/vmm_hashtable.h>
24 #include <palacios/vmm_ethernet.h>
25 #undef __V3VEE__
26
27 #include "palacios.h"
28 #include "palacios-packet.h"
29
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     if(vnet_debug >= 4){
144         printk("Palacios Packet: send pkt to NIC (size: %d)\n", len);
145         print_hex_dump(NULL, "pkt_header: ", 0, 20, 20, pkt, 20, 0);
146         printk("palacios_packet_send return: %d\n", size);
147     }
148
149     return size;
150 }
151
152
153 static struct v3_packet_hooks palacios_packet_hooks = {
154     .send       = palacios_packet_send,
155     .add_recver = palacios_packet_add_recver,
156     .del_recver = palacios_packet_del_recver,
157 };
158
159
160 static int 
161 recv_pkt(char * pkt, int len) {
162     struct msghdr msg;
163     struct iovec iov;
164     mm_segment_t oldfs;
165     int size = 0;
166     
167     if (packet_state.raw_sock == NULL) {
168         return -1;
169     }
170
171     iov.iov_base = pkt;
172     iov.iov_len = len;
173     
174     msg.msg_flags = 0;
175     msg.msg_name = NULL;
176     msg.msg_namelen = 0;
177     msg.msg_control = NULL;
178     msg.msg_controllen = 0;
179     msg.msg_iov = &iov;
180     msg.msg_iovlen = 1;
181     msg.msg_control = NULL;
182     
183     oldfs = get_fs();
184     set_fs(KERNEL_DS);
185     size = sock_recvmsg(packet_state.raw_sock, &msg, len, msg.msg_flags);
186     set_fs(oldfs);
187     
188     return size;
189 }
190
191
192 void
193 send_raw_packet_to_palacios(char * pkt,
194                                int len,
195                                struct v3_vm_info * vm) {
196     struct v3_packet_event event;
197     char data[ETHERNET_PACKET_LEN];
198
199     /* one memory copy */
200     memcpy(data, pkt, len);
201     event.pkt = data;
202     event.size = len;
203         
204     v3_deliver_packet_event(vm, &event);
205 }
206
207 static int packet_server(void * arg) {
208     char pkt[ETHERNET_PACKET_LEN];
209     int size;
210     struct v3_vm_info *vm;
211
212     printk("Palacios Raw Packet Bridge: Staring receiving server\n");
213
214     while (!kthread_should_stop()) {
215         size = recv_pkt(pkt, ETHERNET_PACKET_LEN);
216         if (size < 0) {
217             printk(KERN_WARNING "Palacios raw packet receive error, Server terminated\n");
218             break;
219         }
220
221         if(vnet_debug >= 4){
222             printk("Palacios Packet: receive pkt from NIC (size: %d)\n",size);
223             print_hex_dump(NULL, "pkt_header: ", 0, 10, 10, pkt, 20, 0);
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         if(vm != NULL){
236             printk("Find destinated VM 0x%p\n", vm);
237             send_raw_packet_to_palacios(pkt, size, vm);
238         }
239     }
240
241     return 0;
242 }
243
244
245 int palacios_init_packet(const char * eth_dev) {
246
247     if(packet_state.inited == 0){
248         packet_state.inited = 1;
249
250         if(init_raw_socket(eth_dev) == -1){
251             printk("Error to initiate palacios packet interface\n");
252             return -1;
253         }
254         
255         V3_Init_Packet(&palacios_packet_hooks);
256
257         packet_state.mac_vm_cache = v3_create_htable(0, &hash_fn, &hash_eq);
258
259         packet_state.server_thread = kthread_run(packet_server, NULL, "raw-packet-server");
260     }
261         
262     return 0;
263 }
264
265 void palacios_deinit_packet(const char * eth_dev) {
266
267     kthread_stop(packet_state.server_thread);
268     packet_state.raw_sock->ops->release(packet_state.raw_sock);
269     v3_free_htable(packet_state.mac_vm_cache, 0, 1);
270     packet_state.inited = 0;
271 }
272