diff options
Diffstat (limited to 'drivers/net/vxlan')
| -rw-r--r-- | drivers/net/vxlan/vxlan_core.c | 802 | ||||
| -rw-r--r-- | drivers/net/vxlan/vxlan_mdb.c | 45 | ||||
| -rw-r--r-- | drivers/net/vxlan/vxlan_multicast.c | 94 | ||||
| -rw-r--r-- | drivers/net/vxlan/vxlan_private.h | 34 | ||||
| -rw-r--r-- | drivers/net/vxlan/vxlan_vnifilter.c | 208 |
5 files changed, 751 insertions, 432 deletions
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 3390e341d1e5..278d41f58d89 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -110,20 +110,23 @@ static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, vni = 0; hlist_for_each_entry_rcu(node, vni_head(vs, vni), hlist) { + const struct vxlan_config *cfg; + if (!node->vxlan) continue; + + cfg = rcu_dereference(node->vxlan->cfg); + vnode = NULL; - if (node->vxlan->cfg.flags & VXLAN_F_VNIFILTER) { + if (cfg->flags & VXLAN_F_VNIFILTER) { vnode = vxlan_vnifilter_lookup(node->vxlan, vni); if (!vnode) continue; - } else if (node->vxlan->default_dst.remote_vni != vni) { + } else if (cfg->vni != vni) { continue; } if (IS_ENABLED(CONFIG_IPV6)) { - const struct vxlan_config *cfg = &node->vxlan->cfg; - if ((cfg->flags & VXLAN_F_IPV6_LINKLOCAL) && cfg->remote_ifindex != ifindex) continue; @@ -157,6 +160,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, u32 portid, u32 seq, int type, unsigned int flags, const struct vxlan_rdst *rdst) { + const struct vxlan_config *cfg = rcu_dereference_rtnl(vxlan->cfg); unsigned long now = jiffies; struct nda_cacheinfo ci; bool send_ip, send_eth; @@ -216,10 +220,10 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, goto nla_put_failure; if (rdst->remote_port && - rdst->remote_port != vxlan->cfg.dst_port && + rdst->remote_port != cfg->dst_port && nla_put_be16(skb, NDA_PORT, rdst->remote_port)) goto nla_put_failure; - if (rdst->remote_vni != vxlan->default_dst.remote_vni && + if (rdst->remote_vni != cfg->vni && nla_put_u32(skb, NDA_VNI, be32_to_cpu(rdst->remote_vni))) goto nla_put_failure; if (rdst->remote_ifindex && @@ -227,7 +231,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, goto nla_put_failure; } - if ((vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) && fdb->key.vni && + if ((cfg->flags & VXLAN_F_COLLECT_METADATA) && fdb->key.vni && nla_put_u32(skb, NDA_SRC_VNI, be32_to_cpu(fdb->key.vni))) goto nla_put_failure; @@ -377,14 +381,15 @@ static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN]) /* Look up Ethernet address in forwarding table */ static struct vxlan_fdb *vxlan_find_mac_rcu(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, const u8 *mac, __be32 vni) { struct vxlan_fdb_key key; memset(&key, 0, sizeof(key)); memcpy(key.eth_addr, mac, sizeof(key.eth_addr)); - if (!(vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA)) - key.vni = vxlan->default_dst.remote_vni; + if (!(cfg->flags & VXLAN_F_COLLECT_METADATA)) + key.vni = cfg->vni; else key.vni = vni; @@ -393,11 +398,12 @@ static struct vxlan_fdb *vxlan_find_mac_rcu(struct vxlan_dev *vxlan, } static struct vxlan_fdb *vxlan_find_mac_tx(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, const u8 *mac, __be32 vni) { struct vxlan_fdb *f; - f = vxlan_find_mac_rcu(vxlan, mac, vni); + f = vxlan_find_mac_rcu(vxlan, cfg, mac, vni); if (f) { unsigned long now = jiffies; @@ -416,7 +422,7 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan, lockdep_assert_held_once(&vxlan->hash_lock); rcu_read_lock(); - f = vxlan_find_mac_rcu(vxlan, mac, vni); + f = vxlan_find_mac_rcu(vxlan, rcu_dereference(vxlan->cfg), mac, vni); rcu_read_unlock(); return f; @@ -457,7 +463,7 @@ int vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, __be32 vni, rcu_read_lock(); - f = vxlan_find_mac_rcu(vxlan, eth_addr, vni); + f = vxlan_find_mac_rcu(vxlan, rcu_dereference(vxlan->cfg), eth_addr, vni); if (f) rdst = first_remote_rcu(f); if (!rdst) { @@ -798,6 +804,7 @@ static int vxlan_fdb_nh_update(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, u32 nhid, struct netlink_ext_ack *extack) { struct nexthop *old_nh = rtnl_dereference(fdb->nh); + const struct vxlan_config *cfg; struct nexthop *nh; int err = -EINVAL; @@ -826,7 +833,8 @@ static int vxlan_fdb_nh_update(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, } /* check nexthop group family */ - switch (vxlan->default_dst.remote_ip.sa.sa_family) { + cfg = rtnl_dereference(vxlan->cfg); + switch (cfg->remote_ip.sa.sa_family) { case AF_INET: if (!nexthop_has_v4(nh)) { err = -EAFNOSUPPORT; @@ -863,12 +871,13 @@ int vxlan_fdb_create(struct vxlan_dev *vxlan, u32 nhid, struct vxlan_fdb **fdb, struct netlink_ext_ack *extack) { + const struct vxlan_config *cfg = rcu_dereference_rtnl(vxlan->cfg); struct vxlan_rdst *rd = NULL; struct vxlan_fdb *f; int rc; - if (vxlan->cfg.addrmax && - vxlan->addrcnt >= vxlan->cfg.addrmax) + if (cfg->addrmax && + vxlan->addrcnt >= cfg->addrmax) return -ENOSPC; netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); @@ -1154,6 +1163,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, __be32 *vni, u32 *ifindex, u32 *nhid, struct netlink_ext_ack *extack) { + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); struct net *net = dev_net(vxlan->dev); int err; @@ -1170,7 +1180,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, return err; } } else { - union vxlan_addr *remote = &vxlan->default_dst.remote_ip; + const union vxlan_addr *remote = &cfg->remote_ip; if (remote->sa.sa_family == AF_INET) { ip->sin.sin_addr.s_addr = htonl(INADDR_ANY); @@ -1190,7 +1200,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, } *port = nla_get_be16(tb[NDA_PORT]); } else { - *port = vxlan->cfg.dst_port; + *port = cfg->dst_port; } if (tb[NDA_VNI]) { @@ -1200,7 +1210,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, } *vni = cpu_to_be32(nla_get_u32(tb[NDA_VNI])); } else { - *vni = vxlan->default_dst.remote_vni; + *vni = cfg->vni; } if (tb[NDA_SRC_VNI]) { @@ -1210,7 +1220,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, } *src_vni = cpu_to_be32(nla_get_u32(tb[NDA_SRC_VNI])); } else { - *src_vni = vxlan->default_dst.remote_vni; + *src_vni = cfg->vni; } if (tb[NDA_IFINDEX]) { @@ -1241,6 +1251,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], const unsigned char *addr, u16 vid, u16 flags, bool *notified, struct netlink_ext_ack *extack) { + const struct vxlan_config *cfg; struct vxlan_dev *vxlan = netdev_priv(dev); /* struct net *net = dev_net(vxlan->dev); */ union vxlan_addr ip; @@ -1268,7 +1279,8 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return -EINVAL; } - if (vxlan->default_dst.remote_ip.sa.sa_family != ip.sa.sa_family) + cfg = rtnl_dereference(vxlan->cfg); + if (cfg->remote_ip.sa.sa_family != ip.sa.sa_family) return -EAFNOSUPPORT; spin_lock_bh(&vxlan->hash_lock); @@ -1405,18 +1417,21 @@ static int vxlan_fdb_get(struct sk_buff *skb, struct netlink_ext_ack *extack) { struct vxlan_dev *vxlan = netdev_priv(dev); + const struct vxlan_config *cfg; struct vxlan_fdb *f; __be32 vni; int err; + cfg = rcu_dereference_rtnl(vxlan->cfg); + if (tb[NDA_VNI]) vni = cpu_to_be32(nla_get_u32(tb[NDA_VNI])); else - vni = vxlan->default_dst.remote_vni; + vni = cfg->vni; rcu_read_lock(); - f = vxlan_find_mac_rcu(vxlan, addr, vni); + f = vxlan_find_mac_rcu(vxlan, cfg, addr, vni); if (!f) { NL_SET_ERR_MSG(extack, "Fdb entry not found"); err = -ENOENT; @@ -1434,6 +1449,7 @@ errout: * and Tunnel endpoint. */ static enum skb_drop_reason vxlan_snoop(struct net_device *dev, + const struct vxlan_config *cfg, union vxlan_addr *src_ip, const u8 *src_mac, u32 src_ifindex, __be32 vni) @@ -1452,7 +1468,7 @@ static enum skb_drop_reason vxlan_snoop(struct net_device *dev, ifindex = src_ifindex; #endif - f = vxlan_find_mac_rcu(vxlan, src_mac, vni); + f = vxlan_find_mac_rcu(vxlan, cfg, src_mac, vni); if (likely(f)) { struct vxlan_rdst *rdst = first_remote_rcu(f); unsigned long now = jiffies; @@ -1488,9 +1504,9 @@ static enum skb_drop_reason vxlan_snoop(struct net_device *dev, vxlan_fdb_update(vxlan, src_mac, src_ip, NUD_REACHABLE, NLM_F_EXCL|NLM_F_CREATE, - vxlan->cfg.dst_port, + cfg->dst_port, vni, - vxlan->default_dst.remote_vni, + cfg->vni, ifindex, NTF_SELF, 0, true, NULL); spin_unlock(&vxlan->hash_lock); } @@ -1518,6 +1534,7 @@ static bool __vxlan_sock_release_prep(struct vxlan_sock *vs) static void vxlan_sock_release(struct vxlan_dev *vxlan) { + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock); #if IS_ENABLED(CONFIG_IPV6) struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock); @@ -1527,7 +1544,7 @@ static void vxlan_sock_release(struct vxlan_dev *vxlan) RCU_INIT_POINTER(vxlan->vn4_sock, NULL); - if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) + if (cfg->flags & VXLAN_F_VNIFILTER) vxlan_vs_del_vnigrp(vxlan); else vxlan_vs_del_dev(vxlan); @@ -1598,6 +1615,7 @@ static void vxlan_parse_gbp_hdr(struct sk_buff *skb, u32 vxflags, } static enum skb_drop_reason vxlan_set_mac(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, struct vxlan_sock *vs, struct sk_buff *skb, __be32 vni) { @@ -1623,10 +1641,10 @@ static enum skb_drop_reason vxlan_set_mac(struct vxlan_dev *vxlan, #endif } - if (!(vxlan->cfg.flags & VXLAN_F_LEARN)) + if (!(cfg->flags & VXLAN_F_LEARN)) return SKB_NOT_DROPPED_YET; - return vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, + return vxlan_snoop(skb->dev, cfg, &saddr, eth_hdr(skb)->h_source, ifindex, vni); } @@ -1657,18 +1675,21 @@ static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph, static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) { struct vxlan_vni_node *vninode = NULL; - const struct vxlanhdr *vh; - struct vxlan_dev *vxlan; - struct vxlan_sock *vs; - struct vxlan_metadata _md; - struct vxlan_metadata *md = &_md; __be16 protocol = htons(ETH_P_TEB); + const struct vxlan_config *cfg; enum skb_drop_reason reason; + const struct vxlanhdr *vh; + struct vxlan_metadata *md; + struct vxlan_metadata _md; + struct vxlan_dev *vxlan; bool raw_proto = false; - void *oiph; + struct vxlan_sock *vs; __be32 vni = 0; + void *oiph; int nh; + md = &_md; + /* Need UDP and VXLAN header to be present */ reason = pskb_may_pull_reason(skb, VXLAN_HLEN); if (reason) @@ -1679,7 +1700,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) if (!(vh->vx_flags & VXLAN_HF_VNI)) { netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n", ntohl(vh->vx_flags), ntohl(vh->vx_vni)); - reason = SKB_DROP_REASON_VXLAN_INVALID_HDR; + reason = SKB_DROP_REASON_TUNNEL_INVALID_HDR; /* Return non vxlan pkt */ goto drop; } @@ -1692,12 +1713,14 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) vxlan = vxlan_vs_find_vni(vs, skb->dev->ifindex, vni, &vninode); if (!vxlan) { - reason = SKB_DROP_REASON_VXLAN_VNI_NOT_FOUND; + reason = SKB_DROP_REASON_TUNNEL_NOT_FOUND; goto drop; } - if (vh->vx_flags & vxlan->cfg.reserved_bits.vx_flags || - vh->vx_vni & vxlan->cfg.reserved_bits.vx_vni) { + cfg = rcu_dereference(vxlan->cfg); + + if (vh->vx_flags & cfg->reserved_bits.vx_flags || + vh->vx_vni & cfg->reserved_bits.vx_vni) { /* If the header uses bits besides those enabled by the * netdevice configuration, treat this as a malformed packet. * This behavior diverges from VXLAN RFC (RFC7348) which @@ -1706,28 +1729,28 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) * previous stack code, and also is more robust and provides a * little more security in adding extensions to VXLAN. */ - reason = SKB_DROP_REASON_VXLAN_INVALID_HDR; + reason = SKB_DROP_REASON_TUNNEL_INVALID_HDR; DEV_STATS_INC(vxlan->dev, rx_frame_errors); DEV_STATS_INC(vxlan->dev, rx_errors); - vxlan_vnifilter_count(vxlan, vni, vninode, + vxlan_vnifilter_count(vxlan, cfg, vni, vninode, VXLAN_VNI_STATS_RX_ERRORS, 0); goto drop; } - if (vxlan->cfg.flags & VXLAN_F_GPE) { + if (cfg->flags & VXLAN_F_GPE) { if (!vxlan_parse_gpe_proto(vh, &protocol)) goto drop; raw_proto = true; } - if (__iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto, - !net_eq(vxlan->net, dev_net(vxlan->dev)))) { - reason = SKB_DROP_REASON_NOMEM; + reason = __iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto, + !net_eq(vxlan->net, + dev_net(vxlan->dev))); + if (reason) goto drop; - } - if (vxlan->cfg.flags & VXLAN_F_REMCSUM_RX) { - reason = vxlan_remcsum(skb, vxlan->cfg.flags); + if (cfg->flags & VXLAN_F_REMCSUM_RX) { + reason = vxlan_remcsum(skb, cfg->flags); if (unlikely(reason)) goto drop; } @@ -1752,14 +1775,14 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) memset(md, 0, sizeof(*md)); } - if (vxlan->cfg.flags & VXLAN_F_GBP) - vxlan_parse_gbp_hdr(skb, vxlan->cfg.flags, md); + if (cfg->flags & VXLAN_F_GBP) + vxlan_parse_gbp_hdr(skb, cfg->flags, md); /* Note that GBP and GPE can never be active together. This is * ensured in vxlan_dev_configure. */ if (!raw_proto) { - reason = vxlan_set_mac(vxlan, vs, skb, vni); + reason = vxlan_set_mac(vxlan, cfg, vs, skb, vni); if (reason) goto drop; } else { @@ -1780,7 +1803,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) if (reason) { DEV_STATS_INC(vxlan->dev, rx_length_errors); DEV_STATS_INC(vxlan->dev, rx_errors); - vxlan_vnifilter_count(vxlan, vni, vninode, + vxlan_vnifilter_count(vxlan, cfg, vni, vninode, VXLAN_VNI_STATS_RX_ERRORS, 0); goto drop; } @@ -1792,7 +1815,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) reason = SKB_DROP_REASON_IP_TUNNEL_ECN; DEV_STATS_INC(vxlan->dev, rx_frame_errors); DEV_STATS_INC(vxlan->dev, rx_errors); - vxlan_vnifilter_count(vxlan, vni, vninode, + vxlan_vnifilter_count(vxlan, cfg, vni, vninode, VXLAN_VNI_STATS_RX_ERRORS, 0); goto drop; } @@ -1802,14 +1825,15 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) if (unlikely(!(vxlan->dev->flags & IFF_UP))) { rcu_read_unlock(); dev_dstats_rx_dropped(vxlan->dev); - vxlan_vnifilter_count(vxlan, vni, vninode, + vxlan_vnifilter_count(vxlan, cfg, vni, vninode, VXLAN_VNI_STATS_RX_DROPS, 0); reason = SKB_DROP_REASON_DEV_READY; goto drop; } dev_dstats_rx_add(vxlan->dev, skb->len); - vxlan_vnifilter_count(vxlan, vni, vninode, VXLAN_VNI_STATS_RX, skb->len); + vxlan_vnifilter_count(vxlan, cfg, vni, vninode, VXLAN_VNI_STATS_RX, + skb->len); gro_cells_receive(&vxlan->gro_cells, skb); rcu_read_unlock(); @@ -1850,20 +1874,21 @@ static int vxlan_err_lookup(struct sock *sk, struct sk_buff *skb) return 0; } -static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) +static int arp_reduce(struct net_device *dev, struct sk_buff *skb, + const struct vxlan_config *cfg, __be32 vni) { struct vxlan_dev *vxlan = netdev_priv(dev); + struct neighbour *n; struct arphdr *parp; u8 *arpptr, *sha; __be32 sip, tip; - struct neighbour *n; if (dev->flags & IFF_NOARP) goto out; if (!pskb_network_may_pull(skb, arp_hdr_len(dev))) { dev_dstats_tx_dropped(dev); - vxlan_vnifilter_count(vxlan, vni, NULL, + vxlan_vnifilter_count(vxlan, cfg, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); goto out; } @@ -1888,8 +1913,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) ipv4_is_multicast(tip)) goto out; - n = neigh_lookup(&arp_tbl, &tip, dev); - + n = ipv4_neigh_lookup(dev, &tip); if (n) { struct vxlan_rdst *rdst = NULL; u8 ha[ETH_ALEN] __aligned(2); @@ -1904,7 +1928,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) neigh_ha_snapshot(ha, n, n->dev); rcu_read_lock(); - f = vxlan_find_mac_tx(vxlan, ha, vni); + f = vxlan_find_mac_tx(vxlan, cfg, ha, vni); if (f) rdst = first_remote_rcu(f); if (rdst && vxlan_addr_any(&rdst->remote_ip)) { @@ -1930,11 +1954,11 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) if (netif_rx(reply) == NET_RX_DROP) { dev_dstats_rx_dropped(dev); - vxlan_vnifilter_count(vxlan, vni, NULL, + vxlan_vnifilter_count(vxlan, cfg, vni, NULL, VXLAN_VNI_STATS_RX_DROPS, 0); } - } else if (vxlan->cfg.flags & VXLAN_F_L3MISS) { + } else if (cfg->flags & VXLAN_F_L3MISS) { union vxlan_addr ipa = { .sin.sin_addr.s_addr = tip, .sin.sin_family = AF_INET, @@ -2044,7 +2068,8 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request, return reply; } -static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) +static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, + const struct vxlan_config *cfg, __be32 vni) { struct vxlan_dev *vxlan = netdev_priv(dev); const struct in6_addr *daddr; @@ -2064,8 +2089,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) ipv6_addr_is_multicast(&msg->target)) goto out; - n = neigh_lookup(&nd_tbl, &msg->target, dev); - + n = ipv6_neigh_lookup(dev, &msg->target); if (n) { struct vxlan_rdst *rdst = NULL; u8 ha[ETH_ALEN] __aligned(2); @@ -2078,7 +2102,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) } neigh_ha_snapshot(ha, n, n->dev); - f = vxlan_find_mac_tx(vxlan, ha, vni); + f = vxlan_find_mac_tx(vxlan, cfg, ha, vni); if (f) rdst = first_remote_rcu(f); if (rdst && vxlan_addr_any(&rdst->remote_ip)) { @@ -2097,10 +2121,10 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) if (netif_rx(reply) == NET_RX_DROP) { dev_dstats_rx_dropped(dev); - vxlan_vnifilter_count(vxlan, vni, NULL, + vxlan_vnifilter_count(vxlan, cfg, vni, NULL, VXLAN_VNI_STATS_RX_DROPS, 0); } - } else if (vxlan->cfg.flags & VXLAN_F_L3MISS) { + } else if (cfg->flags & VXLAN_F_L3MISS) { union vxlan_addr ipa = { .sin6.sin6_addr = msg->target, .sin6.sin6_family = AF_INET6, @@ -2116,9 +2140,9 @@ out: } #endif -static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) +static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb, + const struct vxlan_config *cfg) { - struct vxlan_dev *vxlan = netdev_priv(dev); struct neighbour *n; if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) @@ -2132,9 +2156,10 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) if (!pskb_network_may_pull(skb, sizeof(struct iphdr))) return false; + pip = ip_hdr(skb); - n = neigh_lookup(&arp_tbl, &pip->daddr, dev); - if (!n && (vxlan->cfg.flags & VXLAN_F_L3MISS)) { + n = ipv4_neigh_lookup(dev, &pip->daddr); + if (!n && (cfg->flags & VXLAN_F_L3MISS)) { union vxlan_addr ipa = { .sin.sin_addr.s_addr = pip->daddr, .sin.sin_family = AF_INET, @@ -2158,9 +2183,10 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) return false; if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) return false; + pip6 = ipv6_hdr(skb); - n = neigh_lookup(&nd_tbl, &pip6->daddr, dev); - if (!n && (vxlan->cfg.flags & VXLAN_F_L3MISS)) { + n = ipv6_neigh_lookup(dev, &pip6->daddr); + if (!n && (cfg->flags & VXLAN_F_L3MISS)) { union vxlan_addr ipa = { .sin6.sin6_addr = pip6->daddr, .sin6.sin6_family = AF_INET6, @@ -2278,20 +2304,28 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst, /* Bypass encapsulation if the destination is local */ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, - struct vxlan_dev *dst_vxlan, __be32 vni, - bool snoop) + struct vxlan_dev *dst_vxlan, + const struct vxlan_config *src_cfg, + __be32 vni, bool snoop) { + const struct vxlan_config *dst_cfg; union vxlan_addr loopback; - union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip; unsigned int len = skb->len; - struct net_device *dev; + struct net_device *dev = dst_vxlan->dev; skb->pkt_type = PACKET_HOST; skb->encapsulation = 0; - skb->dev = dst_vxlan->dev; + skb->dev = dev; __skb_pull(skb, skb_network_offset(skb)); - if (remote_ip->sa.sa_family == AF_INET) { + rcu_read_lock(); + dst_cfg = rcu_dereference(dst_vxlan->cfg); + if (unlikely(!(dev->flags & IFF_UP))) { + kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY); + goto drop; + } + + if (dst_cfg->remote_ip.sa.sa_family == AF_INET) { loopback.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); loopback.sa.sa_family = AF_INET; #if IS_ENABLED(CONFIG_IPV6) @@ -2301,27 +2335,20 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, #endif } - rcu_read_lock(); - dev = skb->dev; - if (unlikely(!(dev->flags & IFF_UP))) { - kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY); - goto drop; - } - - if ((dst_vxlan->cfg.flags & VXLAN_F_LEARN) && snoop) - vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni); + if ((dst_cfg->flags & VXLAN_F_LEARN) && snoop) + vxlan_snoop(dev, dst_cfg, &loopback, eth_hdr(skb)->h_source, 0, vni); dev_dstats_tx_add(src_vxlan->dev, len); - vxlan_vnifilter_count(src_vxlan, vni, NULL, VXLAN_VNI_STATS_TX, len); + vxlan_vnifilter_count(src_vxlan, src_cfg, vni, NULL, VXLAN_VNI_STATS_TX, len); if (__netif_rx(skb) == NET_RX_SUCCESS) { dev_dstats_rx_add(dst_vxlan->dev, len); - vxlan_vnifilter_count(dst_vxlan, vni, NULL, VXLAN_VNI_STATS_RX, + vxlan_vnifilter_count(dst_vxlan, dst_cfg, vni, NULL, VXLAN_VNI_STATS_RX, len); } else { drop: dev_dstats_rx_dropped(dev); - vxlan_vnifilter_count(dst_vxlan, vni, NULL, + vxlan_vnifilter_count(dst_vxlan, dst_cfg, vni, NULL, VXLAN_VNI_STATS_RX_DROPS, 0); } rcu_read_unlock(); @@ -2329,6 +2356,7 @@ drop: static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, int addr_family, __be16 dst_port, int dst_ifindex, __be32 vni, struct dst_entry *dst, @@ -2344,22 +2372,22 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, /* Bypass encapsulation if the destination is local */ if (rt_flags & RTCF_LOCAL && !(rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) && - vxlan->cfg.flags & VXLAN_F_LOCALBYPASS) { + cfg->flags & VXLAN_F_LOCALBYPASS) { struct vxlan_dev *dst_vxlan; dst_release(dst); dst_vxlan = vxlan_find_vni(vxlan->net, dst_ifindex, vni, addr_family, dst_port, - vxlan->cfg.flags); + cfg->flags); if (!dst_vxlan) { DEV_STATS_INC(dev, tx_errors); - vxlan_vnifilter_count(vxlan, vni, NULL, + vxlan_vnifilter_count(vxlan, cfg, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0); - kfree_skb_reason(skb, SKB_DROP_REASON_VXLAN_VNI_NOT_FOUND); + kfree_skb_reason(skb, SKB_DROP_REASON_TUNNEL_NOT_FOUND); return -ENOENT; } - vxlan_encap_bypass(skb, vxlan, dst_vxlan, vni, true); + vxlan_encap_bypass(skb, vxlan, dst_vxlan, cfg, vni, true); return 1; } @@ -2367,30 +2395,35 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, } void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + const struct vxlan_config *cfg, __be32 default_vni, struct vxlan_rdst *rdst, bool did_rsc) { + unsigned int pkt_len = skb->len; + struct vxlan_metadata _md = {}; + __be16 src_port = 0, dst_port; + struct dst_entry *ndst = NULL; + enum skb_drop_reason reason; struct dst_cache *dst_cache; + const struct iphdr *old_iph; struct ip_tunnel_info *info; struct ip_tunnel_key *pkey; + struct vxlan_metadata *md; struct ip_tunnel_key key; - struct vxlan_dev *vxlan = netdev_priv(dev); - const struct iphdr *old_iph; - struct vxlan_metadata _md = {}; - struct vxlan_metadata *md = &_md; - unsigned int pkt_len = skb->len; - __be16 src_port = 0, dst_port; - struct dst_entry *ndst = NULL; + struct vxlan_dev *vxlan; + u32 flags = cfg->flags; + bool udp_sum = false; + bool no_eth_encap; int addr_family; + bool use_cache; + __be32 vni = 0; __u8 tos, ttl; int ifindex; int err = 0; - u32 flags = vxlan->cfg.flags; - bool use_cache; - bool udp_sum = false; - bool xnet = !net_eq(vxlan->net, dev_net(vxlan->dev)); - enum skb_drop_reason reason; - bool no_eth_encap; - __be32 vni = 0; + bool xnet; + + vxlan = netdev_priv(dev); + xnet = !net_eq(vxlan->net, dev_net(vxlan->dev)); + md = &_md; no_eth_encap = flags & VXLAN_F_GPE && skb->protocol != htons(ETH_P_TEB); reason = skb_vlan_inet_prepare(skb, no_eth_encap); @@ -2410,23 +2443,23 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (vxlan_addr_any(&rdst->remote_ip)) { if (did_rsc) { /* short-circuited back to local bridge */ - vxlan_encap_bypass(skb, vxlan, vxlan, + vxlan_encap_bypass(skb, vxlan, vxlan, cfg, default_vni, true); return; } goto drop; } - addr_family = vxlan->cfg.saddr.sa.sa_family; - dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port; + addr_family = cfg->saddr.sa.sa_family; + dst_port = rdst->remote_port ? rdst->remote_port : cfg->dst_port; vni = (rdst->remote_vni) ? : default_vni; ifindex = rdst->remote_ifindex; if (addr_family == AF_INET) { - key.u.ipv4.src = vxlan->cfg.saddr.sin.sin_addr.s_addr; + key.u.ipv4.src = cfg->saddr.sin.sin_addr.s_addr; key.u.ipv4.dst = rdst->remote_ip.sin.sin_addr.s_addr; } else { - key.u.ipv6.src = vxlan->cfg.saddr.sin6.sin6_addr; + key.u.ipv6.src = cfg->saddr.sin6.sin6_addr; key.u.ipv6.dst = rdst->remote_ip.sin6.sin6_addr; } @@ -2435,11 +2468,11 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (flags & VXLAN_F_TTL_INHERIT) { ttl = ip_tunnel_get_ttl(old_iph, skb); } else { - ttl = vxlan->cfg.ttl; + ttl = cfg->ttl; if (!ttl && vxlan_addr_multicast(&rdst->remote_ip)) ttl = 1; } - tos = vxlan->cfg.tos; + tos = cfg->tos; if (tos == 1) tos = ip_tunnel_get_dsfield(old_iph, skb); if (tos && !info) @@ -2450,9 +2483,9 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, else udp_sum = !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX); #if IS_ENABLED(CONFIG_IPV6) - switch (vxlan->cfg.label_policy) { + switch (cfg->label_policy) { case VXLAN_LABEL_FIXED: - key.label = vxlan->cfg.label; + key.label = cfg->label; break; case VXLAN_LABEL_INHERIT: key.label = ip_tunnel_get_flowlabel(old_iph, skb); @@ -2470,7 +2503,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } pkey = &info->key; addr_family = ip_tunnel_info_af(info); - dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port; + dst_port = info->key.tp_dst ? : cfg->dst_port; vni = tunnel_id_to_key32(info->key.tun_id); ifindex = 0; dst_cache = &info->dst_cache; @@ -2483,8 +2516,8 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos = info->key.tos; udp_sum = test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags); } - src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min, - vxlan->cfg.port_max, true); + src_port = udp_flow_src_port(dev_net(dev), skb, cfg->port_min, + cfg->port_max, true); rcu_read_lock(); if (addr_family == AF_INET) { @@ -2508,7 +2541,10 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos, use_cache ? dst_cache : NULL); if (IS_ERR(rt)) { err = PTR_ERR(rt); - reason = SKB_DROP_REASON_IP_OUTNOROUTES; + if (err == -ELOOP) + reason = SKB_DROP_REASON_RECURSION_LIMIT; + else + reason = SKB_DROP_REASON_IP_OUTNOROUTES; goto tx_error; } @@ -2517,15 +2553,15 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (!info) { /* Bypass encapsulation if the destination is local */ - err = encap_bypass_if_local(skb, dev, vxlan, AF_INET, + err = encap_bypass_if_local(skb, dev, vxlan, cfg, AF_INET, dst_port, ifindex, vni, &rt->dst, rt->rt_flags); if (err) goto out_unlock; - if (vxlan->cfg.df == VXLAN_DF_SET) { + if (cfg->df == VXLAN_DF_SET) { df = htons(IP_DF); - } else if (vxlan->cfg.df == VXLAN_DF_INHERIT) { + } else if (cfg->df == VXLAN_DF_INHERIT) { struct ethhdr *eth = eth_hdr(skb); if (ntohs(eth->h_proto) == ETH_P_IPV6 || @@ -2554,7 +2590,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, unclone->key.u.ipv4.src = pkey->u.ipv4.dst; unclone->key.u.ipv4.dst = saddr; } - vxlan_encap_bypass(skb, vxlan, vxlan, vni, false); + vxlan_encap_bypass(skb, vxlan, vxlan, cfg, vni, false); dst_release(ndst); goto out_unlock; } @@ -2594,7 +2630,10 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (IS_ERR(ndst)) { err = PTR_ERR(ndst); ndst = NULL; - reason = SKB_DROP_REASON_IP_OUTNOROUTES; + if (err == -ELOOP) + reason = SKB_DROP_REASON_RECURSION_LIMIT; + else + reason = SKB_DROP_REASON_IP_OUTNOROUTES; goto tx_error; } @@ -2604,7 +2643,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (!info) { u32 rt6i_flags = dst_rt6_info(ndst)->rt6i_flags; - err = encap_bypass_if_local(skb, dev, vxlan, AF_INET6, + err = encap_bypass_if_local(skb, dev, vxlan, cfg, AF_INET6, dst_port, ifindex, vni, ndst, rt6i_flags); if (err) @@ -2628,7 +2667,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, unclone->key.u.ipv6.dst = saddr; } - vxlan_encap_bypass(skb, vxlan, vxlan, vni, false); + vxlan_encap_bypass(skb, vxlan, vxlan, cfg, vni, false); dst_release(ndst); goto out_unlock; } @@ -2649,14 +2688,14 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ip6cb_flags); #endif } - vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX, pkt_len); + vxlan_vnifilter_count(vxlan, cfg, vni, NULL, VXLAN_VNI_STATS_TX, pkt_len); out_unlock: rcu_read_unlock(); return; drop: dev_dstats_tx_dropped(dev); - vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); + vxlan_vnifilter_count(vxlan, cfg, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); kfree_skb_reason(skb, reason); return; @@ -2668,11 +2707,12 @@ tx_error: DEV_STATS_INC(dev, tx_carrier_errors); dst_release(ndst); DEV_STATS_INC(dev, tx_errors); - vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0); + vxlan_vnifilter_count(vxlan, cfg, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0); kfree_skb_reason(skb, reason); } static void vxlan_xmit_nh(struct sk_buff *skb, struct net_device *dev, + const struct vxlan_config *cfg, struct vxlan_fdb *f, __be32 vni, bool did_rsc) { struct vxlan_rdst nh_rdst; @@ -2689,7 +2729,7 @@ static void vxlan_xmit_nh(struct sk_buff *skb, struct net_device *dev, do_xmit = vxlan_fdb_nh_path_select(nh, hash, &nh_rdst); if (likely(do_xmit)) - vxlan_xmit_one(skb, dev, vni, &nh_rdst, did_rsc); + vxlan_xmit_one(skb, dev, cfg, vni, &nh_rdst, did_rsc); else goto drop; @@ -2697,15 +2737,15 @@ static void vxlan_xmit_nh(struct sk_buff *skb, struct net_device *dev, drop: dev_dstats_tx_dropped(dev); - vxlan_vnifilter_count(netdev_priv(dev), vni, NULL, + vxlan_vnifilter_count(netdev_priv(dev), cfg, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); dev_kfree_skb(skb); } static netdev_tx_t vxlan_xmit_nhid(struct sk_buff *skb, struct net_device *dev, - u32 nhid, __be32 vni) + u32 nhid, __be32 vni, + const struct vxlan_config *cfg) { - struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst nh_rdst; struct nexthop *nh; bool do_xmit; @@ -2723,11 +2763,11 @@ static netdev_tx_t vxlan_xmit_nhid(struct sk_buff *skb, struct net_device *dev, do_xmit = vxlan_fdb_nh_path_select(nh, hash, &nh_rdst); rcu_read_unlock(); - if (vxlan->cfg.saddr.sa.sa_family != nh_rdst.remote_ip.sa.sa_family) + if (cfg->saddr.sa.sa_family != nh_rdst.remote_ip.sa.sa_family) goto drop; if (likely(do_xmit)) - vxlan_xmit_one(skb, dev, vni, &nh_rdst, false); + vxlan_xmit_one(skb, dev, cfg, vni, &nh_rdst, false); else goto drop; @@ -2735,7 +2775,7 @@ static netdev_tx_t vxlan_xmit_nhid(struct sk_buff *skb, struct net_device *dev, drop: dev_dstats_tx_dropped(dev); - vxlan_vnifilter_count(netdev_priv(dev), vni, NULL, + vxlan_vnifilter_count(netdev_priv(dev), cfg, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); dev_kfree_skb(skb); return NETDEV_TX_OK; @@ -2752,34 +2792,47 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst *rdst, *fdst = NULL; const struct ip_tunnel_info *info; + const struct vxlan_config *cfg; + __be32 default_vni; struct vxlan_fdb *f; struct ethhdr *eth; __be32 vni = 0; - u32 nhid = 0; bool did_rsc; + u32 nhid = 0; + u32 flags; + + rcu_read_lock(); + cfg = rcu_dereference(vxlan->cfg); + flags = cfg->flags; + default_vni = cfg->vni; info = skb_tunnel_info(skb); skb_reset_mac_header(skb); - if (vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) { + if (flags & VXLAN_F_COLLECT_METADATA) { if (info && info->mode & IP_TUNNEL_INFO_BRIDGE && info->mode & IP_TUNNEL_INFO_TX) { vni = tunnel_id_to_key32(info->key.tun_id); nhid = info->key.nhid; } else { if (info && info->mode & IP_TUNNEL_INFO_TX) - vxlan_xmit_one(skb, dev, vni, NULL, false); + vxlan_xmit_one(skb, dev, cfg, vni, NULL, false); else kfree_skb_reason(skb, SKB_DROP_REASON_TUNNEL_TXINFO); + rcu_read_unlock(); return NETDEV_TX_OK; } } - if (vxlan->cfg.flags & VXLAN_F_PROXY) { + if (flags & VXLAN_F_PROXY) { eth = eth_hdr(skb); - if (ntohs(eth->h_proto) == ETH_P_ARP) - return arp_reduce(dev, skb, vni); + if (ntohs(eth->h_proto) == ETH_P_ARP) { + netdev_tx_t res = arp_reduce(dev, skb, cfg, vni); + + rcu_read_unlock(); + return res; + } #if IS_ENABLED(CONFIG_IPV6) else if (ntohs(eth->h_proto) == ETH_P_IPV6 && pskb_network_may_pull(skb, sizeof(struct ipv6hdr) + @@ -2788,53 +2841,57 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) struct nd_msg *m = (struct nd_msg *)(ipv6_hdr(skb) + 1); if (m->icmph.icmp6_code == 0 && - m->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) - return neigh_reduce(dev, skb, vni); + m->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { + netdev_tx_t res = neigh_reduce(dev, skb, cfg, vni); + + rcu_read_unlock(); + return res; + } } #endif } - if (nhid) - return vxlan_xmit_nhid(skb, dev, nhid, vni); + if (nhid) { + netdev_tx_t res = vxlan_xmit_nhid(skb, dev, nhid, vni, cfg); + + rcu_read_unlock(); + return res; + } - if (vxlan->cfg.flags & VXLAN_F_MDB) { + if (test_bit(VXLAN_DEV_F_MDB, &vxlan->flags)) { struct vxlan_mdb_entry *mdb_entry; - rcu_read_lock(); - mdb_entry = vxlan_mdb_entry_skb_get(vxlan, skb, vni); + mdb_entry = vxlan_mdb_entry_skb_get(vxlan, cfg, skb, vni); if (mdb_entry) { - netdev_tx_t ret; + netdev_tx_t ret = vxlan_mdb_xmit(vxlan, cfg, mdb_entry, skb); - ret = vxlan_mdb_xmit(vxlan, mdb_entry, skb); rcu_read_unlock(); return ret; } - rcu_read_unlock(); } eth = eth_hdr(skb); - rcu_read_lock(); - f = vxlan_find_mac_tx(vxlan, eth->h_dest, vni); + f = vxlan_find_mac_tx(vxlan, cfg, eth->h_dest, vni); did_rsc = false; - if (f && (f->flags & NTF_ROUTER) && (vxlan->cfg.flags & VXLAN_F_RSC) && + if (f && (f->flags & NTF_ROUTER) && (flags & VXLAN_F_RSC) && (ntohs(eth->h_proto) == ETH_P_IP || ntohs(eth->h_proto) == ETH_P_IPV6)) { - did_rsc = route_shortcircuit(dev, skb); + did_rsc = route_shortcircuit(dev, skb, cfg); eth = eth_hdr(skb); if (did_rsc) - f = vxlan_find_mac_tx(vxlan, eth->h_dest, vni); + f = vxlan_find_mac_tx(vxlan, cfg, eth->h_dest, vni); } if (f == NULL) { - f = vxlan_find_mac_tx(vxlan, all_zeros_mac, vni); + f = vxlan_find_mac_tx(vxlan, cfg, all_zeros_mac, vni); if (f == NULL) { - if ((vxlan->cfg.flags & VXLAN_F_L2MISS) && + if ((flags & VXLAN_F_L2MISS) && !is_multicast_ether_addr(eth->h_dest)) vxlan_fdb_miss(vxlan, eth->h_dest); dev_dstats_tx_dropped(dev); - vxlan_vnifilter_count(vxlan, vni, NULL, + vxlan_vnifilter_count(vxlan, cfg, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); kfree_skb_reason(skb, SKB_DROP_REASON_NO_TX_TARGET); goto out; @@ -2842,8 +2899,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) } if (rcu_access_pointer(f->nh)) { - vxlan_xmit_nh(skb, dev, f, - (vni ? : vxlan->default_dst.remote_vni), did_rsc); + vxlan_xmit_nh(skb, dev, cfg, f, + (vni ? : default_vni), did_rsc); } else { list_for_each_entry_rcu(rdst, &f->remotes, list) { struct sk_buff *skb1; @@ -2854,10 +2911,10 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) } skb1 = skb_clone(skb, GFP_ATOMIC); if (skb1) - vxlan_xmit_one(skb1, dev, vni, rdst, did_rsc); + vxlan_xmit_one(skb1, dev, cfg, vni, rdst, did_rsc); } if (fdst) - vxlan_xmit_one(skb, dev, vni, fdst, did_rsc); + vxlan_xmit_one(skb, dev, cfg, vni, fdst, did_rsc); else kfree_skb_reason(skb, SKB_DROP_REASON_NO_TX_TARGET); } @@ -2872,12 +2929,15 @@ static void vxlan_cleanup(struct timer_list *t) { struct vxlan_dev *vxlan = timer_container_of(vxlan, t, age_timer); unsigned long next_timer = jiffies + FDB_AGE_INTERVAL; + const struct vxlan_config *cfg; struct vxlan_fdb *f; if (!netif_running(vxlan->dev)) return; rcu_read_lock(); + cfg = rcu_dereference(vxlan->cfg); + hlist_for_each_entry_rcu(f, &vxlan->fdb_list, fdb_node) { unsigned long timeout; @@ -2887,7 +2947,7 @@ static void vxlan_cleanup(struct timer_list *t) if (f->flags & NTF_EXT_LEARNED) continue; - timeout = READ_ONCE(f->updated) + vxlan->cfg.age_interval * HZ; + timeout = READ_ONCE(f->updated) + cfg->age_interval * HZ; if (time_before_eq(timeout, jiffies)) { spin_lock(&vxlan->hash_lock); if (!hlist_unhashed(&f->fdb_node)) { @@ -2919,10 +2979,14 @@ static void vxlan_vs_del_dev(struct vxlan_dev *vxlan) static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan, struct vxlan_dev_node *node) { - __be32 vni = vxlan->default_dst.remote_vni; + const struct vxlan_config *cfg; + __be32 vni; ASSERT_RTNL(); + cfg = rtnl_dereference(vxlan->cfg); + vni = cfg->vni; + node->vxlan = vxlan; hlist_add_head_rcu(&node->hlist, vni_head(vs, vni)); } @@ -2931,13 +2995,16 @@ static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan, static int vxlan_init(struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); + const struct vxlan_config *cfg; int err; + cfg = rtnl_dereference(vxlan->cfg); + err = rhashtable_init(&vxlan->fdb_hash_tbl, &vxlan_fdb_rht_params); if (err) return err; - if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) { + if (cfg->flags & VXLAN_F_VNIFILTER) { err = vxlan_vnigroup_init(vxlan); if (err) goto err_rhashtable_destroy; @@ -2957,7 +3024,7 @@ static int vxlan_init(struct net_device *dev) err_gro_cells_destroy: gro_cells_destroy(&vxlan->gro_cells); err_vnigroup_uninit: - if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) + if (cfg->flags & VXLAN_F_VNIFILTER) vxlan_vnigroup_uninit(vxlan); err_rhashtable_destroy: rhashtable_destroy(&vxlan->fdb_hash_tbl); @@ -2967,10 +3034,13 @@ err_rhashtable_destroy: static void vxlan_uninit(struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); + const struct vxlan_config *cfg; + + cfg = rtnl_dereference(vxlan->cfg); vxlan_mdb_fini(vxlan); - if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) + if (cfg->flags & VXLAN_F_VNIFILTER) vxlan_vnigroup_uninit(vxlan); gro_cells_destroy(&vxlan->gro_cells); @@ -2982,6 +3052,7 @@ static void vxlan_uninit(struct net_device *dev) static int vxlan_open(struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); + const struct vxlan_config *cfg; int ret; ret = vxlan_sock_add(vxlan); @@ -2994,7 +3065,8 @@ static int vxlan_open(struct net_device *dev) return ret; } - if (vxlan->cfg.age_interval) + cfg = rtnl_dereference(vxlan->cfg); + if (cfg->age_interval) mod_timer(&vxlan->age_timer, jiffies + FDB_AGE_INTERVAL); return ret; @@ -3016,8 +3088,10 @@ struct vxlan_fdb_flush_desc { static bool vxlan_fdb_is_default_entry(const struct vxlan_fdb *f, const struct vxlan_dev *vxlan) { + const struct vxlan_config *cfg = rcu_dereference_rtnl(vxlan->cfg); + return is_zero_ether_addr(f->key.eth_addr) && - f->key.vni == vxlan->cfg.vni; + f->key.vni == cfg->vni; } static bool vxlan_fdb_nhid_matches(const struct vxlan_fdb *f, u32 nhid) @@ -3234,15 +3308,18 @@ static void vxlan_set_multicast_list(struct net_device *dev) static int vxlan_change_mtu(struct net_device *dev, int new_mtu) { struct vxlan_dev *vxlan = netdev_priv(dev); - struct vxlan_rdst *dst = &vxlan->default_dst; - struct net_device *lowerdev = __dev_get_by_index(vxlan->net, - dst->remote_ifindex); + const struct vxlan_config *cfg; + struct net_device *lowerdev; + + cfg = rtnl_dereference(vxlan->cfg); + + lowerdev = __dev_get_by_index(vxlan->net, cfg->remote_ifindex); /* This check is different than dev->max_mtu, because it looks at * the lowerdev->mtu, rather than the static dev->max_mtu */ if (lowerdev) { - int max_mtu = lowerdev->mtu - vxlan_headroom(vxlan->cfg.flags); + int max_mtu = lowerdev->mtu - vxlan_headroom(cfg->flags); if (new_mtu > max_mtu) return -EINVAL; } @@ -3255,11 +3332,14 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) { struct vxlan_dev *vxlan = netdev_priv(dev); struct ip_tunnel_info *info = skb_tunnel_info(skb); + const struct vxlan_config *cfg; __be16 sport, dport; - sport = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min, - vxlan->cfg.port_max, true); - dport = info->key.tp_dst ? : vxlan->cfg.dst_port; + cfg = rcu_dereference(vxlan->cfg); + + sport = udp_flow_src_port(dev_net(dev), skb, cfg->port_min, + cfg->port_max, true); + dport = info->key.tp_dst ? : cfg->dst_port; if (ip_tunnel_info_af(info) == AF_INET) { struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock); @@ -3369,6 +3449,15 @@ static void vxlan_offload_rx_ports(struct net_device *dev, bool push) } } +static void vxlan_free_dev(struct net_device *dev) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_config *cfg = rcu_dereference_protected(vxlan->cfg, 1); + + RCU_INIT_POINTER(vxlan->cfg, NULL); + kfree(cfg); +} + /* Initialize the device structure. */ static void vxlan_setup(struct net_device *dev) { @@ -3377,6 +3466,8 @@ static void vxlan_setup(struct net_device *dev) eth_hw_addr_random(dev); ether_setup(dev); + dev->priv_destructor = vxlan_free_dev; + dev->needs_free_netdev = true; SET_NETDEV_DEVTYPE(dev, &vxlan_type); @@ -3551,9 +3642,11 @@ static int vxlan_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct vxlan_dev *vxlan = netdev_priv(dev); - struct vxlan_rdst *dst = &vxlan->default_dst; - struct net_device *lowerdev = __dev_get_by_index(vxlan->net, - dst->remote_ifindex); + const struct vxlan_config *cfg; + struct net_device *lowerdev; + + cfg = rtnl_dereference(vxlan->cfg); + lowerdev = __dev_get_by_index(vxlan->net, cfg->remote_ifindex); if (!lowerdev) { cmd->base.duplex = DUPLEX_UNKNOWN; @@ -3659,21 +3752,22 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6, static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) { - bool metadata = vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA; + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); + bool metadata = cfg->flags & VXLAN_F_COLLECT_METADATA; struct vxlan_sock *vs = NULL; struct vxlan_dev_node *node; int l3mdev_index = 0; ASSERT_RTNL(); - if (vxlan->cfg.remote_ifindex) + if (cfg->remote_ifindex) l3mdev_index = l3mdev_master_upper_ifindex_by_index( - vxlan->net, vxlan->cfg.remote_ifindex); + vxlan->net, cfg->remote_ifindex); - if (!vxlan->cfg.no_share) { + if (!cfg->no_share) { rcu_read_lock(); vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET, - vxlan->cfg.dst_port, vxlan->cfg.flags, + cfg->dst_port, cfg->flags, l3mdev_index); if (vs && !refcount_inc_not_zero(&vs->refcnt)) { rcu_read_unlock(); @@ -3683,7 +3777,7 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) } if (!vs) vs = vxlan_socket_create(vxlan->net, ipv6, - vxlan->cfg.dst_port, vxlan->cfg.flags, + cfg->dst_port, cfg->flags, l3mdev_index); if (IS_ERR(vs)) return PTR_ERR(vs); @@ -3698,7 +3792,7 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) node = &vxlan->hlist4; } - if (metadata && (vxlan->cfg.flags & VXLAN_F_VNIFILTER)) + if (metadata && (cfg->flags & VXLAN_F_VNIFILTER)) vxlan_vs_add_vnigrp(vxlan, vs, ipv6); else vxlan_vs_add_dev(vs, vxlan, node); @@ -3708,11 +3802,14 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) static int vxlan_sock_add(struct vxlan_dev *vxlan) { - bool metadata = vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA; - bool ipv6 = vxlan->cfg.flags & VXLAN_F_IPV6 || metadata; - bool ipv4 = !ipv6 || metadata; + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); + bool metadata, ipv6, ipv4; int ret = 0; + metadata = cfg->flags & VXLAN_F_COLLECT_METADATA; + ipv6 = (cfg->flags & VXLAN_F_IPV6) || metadata; + ipv4 = !ipv6 || metadata; + RCU_INIT_POINTER(vxlan->vn4_sock, NULL); #if IS_ENABLED(CONFIG_IPV6) RCU_INIT_POINTER(vxlan->vn6_sock, NULL); @@ -3730,28 +3827,33 @@ static int vxlan_sock_add(struct vxlan_dev *vxlan) } int vxlan_vni_in_use(struct net *src_net, struct vxlan_dev *vxlan, - struct vxlan_config *conf, __be32 vni) + const struct vxlan_config *conf, __be32 vni) { struct vxlan_net *vn = net_generic(src_net, vxlan_net_id); struct vxlan_dev *tmp; list_for_each_entry(tmp, &vn->vxlan_list, next) { + const struct vxlan_config *tmp_cfg; + if (tmp == vxlan) continue; - if (tmp->cfg.flags & VXLAN_F_VNIFILTER) { + + tmp_cfg = rtnl_dereference(tmp->cfg); + + if (tmp_cfg->flags & VXLAN_F_VNIFILTER) { if (!vxlan_vnifilter_lookup(tmp, vni)) continue; - } else if (tmp->cfg.vni != vni) { + } else if (tmp_cfg->vni != vni) { continue; } - if (tmp->cfg.dst_port != conf->dst_port) + if (tmp_cfg->dst_port != conf->dst_port) continue; - if ((tmp->cfg.flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6)) != + if ((tmp_cfg->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6)) != (conf->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6))) continue; if ((conf->flags & VXLAN_F_IPV6_LINKLOCAL) && - tmp->cfg.remote_ifindex != conf->remote_ifindex) + tmp_cfg->remote_ifindex != conf->remote_ifindex) continue; return -EEXIST; @@ -3882,6 +3984,13 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, return -EINVAL; } + if ((conf->flags & VXLAN_F_VNIFILTER) && old && + vxlan_vnifilter_has_multicast(old)) { + NL_SET_ERR_MSG(extack, + "Local interface required for multicast remote group"); + return -EINVAL; + } + #if IS_ENABLED(CONFIG_IPV6) if (conf->flags & VXLAN_F_IPV6_LINKLOCAL) { NL_SET_ERR_MSG(extack, @@ -3913,16 +4022,16 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, } static void vxlan_config_apply(struct net_device *dev, - struct vxlan_config *conf, + struct vxlan_config *new_cfg, struct net_device *lowerdev, struct net *src_net, - bool changelink) + bool changelink, bool lowerdev_changed) { struct vxlan_dev *vxlan = netdev_priv(dev); - struct vxlan_rdst *dst = &vxlan->default_dst; unsigned short needed_headroom = ETH_HLEN; + struct vxlan_config *old_cfg; int max_mtu = ETH_MAX_MTU; - u32 flags = conf->flags; + u32 flags = new_cfg->flags; if (!changelink) { if (flags & VXLAN_F_GPE) @@ -3930,19 +4039,14 @@ static void vxlan_config_apply(struct net_device *dev, else vxlan_ether_setup(dev); - if (conf->mtu) - dev->mtu = conf->mtu; + if (new_cfg->mtu) + WRITE_ONCE(dev->mtu, new_cfg->mtu); vxlan->net = src_net; } - dst->remote_vni = conf->vni; - - memcpy(&dst->remote_ip, &conf->remote_ip, sizeof(conf->remote_ip)); - + dev->needed_tailroom = 0; if (lowerdev) { - dst->remote_ifindex = conf->remote_ifindex; - netif_inherit_tso_max(dev, lowerdev); needed_headroom = lowerdev->hard_header_len; @@ -3950,23 +4054,27 @@ static void vxlan_config_apply(struct net_device *dev, dev->needed_tailroom = lowerdev->needed_tailroom; - max_mtu = lowerdev->mtu - vxlan_headroom(flags); + max_mtu = READ_ONCE(lowerdev->mtu) - vxlan_headroom(flags); if (max_mtu < ETH_MIN_MTU) max_mtu = ETH_MIN_MTU; - if (!changelink && !conf->mtu) - dev->mtu = max_mtu; + if (!changelink && !new_cfg->mtu) + WRITE_ONCE(dev->mtu, max_mtu); } - if (dev->mtu > max_mtu) - dev->mtu = max_mtu; + /* A changelink leaving the lower device alone must not shrink the mtu */ + if (lowerdev_changed && READ_ONCE(dev->mtu) > max_mtu) + WRITE_ONCE(dev->mtu, max_mtu); if (flags & VXLAN_F_COLLECT_METADATA) flags |= VXLAN_F_IPV6; needed_headroom += vxlan_headroom(flags); dev->needed_headroom = needed_headroom; - memcpy(&vxlan->cfg, conf, sizeof(*conf)); + old_cfg = rtnl_dereference(vxlan->cfg); + rcu_assign_pointer(vxlan->cfg, new_cfg); + if (old_cfg) + kfree_rcu(old_cfg, rcu); } static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, @@ -3975,13 +4083,18 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, { struct vxlan_dev *vxlan = netdev_priv(dev); struct net_device *lowerdev; + struct vxlan_config *new_cfg; int ret; ret = vxlan_config_validate(src_net, conf, &lowerdev, vxlan, extack); if (ret) return ret; - vxlan_config_apply(dev, conf, lowerdev, src_net, false); + new_cfg = kmemdup(conf, sizeof(*conf), GFP_KERNEL); + if (!new_cfg) + return -ENOMEM; + + vxlan_config_apply(dev, new_cfg, lowerdev, src_net, false, true); return 0; } @@ -3993,22 +4106,25 @@ static int vxlan_dev_create(struct net *net, struct net_device *dev, struct vxlan_net *vn = net_generic(net, vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); struct net_device *remote_dev = NULL; - struct vxlan_rdst *dst; + const struct vxlan_config *cfg; int err; - dst = &vxlan->default_dst; err = vxlan_dev_configure(net, dev, conf, extack); if (err) return err; + cfg = rtnl_dereference(vxlan->cfg); + dev->ethtool_ops = &vxlan_ethtool_ops; err = register_netdevice(dev); - if (err) + if (err) { + vxlan_free_dev(dev); return err; + } - if (dst->remote_ifindex) { - remote_dev = __dev_get_by_index(net, dst->remote_ifindex); + if (cfg->remote_ifindex) { + remote_dev = __dev_get_by_index(net, cfg->remote_ifindex); if (!remote_dev) { err = -ENODEV; goto unregister; @@ -4018,7 +4134,7 @@ static int vxlan_dev_create(struct net *net, struct net_device *dev, if (err) goto unregister; - dst->remote_dev = remote_dev; + vxlan->lowerdev = remote_dev; } err = rtnl_configure_link(dev, NULL, 0, NULL); @@ -4026,16 +4142,18 @@ static int vxlan_dev_create(struct net *net, struct net_device *dev, goto unlink; /* create an fdb entry for a valid default destination */ - if (!vxlan_addr_any(&dst->remote_ip)) { + if (!vxlan_addr_any(&cfg->remote_ip)) { + union vxlan_addr rip = cfg->remote_ip; + spin_lock_bh(&vxlan->hash_lock); err = vxlan_fdb_update(vxlan, all_zeros_mac, - &dst->remote_ip, + &rip, NUD_REACHABLE | NUD_PERMANENT, NLM_F_EXCL | NLM_F_CREATE, - vxlan->cfg.dst_port, - dst->remote_vni, - dst->remote_vni, - dst->remote_ifindex, + cfg->dst_port, + cfg->vni, + cfg->vni, + cfg->remote_ifindex, NTF_SELF, 0, true, extack); spin_unlock_bh(&vxlan->hash_lock); if (err) @@ -4096,8 +4214,12 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], memset(conf, 0, sizeof(*conf)); /* if changelink operation, start with old existing cfg */ - if (changelink) - memcpy(conf, &vxlan->cfg, sizeof(*conf)); + if (changelink) { + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); + + if (cfg) + memcpy(conf, cfg, sizeof(*conf)); + } if (data[IFLA_VXLAN_ID]) { __be32 vni = cpu_to_be32(nla_get_u32(data[IFLA_VXLAN_ID])); @@ -4443,17 +4565,19 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { + bool lowerdev_changed, rem_ip_changed, change_igmp; struct vxlan_dev *vxlan = netdev_priv(dev); - bool rem_ip_changed, change_igmp; + const struct vxlan_config *cfg; + struct vxlan_config *new_cfg; struct net_device *lowerdev; struct vxlan_config conf; - struct vxlan_rdst *dst; int err; + cfg = rtnl_dereference(vxlan->cfg); + if (!rtnl_dev_link_net_capable(dev, vxlan->net)) return -EPERM; - dst = &vxlan->default_dst; err = vxlan_nl2conf(tb, data, dev, &conf, true, extack); if (err) return err; @@ -4463,76 +4587,108 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], if (err) return err; - if (dst->remote_dev == lowerdev) - lowerdev = NULL; + new_cfg = kmemdup(&conf, sizeof(conf), GFP_KERNEL); + if (!new_cfg) + return -ENOMEM; - err = netdev_adjacent_change_prepare(dst->remote_dev, lowerdev, dev, - extack); - if (err) - return err; + lowerdev_changed = vxlan->lowerdev != lowerdev; + if (lowerdev_changed) { + err = netdev_adjacent_change_prepare(vxlan->lowerdev, lowerdev, + dev, extack); + if (err) { + kfree(new_cfg); + return err; + } + } - rem_ip_changed = !vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip); + rem_ip_changed = !vxlan_addr_equal(&conf.remote_ip, &cfg->remote_ip); change_igmp = vxlan->dev->flags & IFF_UP && (rem_ip_changed || - dst->remote_ifindex != conf.remote_ifindex); + cfg->remote_ifindex != conf.remote_ifindex); /* handle default dst entry */ - if (rem_ip_changed) { + if (rem_ip_changed || cfg->remote_ifindex != conf.remote_ifindex) { spin_lock_bh(&vxlan->hash_lock); if (!vxlan_addr_any(&conf.remote_ip)) { err = vxlan_fdb_update(vxlan, all_zeros_mac, &conf.remote_ip, NUD_REACHABLE | NUD_PERMANENT, NLM_F_APPEND | NLM_F_CREATE, - vxlan->cfg.dst_port, + cfg->dst_port, conf.vni, conf.vni, conf.remote_ifindex, NTF_SELF, 0, true, extack); if (err) { spin_unlock_bh(&vxlan->hash_lock); - netdev_adjacent_change_abort(dst->remote_dev, - lowerdev, dev); + if (lowerdev_changed) + netdev_adjacent_change_abort(vxlan->lowerdev, + lowerdev, dev); + kfree(new_cfg); return err; } } - if (!vxlan_addr_any(&dst->remote_ip)) + if (!vxlan_addr_any(&cfg->remote_ip)) __vxlan_fdb_delete(vxlan, all_zeros_mac, - dst->remote_ip, - vxlan->cfg.dst_port, - dst->remote_vni, - dst->remote_vni, - dst->remote_ifindex, + cfg->remote_ip, + cfg->dst_port, + cfg->vni, + cfg->vni, + cfg->remote_ifindex, true); spin_unlock_bh(&vxlan->hash_lock); - /* If vni filtering device, also update fdb entries of - * all vnis that were using default remote ip + /* If vni filtering device, also update default fdb entries of + * all vnis */ - if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) { - err = vxlan_vnilist_update_group(vxlan, &dst->remote_ip, - &conf.remote_ip, extack); + if (cfg->flags & VXLAN_F_VNIFILTER) { + err = vxlan_vnilist_update_group(vxlan, &cfg->remote_ip, + &conf.remote_ip, + cfg->remote_ifindex, + conf.remote_ifindex, + extack); if (err) { - netdev_adjacent_change_abort(dst->remote_dev, - lowerdev, dev); + vxlan_update_default_fdb_entry(vxlan, conf.vni, + &conf.remote_ip, + &cfg->remote_ip, + conf.remote_ifindex, + cfg->remote_ifindex, + NULL); + if (lowerdev_changed) + netdev_adjacent_change_abort(vxlan->lowerdev, + lowerdev, dev); + kfree(new_cfg); return err; } } } - if (change_igmp && vxlan_addr_multicast(&dst->remote_ip)) + if (change_igmp && + (vxlan_addr_multicast(&cfg->remote_ip) || + (cfg->flags & VXLAN_F_VNIFILTER))) err = vxlan_multicast_leave(vxlan); - if (netif_running(dev) && conf.age_interval != vxlan->cfg.age_interval) + if (netif_running(dev) && conf.age_interval != cfg->age_interval) mod_timer(&vxlan->age_timer, jiffies); - netdev_adjacent_change_commit(dst->remote_dev, lowerdev, dev); - if (lowerdev && lowerdev != dst->remote_dev) - dst->remote_dev = lowerdev; - vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true); + if (lowerdev_changed) { + if (lowerdev) + netdev_adjacent_change_commit(vxlan->lowerdev, lowerdev, + dev); + else + netdev_upper_dev_unlink(vxlan->lowerdev, dev); + vxlan->lowerdev = lowerdev; + } + vxlan_config_apply(dev, new_cfg, lowerdev, vxlan->net, true, + lowerdev_changed); - if (!err && change_igmp && - vxlan_addr_multicast(&dst->remote_ip)) - err = vxlan_multicast_join(vxlan); + if (change_igmp && + (vxlan_addr_multicast(&new_cfg->remote_ip) || + (new_cfg->flags & VXLAN_F_VNIFILTER))) { + int join_err = vxlan_multicast_join(vxlan); + + if (join_err) + err = join_err; + } return err; } @@ -4546,8 +4702,8 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head) list_del(&vxlan->next); unregister_netdevice_queue(dev, head); - if (vxlan->default_dst.remote_dev) - netdev_upper_dev_unlink(vxlan->default_dst.remote_dev, dev); + if (vxlan->lowerdev) + netdev_upper_dev_unlink(vxlan->lowerdev, dev); } static size_t vxlan_get_size(const struct net_device *dev) @@ -4591,110 +4747,114 @@ static size_t vxlan_get_size(const struct net_device *dev) static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) { const struct vxlan_dev *vxlan = netdev_priv(dev); - const struct vxlan_rdst *dst = &vxlan->default_dst; - struct ifla_vxlan_port_range ports = { - .low = htons(vxlan->cfg.port_min), - .high = htons(vxlan->cfg.port_max), - }; + struct ifla_vxlan_port_range ports; + const struct vxlan_config *cfg; + + rcu_read_lock(); + cfg = rcu_dereference(vxlan->cfg); - if (nla_put_u32(skb, IFLA_VXLAN_ID, be32_to_cpu(dst->remote_vni))) + if (nla_put_u32(skb, IFLA_VXLAN_ID, be32_to_cpu(cfg->vni))) goto nla_put_failure; - if (!vxlan_addr_any(&dst->remote_ip)) { - if (dst->remote_ip.sa.sa_family == AF_INET) { + if (!vxlan_addr_any(&cfg->remote_ip)) { + if (cfg->remote_ip.sa.sa_family == AF_INET) { if (nla_put_in_addr(skb, IFLA_VXLAN_GROUP, - dst->remote_ip.sin.sin_addr.s_addr)) + cfg->remote_ip.sin.sin_addr.s_addr)) goto nla_put_failure; #if IS_ENABLED(CONFIG_IPV6) } else { if (nla_put_in6_addr(skb, IFLA_VXLAN_GROUP6, - &dst->remote_ip.sin6.sin6_addr)) + &cfg->remote_ip.sin6.sin6_addr)) goto nla_put_failure; #endif } } - if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex)) + if (cfg->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, cfg->remote_ifindex)) goto nla_put_failure; - if (!vxlan_addr_any(&vxlan->cfg.saddr)) { - if (vxlan->cfg.saddr.sa.sa_family == AF_INET) { + if (!vxlan_addr_any(&cfg->saddr)) { + if (cfg->saddr.sa.sa_family == AF_INET) { if (nla_put_in_addr(skb, IFLA_VXLAN_LOCAL, - vxlan->cfg.saddr.sin.sin_addr.s_addr)) + cfg->saddr.sin.sin_addr.s_addr)) goto nla_put_failure; #if IS_ENABLED(CONFIG_IPV6) } else { if (nla_put_in6_addr(skb, IFLA_VXLAN_LOCAL6, - &vxlan->cfg.saddr.sin6.sin6_addr)) + &cfg->saddr.sin6.sin6_addr)) goto nla_put_failure; #endif } } - if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->cfg.ttl) || + if (nla_put_u8(skb, IFLA_VXLAN_TTL, cfg->ttl) || nla_put_u8(skb, IFLA_VXLAN_TTL_INHERIT, - !!(vxlan->cfg.flags & VXLAN_F_TTL_INHERIT)) || - nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) || - nla_put_u8(skb, IFLA_VXLAN_DF, vxlan->cfg.df) || - nla_put_be32(skb, IFLA_VXLAN_LABEL, vxlan->cfg.label) || - nla_put_u32(skb, IFLA_VXLAN_LABEL_POLICY, vxlan->cfg.label_policy) || + !!(cfg->flags & VXLAN_F_TTL_INHERIT)) || + nla_put_u8(skb, IFLA_VXLAN_TOS, cfg->tos) || + nla_put_u8(skb, IFLA_VXLAN_DF, cfg->df) || + nla_put_be32(skb, IFLA_VXLAN_LABEL, cfg->label) || + nla_put_u32(skb, IFLA_VXLAN_LABEL_POLICY, cfg->label_policy) || nla_put_u8(skb, IFLA_VXLAN_LEARNING, - !!(vxlan->cfg.flags & VXLAN_F_LEARN)) || + !!(cfg->flags & VXLAN_F_LEARN)) || nla_put_u8(skb, IFLA_VXLAN_PROXY, - !!(vxlan->cfg.flags & VXLAN_F_PROXY)) || + !!(cfg->flags & VXLAN_F_PROXY)) || nla_put_u8(skb, IFLA_VXLAN_RSC, - !!(vxlan->cfg.flags & VXLAN_F_RSC)) || + !!(cfg->flags & VXLAN_F_RSC)) || nla_put_u8(skb, IFLA_VXLAN_L2MISS, - !!(vxlan->cfg.flags & VXLAN_F_L2MISS)) || + !!(cfg->flags & VXLAN_F_L2MISS)) || nla_put_u8(skb, IFLA_VXLAN_L3MISS, - !!(vxlan->cfg.flags & VXLAN_F_L3MISS)) || + !!(cfg->flags & VXLAN_F_L3MISS)) || nla_put_u8(skb, IFLA_VXLAN_COLLECT_METADATA, - !!(vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA)) || - nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->cfg.age_interval) || - nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->cfg.addrmax) || - nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->cfg.dst_port) || + !!(cfg->flags & VXLAN_F_COLLECT_METADATA)) || + nla_put_u32(skb, IFLA_VXLAN_AGEING, cfg->age_interval) || + nla_put_u32(skb, IFLA_VXLAN_LIMIT, cfg->addrmax) || + nla_put_be16(skb, IFLA_VXLAN_PORT, cfg->dst_port) || nla_put_u8(skb, IFLA_VXLAN_UDP_CSUM, - !(vxlan->cfg.flags & VXLAN_F_UDP_ZERO_CSUM_TX)) || + !(cfg->flags & VXLAN_F_UDP_ZERO_CSUM_TX)) || nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, - !!(vxlan->cfg.flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) || + !!(cfg->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) || nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, - !!(vxlan->cfg.flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) || + !!(cfg->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) || nla_put_u8(skb, IFLA_VXLAN_REMCSUM_TX, - !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_TX)) || + !!(cfg->flags & VXLAN_F_REMCSUM_TX)) || nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX, - !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX)) || + !!(cfg->flags & VXLAN_F_REMCSUM_RX)) || nla_put_u8(skb, IFLA_VXLAN_LOCALBYPASS, - !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS))) + !!(cfg->flags & VXLAN_F_LOCALBYPASS))) goto nla_put_failure; + ports.low = htons(cfg->port_min); + ports.high = htons(cfg->port_max); if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) goto nla_put_failure; - if (vxlan->cfg.flags & VXLAN_F_GBP && + if (cfg->flags & VXLAN_F_GBP && nla_put_flag(skb, IFLA_VXLAN_GBP)) goto nla_put_failure; - if (vxlan->cfg.flags & VXLAN_F_GPE && + if (cfg->flags & VXLAN_F_GPE && nla_put_flag(skb, IFLA_VXLAN_GPE)) goto nla_put_failure; - if (vxlan->cfg.flags & VXLAN_F_REMCSUM_NOPARTIAL && + if (cfg->flags & VXLAN_F_REMCSUM_NOPARTIAL && nla_put_flag(skb, IFLA_VXLAN_REMCSUM_NOPARTIAL)) goto nla_put_failure; - if (vxlan->cfg.flags & VXLAN_F_VNIFILTER && + if (cfg->flags & VXLAN_F_VNIFILTER && nla_put_u8(skb, IFLA_VXLAN_VNIFILTER, - !!(vxlan->cfg.flags & VXLAN_F_VNIFILTER))) + !!(cfg->flags & VXLAN_F_VNIFILTER))) goto nla_put_failure; if (nla_put(skb, IFLA_VXLAN_RESERVED_BITS, - sizeof(vxlan->cfg.reserved_bits), - &vxlan->cfg.reserved_bits)) + sizeof(cfg->reserved_bits), + &cfg->reserved_bits)) goto nla_put_failure; + rcu_read_unlock(); return 0; nla_put_failure: + rcu_read_unlock(); return -EMSGSIZE; } @@ -4727,7 +4887,7 @@ static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn, LIST_HEAD(list_kill); list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) { - struct vxlan_rdst *dst = &vxlan->default_dst; + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); /* In case we created vxlan device with carrier * and we loose the carrier due to module unload @@ -4735,7 +4895,7 @@ static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn, * cases, it's not necessary and remote_ifindex * is 0 here, so no matches. */ - if (dst->remote_ifindex == dev->ifindex) + if (cfg->remote_ifindex == dev->ifindex) vxlan_dellink(vxlan->dev, &list_kill); } @@ -4748,6 +4908,10 @@ static int vxlan_netdevice_event(struct notifier_block *unused, struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); + if ((event == NETDEV_REGISTER || event == NETDEV_UNREGISTER) && + netif_is_vxlan(dev)) + vxlan_vnifilter_seq_inc(dev_net(dev)); + if (event == NETDEV_UNREGISTER) vxlan_handle_lowerdev_unregister(vn, dev); else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO) diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c index 841f42ffecb9..c1a055199055 100644 --- a/drivers/net/vxlan/vxlan_mdb.c +++ b/drivers/net/vxlan/vxlan_mdb.c @@ -165,6 +165,7 @@ static int vxlan_mdb_entry_info_fill(const struct vxlan_dev *vxlan, const struct vxlan_mdb_entry *mdb_entry, const struct vxlan_mdb_remote *remote) { + const struct vxlan_config *cfg = rcu_dereference_rtnl(vxlan->cfg); struct vxlan_rdst *rd = rtnl_dereference(remote->rd); struct br_mdb_entry e; struct nlattr *nest; @@ -189,12 +190,12 @@ static int vxlan_mdb_entry_info_fill(const struct vxlan_dev *vxlan, vxlan_nla_put_addr(skb, MDBA_MDB_EATTR_DST, &rd->remote_ip)) goto nest_err; - if (rd->remote_port && rd->remote_port != vxlan->cfg.dst_port && + if (rd->remote_port && rd->remote_port != cfg->dst_port && nla_put_u16(skb, MDBA_MDB_EATTR_DST_PORT, be16_to_cpu(rd->remote_port))) goto nest_err; - if (rd->remote_vni != vxlan->default_dst.remote_vni && + if (rd->remote_vni != cfg->vni && nla_put_u32(skb, MDBA_MDB_EATTR_VNI, be32_to_cpu(rd->remote_vni))) goto nest_err; @@ -202,7 +203,7 @@ static int vxlan_mdb_entry_info_fill(const struct vxlan_dev *vxlan, nla_put_u32(skb, MDBA_MDB_EATTR_IFINDEX, rd->remote_ifindex)) goto nest_err; - if ((vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) && + if ((cfg->flags & VXLAN_F_COLLECT_METADATA) && mdb_entry->key.vni && nla_put_u32(skb, MDBA_MDB_EATTR_SRC_VNI, be32_to_cpu(mdb_entry->key.vni))) goto nest_err; @@ -613,16 +614,19 @@ static int vxlan_mdb_config_init(struct vxlan_mdb_config *cfg, { struct br_mdb_entry *entry = nla_data(tb[MDBA_SET_ENTRY]); struct vxlan_dev *vxlan = netdev_priv(dev); + const struct vxlan_config *vcfg; + + vcfg = rtnl_dereference(vxlan->cfg); memset(cfg, 0, sizeof(*cfg)); cfg->vxlan = vxlan; - cfg->group.vni = vxlan->default_dst.remote_vni; + cfg->group.vni = vcfg->vni; INIT_LIST_HEAD(&cfg->src_list); cfg->nlflags = nlmsg_flags; cfg->filter_mode = MCAST_EXCLUDE; cfg->rt_protocol = RTPROT_STATIC; - cfg->remote_vni = vxlan->default_dst.remote_vni; - cfg->remote_port = vxlan->cfg.dst_port; + cfg->remote_vni = vcfg->vni; + cfg->remote_port = vcfg->dst_port; if (entry->ifindex != dev->ifindex) { NL_SET_ERR_MSG_MOD(extack, "Port net device must be the VXLAN net device"); @@ -957,11 +961,12 @@ vxlan_mdb_nlmsg_remote_size(const struct vxlan_dev *vxlan, const struct vxlan_mdb_entry *mdb_entry, const struct vxlan_mdb_remote *remote) { + const struct vxlan_config *cfg = rcu_dereference_rtnl(vxlan->cfg); const struct vxlan_mdb_entry_key *group = &mdb_entry->key; struct vxlan_rdst *rd = rtnl_dereference(remote->rd); size_t nlmsg_size; - /* MDBA_MDB_ENTRY_INFO */ + /* MDBA_MDB_ENTRY_INFO */ nlmsg_size = nla_total_size(sizeof(struct br_mdb_entry)) + /* MDBA_MDB_EATTR_TIMER */ nla_total_size(sizeof(u32)); @@ -978,16 +983,16 @@ vxlan_mdb_nlmsg_remote_size(const struct vxlan_dev *vxlan, /* MDBA_MDB_EATTR_DST */ nlmsg_size += nla_total_size(vxlan_addr_size(&rd->remote_ip)); /* MDBA_MDB_EATTR_DST_PORT */ - if (rd->remote_port && rd->remote_port != vxlan->cfg.dst_port) + if (rd->remote_port && rd->remote_port != cfg->dst_port) nlmsg_size += nla_total_size(sizeof(u16)); /* MDBA_MDB_EATTR_VNI */ - if (rd->remote_vni != vxlan->default_dst.remote_vni) + if (rd->remote_vni != cfg->vni) nlmsg_size += nla_total_size(sizeof(u32)); /* MDBA_MDB_EATTR_IFINDEX */ if (rd->remote_ifindex) nlmsg_size += nla_total_size(sizeof(u32)); /* MDBA_MDB_EATTR_SRC_VNI */ - if ((vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) && group->vni) + if ((cfg->flags & VXLAN_F_COLLECT_METADATA) && group->vni) nlmsg_size += nla_total_size(sizeof(u32)); return nlmsg_size; @@ -1216,7 +1221,7 @@ vxlan_mdb_entry_get(struct vxlan_dev *vxlan, goto err_free_entry; if (hlist_is_singular_node(&mdb_entry->mdb_node, &vxlan->mdb_list)) - vxlan->cfg.flags |= VXLAN_F_MDB; + set_bit(VXLAN_DEV_F_MDB, &vxlan->flags); return mdb_entry; @@ -1233,7 +1238,7 @@ static void vxlan_mdb_entry_put(struct vxlan_dev *vxlan, return; if (hlist_is_singular_node(&mdb_entry->mdb_node, &vxlan->mdb_list)) - vxlan->cfg.flags &= ~VXLAN_F_MDB; + clear_bit(VXLAN_DEV_F_MDB, &vxlan->flags); rhashtable_remove_fast(&vxlan->mdb_tbl, &mdb_entry->rhnode, vxlan_mdb_rht_params); @@ -1483,11 +1488,13 @@ static int vxlan_mdb_get_parse(struct net_device *dev, struct nlattr *tb[], { struct br_mdb_entry *entry = nla_data(tb[MDBA_GET_ENTRY]); struct nlattr *mdbe_attrs[MDBE_ATTR_MAX + 1]; + const struct vxlan_config *cfg; struct vxlan_dev *vxlan = netdev_priv(dev); int err; + cfg = rtnl_dereference(vxlan->cfg); memset(group, 0, sizeof(*group)); - group->vni = vxlan->default_dst.remote_vni; + group->vni = cfg->vni; if (!tb[MDBA_GET_ENTRY_ATTRS]) { vxlan_mdb_group_set(group, entry, NULL); @@ -1621,6 +1628,7 @@ free: } struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, struct sk_buff *skb, __be32 src_vni) { @@ -1634,8 +1642,8 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan, /* When not in collect metadata mode, 'src_vni' is zero, but MDB * entries are stored with the VNI of the VXLAN device. */ - if (!(vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA)) - src_vni = vxlan->default_dst.remote_vni; + if (!(cfg->flags & VXLAN_F_COLLECT_METADATA)) + src_vni = cfg->vni; memset(&group, 0, sizeof(group)); group.vni = src_vni; @@ -1700,6 +1708,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan, } netdev_tx_t vxlan_mdb_xmit(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, const struct vxlan_mdb_entry *mdb_entry, struct sk_buff *skb) { @@ -1721,12 +1730,12 @@ netdev_tx_t vxlan_mdb_xmit(struct vxlan_dev *vxlan, skb1 = skb_clone(skb, GFP_ATOMIC); if (skb1) - vxlan_xmit_one(skb1, vxlan->dev, src_vni, + vxlan_xmit_one(skb1, vxlan->dev, cfg, src_vni, rcu_dereference(remote->rd), false); } if (fremote) - vxlan_xmit_one(skb, vxlan->dev, src_vni, + vxlan_xmit_one(skb, vxlan->dev, cfg, src_vni, rcu_dereference(fremote->rd), false); else kfree_skb_reason(skb, SKB_DROP_REASON_NO_TX_TARGET); @@ -1757,7 +1766,7 @@ void vxlan_mdb_fini(struct vxlan_dev *vxlan) struct vxlan_mdb_flush_desc desc = {}; vxlan_mdb_flush(vxlan, &desc); - WARN_ON_ONCE(vxlan->cfg.flags & VXLAN_F_MDB); + WARN_ON_ONCE(test_bit(VXLAN_DEV_F_MDB, &vxlan->flags)); rhashtable_free_and_destroy(&vxlan->mdb_tbl, vxlan_mdb_check_empty, NULL); } diff --git a/drivers/net/vxlan/vxlan_multicast.c b/drivers/net/vxlan/vxlan_multicast.c index 3b75b48dc726..a5ef6f66f00d 100644 --- a/drivers/net/vxlan/vxlan_multicast.c +++ b/drivers/net/vxlan/vxlan_multicast.c @@ -14,11 +14,12 @@ /* Update multicast group membership when first VNI on * multicast address is brought up */ -int vxlan_igmp_join(struct vxlan_dev *vxlan, union vxlan_addr *rip, +int vxlan_igmp_join(struct vxlan_dev *vxlan, const union vxlan_addr *rip, int rifindex) { - union vxlan_addr *ip = (rip ? : &vxlan->default_dst.remote_ip); - int ifindex = (rifindex ? : vxlan->default_dst.remote_ifindex); + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); + const union vxlan_addr *ip = (rip ? : &cfg->remote_ip); + int ifindex = (rifindex ? : cfg->remote_ifindex); int ret = -EINVAL; struct sock *sk; @@ -47,11 +48,12 @@ int vxlan_igmp_join(struct vxlan_dev *vxlan, union vxlan_addr *rip, return ret; } -int vxlan_igmp_leave(struct vxlan_dev *vxlan, union vxlan_addr *rip, +int vxlan_igmp_leave(struct vxlan_dev *vxlan, const union vxlan_addr *rip, int rifindex) { - union vxlan_addr *ip = (rip ? : &vxlan->default_dst.remote_ip); - int ifindex = (rifindex ? : vxlan->default_dst.remote_ifindex); + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); + const union vxlan_addr *ip = (rip ? : &cfg->remote_ip); + int ifindex = (rifindex ? : cfg->remote_ifindex); int ret = -EINVAL; struct sock *sk; @@ -80,8 +82,8 @@ int vxlan_igmp_leave(struct vxlan_dev *vxlan, union vxlan_addr *rip, return ret; } -static bool vxlan_group_used_match(union vxlan_addr *ip, int ifindex, - union vxlan_addr *rip, int rifindex) +static bool vxlan_group_used_match(const union vxlan_addr *ip, int ifindex, + const union vxlan_addr *rip, int rifindex) { if (!vxlan_addr_multicast(rip)) return false; @@ -96,14 +98,16 @@ static bool vxlan_group_used_match(union vxlan_addr *ip, int ifindex, } static bool vxlan_group_used_by_vnifilter(struct vxlan_dev *vxlan, - union vxlan_addr *ip, int ifindex) + const struct vxlan_config *cfg, + const union vxlan_addr *ip, + int ifindex) { struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp); struct vxlan_vni_node *v, *tmp; if (vxlan_group_used_match(ip, ifindex, - &vxlan->default_dst.remote_ip, - vxlan->default_dst.remote_ifindex)) + &cfg->remote_ip, + cfg->remote_ifindex)) return true; list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) { @@ -112,7 +116,7 @@ static bool vxlan_group_used_by_vnifilter(struct vxlan_dev *vxlan, if (vxlan_group_used_match(ip, ifindex, &v->remote_ip, - vxlan->default_dst.remote_ifindex)) + cfg->remote_ifindex)) return true; } @@ -121,16 +125,17 @@ static bool vxlan_group_used_by_vnifilter(struct vxlan_dev *vxlan, /* See if multicast group is already in use by other ID */ bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev, - __be32 vni, union vxlan_addr *rip, int rifindex) + __be32 vni, const union vxlan_addr *rip, int rifindex) { - union vxlan_addr *ip = (rip ? : &dev->default_dst.remote_ip); - int ifindex = (rifindex ? : dev->default_dst.remote_ifindex); + const struct vxlan_config *dev_cfg = rtnl_dereference(dev->cfg); + const union vxlan_addr *ip = (rip ? : &dev_cfg->remote_ip); + int ifindex = (rifindex ? : dev_cfg->remote_ifindex); struct vxlan_dev *vxlan; struct vxlan_sock *sock4; #if IS_ENABLED(CONFIG_IPV6) struct vxlan_sock *sock6; #endif - unsigned short family = dev->default_dst.remote_ip.sa.sa_family; + unsigned short family = dev_cfg->remote_ip.sa.sa_family; sock4 = rtnl_dereference(dev->vn4_sock); @@ -147,6 +152,8 @@ bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev, #endif list_for_each_entry(vxlan, &vn->vxlan_list, next) { + const struct vxlan_config *cfg; + if (!netif_running(vxlan->dev) || vxlan == dev) continue; @@ -158,13 +165,15 @@ bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev, rtnl_dereference(vxlan->vn6_sock) != sock6) continue; #endif - if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) { - if (!vxlan_group_used_by_vnifilter(vxlan, ip, ifindex)) + cfg = rtnl_dereference(vxlan->cfg); + + if (cfg->flags & VXLAN_F_VNIFILTER) { + if (!vxlan_group_used_by_vnifilter(vxlan, cfg, ip, ifindex)) continue; } else { if (!vxlan_group_used_match(ip, ifindex, - &vxlan->default_dst.remote_ip, - vxlan->default_dst.remote_ifindex)) + &cfg->remote_ip, + cfg->remote_ifindex)) continue; } @@ -174,7 +183,8 @@ bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev, return false; } -static int vxlan_multicast_join_vnigrp(struct vxlan_dev *vxlan) +static int vxlan_multicast_join_vnigrp(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg) { struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp); struct vxlan_vni_node *v, *tmp, *vgood = NULL; @@ -185,7 +195,7 @@ static int vxlan_multicast_join_vnigrp(struct vxlan_dev *vxlan) continue; /* skip if address is same as default address */ if (vxlan_addr_equal(&v->remote_ip, - &vxlan->default_dst.remote_ip)) + &cfg->remote_ip)) continue; ret = vxlan_igmp_join(vxlan, &v->remote_ip, 0); if (ret == -EADDRINUSE) @@ -200,7 +210,7 @@ out: if (!vxlan_addr_multicast(&v->remote_ip)) continue; if (vxlan_addr_equal(&v->remote_ip, - &vxlan->default_dst.remote_ip)) + &cfg->remote_ip)) continue; vxlan_igmp_leave(vxlan, &v->remote_ip, 0); if (v == vgood) @@ -211,7 +221,8 @@ out: return ret; } -static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan) +static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg) { struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp); @@ -219,10 +230,17 @@ static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan) int last_err = 0, ret; list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) { - if (vxlan_addr_multicast(&v->remote_ip) && - !vxlan_group_used(vn, vxlan, v->vni, &v->remote_ip, + if (!vxlan_addr_multicast(&v->remote_ip)) + continue; + /* skip if address is same as default address */ + if (vxlan_addr_equal(&v->remote_ip, + &cfg->remote_ip)) + continue; + if (!vxlan_group_used(vn, vxlan, v->vni, &v->remote_ip, 0)) { ret = vxlan_igmp_leave(vxlan, &v->remote_ip, 0); + if (ret == -EADDRNOTAVAIL) + ret = 0; if (ret) last_err = ret; } @@ -233,38 +251,42 @@ static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan) int vxlan_multicast_join(struct vxlan_dev *vxlan) { + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); int ret = 0; - if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip)) { - ret = vxlan_igmp_join(vxlan, &vxlan->default_dst.remote_ip, - vxlan->default_dst.remote_ifindex); + if (vxlan_addr_multicast(&cfg->remote_ip)) { + ret = vxlan_igmp_join(vxlan, &cfg->remote_ip, + cfg->remote_ifindex); if (ret == -EADDRINUSE) ret = 0; if (ret) return ret; } - if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) - return vxlan_multicast_join_vnigrp(vxlan); + if (cfg->flags & VXLAN_F_VNIFILTER) + return vxlan_multicast_join_vnigrp(vxlan, cfg); return 0; } int vxlan_multicast_leave(struct vxlan_dev *vxlan) { + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); int ret = 0; - if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip) && + if (vxlan_addr_multicast(&cfg->remote_ip) && !vxlan_group_used(vn, vxlan, 0, NULL, 0)) { - ret = vxlan_igmp_leave(vxlan, &vxlan->default_dst.remote_ip, - vxlan->default_dst.remote_ifindex); + ret = vxlan_igmp_leave(vxlan, &cfg->remote_ip, + cfg->remote_ifindex); + if (ret == -EADDRNOTAVAIL) + ret = 0; if (ret) return ret; } - if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) - return vxlan_multicast_leave_vnigrp(vxlan); + if (cfg->flags & VXLAN_F_VNIFILTER) + return vxlan_multicast_leave_vnigrp(vxlan, cfg); return 0; } diff --git a/drivers/net/vxlan/vxlan_private.h b/drivers/net/vxlan/vxlan_private.h index b1eec2216360..f0ee85f83732 100644 --- a/drivers/net/vxlan/vxlan_private.h +++ b/drivers/net/vxlan/vxlan_private.h @@ -22,6 +22,8 @@ struct vxlan_net { /* sock_list is protected by rtnl lock */ struct hlist_head sock_list[PORT_HASH_SIZE]; struct notifier_block nexthop_notifier_block; + /* Generation counter for RTM_GETTUNNEL dumps */ + atomic_t vnifilter_seq; }; struct vxlan_fdb_key { @@ -177,6 +179,13 @@ vxlan_vnifilter_lookup(struct vxlan_dev *vxlan, __be32 vni) vxlan_vni_rht_params); } +static inline void vxlan_vnifilter_seq_inc(const struct net *net) +{ + struct vxlan_net *vn = net_generic(net, vxlan_net_id); + + atomic_inc(&vn->vnifilter_seq); +} + /* vxlan_core.c */ int vxlan_fdb_create(struct vxlan_dev *vxlan, const u8 *mac, union vxlan_addr *ip, @@ -195,9 +204,10 @@ int vxlan_fdb_update(struct vxlan_dev *vxlan, __u32 ifindex, __u16 ndm_flags, u32 nhid, bool swdev_notify, struct netlink_ext_ack *extack); void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + const struct vxlan_config *cfg, __be32 default_vni, struct vxlan_rdst *rdst, bool did_rsc); int vxlan_vni_in_use(struct net *src_net, struct vxlan_dev *vxlan, - struct vxlan_config *conf, __be32 vni); + const struct vxlan_config *conf, __be32 vni); /* vxlan_vnifilter.c */ int vxlan_vnigroup_init(struct vxlan_dev *vxlan); @@ -205,7 +215,8 @@ void vxlan_vnigroup_uninit(struct vxlan_dev *vxlan); int vxlan_vnifilter_init(void); void vxlan_vnifilter_uninit(void); -void vxlan_vnifilter_count(struct vxlan_dev *vxlan, __be32 vni, +void vxlan_vnifilter_count(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, __be32 vni, struct vxlan_vni_node *vninode, int type, unsigned int len); @@ -213,9 +224,16 @@ void vxlan_vs_add_vnigrp(struct vxlan_dev *vxlan, struct vxlan_sock *vs, bool ipv6); void vxlan_vs_del_vnigrp(struct vxlan_dev *vxlan); +bool vxlan_vnifilter_has_multicast(const struct vxlan_dev *vxlan); +int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni, + const union vxlan_addr *old_remote_ip, + const union vxlan_addr *remote_ip, + u32 old_ifindex, u32 new_ifindex, + struct netlink_ext_ack *extack); int vxlan_vnilist_update_group(struct vxlan_dev *vxlan, - union vxlan_addr *old_remote_ip, - union vxlan_addr *new_remote_ip, + const union vxlan_addr *old_remote_ip, + const union vxlan_addr *new_remote_ip, + u32 old_ifindex, u32 new_ifindex, struct netlink_ext_ack *extack); @@ -223,10 +241,10 @@ int vxlan_vnilist_update_group(struct vxlan_dev *vxlan, int vxlan_multicast_join(struct vxlan_dev *vxlan); int vxlan_multicast_leave(struct vxlan_dev *vxlan); bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev, - __be32 vni, union vxlan_addr *rip, int rifindex); -int vxlan_igmp_join(struct vxlan_dev *vxlan, union vxlan_addr *rip, + __be32 vni, const union vxlan_addr *rip, int rifindex); +int vxlan_igmp_join(struct vxlan_dev *vxlan, const union vxlan_addr *rip, int rifindex); -int vxlan_igmp_leave(struct vxlan_dev *vxlan, union vxlan_addr *rip, +int vxlan_igmp_leave(struct vxlan_dev *vxlan, const union vxlan_addr *rip, int rifindex); /* vxlan_mdb.c */ @@ -241,9 +259,11 @@ int vxlan_mdb_del_bulk(struct net_device *dev, struct nlattr *tb[], int vxlan_mdb_get(struct net_device *dev, struct nlattr *tb[], u32 portid, u32 seq, struct netlink_ext_ack *extack); struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, struct sk_buff *skb, __be32 src_vni); netdev_tx_t vxlan_mdb_xmit(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, const struct vxlan_mdb_entry *mdb_entry, struct sk_buff *skb); int vxlan_mdb_init(struct vxlan_dev *vxlan); diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c index dd94085e0886..124ba47758e9 100644 --- a/drivers/net/vxlan/vxlan_vnifilter.c +++ b/drivers/net/vxlan/vxlan_vnifilter.c @@ -171,13 +171,14 @@ static void vxlan_vnifilter_stats_add(struct vxlan_vni_node *vninode, u64_stats_update_end(&pstats->syncp); } -void vxlan_vnifilter_count(struct vxlan_dev *vxlan, __be32 vni, +void vxlan_vnifilter_count(struct vxlan_dev *vxlan, + const struct vxlan_config *cfg, __be32 vni, struct vxlan_vni_node *vninode, int type, unsigned int len) { struct vxlan_vni_node *vnode; - if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER)) + if (!(cfg->flags & VXLAN_F_VNIFILTER)) return; if (vninode) { @@ -333,22 +334,36 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev, struct sk_buff *skb, struct netlink_callback *cb) { - struct vxlan_vni_node *tmp, *v, *vbegin = NULL, *vend = NULL; + struct vxlan_vni_node *v, *vbegin = NULL, *vend = NULL; struct vxlan_dev *vxlan = netdev_priv(dev); struct tunnel_msg *new_tmsg, *tmsg; - int idx = 0, s_idx = cb->args[1]; + const struct vxlan_config *cfg; struct vxlan_vni_group *vg; struct nlmsghdr *nlh; + int idx = 0, s_idx; bool dump_stats; int err = 0; - if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER)) + if (cb->args[2] != dev->ifindex) { + cb->args[1] = 0; + cb->args[2] = dev->ifindex; + } + s_idx = cb->args[1]; + + cfg = rcu_dereference(vxlan->cfg); + if (!(cfg->flags & VXLAN_F_VNIFILTER)) { + cb->args[1] = 0; + cb->args[2] = 0; return -EINVAL; + } /* RCU needed because of the vni locking rules (rcu || rtnl) */ vg = rcu_dereference(vxlan->vnigrp); - if (!vg || !vg->num_vnis) + if (!vg || !vg->num_vnis) { + cb->args[1] = 0; + cb->args[2] = 0; return 0; + } tmsg = nlmsg_data(cb->nlh); dump_stats = !!(tmsg->flags & TUNNEL_MSG_FLAG_STATS); @@ -362,7 +377,7 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev, new_tmsg->family = PF_BRIDGE; new_tmsg->ifindex = dev->ifindex; - list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) { + list_for_each_entry_rcu(v, &vg->vni_list, vlist) { if (idx < s_idx) { idx++; continue; @@ -394,12 +409,26 @@ update_end: } cb->args[1] = err ? idx : 0; + cb->args[2] = err ? dev->ifindex : 0; nlmsg_end(skb, nlh); + nl_dump_check_consistent(cb, nlh); + return err; } +static u32 vxlan_vnifilter_base_seq(const struct net *net) +{ + const struct vxlan_net *vn = net_generic(net, vxlan_net_id); + u32 res = atomic_read(&vn->vnifilter_seq); + + /* Must not return 0 (see nl_dump_check_consistent()) */ + if (!res) + res = 0x80000000; + return res; +} + static int vxlan_vnifilter_dump(struct sk_buff *skb, struct netlink_callback *cb) { int idx = 0, err = 0, s_idx = cb->args[0]; @@ -419,6 +448,9 @@ static int vxlan_vnifilter_dump(struct sk_buff *skb, struct netlink_callback *cb } rcu_read_lock(); + + cb->seq = vxlan_vnifilter_base_seq(net); + if (tmsg->ifindex) { dev = dev_get_by_index_rcu(net, tmsg->ifindex); if (!dev) { @@ -467,29 +499,53 @@ static const struct nla_policy vni_filter_entry_policy[VXLAN_VNIFILTER_ENTRY_MAX }; static const struct nla_policy vni_filter_policy[VXLAN_VNIFILTER_MAX + 1] = { - [VXLAN_VNIFILTER_ENTRY] = { .type = NLA_NESTED }, + [VXLAN_VNIFILTER_ENTRY] = NLA_POLICY_NESTED(vni_filter_entry_policy), }; -static int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni, - union vxlan_addr *old_remote_ip, - union vxlan_addr *remote_ip, - struct netlink_ext_ack *extack) +bool vxlan_vnifilter_has_multicast(const struct vxlan_dev *vxlan) { - struct vxlan_rdst *dst = &vxlan->default_dst; + struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp); + struct vxlan_vni_node *v; + + if (!vg) + return false; + + list_for_each_entry(v, &vg->vni_list, vlist) { + if (vxlan_addr_multicast(&v->remote_ip)) + return true; + } + + return false; +} + +int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni, + const union vxlan_addr *old_remote_ip, + const union vxlan_addr *remote_ip, + u32 old_ifindex, u32 new_ifindex, + struct netlink_ext_ack *extack) +{ + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); int err = 0; + if (old_remote_ip && remote_ip && + vxlan_addr_equal(old_remote_ip, remote_ip) && + old_ifindex == new_ifindex) + return 0; + spin_lock_bh(&vxlan->hash_lock); if (remote_ip && !vxlan_addr_any(remote_ip)) { + union vxlan_addr rip = *remote_ip; + err = vxlan_fdb_update(vxlan, all_zeros_mac, - remote_ip, + &rip, NUD_REACHABLE | NUD_PERMANENT, NLM_F_APPEND | NLM_F_CREATE, - vxlan->cfg.dst_port, + cfg->dst_port, vni, vni, - dst->remote_ifindex, + new_ifindex, NTF_SELF, 0, true, extack); - if (err) { + if (err && extack) { spin_unlock_bh(&vxlan->hash_lock); return err; } @@ -498,9 +554,9 @@ static int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni, if (old_remote_ip && !vxlan_addr_any(old_remote_ip)) { __vxlan_fdb_delete(vxlan, all_zeros_mac, *old_remote_ip, - vxlan->cfg.dst_port, + cfg->dst_port, vni, vni, - dst->remote_ifindex, + old_ifindex, true); } spin_unlock_bh(&vxlan->hash_lock); @@ -515,8 +571,8 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan, struct netlink_ext_ack *extack) { struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); - struct vxlan_rdst *dst = &vxlan->default_dst; - union vxlan_addr *newrip = NULL, *oldrip = NULL; + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); + const union vxlan_addr *newrip = NULL, *oldrip = NULL; union vxlan_addr old_remote_ip; int ret = 0; @@ -528,15 +584,16 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan, if (group && !vxlan_addr_any(group)) { newrip = group; } else { - if (!vxlan_addr_any(&dst->remote_ip)) - newrip = &dst->remote_ip; + if (!vxlan_addr_any(&cfg->remote_ip)) + newrip = &cfg->remote_ip; } - /* if old rip exists, and no newrip, - * explicitly delete old rip - */ - if (!newrip && !vxlan_addr_any(&old_remote_ip)) - oldrip = &old_remote_ip; + if (!create) { + if (!vxlan_addr_any(&old_remote_ip)) + oldrip = &old_remote_ip; + else if (!vxlan_addr_any(&cfg->remote_ip)) + oldrip = &cfg->remote_ip; + } if (!newrip && !oldrip) return 0; @@ -546,20 +603,27 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan, ret = vxlan_update_default_fdb_entry(vxlan, vninode->vni, oldrip, newrip, + cfg->remote_ifindex, + cfg->remote_ifindex, extack); if (ret) goto out; - if (group) + if (group) { memcpy(&vninode->remote_ip, group, sizeof(vninode->remote_ip)); + if (!create) + vxlan_vnifilter_seq_inc(dev_net(vxlan->dev)); + } if (vxlan->dev->flags & IFF_UP) { if (vxlan_addr_multicast(&old_remote_ip) && !vxlan_group_used(vn, vxlan, vninode->vni, &old_remote_ip, - vxlan->default_dst.remote_ifindex)) { + cfg->remote_ifindex)) { ret = vxlan_igmp_leave(vxlan, &old_remote_ip, 0); + if (ret == -EADDRNOTAVAIL) + ret = 0; if (ret) goto out; } @@ -581,10 +645,12 @@ out: } int vxlan_vnilist_update_group(struct vxlan_dev *vxlan, - union vxlan_addr *old_remote_ip, - union vxlan_addr *new_remote_ip, + const union vxlan_addr *old_remote_ip, + const union vxlan_addr *new_remote_ip, + u32 old_ifindex, u32 new_ifindex, struct netlink_ext_ack *extack) { + const union vxlan_addr *oldrip, *newrip; struct list_head *headp, *hpos; struct vxlan_vni_group *vg; struct vxlan_vni_node *vent; @@ -595,37 +661,66 @@ int vxlan_vnilist_update_group(struct vxlan_dev *vxlan, headp = &vg->vni_list; list_for_each_prev(hpos, headp) { vent = list_entry(hpos, struct vxlan_vni_node, vlist); + if (vxlan_addr_any(&vent->remote_ip)) { - ret = vxlan_update_default_fdb_entry(vxlan, vent->vni, - old_remote_ip, - new_remote_ip, - extack); - if (ret) - return ret; + oldrip = old_remote_ip; + newrip = new_remote_ip; + } else { + /* A vni with its own group keeps it, but its fdb entry + * is still keyed on the device remote_ifindex. + */ + oldrip = &vent->remote_ip; + newrip = &vent->remote_ip; } + + ret = vxlan_update_default_fdb_entry(vxlan, vent->vni, + oldrip, newrip, + old_ifindex, new_ifindex, + extack); + if (ret) + goto err_unwind; } return 0; + +err_unwind: + list_for_each_continue(hpos, headp) { + vent = list_entry(hpos, struct vxlan_vni_node, vlist); + + if (vxlan_addr_any(&vent->remote_ip)) { + oldrip = old_remote_ip; + newrip = new_remote_ip; + } else { + oldrip = &vent->remote_ip; + newrip = &vent->remote_ip; + } + + vxlan_update_default_fdb_entry(vxlan, vent->vni, + newrip, oldrip, + new_ifindex, old_ifindex, + NULL); + } + return ret; } static void vxlan_vni_delete_group(struct vxlan_dev *vxlan, struct vxlan_vni_node *vninode) { struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); - struct vxlan_rdst *dst = &vxlan->default_dst; + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); /* if per vni remote_ip not present, delete the * default dst remote_ip previously added for this vni */ if (!vxlan_addr_any(&vninode->remote_ip) || - !vxlan_addr_any(&dst->remote_ip)) { + !vxlan_addr_any(&cfg->remote_ip)) { spin_lock_bh(&vxlan->hash_lock); __vxlan_fdb_delete(vxlan, all_zeros_mac, (vxlan_addr_any(&vninode->remote_ip) ? - dst->remote_ip : vninode->remote_ip), - vxlan->cfg.dst_port, + cfg->remote_ip : vninode->remote_ip), + cfg->dst_port, vninode->vni, vninode->vni, - dst->remote_ifindex, + cfg->remote_ifindex, true); spin_unlock_bh(&vxlan->hash_lock); } @@ -634,7 +729,7 @@ static void vxlan_vni_delete_group(struct vxlan_dev *vxlan, if (vxlan_addr_multicast(&vninode->remote_ip) && !vxlan_group_used(vn, vxlan, vninode->vni, &vninode->remote_ip, - dst->remote_ifindex)) { + cfg->remote_ifindex)) { vxlan_igmp_leave(vxlan, &vninode->remote_ip, 0); } } @@ -665,7 +760,8 @@ static int vxlan_vni_update(struct vxlan_dev *vxlan, return 0; } -static void __vxlan_vni_add_list(struct vxlan_vni_group *vg, +static void __vxlan_vni_add_list(struct vxlan_dev *vxlan, + struct vxlan_vni_group *vg, struct vxlan_vni_node *v) { struct list_head *headp, *hpos; @@ -681,13 +777,16 @@ static void __vxlan_vni_add_list(struct vxlan_vni_group *vg, } list_add_rcu(&v->vlist, hpos); vg->num_vnis++; + vxlan_vnifilter_seq_inc(dev_net(vxlan->dev)); } -static void __vxlan_vni_del_list(struct vxlan_vni_group *vg, +static void __vxlan_vni_del_list(struct vxlan_dev *vxlan, + struct vxlan_vni_group *vg, struct vxlan_vni_node *v) { list_del_rcu(&v->vlist); vg->num_vnis--; + vxlan_vnifilter_seq_inc(dev_net(vxlan->dev)); } static struct vxlan_vni_node *vxlan_vni_alloc(struct vxlan_dev *vxlan, @@ -723,6 +822,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, u32 vni, union vxlan_addr *group, struct netlink_ext_ack *extack) { + const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg); struct vxlan_vni_node *vninode; __be32 v = cpu_to_be32(vni); bool changed = false; @@ -731,7 +831,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, if (vxlan_vnifilter_lookup(vxlan, v)) return vxlan_vni_update(vxlan, vg, v, group, &changed, extack); - err = vxlan_vni_in_use(vxlan->net, vxlan, &vxlan->cfg, v); + err = vxlan_vni_in_use(vxlan->net, vxlan, cfg, v); if (err) { NL_SET_ERR_MSG(extack, "VNI in use"); return err; @@ -749,7 +849,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, return err; } - __vxlan_vni_add_list(vg, vninode); + __vxlan_vni_add_list(vxlan, vg, vninode); if (vxlan->dev->flags & IFF_UP) vxlan_vs_add_del_vninode(vxlan, vninode, false); @@ -795,7 +895,7 @@ static int vxlan_vni_del(struct vxlan_dev *vxlan, if (err) goto out; - __vxlan_vni_del_list(vg, vninode); + __vxlan_vni_del_list(vxlan, vg, vninode); vxlan_vnifilter_notify(vxlan, vninode, RTM_DELTUNNEL); @@ -844,6 +944,7 @@ static int vxlan_process_vni_filter(struct vxlan_dev *vxlan, int cmd, struct netlink_ext_ack *extack) { struct nlattr *vattrs[VXLAN_VNIFILTER_ENTRY_MAX + 1]; + const struct vxlan_config *cfg; u32 vni_start = 0, vni_end = 0; union vxlan_addr group; int err; @@ -881,7 +982,8 @@ static int vxlan_process_vni_filter(struct vxlan_dev *vxlan, memset(&group, 0, sizeof(group)); } - if (vxlan_addr_multicast(&group) && !vxlan->default_dst.remote_ifindex) { + cfg = rtnl_dereference(vxlan->cfg); + if (vxlan_addr_multicast(&group) && !cfg->remote_ifindex) { NL_SET_ERR_MSG(extack, "Local interface required for multicast remote group"); @@ -909,7 +1011,7 @@ void vxlan_vnigroup_uninit(struct vxlan_dev *vxlan) #if IS_ENABLED(CONFIG_IPV6) hlist_del_init_rcu(&v->hlist6.hlist); #endif - __vxlan_vni_del_list(vg, v); + __vxlan_vni_del_list(vxlan, vg, v); vxlan_vnifilter_notify(vxlan, v, RTM_DELTUNNEL); call_rcu(&v->rcu, vxlan_vni_node_rcu_free); } @@ -940,6 +1042,7 @@ static int vxlan_vnifilter_process(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { struct net *net = sock_net(skb->sk); + const struct vxlan_config *cfg; struct tunnel_msg *tmsg; struct vxlan_dev *vxlan; struct net_device *dev; @@ -964,8 +1067,9 @@ static int vxlan_vnifilter_process(struct sk_buff *skb, struct nlmsghdr *nlh, } vxlan = netdev_priv(dev); + cfg = rtnl_dereference(vxlan->cfg); - if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER)) + if (!(cfg->flags & VXLAN_F_VNIFILTER)) return -EOPNOTSUPP; nlmsg_for_each_attr_type(attr, VXLAN_VNIFILTER_ENTRY, nlh, |
