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