@ -389,8 +389,8 @@ static inline size_t vxlan_nlmsg_size(void)
+ nla_total_size ( sizeof ( struct nda_cacheinfo ) ) ;
}
static void vxlan_fdb_notify ( struct vxlan_dev * vxlan ,
struct vxlan_fdb * fdb , int type )
static void vxlan_fdb_notify ( struct vxlan_dev * vxlan , struct vxlan_fdb * fdb ,
struct vxlan_rdst * rd , int type )
{
struct net * net = dev_net ( vxlan - > dev ) ;
struct sk_buff * skb ;
@ -400,8 +400,7 @@ static void vxlan_fdb_notify(struct vxlan_dev *vxlan,
if ( skb = = NULL )
goto errout ;
err = vxlan_fdb_info ( skb , vxlan , fdb , 0 , 0 , type , 0 ,
first_remote_rtnl ( fdb ) ) ;
err = vxlan_fdb_info ( skb , vxlan , fdb , 0 , 0 , type , 0 , rd ) ;
if ( err < 0 ) {
/* -EMSGSIZE implies BUG in vxlan_nlmsg_size() */
WARN_ON ( err = = - EMSGSIZE ) ;
@ -427,10 +426,7 @@ static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa)
. remote_vni = VXLAN_N_VID ,
} ;
INIT_LIST_HEAD ( & f . remotes ) ;
list_add_rcu ( & remote . list , & f . remotes ) ;
vxlan_fdb_notify ( vxlan , & f , RTM_GETNEIGH ) ;
vxlan_fdb_notify ( vxlan , & f , & remote , RTM_GETNEIGH ) ;
}
static void vxlan_fdb_miss ( struct vxlan_dev * vxlan , const u8 eth_addr [ ETH_ALEN ] )
@ -438,11 +434,11 @@ static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN])
struct vxlan_fdb f = {
. state = NUD_STALE ,
} ;
struct vxlan_rdst remote = { } ;
INIT_LIST_HEAD ( & f . remotes ) ;
memcpy ( f . eth_addr , eth_addr , ETH_ALEN ) ;
vxlan_fdb_notify ( vxlan , & f , RTM_GETNEIGH ) ;
vxlan_fdb_notify ( vxlan , & f , & remote , RTM_GETNEIGH ) ;
}
/* Hash Ethernet address */
@ -533,7 +529,8 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,
/* Add/update destinations for multicast */
static int vxlan_fdb_append ( struct vxlan_fdb * f ,
union vxlan_addr * ip , __be16 port , __u32 vni , __u32 ifindex )
union vxlan_addr * ip , __be16 port , __u32 vni ,
__u32 ifindex , struct vxlan_rdst * * rdp )
{
struct vxlan_rdst * rd ;
@ -551,6 +548,7 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
list_add_tail_rcu ( & rd - > list , & f - > remotes ) ;
* rdp = rd ;
return 1 ;
}
@ -690,6 +688,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
__be16 port , __u32 vni , __u32 ifindex ,
__u8 ndm_flags )
{
struct vxlan_rdst * rd = NULL ;
struct vxlan_fdb * f ;
int notify = 0 ;
@ -726,7 +725,8 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
if ( ( flags & NLM_F_APPEND ) & &
( is_multicast_ether_addr ( f - > eth_addr ) | |
is_zero_ether_addr ( f - > eth_addr ) ) ) {
int rc = vxlan_fdb_append ( f , ip , port , vni , ifindex ) ;
int rc = vxlan_fdb_append ( f , ip , port , vni , ifindex ,
& rd ) ;
if ( rc < 0 )
return rc ;
@ -756,15 +756,18 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
INIT_LIST_HEAD ( & f - > remotes ) ;
memcpy ( f - > eth_addr , mac , ETH_ALEN ) ;
vxlan_fdb_append ( f , ip , port , vni , ifindex ) ;
vxlan_fdb_append ( f , ip , port , vni , ifindex , & rd ) ;
+ + vxlan - > addrcnt ;
hlist_add_head_rcu ( & f - > hlist ,
vxlan_fdb_head ( vxlan , mac ) ) ;
}
if ( notify )
vxlan_fdb_notify ( vxlan , f , RTM_NEWNEIGH ) ;
if ( notify ) {
if ( rd = = NULL )
rd = first_remote_rtnl ( f ) ;
vxlan_fdb_notify ( vxlan , f , rd , RTM_NEWNEIGH ) ;
}
return 0 ;
}
@ -785,7 +788,7 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f)
" delete %pM \n " , f - > eth_addr ) ;
- - vxlan - > addrcnt ;
vxlan_fdb_notify ( vxlan , f , RTM_DELNEIGH ) ;
vxlan_fdb_notify ( vxlan , f , first_remote_rtnl ( f ) , RTM_DELNEIGH ) ;
hlist_del_rcu ( & f - > hlist ) ;
call_rcu ( & f - > rcu , vxlan_fdb_free ) ;
@ -919,6 +922,7 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
*/
if ( rd & & ! list_is_singular ( & f - > remotes ) ) {
list_del_rcu ( & rd - > list ) ;
vxlan_fdb_notify ( vxlan , f , rd , RTM_DELNEIGH ) ;
kfree_rcu ( rd , rcu ) ;
goto out ;
}
@ -993,7 +997,7 @@ static bool vxlan_snoop(struct net_device *dev,
rdst - > remote_ip = * src_ip ;
f - > updated = jiffies ;
vxlan_fdb_notify ( vxlan , f , RTM_NEWNEIGH ) ;
vxlan_fdb_notify ( vxlan , f , rdst , RTM_NEWNEIGH ) ;
} else {
/* learned new entry */
spin_lock ( & vxlan - > hash_lock ) ;