size_t rlen;
#endif
- void (*netif_rx)(unsigned char* data, int len);
+ void (*netif_rx)(unsigned char* data, int len, void* arg);
+ void *netif_rx_arg;
};
+struct netfront_dev_list {
+ struct netfront_dev *dev;
+ unsigned char rawmac[6];
+ char *ip;
+
+ int refcount;
+
+ struct netfront_dev_list *next;
+};
+
+static struct netfront_dev_list *dev_list = NULL;
+
void init_rx_buffers(struct netfront_dev *dev);
+static struct netfront_dev *_init_netfront(struct netfront_dev *dev,
+ unsigned char rawmac[6], char **ip);
+static void _shutdown_netfront(struct netfront_dev *dev);
+void netfront_set_rx_handler(struct netfront_dev *dev,
+ void (*thenetif_rx)(unsigned char *data, int len,
+ void *arg),
+ void *arg);
static inline void add_id_to_freelist(unsigned int id,unsigned short* freelist)
{
return id;
}
-__attribute__((weak)) void netif_rx(unsigned char* data,int len)
+__attribute__((weak)) void netif_rx(unsigned char* data, int len, void *arg)
{
printk("%d bytes incoming at %p\n",len,data);
}
page = (unsigned char*)buf->page;
gnttab_end_access(buf->gref);
- if (rx->status > NETIF_RSP_NULL)
- {
+ if (rx->status > NETIF_RSP_NULL) {
#ifdef HAVE_LIBC
- if (dev->netif_rx == NETIF_SELECT_RX) {
- int len = rx->status;
- ASSERT(current == main_thread);
- if (len > dev->len)
- len = dev->len;
- memcpy(dev->data, page+rx->offset, len);
- dev->rlen = len;
- /* No need to receive the rest for now */
- dobreak = 1;
- } else
+ if (dev->netif_rx == NETIF_SELECT_RX) {
+ int len = rx->status;
+ ASSERT(current == main_thread);
+ if (len > dev->len)
+ len = dev->len;
+ memcpy(dev->data, page+rx->offset, len);
+ dev->rlen = len;
+ /* No need to receive the rest for now */
+ dobreak = 1;
+ } else
#endif
- dev->netif_rx(page+rx->offset,rx->status);
+ dev->netif_rx(page+rx->offset, rx->status, dev->netif_rx_arg);
}
}
dev->rx.rsp_cons=cons;
req_prod = dev->rx.req_prod_pvt;
- for(i=0; i<nr_consumed; i++)
- {
+ for (i = 0; i < nr_consumed; i++) {
int id = xennet_rxidx(req_prod + i);
netif_rx_request_t *req = RING_GET_REQUEST(&dev->rx, req_prod + i);
struct net_buffer* buf = &dev->rx_buffers[id];
void* page = buf->page;
/* We are sure to have free gnttab entries since they got released above */
- buf->gref = req->gref =
- gnttab_grant_access(dev->dom,virt_to_mfn(page),0);
-
+ buf->gref = req->gref = gnttab_grant_access(dev->dom,
+ virt_to_mfn(page),
+ 0);
req->id = id;
}
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->rx, notify);
if (notify)
notify_remote_via_evtchn(dev->evtchn);
-
}
void network_tx_buf_gc(struct netfront_dev *dev)
{
-
-
RING_IDX cons, prod;
unsigned short id;
gnttab_end_access(buf->gref);
buf->gref=GRANT_INVALID_REF;
- add_id_to_freelist(id,dev->tx_freelist);
- up(&dev->tx_sem);
+ add_id_to_freelist(id,dev->tx_freelist);
+ up(&dev->tx_sem);
}
dev->tx.rsp_cons = prod;
prod + ((dev->tx.sring->req_prod - prod) >> 1) + 1;
mb();
} while ((cons == prod) && (prod != dev->tx.sring->rsp_prod));
-
-
}
void netfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
{
int i;
- for(i=0;i<NET_TX_RING_SIZE;i++)
- down(&dev->tx_sem);
+ for(i = 0; i < NET_TX_RING_SIZE; i++)
+ down(&dev->tx_sem);
mask_evtchn(dev->evtchn);
unbind_evtchn(dev->evtchn);
- for(i=0;i<NET_RX_RING_SIZE;i++) {
- gnttab_end_access(dev->rx_buffers[i].gref);
- free_page(dev->rx_buffers[i].page);
+ for (i = 0; i < NET_RX_RING_SIZE; i++) {
+ if (dev->rx_buffers[i].page) {
+ gnttab_end_access(dev->rx_buffers[i].gref);
+ free_page(dev->rx_buffers[i].page);
+ }
}
- for(i=0;i<NET_TX_RING_SIZE;i++)
- if (dev->tx_buffers[i].page)
- free_page(dev->tx_buffers[i].page);
+ for (i = 0; i < NET_TX_RING_SIZE; i++)
+ if (dev->tx_buffers[i].page)
+ free_page(dev->tx_buffers[i].page);
free(dev->nodename);
free(dev);
}
-struct netfront_dev *init_netfront(char *_nodename, void (*thenetif_rx)(unsigned char* data, int len), unsigned char rawmac[6], char **ip)
+struct netfront_dev *init_netfront(char *_nodename,
+ void (*thenetif_rx)(unsigned char* data,
+ int len, void* arg),
+ unsigned char rawmac[6],
+ char **ip)
{
- xenbus_transaction_t xbt;
- char* err;
- char* message=NULL;
- struct netif_tx_sring *txs;
- struct netif_rx_sring *rxs;
- int retry=0;
- int i;
- char* msg = NULL;
char nodename[256];
- char path[256];
struct netfront_dev *dev;
+ struct netfront_dev_list *ldev = NULL;
+ struct netfront_dev_list *list = NULL;
static int netfrontends = 0;
if (!_nodename)
strncpy(nodename, _nodename, sizeof(nodename) - 1);
nodename[sizeof(nodename) - 1] = 0;
}
- netfrontends++;
+
+ /* Check if the device is already initialized */
+ for (list = dev_list; list != NULL; list = list->next) {
+ if (strcmp(nodename, list->dev->nodename) == 0) {
+ list->refcount++;
+ dev = list->dev;
+ if (thenetif_rx)
+ netfront_set_rx_handler(dev, thenetif_rx, NULL);
+ goto out;
+ }
+ }
if (!thenetif_rx)
- thenetif_rx = netif_rx;
+ thenetif_rx = netif_rx;
printk("************************ NETFRONT for %s **********\n\n\n", nodename);
#ifdef HAVE_LIBC
dev->fd = -1;
#endif
+ dev->netif_rx = thenetif_rx;
+ dev->netif_rx_arg = NULL;
+
+ ldev = malloc(sizeof(struct netfront_dev_list));
+ memset(ldev, 0, sizeof(struct netfront_dev_list));
+
+ if (_init_netfront(dev, ldev->rawmac, &(ldev->ip))) {
+ ldev->dev = dev;
+ ldev->refcount = 1;
+ ldev->next = NULL;
+
+ if (!dev_list) {
+ dev_list = ldev;
+ } else {
+ for (list = dev_list; list->next != NULL; list = list->next)
+ ;
+ list->next = ldev;
+ }
+ netfrontends++;
+ } else {
+ free(ldev);
+ dev = NULL;
+ goto err;
+ }
+
+out:
+ if (rawmac) {
+ rawmac[0] = ldev->rawmac[0];
+ rawmac[1] = ldev->rawmac[1];
+ rawmac[2] = ldev->rawmac[2];
+ rawmac[3] = ldev->rawmac[3];
+ rawmac[4] = ldev->rawmac[4];
+ rawmac[5] = ldev->rawmac[5];
+ }
+ if (ip)
+ *ip = strdup(ldev->ip);
+
+err:
+ return dev;
+}
+
+static struct netfront_dev *_init_netfront(struct netfront_dev *dev,
+ unsigned char rawmac[6],
+ char **ip)
+{
+ xenbus_transaction_t xbt;
+ char* err = NULL;
+ char* message=NULL;
+ struct netif_tx_sring *txs;
+ struct netif_rx_sring *rxs;
+ char* msg = NULL;
+ int retry=0;
+ int i;
+ char path[256];
printk("net TX ring size %lu\n", (unsigned long) NET_TX_RING_SIZE);
printk("net RX ring size %lu\n", (unsigned long) NET_RX_RING_SIZE);
init_SEMAPHORE(&dev->tx_sem, NET_TX_RING_SIZE);
- for(i=0;i<NET_TX_RING_SIZE;i++)
- {
- add_id_to_freelist(i,dev->tx_freelist);
+ for (i = 0; i < NET_TX_RING_SIZE; i++) {
+ add_id_to_freelist(i, dev->tx_freelist);
dev->tx_buffers[i].page = NULL;
}
- for(i=0;i<NET_RX_RING_SIZE;i++)
- {
- /* TODO: that's a lot of memory */
+ for (i = 0; i < NET_RX_RING_SIZE; i++) {
+ /* TODO: that's a lot of memory */
dev->rx_buffers[i].page = (char*)alloc_page();
+ BUG_ON(dev->rx_buffers[i].page == NULL);
}
- snprintf(path, sizeof(path), "%s/backend-id", nodename);
+ snprintf(path, sizeof(path), "%s/backend-id", dev->nodename);
dev->dom = xenbus_read_integer(path);
#ifdef HAVE_LIBC
- if (thenetif_rx == NETIF_SELECT_RX)
+ if (dev->netif_rx == NETIF_SELECT_RX)
evtchn_alloc_unbound(dev->dom, netfront_select_handler, dev, &dev->evtchn);
else
#endif
txs = (struct netif_tx_sring *) alloc_page();
rxs = (struct netif_rx_sring *) alloc_page();
- memset(txs,0,PAGE_SIZE);
- memset(rxs,0,PAGE_SIZE);
-
+ memset(txs, 0, PAGE_SIZE);
+ memset(rxs, 0, PAGE_SIZE);
SHARED_RING_INIT(txs);
SHARED_RING_INIT(rxs);
FRONT_RING_INIT(&dev->tx, txs, PAGE_SIZE);
FRONT_RING_INIT(&dev->rx, rxs, PAGE_SIZE);
- dev->tx_ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(txs),0);
- dev->rx_ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(rxs),0);
+ dev->tx_ring_ref = gnttab_grant_access(dev->dom, virt_to_mfn(txs), 0);
+ dev->rx_ring_ref = gnttab_grant_access(dev->dom, virt_to_mfn(rxs), 0);
init_rx_buffers(dev);
- dev->netif_rx = thenetif_rx;
-
dev->events = NULL;
again:
free(err);
}
- err = xenbus_printf(xbt, nodename, "tx-ring-ref","%u",
- dev->tx_ring_ref);
+ err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u",
+ dev->tx_ring_ref);
if (err) {
message = "writing tx ring-ref";
goto abort_transaction;
}
- err = xenbus_printf(xbt, nodename, "rx-ring-ref","%u",
- dev->rx_ring_ref);
+ err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u",
+ dev->rx_ring_ref);
if (err) {
message = "writing rx ring-ref";
goto abort_transaction;
}
- err = xenbus_printf(xbt, nodename,
- "event-channel", "%u", dev->evtchn);
+ err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", dev->evtchn);
if (err) {
message = "writing event-channel";
goto abort_transaction;
}
- err = xenbus_printf(xbt, nodename, "request-rx-copy", "%u", 1);
-
+ err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u", 1);
if (err) {
message = "writing request-rx-copy";
goto abort_transaction;
}
- snprintf(path, sizeof(path), "%s/state", nodename);
+ snprintf(path, sizeof(path), "%s/state", dev->nodename);
err = xenbus_switch_state(xbt, path, XenbusStateConnected);
if (err) {
message = "switching state";
err = xenbus_transaction_end(xbt, 0, &retry);
free(err);
if (retry) {
- goto again;
+ goto again;
printk("completing transaction\n");
}
goto error;
done:
-
- snprintf(path, sizeof(path), "%s/backend", nodename);
+ snprintf(path, sizeof(path), "%s/backend", dev->nodename);
msg = xenbus_read(XBT_NIL, path, &dev->backend);
- snprintf(path, sizeof(path), "%s/mac", nodename);
+ snprintf(path, sizeof(path), "%s/mac", dev->nodename);
msg = xenbus_read(XBT_NIL, path, &dev->mac);
if ((dev->backend == NULL) || (dev->mac == NULL)) {
goto error;
}
- printk("backend at %s\n",dev->backend);
- printk("mac is %s\n",dev->mac);
+ printk("backend at %s\n", dev->backend);
+ printk("mac is %s\n", dev->mac);
{
XenbusState state;
unmask_evtchn(dev->evtchn);
- /* Special conversion specifier 'hh' needed for __ia64__. Without
- this mini-os panics with 'Unaligned reference'. */
+ /* Special conversion specifier 'hh' needed for __ia64__. Without
+ * this mini-os panics with 'Unaligned reference'.
+ */
if (rawmac)
- sscanf(dev->mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
- &rawmac[0],
- &rawmac[1],
- &rawmac[2],
- &rawmac[3],
- &rawmac[4],
- &rawmac[5]);
+ sscanf(dev->mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ &rawmac[0],
+ &rawmac[1],
+ &rawmac[2],
+ &rawmac[3],
+ &rawmac[4],
+ &rawmac[5]);
return dev;
+
error:
free(msg);
free(err);
#endif
void shutdown_netfront(struct netfront_dev *dev)
+{
+ struct netfront_dev_list *list = NULL;
+ struct netfront_dev_list *to_del = NULL;
+
+ /* Check this is a valid device */
+ for (list = dev_list; list != NULL; list = list->next) {
+ if (list->dev == dev)
+ break;
+ }
+
+ if (!list) {
+ printk("Trying to shutdown an invalid netfront device (%p)\n", dev);
+ return;
+ }
+
+ list->refcount--;
+ if (list->refcount == 0) {
+ _shutdown_netfront(dev);
+ free(dev->nodename);
+ free(dev);
+
+ to_del = list;
+ if (to_del == dev_list) {
+ free(to_del);
+ dev_list = NULL;
+ } else {
+ for (list = dev_list; list->next != to_del; list = list->next)
+ ;
+ list->next = to_del->next;
+ free(to_del);
+ }
+ }
+}
+
+static void _shutdown_netfront(struct netfront_dev *dev)
{
char* err = NULL, *err2;
XenbusState state;
free_netfront(dev);
}
+void suspend_netfront(void)
+{
+ struct netfront_dev_list *list;
+
+ for (list = dev_list; list != NULL; list = list->next)
+ _shutdown_netfront(list->dev);
+}
+
+void resume_netfront(void)
+{
+ struct netfront_dev_list *list;
+
+ for (list = dev_list; list != NULL; list = list->next)
+ _init_netfront(list->dev, NULL, NULL);
+}
void init_rx_buffers(struct netfront_dev *dev)
{
local_irq_save(flags);
network_rx(dev);
if (!dev->rlen && fd != -1)
- /* No data for us, make select stop returning */
- files[fd].read = 0;
+ /* No data for us, make select stop returning */
+ files[fd].read = 0;
/* Before re-enabling the interrupts, in case a packet just arrived in the
* meanwhile. */
local_irq_restore(flags);
return dev->rlen;
}
#endif
+
+void netfront_set_rx_handler(struct netfront_dev *dev,
+ void (*thenetif_rx)(unsigned char *data, int len,
+ void *arg),
+ void *arg)
+{
+ if (dev->netif_rx && dev->netif_rx != netif_rx)
+ printk("Replacing netif_rx handler for dev %s\n", dev->nodename);
+
+ dev->netif_rx = thenetif_rx;
+ dev->netif_rx_arg = arg;
+}