1f9c4bb0bSRoopa Prabhu // SPDX-License-Identifier: GPL-2.0-only
2f9c4bb0bSRoopa Prabhu /*
3f9c4bb0bSRoopa Prabhu  *	Vxlan vni filter for collect metadata mode
4f9c4bb0bSRoopa Prabhu  *
5f9c4bb0bSRoopa Prabhu  *	Authors: Roopa Prabhu <roopa@nvidia.com>
6f9c4bb0bSRoopa Prabhu  *
7f9c4bb0bSRoopa Prabhu  */
8f9c4bb0bSRoopa Prabhu 
9f9c4bb0bSRoopa Prabhu #include <linux/kernel.h>
10f9c4bb0bSRoopa Prabhu #include <linux/slab.h>
11f9c4bb0bSRoopa Prabhu #include <linux/etherdevice.h>
12f9c4bb0bSRoopa Prabhu #include <linux/rhashtable.h>
13f9c4bb0bSRoopa Prabhu #include <net/rtnetlink.h>
14f9c4bb0bSRoopa Prabhu #include <net/net_namespace.h>
15f9c4bb0bSRoopa Prabhu #include <net/sock.h>
16f9c4bb0bSRoopa Prabhu #include <net/vxlan.h>
17f9c4bb0bSRoopa Prabhu 
18f9c4bb0bSRoopa Prabhu #include "vxlan_private.h"
19f9c4bb0bSRoopa Prabhu 
vxlan_vni_cmp(struct rhashtable_compare_arg * arg,const void * ptr)20f9c4bb0bSRoopa Prabhu static inline int vxlan_vni_cmp(struct rhashtable_compare_arg *arg,
21f9c4bb0bSRoopa Prabhu 				const void *ptr)
22f9c4bb0bSRoopa Prabhu {
23f9c4bb0bSRoopa Prabhu 	const struct vxlan_vni_node *vnode = ptr;
24f9c4bb0bSRoopa Prabhu 	__be32 vni = *(__be32 *)arg->key;
25f9c4bb0bSRoopa Prabhu 
26f9c4bb0bSRoopa Prabhu 	return vnode->vni != vni;
27f9c4bb0bSRoopa Prabhu }
28f9c4bb0bSRoopa Prabhu 
29f9c4bb0bSRoopa Prabhu const struct rhashtable_params vxlan_vni_rht_params = {
30f9c4bb0bSRoopa Prabhu 	.head_offset = offsetof(struct vxlan_vni_node, vnode),
31f9c4bb0bSRoopa Prabhu 	.key_offset = offsetof(struct vxlan_vni_node, vni),
32f9c4bb0bSRoopa Prabhu 	.key_len = sizeof(__be32),
33f9c4bb0bSRoopa Prabhu 	.nelem_hint = 3,
34f9c4bb0bSRoopa Prabhu 	.max_size = VXLAN_N_VID,
35f9c4bb0bSRoopa Prabhu 	.obj_cmpfn = vxlan_vni_cmp,
36f9c4bb0bSRoopa Prabhu 	.automatic_shrinking = true,
37f9c4bb0bSRoopa Prabhu };
38f9c4bb0bSRoopa Prabhu 
vxlan_vs_add_del_vninode(struct vxlan_dev * vxlan,struct vxlan_vni_node * v,bool del)39f9c4bb0bSRoopa Prabhu static void vxlan_vs_add_del_vninode(struct vxlan_dev *vxlan,
40f9c4bb0bSRoopa Prabhu 				     struct vxlan_vni_node *v,
41f9c4bb0bSRoopa Prabhu 				     bool del)
42f9c4bb0bSRoopa Prabhu {
43f9c4bb0bSRoopa Prabhu 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
44f9c4bb0bSRoopa Prabhu 	struct vxlan_dev_node *node;
45f9c4bb0bSRoopa Prabhu 	struct vxlan_sock *vs;
46f9c4bb0bSRoopa Prabhu 
47f9c4bb0bSRoopa Prabhu 	spin_lock(&vn->sock_lock);
48f9c4bb0bSRoopa Prabhu 	if (del) {
49f9c4bb0bSRoopa Prabhu 		if (!hlist_unhashed(&v->hlist4.hlist))
50f9c4bb0bSRoopa Prabhu 			hlist_del_init_rcu(&v->hlist4.hlist);
51f9c4bb0bSRoopa Prabhu #if IS_ENABLED(CONFIG_IPV6)
52f9c4bb0bSRoopa Prabhu 		if (!hlist_unhashed(&v->hlist6.hlist))
53f9c4bb0bSRoopa Prabhu 			hlist_del_init_rcu(&v->hlist6.hlist);
54f9c4bb0bSRoopa Prabhu #endif
55f9c4bb0bSRoopa Prabhu 		goto out;
56f9c4bb0bSRoopa Prabhu 	}
57f9c4bb0bSRoopa Prabhu 
58f9c4bb0bSRoopa Prabhu #if IS_ENABLED(CONFIG_IPV6)
59f9c4bb0bSRoopa Prabhu 	vs = rtnl_dereference(vxlan->vn6_sock);
60f9c4bb0bSRoopa Prabhu 	if (vs && v) {
61f9c4bb0bSRoopa Prabhu 		node = &v->hlist6;
62f9c4bb0bSRoopa Prabhu 		hlist_add_head_rcu(&node->hlist, vni_head(vs, v->vni));
63f9c4bb0bSRoopa Prabhu 	}
64f9c4bb0bSRoopa Prabhu #endif
65f9c4bb0bSRoopa Prabhu 	vs = rtnl_dereference(vxlan->vn4_sock);
66f9c4bb0bSRoopa Prabhu 	if (vs && v) {
67f9c4bb0bSRoopa Prabhu 		node = &v->hlist4;
68f9c4bb0bSRoopa Prabhu 		hlist_add_head_rcu(&node->hlist, vni_head(vs, v->vni));
69f9c4bb0bSRoopa Prabhu 	}
70f9c4bb0bSRoopa Prabhu out:
71f9c4bb0bSRoopa Prabhu 	spin_unlock(&vn->sock_lock);
72f9c4bb0bSRoopa Prabhu }
73f9c4bb0bSRoopa Prabhu 
vxlan_vs_add_vnigrp(struct vxlan_dev * vxlan,struct vxlan_sock * vs,bool ipv6)74f9c4bb0bSRoopa Prabhu void vxlan_vs_add_vnigrp(struct vxlan_dev *vxlan,
75f9c4bb0bSRoopa Prabhu 			 struct vxlan_sock *vs,
76f9c4bb0bSRoopa Prabhu 			 bool ipv6)
77f9c4bb0bSRoopa Prabhu {
78f9c4bb0bSRoopa Prabhu 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
79f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp);
80f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *v, *tmp;
81f9c4bb0bSRoopa Prabhu 	struct vxlan_dev_node *node;
82f9c4bb0bSRoopa Prabhu 
83f9c4bb0bSRoopa Prabhu 	if (!vg)
84f9c4bb0bSRoopa Prabhu 		return;
85f9c4bb0bSRoopa Prabhu 
86f9c4bb0bSRoopa Prabhu 	spin_lock(&vn->sock_lock);
87f9c4bb0bSRoopa Prabhu 	list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
88f9c4bb0bSRoopa Prabhu #if IS_ENABLED(CONFIG_IPV6)
89f9c4bb0bSRoopa Prabhu 		if (ipv6)
90f9c4bb0bSRoopa Prabhu 			node = &v->hlist6;
91f9c4bb0bSRoopa Prabhu 		else
92f9c4bb0bSRoopa Prabhu #endif
93f9c4bb0bSRoopa Prabhu 			node = &v->hlist4;
94f9c4bb0bSRoopa Prabhu 		node->vxlan = vxlan;
95f9c4bb0bSRoopa Prabhu 		hlist_add_head_rcu(&node->hlist, vni_head(vs, v->vni));
96f9c4bb0bSRoopa Prabhu 	}
97f9c4bb0bSRoopa Prabhu 	spin_unlock(&vn->sock_lock);
98f9c4bb0bSRoopa Prabhu }
99f9c4bb0bSRoopa Prabhu 
vxlan_vs_del_vnigrp(struct vxlan_dev * vxlan)100f9c4bb0bSRoopa Prabhu void vxlan_vs_del_vnigrp(struct vxlan_dev *vxlan)
101f9c4bb0bSRoopa Prabhu {
102f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp);
103f9c4bb0bSRoopa Prabhu 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
104f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *v, *tmp;
105f9c4bb0bSRoopa Prabhu 
106f9c4bb0bSRoopa Prabhu 	if (!vg)
107f9c4bb0bSRoopa Prabhu 		return;
108f9c4bb0bSRoopa Prabhu 
109f9c4bb0bSRoopa Prabhu 	spin_lock(&vn->sock_lock);
110f9c4bb0bSRoopa Prabhu 	list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
111f9c4bb0bSRoopa Prabhu 		hlist_del_init_rcu(&v->hlist4.hlist);
112f9c4bb0bSRoopa Prabhu #if IS_ENABLED(CONFIG_IPV6)
113f9c4bb0bSRoopa Prabhu 		hlist_del_init_rcu(&v->hlist6.hlist);
114f9c4bb0bSRoopa Prabhu #endif
115f9c4bb0bSRoopa Prabhu 	}
116f9c4bb0bSRoopa Prabhu 	spin_unlock(&vn->sock_lock);
117f9c4bb0bSRoopa Prabhu }
118f9c4bb0bSRoopa Prabhu 
vxlan_vnifilter_stats_get(const struct vxlan_vni_node * vninode,struct vxlan_vni_stats * dest)119445b2f36SNikolay Aleksandrov static void vxlan_vnifilter_stats_get(const struct vxlan_vni_node *vninode,
120445b2f36SNikolay Aleksandrov 				      struct vxlan_vni_stats *dest)
121445b2f36SNikolay Aleksandrov {
122445b2f36SNikolay Aleksandrov 	int i;
123445b2f36SNikolay Aleksandrov 
124445b2f36SNikolay Aleksandrov 	memset(dest, 0, sizeof(*dest));
125445b2f36SNikolay Aleksandrov 	for_each_possible_cpu(i) {
126445b2f36SNikolay Aleksandrov 		struct vxlan_vni_stats_pcpu *pstats;
127445b2f36SNikolay Aleksandrov 		struct vxlan_vni_stats temp;
128445b2f36SNikolay Aleksandrov 		unsigned int start;
129445b2f36SNikolay Aleksandrov 
130445b2f36SNikolay Aleksandrov 		pstats = per_cpu_ptr(vninode->stats, i);
131445b2f36SNikolay Aleksandrov 		do {
132068c38adSThomas Gleixner 			start = u64_stats_fetch_begin(&pstats->syncp);
133445b2f36SNikolay Aleksandrov 			memcpy(&temp, &pstats->stats, sizeof(temp));
134068c38adSThomas Gleixner 		} while (u64_stats_fetch_retry(&pstats->syncp, start));
135445b2f36SNikolay Aleksandrov 
136445b2f36SNikolay Aleksandrov 		dest->rx_packets += temp.rx_packets;
137445b2f36SNikolay Aleksandrov 		dest->rx_bytes += temp.rx_bytes;
138445b2f36SNikolay Aleksandrov 		dest->rx_drops += temp.rx_drops;
139445b2f36SNikolay Aleksandrov 		dest->rx_errors += temp.rx_errors;
140445b2f36SNikolay Aleksandrov 		dest->tx_packets += temp.tx_packets;
141445b2f36SNikolay Aleksandrov 		dest->tx_bytes += temp.tx_bytes;
142445b2f36SNikolay Aleksandrov 		dest->tx_drops += temp.tx_drops;
143445b2f36SNikolay Aleksandrov 		dest->tx_errors += temp.tx_errors;
144445b2f36SNikolay Aleksandrov 	}
145445b2f36SNikolay Aleksandrov }
146445b2f36SNikolay Aleksandrov 
vxlan_vnifilter_stats_add(struct vxlan_vni_node * vninode,int type,unsigned int len)1474095e0e1SNikolay Aleksandrov static void vxlan_vnifilter_stats_add(struct vxlan_vni_node *vninode,
1484095e0e1SNikolay Aleksandrov 				      int type, unsigned int len)
1494095e0e1SNikolay Aleksandrov {
1504095e0e1SNikolay Aleksandrov 	struct vxlan_vni_stats_pcpu *pstats = this_cpu_ptr(vninode->stats);
1514095e0e1SNikolay Aleksandrov 
1524095e0e1SNikolay Aleksandrov 	u64_stats_update_begin(&pstats->syncp);
1534095e0e1SNikolay Aleksandrov 	switch (type) {
1544095e0e1SNikolay Aleksandrov 	case VXLAN_VNI_STATS_RX:
1554095e0e1SNikolay Aleksandrov 		pstats->stats.rx_bytes += len;
1564095e0e1SNikolay Aleksandrov 		pstats->stats.rx_packets++;
1574095e0e1SNikolay Aleksandrov 		break;
1584095e0e1SNikolay Aleksandrov 	case VXLAN_VNI_STATS_RX_DROPS:
1594095e0e1SNikolay Aleksandrov 		pstats->stats.rx_drops++;
1604095e0e1SNikolay Aleksandrov 		break;
1614095e0e1SNikolay Aleksandrov 	case VXLAN_VNI_STATS_RX_ERRORS:
1624095e0e1SNikolay Aleksandrov 		pstats->stats.rx_errors++;
1634095e0e1SNikolay Aleksandrov 		break;
1644095e0e1SNikolay Aleksandrov 	case VXLAN_VNI_STATS_TX:
1654095e0e1SNikolay Aleksandrov 		pstats->stats.tx_bytes += len;
1664095e0e1SNikolay Aleksandrov 		pstats->stats.tx_packets++;
1674095e0e1SNikolay Aleksandrov 		break;
1684095e0e1SNikolay Aleksandrov 	case VXLAN_VNI_STATS_TX_DROPS:
1694095e0e1SNikolay Aleksandrov 		pstats->stats.tx_drops++;
1704095e0e1SNikolay Aleksandrov 		break;
1714095e0e1SNikolay Aleksandrov 	case VXLAN_VNI_STATS_TX_ERRORS:
1724095e0e1SNikolay Aleksandrov 		pstats->stats.tx_errors++;
1734095e0e1SNikolay Aleksandrov 		break;
1744095e0e1SNikolay Aleksandrov 	}
1754095e0e1SNikolay Aleksandrov 	u64_stats_update_end(&pstats->syncp);
1764095e0e1SNikolay Aleksandrov }
1774095e0e1SNikolay Aleksandrov 
vxlan_vnifilter_count(struct vxlan_dev * vxlan,__be32 vni,struct vxlan_vni_node * vninode,int type,unsigned int len)1784095e0e1SNikolay Aleksandrov void vxlan_vnifilter_count(struct vxlan_dev *vxlan, __be32 vni,
1794095e0e1SNikolay Aleksandrov 			   struct vxlan_vni_node *vninode,
1804095e0e1SNikolay Aleksandrov 			   int type, unsigned int len)
1814095e0e1SNikolay Aleksandrov {
1824095e0e1SNikolay Aleksandrov 	struct vxlan_vni_node *vnode;
1834095e0e1SNikolay Aleksandrov 
1844095e0e1SNikolay Aleksandrov 	if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER))
1854095e0e1SNikolay Aleksandrov 		return;
1864095e0e1SNikolay Aleksandrov 
1874095e0e1SNikolay Aleksandrov 	if (vninode) {
1884095e0e1SNikolay Aleksandrov 		vnode = vninode;
1894095e0e1SNikolay Aleksandrov 	} else {
1904095e0e1SNikolay Aleksandrov 		vnode = vxlan_vnifilter_lookup(vxlan, vni);
1914095e0e1SNikolay Aleksandrov 		if (!vnode)
1924095e0e1SNikolay Aleksandrov 			return;
1934095e0e1SNikolay Aleksandrov 	}
1944095e0e1SNikolay Aleksandrov 
1954095e0e1SNikolay Aleksandrov 	vxlan_vnifilter_stats_add(vnode, type, len);
1964095e0e1SNikolay Aleksandrov }
1974095e0e1SNikolay Aleksandrov 
vnirange(struct vxlan_vni_node * vbegin,struct vxlan_vni_node * vend)198f9c4bb0bSRoopa Prabhu static u32 vnirange(struct vxlan_vni_node *vbegin,
199f9c4bb0bSRoopa Prabhu 		    struct vxlan_vni_node *vend)
200f9c4bb0bSRoopa Prabhu {
201f9c4bb0bSRoopa Prabhu 	return (be32_to_cpu(vend->vni) - be32_to_cpu(vbegin->vni));
202f9c4bb0bSRoopa Prabhu }
203f9c4bb0bSRoopa Prabhu 
vxlan_vnifilter_entry_nlmsg_size(void)204f9c4bb0bSRoopa Prabhu static size_t vxlan_vnifilter_entry_nlmsg_size(void)
205f9c4bb0bSRoopa Prabhu {
206f9c4bb0bSRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct tunnel_msg))
207f9c4bb0bSRoopa Prabhu 		+ nla_total_size(0) /* VXLAN_VNIFILTER_ENTRY */
208f9c4bb0bSRoopa Prabhu 		+ nla_total_size(sizeof(u32)) /* VXLAN_VNIFILTER_ENTRY_START */
209f9c4bb0bSRoopa Prabhu 		+ nla_total_size(sizeof(u32)) /* VXLAN_VNIFILTER_ENTRY_END */
210f9c4bb0bSRoopa Prabhu 		+ nla_total_size(sizeof(struct in6_addr));/* VXLAN_VNIFILTER_ENTRY_GROUP{6} */
211f9c4bb0bSRoopa Prabhu }
212f9c4bb0bSRoopa Prabhu 
__vnifilter_entry_fill_stats(struct sk_buff * skb,const struct vxlan_vni_node * vbegin)213445b2f36SNikolay Aleksandrov static int __vnifilter_entry_fill_stats(struct sk_buff *skb,
214445b2f36SNikolay Aleksandrov 					const struct vxlan_vni_node *vbegin)
215445b2f36SNikolay Aleksandrov {
216445b2f36SNikolay Aleksandrov 	struct vxlan_vni_stats vstats;
217445b2f36SNikolay Aleksandrov 	struct nlattr *vstats_attr;
218445b2f36SNikolay Aleksandrov 
219445b2f36SNikolay Aleksandrov 	vstats_attr = nla_nest_start(skb, VXLAN_VNIFILTER_ENTRY_STATS);
220445b2f36SNikolay Aleksandrov 	if (!vstats_attr)
221445b2f36SNikolay Aleksandrov 		goto out_stats_err;
222445b2f36SNikolay Aleksandrov 
223445b2f36SNikolay Aleksandrov 	vxlan_vnifilter_stats_get(vbegin, &vstats);
224445b2f36SNikolay Aleksandrov 	if (nla_put_u64_64bit(skb, VNIFILTER_ENTRY_STATS_RX_BYTES,
225445b2f36SNikolay Aleksandrov 			      vstats.rx_bytes, VNIFILTER_ENTRY_STATS_PAD) ||
226445b2f36SNikolay Aleksandrov 	    nla_put_u64_64bit(skb, VNIFILTER_ENTRY_STATS_RX_PKTS,
227445b2f36SNikolay Aleksandrov 			      vstats.rx_packets, VNIFILTER_ENTRY_STATS_PAD) ||
228445b2f36SNikolay Aleksandrov 	    nla_put_u64_64bit(skb, VNIFILTER_ENTRY_STATS_RX_DROPS,
229445b2f36SNikolay Aleksandrov 			      vstats.rx_drops, VNIFILTER_ENTRY_STATS_PAD) ||
230445b2f36SNikolay Aleksandrov 	    nla_put_u64_64bit(skb, VNIFILTER_ENTRY_STATS_RX_ERRORS,
231445b2f36SNikolay Aleksandrov 			      vstats.rx_errors, VNIFILTER_ENTRY_STATS_PAD) ||
232445b2f36SNikolay Aleksandrov 	    nla_put_u64_64bit(skb, VNIFILTER_ENTRY_STATS_TX_BYTES,
233445b2f36SNikolay Aleksandrov 			      vstats.tx_bytes, VNIFILTER_ENTRY_STATS_PAD) ||
234445b2f36SNikolay Aleksandrov 	    nla_put_u64_64bit(skb, VNIFILTER_ENTRY_STATS_TX_PKTS,
235445b2f36SNikolay Aleksandrov 			      vstats.tx_packets, VNIFILTER_ENTRY_STATS_PAD) ||
236445b2f36SNikolay Aleksandrov 	    nla_put_u64_64bit(skb, VNIFILTER_ENTRY_STATS_TX_DROPS,
237445b2f36SNikolay Aleksandrov 			      vstats.tx_drops, VNIFILTER_ENTRY_STATS_PAD) ||
238445b2f36SNikolay Aleksandrov 	    nla_put_u64_64bit(skb, VNIFILTER_ENTRY_STATS_TX_ERRORS,
239445b2f36SNikolay Aleksandrov 			      vstats.tx_errors, VNIFILTER_ENTRY_STATS_PAD))
240445b2f36SNikolay Aleksandrov 		goto out_stats_err;
241445b2f36SNikolay Aleksandrov 
242445b2f36SNikolay Aleksandrov 	nla_nest_end(skb, vstats_attr);
243445b2f36SNikolay Aleksandrov 
244445b2f36SNikolay Aleksandrov 	return 0;
245445b2f36SNikolay Aleksandrov 
246445b2f36SNikolay Aleksandrov out_stats_err:
247445b2f36SNikolay Aleksandrov 	nla_nest_cancel(skb, vstats_attr);
248445b2f36SNikolay Aleksandrov 	return -EMSGSIZE;
249445b2f36SNikolay Aleksandrov }
250445b2f36SNikolay Aleksandrov 
vxlan_fill_vni_filter_entry(struct sk_buff * skb,struct vxlan_vni_node * vbegin,struct vxlan_vni_node * vend,bool fill_stats)251f9c4bb0bSRoopa Prabhu static bool vxlan_fill_vni_filter_entry(struct sk_buff *skb,
252f9c4bb0bSRoopa Prabhu 					struct vxlan_vni_node *vbegin,
253445b2f36SNikolay Aleksandrov 					struct vxlan_vni_node *vend,
254445b2f36SNikolay Aleksandrov 					bool fill_stats)
255f9c4bb0bSRoopa Prabhu {
256f9c4bb0bSRoopa Prabhu 	struct nlattr *ventry;
257f9c4bb0bSRoopa Prabhu 	u32 vs = be32_to_cpu(vbegin->vni);
258f9c4bb0bSRoopa Prabhu 	u32 ve = 0;
259f9c4bb0bSRoopa Prabhu 
260f9c4bb0bSRoopa Prabhu 	if (vbegin != vend)
261f9c4bb0bSRoopa Prabhu 		ve = be32_to_cpu(vend->vni);
262f9c4bb0bSRoopa Prabhu 
263f9c4bb0bSRoopa Prabhu 	ventry = nla_nest_start(skb, VXLAN_VNIFILTER_ENTRY);
264f9c4bb0bSRoopa Prabhu 	if (!ventry)
265f9c4bb0bSRoopa Prabhu 		return false;
266f9c4bb0bSRoopa Prabhu 
267f9c4bb0bSRoopa Prabhu 	if (nla_put_u32(skb, VXLAN_VNIFILTER_ENTRY_START, vs))
268f9c4bb0bSRoopa Prabhu 		goto out_err;
269f9c4bb0bSRoopa Prabhu 
270f9c4bb0bSRoopa Prabhu 	if (ve && nla_put_u32(skb, VXLAN_VNIFILTER_ENTRY_END, ve))
271f9c4bb0bSRoopa Prabhu 		goto out_err;
272f9c4bb0bSRoopa Prabhu 
273f9c4bb0bSRoopa Prabhu 	if (!vxlan_addr_any(&vbegin->remote_ip)) {
274f9c4bb0bSRoopa Prabhu 		if (vbegin->remote_ip.sa.sa_family == AF_INET) {
275f9c4bb0bSRoopa Prabhu 			if (nla_put_in_addr(skb, VXLAN_VNIFILTER_ENTRY_GROUP,
276f9c4bb0bSRoopa Prabhu 					    vbegin->remote_ip.sin.sin_addr.s_addr))
277f9c4bb0bSRoopa Prabhu 				goto out_err;
278f9c4bb0bSRoopa Prabhu #if IS_ENABLED(CONFIG_IPV6)
279f9c4bb0bSRoopa Prabhu 		} else {
280f9c4bb0bSRoopa Prabhu 			if (nla_put_in6_addr(skb, VXLAN_VNIFILTER_ENTRY_GROUP6,
281f9c4bb0bSRoopa Prabhu 					     &vbegin->remote_ip.sin6.sin6_addr))
282f9c4bb0bSRoopa Prabhu 				goto out_err;
283f9c4bb0bSRoopa Prabhu #endif
284f9c4bb0bSRoopa Prabhu 		}
285f9c4bb0bSRoopa Prabhu 	}
286f9c4bb0bSRoopa Prabhu 
287445b2f36SNikolay Aleksandrov 	if (fill_stats && __vnifilter_entry_fill_stats(skb, vbegin))
288445b2f36SNikolay Aleksandrov 		goto out_err;
289445b2f36SNikolay Aleksandrov 
290f9c4bb0bSRoopa Prabhu 	nla_nest_end(skb, ventry);
291f9c4bb0bSRoopa Prabhu 
292f9c4bb0bSRoopa Prabhu 	return true;
293f9c4bb0bSRoopa Prabhu 
294f9c4bb0bSRoopa Prabhu out_err:
295f9c4bb0bSRoopa Prabhu 	nla_nest_cancel(skb, ventry);
296f9c4bb0bSRoopa Prabhu 
297f9c4bb0bSRoopa Prabhu 	return false;
298f9c4bb0bSRoopa Prabhu }
299f9c4bb0bSRoopa Prabhu 
vxlan_vnifilter_notify(const struct vxlan_dev * vxlan,struct vxlan_vni_node * vninode,int cmd)300f9c4bb0bSRoopa Prabhu static void vxlan_vnifilter_notify(const struct vxlan_dev *vxlan,
301f9c4bb0bSRoopa Prabhu 				   struct vxlan_vni_node *vninode, int cmd)
302f9c4bb0bSRoopa Prabhu {
303f9c4bb0bSRoopa Prabhu 	struct tunnel_msg *tmsg;
304f9c4bb0bSRoopa Prabhu 	struct sk_buff *skb;
305f9c4bb0bSRoopa Prabhu 	struct nlmsghdr *nlh;
306f9c4bb0bSRoopa Prabhu 	struct net *net = dev_net(vxlan->dev);
307f9c4bb0bSRoopa Prabhu 	int err = -ENOBUFS;
308f9c4bb0bSRoopa Prabhu 
309f9c4bb0bSRoopa Prabhu 	skb = nlmsg_new(vxlan_vnifilter_entry_nlmsg_size(), GFP_KERNEL);
310f9c4bb0bSRoopa Prabhu 	if (!skb)
311f9c4bb0bSRoopa Prabhu 		goto out_err;
312f9c4bb0bSRoopa Prabhu 
313f9c4bb0bSRoopa Prabhu 	err = -EMSGSIZE;
314f9c4bb0bSRoopa Prabhu 	nlh = nlmsg_put(skb, 0, 0, cmd, sizeof(*tmsg), 0);
315f9c4bb0bSRoopa Prabhu 	if (!nlh)
316f9c4bb0bSRoopa Prabhu 		goto out_err;
317f9c4bb0bSRoopa Prabhu 	tmsg = nlmsg_data(nlh);
318f9c4bb0bSRoopa Prabhu 	memset(tmsg, 0, sizeof(*tmsg));
319f9c4bb0bSRoopa Prabhu 	tmsg->family = AF_BRIDGE;
320f9c4bb0bSRoopa Prabhu 	tmsg->ifindex = vxlan->dev->ifindex;
321f9c4bb0bSRoopa Prabhu 
322445b2f36SNikolay Aleksandrov 	if (!vxlan_fill_vni_filter_entry(skb, vninode, vninode, false))
323f9c4bb0bSRoopa Prabhu 		goto out_err;
324f9c4bb0bSRoopa Prabhu 
325f9c4bb0bSRoopa Prabhu 	nlmsg_end(skb, nlh);
326f9c4bb0bSRoopa Prabhu 	rtnl_notify(skb, net, 0, RTNLGRP_TUNNEL, NULL, GFP_KERNEL);
327f9c4bb0bSRoopa Prabhu 
328f9c4bb0bSRoopa Prabhu 	return;
329f9c4bb0bSRoopa Prabhu 
330f9c4bb0bSRoopa Prabhu out_err:
331f9c4bb0bSRoopa Prabhu 	rtnl_set_sk_err(net, RTNLGRP_TUNNEL, err);
332f9c4bb0bSRoopa Prabhu 
333f9c4bb0bSRoopa Prabhu 	kfree_skb(skb);
334f9c4bb0bSRoopa Prabhu }
335f9c4bb0bSRoopa Prabhu 
vxlan_vnifilter_dump_dev(const struct net_device * dev,struct sk_buff * skb,struct netlink_callback * cb)336f9c4bb0bSRoopa Prabhu static int vxlan_vnifilter_dump_dev(const struct net_device *dev,
337f9c4bb0bSRoopa Prabhu 				    struct sk_buff *skb,
338f9c4bb0bSRoopa Prabhu 				    struct netlink_callback *cb)
339f9c4bb0bSRoopa Prabhu {
340f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *tmp, *v, *vbegin = NULL, *vend = NULL;
341f9c4bb0bSRoopa Prabhu 	struct vxlan_dev *vxlan = netdev_priv(dev);
342445b2f36SNikolay Aleksandrov 	struct tunnel_msg *new_tmsg, *tmsg;
343f9c4bb0bSRoopa Prabhu 	int idx = 0, s_idx = cb->args[1];
344f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_group *vg;
345f9c4bb0bSRoopa Prabhu 	struct nlmsghdr *nlh;
346445b2f36SNikolay Aleksandrov 	bool dump_stats;
347f9c4bb0bSRoopa Prabhu 	int err = 0;
348f9c4bb0bSRoopa Prabhu 
349f9c4bb0bSRoopa Prabhu 	if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER))
350f9c4bb0bSRoopa Prabhu 		return -EINVAL;
351f9c4bb0bSRoopa Prabhu 
352f9c4bb0bSRoopa Prabhu 	/* RCU needed because of the vni locking rules (rcu || rtnl) */
353f9c4bb0bSRoopa Prabhu 	vg = rcu_dereference(vxlan->vnigrp);
354f9c4bb0bSRoopa Prabhu 	if (!vg || !vg->num_vnis)
355f9c4bb0bSRoopa Prabhu 		return 0;
356f9c4bb0bSRoopa Prabhu 
357445b2f36SNikolay Aleksandrov 	tmsg = nlmsg_data(cb->nlh);
358445b2f36SNikolay Aleksandrov 	dump_stats = !!(tmsg->flags & TUNNEL_MSG_FLAG_STATS);
359445b2f36SNikolay Aleksandrov 
360f9c4bb0bSRoopa Prabhu 	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
361f9c4bb0bSRoopa Prabhu 			RTM_NEWTUNNEL, sizeof(*new_tmsg), NLM_F_MULTI);
362f9c4bb0bSRoopa Prabhu 	if (!nlh)
363f9c4bb0bSRoopa Prabhu 		return -EMSGSIZE;
364f9c4bb0bSRoopa Prabhu 	new_tmsg = nlmsg_data(nlh);
365f9c4bb0bSRoopa Prabhu 	memset(new_tmsg, 0, sizeof(*new_tmsg));
366f9c4bb0bSRoopa Prabhu 	new_tmsg->family = PF_BRIDGE;
367f9c4bb0bSRoopa Prabhu 	new_tmsg->ifindex = dev->ifindex;
368f9c4bb0bSRoopa Prabhu 
369f9c4bb0bSRoopa Prabhu 	list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
370f9c4bb0bSRoopa Prabhu 		if (idx < s_idx) {
371f9c4bb0bSRoopa Prabhu 			idx++;
372f9c4bb0bSRoopa Prabhu 			continue;
373f9c4bb0bSRoopa Prabhu 		}
374f9c4bb0bSRoopa Prabhu 		if (!vbegin) {
375f9c4bb0bSRoopa Prabhu 			vbegin = v;
376f9c4bb0bSRoopa Prabhu 			vend = v;
377f9c4bb0bSRoopa Prabhu 			continue;
378f9c4bb0bSRoopa Prabhu 		}
379445b2f36SNikolay Aleksandrov 		if (!dump_stats && vnirange(vend, v) == 1 &&
380f9c4bb0bSRoopa Prabhu 		    vxlan_addr_equal(&v->remote_ip, &vend->remote_ip)) {
381f9c4bb0bSRoopa Prabhu 			goto update_end;
382f9c4bb0bSRoopa Prabhu 		} else {
383445b2f36SNikolay Aleksandrov 			if (!vxlan_fill_vni_filter_entry(skb, vbegin, vend,
384445b2f36SNikolay Aleksandrov 							 dump_stats)) {
385f9c4bb0bSRoopa Prabhu 				err = -EMSGSIZE;
386f9c4bb0bSRoopa Prabhu 				break;
387f9c4bb0bSRoopa Prabhu 			}
388f9c4bb0bSRoopa Prabhu 			idx += vnirange(vbegin, vend) + 1;
389f9c4bb0bSRoopa Prabhu 			vbegin = v;
390f9c4bb0bSRoopa Prabhu 		}
391f9c4bb0bSRoopa Prabhu update_end:
392f9c4bb0bSRoopa Prabhu 		vend = v;
393f9c4bb0bSRoopa Prabhu 	}
394f9c4bb0bSRoopa Prabhu 
395f9c4bb0bSRoopa Prabhu 	if (!err && vbegin) {
396445b2f36SNikolay Aleksandrov 		if (!vxlan_fill_vni_filter_entry(skb, vbegin, vend, dump_stats))
397f9c4bb0bSRoopa Prabhu 			err = -EMSGSIZE;
398f9c4bb0bSRoopa Prabhu 	}
399f9c4bb0bSRoopa Prabhu 
400f9c4bb0bSRoopa Prabhu 	cb->args[1] = err ? idx : 0;
401f9c4bb0bSRoopa Prabhu 
402f9c4bb0bSRoopa Prabhu 	nlmsg_end(skb, nlh);
403f9c4bb0bSRoopa Prabhu 
404f9c4bb0bSRoopa Prabhu 	return err;
405f9c4bb0bSRoopa Prabhu }
406f9c4bb0bSRoopa Prabhu 
vxlan_vnifilter_dump(struct sk_buff * skb,struct netlink_callback * cb)407f9c4bb0bSRoopa Prabhu static int vxlan_vnifilter_dump(struct sk_buff *skb, struct netlink_callback *cb)
408f9c4bb0bSRoopa Prabhu {
409f9c4bb0bSRoopa Prabhu 	int idx = 0, err = 0, s_idx = cb->args[0];
410f9c4bb0bSRoopa Prabhu 	struct net *net = sock_net(skb->sk);
411f9c4bb0bSRoopa Prabhu 	struct tunnel_msg *tmsg;
412f9c4bb0bSRoopa Prabhu 	struct net_device *dev;
413f9c4bb0bSRoopa Prabhu 
414f9c4bb0bSRoopa Prabhu 	tmsg = nlmsg_data(cb->nlh);
415f9c4bb0bSRoopa Prabhu 
416445b2f36SNikolay Aleksandrov 	if (tmsg->flags & ~TUNNEL_MSG_VALID_USER_FLAGS) {
417445b2f36SNikolay Aleksandrov 		NL_SET_ERR_MSG(cb->extack, "Invalid tunnelmsg flags in ancillary header");
418445b2f36SNikolay Aleksandrov 		return -EINVAL;
419445b2f36SNikolay Aleksandrov 	}
420445b2f36SNikolay Aleksandrov 
421f9c4bb0bSRoopa Prabhu 	rcu_read_lock();
422f9c4bb0bSRoopa Prabhu 	if (tmsg->ifindex) {
423f9c4bb0bSRoopa Prabhu 		dev = dev_get_by_index_rcu(net, tmsg->ifindex);
424f9c4bb0bSRoopa Prabhu 		if (!dev) {
425f9c4bb0bSRoopa Prabhu 			err = -ENODEV;
426f9c4bb0bSRoopa Prabhu 			goto out_err;
427f9c4bb0bSRoopa Prabhu 		}
4289d570741SEric Dumazet 		if (!netif_is_vxlan(dev)) {
4299d570741SEric Dumazet 			NL_SET_ERR_MSG(cb->extack,
4309d570741SEric Dumazet 				       "The device is not a vxlan device");
4319d570741SEric Dumazet 			err = -EINVAL;
4329d570741SEric Dumazet 			goto out_err;
4339d570741SEric Dumazet 		}
434f9c4bb0bSRoopa Prabhu 		err = vxlan_vnifilter_dump_dev(dev, skb, cb);
435f9c4bb0bSRoopa Prabhu 		/* if the dump completed without an error we return 0 here */
436f9c4bb0bSRoopa Prabhu 		if (err != -EMSGSIZE)
437f9c4bb0bSRoopa Prabhu 			goto out_err;
438f9c4bb0bSRoopa Prabhu 	} else {
439f9c4bb0bSRoopa Prabhu 		for_each_netdev_rcu(net, dev) {
440f9c4bb0bSRoopa Prabhu 			if (!netif_is_vxlan(dev))
441f9c4bb0bSRoopa Prabhu 				continue;
442f9c4bb0bSRoopa Prabhu 			if (idx < s_idx)
443f9c4bb0bSRoopa Prabhu 				goto skip;
444f9c4bb0bSRoopa Prabhu 			err = vxlan_vnifilter_dump_dev(dev, skb, cb);
445f9c4bb0bSRoopa Prabhu 			if (err == -EMSGSIZE)
446f9c4bb0bSRoopa Prabhu 				break;
447f9c4bb0bSRoopa Prabhu skip:
448f9c4bb0bSRoopa Prabhu 			idx++;
449f9c4bb0bSRoopa Prabhu 		}
450f9c4bb0bSRoopa Prabhu 	}
451f9c4bb0bSRoopa Prabhu 	cb->args[0] = idx;
452f9c4bb0bSRoopa Prabhu 	rcu_read_unlock();
453f9c4bb0bSRoopa Prabhu 
454f9c4bb0bSRoopa Prabhu 	return skb->len;
455f9c4bb0bSRoopa Prabhu 
456f9c4bb0bSRoopa Prabhu out_err:
457f9c4bb0bSRoopa Prabhu 	rcu_read_unlock();
458f9c4bb0bSRoopa Prabhu 
459f9c4bb0bSRoopa Prabhu 	return err;
460f9c4bb0bSRoopa Prabhu }
461f9c4bb0bSRoopa Prabhu 
462f9c4bb0bSRoopa Prabhu static const struct nla_policy vni_filter_entry_policy[VXLAN_VNIFILTER_ENTRY_MAX + 1] = {
463f9c4bb0bSRoopa Prabhu 	[VXLAN_VNIFILTER_ENTRY_START] = { .type = NLA_U32 },
464f9c4bb0bSRoopa Prabhu 	[VXLAN_VNIFILTER_ENTRY_END] = { .type = NLA_U32 },
465f9c4bb0bSRoopa Prabhu 	[VXLAN_VNIFILTER_ENTRY_GROUP]	= { .type = NLA_BINARY,
466f9c4bb0bSRoopa Prabhu 					    .len = sizeof_field(struct iphdr, daddr) },
467f9c4bb0bSRoopa Prabhu 	[VXLAN_VNIFILTER_ENTRY_GROUP6]	= { .type = NLA_BINARY,
468f9c4bb0bSRoopa Prabhu 					    .len = sizeof(struct in6_addr) },
469f9c4bb0bSRoopa Prabhu };
470f9c4bb0bSRoopa Prabhu 
471f9c4bb0bSRoopa Prabhu static const struct nla_policy vni_filter_policy[VXLAN_VNIFILTER_MAX + 1] = {
472f9c4bb0bSRoopa Prabhu 	[VXLAN_VNIFILTER_ENTRY] = { .type = NLA_NESTED },
473f9c4bb0bSRoopa Prabhu };
474f9c4bb0bSRoopa Prabhu 
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)475f9c4bb0bSRoopa Prabhu static int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni,
476f9c4bb0bSRoopa Prabhu 					  union vxlan_addr *old_remote_ip,
477f9c4bb0bSRoopa Prabhu 					  union vxlan_addr *remote_ip,
478f9c4bb0bSRoopa Prabhu 					  struct netlink_ext_ack *extack)
479f9c4bb0bSRoopa Prabhu {
480f9c4bb0bSRoopa Prabhu 	struct vxlan_rdst *dst = &vxlan->default_dst;
481f9c4bb0bSRoopa Prabhu 	u32 hash_index;
482f9c4bb0bSRoopa Prabhu 	int err = 0;
483f9c4bb0bSRoopa Prabhu 
484f9c4bb0bSRoopa Prabhu 	hash_index = fdb_head_index(vxlan, all_zeros_mac, vni);
485f9c4bb0bSRoopa Prabhu 	spin_lock_bh(&vxlan->hash_lock[hash_index]);
486f9c4bb0bSRoopa Prabhu 	if (remote_ip && !vxlan_addr_any(remote_ip)) {
487f9c4bb0bSRoopa Prabhu 		err = vxlan_fdb_update(vxlan, all_zeros_mac,
488f9c4bb0bSRoopa Prabhu 				       remote_ip,
489f9c4bb0bSRoopa Prabhu 				       NUD_REACHABLE | NUD_PERMANENT,
490f9c4bb0bSRoopa Prabhu 				       NLM_F_APPEND | NLM_F_CREATE,
491f9c4bb0bSRoopa Prabhu 				       vxlan->cfg.dst_port,
492f9c4bb0bSRoopa Prabhu 				       vni,
493f9c4bb0bSRoopa Prabhu 				       vni,
494f9c4bb0bSRoopa Prabhu 				       dst->remote_ifindex,
495f9c4bb0bSRoopa Prabhu 				       NTF_SELF, 0, true, extack);
496f9c4bb0bSRoopa Prabhu 		if (err) {
497f9c4bb0bSRoopa Prabhu 			spin_unlock_bh(&vxlan->hash_lock[hash_index]);
498f9c4bb0bSRoopa Prabhu 			return err;
499f9c4bb0bSRoopa Prabhu 		}
500f9c4bb0bSRoopa Prabhu 	}
501f9c4bb0bSRoopa Prabhu 
502f9c4bb0bSRoopa Prabhu 	if (old_remote_ip && !vxlan_addr_any(old_remote_ip)) {
503f9c4bb0bSRoopa Prabhu 		__vxlan_fdb_delete(vxlan, all_zeros_mac,
504f9c4bb0bSRoopa Prabhu 				   *old_remote_ip,
505f9c4bb0bSRoopa Prabhu 				   vxlan->cfg.dst_port,
506f9c4bb0bSRoopa Prabhu 				   vni, vni,
507f9c4bb0bSRoopa Prabhu 				   dst->remote_ifindex,
508f9c4bb0bSRoopa Prabhu 				   true);
509f9c4bb0bSRoopa Prabhu 	}
510f9c4bb0bSRoopa Prabhu 	spin_unlock_bh(&vxlan->hash_lock[hash_index]);
511f9c4bb0bSRoopa Prabhu 
512f9c4bb0bSRoopa Prabhu 	return err;
513f9c4bb0bSRoopa Prabhu }
514f9c4bb0bSRoopa Prabhu 
vxlan_vni_update_group(struct vxlan_dev * vxlan,struct vxlan_vni_node * vninode,union vxlan_addr * group,bool create,bool * changed,struct netlink_ext_ack * extack)515f9c4bb0bSRoopa Prabhu static int vxlan_vni_update_group(struct vxlan_dev *vxlan,
516f9c4bb0bSRoopa Prabhu 				  struct vxlan_vni_node *vninode,
517f9c4bb0bSRoopa Prabhu 				  union vxlan_addr *group,
518f9c4bb0bSRoopa Prabhu 				  bool create, bool *changed,
519f9c4bb0bSRoopa Prabhu 				  struct netlink_ext_ack *extack)
520f9c4bb0bSRoopa Prabhu {
521f9c4bb0bSRoopa Prabhu 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
522f9c4bb0bSRoopa Prabhu 	struct vxlan_rdst *dst = &vxlan->default_dst;
523f9c4bb0bSRoopa Prabhu 	union vxlan_addr *newrip = NULL, *oldrip = NULL;
524f9c4bb0bSRoopa Prabhu 	union vxlan_addr old_remote_ip;
525f9c4bb0bSRoopa Prabhu 	int ret = 0;
526f9c4bb0bSRoopa Prabhu 
527f9c4bb0bSRoopa Prabhu 	memcpy(&old_remote_ip, &vninode->remote_ip, sizeof(old_remote_ip));
528f9c4bb0bSRoopa Prabhu 
529f9c4bb0bSRoopa Prabhu 	/* if per vni remote ip is not present use vxlan dev
530f9c4bb0bSRoopa Prabhu 	 * default dst remote ip for fdb entry
531f9c4bb0bSRoopa Prabhu 	 */
532f9c4bb0bSRoopa Prabhu 	if (group && !vxlan_addr_any(group)) {
533f9c4bb0bSRoopa Prabhu 		newrip = group;
534f9c4bb0bSRoopa Prabhu 	} else {
535f9c4bb0bSRoopa Prabhu 		if (!vxlan_addr_any(&dst->remote_ip))
536f9c4bb0bSRoopa Prabhu 			newrip = &dst->remote_ip;
537f9c4bb0bSRoopa Prabhu 	}
538f9c4bb0bSRoopa Prabhu 
539f9c4bb0bSRoopa Prabhu 	/* if old rip exists, and no newrip,
540f9c4bb0bSRoopa Prabhu 	 * explicitly delete old rip
541f9c4bb0bSRoopa Prabhu 	 */
542f9c4bb0bSRoopa Prabhu 	if (!newrip && !vxlan_addr_any(&old_remote_ip))
543f9c4bb0bSRoopa Prabhu 		oldrip = &old_remote_ip;
544f9c4bb0bSRoopa Prabhu 
545f9c4bb0bSRoopa Prabhu 	if (!newrip && !oldrip)
546f9c4bb0bSRoopa Prabhu 		return 0;
547f9c4bb0bSRoopa Prabhu 
548f9c4bb0bSRoopa Prabhu 	if (!create && oldrip && newrip && vxlan_addr_equal(oldrip, newrip))
549f9c4bb0bSRoopa Prabhu 		return 0;
550f9c4bb0bSRoopa Prabhu 
551f9c4bb0bSRoopa Prabhu 	ret = vxlan_update_default_fdb_entry(vxlan, vninode->vni,
552f9c4bb0bSRoopa Prabhu 					     oldrip, newrip,
553f9c4bb0bSRoopa Prabhu 					     extack);
554f9c4bb0bSRoopa Prabhu 	if (ret)
555f9c4bb0bSRoopa Prabhu 		goto out;
556f9c4bb0bSRoopa Prabhu 
557f9c4bb0bSRoopa Prabhu 	if (group)
558f9c4bb0bSRoopa Prabhu 		memcpy(&vninode->remote_ip, group, sizeof(vninode->remote_ip));
559f9c4bb0bSRoopa Prabhu 
560f9c4bb0bSRoopa Prabhu 	if (vxlan->dev->flags & IFF_UP) {
561f9c4bb0bSRoopa Prabhu 		if (vxlan_addr_multicast(&old_remote_ip) &&
562f9c4bb0bSRoopa Prabhu 		    !vxlan_group_used(vn, vxlan, vninode->vni,
563f9c4bb0bSRoopa Prabhu 				      &old_remote_ip,
564f9c4bb0bSRoopa Prabhu 				      vxlan->default_dst.remote_ifindex)) {
565f9c4bb0bSRoopa Prabhu 			ret = vxlan_igmp_leave(vxlan, &old_remote_ip,
566f9c4bb0bSRoopa Prabhu 					       0);
567f9c4bb0bSRoopa Prabhu 			if (ret)
568f9c4bb0bSRoopa Prabhu 				goto out;
569f9c4bb0bSRoopa Prabhu 		}
570f9c4bb0bSRoopa Prabhu 
571f9c4bb0bSRoopa Prabhu 		if (vxlan_addr_multicast(&vninode->remote_ip)) {
572f9c4bb0bSRoopa Prabhu 			ret = vxlan_igmp_join(vxlan, &vninode->remote_ip, 0);
573f9c4bb0bSRoopa Prabhu 			if (ret == -EADDRINUSE)
574f9c4bb0bSRoopa Prabhu 				ret = 0;
575f9c4bb0bSRoopa Prabhu 			if (ret)
576f9c4bb0bSRoopa Prabhu 				goto out;
577f9c4bb0bSRoopa Prabhu 		}
578f9c4bb0bSRoopa Prabhu 	}
579f9c4bb0bSRoopa Prabhu 
580f9c4bb0bSRoopa Prabhu 	*changed = true;
581f9c4bb0bSRoopa Prabhu 
582f9c4bb0bSRoopa Prabhu 	return 0;
583f9c4bb0bSRoopa Prabhu out:
584f9c4bb0bSRoopa Prabhu 	return ret;
585f9c4bb0bSRoopa Prabhu }
586f9c4bb0bSRoopa Prabhu 
vxlan_vnilist_update_group(struct vxlan_dev * vxlan,union vxlan_addr * old_remote_ip,union vxlan_addr * new_remote_ip,struct netlink_ext_ack * extack)587f9c4bb0bSRoopa Prabhu int vxlan_vnilist_update_group(struct vxlan_dev *vxlan,
588f9c4bb0bSRoopa Prabhu 			       union vxlan_addr *old_remote_ip,
589f9c4bb0bSRoopa Prabhu 			       union vxlan_addr *new_remote_ip,
590f9c4bb0bSRoopa Prabhu 			       struct netlink_ext_ack *extack)
591f9c4bb0bSRoopa Prabhu {
592f9c4bb0bSRoopa Prabhu 	struct list_head *headp, *hpos;
593f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_group *vg;
594f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *vent;
595f9c4bb0bSRoopa Prabhu 	int ret;
596f9c4bb0bSRoopa Prabhu 
597f9c4bb0bSRoopa Prabhu 	vg = rtnl_dereference(vxlan->vnigrp);
598f9c4bb0bSRoopa Prabhu 
599f9c4bb0bSRoopa Prabhu 	headp = &vg->vni_list;
600f9c4bb0bSRoopa Prabhu 	list_for_each_prev(hpos, headp) {
601f9c4bb0bSRoopa Prabhu 		vent = list_entry(hpos, struct vxlan_vni_node, vlist);
602f9c4bb0bSRoopa Prabhu 		if (vxlan_addr_any(&vent->remote_ip)) {
603f9c4bb0bSRoopa Prabhu 			ret = vxlan_update_default_fdb_entry(vxlan, vent->vni,
604f9c4bb0bSRoopa Prabhu 							     old_remote_ip,
605f9c4bb0bSRoopa Prabhu 							     new_remote_ip,
606f9c4bb0bSRoopa Prabhu 							     extack);
607f9c4bb0bSRoopa Prabhu 			if (ret)
608f9c4bb0bSRoopa Prabhu 				return ret;
609f9c4bb0bSRoopa Prabhu 		}
610f9c4bb0bSRoopa Prabhu 	}
611f9c4bb0bSRoopa Prabhu 
612f9c4bb0bSRoopa Prabhu 	return 0;
613f9c4bb0bSRoopa Prabhu }
614f9c4bb0bSRoopa Prabhu 
vxlan_vni_delete_group(struct vxlan_dev * vxlan,struct vxlan_vni_node * vninode)615f9c4bb0bSRoopa Prabhu static void vxlan_vni_delete_group(struct vxlan_dev *vxlan,
616f9c4bb0bSRoopa Prabhu 				   struct vxlan_vni_node *vninode)
617f9c4bb0bSRoopa Prabhu {
618f9c4bb0bSRoopa Prabhu 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
619f9c4bb0bSRoopa Prabhu 	struct vxlan_rdst *dst = &vxlan->default_dst;
620f9c4bb0bSRoopa Prabhu 
621f9c4bb0bSRoopa Prabhu 	/* if per vni remote_ip not present, delete the
622f9c4bb0bSRoopa Prabhu 	 * default dst remote_ip previously added for this vni
623f9c4bb0bSRoopa Prabhu 	 */
624f9c4bb0bSRoopa Prabhu 	if (!vxlan_addr_any(&vninode->remote_ip) ||
625f9c4bb0bSRoopa Prabhu 	    !vxlan_addr_any(&dst->remote_ip))
626f9c4bb0bSRoopa Prabhu 		__vxlan_fdb_delete(vxlan, all_zeros_mac,
627f9c4bb0bSRoopa Prabhu 				   (vxlan_addr_any(&vninode->remote_ip) ?
628f9c4bb0bSRoopa Prabhu 				   dst->remote_ip : vninode->remote_ip),
629f9c4bb0bSRoopa Prabhu 				   vxlan->cfg.dst_port,
630f9c4bb0bSRoopa Prabhu 				   vninode->vni, vninode->vni,
631f9c4bb0bSRoopa Prabhu 				   dst->remote_ifindex,
632f9c4bb0bSRoopa Prabhu 				   true);
633f9c4bb0bSRoopa Prabhu 
634f9c4bb0bSRoopa Prabhu 	if (vxlan->dev->flags & IFF_UP) {
635f9c4bb0bSRoopa Prabhu 		if (vxlan_addr_multicast(&vninode->remote_ip) &&
636f9c4bb0bSRoopa Prabhu 		    !vxlan_group_used(vn, vxlan, vninode->vni,
637f9c4bb0bSRoopa Prabhu 				      &vninode->remote_ip,
638f9c4bb0bSRoopa Prabhu 				      dst->remote_ifindex)) {
639f9c4bb0bSRoopa Prabhu 			vxlan_igmp_leave(vxlan, &vninode->remote_ip, 0);
640f9c4bb0bSRoopa Prabhu 		}
641f9c4bb0bSRoopa Prabhu 	}
642f9c4bb0bSRoopa Prabhu }
643f9c4bb0bSRoopa Prabhu 
vxlan_vni_update(struct vxlan_dev * vxlan,struct vxlan_vni_group * vg,__be32 vni,union vxlan_addr * group,bool * changed,struct netlink_ext_ack * extack)644f9c4bb0bSRoopa Prabhu static int vxlan_vni_update(struct vxlan_dev *vxlan,
645f9c4bb0bSRoopa Prabhu 			    struct vxlan_vni_group *vg,
646f9c4bb0bSRoopa Prabhu 			    __be32 vni, union vxlan_addr *group,
647f9c4bb0bSRoopa Prabhu 			    bool *changed,
648f9c4bb0bSRoopa Prabhu 			    struct netlink_ext_ack *extack)
649f9c4bb0bSRoopa Prabhu {
650f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *vninode;
651f9c4bb0bSRoopa Prabhu 	int ret;
652f9c4bb0bSRoopa Prabhu 
653f9c4bb0bSRoopa Prabhu 	vninode = rhashtable_lookup_fast(&vg->vni_hash, &vni,
654f9c4bb0bSRoopa Prabhu 					 vxlan_vni_rht_params);
655f9c4bb0bSRoopa Prabhu 	if (!vninode)
656f9c4bb0bSRoopa Prabhu 		return 0;
657f9c4bb0bSRoopa Prabhu 
658f9c4bb0bSRoopa Prabhu 	ret = vxlan_vni_update_group(vxlan, vninode, group, false, changed,
659f9c4bb0bSRoopa Prabhu 				     extack);
660f9c4bb0bSRoopa Prabhu 	if (ret)
661f9c4bb0bSRoopa Prabhu 		return ret;
662f9c4bb0bSRoopa Prabhu 
663f9c4bb0bSRoopa Prabhu 	if (changed)
664f9c4bb0bSRoopa Prabhu 		vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL);
665f9c4bb0bSRoopa Prabhu 
666f9c4bb0bSRoopa Prabhu 	return 0;
667f9c4bb0bSRoopa Prabhu }
668f9c4bb0bSRoopa Prabhu 
__vxlan_vni_add_list(struct vxlan_vni_group * vg,struct vxlan_vni_node * v)669f9c4bb0bSRoopa Prabhu static void __vxlan_vni_add_list(struct vxlan_vni_group *vg,
670f9c4bb0bSRoopa Prabhu 				 struct vxlan_vni_node *v)
671f9c4bb0bSRoopa Prabhu {
672f9c4bb0bSRoopa Prabhu 	struct list_head *headp, *hpos;
673f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *vent;
674f9c4bb0bSRoopa Prabhu 
675f9c4bb0bSRoopa Prabhu 	headp = &vg->vni_list;
676f9c4bb0bSRoopa Prabhu 	list_for_each_prev(hpos, headp) {
677f9c4bb0bSRoopa Prabhu 		vent = list_entry(hpos, struct vxlan_vni_node, vlist);
678f9c4bb0bSRoopa Prabhu 		if (be32_to_cpu(v->vni) < be32_to_cpu(vent->vni))
679f9c4bb0bSRoopa Prabhu 			continue;
680f9c4bb0bSRoopa Prabhu 		else
681f9c4bb0bSRoopa Prabhu 			break;
682f9c4bb0bSRoopa Prabhu 	}
683f9c4bb0bSRoopa Prabhu 	list_add_rcu(&v->vlist, hpos);
684f9c4bb0bSRoopa Prabhu 	vg->num_vnis++;
685f9c4bb0bSRoopa Prabhu }
686f9c4bb0bSRoopa Prabhu 
__vxlan_vni_del_list(struct vxlan_vni_group * vg,struct vxlan_vni_node * v)687f9c4bb0bSRoopa Prabhu static void __vxlan_vni_del_list(struct vxlan_vni_group *vg,
688f9c4bb0bSRoopa Prabhu 				 struct vxlan_vni_node *v)
689f9c4bb0bSRoopa Prabhu {
690f9c4bb0bSRoopa Prabhu 	list_del_rcu(&v->vlist);
691f9c4bb0bSRoopa Prabhu 	vg->num_vnis--;
692f9c4bb0bSRoopa Prabhu }
693f9c4bb0bSRoopa Prabhu 
vxlan_vni_alloc(struct vxlan_dev * vxlan,__be32 vni)694f9c4bb0bSRoopa Prabhu static struct vxlan_vni_node *vxlan_vni_alloc(struct vxlan_dev *vxlan,
695f9c4bb0bSRoopa Prabhu 					      __be32 vni)
696f9c4bb0bSRoopa Prabhu {
697f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *vninode;
698f9c4bb0bSRoopa Prabhu 
699*63c11dc2SIdo Schimmel 	vninode = kzalloc(sizeof(*vninode), GFP_KERNEL);
700f9c4bb0bSRoopa Prabhu 	if (!vninode)
701f9c4bb0bSRoopa Prabhu 		return NULL;
7024095e0e1SNikolay Aleksandrov 	vninode->stats = netdev_alloc_pcpu_stats(struct vxlan_vni_stats_pcpu);
7034095e0e1SNikolay Aleksandrov 	if (!vninode->stats) {
7044095e0e1SNikolay Aleksandrov 		kfree(vninode);
7054095e0e1SNikolay Aleksandrov 		return NULL;
7064095e0e1SNikolay Aleksandrov 	}
707f9c4bb0bSRoopa Prabhu 	vninode->vni = vni;
708f9c4bb0bSRoopa Prabhu 	vninode->hlist4.vxlan = vxlan;
709f9c4bb0bSRoopa Prabhu #if IS_ENABLED(CONFIG_IPV6)
710f9c4bb0bSRoopa Prabhu 	vninode->hlist6.vxlan = vxlan;
711f9c4bb0bSRoopa Prabhu #endif
712f9c4bb0bSRoopa Prabhu 
713f9c4bb0bSRoopa Prabhu 	return vninode;
714f9c4bb0bSRoopa Prabhu }
715f9c4bb0bSRoopa Prabhu 
vxlan_vni_free(struct vxlan_vni_node * vninode)716b1c936e9SFedor Pchelkin static void vxlan_vni_free(struct vxlan_vni_node *vninode)
717b1c936e9SFedor Pchelkin {
718b1c936e9SFedor Pchelkin 	free_percpu(vninode->stats);
719b1c936e9SFedor Pchelkin 	kfree(vninode);
720b1c936e9SFedor Pchelkin }
721b1c936e9SFedor Pchelkin 
vxlan_vni_add(struct vxlan_dev * vxlan,struct vxlan_vni_group * vg,u32 vni,union vxlan_addr * group,struct netlink_ext_ack * extack)722f9c4bb0bSRoopa Prabhu static int vxlan_vni_add(struct vxlan_dev *vxlan,
723f9c4bb0bSRoopa Prabhu 			 struct vxlan_vni_group *vg,
724f9c4bb0bSRoopa Prabhu 			 u32 vni, union vxlan_addr *group,
725f9c4bb0bSRoopa Prabhu 			 struct netlink_ext_ack *extack)
726f9c4bb0bSRoopa Prabhu {
727f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *vninode;
728f9c4bb0bSRoopa Prabhu 	__be32 v = cpu_to_be32(vni);
729f9c4bb0bSRoopa Prabhu 	bool changed = false;
730f9c4bb0bSRoopa Prabhu 	int err = 0;
731f9c4bb0bSRoopa Prabhu 
732f9c4bb0bSRoopa Prabhu 	if (vxlan_vnifilter_lookup(vxlan, v))
733f9c4bb0bSRoopa Prabhu 		return vxlan_vni_update(vxlan, vg, v, group, &changed, extack);
734f9c4bb0bSRoopa Prabhu 
735f9c4bb0bSRoopa Prabhu 	err = vxlan_vni_in_use(vxlan->net, vxlan, &vxlan->cfg, v);
736f9c4bb0bSRoopa Prabhu 	if (err) {
737f9c4bb0bSRoopa Prabhu 		NL_SET_ERR_MSG(extack, "VNI in use");
738f9c4bb0bSRoopa Prabhu 		return err;
739f9c4bb0bSRoopa Prabhu 	}
740f9c4bb0bSRoopa Prabhu 
741f9c4bb0bSRoopa Prabhu 	vninode = vxlan_vni_alloc(vxlan, v);
742f9c4bb0bSRoopa Prabhu 	if (!vninode)
743f9c4bb0bSRoopa Prabhu 		return -ENOMEM;
744f9c4bb0bSRoopa Prabhu 
745f9c4bb0bSRoopa Prabhu 	err = rhashtable_lookup_insert_fast(&vg->vni_hash,
746f9c4bb0bSRoopa Prabhu 					    &vninode->vnode,
747f9c4bb0bSRoopa Prabhu 					    vxlan_vni_rht_params);
748f9c4bb0bSRoopa Prabhu 	if (err) {
749b1c936e9SFedor Pchelkin 		vxlan_vni_free(vninode);
750f9c4bb0bSRoopa Prabhu 		return err;
751f9c4bb0bSRoopa Prabhu 	}
752f9c4bb0bSRoopa Prabhu 
753f9c4bb0bSRoopa Prabhu 	__vxlan_vni_add_list(vg, vninode);
754f9c4bb0bSRoopa Prabhu 
755f9c4bb0bSRoopa Prabhu 	if (vxlan->dev->flags & IFF_UP)
756f9c4bb0bSRoopa Prabhu 		vxlan_vs_add_del_vninode(vxlan, vninode, false);
757f9c4bb0bSRoopa Prabhu 
758f9c4bb0bSRoopa Prabhu 	err = vxlan_vni_update_group(vxlan, vninode, group, true, &changed,
759f9c4bb0bSRoopa Prabhu 				     extack);
760f9c4bb0bSRoopa Prabhu 
761f9c4bb0bSRoopa Prabhu 	if (changed)
762f9c4bb0bSRoopa Prabhu 		vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL);
763f9c4bb0bSRoopa Prabhu 
764f9c4bb0bSRoopa Prabhu 	return err;
765f9c4bb0bSRoopa Prabhu }
766f9c4bb0bSRoopa Prabhu 
vxlan_vni_node_rcu_free(struct rcu_head * rcu)767f9c4bb0bSRoopa Prabhu static void vxlan_vni_node_rcu_free(struct rcu_head *rcu)
768f9c4bb0bSRoopa Prabhu {
769f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *v;
770f9c4bb0bSRoopa Prabhu 
771f9c4bb0bSRoopa Prabhu 	v = container_of(rcu, struct vxlan_vni_node, rcu);
772b1c936e9SFedor Pchelkin 	vxlan_vni_free(v);
773f9c4bb0bSRoopa Prabhu }
774f9c4bb0bSRoopa Prabhu 
vxlan_vni_del(struct vxlan_dev * vxlan,struct vxlan_vni_group * vg,u32 vni,struct netlink_ext_ack * extack)775f9c4bb0bSRoopa Prabhu static int vxlan_vni_del(struct vxlan_dev *vxlan,
776f9c4bb0bSRoopa Prabhu 			 struct vxlan_vni_group *vg,
777f9c4bb0bSRoopa Prabhu 			 u32 vni, struct netlink_ext_ack *extack)
778f9c4bb0bSRoopa Prabhu {
779f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *vninode;
780f9c4bb0bSRoopa Prabhu 	__be32 v = cpu_to_be32(vni);
781f9c4bb0bSRoopa Prabhu 	int err = 0;
782f9c4bb0bSRoopa Prabhu 
783f9c4bb0bSRoopa Prabhu 	vg = rtnl_dereference(vxlan->vnigrp);
784f9c4bb0bSRoopa Prabhu 
785f9c4bb0bSRoopa Prabhu 	vninode = rhashtable_lookup_fast(&vg->vni_hash, &v,
786f9c4bb0bSRoopa Prabhu 					 vxlan_vni_rht_params);
787f9c4bb0bSRoopa Prabhu 	if (!vninode) {
788f9c4bb0bSRoopa Prabhu 		err = -ENOENT;
789f9c4bb0bSRoopa Prabhu 		goto out;
790f9c4bb0bSRoopa Prabhu 	}
791f9c4bb0bSRoopa Prabhu 
792f9c4bb0bSRoopa Prabhu 	vxlan_vni_delete_group(vxlan, vninode);
793f9c4bb0bSRoopa Prabhu 
794f9c4bb0bSRoopa Prabhu 	err = rhashtable_remove_fast(&vg->vni_hash,
795f9c4bb0bSRoopa Prabhu 				     &vninode->vnode,
796f9c4bb0bSRoopa Prabhu 				     vxlan_vni_rht_params);
797f9c4bb0bSRoopa Prabhu 	if (err)
798f9c4bb0bSRoopa Prabhu 		goto out;
799f9c4bb0bSRoopa Prabhu 
800f9c4bb0bSRoopa Prabhu 	__vxlan_vni_del_list(vg, vninode);
801f9c4bb0bSRoopa Prabhu 
802f9c4bb0bSRoopa Prabhu 	vxlan_vnifilter_notify(vxlan, vninode, RTM_DELTUNNEL);
803f9c4bb0bSRoopa Prabhu 
804f9c4bb0bSRoopa Prabhu 	if (vxlan->dev->flags & IFF_UP)
805f9c4bb0bSRoopa Prabhu 		vxlan_vs_add_del_vninode(vxlan, vninode, true);
806f9c4bb0bSRoopa Prabhu 
807f9c4bb0bSRoopa Prabhu 	call_rcu(&vninode->rcu, vxlan_vni_node_rcu_free);
808f9c4bb0bSRoopa Prabhu 
809f9c4bb0bSRoopa Prabhu 	return 0;
810f9c4bb0bSRoopa Prabhu out:
811f9c4bb0bSRoopa Prabhu 	return err;
812f9c4bb0bSRoopa Prabhu }
813f9c4bb0bSRoopa Prabhu 
vxlan_vni_add_del(struct vxlan_dev * vxlan,__u32 start_vni,__u32 end_vni,union vxlan_addr * group,int cmd,struct netlink_ext_ack * extack)814f9c4bb0bSRoopa Prabhu static int vxlan_vni_add_del(struct vxlan_dev *vxlan, __u32 start_vni,
815f9c4bb0bSRoopa Prabhu 			     __u32 end_vni, union vxlan_addr *group,
816f9c4bb0bSRoopa Prabhu 			     int cmd, struct netlink_ext_ack *extack)
817f9c4bb0bSRoopa Prabhu {
818f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_group *vg;
819f9c4bb0bSRoopa Prabhu 	int v, err = 0;
820f9c4bb0bSRoopa Prabhu 
821f9c4bb0bSRoopa Prabhu 	vg = rtnl_dereference(vxlan->vnigrp);
822f9c4bb0bSRoopa Prabhu 
823f9c4bb0bSRoopa Prabhu 	for (v = start_vni; v <= end_vni; v++) {
824f9c4bb0bSRoopa Prabhu 		switch (cmd) {
825f9c4bb0bSRoopa Prabhu 		case RTM_NEWTUNNEL:
826f9c4bb0bSRoopa Prabhu 			err = vxlan_vni_add(vxlan, vg, v, group, extack);
827f9c4bb0bSRoopa Prabhu 			break;
828f9c4bb0bSRoopa Prabhu 		case RTM_DELTUNNEL:
829f9c4bb0bSRoopa Prabhu 			err = vxlan_vni_del(vxlan, vg, v, extack);
830f9c4bb0bSRoopa Prabhu 			break;
831f9c4bb0bSRoopa Prabhu 		default:
832f9c4bb0bSRoopa Prabhu 			err = -EOPNOTSUPP;
833f9c4bb0bSRoopa Prabhu 			break;
834f9c4bb0bSRoopa Prabhu 		}
835f9c4bb0bSRoopa Prabhu 		if (err)
836f9c4bb0bSRoopa Prabhu 			goto out;
837f9c4bb0bSRoopa Prabhu 	}
838f9c4bb0bSRoopa Prabhu 
839f9c4bb0bSRoopa Prabhu 	return 0;
840f9c4bb0bSRoopa Prabhu out:
841f9c4bb0bSRoopa Prabhu 	return err;
842f9c4bb0bSRoopa Prabhu }
843f9c4bb0bSRoopa Prabhu 
vxlan_process_vni_filter(struct vxlan_dev * vxlan,struct nlattr * nlvnifilter,int cmd,struct netlink_ext_ack * extack)844f9c4bb0bSRoopa Prabhu static int vxlan_process_vni_filter(struct vxlan_dev *vxlan,
845f9c4bb0bSRoopa Prabhu 				    struct nlattr *nlvnifilter,
846f9c4bb0bSRoopa Prabhu 				    int cmd, struct netlink_ext_ack *extack)
847f9c4bb0bSRoopa Prabhu {
848f9c4bb0bSRoopa Prabhu 	struct nlattr *vattrs[VXLAN_VNIFILTER_ENTRY_MAX + 1];
849f9c4bb0bSRoopa Prabhu 	u32 vni_start = 0, vni_end = 0;
850f9c4bb0bSRoopa Prabhu 	union vxlan_addr group;
851f9c4bb0bSRoopa Prabhu 	int err;
852f9c4bb0bSRoopa Prabhu 
853f9c4bb0bSRoopa Prabhu 	err = nla_parse_nested(vattrs,
854f9c4bb0bSRoopa Prabhu 			       VXLAN_VNIFILTER_ENTRY_MAX,
855f9c4bb0bSRoopa Prabhu 			       nlvnifilter, vni_filter_entry_policy,
856f9c4bb0bSRoopa Prabhu 			       extack);
857f9c4bb0bSRoopa Prabhu 	if (err)
858f9c4bb0bSRoopa Prabhu 		return err;
859f9c4bb0bSRoopa Prabhu 
860f9c4bb0bSRoopa Prabhu 	if (vattrs[VXLAN_VNIFILTER_ENTRY_START]) {
861f9c4bb0bSRoopa Prabhu 		vni_start = nla_get_u32(vattrs[VXLAN_VNIFILTER_ENTRY_START]);
862f9c4bb0bSRoopa Prabhu 		vni_end = vni_start;
863f9c4bb0bSRoopa Prabhu 	}
864f9c4bb0bSRoopa Prabhu 
865f9c4bb0bSRoopa Prabhu 	if (vattrs[VXLAN_VNIFILTER_ENTRY_END])
866f9c4bb0bSRoopa Prabhu 		vni_end = nla_get_u32(vattrs[VXLAN_VNIFILTER_ENTRY_END]);
867f9c4bb0bSRoopa Prabhu 
868f9c4bb0bSRoopa Prabhu 	if (!vni_start && !vni_end) {
869f9c4bb0bSRoopa Prabhu 		NL_SET_ERR_MSG_ATTR(extack, nlvnifilter,
870f9c4bb0bSRoopa Prabhu 				    "vni start nor end found in vni entry");
871f9c4bb0bSRoopa Prabhu 		return -EINVAL;
872f9c4bb0bSRoopa Prabhu 	}
873f9c4bb0bSRoopa Prabhu 
874f9c4bb0bSRoopa Prabhu 	if (vattrs[VXLAN_VNIFILTER_ENTRY_GROUP]) {
875f9c4bb0bSRoopa Prabhu 		group.sin.sin_addr.s_addr =
876f9c4bb0bSRoopa Prabhu 			nla_get_in_addr(vattrs[VXLAN_VNIFILTER_ENTRY_GROUP]);
877f9c4bb0bSRoopa Prabhu 		group.sa.sa_family = AF_INET;
878f9c4bb0bSRoopa Prabhu 	} else if (vattrs[VXLAN_VNIFILTER_ENTRY_GROUP6]) {
879f9c4bb0bSRoopa Prabhu 		group.sin6.sin6_addr =
880f9c4bb0bSRoopa Prabhu 			nla_get_in6_addr(vattrs[VXLAN_VNIFILTER_ENTRY_GROUP6]);
881f9c4bb0bSRoopa Prabhu 		group.sa.sa_family = AF_INET6;
882f9c4bb0bSRoopa Prabhu 	} else {
883f9c4bb0bSRoopa Prabhu 		memset(&group, 0, sizeof(group));
884f9c4bb0bSRoopa Prabhu 	}
885f9c4bb0bSRoopa Prabhu 
886f9c4bb0bSRoopa Prabhu 	if (vxlan_addr_multicast(&group) && !vxlan->default_dst.remote_ifindex) {
887f9c4bb0bSRoopa Prabhu 		NL_SET_ERR_MSG(extack,
888f9c4bb0bSRoopa Prabhu 			       "Local interface required for multicast remote group");
889f9c4bb0bSRoopa Prabhu 
890f9c4bb0bSRoopa Prabhu 		return -EINVAL;
891f9c4bb0bSRoopa Prabhu 	}
892f9c4bb0bSRoopa Prabhu 
893f9c4bb0bSRoopa Prabhu 	err = vxlan_vni_add_del(vxlan, vni_start, vni_end, &group, cmd,
894f9c4bb0bSRoopa Prabhu 				extack);
895f9c4bb0bSRoopa Prabhu 	if (err)
896f9c4bb0bSRoopa Prabhu 		return err;
897f9c4bb0bSRoopa Prabhu 
898f9c4bb0bSRoopa Prabhu 	return 0;
899f9c4bb0bSRoopa Prabhu }
900f9c4bb0bSRoopa Prabhu 
vxlan_vnigroup_uninit(struct vxlan_dev * vxlan)901f9c4bb0bSRoopa Prabhu void vxlan_vnigroup_uninit(struct vxlan_dev *vxlan)
902f9c4bb0bSRoopa Prabhu {
903f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_node *v, *tmp;
904f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_group *vg;
905f9c4bb0bSRoopa Prabhu 
906f9c4bb0bSRoopa Prabhu 	vg = rtnl_dereference(vxlan->vnigrp);
907f9c4bb0bSRoopa Prabhu 	list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
908f9c4bb0bSRoopa Prabhu 		rhashtable_remove_fast(&vg->vni_hash, &v->vnode,
909f9c4bb0bSRoopa Prabhu 				       vxlan_vni_rht_params);
910f9c4bb0bSRoopa Prabhu 		hlist_del_init_rcu(&v->hlist4.hlist);
911f9c4bb0bSRoopa Prabhu #if IS_ENABLED(CONFIG_IPV6)
912f9c4bb0bSRoopa Prabhu 		hlist_del_init_rcu(&v->hlist6.hlist);
913f9c4bb0bSRoopa Prabhu #endif
914f9c4bb0bSRoopa Prabhu 		__vxlan_vni_del_list(vg, v);
915f9c4bb0bSRoopa Prabhu 		vxlan_vnifilter_notify(vxlan, v, RTM_DELTUNNEL);
916f9c4bb0bSRoopa Prabhu 		call_rcu(&v->rcu, vxlan_vni_node_rcu_free);
917f9c4bb0bSRoopa Prabhu 	}
918f9c4bb0bSRoopa Prabhu 	rhashtable_destroy(&vg->vni_hash);
919f9c4bb0bSRoopa Prabhu 	kfree(vg);
920f9c4bb0bSRoopa Prabhu }
921f9c4bb0bSRoopa Prabhu 
vxlan_vnigroup_init(struct vxlan_dev * vxlan)922f9c4bb0bSRoopa Prabhu int vxlan_vnigroup_init(struct vxlan_dev *vxlan)
923f9c4bb0bSRoopa Prabhu {
924f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_group *vg;
925f9c4bb0bSRoopa Prabhu 	int ret;
926f9c4bb0bSRoopa Prabhu 
927f9c4bb0bSRoopa Prabhu 	vg = kzalloc(sizeof(*vg), GFP_KERNEL);
928f9c4bb0bSRoopa Prabhu 	if (!vg)
929f9c4bb0bSRoopa Prabhu 		return -ENOMEM;
930f9c4bb0bSRoopa Prabhu 	ret = rhashtable_init(&vg->vni_hash, &vxlan_vni_rht_params);
931f9c4bb0bSRoopa Prabhu 	if (ret) {
932f9c4bb0bSRoopa Prabhu 		kfree(vg);
933f9c4bb0bSRoopa Prabhu 		return ret;
934f9c4bb0bSRoopa Prabhu 	}
935f9c4bb0bSRoopa Prabhu 	INIT_LIST_HEAD(&vg->vni_list);
936f9c4bb0bSRoopa Prabhu 	rcu_assign_pointer(vxlan->vnigrp, vg);
937f9c4bb0bSRoopa Prabhu 
938f9c4bb0bSRoopa Prabhu 	return 0;
939f9c4bb0bSRoopa Prabhu }
940f9c4bb0bSRoopa Prabhu 
vxlan_vnifilter_process(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)941f9c4bb0bSRoopa Prabhu static int vxlan_vnifilter_process(struct sk_buff *skb, struct nlmsghdr *nlh,
942f9c4bb0bSRoopa Prabhu 				   struct netlink_ext_ack *extack)
943f9c4bb0bSRoopa Prabhu {
944f9c4bb0bSRoopa Prabhu 	struct net *net = sock_net(skb->sk);
945f9c4bb0bSRoopa Prabhu 	struct tunnel_msg *tmsg;
946f9c4bb0bSRoopa Prabhu 	struct vxlan_dev *vxlan;
947f9c4bb0bSRoopa Prabhu 	struct net_device *dev;
948f9c4bb0bSRoopa Prabhu 	struct nlattr *attr;
949f9c4bb0bSRoopa Prabhu 	int err, vnis = 0;
950f9c4bb0bSRoopa Prabhu 	int rem;
951f9c4bb0bSRoopa Prabhu 
952f9c4bb0bSRoopa Prabhu 	/* this should validate the header and check for remaining bytes */
953f9c4bb0bSRoopa Prabhu 	err = nlmsg_parse(nlh, sizeof(*tmsg), NULL, VXLAN_VNIFILTER_MAX,
954f9c4bb0bSRoopa Prabhu 			  vni_filter_policy, extack);
955f9c4bb0bSRoopa Prabhu 	if (err < 0)
956f9c4bb0bSRoopa Prabhu 		return err;
957f9c4bb0bSRoopa Prabhu 
958f9c4bb0bSRoopa Prabhu 	tmsg = nlmsg_data(nlh);
959f9c4bb0bSRoopa Prabhu 	dev = __dev_get_by_index(net, tmsg->ifindex);
960f9c4bb0bSRoopa Prabhu 	if (!dev)
961f9c4bb0bSRoopa Prabhu 		return -ENODEV;
962f9c4bb0bSRoopa Prabhu 
963f9c4bb0bSRoopa Prabhu 	if (!netif_is_vxlan(dev)) {
964f9c4bb0bSRoopa Prabhu 		NL_SET_ERR_MSG_MOD(extack, "The device is not a vxlan device");
965f9c4bb0bSRoopa Prabhu 		return -EINVAL;
966f9c4bb0bSRoopa Prabhu 	}
967f9c4bb0bSRoopa Prabhu 
968f9c4bb0bSRoopa Prabhu 	vxlan = netdev_priv(dev);
969f9c4bb0bSRoopa Prabhu 
970f9c4bb0bSRoopa Prabhu 	if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER))
971f9c4bb0bSRoopa Prabhu 		return -EOPNOTSUPP;
972f9c4bb0bSRoopa Prabhu 
973f9c4bb0bSRoopa Prabhu 	nlmsg_for_each_attr(attr, nlh, sizeof(*tmsg), rem) {
974f9c4bb0bSRoopa Prabhu 		switch (nla_type(attr)) {
975f9c4bb0bSRoopa Prabhu 		case VXLAN_VNIFILTER_ENTRY:
976f9c4bb0bSRoopa Prabhu 			err = vxlan_process_vni_filter(vxlan, attr,
977f9c4bb0bSRoopa Prabhu 						       nlh->nlmsg_type, extack);
978f9c4bb0bSRoopa Prabhu 			break;
979f9c4bb0bSRoopa Prabhu 		default:
980f9c4bb0bSRoopa Prabhu 			continue;
981f9c4bb0bSRoopa Prabhu 		}
982f9c4bb0bSRoopa Prabhu 		vnis++;
983f9c4bb0bSRoopa Prabhu 		if (err)
984f9c4bb0bSRoopa Prabhu 			break;
985f9c4bb0bSRoopa Prabhu 	}
986f9c4bb0bSRoopa Prabhu 
987f9c4bb0bSRoopa Prabhu 	if (!vnis) {
988f9c4bb0bSRoopa Prabhu 		NL_SET_ERR_MSG_MOD(extack, "No vnis found to process");
989f9c4bb0bSRoopa Prabhu 		err = -EINVAL;
990f9c4bb0bSRoopa Prabhu 	}
991f9c4bb0bSRoopa Prabhu 
992f9c4bb0bSRoopa Prabhu 	return err;
993f9c4bb0bSRoopa Prabhu }
994f9c4bb0bSRoopa Prabhu 
vxlan_vnifilter_init(void)995f9c4bb0bSRoopa Prabhu void vxlan_vnifilter_init(void)
996f9c4bb0bSRoopa Prabhu {
997f9c4bb0bSRoopa Prabhu 	rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETTUNNEL, NULL,
998f9c4bb0bSRoopa Prabhu 			     vxlan_vnifilter_dump, 0);
999f9c4bb0bSRoopa Prabhu 	rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_NEWTUNNEL,
1000f9c4bb0bSRoopa Prabhu 			     vxlan_vnifilter_process, NULL, 0);
1001f9c4bb0bSRoopa Prabhu 	rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_DELTUNNEL,
1002f9c4bb0bSRoopa Prabhu 			     vxlan_vnifilter_process, NULL, 0);
1003f9c4bb0bSRoopa Prabhu }
1004f9c4bb0bSRoopa Prabhu 
vxlan_vnifilter_uninit(void)1005f9c4bb0bSRoopa Prabhu void vxlan_vnifilter_uninit(void)
1006f9c4bb0bSRoopa Prabhu {
1007f9c4bb0bSRoopa Prabhu 	rtnl_unregister(PF_BRIDGE, RTM_GETTUNNEL);
1008f9c4bb0bSRoopa Prabhu 	rtnl_unregister(PF_BRIDGE, RTM_NEWTUNNEL);
1009f9c4bb0bSRoopa Prabhu 	rtnl_unregister(PF_BRIDGE, RTM_DELTUNNEL);
1010f9c4bb0bSRoopa Prabhu }
1011