From patchwork Wed Mar 26 16:31:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Pirko X-Patchwork-Id: 333994 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id ED034140090 for ; Thu, 27 Mar 2014 03:31:47 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755779AbaCZQbo (ORCPT ); Wed, 26 Mar 2014 12:31:44 -0400 Received: from mail-ee0-f48.google.com ([74.125.83.48]:40823 "EHLO mail-ee0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755593AbaCZQbg (ORCPT ); Wed, 26 Mar 2014 12:31:36 -0400 Received: by mail-ee0-f48.google.com with SMTP id b57so1857922eek.7 for ; Wed, 26 Mar 2014 09:31:34 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=gTk3Btoatq828PleQdXqeHSvu/yZvSVDhvD1wsixznI=; b=iyQq1tvwNwxBh6+yfihfJ0jM5VY7QrZyPVD1E0IJap/A5FHrr9apT+8Yb9yG5JP6rB me2jbwupxLmzD3i0J9h33dv8Wy7HIzx+mVY1lliXH+25MZEboSv+KgQoV1onQ5fg9IKR wzJ/cUoYZongE+s4wYepa47gCDgiLN/wkdSkUAfzs6Qqmo8/Jva/EUg8fOFR+C07DIKa owgBqKMfk8/iPQ+inS1EKHu7aehzv1h7TvwaRehQOXKwTlnpQzwRCQXJN2znSTYL8PsY U0VRSuglopbXwDXyKNP7naG8jXhXxc/87TPy+E9xUljCNMi/h1iHodywNJWAieJqyEJY ijCQ== X-Gm-Message-State: ALoCoQnLqan+FA5cnk/2f4sJCiL56DUs2bITQwJfGp/STbQr16hg+k4ajtLOBmA9meBR08qBl9Ys X-Received: by 10.15.31.70 with SMTP id x46mr12054317eeu.26.1395851494308; Wed, 26 Mar 2014 09:31:34 -0700 (PDT) Received: from localhost (ip-94-113-121-85.net.upcbroadband.cz. [94.113.121.85]) by mx.google.com with ESMTPSA id y51sm48110452eeu.0.2014.03.26.09.31.32 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 26 Mar 2014 09:31:33 -0700 (PDT) From: Jiri Pirko To: netdev@vger.kernel.org Cc: davem@davemloft.net, nhorman@tuxdriver.com, andy@greyhouse.net, tgraf@suug.ch, dborkman@redhat.com, ogerlitz@mellanox.com, jesse@nicira.com, pshelar@nicira.com, azhou@nicira.com, ben@decadent.org.uk, stephen@networkplumber.org, jeffrey.t.kirsher@intel.com, vyasevic@redhat.com, xiyou.wangcong@gmail.com, john.r.fastabend@intel.com, edumazet@google.com, jhs@mojatatu.com, sfeldma@cumulusnetworks.com, f.fainelli@gmail.com, roopa@cumulusnetworks.com, linville@tuxdriver.com, dev@openvswitch.org Subject: [patch net-next RFC v2 6/6] net: introduce dummy switch Date: Wed, 26 Mar 2014 17:31:12 +0100 Message-Id: <1395851472-10524-7-git-send-email-jiri@resnulli.us> X-Mailer: git-send-email 1.8.5.3 In-Reply-To: <1395851472-10524-1-git-send-email-jiri@resnulli.us> References: <1395851472-10524-1-git-send-email-jiri@resnulli.us> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Dummy switch implementation using switchdev API Signed-off-by: Jiri Pirko --- drivers/net/Kconfig | 7 ++ drivers/net/Makefile | 1 + drivers/net/dummyswitch.c | 235 +++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/if_link.h | 9 ++ 4 files changed, 252 insertions(+) create mode 100644 drivers/net/dummyswitch.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 89402c3..a9629a7 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -71,6 +71,13 @@ config DUMMY To compile this driver as a module, choose M here: the module will be called dummy. +config NET_DUMMY_SWITCH + tristate "Dummy switch net driver support" + depends on NET_SWITCHDEV + ---help--- + To compile this driver as a module, choose M here: the module + will be called dummyswitch. + config EQUALIZER tristate "EQL (serial line load balancing) support" ---help--- diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3fef8a8..d5d4ce6 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -7,6 +7,7 @@ # obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_DUMMY) += dummy.o +obj-$(CONFIG_NET_DUMMY_SWITCH) += dummyswitch.o obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_IFB) += ifb.o obj-$(CONFIG_MACVLAN) += macvlan.o diff --git a/drivers/net/dummyswitch.c b/drivers/net/dummyswitch.c new file mode 100644 index 0000000..58c65a9 --- /dev/null +++ b/drivers/net/dummyswitch.c @@ -0,0 +1,235 @@ +/* + * drivers/net/dummyswitch.c - Dummy switch device + * Copyright (c) 2014 Jiri Pirko + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include + +/* + * Dummy switch + */ + +static void dummysw_uninit(struct net_device *dev) +{ + __swdev_unregister(dev); +} + +static netdev_tx_t dummysw_xmit(struct sk_buff *skb, struct net_device *dev) +{ + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static int dummysw_flow_insert(struct net_device *dev, struct sw_flow *flow) +{ + netdev_dbg(dev, "Flow inserted"); + return 0; +} +static int dummysw_flow_remove(struct net_device *dev, struct sw_flow *flow) +{ + netdev_dbg(dev, "Flow removed"); + return 0; +} + +static const struct net_device_ops dummysw_netdev_ops = { + .ndo_uninit = dummysw_uninit, + .ndo_start_xmit = dummysw_xmit, + .ndo_swdev_flow_insert = dummysw_flow_insert, + .ndo_swdev_flow_remove = dummysw_flow_remove, +}; + +static void dummysw_setup(struct net_device *dev) +{ + ether_setup(dev); + + /* Initialize the device structure. */ + dev->netdev_ops = &dummysw_netdev_ops; + dev->destructor = free_netdev; + + /* Fill in device structure with ethernet-generic values. */ + dev->tx_queue_len = 0; + dev->flags |= IFF_NOARP; + dev->flags &= ~IFF_MULTICAST; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO; + dev->features |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX; + eth_hw_addr_random(dev); +} + +static int dummysw_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + return 0; +} + +static int dummysw_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + int err; + + err = register_netdevice(dev); + if (err) + return err; + err = __swdev_register(dev); + if (err) + goto err_swdev_register; + netif_carrier_on(dev); + return 0; + +err_swdev_register: + unregister_netdevice(dev); + return err; +} + +static struct rtnl_link_ops dummysw_link_ops __read_mostly = { + .kind = "dummysw", + .setup = dummysw_setup, + .validate = dummysw_validate, + .newlink = dummysw_newlink, +}; + + +/* + * Dummy switch port + */ + +static void dummyswport_uninit(struct net_device *dev) +{ + __swportdev_unregister(dev); +} + +static netdev_tx_t dummyswport_xmit(struct sk_buff *skb, struct net_device *dev) +{ + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static const struct net_device_ops dummyswport_netdev_ops = { + .ndo_uninit = dummyswport_uninit, + .ndo_start_xmit = dummyswport_xmit, +}; + +static void dummyswport_setup(struct net_device *dev) +{ + ether_setup(dev); + + /* Initialize the device structure. */ + dev->netdev_ops = &dummyswport_netdev_ops; + dev->destructor = free_netdev; + + /* Fill in device structure with ethernet-generic values. */ + dev->tx_queue_len = 0; + dev->flags |= IFF_NOARP; + dev->flags &= ~IFF_MULTICAST; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO; + dev->features |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX; +} + +static int dummyswport_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (tb[IFLA_ADDRESS]) + return -EINVAL; + if (!data || !data[IFLA_DUMMYSWPORT_MASTER]) + return -EINVAL; + return 0; +} + +static int dummyswport_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct net_device *switch_dev; + uint32_t switch_ifindex; + int err; + + switch_ifindex = nla_get_u32(data[IFLA_DUMMYSWPORT_MASTER]); + switch_dev = __dev_get_by_index(dev_net(dev), switch_ifindex); + if (!switch_dev) + return -ENODEV; + if (!swdev_dev_check(switch_dev)) + return -EOPNOTSUPP; + + err = register_netdevice(dev); + if (err) + return err; + err = __swportdev_register(dev, switch_dev); + if (err) + goto err_swportdev_register; + + memcpy(dev->dev_addr, switch_dev->dev_addr, dev->addr_len); + dev->addr_assign_type = NET_ADDR_STOLEN; + netif_carrier_on(dev); + + return 0; + +err_swportdev_register: + unregister_netdevice(dev); + return err; +} + +static const struct nla_policy dummyswport_policy[IFLA_DUMMYSWPORT_MAX + 1] = { + [IFLA_DUMMYSWPORT_MASTER] = { .type = NLA_U32 }, +}; + +static struct rtnl_link_ops dummyswport_link_ops __read_mostly = { + .kind = "dummyswport", + .setup = dummyswport_setup, + .validate = dummyswport_validate, + .newlink = dummyswport_newlink, + .policy = dummyswport_policy, + .maxtype = IFLA_DUMMYSWPORT_MAX, +}; + + +/* + * Module init/exit + */ + +static int __init dummysw_module_init(void) +{ + int err; + + err = rtnl_link_register(&dummysw_link_ops); + if (err) + return err; + err = rtnl_link_register(&dummyswport_link_ops); + if (err) + goto err_rtnl_link_register; + return 0; + +err_rtnl_link_register: + rtnl_link_unregister(&dummysw_link_ops); + return err; +} + +static void __exit dummysw_module_exit(void) +{ + rtnl_link_unregister(&dummyswport_link_ops); + rtnl_link_unregister(&dummysw_link_ops); +} + +module_init(dummysw_module_init); +module_exit(dummysw_module_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Jiri Pirko "); +MODULE_DESCRIPTION("Dummy switch device"); +MODULE_ALIAS_RTNL_LINK("dummysw"); +MODULE_ALIAS_RTNL_LINK("dummyswport"); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 16410b6..ec14dd3 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -544,4 +544,13 @@ enum { #define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1) +/* DUMMYSWPORT section */ +enum { + IFLA_DUMMYSWPORT_UNSPEC, + IFLA_DUMMYSWPORT_MASTER, + __IFLA_DUMMYSWPORT_MAX, +}; + +#define IFLA_DUMMYSWPORT_MAX (__IFLA_DUMMYSWPORT_MAX - 1) + #endif /* _UAPI_LINUX_IF_LINK_H */