@@ -192,7 +192,7 @@ static char *gen_eth_tnl_hdr(char *buf, struct net_device *dev,
char *ip;
ether_addr_copy(eth->h_dest, e->h_dest);
- ether_addr_copy(eth->h_source, dev->dev_addr);
+ ether_addr_copy(eth->h_source, e->h_source);
if (is_vlan_dev(dev)) {
struct vlan_hdr *vlan = (struct vlan_hdr *)
((char *)eth + ETH_HLEN);
@@ -256,6 +256,7 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv,
e->m_neigh.family = n->ops->family;
memcpy(&e->m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
e->out_dev = out_dev;
+ e->route_dev = route_dev;
/* It's important to add the neigh to the hash table before checking
* the neigh validity state. So if we'll get a notification, in case the
@@ -270,6 +271,8 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv,
nud_state = n->nud_state;
ether_addr_copy(e->h_dest, n->ha);
read_unlock_bh(&n->lock);
+
+ ether_addr_copy(e->h_source, route_dev->dev_addr);
/* add ethernet header */
ip = (struct iphdr *)gen_eth_tnl_hdr(encap_header, route_dev, e,
@@ -581,19 +581,24 @@ static void mlx5e_rep_neigh_entry_release(struct mlx5e_neigh_hash_entry *nhe)
static void mlx5e_rep_update_flows(struct mlx5e_priv *priv,
struct mlx5e_encap_entry *e,
bool neigh_connected,
- unsigned char ha[ETH_ALEN])
+ unsigned char ha[ETH_ALEN],
+ bool source_mac_changed)
{
struct ethhdr *eth = (struct ethhdr *)e->encap_header;
ASSERT_RTNL();
if ((e->flags & MLX5_ENCAP_ENTRY_VALID) &&
- (!neigh_connected || !ether_addr_equal(e->h_dest, ha)))
+ (!neigh_connected ||
+ !ether_addr_equal(e->h_dest, ha) ||
+ source_mac_changed))
mlx5e_tc_encap_flows_del(priv, e);
- if (neigh_connected && !(e->flags & MLX5_ENCAP_ENTRY_VALID)) {
+ if (!(e->flags & MLX5_ENCAP_ENTRY_VALID) &&
+ (neigh_connected || source_mac_changed)) {
ether_addr_copy(e->h_dest, ha);
ether_addr_copy(eth->h_dest, ha);
+ ether_addr_copy(eth->h_source, e->route_dev->dev_addr);
mlx5e_tc_encap_flows_add(priv, e);
}
@@ -609,7 +614,9 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
struct mlx5e_priv *priv;
bool neigh_connected;
bool encap_connected;
+ bool source_mac_changed;
u8 nud_state, dead;
+ struct net_device *netdev;
rtnl_lock();
@@ -622,17 +629,20 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
memcpy(ha, n->ha, ETH_ALEN);
nud_state = n->nud_state;
dead = n->dead;
+ netdev = n->dev;
read_unlock_bh(&n->lock);
neigh_connected = (nud_state & NUD_VALID) && !dead;
+ source_mac_changed = (e->h_source == netdev) && !ether_addr_equal(e->h_source, netdev->dev_addr);
list_for_each_entry(e, &nhe->encap_list, encap_list) {
encap_connected = !!(e->flags & MLX5_ENCAP_ENTRY_VALID);
priv = netdev_priv(e->out_dev);
if (encap_connected != neigh_connected ||
- !ether_addr_equal(e->h_dest, ha))
- mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
+ !ether_addr_equal(e->h_dest, ha) ||
+ source_mac_changed)
+ mlx5e_rep_update_flows(priv, e, neigh_connected, ha, source_mac_changed);
}
mlx5e_rep_neigh_entry_release(nhe);
rtnl_unlock();
@@ -146,8 +146,10 @@ struct mlx5e_encap_entry {
u32 encap_id;
struct ip_tunnel_info tun_info;
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
+ unsigned char h_source[ETH_ALEN];
struct net_device *out_dev;
+ struct net_device *route_dev;
int tunnel_type;
int tunnel_hlen;
int reformat_type;