2 * Palacios Raw Packet Interface Implementation
6 #include <asm/uaccess.h>
7 #include <linux/inet.h>
8 #include <linux/kthread.h>
9 #include <linux/netdevice.h>
12 #include <linux/string.h>
13 #include <linux/preempt.h>
14 #include <linux/sched.h>
15 #include <linux/if_packet.h>
16 #include <linux/errno.h>
19 #include <interfaces/vmm_packet.h>
20 #include <palacios/vmm_ethernet.h>
23 #include "util-hashtable.h"
24 #include "linux-exts.h"
28 /* there is one for each host nic */
29 struct raw_interface {
30 char eth_dev[126]; /* host nic name "eth0" ... */
32 struct socket * raw_sock;
35 struct list_head brdcast_recvers;
36 struct hashtable * mac_to_recver;
38 struct task_struct * recv_thread;
40 struct list_head node;
43 struct palacios_packet_state{
46 struct list_head open_interfaces;
49 struct palacios_packet_state packet_state;
51 static inline uint_t hash_fn(addr_t hdr_ptr) {
52 uint8_t * hdr_buf = (uint8_t *)hdr_ptr;
54 return palacios_hash_buffer(hdr_buf, ETH_ALEN);
57 static inline int hash_eq(addr_t key1, addr_t key2) {
58 return (memcmp((uint8_t *)key1, (uint8_t *)key2, ETH_ALEN) == 0);
63 recv_pkt(struct socket * raw_sock, unsigned char * pkt, unsigned int len) {
67 unsigned int size = 0;
69 if (raw_sock == NULL) {
79 msg.msg_control = NULL;
80 msg.msg_controllen = 0;
81 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
85 iov_iter_init(&(msg.msg_iter),WRITE,&iov,1,0);
87 msg.msg_control = NULL;
91 size = sock_recvmsg(raw_sock, &msg, len, msg.msg_flags);
99 init_socket(struct raw_interface * iface, const char * eth_dev){
101 struct sockaddr_ll sock_addr;
102 struct net_device * net_dev;
104 err = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &(iface->raw_sock));
106 WARNING("Could not create a PF_PACKET Socket, err %d\n", err);
110 net_dev = dev_get_by_name(&init_net, eth_dev);
111 if(net_dev == NULL) {
112 WARNING("Palacios Packet: Unable to get index for device %s\n", eth_dev);
113 sock_release(iface->raw_sock);
117 memset(&sock_addr, 0, sizeof(sock_addr));
118 sock_addr.sll_family = PF_PACKET;
119 sock_addr.sll_protocol = htons(ETH_P_ALL);
120 sock_addr.sll_ifindex = net_dev->ifindex;
122 err = iface->raw_sock->ops->bind(iface->raw_sock,
123 (struct sockaddr *)&sock_addr,
127 WARNING("Error binding raw packet to device %s, %d\n", eth_dev, err);
128 sock_release(iface->raw_sock);
133 INFO("Bind a palacios raw packet interface to device %s, device index %d\n",
134 eth_dev, net_dev->ifindex);
141 is_multicast_ethaddr(const unsigned char * addr)
143 return (0x01 & addr[0]);
147 is_broadcast_ethaddr(const unsigned char * addr)
149 unsigned char ret = 0xff;
152 for(i=0; i<ETH_ALEN; i++) {
156 return (ret == 0xff);
159 static int packet_recv_thread( void * arg ) {
162 struct v3_packet * recver_state;
163 struct raw_interface * iface = (struct raw_interface *)arg;
165 pkt = (unsigned char *)palacios_alloc(ETHERNET_PACKET_LEN);
168 ERROR("Unable to allocate packet in vnet receive thread\n");
172 INFO("Palacios Raw Packet Bridge: Staring receiving on ethernet device %s\n",
175 while (!kthread_should_stop()) {
176 size = recv_pkt(iface->raw_sock, pkt, ETHERNET_PACKET_LEN);
179 WARNING("Palacios raw packet receive error, Server terminated\n");
183 if(is_broadcast_ethaddr(pkt)) {
186 list_for_each_entry(recver_state, &(iface->brdcast_recvers), node) {
187 recver_state->input(recver_state, pkt, size);
190 } else if(is_multicast_ethaddr(pkt)) {
194 recver_state = (struct v3_packet *)palacios_htable_search(iface->mac_to_recver,
196 if(recver_state != NULL) {
197 recver_state->input(recver_state, pkt, size);
207 init_raw_interface(struct raw_interface * iface, const char * eth_dev){
209 memcpy(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN);
210 if(init_socket(iface, eth_dev) !=0) {
211 WARNING("packet: fails to initiate raw socket\n");
216 INIT_LIST_HEAD(&(iface->brdcast_recvers));
217 iface->mac_to_recver = palacios_create_htable(0, &hash_fn, &hash_eq);
218 iface->recv_thread = kthread_run(packet_recv_thread, (void *)iface, "bridge-recver");
226 deinit_raw_interface(struct raw_interface * iface){
227 struct v3_packet * recver_state, * tmp_state;
229 kthread_stop(iface->recv_thread);
230 sock_release(iface->raw_sock);
231 palacios_free_htable(iface->mac_to_recver, 0, 0);
233 list_for_each_entry_safe(recver_state, tmp_state, &(iface->brdcast_recvers), node) {
234 palacios_free(recver_state);
239 static inline struct raw_interface *
240 find_interface(const char * eth_dev) {
241 struct raw_interface * iface;
243 list_for_each_entry(iface, &(packet_state.open_interfaces), node) {
244 if (strncmp(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN) == 0) {
254 palacios_packet_connect(struct v3_packet * packet,
255 const char * host_nic,
256 void * host_vm_data) {
257 struct raw_interface * iface;
260 palacios_spinlock_lock_irqsave(&(packet_state.lock), flags);
261 iface = find_interface(host_nic);
262 palacios_spinlock_unlock_irqrestore(&(packet_state.lock),flags);
265 iface = (struct raw_interface *)palacios_alloc(sizeof(struct raw_interface));
267 ERROR("Palacios Packet Interface: Fails to allocate interface\n");
270 if(init_raw_interface(iface, host_nic) != 0) {
271 ERROR("Palacios Packet Interface: Fails to initiate an raw interface on device %s\n", host_nic);
272 palacios_free(iface);
275 palacios_spinlock_lock_irqsave(&(packet_state.lock), flags);
276 list_add(&(iface->node), &(packet_state.open_interfaces));
277 palacios_spinlock_unlock_irqrestore(&(packet_state.lock),flags);
280 packet->host_packet_data = iface;
282 list_add(&(packet->node), &(iface->brdcast_recvers));
283 palacios_htable_insert(iface->mac_to_recver,
284 (addr_t)packet->dev_mac,
287 INFO("Packet: Add Receiver MAC to ethernet device %s: %2x:%2x:%2x:%2x:%2x:%2x\n",
289 packet->dev_mac[0], packet->dev_mac[1],
290 packet->dev_mac[2], packet->dev_mac[3],
291 packet->dev_mac[4], packet->dev_mac[5]);
297 palacios_packet_send(struct v3_packet * packet,
300 struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
306 if(iface->inited == 0 ||
307 iface->raw_sock == NULL){
308 ERROR("Palacios Packet Interface: Send fails due to inapproriate interface\n");
312 iov.iov_base = (void *)pkt;
313 iov.iov_len = (__kernel_size_t)len;
315 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
319 iov_iter_init(&(msg.msg_iter),WRITE,&iov,1,0);
321 msg.msg_control = NULL;
322 msg.msg_controllen = 0;
329 size = sock_sendmsg(iface->raw_sock, &msg, len);
337 palacios_packet_close(struct v3_packet * packet) {
338 struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
340 list_del(&(packet->node));
341 palacios_htable_remove(iface->mac_to_recver, (addr_t)(packet->dev_mac), 0);
343 packet->host_packet_data = NULL;
347 static struct v3_packet_hooks palacios_packet_hooks = {
348 .connect = palacios_packet_connect,
349 .send = palacios_packet_send,
350 .close = palacios_packet_close,
353 static int packet_init( void ) {
354 V3_Init_Packet(&palacios_packet_hooks);
356 memset(&packet_state, 0, sizeof(struct palacios_packet_state));
357 palacios_spinlock_init(&(packet_state.lock));
358 INIT_LIST_HEAD(&(packet_state.open_interfaces));
360 // REGISTER GLOBAL CONTROL to add interfaces...
365 static int packet_deinit( void ) {
366 struct raw_interface * iface, * tmp;
368 list_for_each_entry_safe(iface, tmp, &(packet_state.open_interfaces), node) {
369 deinit_raw_interface(iface);
370 palacios_free(iface);
373 palacios_spinlock_deinit(&(packet_state.lock));
378 static struct linux_ext pkt_ext = {
379 .name = "PACKET_INTERFACE",
381 .deinit = packet_deinit,
387 register_extension(&pkt_ext);