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] [day] [month] [year] [list]
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

Powered by Openwall GNU/*/Linux Powered by OpenVZ