Merge branch 'amt-driver'

Taehee Yoo says:

====================
amt: add initial driver for Automatic Multicast Tunneling (AMT)

This is an implementation of AMT(Automatic Multicast Tunneling), RFC 7450.
https://datatracker.ietf.org/doc/html/rfc7450

This implementation supports IGMPv2, IGMPv3, MLDv1, MLDv2, and IPv4
underlay.

 Summary of RFC 7450
The purpose of this protocol is to provide multicast tunneling.
The main use-case of this protocol is to provide delivery multicast
traffic from a multicast-enabled network to sites that lack multicast
connectivity to the source network.
There are two roles in AMT protocol, Gateway, and Relay.
The main purpose of Gateway mode is to forward multicast listening
information(IGMP, MLD) to the source.
The main purpose of Relay mode is to forward multicast data to listeners.
These multicast traffics(IGMP, MLD, multicast data packets) are tunneled.

Listeners are located behind Gateway endpoint.
But gateway itself can be a listener too.
Senders are located behind Relay endpoint.

    ___________       _________       _______       ________
   |           |     |         |     |       |     |        |
   | Listeners <-----> Gateway <-----> Relay <-----> Source |
   |___________|     |_________|     |_______|     |________|
      IGMP/MLD---------(encap)----------->
         <-------------(decap)--------(encap)------Multicast Data

 Usage of AMT interface
1. Create gateway interface
ip link add amtg type amt mode gateway local 10.0.0.1 discovery 10.0.0.2 \
dev gw1_rt gateway_port 2268 relay_port 2268

2. Create Relay interface
ip link add amtr type amt mode relay local 10.0.0.2 dev relay_rt \
relay_port 2268 max_tunnels 4

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.
 - Use CHECKSUM_NONE instead of CHECKSUM_UNNECESSARY.
 - Fix compile error.

v4 -> v5:
 - Remove unnecessary rcu_read_lock().
 - Remove unnecessary amt_change_mtu().
 - Change netlink error message.
 - Add validation for IFLA_AMT_LOCAL_IP and IFLA_AMT_DISCOVERY_IP.
 - Add comments in amt.h.
 - Add missing dev_put() in error path of amt_newlink().
 - Fix typo.
 - Add BUILD_BUG_ON() in amt_smb_cb().
 - Use macro instead of magic values.
 - Use kzalloc() instead of kmalloc().
 - Add selftest script.

v5 -> v6:
 - Reset remote_ip in amt_dev_stop().

v6 -> v7:
 - Fix compile error.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2021-11-01 13:36:09 +00:00
commit 6008889121
9 changed files with 4054 additions and 0 deletions

View File

@ -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@gmail.com>
L: netdev@vger.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@analog.com>
L: linux-iio@vger.kernel.org

View File

@ -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

View File

@ -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

3296
drivers/net/amt.c Normal file

File diff suppressed because it is too large Load Diff

385
include/net/amt.h Normal file
View File

