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;
83 msg.msg_control = NULL;
87 size = sock_recvmsg(raw_sock, &msg, len, msg.msg_flags);
95 init_socket(struct raw_interface * iface, const char * eth_dev){
97 struct sockaddr_ll sock_addr;
98 struct net_device * net_dev;
100 err = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &(iface->raw_sock));
102 WARNING("Could not create a PF_PACKET Socket, err %d\n", err);
106 net_dev = dev_get_by_name(&init_net, eth_dev);
107 if(net_dev == NULL) {
108 WARNING("Palacios Packet: Unable to get index for device %s\n", eth_dev);
109 sock_release(iface->raw_sock);
113 memset(&sock_addr, 0, sizeof(sock_addr));
114 sock_addr.sll_family = PF_PACKET;
115 sock_addr.sll_protocol = htons(ETH_P_ALL);
116 sock_addr.sll_ifindex = net_dev->ifindex;
118 err = iface->raw_sock->ops->bind(iface->raw_sock,
119 (struct sockaddr *)&sock_addr,
123 WARNING("Error binding raw packet to device %s, %d\n", eth_dev, err);
124 sock_release(iface->raw_sock);
129 INFO("Bind a palacios raw packet interface to device %s, device index %d\n",
130 eth_dev, net_dev->ifindex);
137 is_multicast_ethaddr(const unsigned char * addr)
139 return (0x01 & addr[0]);
143 is_broadcast_ethaddr(const unsigned char * addr)
145 unsigned char ret = 0xff;
148 for(i=0; i<ETH_ALEN; i++) {
152 return (ret == 0xff);
155 static int packet_recv_thread( void * arg ) {
158 struct v3_packet * recver_state;
159 struct raw_interface * iface = (struct raw_interface *)arg;
161 pkt = (unsigned char *)palacios_alloc(ETHERNET_PACKET_LEN);
164 ERROR("Unable to allocate packet in vnet receive thread\n");
168 INFO("Palacios Raw Packet Bridge: Staring receiving on ethernet device %s\n",
171 while (!kthread_should_stop()) {
172 size = recv_pkt(iface->raw_sock, pkt, ETHERNET_PACKET_LEN);
175 WARNING("Palacios raw packet receive error, Server terminated\n");
179 if(is_broadcast_ethaddr(pkt)) {
182 list_for_each_entry(recver_state, &(iface->brdcast_recvers), node) {
183 recver_state->input(recver_state, pkt, size);
186 } else if(is_multicast_ethaddr(pkt)) {
190 recver_state = (struct v3_packet *)palacios_htable_search(iface->mac_to_recver,
192 if(recver_state != NULL) {
193 recver_state->input(recver_state, pkt, size);
203 init_raw_interface(struct raw_interface * iface, const char * eth_dev){
205 memcpy(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN);
206 if(init_socket(iface, eth_dev) !=0) {
207 WARNING("packet: fails to initiate raw socket\n");
212 INIT_LIST_HEAD(&(iface->brdcast_recvers));
213 iface->mac_to_recver = palacios_create_htable(0, &hash_fn, &hash_eq);
214 iface->recv_thread = kthread_run(packet_recv_thread, (void *)iface, "bridge-recver");
222 deinit_raw_interface(struct raw_interface * iface){
223 struct v3_packet * recver_state, * tmp_state;
225 kthread_stop(iface->recv_thread);
226 sock_release(iface->raw_sock);
227 palacios_free_htable(iface->mac_to_recver, 0, 0);
229 list_for_each_entry_safe(recver_state, tmp_state, &(iface->brdcast_recvers), node) {
230 palacios_free(recver_state);
235 static inline struct raw_interface *
236 find_interface(const char * eth_dev) {
237 struct raw_interface * iface;
239 list_for_each_entry(iface, &(packet_state.open_interfaces), node) {
240 if (strncmp(iface->eth_dev, eth_dev, V3_ETHINT_NAMELEN) == 0) {
250 palacios_packet_connect(struct v3_packet * packet,
251 const char * host_nic,
252 void * host_vm_data) {
253 struct raw_interface * iface;
256 palacios_spinlock_lock_irqsave(&(packet_state.lock), flags);
257 iface = find_interface(host_nic);
258 palacios_spinlock_unlock_irqrestore(&(packet_state.lock),flags);
261 iface = (struct raw_interface *)palacios_alloc(sizeof(struct raw_interface));
263 ERROR("Palacios Packet Interface: Fails to allocate interface\n");
266 if(init_raw_interface(iface, host_nic) != 0) {
267 ERROR("Palacios Packet Interface: Fails to initiate an raw interface on device %s\n", host_nic);
268 palacios_free(iface);
271 palacios_spinlock_lock_irqsave(&(packet_state.lock), flags);
272 list_add(&(iface->node), &(packet_state.open_interfaces));
273 palacios_spinlock_unlock_irqrestore(&(packet_state.lock),flags);
276 packet->host_packet_data = iface;
278 list_add(&(packet->node), &(iface->brdcast_recvers));
279 palacios_htable_insert(iface->mac_to_recver,
280 (addr_t)packet->dev_mac,
283 INFO("Packet: Add Receiver MAC to ethernet device %s: %2x:%2x:%2x:%2x:%2x:%2x\n",
285 packet->dev_mac[0], packet->dev_mac[1],
286 packet->dev_mac[2], packet->dev_mac[3],
287 packet->dev_mac[4], packet->dev_mac[5]);
293 palacios_packet_send(struct v3_packet * packet,
296 struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
302 if(iface->inited == 0 ||
303 iface->raw_sock == NULL){
304 ERROR("Palacios Packet Interface: Send fails due to inapproriate interface\n");
308 iov.iov_base = (void *)pkt;
309 iov.iov_len = (__kernel_size_t)len;
313 msg.msg_control = NULL;
314 msg.msg_controllen = 0;
321 size = sock_sendmsg(iface->raw_sock, &msg, len);
329 palacios_packet_close(struct v3_packet * packet) {
330 struct raw_interface * iface = (struct raw_interface *)packet->host_packet_data;
332 list_del(&(packet->node));
333 palacios_htable_remove(iface->mac_to_recver, (addr_t)(packet->dev_mac), 0);
335 packet->host_packet_data = NULL;
339 static struct v3_packet_hooks palacios_packet_hooks = {
340 .connect = palacios_packet_connect,
341 .send = palacios_packet_send,
342 .close = palacios_packet_close,
345 static int packet_init( void ) {
346 V3_Init_Packet(&palacios_packet_hooks);
348 memset(&packet_state, 0, sizeof(struct palacios_packet_state));
349 palacios_spinlock_init(&(packet_state.lock));
350 INIT_LIST_HEAD(&(packet_state.open_interfaces));
352 // REGISTER GLOBAL CONTROL to add interfaces...
357 static int packet_deinit( void ) {
358 struct raw_interface * iface, * tmp;
360 list_for_each_entry_safe(iface, tmp, &(packet_state.open_interfaces), node) {
361 deinit_raw_interface(iface);
362 palacios_free(iface);
365 palacios_spinlock_deinit(&(packet_state.lock));
370 static struct linux_ext pkt_ext = {
371 .name = "PACKET_INTERFACE",
373 .deinit = packet_deinit,
379 register_extension(&pkt_ext);