1 /* veth driver port to Linux 2.6.18 */
6 * Copyright (C) 2007, 2009 OpenVZ http://openvz.org, SWsoft Inc
8 * Author: Pavel Emelianov <xemul@openvz.org>
9 * Ethtool interface from: Eric W. Biederman <ebiederm@xmission.com>
13 #include <linux/list.h>
14 #include <linux/netdevice.h>
15 #include <linux/ethtool.h>
16 #include <linux/etherdevice.h>
21 #define DRV_NAME "veth"
22 #define DRV_VERSION "1.0"
24 struct veth_net_stats {
25 unsigned long rx_packets;
26 unsigned long tx_packets;
27 unsigned long rx_bytes;
28 unsigned long tx_bytes;
29 unsigned long tx_dropped;
33 struct net_device *peer;
34 struct net_device *dev;
35 struct list_head list;
36 struct veth_net_stats *stats;
38 struct net_device_stats dev_stats;
41 static LIST_HEAD(veth_list);
48 const char string[ETH_GSTRING_LEN];
49 } ethtool_stats_keys[] = {
53 static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
57 cmd->speed = SPEED_10000;
58 cmd->duplex = DUPLEX_FULL;
61 cmd->transceiver = XCVR_INTERNAL;
62 cmd->autoneg = AUTONEG_DISABLE;
68 static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
70 strcpy(info->driver, DRV_NAME);
71 strcpy(info->version, DRV_VERSION);
72 strcpy(info->fw_version, "N/A");
75 static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
79 memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys));
84 static void veth_get_ethtool_stats(struct net_device *dev,
85 struct ethtool_stats *stats, u64 *data)
87 struct veth_priv *priv;
89 priv = netdev_priv(dev);
90 data[0] = priv->peer->ifindex;
93 static u32 veth_get_rx_csum(struct net_device *dev)
95 struct veth_priv *priv;
97 priv = netdev_priv(dev);
98 return priv->ip_summed == CHECKSUM_UNNECESSARY;
101 static int veth_set_rx_csum(struct net_device *dev, u32 data)
103 struct veth_priv *priv;
105 priv = netdev_priv(dev);
106 priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
110 static u32 veth_get_tx_csum(struct net_device *dev)
112 return (dev->features & NETIF_F_NO_CSUM) != 0;
115 static int veth_set_tx_csum(struct net_device *dev, u32 data)
118 dev->features |= NETIF_F_NO_CSUM;
120 dev->features &= ~NETIF_F_NO_CSUM;
124 static struct ethtool_ops veth_ethtool_ops = {
125 .get_settings = veth_get_settings,
126 .get_drvinfo = veth_get_drvinfo,
127 .get_link = ethtool_op_get_link,
128 .get_rx_csum = veth_get_rx_csum,
129 .set_rx_csum = veth_set_rx_csum,
130 .get_tx_csum = veth_get_tx_csum,
131 .set_tx_csum = veth_set_tx_csum,
132 .get_sg = ethtool_op_get_sg,
133 .set_sg = ethtool_op_set_sg,
134 .get_strings = veth_get_strings,
135 .get_ethtool_stats = veth_get_ethtool_stats,
142 static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
144 struct net_device *rcv = NULL;
145 struct veth_priv *priv, *rcv_priv;
146 struct veth_net_stats *stats;
151 priv = netdev_priv(dev);
153 rcv_priv = netdev_priv(rcv);
155 cpu = smp_processor_id();
156 stats = per_cpu_ptr(priv->stats, cpu);
158 if (!(rcv->flags & IFF_UP))
162 skb->pkt_type = PACKET_HOST;
163 skb->protocol = eth_type_trans(skb, rcv);
164 if (dev->features & NETIF_F_NO_CSUM)
165 skb->ip_summed = rcv_priv->ip_summed;
167 dst_release(skb->dst);
174 stats->tx_bytes += length;
177 stats = per_cpu_ptr(rcv_priv->stats, cpu);
178 stats->rx_bytes += length;
194 static struct net_device_stats *veth_get_stats(struct net_device *dev)
196 struct veth_priv *priv;
197 struct net_device_stats *dev_stats;
199 struct veth_net_stats *stats;
201 priv = netdev_priv(dev);
202 dev_stats = &priv->dev_stats;
204 dev_stats->rx_packets = 0;
205 dev_stats->tx_packets = 0;
206 dev_stats->rx_bytes = 0;
207 dev_stats->tx_bytes = 0;
208 dev_stats->tx_dropped = 0;
210 for_each_online_cpu(cpu) {
211 stats = per_cpu_ptr(priv->stats, cpu);
213 dev_stats->rx_packets += stats->rx_packets;
214 dev_stats->tx_packets += stats->tx_packets;
215 dev_stats->rx_bytes += stats->rx_bytes;
216 dev_stats->tx_bytes += stats->tx_bytes;
217 dev_stats->tx_dropped += stats->tx_dropped;
223 static int veth_open(struct net_device *dev)
225 struct veth_priv *priv;
227 priv = netdev_priv(dev);
228 if (priv->peer == NULL)
231 if (priv->peer->flags & IFF_UP) {
232 netif_carrier_on(dev);
233 netif_carrier_on(priv->peer);
238 static int veth_dev_init(struct net_device *dev)
240 struct veth_net_stats *stats;
241 struct veth_priv *priv;
243 stats = alloc_percpu(struct veth_net_stats);
247 priv = netdev_priv(dev);
252 static void veth_dev_free(struct net_device *dev)
254 struct veth_priv *priv;
256 priv = netdev_priv(dev);
257 free_percpu(priv->stats);
261 static void veth_setup(struct net_device *dev)
265 dev->hard_start_xmit = veth_xmit;
266 dev->get_stats = veth_get_stats;
267 dev->open = veth_open;
268 dev->ethtool_ops = &veth_ethtool_ops;
269 dev->features |= NETIF_F_LLTX;
270 dev->init = veth_dev_init;
271 dev->destructor = veth_dev_free;
274 static void veth_change_state(struct net_device *dev)
276 struct net_device *peer;
277 struct veth_priv *priv;
279 priv = netdev_priv(dev);
282 if (netif_carrier_ok(peer)) {
283 if (!netif_carrier_ok(dev))
284 netif_carrier_on(dev);
286 if (netif_carrier_ok(dev))
287 netif_carrier_off(dev);
291 static int veth_device_event(struct notifier_block *unused,
292 unsigned long event, void *ptr)
294 struct net_device *dev = ptr;
296 if (dev->open != veth_open)
301 veth_change_state(dev);
308 static struct notifier_block veth_notifier_block __read_mostly = {
309 .notifier_call = veth_device_event,
316 static int veth_newlink(const char *devname, const char *peername)
319 const char *names[2];
320 struct net_device *devs[2];
325 devs[0] = devs[1] = NULL;
327 for (i = 0; i < 2; i++) {
328 struct net_device *dev;
331 devs[i] = alloc_netdev(sizeof(struct veth_priv),
332 names[i], veth_setup);
339 if (strchr(dev->name, '%')) {
340 err = dev_alloc_name(dev, dev->name);
344 random_ether_addr(dev->dev_addr);
346 err = register_netdevice(dev);
350 netif_carrier_off(dev);
354 * tie the devices together
357 for (i = 0; i < 2; i++) {
358 struct veth_priv *priv = netdev_priv(devs[i]);
360 priv->peer = devs[!i];
362 list_add(&priv->list, &veth_list);
364 INIT_LIST_HEAD(&priv->list);
369 for (i = 0; i < 2; i++) {
371 if (devs[i]->reg_state != NETREG_UNINITIALIZED)
372 unregister_netdevice(devs[i]);
374 free_netdev(devs[i]);
380 static void veth_dellink(struct net_device *dev)
382 struct veth_priv *priv;
383 struct net_device *peer;
385 priv = netdev_priv(dev);
388 if (!list_empty(&priv->list))
389 list_del(&priv->list);
391 priv = netdev_priv(peer);
392 if (!list_empty(&priv->list))
393 list_del(&priv->list);
395 unregister_netdevice(dev);
396 unregister_netdevice(peer);
404 * "show" function for the veth_pairs attribute.
405 * The class parameter is ignored.
407 static ssize_t veth_show_veth_pairs(struct class *cls, char *buffer)
410 struct veth_priv *priv;
412 list_for_each_entry(priv, &veth_list, list) {
413 if (res > (PAGE_SIZE - (IFNAMSIZ * 2 + 1))) {
414 /* not enough space for another interface name */
415 if ((PAGE_SIZE - res) > 10)
416 res = PAGE_SIZE - 10;
417 res += sprintf(buffer + res, "++more++");
420 res += sprintf(buffer + res, "%s,%s ",
421 priv->dev->name, priv->peer->name);
423 res += sprintf(buffer + res, "\n");
429 * "store" function for the veth_pairs attribute. This is what
430 * creates and deletes veth pairs.
432 * The class parameter is ignored.
435 static ssize_t veth_store_veth_pairs(struct class *cls, const char *buffer,
441 char devname[IFNAMSIZ + 1] = "";
442 char peername[IFNAMSIZ + 1] = "";
443 char *comma = strchr(buffer, ',');
446 strncat(devname, buffer,
447 min_t(int, sizeof devname, comma - buffer));
448 strncat(peername, comma + 1,
449 min_t(int, sizeof peername, strcspn(comma + 1, "\n")));
450 if (!dev_valid_name(devname) || !dev_valid_name(peername))
453 retval = veth_newlink(devname, peername);
455 return retval ? retval : count;
456 } else if (c == '-') {
457 struct net_device *dev;
460 dev = dev_get_by_name(buffer);
463 else if (dev->init != veth_dev_init)
475 printk(KERN_ERR DRV_NAME ": no command found in veth_pairs. Use +ifname,peername or -ifname.\n");
479 /* class attribute for veth_pairs file. This ends up in /sys/class/net */
480 static CLASS_ATTR(veth_pairs, S_IWUSR | S_IRUGO,
481 veth_show_veth_pairs, veth_store_veth_pairs);
483 static struct class *netdev_class;
486 * Initialize sysfs. This sets up the veth_pairs file in
489 int veth_create_sysfs(void)
491 struct net_device *dev = dev_get_by_name("lo");
494 netdev_class = dev->class_dev.class;
498 return class_create_file(netdev_class, &class_attr_veth_pairs);
502 * Remove /sys/class/net/veth_pairs.
504 void veth_destroy_sysfs(void)
506 class_remove_file(netdev_class, &class_attr_veth_pairs);
515 static __init int veth_init(void)
517 int retval = veth_create_sysfs();
520 register_netdevice_notifier(&veth_notifier_block);
524 static __exit void veth_exit(void)
526 unregister_netdevice_notifier(&veth_notifier_block);
529 module_init(veth_init);
530 module_exit(veth_exit);
532 MODULE_DESCRIPTION("Virtual Ethernet Tunnel");
533 MODULE_LICENSE("GPL v2");