[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <f765a500-742c-4384-3495-75474d878810@gmail.com>
Date: Fri, 29 Oct 2021 00:03:27 +0900
From: Taehee Yoo <ap420073@...il.com>
To: Denis Kirjanov <dkirjanov@...e.de>, 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
Hi Denis,
Thank you for your review!
On 10/28/21 10:57 PM, Denis Kirjanov wrote:
>
>
> 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
Thanks, I will fix it!
>> + 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_ */
>>
Thanks a lot,
Taehee
Powered by blists - more mailing lists