mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
Merge branch 'geneve-allow-binding-udp-socket-to-a-specific-address'
Kuniyuki Iwashima says: ==================== geneve: Allow binding UDP socket to a specific address. By default, a GENEVE device bind()s its underlying UDP socket(s) to the IPv4 or IPv6 wildcard address because there is no way to specify a specific local IP address to bind() to. This prevents deploying multiple GENEVE devices on a multi-homed host where each device should be isolated and bound to a different local IP address on the same UDP port. This series introduces two options to specify local IPv4 or IPv6 addresses for a GENEVE device. ==================== Link: https://patch.msgid.link/20260602190436.139591-1-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
1de680c1c4
|
|
@ -1941,6 +1941,15 @@ attribute-sets:
|
|||
-
|
||||
name: gro-hint
|
||||
type: flag
|
||||
-
|
||||
name: local
|
||||
type: u32
|
||||
byte-order: big-endian
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: local6
|
||||
type: binary
|
||||
display-hint: ipv6
|
||||
-
|
||||
name: linkinfo-hsr-attrs
|
||||
name-prefix: ifla-hsr-
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ struct geneve_dev_node {
|
|||
|
||||
struct geneve_config {
|
||||
bool collect_md;
|
||||
bool dualstack;
|
||||
bool use_udp6_rx_checksums;
|
||||
bool ttl_inherit;
|
||||
bool gro_hint;
|
||||
|
|
@ -760,9 +761,10 @@ static int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb)
|
|||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
static struct sock *geneve_create_sock(struct net *net, bool ipv6,
|
||||
__be16 port, bool ipv6_rx_csum)
|
||||
static struct sock *geneve_create_sock(struct net *net,
|
||||
struct geneve_dev *geneve, bool ipv6)
|
||||
{
|
||||
struct ip_tunnel_info *info = &geneve->cfg.info;
|
||||
struct udp_port_cfg udp_conf;
|
||||
struct socket *sock;
|
||||
int err;
|
||||
|
|
@ -772,13 +774,14 @@ static struct sock *geneve_create_sock(struct net *net, bool ipv6,
|
|||
if (ipv6) {
|
||||
udp_conf.family = AF_INET6;
|
||||
udp_conf.ipv6_v6only = 1;
|
||||
udp_conf.use_udp6_rx_checksums = ipv6_rx_csum;
|
||||
udp_conf.use_udp6_rx_checksums = geneve->cfg.use_udp6_rx_checksums;
|
||||
udp_conf.local_ip6 = info->key.u.ipv6.src;
|
||||
} else {
|
||||
udp_conf.family = AF_INET;
|
||||
udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
|
||||
udp_conf.local_ip.s_addr = info->key.u.ipv4.src;
|
||||
}
|
||||
|
||||
udp_conf.local_udp_port = port;
|
||||
udp_conf.local_udp_port = info->key.tp_dst;
|
||||
|
||||
/* Open UDP socket */
|
||||
err = udp_sock_create(net, &udp_conf, &sock);
|
||||
|
|
@ -970,8 +973,8 @@ static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb,
|
|||
}
|
||||
|
||||
/* Create new listen socket if needed */
|
||||
static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
|
||||
bool ipv6, bool ipv6_rx_csum)
|
||||
static struct geneve_sock *geneve_socket_create(struct net *net,
|
||||
struct geneve_dev *geneve, bool ipv6)
|
||||
{
|
||||
struct geneve_net *gn = net_generic(net, geneve_net_id);
|
||||
struct udp_tunnel_sock_cfg tunnel_cfg;
|
||||
|
|
@ -983,7 +986,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
|
|||
if (!gs)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
sk = geneve_create_sock(net, ipv6, port, ipv6_rx_csum);
|
||||
sk = geneve_create_sock(net, geneve, ipv6);
|
||||
if (IS_ERR(sk)) {
|
||||
kfree(gs);
|
||||
return ERR_CAST(sk);
|
||||
|
|
@ -1039,48 +1042,63 @@ static void geneve_sock_release(struct geneve_dev *geneve)
|
|||
#endif
|
||||
}
|
||||
|
||||
static struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
|
||||
sa_family_t family,
|
||||
__be16 dst_port,
|
||||
bool gro_hint)
|
||||
static struct geneve_sock *geneve_find_sock(struct net *net,
|
||||
struct geneve_dev *geneve, bool ipv6)
|
||||
{
|
||||
struct geneve_net *gn = net_generic(net, geneve_net_id);
|
||||
struct ip_tunnel_info *info = &geneve->cfg.info;
|
||||
sa_family_t family = ipv6 ? AF_INET6 : AF_INET;
|
||||
bool gro_hint = geneve->cfg.gro_hint;
|
||||
__be16 dst_port = info->key.tp_dst;
|
||||
struct geneve_sock *gs;
|
||||
|
||||
list_for_each_entry(gs, &gn->sock_list, list) {
|
||||
if (inet_sk(gs->sk)->inet_sport == dst_port &&
|
||||
geneve_get_sk_family(gs) == family &&
|
||||
gs->gro_hint == gro_hint) {
|
||||
return gs;
|
||||
}
|
||||
if (inet_sk(gs->sk)->inet_sport != dst_port)
|
||||
continue;
|
||||
|
||||
if (geneve_get_sk_family(gs) != family)
|
||||
continue;
|
||||
|
||||
if (gs->gro_hint != gro_hint)
|
||||
continue;
|
||||
|
||||
if (family == AF_INET &&
|
||||
inet_sk(gs->sk)->inet_saddr != info->key.u.ipv4.src)
|
||||
continue;
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (family == AF_INET6 &&
|
||||
!ipv6_addr_equal(&gs->sk->sk_v6_rcv_saddr, &info->key.u.ipv6.src))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
return gs;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
|
||||
{
|
||||
struct net *net = geneve->net;
|
||||
struct geneve_net *gn = net_generic(net, geneve_net_id);
|
||||
bool gro_hint = geneve->cfg.gro_hint;
|
||||
struct geneve_dev_node *node;
|
||||
struct geneve_sock *gs;
|
||||
__u8 vni[3];
|
||||
__u32 hash;
|
||||
|
||||
gs = geneve_find_sock(gn, ipv6 ? AF_INET6 : AF_INET,
|
||||
geneve->cfg.info.key.tp_dst, gro_hint);
|
||||
gs = geneve_find_sock(net, geneve, ipv6);
|
||||
if (gs) {
|
||||
gs->refcnt++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
gs = geneve_socket_create(net, geneve->cfg.info.key.tp_dst, ipv6,
|
||||
geneve->cfg.use_udp6_rx_checksums);
|
||||
gs = geneve_socket_create(net, geneve, ipv6);
|
||||
if (IS_ERR(gs))
|
||||
return PTR_ERR(gs);
|
||||
|
||||
out:
|
||||
gs->collect_md = geneve->cfg.collect_md;
|
||||
gs->gro_hint = gro_hint;
|
||||
gs->gro_hint = geneve->cfg.gro_hint;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (ipv6) {
|
||||
rcu_assign_pointer(geneve->sock6, gs);
|
||||
|
|
@ -1102,12 +1120,12 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
|
|||
static int geneve_open(struct net_device *dev)
|
||||
{
|
||||
struct geneve_dev *geneve = netdev_priv(dev);
|
||||
bool metadata = geneve->cfg.collect_md;
|
||||
bool dualstack = geneve->cfg.dualstack;
|
||||
bool ipv4, ipv6;
|
||||
int ret = 0;
|
||||
|
||||
ipv6 = geneve->cfg.info.mode & IP_TUNNEL_INFO_IPV6 || metadata;
|
||||
ipv4 = !ipv6 || metadata;
|
||||
ipv6 = geneve->cfg.info.mode & IP_TUNNEL_INFO_IPV6 || dualstack;
|
||||
ipv4 = !ipv6 || dualstack;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (ipv6) {
|
||||
ret = geneve_sock_add(geneve, true);
|
||||
|
|
@ -1320,6 +1338,12 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
|
|||
if (IS_ERR(rt))
|
||||
return PTR_ERR(rt);
|
||||
|
||||
if (geneve->cfg.info.key.u.ipv4.src &&
|
||||
saddr != geneve->cfg.info.key.u.ipv4.src) {
|
||||
dst_release(&rt->dst);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
err = skb_tunnel_check_pmtu(skb, &rt->dst,
|
||||
GENEVE_IPV4_HLEN + info->options_len +
|
||||
geneve_build_gro_hint_opt(geneve, skb),
|
||||
|
|
@ -1431,6 +1455,12 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
|
|||
if (IS_ERR(dst))
|
||||
return PTR_ERR(dst);
|
||||
|
||||
if (!ipv6_addr_any(&geneve->cfg.info.key.u.ipv6.src) &&
|
||||
!ipv6_addr_equal(&saddr, &geneve->cfg.info.key.u.ipv6.src)) {
|
||||
dst_release(dst);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
err = skb_tunnel_check_pmtu(skb, dst,
|
||||
GENEVE_IPV6_HLEN + info->options_len +
|
||||
geneve_build_gro_hint_opt(geneve, skb),
|
||||
|
|
@ -1722,6 +1752,8 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
|
|||
[IFLA_GENEVE_INNER_PROTO_INHERIT] = { .type = NLA_FLAG },
|
||||
[IFLA_GENEVE_PORT_RANGE] = NLA_POLICY_EXACT_LEN(sizeof(struct ifla_geneve_port_range)),
|
||||
[IFLA_GENEVE_GRO_HINT] = { .type = NLA_FLAG },
|
||||
[IFLA_GENEVE_LOCAL] = { .type = NLA_BE32 },
|
||||
[IFLA_GENEVE_LOCAL6] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
|
||||
};
|
||||
|
||||
static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
|
||||
|
|
@ -1781,7 +1813,45 @@ static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool geneve_saddr_wildcard(const struct ip_tunnel_info *info)
|
||||
{
|
||||
if (ip_tunnel_info_af(info) == AF_INET) {
|
||||
if (!info->key.u.ipv4.src)
|
||||
return true;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else {
|
||||
if (ipv6_addr_any(&info->key.u.ipv6.src))
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool geneve_saddr_conflict(const struct ip_tunnel_info *a,
|
||||
const struct ip_tunnel_info *b)
|
||||
{
|
||||
if (ip_tunnel_info_af(a) != ip_tunnel_info_af(b))
|
||||
return false;
|
||||
|
||||
if (geneve_saddr_wildcard(a) || geneve_saddr_wildcard(b))
|
||||
return true;
|
||||
|
||||
if (ip_tunnel_info_af(a) == AF_INET) {
|
||||
if (a->key.u.ipv4.src == b->key.u.ipv4.src)
|
||||
return true;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else {
|
||||
if (ipv6_addr_equal(&a->key.u.ipv6.src, &b->key.u.ipv6.src))
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
|
||||
const struct geneve_config *cfg,
|
||||
const struct ip_tunnel_info *info,
|
||||
bool *tun_on_same_port,
|
||||
bool *tun_collect_md)
|
||||
|
|
@ -1791,8 +1861,10 @@ static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
|
|||
*tun_on_same_port = false;
|
||||
*tun_collect_md = false;
|
||||
list_for_each_entry(geneve, &gn->geneve_list, next) {
|
||||
if (info->key.tp_dst == geneve->cfg.info.key.tp_dst) {
|
||||
*tun_collect_md = geneve->cfg.collect_md;
|
||||
if (info->key.tp_dst == geneve->cfg.info.key.tp_dst &&
|
||||
(cfg->dualstack || geneve->cfg.dualstack ||
|
||||
geneve_saddr_conflict(info, &geneve->cfg.info))) {
|
||||
*tun_collect_md |= geneve->cfg.collect_md;
|
||||
*tun_on_same_port = true;
|
||||
}
|
||||
if (info->key.tun_id == geneve->cfg.info.key.tun_id &&
|
||||
|
|
@ -1808,7 +1880,12 @@ static bool is_tnl_info_zero(const struct ip_tunnel_info *info)
|
|||
return !(info->key.tun_id || info->key.tos ||
|
||||
!ip_tunnel_flags_empty(info->key.tun_flags) ||
|
||||
info->key.ttl || info->key.label || info->key.tp_src ||
|
||||
memchr_inv(&info->key.u, 0, sizeof(info->key.u)));
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
(ip_tunnel_info_af(info) == AF_INET6 &&
|
||||
!ipv6_addr_any(&info->key.u.ipv6.dst)) ||
|
||||
#endif
|
||||
(ip_tunnel_info_af(info) == AF_INET &&
|
||||
info->key.u.ipv4.dst));
|
||||
}
|
||||
|
||||
static bool geneve_dst_addr_equal(struct ip_tunnel_info *a,
|
||||
|
|
@ -1839,7 +1916,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,
|
|||
geneve->net = net;
|
||||
geneve->dev = dev;
|
||||
|
||||
t = geneve_find_dev(gn, info, &tun_on_same_port, &tun_collect_md);
|
||||
t = geneve_find_dev(gn, cfg, info, &tun_on_same_port, &tun_collect_md);
|
||||
if (t)
|
||||
return -EBUSY;
|
||||
|
||||
|
|
@ -1857,13 +1934,13 @@ static int geneve_configure(struct net *net, struct net_device *dev,
|
|||
if (cfg->collect_md) {
|
||||
if (tun_on_same_port) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"There can be only one externally controlled device on a destination port");
|
||||
"There can be only one externally controlled device on a destination port and a source address");
|
||||
return -EPERM;
|
||||
}
|
||||
} else {
|
||||
if (tun_collect_md) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"There already exists an externally controlled device on this destination port");
|
||||
"There already exists an externally controlled device on this destination port and the source address");
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
|
@ -1900,9 +1977,20 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
|
|||
struct ip_tunnel_info *info = &cfg->info;
|
||||
int attrtype;
|
||||
|
||||
if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) {
|
||||
if (data[IFLA_GENEVE_COLLECT_METADATA]) {
|
||||
if (changelink) {
|
||||
attrtype = IFLA_GENEVE_COLLECT_METADATA;
|
||||
goto change_notsup;
|
||||
}
|
||||
|
||||
cfg->collect_md = true;
|
||||
cfg->dualstack = true;
|
||||
}
|
||||
|
||||
if ((data[IFLA_GENEVE_LOCAL] || data[IFLA_GENEVE_REMOTE]) &&
|
||||
(data[IFLA_GENEVE_LOCAL6] || data[IFLA_GENEVE_REMOTE6])) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Cannot specify both IPv4 and IPv6 Remote addresses");
|
||||
"Cannot specify both IPv4/IPv6 Remote/Local addresses");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1924,6 +2012,8 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
|
|||
|
||||
if (data[IFLA_GENEVE_REMOTE6]) {
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
int addr_type;
|
||||
|
||||
if (changelink && (ip_tunnel_info_af(info) == AF_INET)) {
|
||||
attrtype = IFLA_GENEVE_REMOTE6;
|
||||
goto change_notsup;
|
||||
|
|
@ -1933,13 +2023,13 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
|
|||
info->key.u.ipv6.dst =
|
||||
nla_get_in6_addr(data[IFLA_GENEVE_REMOTE6]);
|
||||
|
||||
if (ipv6_addr_type(&info->key.u.ipv6.dst) &
|
||||
IPV6_ADDR_LINKLOCAL) {
|
||||
addr_type = ipv6_addr_type(&info->key.u.ipv6.dst);
|
||||
if (addr_type & IPV6_ADDR_LINKLOCAL) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
|
||||
"Remote IPv6 address cannot be link-local");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) {
|
||||
if (addr_type & IPV6_ADDR_MULTICAST) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
|
||||
"Remote IPv6 address cannot be Multicast");
|
||||
return -EINVAL;
|
||||
|
|
@ -1953,6 +2043,65 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
|
|||
#endif
|
||||
}
|
||||
|
||||
if (data[IFLA_GENEVE_LOCAL]) {
|
||||
if (changelink) {
|
||||
__be32 src = nla_get_in_addr(data[IFLA_GENEVE_LOCAL]);
|
||||
|
||||
if (ip_tunnel_info_af(info) == AF_INET6 ||
|
||||
src != info->key.u.ipv4.src) {
|
||||
attrtype = IFLA_GENEVE_LOCAL;
|
||||
goto change_notsup;
|
||||
}
|
||||
} else {
|
||||
info->key.u.ipv4.src = nla_get_in_addr(data[IFLA_GENEVE_LOCAL]);
|
||||
|
||||
if (ipv4_is_multicast(info->key.u.ipv4.src)) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL],
|
||||
"Local IPv4 address cannot be Multicast");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cfg->dualstack = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[IFLA_GENEVE_LOCAL6]) {
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (changelink) {
|
||||
struct in6_addr src = nla_get_in6_addr(data[IFLA_GENEVE_LOCAL6]);
|
||||
|
||||
if (ip_tunnel_info_af(info) == AF_INET ||
|
||||
!ipv6_addr_equal(&src, &info->key.u.ipv6.src)) {
|
||||
attrtype = IFLA_GENEVE_LOCAL6;
|
||||
goto change_notsup;
|
||||
}
|
||||
} else {
|
||||
int addr_type;
|
||||
|
||||
info->mode = IP_TUNNEL_INFO_IPV6;
|
||||
info->key.u.ipv6.src = nla_get_in6_addr(data[IFLA_GENEVE_LOCAL6]);
|
||||
|
||||
addr_type = ipv6_addr_type(&info->key.u.ipv6.src);
|
||||
if (addr_type & IPV6_ADDR_LINKLOCAL) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL6],
|
||||
"Local IPv6 address cannot be link-local");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (addr_type & IPV6_ADDR_MULTICAST) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL6],
|
||||
"Local IPv6 address cannot be Multicast");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cfg->dualstack = false;
|
||||
}
|
||||
#else
|
||||
NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL6],
|
||||
"IPv6 support not enabled in the kernel");
|
||||
return -EPFNOSUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (data[IFLA_GENEVE_ID]) {
|
||||
__u32 vni;
|
||||
__u8 tvni[3];
|
||||
|
|
@ -2017,14 +2166,6 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
|
|||
cfg->port_max = ntohs(p->high);
|
||||
}
|
||||
|
||||
if (data[IFLA_GENEVE_COLLECT_METADATA]) {
|
||||
if (changelink) {
|
||||
attrtype = IFLA_GENEVE_COLLECT_METADATA;
|
||||
goto change_notsup;
|
||||
}
|
||||
cfg->collect_md = true;
|
||||
}
|
||||
|
||||
if (data[IFLA_GENEVE_UDP_CSUM]) {
|
||||
if (changelink) {
|
||||
attrtype = IFLA_GENEVE_UDP_CSUM;
|
||||
|
|
@ -2145,6 +2286,7 @@ static int geneve_newlink(struct net_device *dev,
|
|||
.use_udp6_rx_checksums = false,
|
||||
.ttl_inherit = false,
|
||||
.collect_md = false,
|
||||
.dualstack = false,
|
||||
.port_min = 1,
|
||||
.port_max = USHRT_MAX,
|
||||
};
|
||||
|
|
@ -2253,6 +2395,7 @@ static size_t geneve_get_size(const struct net_device *dev)
|
|||
{
|
||||
return nla_total_size(sizeof(__u32)) + /* IFLA_GENEVE_ID */
|
||||
nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
|
||||
nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_LOCAL{6} */
|
||||
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */
|
||||
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */
|
||||
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_DF */
|
||||
|
|
@ -2308,6 +2451,24 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|||
#endif
|
||||
}
|
||||
|
||||
if (!geneve->cfg.dualstack) {
|
||||
if (ip_tunnel_info_af(info) == AF_INET) {
|
||||
if ((info->key.u.ipv4.src ||
|
||||
geneve->cfg.collect_md) &&
|
||||
nla_put_in_addr(skb, IFLA_GENEVE_LOCAL,
|
||||
info->key.u.ipv4.src))
|
||||
goto nla_put_failure;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else {
|
||||
if ((!ipv6_addr_any(&info->key.u.ipv6.src) ||
|
||||
geneve->cfg.collect_md) &&
|
||||
nla_put_in6_addr(skb, IFLA_GENEVE_LOCAL6,
|
||||
&info->key.u.ipv6.src))
|
||||
goto nla_put_failure;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (nla_put_u8(skb, IFLA_GENEVE_TTL, info->key.ttl) ||
|
||||
nla_put_u8(skb, IFLA_GENEVE_TOS, info->key.tos) ||
|
||||
nla_put_be32(skb, IFLA_GENEVE_LABEL, info->key.label))
|
||||
|
|
@ -2374,6 +2535,7 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
|
|||
.use_udp6_rx_checksums = true,
|
||||
.ttl_inherit = false,
|
||||
.collect_md = true,
|
||||
.dualstack = true,
|
||||
.port_min = 1,
|
||||
.port_max = USHRT_MAX,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1506,6 +1506,8 @@ enum {
|
|||
IFLA_GENEVE_INNER_PROTO_INHERIT,
|
||||
IFLA_GENEVE_PORT_RANGE,
|
||||
IFLA_GENEVE_GRO_HINT,
|
||||
IFLA_GENEVE_LOCAL,
|
||||
IFLA_GENEVE_LOCAL6,
|
||||
__IFLA_GENEVE_MAX
|
||||
};
|
||||
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user