[RFC PATCH v4 07/27] qed: Add IP services APIs support
Shai Malin
malin1024 at gmail.com
Mon May 3 16:44:16 BST 2021
On 5/2/21 2:26 PM, Hannes Reinecke wrote:
> On 4/29/21 9:09 PM, Shai Malin wrote:
> > From: Nikolay Assa <nassa at marvell.com>
> >
> > 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 at marvell.com>
> > Signed-off-by: Nikolay Assa <nassa at marvell.com>
> > Signed-off-by: Prabhakar Kushwaha <pkushwaha at marvell.com>
> > Signed-off-by: Omkar Kulkarni <okulkarni at marvell.com>
> > Signed-off-by: Michal Kalderon <mkalderon at marvell.com>
> > Signed-off-by: Ariel Elior <aelior at marvell.com>
> > Signed-off-by: Shai Malin <smalin at marvell.com>
> > ---
> > .../qlogic/qed/qed_nvmetcp_ip_services.c | 239 ++++++++++++++++++
> > .../linux/qed/qed_nvmetcp_ip_services_if.h | 29 +++
> > 2 files changed, 268 insertions(+)
> > create mode 100644 drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c
> > create mode 100644 include/linux/qed/qed_nvmetcp_ip_services_if.h
> >
> > diff --git a/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c
> > new file mode 100644
> > index 000000000000..2904b1a0830a
> > --- /dev/null
> > +++ b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c
> > @@ -0,0 +1,239 @@
> > +// 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);
> > diff --git a/include/linux/qed/qed_nvmetcp_ip_services_if.h b/include/linux/qed/qed_nvmetcp_ip_services_if.h
> > new file mode 100644
> > index 000000000000..3604aee53796
> > --- /dev/null
> > +++ b/include/linux/qed/qed_nvmetcp_ip_services_if.h
> > @@ -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 */
> >
> Reviewed-by: Hannes Reinecke <hare at suse.de>
>
Thanks.
> Cheers,
>
> Hannes
> --
> Dr. Hannes Reinecke Kernel Storage Architect
> hare at suse.de +49 911 74053 688
> SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
> HRB 36809 (AG Nürnberg), Geschäftsführer: Felix Imendörffer
More information about the Linux-nvme
mailing list