Commit 3020f252 authored by Shiraz Saleem's avatar Shiraz Saleem Committed by Jason Gunthorpe

i40iw: Selectively teardown QPs on IP addr change event

On IP address change event, all connected QPs are torn down
irrespective of whether IP address is involved in a connection.

Only teardown connections those source or destination address
matches the netdev interface IP address being changed, and if
they are on the same VLAN as the netdev.

Fixes: e5e74b61 ("i40iw: Add IP addr handling on netdev events")
Signed-off-by: default avatarShiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent 0c5d5155
...@@ -4228,10 +4228,16 @@ static void i40iw_qhash_ctrl(struct i40iw_device *iwdev, ...@@ -4228,10 +4228,16 @@ static void i40iw_qhash_ctrl(struct i40iw_device *iwdev,
} }
/** /**
* i40iw_cm_disconnect_all - disconnect all connected qp's * i40iw_cm_teardown_connections - teardown QPs
* @iwdev: device pointer * @iwdev: device pointer
* @ipaddr: Pointer to IPv4 or IPv6 address
* @ipv4: flag indicating IPv4 when true
* @disconnect_all: flag indicating disconnect all QPs
* teardown QPs where source or destination addr matches ip addr
*/ */
void i40iw_cm_disconnect_all(struct i40iw_device *iwdev) void i40iw_cm_teardown_connections(struct i40iw_device *iwdev, u32 *ipaddr,
struct i40iw_cm_info *nfo,
bool disconnect_all)
{ {
struct i40iw_cm_core *cm_core = &iwdev->cm_core; struct i40iw_cm_core *cm_core = &iwdev->cm_core;
struct list_head *list_core_temp; struct list_head *list_core_temp;
...@@ -4245,9 +4251,14 @@ void i40iw_cm_disconnect_all(struct i40iw_device *iwdev) ...@@ -4245,9 +4251,14 @@ void i40iw_cm_disconnect_all(struct i40iw_device *iwdev)
spin_lock_irqsave(&cm_core->ht_lock, flags); spin_lock_irqsave(&cm_core->ht_lock, flags);
list_for_each_safe(list_node, list_core_temp, &cm_core->connected_nodes) { list_for_each_safe(list_node, list_core_temp, &cm_core->connected_nodes) {
cm_node = container_of(list_node, struct i40iw_cm_node, list); cm_node = container_of(list_node, struct i40iw_cm_node, list);
if (disconnect_all ||
(nfo->vlan_id == cm_node->vlan_id &&
(!memcmp(cm_node->loc_addr, ipaddr, nfo->ipv4 ? 4 : 16) ||
!memcmp(cm_node->rem_addr, ipaddr, nfo->ipv4 ? 4 : 16)))) {
atomic_inc(&cm_node->ref_count); atomic_inc(&cm_node->ref_count);
list_add(&cm_node->connected_entry, &connected_list); list_add(&cm_node->connected_entry, &connected_list);
} }
}
spin_unlock_irqrestore(&cm_core->ht_lock, flags); spin_unlock_irqrestore(&cm_core->ht_lock, flags);
list_for_each_safe(list_node, list_core_temp, &connected_list) { list_for_each_safe(list_node, list_core_temp, &connected_list) {
...@@ -4280,6 +4291,9 @@ void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev, ...@@ -4280,6 +4291,9 @@ void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev,
enum i40iw_quad_hash_manage_type op = enum i40iw_quad_hash_manage_type op =
ifup ? I40IW_QHASH_MANAGE_TYPE_ADD : I40IW_QHASH_MANAGE_TYPE_DELETE; ifup ? I40IW_QHASH_MANAGE_TYPE_ADD : I40IW_QHASH_MANAGE_TYPE_DELETE;
nfo.vlan_id = vlan_id;
nfo.ipv4 = ipv4;
/* Disable or enable qhash for listeners */ /* Disable or enable qhash for listeners */
spin_lock_irqsave(&cm_core->listen_list_lock, flags); spin_lock_irqsave(&cm_core->listen_list_lock, flags);
list_for_each_entry(listen_node, &cm_core->listen_nodes, list) { list_for_each_entry(listen_node, &cm_core->listen_nodes, list) {
...@@ -4289,8 +4303,6 @@ void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev, ...@@ -4289,8 +4303,6 @@ void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev,
memcpy(nfo.loc_addr, listen_node->loc_addr, memcpy(nfo.loc_addr, listen_node->loc_addr,
sizeof(nfo.loc_addr)); sizeof(nfo.loc_addr));
nfo.loc_port = listen_node->loc_port; nfo.loc_port = listen_node->loc_port;
nfo.ipv4 = listen_node->ipv4;
nfo.vlan_id = listen_node->vlan_id;
nfo.user_pri = listen_node->user_pri; nfo.user_pri = listen_node->user_pri;
if (!list_empty(&listen_node->child_listen_list)) { if (!list_empty(&listen_node->child_listen_list)) {
i40iw_qhash_ctrl(iwdev, i40iw_qhash_ctrl(iwdev,
...@@ -4312,7 +4324,7 @@ void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev, ...@@ -4312,7 +4324,7 @@ void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev,
} }
spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
/* disconnect any connected qp's on ifdown */ /* teardown connected qp's on ifdown */
if (!ifup) if (!ifup)
i40iw_cm_disconnect_all(iwdev); i40iw_cm_teardown_connections(iwdev, ipaddr, &nfo, false);
} }
...@@ -453,5 +453,7 @@ int i40iw_arp_table(struct i40iw_device *iwdev, ...@@ -453,5 +453,7 @@ int i40iw_arp_table(struct i40iw_device *iwdev,
void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev, void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev,
u32 *ipaddr, bool ipv4, bool ifup); u32 *ipaddr, bool ipv4, bool ifup);
void i40iw_cm_disconnect_all(struct i40iw_device *iwdev); void i40iw_cm_teardown_connections(struct i40iw_device *iwdev, u32 *ipaddr,
struct i40iw_cm_info *nfo,
bool disconnect_all);
#endif /* I40IW_CM_H */ #endif /* I40IW_CM_H */
...@@ -1800,7 +1800,7 @@ static void i40iw_close(struct i40e_info *ldev, struct i40e_client *client, bool ...@@ -1800,7 +1800,7 @@ static void i40iw_close(struct i40e_info *ldev, struct i40e_client *client, bool
if (reset) if (reset)
iwdev->reset = true; iwdev->reset = true;
i40iw_cm_disconnect_all(iwdev); i40iw_cm_teardown_connections(iwdev, NULL, NULL, true);
destroy_workqueue(iwdev->virtchnl_wq); destroy_workqueue(iwdev->virtchnl_wq);
i40iw_deinit_device(iwdev); i40iw_deinit_device(iwdev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment