lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 28 Oct 2021 16:57:36 +0300
From:   Denis Kirjanov <dkirjanov@...e.de>
To:     Taehee Yoo <ap420073@...il.com>, davem@...emloft.net,
        kuba@...nel.org, dsahern@...nel.org, netdev@...r.kernel.org
Subject: Re: [PATCH net-next 1/4 v4] amt: add control plane of amt interface



10/26/21 6:10 PM, Taehee Yoo пишет:
> It adds definitions and control plane code for AMT.
> this is very similar to udp tunneling interfaces such as gtp, vxlan, etc.
> In the next patch, data plane code will be added.
> 
> Signed-off-by: Taehee Yoo <ap420073@...il.com>
> ---
> v1 -> v2:
>   - Eliminate sparse warnings
>     - Use bool type instead of __be16 for identifying v4/v6 protocol.
> 
> v2 -> v3:
>   - Fix compile warning due to unsed variable.
>   - Add missing spinlock comment.
>   - Update help message of amt in Kconfig.
> 
> v3 -> v4:
>   - Split patch.
>   - Fix compile error
> 
>   MAINTAINERS              |   8 +
>   drivers/net/Kconfig      |  16 ++
>   drivers/net/Makefile     |   1 +
>   drivers/net/amt.c        | 487 +++++++++++++++++++++++++++++++++++++++
>   include/net/amt.h        | 236 +++++++++++++++++++
>   include/uapi/linux/amt.h |  31 +++
>   6 files changed, 779 insertions(+)
>   create mode 100644 drivers/net/amt.c
>   create mode 100644 include/net/amt.h
>   create mode 100644 include/uapi/linux/amt.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 975086c5345d..7fc24375e0c8 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1020,6 +1020,14 @@ S:	Maintained
>   F:	Documentation/devicetree/bindings/iio/light/ams,as73211.yaml
>   F:	drivers/iio/light/as73211.c
>   
> +AMT (Automatic Multicast Tunneling)
> +M:	Taehee Yoo <ap420073@...il.com>
> +L:	netdev@...r.kernel.org
> +S:	Maintained
> +T:	git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
> +T:	git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
> +F:	drivers/net/amt.c
> +
>   ANALOG DEVICES INC AD7192 DRIVER
>   M:	Alexandru Tachici <alexandru.tachici@...log.com>
>   L:	linux-iio@...r.kernel.org
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index f37b1c56f7c4..dae126b31cd5 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -291,6 +291,22 @@ config GTP
>   	  To compile this drivers as a module, choose M here: the module
>   	  will be called gtp.
>   
> +config AMT
> +	tristate "Automatic Multicast Tunneling (AMT)"
> +	depends on INET && IP_MULTICAST
> +	select NET_UDP_TUNNEL
> +	help
> +	  This allows one to create AMT(Automatic Multicast Tunneling)
> +	  virtual interfaces that provide multicast tunneling.
> +	  There are two roles, Gateway, and Relay.
> +	  Gateway Encapsulates IGMP/MLD traffic from listeners to the Relay.
> +	  Gateway Decapsulates multicast traffic from the Relay to Listeners.
> +	  Relay Encapsulates multicast traffic from Sources to Gateway.
> +	  Relay Decapsulates IGMP/MLD traffic from Gateway.
> +
> +	  To compile this drivers as a module, choose M here: the module
> +	  will be called amt.
> +
>   config MACSEC
>   	tristate "IEEE 802.1AE MAC-level encryption (MACsec)"
>   	select CRYPTO
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 739838623cf6..50b23e71065f 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_WIREGUARD) += wireguard/
>   obj-$(CONFIG_EQUALIZER) += eql.o
>   obj-$(CONFIG_IFB) += ifb.o
>   obj-$(CONFIG_MACSEC) += macsec.o
> +obj-$(CONFIG_AMT) += amt.o
>   obj-$(CONFIG_MACVLAN) += macvlan.o
>   obj-$(CONFIG_MACVTAP) += macvtap.o
>   obj-$(CONFIG_MII) += mii.o
> diff --git a/drivers/net/amt.c b/drivers/net/amt.c
> new file mode 100644
> index 000000000000..8d4782c66cde
> --- /dev/null
> +++ b/drivers/net/amt.c
> @@ -0,0 +1,487 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/* Copyright (c) 2021 Taehee Yoo <ap420073@...il.com> */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/skbuff.h>
> +#include <linux/udp.h>
> +#include <linux/jhash.h>
> +#include <linux/if_tunnel.h>
> +#include <linux/net.h>
> +#include <linux/igmp.h>
> +#include <net/net_namespace.h>
> +#include <net/protocol.h>
> +#include <net/ip.h>
> +#include <net/udp.h>
> +#include <net/udp_tunnel.h>
> +#include <net/icmp.h>
> +#include <net/mld.h>
> +#include <net/amt.h>
> +#include <uapi/linux/amt.h>
> +#include <linux/security.h>
> +#include <net/gro_cells.h>
> +#include <net/ipv6.h>
> +#include <net/protocol.h>
> +#include <net/if_inet6.h>
> +#include <net/ndisc.h>
> +#include <net/addrconf.h>
> +#include <net/ip6_route.h>
> +#include <net/inet_common.h>
> +
> +static struct workqueue_struct *amt_wq;
> +
> +static struct socket *amt_create_sock(struct net *net, __be16 port)
> +{
> +	struct udp_port_cfg udp_conf;
> +	struct socket *sock;
> +	int err;
> +
> +	memset(&udp_conf, 0, sizeof(udp_conf));
> +	udp_conf.family = AF_INET;
> +	udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
> +
> +	udp_conf.local_udp_port = port;
> +
> +	err = udp_sock_create(net, &udp_conf, &sock);
> +	if (err < 0)
> +		return ERR_PTR(err);
> +
> +	return sock;
> +}
> +
> +static int amt_socket_create(struct amt_dev *amt)
> +{
> +	struct udp_tunnel_sock_cfg tunnel_cfg;
> +	struct socket *sock;
> +
> +	sock = amt_create_sock(amt->net, amt->relay_port);
> +	if (IS_ERR(sock))
> +		return PTR_ERR(sock);
> +
> +	/* Mark socket as an encapsulation socket */
> +	memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
> +	tunnel_cfg.sk_user_data = amt;
> +	tunnel_cfg.encap_type = 1;
> +	tunnel_cfg.encap_destroy = NULL;
> +	setup_udp_tunnel_sock(amt->net, sock, &tunnel_cfg);
> +
> +	rcu_assign_pointer(amt->sock, sock);
> +	return 0;
> +}
> +
> +static int amt_dev_open(struct net_device *dev)
> +{
> +	struct amt_dev *amt = netdev_priv(dev);
> +	int err;
> +
> +	amt->ready4 = false;
> +	amt->ready6 = false;
> +
> +	err = amt_socket_create(amt);
> +	if (err)
> +		return err;
> +
> +	spin_lock_bh(&amt->lock);
> +	amt->req_cnt = 0;
> +	get_random_bytes(&amt->key, sizeof(siphash_key_t));
> +	spin_unlock_bh(&amt->lock);
> +
> +	amt->status = AMT_STATUS_INIT;
> +	return err;
> +}
> +
> +static int amt_dev_stop(struct net_device *dev)
> +{
> +	struct amt_dev *amt = netdev_priv(dev);
> +	struct socket *sock;
> +
> +	/* shutdown */
> +	sock = rtnl_dereference(amt->sock);
> +	RCU_INIT_POINTER(amt->sock, NULL);
> +	synchronize_net();
> +	if (sock)
> +		udp_tunnel_sock_release(sock);
> +
> +	amt->ready4 = false;
> +	amt->ready6 = false;
> +
> +	return 0;
> +}
> +
> +static const struct device_type amt_type = {
> +	.name = "amt",
> +};
> +
> +static int amt_dev_init(struct net_device *dev)
> +{
> +	struct amt_dev *amt = netdev_priv(dev);
> +	int err;
> +
> +	amt->dev = dev;
> +	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
> +	if (!dev->tstats)
> +		return -ENOMEM;
> +
> +	err = gro_cells_init(&amt->gro_cells, dev);
> +	if (err) {
> +		free_percpu(dev->tstats);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static void amt_dev_uninit(struct net_device *dev)
> +{
> +	struct amt_dev *amt = netdev_priv(dev);
> +
> +	gro_cells_destroy(&amt->gro_cells);
> +	free_percpu(dev->tstats);
> +}
> +
> +static int amt_change_mtu(struct net_device *dev, int new_mtu)
> +{
> +	if (new_mtu > dev->max_mtu)
> +		new_mtu = dev->max_mtu;
> +	else if (new_mtu < dev->min_mtu)
> +		new_mtu = dev->min_mtu;
> +
> +	dev->mtu = new_mtu;
> +	return 0;
> +}
> +
> +static const struct net_device_ops amt_netdev_ops = {
> +	.ndo_init               = amt_dev_init,
> +	.ndo_uninit             = amt_dev_uninit,
> +	.ndo_open		= amt_dev_open,
> +	.ndo_stop		= amt_dev_stop,
> +	.ndo_get_stats64        = dev_get_tstats64,
> +	.ndo_change_mtu         = amt_change_mtu,
> +};
> +
> +static void amt_link_setup(struct net_device *dev)
> +{
> +	dev->netdev_ops         = &amt_netdev_ops;
> +	dev->needs_free_netdev  = true;
> +	SET_NETDEV_DEVTYPE(dev, &amt_type);
> +	dev->min_mtu		= ETH_MIN_MTU;
> +	dev->max_mtu		= ETH_MAX_MTU;
> +	dev->type		= ARPHRD_NONE;
> +	dev->flags		= IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
> +	dev->hard_header_len	= 0;
> +	dev->addr_len		= 0;
> +	dev->priv_flags		|= IFF_NO_QUEUE;
> +	dev->features		|= NETIF_F_LLTX;
> +	dev->features		|= NETIF_F_GSO_SOFTWARE;
> +	dev->features		|= NETIF_F_NETNS_LOCAL;
> +	dev->hw_features	|= NETIF_F_SG | NETIF_F_HW_CSUM;
> +	dev->hw_features	|= NETIF_F_FRAGLIST | NETIF_F_RXCSUM;
> +	dev->hw_features	|= NETIF_F_GSO_SOFTWARE;
> +	eth_hw_addr_random(dev);
> +	eth_zero_addr(dev->broadcast);
> +	ether_setup(dev);
> +}
> +
> +static const struct nla_policy amt_policy[IFLA_AMT_MAX + 1] = {
> +	[IFLA_AMT_MODE]		= { .type = NLA_U32 },
> +	[IFLA_AMT_RELAY_PORT]	= { .type = NLA_U16 },
> +	[IFLA_AMT_GATEWAY_PORT]	= { .type = NLA_U16 },
> +	[IFLA_AMT_LINK]		= { .type = NLA_U32 },
> +	[IFLA_AMT_LOCAL_IP]	= { .len = sizeof_field(struct iphdr, daddr) },
> +	[IFLA_AMT_REMOTE_IP]	= { .len = sizeof_field(struct iphdr, daddr) },
> +	[IFLA_AMT_DISCOVERY_IP]	= { .len = sizeof_field(struct iphdr, daddr) },
> +	[IFLA_AMT_MAX_TUNNELS]	= { .type = NLA_U32 },
> +};
> +
> +static int amt_validate(struct nlattr *tb[], struct nlattr *data[],
> +			struct netlink_ext_ack *extack)
> +{
> +	if (!data)
> +		return -EINVAL;
> +
> +	if (!data[IFLA_AMT_LINK]) {
> +		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_AMT_LINK],
> +				    "link interface should not be empty");
> +		return -EINVAL;
> +	}
> +
> +	if (!data[IFLA_AMT_MODE] ||
> +	    nla_get_u32(data[IFLA_AMT_MODE]) > AMT_MODE_MAX) {
> +		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_AMT_MODE],
> +				    "mode should not be empty");
> +		return -EINVAL;
> +	}
> +
> +	if (!data[IFLA_AMT_LOCAL_IP]) {
> +		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_AMT_DISCOVERY_IP],
> +				    "local should not be empty");
> +		return -EINVAL;
> +	}
> +
> +	if (!data[IFLA_AMT_DISCOVERY_IP] &&
> +	    nla_get_u32(data[IFLA_AMT_MODE]) == AMT_MODE_GATEWAY) {
> +		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_AMT_LOCAL_IP],
> +				    "discovery should not be empty");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int amt_newlink(struct net *net, struct net_device *dev,
> +		       struct nlattr *tb[], struct nlattr *data[],
> +		       struct netlink_ext_ack *extack)
> +{
> +	struct amt_dev *amt = netdev_priv(dev);
> +	int err;
> +
> +	amt->net = net;
> +	amt->mode = nla_get_u32(data[IFLA_AMT_MODE]);
> +
> +	if (data[IFLA_AMT_MAX_TUNNELS])
> +		amt->max_tunnels = nla_get_u32(data[IFLA_AMT_MAX_TUNNELS]);
> +	else
> +		amt->max_tunnels = AMT_MAX_TUNNELS;
> +
> +	spin_lock_init(&amt->lock);
> +	amt->max_groups = AMT_MAX_GROUP;
> +	amt->max_sources = AMT_MAX_SOURCE;
> +	amt->hash_buckets = AMT_HSIZE;
> +	amt->nr_tunnels = 0;
> +	get_random_bytes(&amt->hash_seed, sizeof(amt->hash_seed));
> +	amt->stream_dev = dev_get_by_index(net,
> +					   nla_get_u32(data[IFLA_AMT_LINK]));
> +	if (!amt->stream_dev) {
> +		NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_AMT_LINK],
> +				    "Can't find stream device");
> +		return -ENODEV;
> +	}
> +
> +	if (amt->stream_dev->type != ARPHRD_ETHER) {
> +		NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_AMT_LINK],
> +				    "Invalid stream device type");
> +		dev_put(amt->stream_dev);
> +		return -EINVAL;
> +	}
> +
> +	amt->local_ip = nla_get_in_addr(data[IFLA_AMT_LOCAL_IP]);
> +	if (data[IFLA_AMT_RELAY_PORT])
> +		amt->relay_port = nla_get_be16(data[IFLA_AMT_RELAY_PORT]);
> +	else
> +		amt->relay_port = htons(IANA_AMT_UDP_PORT);
> +
> +	if (data[IFLA_AMT_GATEWAY_PORT])
> +		amt->gw_port = nla_get_be16(data[IFLA_AMT_GATEWAY_PORT]);
> +	else
> +		amt->gw_port = htons(IANA_AMT_UDP_PORT);
> +
> +	if (!amt->relay_port) {
> +		NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_AMT_DISCOVERY_IP],
> +				    "relay port must not be 0");
		dev_put() here and below
> +		return -EINVAL;
> +	}
> +	if (amt->mode == AMT_MODE_RELAY) {
> +		amt->qrv = amt->net->ipv4.sysctl_igmp_qrv;
> +		amt->qri = 10;
> +		dev->needed_headroom = amt->stream_dev->needed_headroom +
> +				       AMT_RELAY_HLEN;
> +		dev->mtu = amt->stream_dev->mtu - AMT_RELAY_HLEN;
> +		dev->max_mtu = dev->mtu;
> +		dev->min_mtu = ETH_MIN_MTU + AMT_RELAY_HLEN;
> +	} else {
> +		if (!data[IFLA_AMT_DISCOVERY_IP]) {
> +			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_AMT_DISCOVERY_IP],
> +					    "discovery must be set in gateway mode");
> +			return -EINVAL;
> +		}
> +		if (!amt->gw_port) {
> +			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_AMT_DISCOVERY_IP],
> +					    "gateway port must not be 0");
> +			return -EINVAL;
> +		}
> +		amt->remote_ip = 0;
> +		amt->discovery_ip = nla_get_in_addr(data[IFLA_AMT_DISCOVERY_IP]);
> +		if (ipv4_is_loopback(amt->discovery_ip) ||
> +		    ipv4_is_multicast(amt->discovery_ip)) {
> +			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_AMT_DISCOVERY_IP],
> +					    "discovery must be unicast");
> +			return -EINVAL;
> +		}
> +
> +		dev->needed_headroom = amt->stream_dev->needed_headroom +
> +				       AMT_GW_HLEN;
> +		dev->mtu = amt->stream_dev->mtu - AMT_GW_HLEN;
> +		dev->max_mtu = dev->mtu;
> +		dev->min_mtu = ETH_MIN_MTU + AMT_GW_HLEN;
> +	}
> +	amt->qi = AMT_INIT_QUERY_INTERVAL;
> +
> +	err = register_netdevice(dev);
> +	if (err < 0) {
> +		netdev_dbg(dev, "failed to register new netdev %d\n", err);
> +		dev_put(amt->stream_dev);
> +		return err;
> +	}
> +
> +	err = netdev_upper_dev_link(amt->stream_dev, dev, extack);
> +	if (err < 0) {
> +		dev_put(amt->stream_dev);
> +		unregister_netdevice(dev);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static void amt_dellink(struct net_device *dev, struct list_head *head)
> +{
> +	struct amt_dev *amt = netdev_priv(dev);
> +
> +	unregister_netdevice_queue(dev, head);
> +	netdev_upper_dev_unlink(amt->stream_dev, dev);
> +	dev_put(amt->stream_dev);
> +}
> +
> +static size_t amt_get_size(const struct net_device *dev)
> +{
> +	return nla_total_size(sizeof(__u32)) + /* IFLA_AMT_MODE */
> +	       nla_total_size(sizeof(__u16)) + /* IFLA_AMT_RELAY_PORT */
> +	       nla_total_size(sizeof(__u16)) + /* IFLA_AMT_GATEWAY_PORT */
> +	       nla_total_size(sizeof(__u32)) + /* IFLA_AMT_LINK */
> +	       nla_total_size(sizeof(__u32)) + /* IFLA_MAX_TUNNELS */
> +	       nla_total_size(sizeof(struct iphdr)) + /* IFLA_AMT_DISCOVERY_IP */
> +	       nla_total_size(sizeof(struct iphdr)) + /* IFLA_AMT_REMOTE_IP */
> +	       nla_total_size(sizeof(struct iphdr)); /* IFLA_AMT_LOCAL_IP */
> +}
> +
> +static int amt_fill_info(struct sk_buff *skb, const struct net_device *dev)
> +{
> +	struct amt_dev *amt = netdev_priv(dev);
> +
> +	if (nla_put_u32(skb, IFLA_AMT_MODE, amt->mode))
> +		goto nla_put_failure;
> +	if (nla_put_be16(skb, IFLA_AMT_RELAY_PORT, amt->relay_port))
> +		goto nla_put_failure;
> +	if (nla_put_be16(skb, IFLA_AMT_GATEWAY_PORT, amt->gw_port))
> +		goto nla_put_failure;
> +	if (amt->stream_dev)
> +		if (nla_put_u32(skb, IFLA_AMT_LINK, amt->stream_dev->ifindex))
> +			goto nla_put_failure;
> +	if (nla_put_in_addr(skb, IFLA_AMT_LOCAL_IP, amt->local_ip))
> +		goto nla_put_failure;
> +	if (nla_put_in_addr(skb, IFLA_AMT_DISCOVERY_IP, amt->discovery_ip))
> +		goto nla_put_failure;
> +	if (amt->remote_ip)
> +		if (nla_put_in_addr(skb, IFLA_AMT_REMOTE_IP, amt->remote_ip))
> +			goto nla_put_failure;
> +
> +	return 0;
> +
> +nla_put_failure:
> +	return -EMSGSIZE;
> +}
> +
> +static struct rtnl_link_ops amt_link_ops __read_mostly = {
> +	.kind		= "amt",
> +	.maxtype	= IFLA_AMT_MAX,
> +	.policy		= amt_policy,
> +	.priv_size	= sizeof(struct amt_dev),
> +	.setup		= amt_link_setup,
> +	.validate	= amt_validate,
> +	.newlink	= amt_newlink,
> +	.dellink	= amt_dellink,
> +	.get_size       = amt_get_size,
> +	.fill_info      = amt_fill_info,
> +};
> +
> +static struct net_device *amt_lookup_upper_dev(struct net_device *dev)
> +{
> +	struct net_device *upper_dev;
> +	struct amt_dev *amt;
> +
> +	for_each_netdev(dev_net(dev), upper_dev) {
> +		if (netif_is_amt(upper_dev)) {
> +			amt = netdev_priv(upper_dev);
> +			if (amt->stream_dev == dev)
> +				return upper_dev;
> +		}
> +	}
> +
> +	return NULL;
> +}
> +
> +static int amt_device_event(struct notifier_block *unused,
> +			    unsigned long event, void *ptr)
> +{
> +	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
> +	struct net_device *upper_dev;
> +	struct amt_dev *amt;
> +	LIST_HEAD(list);
> +	int new_mtu;
> +
> +	upper_dev = amt_lookup_upper_dev(dev);
> +	if (!upper_dev)
> +		return NOTIFY_DONE;
> +	amt = netdev_priv(upper_dev);
> +
> +	switch (event) {
> +	case NETDEV_UNREGISTER:
> +		amt_dellink(amt->dev, &list);
> +		unregister_netdevice_many(&list);
> +		break;
> +	case NETDEV_CHANGEMTU:
> +		if (amt->mode == AMT_MODE_RELAY)
> +			new_mtu = dev->mtu - AMT_RELAY_HLEN;
> +		else
> +			new_mtu = dev->mtu - AMT_GW_HLEN;
> +		amt_change_mtu(amt->dev, new_mtu);
> +		break;
> +	}
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block amt_notifier_block __read_mostly = {
> +	.notifier_call = amt_device_event,
> +};
> +
> +static int __init amt_init(void)
> +{
> +	int err;
> +
> +	err = register_netdevice_notifier(&amt_notifier_block);
> +	if (err < 0)
> +		goto err;
> +
> +	err = rtnl_link_register(&amt_link_ops);
> +	if (err < 0)
> +		goto unregister_notifier;
> +
> +	amt_wq = alloc_workqueue("amt", WQ_UNBOUND, 1);
> +	if (!amt_wq)
> +		goto rtnl_unregister;
> +
> +	return 0;
> +
> +rtnl_unregister:
> +	rtnl_link_unregister(&amt_link_ops);
> +unregister_notifier:
> +	unregister_netdevice_notifier(&amt_notifier_block);
> +err:
> +	pr_err("error loading AMT module loaded\n");
> +	return err;
> +}
> +late_initcall(amt_init);
> +
> +static void __exit amt_fini(void)
> +{
> +	rtnl_link_unregister(&amt_link_ops);
> +	unregister_netdevice_notifier(&amt_notifier_block);
> +	destroy_workqueue(amt_wq);
> +}
> +module_exit(amt_fini);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Taehee Yoo <ap420073@...il.com>");
> +MODULE_ALIAS_RTNL_LINK("amt");
> diff --git a/include/net/amt.h b/include/net/amt.h
> new file mode 100644
> index 000000000000..e1520d71d782
> --- /dev/null
> +++ b/include/net/amt.h
> @@ -0,0 +1,236 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2021 Taehee Yoo <ap420073@...il.com>
> + */
> +#ifndef _NET_AMT_H_
> +#define _NET_AMT_H_
> +
> +#include <linux/siphash.h>
> +#include <linux/workqueue.h>
> +#include <linux/jhash.h>
> +
> +enum amt_msg_type {
> +	AMT_MSG_DISCOVERY = 1,
> +	AMT_MSG_ADVERTISEMENT,
> +	AMT_MSG_REQUEST,
> +	AMT_MSG_MEMBERSHIP_QUERY,
> +	AMT_MSG_MEMBERSHIP_UPDATE,
> +	AMT_MSG_MULTICAST_DATA,
> +	AMT_MSG_TEATDOWM,
> +	__AMT_MSG_MAX,
> +};
> +
> +#define AMT_MSG_MAX (__AMT_MSG_MAX - 1)
> +
> +enum amt_status {
> +	AMT_STATUS_INIT,
> +	AMT_STATUS_SENT_DISCOVERY,
> +	AMT_STATUS_RECEIVED_DISCOVERY,
> +	AMT_STATUS_SENT_ADVERTISEMENT,
> +	AMT_STATUS_RECEIVED_ADVERTISEMENT,
> +	AMT_STATUS_SENT_REQUEST,
> +	AMT_STATUS_RECEIVED_REQUEST,
> +	AMT_STATUS_SENT_QUERY,
> +	AMT_STATUS_RECEIVED_QUERY,
> +	AMT_STATUS_SENT_UPDATE,
> +	AMT_STATUS_RECEIVED_UPDATE,
> +	__AMT_STATUS_MAX,
> +};
> +
> +#define AMT_STATUS_MAX (__AMT_STATUS_MAX - 1)
> +
> +struct amt_header_discovery {
> +#if defined(__LITTLE_ENDIAN_BITFIELD)
> +	u32	type:4,
> +		version:4,
> +		reserved:24;
> +#elif defined(__BIG_ENDIAN_BITFIELD)
> +	u32	version:4,
> +		type:4,
> +		reserved:24;
> +#else
> +#error  "Please fix <asm/byteorder.h>"
> +#endif
> +	__be32	nonce;
> +} __packed;
> +
> +struct amt_header_advertisement {
> +#if defined(__LITTLE_ENDIAN_BITFIELD)
> +	u32	type:4,
> +		version:4,
> +		reserved:24;
> +#elif defined(__BIG_ENDIAN_BITFIELD)
> +	u32	version:4,
> +		type:4,
> +		reserved:24;
> +#else
> +#error  "Please fix <asm/byteorder.h>"
> +#endif
> +	__be32	nonce;
> +	__be32	ip4;
> +} __packed;
> +
> +struct amt_header_request {
> +#if defined(__LITTLE_ENDIAN_BITFIELD)
> +	u32	type:4,
> +		version:4,
> +		reserved1:7,
> +		p:1,
> +		reserved2:16;
> +#elif defined(__BIG_ENDIAN_BITFIELD)
> +	u32	version:4,
> +		type:4,
> +		p:1,
> +		reserved1:7,
> +		reserved2:16;
> +#else
> +#error  "Please fix <asm/byteorder.h>"
> +#endif
> +	__be32	nonce;
> +} __packed;
> +
> +struct amt_header_membership_query {
> +#if defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64	type:4,
> +		version:4,
> +		reserved:6,
> +		l:1,
> +		g:1,
> +		response_mac:48;
> +#elif defined(__BIG_ENDIAN_BITFIELD)
> +	u64	version:4,
> +		type:4,
> +		g:1,
> +		l:1,
> +		reserved:6,
> +		response_mac:48;
> +#else
> +#error  "Please fix <asm/byteorder.h>"
> +#endif
> +	__be32	nonce;
> +} __packed;
> +
> +struct amt_header_membership_update {
> +#if defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64	type:4,
> +		version:4,
> +		reserved:8,
> +		response_mac:48;
> +#elif defined(__BIG_ENDIAN_BITFIELD)
> +	u64	version:4,
> +		type:4,
> +		reserved:8,
> +		response_mac:48;
> +#else
> +#error  "Please fix <asm/byteorder.h>"
> +#endif
> +	__be32	nonce;
> +} __packed;
> +
> +struct amt_header_mcast_data {
> +#if defined(__LITTLE_ENDIAN_BITFIELD)
> +	u16	type:4,
> +		version:4,
> +		reserved:8;
> +#elif defined(__BIG_ENDIAN_BITFIELD)
> +	u16	version:4,
> +		type:4,
> +		reserved:8;
> +#else
> +#error  "Please fix <asm/byteorder.h>"
> +#endif
> +} __packed;
> +
> +struct amt_gw_headers {
> +	union {
> +		struct amt_header_discovery discovery;
> +		struct amt_header_request request;
> +		struct amt_header_membership_update update;
> +	};
> +} __packed;
> +
> +struct amt_relay_headers {
> +	union {
> +		struct amt_header_advertisement advertisement;
> +		struct amt_header_membership_query query;
> +		struct amt_header_mcast_data data;
> +	};
> +} __packed;
> +
> +struct amt_dev {
> +	struct net_device       *dev;
> +	struct net_device       *stream_dev;
> +	struct net		*net;
> +	/* Global lock for amt device */
> +	spinlock_t		lock;
> +	/* Used only in relay mode */
> +	struct list_head        tunnel_list;
> +	struct gro_cells	gro_cells;
> +
> +	/* Protected by RTNL */
> +	struct delayed_work     discovery_wq;
> +	/* Protected by RTNL */
> +	struct delayed_work     req_wq;
> +	/* Protected by RTNL */
> +	struct delayed_work     secret_wq;
> +	/* AMT status */
> +	enum amt_status		status;
> +	/* Generated key */
> +	siphash_key_t		key;
> +	struct socket	  __rcu *sock;
> +	u32			max_groups;
> +	u32			max_sources;
> +	u32			hash_buckets;
> +	u32			hash_seed;
> +	/* Default 128 */
> +	u32                     max_tunnels;
> +	/* Default 128 */
> +	u32                     nr_tunnels;
> +	/* Gateway or Relay mode */
> +	u32                     mode;
> +	/* Default 2268 */
> +	__be16			relay_port;
> +	/* Default 2268 */
> +	__be16			gw_port;
> +	/* Outer local ip */
> +	__be32			local_ip;
> +	/* Outer remote ip */
> +	__be32			remote_ip;
> +	/* Outer discovery ip */
> +	__be32			discovery_ip;
> +	/* Only used in gateway mode */
> +	__be32			nonce;
> +	/* Gateway sent request and received query */
> +	bool			ready4;
> +	bool			ready6;
> +	u8			req_cnt;
> +	u8			qi;
> +	u64			qrv;
> +	u64			qri;
> +	/* Used only in gateway mode */
> +	u64			mac:48,
> +				reserved:16;
> +};
> +
> +#define AMT_MAX_GROUP		32
> +#define AMT_MAX_SOURCE		128
> +#define AMT_HSIZE_SHIFT		8
> +#define AMT_HSIZE		(1 << AMT_HSIZE_SHIFT)
> +
> +#define AMT_INIT_QUERY_INTERVAL	125
> +#define IANA_AMT_UDP_PORT	2268
> +#define AMT_MAX_TUNNELS         128
> +#define AMT_MAX_REQS		128
> +#define AMT_GW_HLEN (sizeof(struct iphdr) + \
> +		     sizeof(struct udphdr) + \
> +		     sizeof(struct amt_gw_headers))
> +#define AMT_RELAY_HLEN (sizeof(struct iphdr) + \
> +		     sizeof(struct udphdr) + \
> +		     sizeof(struct amt_relay_headers))
> +
> +static inline bool netif_is_amt(const struct net_device *dev)
> +{
> +	return dev->rtnl_link_ops && !strcmp(dev->rtnl_link_ops->kind, "amt");
> +}
> +
> +#endif /* _NET_AMT_H_ */
> diff --git a/include/uapi/linux/amt.h b/include/uapi/linux/amt.h
> new file mode 100644
> index 000000000000..641ef7f51253
> --- /dev/null
> +++ b/include/uapi/linux/amt.h
> @@ -0,0 +1,31 @@
> +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
> +/*
> + * Copyright (c) 2021 Taehee Yoo <ap420073@...il.com>
> + */
> +#ifndef _UAPI_AMT_H_
> +#define _UAPI_AMT_H_
> +
> +enum ifla_amt_mode {
> +	AMT_MODE_GATEWAY = 0,
> +	AMT_MODE_RELAY,
> +	__AMT_MODE_MAX,
> +};
> +
> +#define AMT_MODE_MAX (__AMT_MODE_MAX - 1)
> +
> +enum {
> +	IFLA_AMT_UNSPEC,
> +	IFLA_AMT_MODE,
> +	IFLA_AMT_RELAY_PORT,
> +	IFLA_AMT_GATEWAY_PORT,
> +	IFLA_AMT_LINK,
> +	IFLA_AMT_LOCAL_IP,
> +	IFLA_AMT_REMOTE_IP,
> +	IFLA_AMT_DISCOVERY_IP,
> +	IFLA_AMT_MAX_TUNNELS,
> +	__IFLA_AMT_MAX,
> +};
> +
> +#define IFLA_AMT_MAX (__IFLA_AMT_MAX - 1)
> +
> +#endif /* _UAPI_AMT_H_ */
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