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.


removed BKL acquisition from daemonization of kernel threads in linux module
[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
82     if (err < 0) {
83         printk(KERN_WARNING "Could not create a PF_PACKET Socket, err %d\n", err);
84         return -1;
85     }
86
87     if (eth_dev == NULL){
88         eth_dev = "eth0"; /* default "eth0" */
89     }
90
91     memset(&if_req, 0, sizeof(if_req));
92     strncpy(if_req.ifr_name, eth_dev, IFNAMSIZ);  //sizeof(if_req.ifr_name));
93
94     err = packet_state.raw_sock->ops->ioctl(packet_state.raw_sock, SIOCGIFINDEX, (long)&if_req);
95
96     if (err < 0){
97         printk(KERN_WARNING "Palacios Packet: Unable to get index for device %s, error %d\n", 
98                if_req.ifr_name, err);
99         dev_idx = 2; /* match ALL  2:"eth0" */
100     } else {
101         dev_idx = if_req.ifr_ifindex;
102     }
103
104     printk(KERN_INFO "Palacios Packet: bind to device index: %d\n", dev_idx);
105
106     memset(&sock_addr, 0, sizeof(sock_addr));
107     sock_addr.sll_family = PF_PACKET;
108     sock_addr.sll_protocol = htons(ETH_P_ALL);
109     sock_addr.sll_ifindex = dev_idx;
110
111     err = packet_state.raw_sock->ops->bind(packet_state.raw_sock, 
112                                            (struct sockaddr *)&sock_addr, 
113                                            sizeof(sock_addr));
114
115     if (err < 0){
116         printk(KERN_WARNING "Error binding raw packet to device %s, %d\n", eth_dev, err);
117         return -1;
118     }
119
120     printk(KERN_INFO "Bind palacios raw packet interface to device %s\n", eth_dev);
121
122     return 0;
123 }
124
125
126 static int
127 palacios_packet_send(const char * pkt, unsigned int len, void * private_data) {
128     struct msghdr msg;
129     struct iovec iov;
130     mm_segment_t oldfs;
131     int size = 0;       
132         
133     iov.iov_base = (void *)pkt;
134     iov.iov_len = (__kernel_size_t)len;
135
136     msg.msg_iov = &iov;
137     msg.msg_iovlen = 1;
138     msg.msg_control = NULL;
139     msg.msg_controllen = 0;
140     msg.msg_name = NULL;
141     msg.msg_namelen = 0;
142     msg.msg_flags = 0;
143
144     oldfs = get_fs();
145     set_fs(KERNEL_DS);
146     size = sock_sendmsg(packet_state.raw_sock, &msg, len);
147     set_fs(oldfs);
148
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 static 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
218         if (size < 0) {
219             printk(KERN_WARNING "Palacios raw packet receive error, Server terminated\n");
220             break;
221         }
222
223
224         /* if VNET is enabled, send to VNET */
225         // ...
226
227
228         /* if it is broadcast or multicase packet */
229         // ...
230
231
232         vm = (struct v3_vm_info *)v3_htable_search(packet_state.mac_vm_cache, (addr_t)pkt);
233
234         if (vm != NULL){
235             printk("Find destinated VM 0x%p\n", vm);
236             send_raw_packet_to_palacios(pkt, size, vm);
237         }
238     }
239
240     return 0;
241 }
242
243
244 static int packet_init( void ) {
245
246     const char * eth_dev = NULL;
247
248     if (packet_state.inited == 0){
249         packet_state.inited = 1;
250
251         if (init_raw_socket(eth_dev) == -1){
252             printk("Error to initiate palacios packet interface\n");
253             return -1;
254         }
255         
256         V3_Init_Packet(&palacios_packet_hooks);
257
258         packet_state.mac_vm_cache = v3_create_htable(0, &hash_fn, &hash_eq);
259
260         packet_state.server_thread = kthread_run(packet_server, NULL, "raw-packet-server");
261     }
262         
263
264     // REGISTER GLOBAL CONTROL to add interfaces...
265
266     return 0;
267 }
268
269 static int packet_deinit( void ) {
270
271
272     kthread_stop(packet_state.server_thread);
273     packet_state.raw_sock->ops->release(packet_state.raw_sock);
274     v3_free_htable(packet_state.mac_vm_cache, 0, 1);
275     packet_state.inited = 0;
276
277     return 0;
278 }
279
280
281
282 static struct linux_ext pkt_ext = {
283     .name = "PACKET_INTERFACE",
284     .init = packet_init,
285     .deinit = packet_deinit,
286     .guest_init = NULL,
287     .guest_deinit = NULL
288 };
289
290
291 register_extension(&pkt_ext);