mirror of https://gitee.com/openkylin/linux.git
i40iw: Add IP addr handling on netdev events
Disable listeners and disconnect all connected QPs on a netdev interface down event. On an interface up event, the listeners are re-enabled. Signed-off-by: Mustafa Ismail <mustafa.ismail@intel.com> Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
parent
d59659340c
commit
e5e74b61b1
|
@ -1556,9 +1556,15 @@ static enum i40iw_status_code i40iw_del_multiple_qhash(
|
||||||
memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
|
memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
|
||||||
sizeof(cm_info->loc_addr));
|
sizeof(cm_info->loc_addr));
|
||||||
cm_info->vlan_id = child_listen_node->vlan_id;
|
cm_info->vlan_id = child_listen_node->vlan_id;
|
||||||
ret = i40iw_manage_qhash(iwdev, cm_info,
|
if (child_listen_node->qhash_set) {
|
||||||
I40IW_QHASH_TYPE_TCP_SYN,
|
ret = i40iw_manage_qhash(iwdev, cm_info,
|
||||||
I40IW_QHASH_MANAGE_TYPE_DELETE, NULL, false);
|
I40IW_QHASH_TYPE_TCP_SYN,
|
||||||
|
I40IW_QHASH_MANAGE_TYPE_DELETE,
|
||||||
|
NULL, false);
|
||||||
|
child_listen_node->qhash_set = false;
|
||||||
|
} else {
|
||||||
|
ret = I40IW_SUCCESS;
|
||||||
|
}
|
||||||
i40iw_debug(&iwdev->sc_dev,
|
i40iw_debug(&iwdev->sc_dev,
|
||||||
I40IW_DEBUG_CM,
|
I40IW_DEBUG_CM,
|
||||||
"freed pointer = %p\n",
|
"freed pointer = %p\n",
|
||||||
|
@ -1687,6 +1693,7 @@ static enum i40iw_status_code i40iw_add_mqh_6(struct i40iw_device *iwdev,
|
||||||
I40IW_QHASH_MANAGE_TYPE_ADD,
|
I40IW_QHASH_MANAGE_TYPE_ADD,
|
||||||
NULL, true);
|
NULL, true);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
child_listen_node->qhash_set = true;
|
||||||
spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
|
spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
|
||||||
list_add(&child_listen_node->child_listen_list,
|
list_add(&child_listen_node->child_listen_list,
|
||||||
&cm_parent_listen_node->child_listen_list);
|
&cm_parent_listen_node->child_listen_list);
|
||||||
|
@ -1765,6 +1772,7 @@ static enum i40iw_status_code i40iw_add_mqh_4(
|
||||||
NULL,
|
NULL,
|
||||||
true);
|
true);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
child_listen_node->qhash_set = true;
|
||||||
spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
|
spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
|
||||||
list_add(&child_listen_node->child_listen_list,
|
list_add(&child_listen_node->child_listen_list,
|
||||||
&cm_parent_listen_node->child_listen_list);
|
&cm_parent_listen_node->child_listen_list);
|
||||||
|
@ -4129,6 +4137,73 @@ static void i40iw_cm_post_event(struct i40iw_cm_event *event)
|
||||||
queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
|
queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i40iw_qhash_ctrl - enable/disable qhash for list
|
||||||
|
* @iwdev: device pointer
|
||||||
|
* @parent_listen_node: parent listen node
|
||||||
|
* @nfo: cm info node
|
||||||
|
* @ipaddr: Pointer to IPv4 or IPv6 address
|
||||||
|
* @ipv4: flag indicating IPv4 when true
|
||||||
|
* @ifup: flag indicating interface up when true
|
||||||
|
*
|
||||||
|
* Enables or disables the qhash for the node in the child
|
||||||
|
* listen list that matches ipaddr. If no matching IP was found
|
||||||
|
* it will allocate and add a new child listen node to the
|
||||||
|
* parent listen node. The listen_list_lock is assumed to be
|
||||||
|
* held when called.
|
||||||
|
*/
|
||||||
|
static void i40iw_qhash_ctrl(struct i40iw_device *iwdev,
|
||||||
|
struct i40iw_cm_listener *parent_listen_node,
|
||||||
|
struct i40iw_cm_info *nfo,
|
||||||
|
u32 *ipaddr, bool ipv4, bool ifup)
|
||||||
|
{
|
||||||
|
struct list_head *child_listen_list = &parent_listen_node->child_listen_list;
|
||||||
|
struct i40iw_cm_listener *child_listen_node;
|
||||||
|
struct list_head *pos, *tpos;
|
||||||
|
enum i40iw_status_code ret;
|
||||||
|
bool node_allocated = false;
|
||||||
|
enum i40iw_quad_hash_manage_type op =
|
||||||
|
ifup ? I40IW_QHASH_MANAGE_TYPE_ADD : I40IW_QHASH_MANAGE_TYPE_DELETE;
|
||||||
|
|
||||||
|
list_for_each_safe(pos, tpos, child_listen_list) {
|
||||||
|
child_listen_node =
|
||||||
|
list_entry(pos,
|
||||||
|
struct i40iw_cm_listener,
|
||||||
|
child_listen_list);
|
||||||
|
if (!memcmp(child_listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16))
|
||||||
|
goto set_qhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if not found then add a child listener if interface is going up */
|
||||||
|
if (!ifup)
|
||||||
|
return;
|
||||||
|
child_listen_node = kzalloc(sizeof(*child_listen_node), GFP_ATOMIC);
|
||||||
|
if (!child_listen_node)
|
||||||
|
return;
|
||||||
|
node_allocated = true;
|
||||||
|
memcpy(child_listen_node, parent_listen_node, sizeof(*child_listen_node));
|
||||||
|
|
||||||
|
memcpy(child_listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16);
|
||||||
|
|
||||||
|
set_qhash:
|
||||||
|
memcpy(nfo->loc_addr,
|
||||||
|
child_listen_node->loc_addr,
|
||||||
|
sizeof(nfo->loc_addr));
|
||||||
|
nfo->vlan_id = child_listen_node->vlan_id;
|
||||||
|
ret = i40iw_manage_qhash(iwdev, nfo,
|
||||||
|
I40IW_QHASH_TYPE_TCP_SYN,
|
||||||
|
op,
|
||||||
|
NULL, false);
|
||||||
|
if (!ret) {
|
||||||
|
child_listen_node->qhash_set = ifup;
|
||||||
|
if (node_allocated)
|
||||||
|
list_add(&child_listen_node->child_listen_list,
|
||||||
|
&parent_listen_node->child_listen_list);
|
||||||
|
} else if (node_allocated) {
|
||||||
|
kfree(child_listen_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* i40iw_cm_disconnect_all - disconnect all connected qp's
|
* i40iw_cm_disconnect_all - disconnect all connected qp's
|
||||||
* @iwdev: device pointer
|
* @iwdev: device pointer
|
||||||
|
@ -4159,3 +4234,60 @@ void i40iw_cm_disconnect_all(struct i40iw_device *iwdev)
|
||||||
i40iw_rem_ref_cm_node(cm_node);
|
i40iw_rem_ref_cm_node(cm_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i40iw_ifdown_notify - process an ifdown on an interface
|
||||||
|
* @iwdev: device pointer
|
||||||
|
* @ipaddr: Pointer to IPv4 or IPv6 address
|
||||||
|
* @ipv4: flag indicating IPv4 when true
|
||||||
|
* @ifup: flag indicating interface up when true
|
||||||
|
*/
|
||||||
|
void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev,
|
||||||
|
u32 *ipaddr, bool ipv4, bool ifup)
|
||||||
|
{
|
||||||
|
struct i40iw_cm_core *cm_core = &iwdev->cm_core;
|
||||||
|
unsigned long flags;
|
||||||
|
struct i40iw_cm_listener *listen_node;
|
||||||
|
static const u32 ip_zero[4] = { 0, 0, 0, 0 };
|
||||||
|
struct i40iw_cm_info nfo;
|
||||||
|
u16 vlan_id = rdma_vlan_dev_vlan_id(netdev);
|
||||||
|
enum i40iw_status_code ret;
|
||||||
|
enum i40iw_quad_hash_manage_type op =
|
||||||
|
ifup ? I40IW_QHASH_MANAGE_TYPE_ADD : I40IW_QHASH_MANAGE_TYPE_DELETE;
|
||||||
|
|
||||||
|
/* Disable or enable qhash for listeners */
|
||||||
|
spin_lock_irqsave(&cm_core->listen_list_lock, flags);
|
||||||
|
list_for_each_entry(listen_node, &cm_core->listen_nodes, list) {
|
||||||
|
if (vlan_id == listen_node->vlan_id &&
|
||||||
|
(!memcmp(listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16) ||
|
||||||
|
!memcmp(listen_node->loc_addr, ip_zero, ipv4 ? 4 : 16))) {
|
||||||
|
memcpy(nfo.loc_addr, listen_node->loc_addr,
|
||||||
|
sizeof(nfo.loc_addr));
|
||||||
|
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;
|
||||||
|
if (!list_empty(&listen_node->child_listen_list)) {
|
||||||
|
i40iw_qhash_ctrl(iwdev,
|
||||||
|
listen_node,
|
||||||
|
&nfo,
|
||||||
|
ipaddr, ipv4, ifup);
|
||||||
|
} else if (memcmp(listen_node->loc_addr, ip_zero,
|
||||||
|
ipv4 ? 4 : 16)) {
|
||||||
|
ret = i40iw_manage_qhash(iwdev,
|
||||||
|
&nfo,
|
||||||
|
I40IW_QHASH_TYPE_TCP_SYN,
|
||||||
|
op,
|
||||||
|
NULL,
|
||||||
|
false);
|
||||||
|
if (!ret)
|
||||||
|
listen_node->qhash_set = ifup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
|
||||||
|
|
||||||
|
/* disconnect any connected qp's on ifdown */
|
||||||
|
if (!ifup)
|
||||||
|
i40iw_cm_disconnect_all(iwdev);
|
||||||
|
}
|
||||||
|
|
|
@ -444,5 +444,7 @@ int i40iw_arp_table(struct i40iw_device *iwdev,
|
||||||
u8 *mac_addr,
|
u8 *mac_addr,
|
||||||
u32 action);
|
u32 action);
|
||||||
|
|
||||||
|
void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev,
|
||||||
|
u32 *ipaddr, bool ipv4, bool ifup);
|
||||||
void i40iw_cm_disconnect_all(struct i40iw_device *iwdev);
|
void i40iw_cm_disconnect_all(struct i40iw_device *iwdev);
|
||||||
#endif /* I40IW_CM_H */
|
#endif /* I40IW_CM_H */
|
||||||
|
|
|
@ -153,6 +153,7 @@ int i40iw_inetaddr_event(struct notifier_block *notifier,
|
||||||
struct i40iw_device *iwdev;
|
struct i40iw_device *iwdev;
|
||||||
struct i40iw_handler *hdl;
|
struct i40iw_handler *hdl;
|
||||||
u32 local_ipaddr;
|
u32 local_ipaddr;
|
||||||
|
u32 action = I40IW_ARP_ADD;
|
||||||
|
|
||||||
hdl = i40iw_find_netdev(event_netdev);
|
hdl = i40iw_find_netdev(event_netdev);
|
||||||
if (!hdl)
|
if (!hdl)
|
||||||
|
@ -164,44 +165,25 @@ int i40iw_inetaddr_event(struct notifier_block *notifier,
|
||||||
if (netdev != event_netdev)
|
if (netdev != event_netdev)
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
|
|
||||||
|
if (upper_dev)
|
||||||
|
local_ipaddr = ntohl(
|
||||||
|
((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address);
|
||||||
|
else
|
||||||
|
local_ipaddr = ntohl(ifa->ifa_address);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NETDEV_DOWN:
|
case NETDEV_DOWN:
|
||||||
if (upper_dev)
|
action = I40IW_ARP_DELETE;
|
||||||
local_ipaddr = ntohl(
|
/* Fall through */
|
||||||
((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address);
|
|
||||||
else
|
|
||||||
local_ipaddr = ntohl(ifa->ifa_address);
|
|
||||||
i40iw_manage_arp_cache(iwdev,
|
|
||||||
netdev->dev_addr,
|
|
||||||
&local_ipaddr,
|
|
||||||
true,
|
|
||||||
I40IW_ARP_DELETE);
|
|
||||||
return NOTIFY_OK;
|
|
||||||
case NETDEV_UP:
|
case NETDEV_UP:
|
||||||
if (upper_dev)
|
/* Fall through */
|
||||||
local_ipaddr = ntohl(
|
|
||||||
((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address);
|
|
||||||
else
|
|
||||||
local_ipaddr = ntohl(ifa->ifa_address);
|
|
||||||
i40iw_manage_arp_cache(iwdev,
|
|
||||||
netdev->dev_addr,
|
|
||||||
&local_ipaddr,
|
|
||||||
true,
|
|
||||||
I40IW_ARP_ADD);
|
|
||||||
break;
|
|
||||||
case NETDEV_CHANGEADDR:
|
case NETDEV_CHANGEADDR:
|
||||||
/* Add the address to the IP table */
|
|
||||||
if (upper_dev)
|
|
||||||
local_ipaddr = ntohl(
|
|
||||||
((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address);
|
|
||||||
else
|
|
||||||
local_ipaddr = ntohl(ifa->ifa_address);
|
|
||||||
|
|
||||||
i40iw_manage_arp_cache(iwdev,
|
i40iw_manage_arp_cache(iwdev,
|
||||||
netdev->dev_addr,
|
netdev->dev_addr,
|
||||||
&local_ipaddr,
|
&local_ipaddr,
|
||||||
true,
|
true,
|
||||||
I40IW_ARP_ADD);
|
action);
|
||||||
|
i40iw_if_notify(iwdev, netdev, &local_ipaddr, true,
|
||||||
|
(action == I40IW_ARP_ADD) ? true : false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -225,6 +207,7 @@ int i40iw_inet6addr_event(struct notifier_block *notifier,
|
||||||
struct i40iw_device *iwdev;
|
struct i40iw_device *iwdev;
|
||||||
struct i40iw_handler *hdl;
|
struct i40iw_handler *hdl;
|
||||||
u32 local_ipaddr6[4];
|
u32 local_ipaddr6[4];
|
||||||
|
u32 action = I40IW_ARP_ADD;
|
||||||
|
|
||||||
hdl = i40iw_find_netdev(event_netdev);
|
hdl = i40iw_find_netdev(event_netdev);
|
||||||
if (!hdl)
|
if (!hdl)
|
||||||
|
@ -235,24 +218,21 @@ int i40iw_inet6addr_event(struct notifier_block *notifier,
|
||||||
if (netdev != event_netdev)
|
if (netdev != event_netdev)
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
|
|
||||||
|
i40iw_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NETDEV_DOWN:
|
case NETDEV_DOWN:
|
||||||
i40iw_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32);
|
action = I40IW_ARP_DELETE;
|
||||||
i40iw_manage_arp_cache(iwdev,
|
/* Fall through */
|
||||||
netdev->dev_addr,
|
|
||||||
local_ipaddr6,
|
|
||||||
false,
|
|
||||||
I40IW_ARP_DELETE);
|
|
||||||
return NOTIFY_OK;
|
|
||||||
case NETDEV_UP:
|
case NETDEV_UP:
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
case NETDEV_CHANGEADDR:
|
case NETDEV_CHANGEADDR:
|
||||||
i40iw_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32);
|
|
||||||
i40iw_manage_arp_cache(iwdev,
|
i40iw_manage_arp_cache(iwdev,
|
||||||
netdev->dev_addr,
|
netdev->dev_addr,
|
||||||
local_ipaddr6,
|
local_ipaddr6,
|
||||||
false,
|
false,
|
||||||
I40IW_ARP_ADD);
|
action);
|
||||||
|
i40iw_if_notify(iwdev, netdev, local_ipaddr6, false,
|
||||||
|
(action == I40IW_ARP_ADD) ? true : false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue