diff --git a/Documentation/netlink/specs/rt-link.yaml b/Documentation/netlink/specs/rt-link.yaml index a5c0297818c6..7f8e3ad3a405 100644 --- a/Documentation/netlink/specs/rt-link.yaml +++ b/Documentation/netlink/specs/rt-link.yaml @@ -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- diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index e8ff03ed87dc..da17b4f6fda5 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -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, }; diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 46413392b402..363526549a01 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -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)