176fc217dSRoopa Prabhu /* SPDX-License-Identifier: GPL-2.0 */
276fc217dSRoopa Prabhu /*
376fc217dSRoopa Prabhu  *	Vxlan private header file
476fc217dSRoopa Prabhu  *
576fc217dSRoopa Prabhu  */
676fc217dSRoopa Prabhu 
776fc217dSRoopa Prabhu #ifndef _VXLAN_PRIVATE_H
876fc217dSRoopa Prabhu #define _VXLAN_PRIVATE_H
976fc217dSRoopa Prabhu 
10f9c4bb0bSRoopa Prabhu #include <linux/rhashtable.h>
11f9c4bb0bSRoopa Prabhu 
1276fc217dSRoopa Prabhu extern unsigned int vxlan_net_id;
1376fc217dSRoopa Prabhu extern const u8 all_zeros_mac[ETH_ALEN + 2];
14f9c4bb0bSRoopa Prabhu extern const struct rhashtable_params vxlan_vni_rht_params;
1576fc217dSRoopa Prabhu 
1676fc217dSRoopa Prabhu #define PORT_HASH_BITS	8
1776fc217dSRoopa Prabhu #define PORT_HASH_SIZE  (1 << PORT_HASH_BITS)
1876fc217dSRoopa Prabhu 
1976fc217dSRoopa Prabhu /* per-network namespace private data for this module */
2076fc217dSRoopa Prabhu struct vxlan_net {
2176fc217dSRoopa Prabhu 	struct list_head  vxlan_list;
2276fc217dSRoopa Prabhu 	struct hlist_head sock_list[PORT_HASH_SIZE];
2376fc217dSRoopa Prabhu 	spinlock_t	  sock_lock;
2476fc217dSRoopa Prabhu 	struct notifier_block nexthop_notifier_block;
2576fc217dSRoopa Prabhu };
2676fc217dSRoopa Prabhu 
2776fc217dSRoopa Prabhu /* Forwarding table entry */
2876fc217dSRoopa Prabhu struct vxlan_fdb {
2976fc217dSRoopa Prabhu 	struct hlist_node hlist;	/* linked list of entries */
3076fc217dSRoopa Prabhu 	struct rcu_head	  rcu;
3176fc217dSRoopa Prabhu 	unsigned long	  updated;	/* jiffies */
3276fc217dSRoopa Prabhu 	unsigned long	  used;
3376fc217dSRoopa Prabhu 	struct list_head  remotes;
3476fc217dSRoopa Prabhu 	u8		  eth_addr[ETH_ALEN];
3576fc217dSRoopa Prabhu 	u16		  state;	/* see ndm_state */
3676fc217dSRoopa Prabhu 	__be32		  vni;
3776fc217dSRoopa Prabhu 	u16		  flags;	/* see ndm_flags and below */
3876fc217dSRoopa Prabhu 	struct list_head  nh_list;
3976fc217dSRoopa Prabhu 	struct nexthop __rcu *nh;
4076fc217dSRoopa Prabhu 	struct vxlan_dev  __rcu *vdev;
4176fc217dSRoopa Prabhu };
4276fc217dSRoopa Prabhu 
4376fc217dSRoopa Prabhu #define NTF_VXLAN_ADDED_BY_USER 0x100
4476fc217dSRoopa Prabhu 
4576fc217dSRoopa Prabhu /* Virtual Network hash table head */
vni_head(struct vxlan_sock * vs,__be32 vni)4676fc217dSRoopa Prabhu static inline struct hlist_head *vni_head(struct vxlan_sock *vs, __be32 vni)
4776fc217dSRoopa Prabhu {
4876fc217dSRoopa Prabhu 	return &vs->vni_list[hash_32((__force u32)vni, VNI_HASH_BITS)];
4976fc217dSRoopa Prabhu }
5076fc217dSRoopa Prabhu 
5176fc217dSRoopa Prabhu /* Socket hash table head */
vs_head(struct net * net,__be16 port)5276fc217dSRoopa Prabhu static inline struct hlist_head *vs_head(struct net *net, __be16 port)
5376fc217dSRoopa Prabhu {
5476fc217dSRoopa Prabhu 	struct vxlan_net *vn = net_generic(net, vxlan_net_id);
5576fc217dSRoopa Prabhu 
5676fc217dSRoopa Prabhu 	return &vn->sock_list[hash_32(ntohs(port), PORT_HASH_BITS)];
5776fc217dSRoopa Prabhu }
5876fc217dSRoopa Prabhu 
5976fc217dSRoopa Prabhu /* First remote destination for a forwarding entry.
6076fc217dSRoopa Prabhu  * Guaranteed to be non-NULL because remotes are never deleted.
6176fc217dSRoopa Prabhu  */
first_remote_rcu(struct vxlan_fdb * fdb)6276fc217dSRoopa Prabhu static inline struct vxlan_rdst *first_remote_rcu(struct vxlan_fdb *fdb)
6376fc217dSRoopa Prabhu {
6476fc217dSRoopa Prabhu 	if (rcu_access_pointer(fdb->nh))
6576fc217dSRoopa Prabhu 		return NULL;
6676fc217dSRoopa Prabhu 	return list_entry_rcu(fdb->remotes.next, struct vxlan_rdst, list);
6776fc217dSRoopa Prabhu }
6876fc217dSRoopa Prabhu 
first_remote_rtnl(struct vxlan_fdb * fdb)6976fc217dSRoopa Prabhu static inline struct vxlan_rdst *first_remote_rtnl(struct vxlan_fdb *fdb)
7076fc217dSRoopa Prabhu {
7176fc217dSRoopa Prabhu 	if (rcu_access_pointer(fdb->nh))
7276fc217dSRoopa Prabhu 		return NULL;
7376fc217dSRoopa Prabhu 	return list_first_entry(&fdb->remotes, struct vxlan_rdst, list);
7476fc217dSRoopa Prabhu }
7576fc217dSRoopa Prabhu 
7676fc217dSRoopa Prabhu #if IS_ENABLED(CONFIG_IPV6)
7776fc217dSRoopa Prabhu static inline
vxlan_addr_equal(const union vxlan_addr * a,const union vxlan_addr * b)7876fc217dSRoopa Prabhu bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
7976fc217dSRoopa Prabhu {
8076fc217dSRoopa Prabhu 	if (a->sa.sa_family != b->sa.sa_family)
8176fc217dSRoopa Prabhu 		return false;
8276fc217dSRoopa Prabhu 	if (a->sa.sa_family == AF_INET6)
8376fc217dSRoopa Prabhu 		return ipv6_addr_equal(&a->sin6.sin6_addr, &b->sin6.sin6_addr);
8476fc217dSRoopa Prabhu 	else
8576fc217dSRoopa Prabhu 		return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
8676fc217dSRoopa Prabhu }
8776fc217dSRoopa Prabhu 
vxlan_nla_get_addr(union vxlan_addr * ip,const struct nlattr * nla)88f307c8bfSIdo Schimmel static inline int vxlan_nla_get_addr(union vxlan_addr *ip,
89f307c8bfSIdo Schimmel 				     const struct nlattr *nla)
90f307c8bfSIdo Schimmel {
91f307c8bfSIdo Schimmel 	if (nla_len(nla) >= sizeof(struct in6_addr)) {
92f307c8bfSIdo Schimmel 		ip->sin6.sin6_addr = nla_get_in6_addr(nla);
93f307c8bfSIdo Schimmel 		ip->sa.sa_family = AF_INET6;
94f307c8bfSIdo Schimmel 		return 0;
95f307c8bfSIdo Schimmel 	} else if (nla_len(nla) >= sizeof(__be32)) {
96f307c8bfSIdo Schimmel 		ip->sin.sin_addr.s_addr = nla_get_in_addr(nla);
97f307c8bfSIdo Schimmel 		ip->sa.sa_family = AF_INET;
98f307c8bfSIdo Schimmel 		return 0;
99f307c8bfSIdo Schimmel 	} else {
100f307c8bfSIdo Schimmel 		return -EAFNOSUPPORT;
101f307c8bfSIdo Schimmel 	}
102f307c8bfSIdo Schimmel }
103f307c8bfSIdo Schimmel 
vxlan_nla_put_addr(struct sk_buff * skb,int attr,const union vxlan_addr * ip)104f307c8bfSIdo Schimmel static inline int vxlan_nla_put_addr(struct sk_buff *skb, int attr,
105f307c8bfSIdo Schimmel 				     const union vxlan_addr *ip)
106f307c8bfSIdo Schimmel {
107f307c8bfSIdo Schimmel 	if (ip->sa.sa_family == AF_INET6)
108f307c8bfSIdo Schimmel 		return nla_put_in6_addr(skb, attr, &ip->sin6.sin6_addr);
109f307c8bfSIdo Schimmel 	else
110f307c8bfSIdo Schimmel 		return nla_put_in_addr(skb, attr, ip->sin.sin_addr.s_addr);
111f307c8bfSIdo Schimmel }
112f307c8bfSIdo Schimmel 
vxlan_addr_is_multicast(const union vxlan_addr * ip)113a3a48de5SIdo Schimmel static inline bool vxlan_addr_is_multicast(const union vxlan_addr *ip)
114a3a48de5SIdo Schimmel {
115a3a48de5SIdo Schimmel 	if (ip->sa.sa_family == AF_INET6)
116a3a48de5SIdo Schimmel 		return ipv6_addr_is_multicast(&ip->sin6.sin6_addr);
117a3a48de5SIdo Schimmel 	else
118a3a48de5SIdo Schimmel 		return ipv4_is_multicast(ip->sin.sin_addr.s_addr);
119a3a48de5SIdo Schimmel }
120a3a48de5SIdo Schimmel 
12176fc217dSRoopa Prabhu #else /* !CONFIG_IPV6 */
12276fc217dSRoopa Prabhu 
12376fc217dSRoopa Prabhu static inline
vxlan_addr_equal(const union vxlan_addr * a,const union vxlan_addr * b)12476fc217dSRoopa Prabhu bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
12576fc217dSRoopa Prabhu {
12676fc217dSRoopa Prabhu 	return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
12776fc217dSRoopa Prabhu }
12876fc217dSRoopa Prabhu 
vxlan_nla_get_addr(union vxlan_addr * ip,const struct nlattr * nla)129f307c8bfSIdo Schimmel static inline int vxlan_nla_get_addr(union vxlan_addr *ip,
130f307c8bfSIdo Schimmel 				     const struct nlattr *nla)
131f307c8bfSIdo Schimmel {
132f307c8bfSIdo Schimmel 	if (nla_len(nla) >= sizeof(struct in6_addr)) {
133f307c8bfSIdo Schimmel 		return -EAFNOSUPPORT;
134f307c8bfSIdo Schimmel 	} else if (nla_len(nla) >= sizeof(__be32)) {
135f307c8bfSIdo Schimmel 		ip->sin.sin_addr.s_addr = nla_get_in_addr(nla);
136f307c8bfSIdo Schimmel 		ip->sa.sa_family = AF_INET;
137f307c8bfSIdo Schimmel 		return 0;
138f307c8bfSIdo Schimmel 	} else {
139f307c8bfSIdo Schimmel 		return -EAFNOSUPPORT;
140f307c8bfSIdo Schimmel 	}
141f307c8bfSIdo Schimmel }
142f307c8bfSIdo Schimmel 
vxlan_nla_put_addr(struct sk_buff * skb,int attr,const union vxlan_addr * ip)143f307c8bfSIdo Schimmel static inline int vxlan_nla_put_addr(struct sk_buff *skb, int attr,
144f307c8bfSIdo Schimmel 				     const union vxlan_addr *ip)
145f307c8bfSIdo Schimmel {
146f307c8bfSIdo Schimmel 	return nla_put_in_addr(skb, attr, ip->sin.sin_addr.s_addr);
147f307c8bfSIdo Schimmel }
148f307c8bfSIdo Schimmel 
vxlan_addr_is_multicast(const union vxlan_addr * ip)149a3a48de5SIdo Schimmel static inline bool vxlan_addr_is_multicast(const union vxlan_addr *ip)
150a3a48de5SIdo Schimmel {
151a3a48de5SIdo Schimmel 	return ipv4_is_multicast(ip->sin.sin_addr.s_addr);
152a3a48de5SIdo Schimmel }
153a3a48de5SIdo Schimmel 
15476fc217dSRoopa Prabhu #endif
15576fc217dSRoopa Prabhu 
vxlan_addr_size(const union vxlan_addr * ip)156a3a48de5SIdo Schimmel static inline size_t vxlan_addr_size(const union vxlan_addr *ip)
157a3a48de5SIdo Schimmel {
158a3a48de5SIdo Schimmel 	if (ip->sa.sa_family == AF_INET6)
159a3a48de5SIdo Schimmel 		return sizeof(struct in6_addr);
160a3a48de5SIdo Schimmel 	else
161a3a48de5SIdo Schimmel 		return sizeof(__be32);
162a3a48de5SIdo Schimmel }
163a3a48de5SIdo Schimmel 
164f9c4bb0bSRoopa Prabhu static inline struct vxlan_vni_node *
vxlan_vnifilter_lookup(struct vxlan_dev * vxlan,__be32 vni)165f9c4bb0bSRoopa Prabhu vxlan_vnifilter_lookup(struct vxlan_dev *vxlan, __be32 vni)
166f9c4bb0bSRoopa Prabhu {
167f9c4bb0bSRoopa Prabhu 	struct vxlan_vni_group *vg;
168f9c4bb0bSRoopa Prabhu 
169f9c4bb0bSRoopa Prabhu 	vg = rcu_dereference_rtnl(vxlan->vnigrp);
170f9c4bb0bSRoopa Prabhu 	if (!vg)
171f9c4bb0bSRoopa Prabhu 		return NULL;
172f9c4bb0bSRoopa Prabhu 
173f9c4bb0bSRoopa Prabhu 	return rhashtable_lookup_fast(&vg->vni_hash, &vni,
174f9c4bb0bSRoopa Prabhu 				      vxlan_vni_rht_params);
175f9c4bb0bSRoopa Prabhu }
176f9c4bb0bSRoopa Prabhu 
177c63053e0SRoopa Prabhu /* vxlan_core.c */
178c63053e0SRoopa Prabhu int vxlan_fdb_create(struct vxlan_dev *vxlan,
179c63053e0SRoopa Prabhu 		     const u8 *mac, union vxlan_addr *ip,
180c63053e0SRoopa Prabhu 		     __u16 state, __be16 port, __be32 src_vni,
181c63053e0SRoopa Prabhu 		     __be32 vni, __u32 ifindex, __u16 ndm_flags,
182c63053e0SRoopa Prabhu 		     u32 nhid, struct vxlan_fdb **fdb,
183c63053e0SRoopa Prabhu 		     struct netlink_ext_ack *extack);
184c63053e0SRoopa Prabhu int __vxlan_fdb_delete(struct vxlan_dev *vxlan,
185c63053e0SRoopa Prabhu 		       const unsigned char *addr, union vxlan_addr ip,
186c63053e0SRoopa Prabhu 		       __be16 port, __be32 src_vni, __be32 vni,
187c63053e0SRoopa Prabhu 		       u32 ifindex, bool swdev_notify);
188c63053e0SRoopa Prabhu u32 eth_vni_hash(const unsigned char *addr, __be32 vni);
189c63053e0SRoopa Prabhu u32 fdb_head_index(struct vxlan_dev *vxlan, const u8 *mac, __be32 vni);
190c63053e0SRoopa Prabhu int vxlan_fdb_update(struct vxlan_dev *vxlan,
191c63053e0SRoopa Prabhu 		     const u8 *mac, union vxlan_addr *ip,
192c63053e0SRoopa Prabhu 		     __u16 state, __u16 flags,
193c63053e0SRoopa Prabhu 		     __be16 port, __be32 src_vni, __be32 vni,
194c63053e0SRoopa Prabhu 		     __u32 ifindex, __u16 ndm_flags, u32 nhid,
195c63053e0SRoopa Prabhu 		     bool swdev_notify, struct netlink_ext_ack *extack);
1966ab271aaSIdo Schimmel void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
1976ab271aaSIdo Schimmel 		    __be32 default_vni, struct vxlan_rdst *rdst, bool did_rsc);
198f9c4bb0bSRoopa Prabhu int vxlan_vni_in_use(struct net *src_net, struct vxlan_dev *vxlan,
199f9c4bb0bSRoopa Prabhu 		     struct vxlan_config *conf, __be32 vni);
200f9c4bb0bSRoopa Prabhu 
201f9c4bb0bSRoopa Prabhu /* vxlan_vnifilter.c */
202f9c4bb0bSRoopa Prabhu int vxlan_vnigroup_init(struct vxlan_dev *vxlan);
203f9c4bb0bSRoopa Prabhu void vxlan_vnigroup_uninit(struct vxlan_dev *vxlan);
204f9c4bb0bSRoopa Prabhu 
205f9c4bb0bSRoopa Prabhu void vxlan_vnifilter_init(void);
206f9c4bb0bSRoopa Prabhu void vxlan_vnifilter_uninit(void);
2074095e0e1SNikolay Aleksandrov void vxlan_vnifilter_count(struct vxlan_dev *vxlan, __be32 vni,
2084095e0e1SNikolay Aleksandrov 			   struct vxlan_vni_node *vninode,
2094095e0e1SNikolay Aleksandrov 			   int type, unsigned int len);
210f9c4bb0bSRoopa Prabhu 
211f9c4bb0bSRoopa Prabhu void vxlan_vs_add_vnigrp(struct vxlan_dev *vxlan,
212f9c4bb0bSRoopa Prabhu 			 struct vxlan_sock *vs,
213f9c4bb0bSRoopa Prabhu 			 bool ipv6);
214f9c4bb0bSRoopa Prabhu void vxlan_vs_del_vnigrp(struct vxlan_dev *vxlan);
215f9c4bb0bSRoopa Prabhu int vxlan_vnilist_update_group(struct vxlan_dev *vxlan,
216f9c4bb0bSRoopa Prabhu 			       union vxlan_addr *old_remote_ip,
217f9c4bb0bSRoopa Prabhu 			       union vxlan_addr *new_remote_ip,
218f9c4bb0bSRoopa Prabhu 			       struct netlink_ext_ack *extack);
219f9c4bb0bSRoopa Prabhu 
220c63053e0SRoopa Prabhu 
221a498c595SRoopa Prabhu /* vxlan_multicast.c */
222f9c4bb0bSRoopa Prabhu int vxlan_multicast_join(struct vxlan_dev *vxlan);
223f9c4bb0bSRoopa Prabhu int vxlan_multicast_leave(struct vxlan_dev *vxlan);
224f9c4bb0bSRoopa Prabhu bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev,
225f9c4bb0bSRoopa Prabhu 		      __be32 vni, union vxlan_addr *rip, int rifindex);
226a498c595SRoopa Prabhu int vxlan_igmp_join(struct vxlan_dev *vxlan, union vxlan_addr *rip,
227a498c595SRoopa Prabhu 		    int rifindex);
228a498c595SRoopa Prabhu int vxlan_igmp_leave(struct vxlan_dev *vxlan, union vxlan_addr *rip,
229a498c595SRoopa Prabhu 		     int rifindex);
230a3a48de5SIdo Schimmel 
231a3a48de5SIdo Schimmel /* vxlan_mdb.c */
232a3a48de5SIdo Schimmel int vxlan_mdb_dump(struct net_device *dev, struct sk_buff *skb,
233a3a48de5SIdo Schimmel 		   struct netlink_callback *cb);
234a3a48de5SIdo Schimmel int vxlan_mdb_add(struct net_device *dev, struct nlattr *tb[], u16 nlmsg_flags,
235a3a48de5SIdo Schimmel 		  struct netlink_ext_ack *extack);
236a3a48de5SIdo Schimmel int vxlan_mdb_del(struct net_device *dev, struct nlattr *tb[],
237a3a48de5SIdo Schimmel 		  struct netlink_ext_ack *extack);
238*0f83e69fSIdo Schimmel struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
239*0f83e69fSIdo Schimmel 						struct sk_buff *skb,
240*0f83e69fSIdo Schimmel 						__be32 src_vni);
241*0f83e69fSIdo Schimmel netdev_tx_t vxlan_mdb_xmit(struct vxlan_dev *vxlan,
242*0f83e69fSIdo Schimmel 			   const struct vxlan_mdb_entry *mdb_entry,
243*0f83e69fSIdo Schimmel 			   struct sk_buff *skb);
244a3a48de5SIdo Schimmel int vxlan_mdb_init(struct vxlan_dev *vxlan);
245a3a48de5SIdo Schimmel void vxlan_mdb_fini(struct vxlan_dev *vxlan);
24676fc217dSRoopa Prabhu #endif
247