Signed-off-by: Jose Renato Santos # HG changeset patch # User jsantos@hpl.hp.com # Node ID caffde2df66580dfcb606bcd2b032dfd7e0b72b7 # Parent 10582388adb5ad9db189804a5b8553ac2ab584f0 Add direct mapping of virtual network devices to physiscal interfaces in netback. An alternative to using bridge diff -r 10582388adb5 -r caffde2df665 linux-2.6-xen-sparse/drivers/xen/netback/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/netback/Makefile Tue Aug 29 08:10:12 2006 -0700 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/Makefile Tue Aug 29 14:16:32 2006 -0700 @@ -1,5 +1,5 @@ obj-$(CONFIG_XEN_NETDEV_BACKEND) := netb obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o obj-$(CONFIG_XEN_NETDEV_LOOPBACK) += netloop.o -netbk-y := netback.o xenbus.o interface.o +netbk-y := netback.o xenbus.o interface.o vifdevmap.o netloop-y := loopback.o diff -r 10582388adb5 -r caffde2df665 linux-2.6-xen-sparse/drivers/xen/netback/common.h --- a/linux-2.6-xen-sparse/drivers/xen/netback/common.h Tue Aug 29 08:10:12 2006 -0700 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/common.h Tue Aug 29 14:16:32 2006 -0700 @@ -55,12 +55,25 @@ #define WPRINTK(fmt, args...) \ printk(KERN_WARNING "xen_net: " fmt, ##args) +#define VIF_HASH_BITS 8 +#define VIF_HASH_SIZE (1 << VIF_HASH_BITS) + +typedef struct vifdevmap_st { + struct net_device *pdev; + u8 pmac[ETH_ALEN]; + int n_netif; + struct list_head list; + struct list_head hash[VIF_HASH_SIZE]; + spinlock_t netif_list_lock; + unsigned int refcnt; +} vifdevmap_t; + typedef struct netif_st { /* Unique identifier for this interface. */ domid_t domid; unsigned int handle; - u8 fe_dev_addr[6]; + u8 fe_dev_addr[ETH_ALEN]; /* Physical parameters of the comms window. */ grant_handle_t tx_shmem_handle; @@ -94,11 +107,15 @@ typedef struct netif_st { /* Miscellaneous private stuff. */ struct list_head list; /* scheduling list */ + struct list_head hashlist; /* hash list on vifdevmap */ atomic_t refcnt; struct net_device *dev; struct net_device_stats stats; wait_queue_head_t waiting_to_free; + + /* Map of virtual interfaces to physical devices */ + vifdevmap_t *vifdevmap; } netif_t; #define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) @@ -106,7 +123,8 @@ typedef struct netif_st { void netif_disconnect(netif_t *netif); -netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN]); +netif_t *netif_alloc(domid_t domid, unsigned int handle, + u8 be_mac[ETH_ALEN], char *pdevname); int netif_map(netif_t *netif, unsigned long tx_ring_ref, unsigned long rx_ring_ref, unsigned int evtchn); @@ -138,4 +156,12 @@ static inline int netbk_can_sg(struct ne return netif->features & NETIF_F_SG; } +void vifdevmap_init(void); +vifdevmap_t *vifdevmap_get(char* pdevname); +void vifdevmap_put(vifdevmap_t *vifdevmap); +vifdevmap_t *vifdevmap_find(struct net_device *pdev); +void vifdevmap_add_netif(netif_t *netif); +void vifdevmap_remove_netif(netif_t *netif); +void vifdevmap_guest_packet(struct sk_buff *skb, netif_t *netif); + #endif /* __NETIF__BACKEND__COMMON_H__ */ diff -r 10582388adb5 -r caffde2df665 linux-2.6-xen-sparse/drivers/xen/netback/interface.c --- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c Tue Aug 29 08:10:12 2006 -0700 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c Tue Aug 29 14:16:32 2006 -0700 @@ -107,7 +107,8 @@ static struct ethtool_ops network_ethtoo .get_link = ethtool_op_get_link, }; -netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN]) +netif_t *netif_alloc(domid_t domid, unsigned int handle, + u8 be_mac[ETH_ALEN], char *pdevname) { int err = 0, i; struct net_device *dev; @@ -130,6 +131,7 @@ netif_t *netif_alloc(domid_t domid, unsi atomic_set(&netif->refcnt, 1); init_waitqueue_head(&netif->waiting_to_free); netif->dev = dev; + netif->vifdevmap = NULL; netif->credit_bytes = netif->remaining_credit = ~0UL; netif->credit_usec = 0UL; @@ -175,6 +177,10 @@ netif_t *netif_alloc(domid_t domid, unsi return ERR_PTR(err); } + if (pdevname) { + netif->vifdevmap = vifdevmap_get(pdevname); + } + DPRINTK("Successfully created netif\n"); return netif; } @@ -308,6 +314,8 @@ err_rx: static void netif_free(netif_t *netif) { + vifdevmap_remove_netif(netif); + atomic_dec(&netif->refcnt); wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0); diff -r 10582388adb5 -r caffde2df665 linux-2.6-xen-sparse/drivers/xen/netback/netback.c --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c Tue Aug 29 08:10:12 2006 -0700 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c Tue Aug 29 14:16:32 2006 -0700 @@ -1293,7 +1293,7 @@ static void net_tx_action(unsigned long netif->stats.rx_bytes += skb->len; netif->stats.rx_packets++; - netif_rx(skb); + vifdevmap_guest_packet(skb, netif); netif->dev->last_rx = jiffies; } } @@ -1477,6 +1477,8 @@ static int __init netback_init(void) spin_lock_init(&net_schedule_list_lock); INIT_LIST_HEAD(&net_schedule_list); + vifdevmap_init(); + netif_xenbus_init(); #ifdef NETBE_DEBUG_INTERRUPT diff -r 10582388adb5 -r caffde2df665 linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c --- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Tue Aug 29 08:10:12 2006 -0700 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Tue Aug 29 14:16:32 2006 -0700 @@ -42,6 +42,8 @@ static void backend_changed(struct xenbu static void backend_changed(struct xenbus_watch *, const char **, unsigned int); +static int xen_net_read_mac(struct xenbus_device *dev, char *name, u8 mac[]); + static int netback_remove(struct xenbus_device *dev) { struct backend_info *be = dev->dev.driver_data; @@ -52,7 +54,10 @@ static int netback_remove(struct xenbus_ be->backend_watch.node = NULL; } if (be->netif) { + vifdevmap_t *vifdevmap = be->netif->vifdevmap; netif_disconnect(be->netif); + if (vifdevmap) + vifdevmap_put(vifdevmap); be->netif = NULL; } kfree(be); @@ -204,8 +209,19 @@ static void backend_changed(struct xenbu if (be->netif == NULL) { u8 be_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - - be->netif = netif_alloc(dev->otherend_id, handle, be_mac); + char *pdevname; + + pdevname = xenbus_read(XBT_NIL, dev->nodename, "pdev", NULL); + if (IS_ERR(pdevname)) { + pdevname = NULL; + } + + be->netif = netif_alloc(dev->otherend_id, handle, + be_mac, pdevname); + + if (pdevname) + kfree (pdevname); + if (IS_ERR(be->netif)) { err = PTR_ERR(be->netif); be->netif = NULL; @@ -320,12 +336,12 @@ static void xen_net_read_rate(struct xen kfree(ratestr); } -static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[]) +static int xen_net_read_mac(struct xenbus_device *dev, char *name, u8 mac[]) { char *s, *e, *macstr; int i; - macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL); + macstr = s = xenbus_read(XBT_NIL, dev->nodename, name, NULL); if (IS_ERR(macstr)) return PTR_ERR(macstr); @@ -351,7 +367,7 @@ static void connect(struct backend_info if (err) return; - err = xen_net_read_mac(dev, be->netif->fe_dev_addr); + err = xen_net_read_mac(dev, "mac", be->netif->fe_dev_addr); if (err) { xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); return; @@ -360,6 +376,8 @@ static void connect(struct backend_info xen_net_read_rate(dev, &be->netif->credit_bytes, &be->netif->credit_usec); be->netif->remaining_credit = be->netif->credit_bytes; + + vifdevmap_add_netif(be->netif); xenbus_switch_state(dev, XenbusStateConnected); } diff -r 10582388adb5 -r caffde2df665 linux-2.6-xen-sparse/net/core/dev.c --- a/linux-2.6-xen-sparse/net/core/dev.c Tue Aug 29 08:10:12 2006 -0700 +++ b/linux-2.6-xen-sparse/net/core/dev.c Tue Aug 29 14:16:32 2006 -0700 @@ -121,6 +121,9 @@ #include #include #include +#ifdef CONFIG_XEN_NETDEV_BACKEND +#include +#endif #endif /* @@ -1415,6 +1418,10 @@ int dev_queue_xmit(struct sk_buff *skb) goto out_kfree_skb; gso: +#ifdef CONFIG_XEN_NETDEV_BACKEND + if (vifdevmap_tx_packet(skb,&rc)) + return rc; +#endif spin_lock_prefetch(&dev->queue_lock); /* Disable soft irqs for various locks below. Also @@ -1762,6 +1769,11 @@ int netif_receive_skb(struct sk_buff *sk skb->proto_data_valid = 0; break; } + +#ifdef CONFIG_XEN_NETDEV_BACKEND + if (vifdevmap_rx_packet(skb,&ret)) + goto out; +#endif #endif list_for_each_entry_rcu(ptype, &ptype_all, list) { diff -r 10582388adb5 -r caffde2df665 tools/python/xen/xend/server/netif.py --- a/tools/python/xen/xend/server/netif.py Tue Aug 29 08:10:12 2006 -0700 +++ b/tools/python/xen/xend/server/netif.py Tue Aug 29 14:16:32 2006 -0700 @@ -157,6 +157,8 @@ class NetifController(DevController): mac = sxp.child_value(config, 'mac') vifname = sxp.child_value(config, 'vifname') rate = sxp.child_value(config, 'rate') + pdev = sxp.child_value(config, 'pdev') + ipaddr = _get_config_ipaddr(config) devid = self.allocateDeviceID() @@ -182,6 +184,8 @@ class NetifController(DevController): back['vifname'] = vifname if rate: back['rate'] = parseRate(rate) + if pdev: + back['pdev'] = pdev return (devid, back, front) diff -r 10582388adb5 -r caffde2df665 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Tue Aug 29 08:10:12 2006 -0700 +++ b/tools/python/xen/xm/create.py Tue Aug 29 14:16:32 2006 -0700 @@ -622,7 +622,7 @@ def configure_vifs(config_devs, vals): def f(k): if k not in ['backend', 'bridge', 'ip', 'mac', 'script', 'type', - 'vifname', 'rate', 'model']: + 'vifname', 'rate', 'model', 'pdev']: err('Invalid vif option: ' + k) config_vif.append([k, d[k]]) diff -r 10582388adb5 -r caffde2df665 linux-2.6-xen-sparse/drivers/xen/netback/vifdevmap.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/vifdevmap.c Tue Aug 29 14:16:32 2006 -0700 @@ -0,0 +1,455 @@ +/****************************************************************************** + * drivers/xen/netback/vifdevmap.c + * + * Map xen netback virtual interfaces to physical interfaces and forward + * network packets among netback, physical device and + * local network stack. This is an alternative to using the linux bridge + * + * Copyright (c) 2006, Hewlett-Packard Co. + * + * Author: Jose Renato Santos (jsantos@hpl.hp.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include "common.h" + +static int vifdevmap_initialized = 0; + +static int n_vifdevmap = 0; +static struct list_head vifdevmap_list; +static spinlock_t vifdevmap_list_lock; + +void vifdevmap_init(void) +{ + if (!vifdevmap_initialized) { + spin_lock_init(&vifdevmap_list_lock); + INIT_LIST_HEAD(&vifdevmap_list); + vifdevmap_initialized = 1; + } +} + +static __inline__ int vif_mac_hash(const unsigned char *mac) +{ + return jhash(mac, ETH_ALEN, 0) & (VIF_HASH_SIZE - 1); +} + +static vifdevmap_t *__vifdevmap_alloc(struct net_device *pdev) +{ + int i; + + vifdevmap_t *vifdevmap = kmalloc(sizeof(vifdevmap_t), GFP_ATOMIC); + + if ( !(vifdevmap = kmalloc(sizeof(vifdevmap_t), GFP_ATOMIC)) ) + return NULL; + + vifdevmap->pdev = pdev; + memcpy(vifdevmap->pmac, pdev->dev_addr, ETH_ALEN); + vifdevmap->n_netif = 0; + + list_add_tail(&vifdevmap->list, &vifdevmap_list); + spin_lock_init(&vifdevmap->netif_list_lock); + for ( i = 0; i < VIF_HASH_SIZE; i++) + INIT_LIST_HEAD(&vifdevmap->hash[i]); + vifdevmap->refcnt = 1; + + n_vifdevmap++; + + return vifdevmap; +} + +static vifdevmap_t *__vifdevmap_find(struct net_device *pdev) +{ + vifdevmap_t *vifdevmap = NULL; + struct list_head *ent; + + /* Find out which vifdevmap is using this device */ + list_for_each (ent, &vifdevmap_list) { + if ( list_entry(ent, vifdevmap_t, list)->pdev == + pdev ) { + vifdevmap = list_entry(ent, vifdevmap_t, list); + break; + } + } + + return vifdevmap; +} + +vifdevmap_t *vifdevmap_find(struct net_device *pdev) +{ + vifdevmap_t *vifdevmap; + unsigned long flags; + + if (!vifdevmap_initialized) + return NULL; + + spin_lock_irqsave(&vifdevmap_list_lock, flags); + vifdevmap = __vifdevmap_find(pdev); + spin_unlock_irqrestore(&vifdevmap_list_lock, flags); + + return vifdevmap; +} + +vifdevmap_t *vifdevmap_get(char* pdevname) +{ + vifdevmap_t *vifdevmap; + struct net_device* pdev = dev_get_by_name(pdevname); + unsigned long flags; + + if (!pdev) + return NULL; + + spin_lock_irqsave(vifdevmap_list_lock, flags); + if ( !(vifdevmap = __vifdevmap_find(pdev)) ) { + if ( !(vifdevmap = __vifdevmap_alloc(pdev)) ) { + spin_unlock_irqrestore(vifdevmap_list_lock, flags); + dev_put(pdev); + return NULL; + } + spin_unlock_irqrestore(vifdevmap_list_lock, flags); + dev_set_promiscuity(pdev, 1); + } + else { + spin_unlock_irqrestore(vifdevmap_list_lock, flags); + vifdevmap->refcnt++; + dev_put(pdev); + } + + return vifdevmap; +} + +static inline void vifdevmap_cleanup_netif(vifdevmap_t *vifdevmap) +{ + netif_t *netif; + struct list_head *ent; + unsigned long flags; + int i; + + spin_lock_irqsave(&vifdevmap->netif_list_lock, flags); + + for ( i = 0; i < VIF_HASH_SIZE; i++) { + list_for_each (ent, &vifdevmap->hash[i]) { + netif = list_entry(ent, netif_t, hashlist); + list_del(&netif->hashlist); + netif->vifdevmap = NULL; + netif_put(netif); + } + } + + spin_unlock_irqrestore(&vifdevmap->netif_list_lock, flags); +} + +static void __vifdevmap_free(vifdevmap_t *vifdevmap) +{ + vifdevmap_cleanup_netif(vifdevmap); + dev_put(vifdevmap->pdev); + list_del(&vifdevmap->list); + n_vifdevmap--; + kfree(vifdevmap); +} + +void vifdevmap_put(vifdevmap_t *vifdevmap) +{ + struct net_device *pdev = vifdevmap->pdev; + unsigned long flags; + spin_lock_irqsave(vifdevmap_list_lock, flags); + dev_put (pdev); + vifdevmap->refcnt--; + if (vifdevmap->refcnt == 0) { + __vifdevmap_free(vifdevmap); + spin_unlock_irqrestore(vifdevmap_list_lock, flags); + dev_set_promiscuity (pdev, -1); + return; + } + + spin_unlock_irqrestore(vifdevmap_list_lock, flags); +} + +static inline int __vifdevmap_has_netif(netif_t *netif, int hash) +{ + struct list_head *ent; + struct list_head *hash_list; + + hash_list = &netif->vifdevmap->hash[hash]; + + list_for_each (ent, hash_list) { + if ( list_entry(ent, netif_t, hashlist) == netif ) + return 1; + } + return 0; +} + +static inline void __vifdevmap_add_netif(netif_t *netif) +{ + vifdevmap_t *vifdevmap = netif->vifdevmap; + int hash = vif_mac_hash(netif->fe_dev_addr); + struct list_head *hash_list; + + if ( __vifdevmap_has_netif(netif, hash) ) + return; + + vifdevmap->n_netif++; + netif_get(netif); + hash_list = &netif->vifdevmap->hash[hash]; + list_add_tail(&netif->hashlist, hash_list); +} + +void vifdevmap_add_netif(netif_t *netif) +{ + unsigned long flags; + + if ( !(netif->vifdevmap) ) + return; + spin_lock_irqsave(netif->vifdevmap->netif_list_lock, flags); + __vifdevmap_add_netif(netif); + spin_unlock_irqrestore(netif->vifdevmap->netif_list_lock, flags); +} + +static inline void __vifdevmap_remove_netif(netif_t *netif) +{ + int hash = vif_mac_hash(netif->fe_dev_addr); + + if ( !(__vifdevmap_has_netif(netif, hash)) ) + return; + + netif->vifdevmap->n_netif--; + netif_put(netif); + list_del(&netif->hashlist); +} + +void vifdevmap_remove_netif(netif_t *netif) +{ + unsigned long flags; + + if ( !netif->vifdevmap ) + return; + spin_lock_irqsave(netif->vifdevmap->netif_list_lock, flags); + __vifdevmap_remove_netif(netif); + spin_unlock_irqrestore(netif->vifdevmap->netif_list_lock, flags); +} + +static int vifdevmap_forward_packet(struct sk_buff *skb, netif_t *netif) +{ + skb->dev = netif->dev; + return netif_be_start_xmit(skb, netif->dev); +} + +/* +static int vifdevmap_clone_packet(struct sk_buff *skb, netif_t *netif) +{ + struct sk_buff *skb_copy; + + if ((skb_copy = skb_clone(skb, GFP_ATOMIC)) == NULL) { + netif->stats.tx_dropped++; + return 0; + } + + skb_copy->dev = netif->dev; + + return netif_be_start_xmit(skb_copy, netif->dev); +} +*/ + +void vifdevmap_guest_packet(struct sk_buff *skb, netif_t *netif) +{ + u8 *mac = skb->data - ETH_HLEN; + + /* Rely on bridge if vif does not have a virtual to physical mapping */ + if (!netif->vifdevmap) { + netif_rx(skb); + return; + } + + /* if multicast or broadcast packet: forward to all vifs, */ + /* physical interface, and local host */ + if (is_multicast_ether_addr(mac)) { + struct sk_buff *skb_copy; + + /* forward packet to physical interface + This will be intercepted at dev_queue_xmit() + and forwarded to all vifs, but remember source + interface to avoid sending it to itself */ + if ((skb_copy = skb_clone(skb, GFP_ATOMIC)) == NULL) { + netif->stats.tx_dropped++; + } else { + skb_copy->dev = netif->vifdevmap->pdev; + skb_copy->input_dev = netif->dev; + skb_copy->nh.raw = skb_copy->data; + skb_push(skb_copy, ETH_HLEN); + dev_queue_xmit(skb_copy); + } + + /* deliver to local host network stack */ + /* pretend packet received on physical interface */ + skb->dev = netif->vifdevmap->pdev; + netif_rx (skb); + } else { /* unicast */ + /* if packet is to local host deliver to local + network stack */ + if (!memcmp(mac, netif->vifdevmap->pmac, ETH_ALEN)) { + skb->dev = netif->vifdevmap->pdev; + skb->pkt_type = PACKET_HOST; + netif_rx(skb); + } else { + skb->nh.raw=skb->data; + skb->dev = netif->vifdevmap->pdev; + skb_push(skb, ETH_HLEN); + dev_queue_xmit(skb); + } + } +} + +void vifdevmap_netif_broadcast (vifdevmap_t *vifdevmap, struct sk_buff *skb) +{ + int n_netif = vifdevmap->n_netif; + netif_t **netif = kmalloc (sizeof(netif_t *) * n_netif, GFP_ATOMIC); + struct list_head *ent; + unsigned long flags; + int i; + int k = 0; + + spin_lock_irqsave(vifdevmap->netif_list_lock, flags); + /* Number of vifs can change since vifs can be added or removed + * if lock is not held. If number of vifs is reduced we adjust + * the count appropriatelly. If number increases we just skip + * some vifs (that is OK since dropping packets is acceptable + * network behavior. This should be a very rare event anyway) + */ + if ( unlikely(n_netif > vifdevmap->n_netif) ) { + n_netif = vifdevmap->n_netif; + } + + for ( i = 0; (i < VIF_HASH_SIZE) && (k < n_netif); i++) { + list_for_each (ent, &vifdevmap->hash[i]) { + netif[k++] = list_entry(ent, netif_t, hashlist); + } + } + spin_unlock_irqrestore(vifdevmap->netif_list_lock, flags); + + /* if the code is sane we should have "netif=k" already, + but just in case... */ + n_netif = k; + + for (i = 0; i < n_netif; i++) { + struct sk_buff *skb_copy; + /* skip netif that sent that has sent the packet */ + if ( netif[i]->dev == skb->input_dev ) + continue; + if ((skb_copy = skb_clone(skb, GFP_ATOMIC)) == NULL) { + netif[i]->stats.tx_dropped++; + goto end; + } + skb_copy->dev = netif[i]->dev; + netif_be_start_xmit(skb_copy, netif[i]->dev); + } + +end: + kfree(netif); +} + +int vifdevmap_rx_packet(struct sk_buff *skb, int *ret) +{ + struct list_head *ent; + netif_t *netif; + u8 *mac = skb->mac.raw; + vifdevmap_t *vifdevmap; + unsigned long flags; + + if ( !(vifdevmap = vifdevmap_find(skb->dev)) ) + return 0; + + /* if destination is multicast/broadcast send packets to all vifs + mapped to this physical interface */ + if (is_multicast_ether_addr(mac)) { + skb->nh.raw=skb->data; + skb_push(skb, ETH_HLEN); + vifdevmap_netif_broadcast(vifdevmap, skb); + skb_pull(skb, ETH_HLEN); + /* received multicast/broadcast packet should also be + delivered to the local network stack */ + return 0; + } else { /* unicast */ + int hash = vif_mac_hash(mac); + spin_lock_irqsave(vifdevmap->netif_list_lock, flags); + list_for_each (ent, &vifdevmap->hash[hash]) { + netif = list_entry(ent, netif_t, hashlist); + if (!memcmp (mac, netif->fe_dev_addr, ETH_ALEN)) { + spin_unlock_irqrestore(&vifdevmap->netif_list_lock, + flags); + skb->dev = netif->dev; + skb->nh.raw=skb->data; + skb_push(skb, ETH_HLEN); + *ret = netif_be_start_xmit(skb, netif->dev); + /* if packet is destined to a vif, do not + deliver it to the local network stack */ + return 1; + } + } + spin_unlock_irqrestore(vifdevmap->netif_list_lock, flags); + return 0; + } +} + +int vifdevmap_tx_packet(struct sk_buff *skb, int *ret) +{ + struct list_head *ent; + netif_t *netif; + unsigned char *mac = skb->data; + vifdevmap_t *vifdevmap = NULL; + unsigned long flags; + + if ( !(vifdevmap = vifdevmap_find(skb->dev)) ) + return 0; + + /* if destination is multicast/broadcast send packets to all vifs + mapped to this physical interface */ + if (is_multicast_ether_addr(mac)) { + vifdevmap_netif_broadcast(vifdevmap, skb); + /* received multicast/broadcast packet should also be + delivered to the local network stack */ + return 0; + } else { /* unicast */ + int hash = vif_mac_hash(mac); + spin_lock_irqsave(vifdevmap->netif_list_lock, flags); + list_for_each (ent, &vifdevmap->hash[hash]) { + netif = list_entry(ent, netif_t, hashlist); + if (!memcmp (mac, netif->fe_dev_addr, ETH_ALEN)) { + spin_unlock_irqrestore(&vifdevmap->netif_list_lock, + flags); + skb->proto_data_valid = 1; + *ret = vifdevmap_forward_packet (skb, netif); + *ret = (*ret == NET_XMIT_SUCCESS) ? 0 : *ret; + /* if packet is destined to a vif, do not + send it to the physical device */ + return 1; + } + } + spin_unlock_irqrestore(vifdevmap->netif_list_lock, flags); + return 0; + } +} + diff -r 10582388adb5 -r caffde2df665 linux-2.6-xen-sparse/include/xen/vifdevmap.h --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/include/xen/vifdevmap.h Tue Aug 29 14:16:32 2006 -0700 @@ -0,0 +1,47 @@ +/****************************************************************************** + * vifdevmap.h + * + * Map xen netback virtual interfaces to physical interfaces and forward + * network packets among netback, physical device and + * local network stack. This is an alternative to using the linux bridge + * + * Copyright (c) 2006, Hewlett-Packard Company + * + * Author: Jose Renato Santos (jsantos@hpl.hp.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __VIFDEVMAP_H__ +#define __VIFDEVMAP_H__ + +#ifdef __KERNEL__ + +int vifdevmap_rx_packet(struct sk_buff *skb, int *ret); +int vifdevmap_tx_packet(struct sk_buff *skb, int *ret); + +#endif /* __KERNEL__ */ + +#endif /* __VIFDEFMAP_H__ */