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.


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