📄 vnet.c
字号:
/* * VNET - Virtual Net Switch device driver. * Copyright (C) 2003 * Skyeye Develop Group <skyeye-developer@lists.sf.linuxforum.net> * Chen Yu <chenyu@hpclab.cs.tsinghua.edu.cn> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * $Id: vnet.c,v 1.7 2003/06/06 13:28:49 chenyu Exp $ *//* * 06/05/2003 vnet 0.2.0 * Chen Yu <chenyu@hpclab.cs.tsinghua.edu.cn> */#define VNET_VER "0.2.0"#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/fcntl.h>#include <linux/init.h>#include <linux/random.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/miscdevice.h>#include <linux/rtnetlink.h>#include <linux/if.h>#include <linux/if_arp.h>#include <linux/if_ether.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/proc_fs.h>#include <linux/file.h>//#include <linux/if_tun.h>#include "if_vnet.h"#ifdef VNET_DEBUG//static int debug;#endif//global datastatic struct vnet_hub *vnetHub[VNET_NUM_HUBS];spinlock_t vnet_nutLock;spinlock_t vnet_boltLock ;static struct proc_dir_entry *vnet_procfs_base = NULL;struct vnet_bolt * vnet_bolthead;// function declare/********************vnet_chr_...*************/static int vnet_chr_close(struct inode *inode, struct file *file);static int vnet_chr_fasync(int fd, struct file *file, int on);static int vnet_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int vnet_chr_open(struct inode *inode, struct file * file);static unsigned int vnet_chr_poll(struct file *file, poll_table * wait);static ssize_t vnet_chr_read(struct file * file, char * buf, size_t count, loff_t *pos);//static ssize_t vnet_chr_readv(struct file *file, const struct iovec *iv,// unsigned long count, loff_t *pos);static ssize_t vnet_chr_write(struct file * file, const char * buf, size_t count, loff_t *pos);//static ssize_t vnet_chr_writev(struct file * file, const struct iovec *iv, // unsigned long count, loff_t *pos);/********************vnet_hostif_...*************/static int vnet_hostif_open(struct net_device *dev);;int vnet_hostif_init(struct net_device *dev);static int vnet_hostif_close(struct net_device *dev);static void vnet_hostif_mclist(struct net_device *dev);static struct net_device_stats *vnet_hostif_stats(struct net_device *dev);static int vnet_hostif_xmit(struct sk_buff *skb, struct net_device *dev);static void vnet_hostif_recv(struct vnet_nut *nut, struct sk_buff *skb);static int vnet_hostif_create(struct inode *inode, struct file *file, struct ifreq *ifr);void vnet_hostif_free(struct vnet_nut *this);int vnet_hostif_procread(char *page,char **start,off_t off,int count,int *eof,void *data); /********************vnet_guestif_...*************/int vnet_guestif_create(struct vnet_bolt **ret);void vnet_guestif_free(struct vnet_guestif *gif);//int vnet_guestif_ioctl(struct vnet_guestif *gif,int vnet_guestif_ioctl(struct vnet_bolt *bolt, struct file *filp, unsigned int iocmd, unsigned long ioarg);//int vnet_guestif_poll(struct vnet_guestif *gif,int vnet_guestif_poll(struct vnet_bolt *bolt, struct file *filp, poll_table *wait);//int vnet_guestif_read(struct vnet_guestif *gif,struct file *filp, char *buf, size_t count);int vnet_guestif_read(struct vnet_bolt *bolt,struct file *filp, char *buf, size_t count);void vnet_guestif_recv(struct vnet_nut *this,struct sk_buff *skb);//int vnet_guestif_write(struct vnet_guestif *gif,struct file *filp, const char *buf, size_t count);int vnet_guestif_write(struct vnet_bolt *bolt,struct file *filp, const char *buf, size_t count);void vnet_gusetif_free(struct vnet_nut *this);int vnet_guestif_procread(char *page,char **start,off_t off,int count,int *eof,void *data); /********************vnet_nut_...*************/static void vnet_nut_release(struct vnet_nut *nut);/********************vnet_bolt_...*************/static void vnet_bolt_addtolist(struct vnet_bolt *bolt);static void vnet_bolt_removefromlist(struct vnet_bolt *bolt);static int vnet_bolt_print(struct vnet_bolt *bolt, char * buf);/********************vnet_hub_...*************/struct vnet_nut * vnet_hub_alloc_nut(int hubnum);static void vnet_hub_boltschanged(struct vnet_nut *nut);int vnet_hub_connect(struct vnet_bolt *bolt, struct vnet_nut *nut);struct vnet_nut* vnet_hub_disconnect(struct vnet_nut *nut);static Bool vnet_hub_cycledetect(struct vnet_nut *nut, int generation);static int vnet_hub_getattachednuts(struct vnet_nut *nut);static Bool vnet_hub_grabnuts(struct vnet_nut *nut);void vnet_hub_init(void);static int vnet_hub_isbridged(struct vnet_nut *nut);static void vnet_hub_free_nut(struct vnet_nut *nut);void vnet_hub_recv(struct vnet_nut *nut, struct sk_buff *skb); //--------------------------------------------------------/* *---------------------------------------------------------------------- * * VNetMulticastFilter -- * * Utility function that filters multicast packets according * to a 64-bit logical address filter (like the one on the * lance chipset). AllMultiFilter lets all packets through. * * We generate a hash value from the destination MAC address * and see if it's in our filter. Broadcast packets have * already OK'd by PacketMatch, so we don't have to worry * about that. * * (This is in the green AMD "Ethernet Controllers" book, * page 1-53.) * * Results: * TRUE if packet is in filter, FALSE if not. * * Side effects: * None. * *---------------------------------------------------------------------- */#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian *///chy: should change in future !!!!Bool vnet_multicastfilter(uint8 *destAddr, uint8 *ladrf){ uint16 hashcode; int32 crc, poly = CRC_POLYNOMIAL_BE; int j, bit, byte; crc = 0xffffffff; /* init CRC for each address */ for (byte=0; byte<6; byte++) { /* for each address byte */ /* process each address bit */ for (bit = *destAddr++,j=0;j<8;j++, bit>>=1) { crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0); } } hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */ for (j=0; j<5; j++) { /* ... in reverse order. */ hashcode = (hashcode << 1) | ((crc>>=1) & 1); } byte = hashcode >> 3; /* bit[3-5] -> byte in filter */ bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ if (ladrf[byte] & bit) { return TRUE; } else { return FALSE; }}Bool vnet_packetmatch(uint8 *destAddr, uint8 *ifAddr, uint8 *ladrf, uint32 flags){ static uint8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; return ((flags & IFF_PROMISC) || VNET_MAC_EQ(destAddr, ifAddr) || ((flags & IFF_BROADCAST) && VNET_MAC_EQ(destAddr, broadcast)) || ((destAddr[0] & 0x1) && (flags & IFF_ALLMULTI || // allow all multi (flags & IFF_MULTICAST && vnet_multicastfilter(destAddr, ladrf)))));}int vnet_procfs_makeentry(struct proc_dir_entry *parent, char *name, int mode, struct proc_dir_entry **ret){ struct proc_dir_entry *ent; //int retval; if (!parent) { parent = vnet_procfs_base; } ent = create_proc_entry(name, mode, parent); *ret = ent; if (!ent) return -ENOMEM; return 0;}/* *---------------------------------------------------------------------- * * VNetProc_RemoveEntry -- * * Remove a previously installed proc entry. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */void vnet_procfs_removeentry(struct proc_dir_entry *node, struct proc_dir_entry *parent){ if (!parent) { parent = vnet_procfs_base; } if (node) { remove_proc_entry(node->name, parent); }}void vnet_procfs_cleanup(void){ vnet_procfs_removeentry(vnet_procfs_base, &proc_root); vnet_procfs_base = NULL;}int vnet_procfs_init(void){ int retval; retval = vnet_procfs_makeentry(&proc_root, "vnet", S_IFDIR, &vnet_procfs_base); return retval; }/* Network device part of the driver *//* Net device open. */static int vnet_hostif_open(struct net_device *dev){ netif_start_queue(dev); return 0;}/* Net device close. */static int vnet_hostif_close(struct net_device *dev){ netif_stop_queue(dev); return 0;}static void vnet_hostif_recv(struct vnet_nut *nut, struct sk_buff *skb){ struct vnet_hostif *hif=(struct vnet_hostif *)nut->private; skb->dev=&hif->dev; skb->protocol=eth_type_trans(skb, &hif->dev); netif_rx_ni(skb); hif->stats.rx_packets++; return;}/* Net device start xmit */static int vnet_hostif_xmit(struct sk_buff *skb, struct net_device *dev){ struct vnet_hostif *hif = (struct vnet_hostif *)dev->priv; struct vnet_nut *peer; DBG(KERN_INFO "vnet: vnet_hostif_xmit begin\n"); /* Drop packet if interface is not attached */ if (!hif->attached) goto drop; /* Queue packet */ /* if (skb_queue_len(&vnet->readq) >= dev->tx_queue_len) goto drop; */ peer=hif->bolt.nut.peer; if(!peer||!peer->rcv){ printk("vnet: vnet_hostif_xmit gif->bolt.nut.peer or peer->rcv is NULL!!!\n"); return -EFAULT; } peer->rcv(peer, skb); hif->stats.tx_packets++; DBG(KERN_INFO "vnet: vnet_hostif_xmit end\n"); return 0;drop: hif->stats.tx_dropped++; kfree_skb(skb); return 0;}static void vnet_hostif_mclist(struct net_device *dev){ /* Nothing to do for multicast filters. * We always accept all frames. */ printk(KERN_INFO "vnet: vnet_hostif_mclist isn't realized yet!!!!\n"); return;}int vnet_hostif_procread(char *page, // IN/OUT: buffer to write into char **start, // OUT: 0 if file < 4k, else offset into page off_t off, // IN: offset of read into the file int count, // IN: maximum number of bytes to read int *eof, // OUT: TRUE if there is nothing more to read void *data) // IN: client data - not used{ struct vnet_hostif *hif = (struct vnet_hostif *)data; int len = 0; if(!hif){ printk("vnet: vnet_hostif_procread hif is NULL!!!\n"); return 0; } len += vnet_bolt_print(&hif->bolt, page+len); len += sprintf(page+len, "\n"); *start = 0; *eof = 1; return len;}static struct net_device_stats *vnet_hostif_stats(struct net_device *dev){ struct vnet_hostif *hif = (struct vnet_hostif *)dev->priv; return &hif->stats;}/* Initialize net device. */int vnet_hostif_init(struct net_device *dev){ struct vnet_hostif *hif = (struct vnet_hostif *)dev->priv; DBG(KERN_INFO "vnet: %s: vnet_hostif_init begin\n", hif->dev.name); SET_MODULE_OWNER(dev); dev->open = vnet_hostif_open; dev->hard_start_xmit = vnet_hostif_xmit; dev->stop = vnet_hostif_close; dev->get_stats = vnet_hostif_stats; switch (hif->flags & VNET_TYPE_MASK) { case VNET_VNET_DEV: /* Ethernet TAP Device */ dev->set_multicast_list = vnet_hostif_mclist; /* Generate random Ethernet address. */ *(u16 *)dev->dev_addr = htons(0x00FF); get_random_bytes(dev->dev_addr + sizeof(u16), 4); ether_setup(dev); memcpy(hif->bolt.paddr,dev->dev_addr,ETH_ALEN); break; default: printk(KERN_INFO "vnet: vnet_hostif_init unknonw flags\n"); return -EINVAL; }; return 0;}/* Character device part *//* Poll */static unsigned int vnet_chr_poll(struct file *file, poll_table * wait){ struct vnet_guestif *gif = (struct vnet_guestif *)file->private_data; struct vnet_bolt *bolt; unsigned int mask; //DBG(KERN_INFO "vnet_chr_poll begin\n"); if (!gif) return -EBADFD; bolt=&(gif->bolt); mask=vnet_guestif_poll(bolt, file, wait); //DBG(KERN_INFO "vnet_chr_poll end\n"); return mask;}/* Get packet from user space buffer(already verified) */static __inline__ ssize_t vnet_get_user(struct vnet_struct *vnet, struct iovec *iv, size_t count){ struct vnet_pi pi = { 0, __constant_htons(ETH_P_IP) }; struct sk_buff *skb; size_t len = count; if (!(vnet->flags & VNET_NO_PI)) { if ((len -= sizeof(pi)) < 0) return -EINVAL; memcpy_fromiovec((void *)&pi, iv, sizeof(pi)); } if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { vnet->stats.rx_dropped++; return -ENOMEM; } skb_reserve(skb, 2); memcpy_fromiovec(skb_put(skb, len), iv, len); skb->dev = &vnet->dev; switch (vnet->flags & VNET_TYPE_MASK) { case VNET_VNET_DEV: skb->mac.raw = skb->data; skb->protocol = pi.proto; break; case VNET_TAP_DEV: skb->protocol = eth_type_trans(skb, &vnet->dev); break; }; if (vnet->flags & VNET_NOCHECKSUM) skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx_ni(skb); vnet->stats.rx_packets++; vnet->stats.rx_bytes += len; return count;} /* Write */static ssize_t vnet_chr_write(struct file * file, const char * buf, size_t count, loff_t *pos){ struct vnet_guestif *gif = (struct vnet_guestif *)file->private_data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -