2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2011, Lei Xia <lxia@northwestern.edu>
11 * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * This is free software. You are permitted to use, redistribute,
15 * and modify it under the terms of the GNU General Public License
16 * Version 2 (GPLv2). The accompanying COPYING file contains the
17 * full text of the license.
20 * Palacios Raw Packet Interface Implementation
22 #include <asm/uaccess.h>
23 #include <linux/inet.h>
24 #include <linux/kthread.h>
25 #include <linux/netdevice.h>
28 #include <linux/string.h>
29 #include <linux/preempt.h>
30 #include <linux/sched.h>
31 #include <linux/if_packet.h>
32 #include <linux/errno.h>
35 #include <interfaces/vmm_packet.h>
36 #include <palacios/vmm_host_events.h>
37 #include <vnet/vnet.h>
41 #include <palacios/vmm_hashtable.h>
42 #include <palacios/vmm_ethernet.h>
46 #include "linux-exts.h"
48 struct palacios_packet_state {
49 struct socket * raw_sock;
52 struct hashtable * mac_vm_cache;
53 struct task_struct * server_thread;
56 static struct palacios_packet_state packet_state;
58 static inline uint_t hash_fn(addr_t hdr_ptr) {
59 uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
61 return v3_hash_buffer(hdr_buf, ETH_ALEN);
64 static inline int hash_eq(addr_t key1, addr_t key2) {
65 return (memcmp((uint8_t *)key1, (uint8_t *)key2, ETH_ALEN) == 0);
69 static int palacios_packet_add_recver(const char * mac,
70 struct v3_vm_info * vm){
73 key = (char *)kmalloc(ETH_ALEN, GFP_KERNEL);
74 memcpy(key, mac, ETH_ALEN);
76 if (v3_htable_insert(packet_state.mac_vm_cache, (addr_t)key, (addr_t)vm) == 0) {
77 printk("Palacios Packet: Failed to insert new mac entry to the hash table\n");
81 printk("Packet: Add MAC: %2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
86 static int palacios_packet_del_recver(const char * mac,
87 struct v3_vm_info * vm){
92 static int init_raw_socket(const char * eth_dev){
94 struct sockaddr_ll sock_addr;
98 err = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &(packet_state.raw_sock));
101 printk(KERN_WARNING "Could not create a PF_PACKET Socket, err %d\n", err);
105 if (eth_dev == NULL){
106 eth_dev = "eth0"; /* default "eth0" */
109 memset(&if_req, 0, sizeof(if_req));
110 strncpy(if_req.ifr_name, eth_dev, IFNAMSIZ); //sizeof(if_req.ifr_name));
112 err = packet_state.raw_sock->ops->ioctl(packet_state.raw_sock, SIOCGIFINDEX, (long)&if_req);
115 printk(KERN_WARNING "Palacios Packet: Unable to get index for device %s, error %d\n",
116 if_req.ifr_name, err);
117 dev_idx = 2; /* match ALL 2:"eth0" */
119 dev_idx = if_req.ifr_ifindex;
122 printk(KERN_INFO "Palacios Packet: bind to device index: %d\n", dev_idx);
124 memset(&sock_addr, 0, sizeof(sock_addr));
125 sock_addr.sll_family = PF_PACKET;
126 sock_addr.sll_protocol = htons(ETH_P_ALL);
127 sock_addr.sll_ifindex = dev_idx;
129 err = packet_state.raw_sock->ops->bind(packet_state.raw_sock,
130 (struct sockaddr *)&sock_addr,
134 printk(KERN_WARNING "Error binding raw packet to device %s, %d\n", eth_dev, err);
138 printk(KERN_INFO "Bind palacios raw packet interface to device %s\n", eth_dev);
145 palacios_packet_send(const char * pkt, unsigned int len, void * private_data) {
151 iov.iov_base = (void *)pkt;
152 iov.iov_len = (__kernel_size_t)len;
156 msg.msg_control = NULL;
157 msg.msg_controllen = 0;
164 size = sock_sendmsg(packet_state.raw_sock, &msg, len);
172 static struct v3_packet_hooks palacios_packet_hooks = {
173 .send = palacios_packet_send,
174 .add_recver = palacios_packet_add_recver,
175 .del_recver = palacios_packet_del_recver,
180 recv_pkt(char * pkt, int len) {
186 if (packet_state.raw_sock == NULL) {
196 msg.msg_control = NULL;
197 msg.msg_controllen = 0;
200 msg.msg_control = NULL;
204 size = sock_recvmsg(packet_state.raw_sock, &msg, len, msg.msg_flags);
212 send_raw_packet_to_palacios(char * pkt,
214 struct v3_vm_info * vm) {
215 struct v3_packet_event event;
216 char data[ETHERNET_PACKET_LEN];
218 /* one memory copy */
219 memcpy(data, pkt, len);
223 v3_deliver_packet_event(vm, &event);
226 static int packet_server(void * arg) {
227 char pkt[ETHERNET_PACKET_LEN];
229 struct v3_vm_info *vm;
231 printk("Palacios Raw Packet Bridge: Staring receiving server\n");
233 while (!kthread_should_stop()) {
234 size = recv_pkt(pkt, ETHERNET_PACKET_LEN);
237 printk(KERN_WARNING "Palacios raw packet receive error, Server terminated\n");
242 /* if VNET is enabled, send to VNET */
246 /* if it is broadcast or multicase packet */
250 vm = (struct v3_vm_info *)v3_htable_search(packet_state.mac_vm_cache, (addr_t)pkt);
253 printk("Find destinated VM 0x%p\n", vm);
254 send_raw_packet_to_palacios(pkt, size, vm);
262 static int packet_init( void ) {
264 const char * eth_dev = NULL;
266 if (packet_state.inited == 0){
267 packet_state.inited = 1;
269 if (init_raw_socket(eth_dev) == -1){
270 printk("Error to initiate palacios packet interface\n");
274 V3_Init_Packet(&palacios_packet_hooks);
276 packet_state.mac_vm_cache = v3_create_htable(0, &hash_fn, &hash_eq);
278 packet_state.server_thread = kthread_run(packet_server, NULL, "raw-packet-server");
282 // REGISTER GLOBAL CONTROL to add interfaces...
287 static int packet_deinit( void ) {
290 kthread_stop(packet_state.server_thread);
291 packet_state.raw_sock->ops->release(packet_state.raw_sock);
292 v3_free_htable(packet_state.mac_vm_cache, 0, 1);
293 packet_state.inited = 0;
300 static struct linux_ext pkt_ext = {
301 .name = "PACKET_INTERFACE",
303 .deinit = packet_deinit,
309 register_extension(&pkt_ext);