mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-06 05:02:31 +00:00
qed: Add IP services APIs support
This patch introduces APIs which the NVMeTCP Offload device (qedn) will use through the paired net-device (qede). It includes APIs for: - ipv4/ipv6 routing - get VLAN from net-device - TCP ports reservation Acked-by: Igor Russkikh <irusskikh@marvell.com> Signed-off-by: Nikolay Assa <nassa@marvell.com> Signed-off-by: Prabhakar Kushwaha <pkushwaha@marvell.com> Signed-off-by: Omkar Kulkarni <okulkarni@marvell.com> Signed-off-by: Michal Kalderon <mkalderon@marvell.com> Signed-off-by: Ariel Elior <aelior@marvell.com> Signed-off-by: Shai Malin <smalin@marvell.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
826da48614
commit
806ee7f81a
238
drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c
Normal file
238
drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c
Normal file
@ -0,0 +1,238 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
/*
|
||||
* Copyright 2021 Marvell. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/param.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/qed/qed_nvmetcp_ip_services_if.h>
|
||||
|
||||
#define QED_IP_RESOL_TIMEOUT 4
|
||||
|
||||
int qed_route_ipv4(struct sockaddr_storage *local_addr,
|
||||
struct sockaddr_storage *remote_addr,
|
||||
struct sockaddr *hardware_address,
|
||||
struct net_device **ndev)
|
||||
{
|
||||
struct neighbour *neigh = NULL;
|
||||
__be32 *loc_ip, *rem_ip;
|
||||
struct rtable *rt;
|
||||
int rc = -ENXIO;
|
||||
int retry;
|
||||
|
||||
loc_ip = &((struct sockaddr_in *)local_addr)->sin_addr.s_addr;
|
||||
rem_ip = &((struct sockaddr_in *)remote_addr)->sin_addr.s_addr;
|
||||
*ndev = NULL;
|
||||
rt = ip_route_output(&init_net, *rem_ip, *loc_ip, 0/*tos*/, 0/*oif*/);
|
||||
if (IS_ERR(rt)) {
|
||||
pr_err("lookup route failed\n");
|
||||
rc = PTR_ERR(rt);
|
||||
goto return_err;
|
||||
}
|
||||
|
||||
neigh = dst_neigh_lookup(&rt->dst, rem_ip);
|
||||
if (!neigh) {
|
||||
rc = -ENOMEM;
|
||||
ip_rt_put(rt);
|
||||
goto return_err;
|
||||
}
|
||||
|
||||
*ndev = rt->dst.dev;
|
||||
ip_rt_put(rt);
|
||||
|
||||
/* If not resolved, kick-off state machine towards resolution */
|
||||
if (!(neigh->nud_state & NUD_VALID))
|
||||
neigh_event_send(neigh, NULL);
|
||||
|
||||
/* query neighbor until resolved or timeout */
|
||||
retry = QED_IP_RESOL_TIMEOUT;
|
||||
while (!(neigh->nud_state & NUD_VALID) && retry > 0) {
|
||||
msleep(1000);
|
||||
retry--;
|
||||
}
|
||||
|
||||
if (neigh->nud_state & NUD_VALID) {
|
||||
/* copy resolved MAC address */
|
||||
neigh_ha_snapshot(hardware_address->sa_data, neigh, *ndev);
|
||||
hardware_address->sa_family = (*ndev)->type;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
neigh_release(neigh);
|
||||
if (!(*loc_ip)) {
|
||||
*loc_ip = inet_select_addr(*ndev, *rem_ip, RT_SCOPE_UNIVERSE);
|
||||
local_addr->ss_family = AF_INET;
|
||||
}
|
||||
|
||||
return_err:
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(qed_route_ipv4);
|
||||
|
||||
int qed_route_ipv6(struct sockaddr_storage *local_addr,
|
||||
struct sockaddr_storage *remote_addr,
|
||||
struct sockaddr *hardware_address,
|
||||
struct net_device **ndev)
|
||||
{
|
||||
struct neighbour *neigh = NULL;
|
||||
struct dst_entry *dst;
|
||||
struct flowi6 fl6;
|
||||
int rc = -ENXIO;
|
||||
int retry;
|
||||
|
||||
memset(&fl6, 0, sizeof(fl6));
|
||||
fl6.saddr = ((struct sockaddr_in6 *)local_addr)->sin6_addr;
|
||||
fl6.daddr = ((struct sockaddr_in6 *)remote_addr)->sin6_addr;
|
||||
dst = ip6_route_output(&init_net, NULL, &fl6);
|
||||
if (!dst || dst->error) {
|
||||
if (dst) {
|
||||
dst_release(dst);
|
||||
pr_err("lookup route failed %d\n", dst->error);
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
neigh = dst_neigh_lookup(dst, &fl6.daddr);
|
||||
if (neigh) {
|
||||
*ndev = ip6_dst_idev(dst)->dev;
|
||||
|
||||
/* If not resolved, kick-off state machine towards resolution */
|
||||
if (!(neigh->nud_state & NUD_VALID))
|
||||
neigh_event_send(neigh, NULL);
|
||||
|
||||
/* query neighbor until resolved or timeout */
|
||||
retry = QED_IP_RESOL_TIMEOUT;
|
||||
while (!(neigh->nud_state & NUD_VALID) && retry > 0) {
|
||||
msleep(1000);
|
||||
retry--;
|
||||
}
|
||||
|
||||
if (neigh->nud_state & NUD_VALID) {
|
||||
neigh_ha_snapshot((u8 *)hardware_address->sa_data,
|
||||
neigh, *ndev);
|
||||
hardware_address->sa_family = (*ndev)->type;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
neigh_release(neigh);
|
||||
|
||||
if (ipv6_addr_any(&fl6.saddr)) {
|
||||
if (ipv6_dev_get_saddr(dev_net(*ndev), *ndev,
|
||||
&fl6.daddr, 0, &fl6.saddr)) {
|
||||
pr_err("Unable to find source IP address\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
local_addr->ss_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)local_addr)->sin6_addr =
|
||||
fl6.saddr;
|
||||
}
|
||||
}
|
||||
|
||||
dst_release(dst);
|
||||
|
||||
out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(qed_route_ipv6);
|
||||
|
||||
void qed_vlan_get_ndev(struct net_device **ndev, u16 *vlan_id)
|
||||
{
|
||||
if (is_vlan_dev(*ndev)) {
|
||||
*vlan_id = vlan_dev_vlan_id(*ndev);
|
||||
*ndev = vlan_dev_real_dev(*ndev);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(qed_vlan_get_ndev);
|
||||
|
||||
struct pci_dev *qed_validate_ndev(struct net_device *ndev)
|
||||
{
|
||||
struct pci_dev *pdev = NULL;
|
||||
struct net_device *upper;
|
||||
|
||||
for_each_pci_dev(pdev) {
|
||||
if (pdev && pdev->driver &&
|
||||
!strcmp(pdev->driver->name, "qede")) {
|
||||
upper = pci_get_drvdata(pdev);
|
||||
if (upper->ifindex == ndev->ifindex)
|
||||
return pdev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(qed_validate_ndev);
|
||||
|
||||
__be16 qed_get_in_port(struct sockaddr_storage *sa)
|
||||
{
|
||||
return sa->ss_family == AF_INET
|
||||
? ((struct sockaddr_in *)sa)->sin_port
|
||||
: ((struct sockaddr_in6 *)sa)->sin6_port;
|
||||
}
|
||||
EXPORT_SYMBOL(qed_get_in_port);
|
||||
|
||||
int qed_fetch_tcp_port(struct sockaddr_storage local_ip_addr,
|
||||
struct socket **sock, u16 *port)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
int rc = 0;
|
||||
|
||||
rc = sock_create(local_ip_addr.ss_family, SOCK_STREAM, IPPROTO_TCP,
|
||||
sock);
|
||||
if (rc) {
|
||||
pr_warn("failed to create socket: %d\n", rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
(*sock)->sk->sk_allocation = GFP_KERNEL;
|
||||
sk_set_memalloc((*sock)->sk);
|
||||
|
||||
rc = kernel_bind(*sock, (struct sockaddr *)&local_ip_addr,
|
||||
sizeof(local_ip_addr));
|
||||
|
||||
if (rc) {
|
||||
pr_warn("failed to bind socket: %d\n", rc);
|
||||
goto err_sock;
|
||||
}
|
||||
|
||||
rc = kernel_getsockname(*sock, (struct sockaddr *)&sa);
|
||||
if (rc < 0) {
|
||||
pr_warn("getsockname() failed: %d\n", rc);
|
||||
goto err_sock;
|
||||
}
|
||||
|
||||
*port = ntohs(qed_get_in_port(&sa));
|
||||
|
||||
return 0;
|
||||
|
||||
err_sock:
|
||||
sock_release(*sock);
|
||||
sock = NULL;
|
||||
err:
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(qed_fetch_tcp_port);
|
||||
|
||||
void qed_return_tcp_port(struct socket *sock)
|
||||
{
|
||||
if (sock && sock->sk) {
|
||||
tcp_set_state(sock->sk, TCP_CLOSE);
|
||||
sock_release(sock);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(qed_return_tcp_port);
|
29
include/linux/qed/qed_nvmetcp_ip_services_if.h
Normal file
29
include/linux/qed/qed_nvmetcp_ip_services_if.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* Copyright 2021 Marvell. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _QED_IP_SERVICES_IF_H
|
||||
#define _QED_IP_SERVICES_IF_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <net/route.h>
|
||||
#include <net/ip6_route.h>
|
||||
#include <linux/inetdevice.h>
|
||||
|
||||
int qed_route_ipv4(struct sockaddr_storage *local_addr,
|
||||
struct sockaddr_storage *remote_addr,
|
||||
struct sockaddr *hardware_address,
|
||||
struct net_device **ndev);
|
||||
int qed_route_ipv6(struct sockaddr_storage *local_addr,
|
||||
struct sockaddr_storage *remote_addr,
|
||||
struct sockaddr *hardware_address,
|
||||
struct net_device **ndev);
|
||||
void qed_vlan_get_ndev(struct net_device **ndev, u16 *vlan_id);
|
||||
struct pci_dev *qed_validate_ndev(struct net_device *ndev);
|
||||
void qed_return_tcp_port(struct socket *sock);
|
||||
int qed_fetch_tcp_port(struct sockaddr_storage local_ip_addr,
|
||||
struct socket **sock, u16 *port);
|
||||
__be16 qed_get_in_port(struct sockaddr_storage *sa);
|
||||
|
||||
#endif /* _QED_IP_SERVICES_IF_H */
|
Loading…
Reference in New Issue
Block a user