@ -0,0 +1,385 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2021 Taehee Yoo <ap420073@gmail.com>
*/
#ifndef _NET_AMT_H_
#define _NET_AMT_H_
#include <linux/siphash.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_TEARDOWM,
__AMT_MSG_MAX,
};
#define AMT_MSG_MAX (__AMT_MSG_MAX - 1)
enum amt_ops {
/* A*B */
AMT_OPS_INT,
/* A+B */
AMT_OPS_UNI,
/* A-B */
AMT_OPS_SUB,
/* B-A */
AMT_OPS_SUB_REV,
__AMT_OPS_MAX,
};
#define AMT_OPS_MAX (__AMT_OPS_MAX - 1)
enum amt_filter {
AMT_FILTER_FWD,
AMT_FILTER_D_FWD,
AMT_FILTER_FWD_NEW,
AMT_FILTER_D_FWD_NEW,
AMT_FILTER_ALL,
AMT_FILTER_NONE_NEW,
AMT_FILTER_BOTH,
AMT_FILTER_BOTH_NEW,
__AMT_FILTER_MAX,
};
#define AMT_FILTER_MAX (__AMT_FILTER_MAX - 1)
enum amt_act {
AMT_ACT_GMI,
AMT_ACT_GMI_ZERO,
AMT_ACT_GT,
AMT_ACT_STATUS_FWD_NEW,
AMT_ACT_STATUS_D_FWD_NEW,
AMT_ACT_STATUS_NONE_NEW,
__AMT_ACT_MAX,
};
#define AMT_ACT_MAX (__AMT_ACT_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 {
#if defined(__LITTLE_ENDIAN_BITFIELD)
u8 type:4,
version:4;
#elif defined(__BIG_ENDIAN_BITFIELD)
u8 version:4,
type:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} __packed;
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_headers {
union {
struct amt_header_discovery discovery;
struct amt_header_advertisement advertisement;
struct amt_header_request request;
struct amt_header_membership_query query;
struct amt_header_membership_update update;
struct amt_header_mcast_data data;
};
} __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_skb_cb {
struct amt_tunnel_list *tunnel;
};
struct amt_tunnel_list {
struct list_head list;
/* Protect All resources under an amt_tunne_list */
spinlock_t lock;
struct amt_dev *amt;
u32 nr_groups;
u32 nr_sources;
enum amt_status status;
struct delayed_work gc_wq;
__be16 source_port;
__be32 ip4;
__be32 nonce;
siphash_key_t key;
u64 mac:48,
reserved:16;
struct rcu_head rcu;
struct hlist_head groups[];
};
union amt_addr {
__be32 ip4;
#if IS_ENABLED(CONFIG_IPV6)
struct in6_addr ip6;
#endif
};
/* RFC 3810
*
* When the router is in EXCLUDE mode, the router state is represented
* by the notation EXCLUDE (X,Y), where X is called the "Requested List"
* and Y is called the "Exclude List". All sources, except those from
* the Exclude List, will be forwarded by the router
*/
enum amt_source_status {
AMT_SOURCE_STATUS_NONE,
/* Node of Requested List */
AMT_SOURCE_STATUS_FWD,
/* Node of Exclude List */
AMT_SOURCE_STATUS_D_FWD,
};
/* protected by gnode->lock */
struct amt_source_node {
struct hlist_node node;
struct amt_group_node *gnode;
struct delayed_work source_timer;
union amt_addr source_addr;
enum amt_source_status status;
#define AMT_SOURCE_OLD 0
#define AMT_SOURCE_NEW 1
u8 flags;
struct rcu_head rcu;
};
/* Protected by amt_tunnel_list->lock */
struct amt_group_node {
struct amt_dev *amt;
union amt_addr group_addr;
union amt_addr host_addr;
bool v6;
u8 filter_mode;
u32 nr_sources;
struct amt_tunnel_list *tunnel_list;
struct hlist_node node;
struct delayed_work group_timer;
struct rcu_head rcu;
struct hlist_head sources[];
};
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_TOS 0xc0
#define AMT_IPHDR_OPTS 4
#define AMT_IP6HDR_OPTS 8
#define AMT_GC_INTERVAL (30 * 1000)
#define AMT_MAX_GROUP 32
#define AMT_MAX_SOURCE 128
#define AMT_HSIZE_SHIFT 8
#define AMT_HSIZE (1 << AMT_HSIZE_SHIFT)
#define AMT_DISCOVERY_TIMEOUT 5000
#define AMT_INIT_REQ_TIMEOUT 1
#define AMT_INIT_QUERY_INTERVAL 125
#define AMT_MAX_REQ_TIMEOUT 120
#define AMT_MAX_REQ_COUNT 3
#define AMT_SECRET_TIMEOUT 60000
#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");
}
static inline u64 amt_gmi(const struct amt_dev *amt)
{
return ((amt->qrv * amt->qi) + amt->qri) * 1000;
}
#endif /* _NET_AMT_H_ */

62
include/uapi/linux/amt.h Normal file
View File

@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Copyright (c) 2021 Taehee Yoo <ap420073@gmail.com>
*/
#ifndef _UAPI_AMT_H_
#define _UAPI_AMT_H_
enum ifla_amt_mode {
/* AMT interface works as Gateway mode.
* The Gateway mode encapsulates IGMP/MLD traffic and decapsulates
* multicast traffic.
*/
AMT_MODE_GATEWAY = 0,
/* AMT interface works as Relay mode.
* The Relay mode encapsulates multicast traffic and decapsulates
* IGMP/MLD traffic.
*/
AMT_MODE_RELAY,
__AMT_MODE_MAX,
};
#define AMT_MODE_MAX (__AMT_MODE_MAX - 1)
enum {
IFLA_AMT_UNSPEC,
/* This attribute specify mode etier Gateway or Relay. */
IFLA_AMT_MODE,
/* This attribute specify Relay port.
* AMT interface is created as Gateway mode, this attribute is used
* to specify relay(remote) port.
* AMT interface is created as Relay mode, this attribute is used
* as local port.
*/
IFLA_AMT_RELAY_PORT,
/* This attribute specify Gateway port.
* AMT interface is created as Gateway mode, this attribute is used
* as local port.
* AMT interface is created as Relay mode, this attribute is not used.
*/
IFLA_AMT_GATEWAY_PORT,
/* This attribute specify physical device */
IFLA_AMT_LINK,
/* This attribute specify local ip address */
IFLA_AMT_LOCAL_IP,
/* This attribute specify Relay ip address.
* So, this is not used by Relay.
*/
IFLA_AMT_REMOTE_IP,
/* This attribute specify Discovery ip address.
* When Gateway get started, it send discovery message to find the
* Relay's ip address.
* So, this is not used by Relay.
*/
IFLA_AMT_DISCOVERY_IP,
/* This attribute specify number of maximum tunnel. */
IFLA_AMT_MAX_TUNNELS,
__IFLA_AMT_MAX,
};
#define IFLA_AMT_MAX (__IFLA_AMT_MAX - 1)
#endif /* _UAPI_AMT_H_ */

View File

@ -22,6 +22,7 @@ TEST_PROGS += devlink_port_split.py
TEST_PROGS += drop_monitor_tests.sh
TEST_PROGS += vrf_route_leaking.sh
TEST_PROGS += bareudp.sh
TEST_PROGS += amt.sh
TEST_PROGS += unicast_extensions.sh
TEST_PROGS += udpgro_fwd.sh
TEST_PROGS += veth.sh

View File

@ -0,0 +1,284 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Author: Taehee Yoo <ap420073@gmail.com>
#
# This script evaluates the AMT driver.
# There are four network-namespaces, LISTENER, SOURCE, GATEWAY, RELAY.
# The role of LISTENER is to listen multicast traffic.
# In order to do that, it send IGMP group join message.
# The role of SOURCE is to send multicast traffic to listener.
# The role of GATEWAY is to work Gateway role of AMT interface.
# The role of RELAY is to work Relay role of AMT interface.
#
#
# +------------------------+
# | LISTENER netns |
# | |
# | +------------------+ |
# | | l_gw | |
# | | 192.168.0.2/24 | |
# | | 2001:db8::2/64 | |
# | +------------------+ |
# | . |
# +------------------------+
# .
# .
# +-----------------------------------------------------+
# | . GATEWAY netns |
# | . |
# |+---------------------------------------------------+|
# || . br0 ||
# || +------------------+ +------------------+ ||
# || | gw_l | | amtg | ||
# || | 192.168.0.1/24 | +--------+---------+ ||
# || | 2001:db8::1/64 | | ||
# || +------------------+ | ||
# |+-------------------------------------|-------------+|
# | | |
# | +--------+---------+ |
# | | gw_relay | |
# | | 10.0.0.1/24 | |
# | +------------------+ |
# | . |
# +-----------------------------------------------------+
# .
# .
# +-----------------------------------------------------+
# | RELAY netns . |
# | +------------------+ |
# | | relay_gw | |
# | | 10.0.0.2/24 | |
# | +--------+---------+ |
# | | |
# | | |
# | +------------------+ +--------+---------+ |
# | | relay_src | | amtr | |
# | | 172.17.0.1/24 | +------------------+ |
# | | 2001:db8:3::1/64 | |
# | +------------------+ |
# | . |
# | . |
# +-----------------------------------------------------+
# .
# .
# +------------------------+
# | . |
# | +------------------+ |
# | | src_relay | |
# | | 172.17.0.2/24 | |
# | | 2001:db8:3::2/64 | |
# | +------------------+ |
# | SOURCE netns |
# +------------------------+
#==============================================================================
readonly LISTENER=$(mktemp -u listener-XXXXXXXX)
readonly GATEWAY=$(mktemp -u gateway-XXXXXXXX)
readonly RELAY=$(mktemp -u relay-XXXXXXXX)
readonly SOURCE=$(mktemp -u source-XXXXXXXX)
ERR=4
err=0
exit_cleanup()
{
for ns in "$@"; do
ip netns delete "${ns}" 2>/dev/null || true
done
exit $ERR
}
create_namespaces()
{
ip netns add "${LISTENER}" || exit_cleanup
ip netns add "${GATEWAY}" || exit_cleanup "${LISTENER}"
ip netns add "${RELAY}" || exit_cleanup "${LISTENER}" "${GATEWAY}"
ip netns add "${SOURCE}" || exit_cleanup "${LISTENER}" "${GATEWAY}" \
"${RELAY}"
}
# The trap function handler
#
exit_cleanup_all()
{
exit_cleanup "${LISTENER}" "${GATEWAY}" "${RELAY}" "${SOURCE}"
}
setup_interface()
{
for ns in "${LISTENER}" "${GATEWAY}" "${RELAY}" "${SOURCE}"; do
ip -netns "${ns}" link set dev lo up
done;
ip link add l_gw type veth peer name gw_l
ip link add gw_relay type veth peer name relay_gw
ip link add relay_src type veth peer name src_relay
ip link set l_gw netns "${LISTENER}" up
ip link set gw_l netns "${GATEWAY}" up
ip link set gw_relay netns "${GATEWAY}" up
ip link set relay_gw netns "${RELAY}" up
ip link set relay_src netns "${RELAY}" up
ip link set src_relay netns "${SOURCE}" up mtu 1400
ip netns exec "${LISTENER}" ip a a 192.168.0.2/24 dev l_gw
ip netns exec "${LISTENER}" ip r a default via 192.168.0.1 dev l_gw
ip netns exec "${LISTENER}" ip a a 2001:db8::2/64 dev l_gw
ip netns exec "${LISTENER}" ip r a default via 2001:db8::1 dev l_gw
ip netns exec "${LISTENER}" ip a a 239.0.0.1/32 dev l_gw autojoin
ip netns exec "${LISTENER}" ip a a ff0e::5:6/128 dev l_gw autojoin
ip netns exec "${GATEWAY}" ip a a 192.168.0.1/24 dev gw_l
ip netns exec "${GATEWAY}" ip a a 2001:db8::1/64 dev gw_l
ip netns exec "${GATEWAY}" ip a a 10.0.0.1/24 dev gw_relay
ip netns exec "${GATEWAY}" ip link add br0 type bridge
ip netns exec "${GATEWAY}" ip link set br0 up
ip netns exec "${GATEWAY}" ip link set gw_l master br0
ip netns exec "${GATEWAY}" ip link set gw_l up
ip netns exec "${GATEWAY}" ip link add amtg master br0 type amt \
mode gateway local 10.0.0.1 discovery 10.0.0.2 dev gw_relay \
gateway_port 2268 relay_port 2268
ip netns exec "${RELAY}" ip a a 10.0.0.2/24 dev relay_gw
ip netns exec "${RELAY}" ip link add amtr type amt mode relay \
local 10.0.0.2 dev relay_gw relay_port 2268 max_tunnels 4
ip netns exec "${RELAY}" ip a a 172.17.0.1/24 dev relay_src
ip netns exec "${RELAY}" ip a a 2001:db8:3::1/64 dev relay_src
ip netns exec "${SOURCE}" ip a a 172.17.0.2/24 dev src_relay
ip netns exec "${SOURCE}" ip a a 2001:db8:3::2/64 dev src_relay
ip netns exec "${SOURCE}" ip r a default via 172.17.0.1 dev src_relay
ip netns exec "${SOURCE}" ip r a default via 2001:db8:3::1 dev src_relay
ip netns exec "${RELAY}" ip link set amtr up
ip netns exec "${GATEWAY}" ip link set amtg up
}
setup_sysctl()
{
ip netns exec "${RELAY}" sysctl net.ipv4.ip_forward=1 -w -q
}
setup_iptables()
{
ip netns exec "${RELAY}" iptables -t mangle -I PREROUTING \
-d 239.0.0.1 -j TTL --ttl-set 2
ip netns exec "${RELAY}" ip6tables -t mangle -I PREROUTING \
-j HL --hl-set 2
}
setup_mcast_routing()
{
ip netns exec "${RELAY}" smcrouted
ip netns exec "${RELAY}" smcroutectl a relay_src \
172.17.0.2 239.0.0.1 amtr
ip netns exec "${RELAY}" smcroutectl a relay_src \
2001:db8:3::2 ff0e::5:6 amtr
}
test_remote_ip()
{
REMOTE=$(ip netns exec "${GATEWAY}" \
ip -d -j link show amtg | jq .[0].linkinfo.info_data.remote)
if [ $REMOTE == "\"10.0.0.2\"" ]; then
printf "TEST: %-60s [ OK ]\n" "amt discovery"
else
printf "TEST: %-60s [FAIL]\n" "amt discovery"
ERR=1
fi
}
send_mcast_torture4()
{
ip netns exec "${SOURCE}" bash -c \
'cat /dev/urandom | head -c 1G | nc -w 1 -u 239.0.0.1 4001'
}
send_mcast_torture6()
{
ip netns exec "${SOURCE}" bash -c \
'cat /dev/urandom | head -c 1G | nc -w 1 -u ff0e::5:6 6001'
}
check_features()
{
ip link help 2>&1 | grep -q amt
if [ $? -ne 0 ]; then
echo "Missing amt support in iproute2" >&2
exit_cleanup
fi
}
test_ipv4_forward()
{
RESULT4=$(ip netns exec "${LISTENER}" nc -w 1 -l -u 239.0.0.1 4000)
if [ "$RESULT4" == "172.17.0.2" ]; then
printf "TEST: %-60s [ OK ]\n" "IPv4 amt multicast forwarding"
exit 0
else
printf "TEST: %-60s [FAIL]\n" "IPv4 amt multicast forwarding"
exit 1
fi
}
test_ipv6_forward()
{
RESULT6=$(ip netns exec "${LISTENER}" nc -w 1 -l -u ff0e::5:6 6000)
if [ "$RESULT6" == "2001:db8:3::2" ]; then
printf "TEST: %-60s [ OK ]\n" "IPv6 amt multicast forwarding"
exit 0
else
printf "TEST: %-60s [FAIL]\n" "IPv6 amt multicast forwarding"
exit 1
fi
}
send_mcast4()
{
sleep 2
ip netns exec "${SOURCE}" bash -c \
'echo 172.17.0.2 | nc -w 1 -u 239.0.0.1 4000' &
}
send_mcast6()
{
sleep 2
ip netns exec "${SOURCE}" bash -c \
'echo 2001:db8:3::2 | nc -w 1 -u ff0e::5:6 6000' &
}
check_features
create_namespaces
set -e
trap exit_cleanup_all EXIT
setup_interface
setup_sysctl
setup_iptables
setup_mcast_routing
test_remote_ip
test_ipv4_forward &
pid=$!
send_mcast4
wait $pid || err=$?
if [ $err -eq 1 ]; then
ERR=1
fi
test_ipv6_forward &
pid=$!
send_mcast6
wait $pid || err=$?
if [ $err -eq 1 ]; then
ERR=1
fi
send_mcast_torture4
printf "TEST: %-60s [ OK ]\n" "IPv4 amt traffic forwarding torture"
send_mcast_torture6
printf "TEST: %-60s [ OK ]\n" "IPv6 amt traffic forwarding torture"
sleep 5
if [ "${ERR}" -eq 1 ]; then
echo "Some tests failed." >&2
else
ERR=0
fi

View File

@ -44,3 +44,4 @@ CONFIG_NET_ACT_MIRRED=m
CONFIG_BAREUDP=m
CONFIG_IPV6_IOAM6_LWTUNNEL=y
CONFIG_CRYPTO_SM4=y
CONFIG_AMT=m