提交 fc8d0590 编写于 作者: A Anish Bhatt 提交者: David S. Miller

libcxgbi: Add ipv6 api to driver

Signed-off-by: NAnish Bhatt <anish@chelsio.com>
Signed-off-by: NKaren Xie <kxie@chelsio.com>
Signed-off-by: NManoj Malviya <manojmalviya@chelsio.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 a3e3b285
...@@ -24,6 +24,10 @@ ...@@ -24,6 +24,10 @@
#include <linux/inet.h> #include <linux/inet.h>
#include <net/dst.h> #include <net/dst.h>
#include <net/route.h> #include <net/route.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <linux/inetdevice.h> /* ip_dev_find */ #include <linux/inetdevice.h> /* ip_dev_find */
#include <linux/module.h> #include <linux/module.h>
#include <net/tcp.h> #include <net/tcp.h>
...@@ -193,8 +197,8 @@ struct cxgbi_device *cxgbi_device_find_by_lldev(void *lldev) ...@@ -193,8 +197,8 @@ struct cxgbi_device *cxgbi_device_find_by_lldev(void *lldev)
} }
EXPORT_SYMBOL_GPL(cxgbi_device_find_by_lldev); EXPORT_SYMBOL_GPL(cxgbi_device_find_by_lldev);
static struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev,
int *port) int *port)
{ {
struct net_device *vdev = NULL; struct net_device *vdev = NULL;
struct cxgbi_device *cdev, *tmp; struct cxgbi_device *cdev, *tmp;
...@@ -224,6 +228,40 @@ static struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, ...@@ -224,6 +228,40 @@ static struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev,
"ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name);
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev);
static struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev,
int *port)
{
struct net_device *vdev = NULL;
struct cxgbi_device *cdev, *tmp;
int i;
if (ndev->priv_flags & IFF_802_1Q_VLAN) {
vdev = ndev;
ndev = vlan_dev_real_dev(ndev);
pr_info("vlan dev %s -> %s.\n", vdev->name, ndev->name);
}
mutex_lock(&cdev_mutex);
list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) {
for (i = 0; i < cdev->nports; i++) {
if (!memcmp(ndev->dev_addr, cdev->ports[i]->dev_addr,
MAX_ADDR_LEN)) {
cdev->hbas[i]->vdev = vdev;
mutex_unlock(&cdev_mutex);
if (port)
*port = i;
return cdev;
}
}
}
mutex_unlock(&cdev_mutex);
log_debug(1 << CXGBI_DBG_DEV,
"ndev 0x%p, %s, NO match mac found.\n",
ndev, ndev->name);
return NULL;
}
void cxgbi_hbas_remove(struct cxgbi_device *cdev) void cxgbi_hbas_remove(struct cxgbi_device *cdev)
{ {
...@@ -320,6 +358,7 @@ static int sock_get_port(struct cxgbi_sock *csk) ...@@ -320,6 +358,7 @@ static int sock_get_port(struct cxgbi_sock *csk)
struct cxgbi_ports_map *pmap = &cdev->pmap; struct cxgbi_ports_map *pmap = &cdev->pmap;
unsigned int start; unsigned int start;
int idx; int idx;
__be16 *port;
if (!pmap->max_connect) { if (!pmap->max_connect) {
pr_err("cdev 0x%p, p#%u %s, NO port map.\n", pr_err("cdev 0x%p, p#%u %s, NO port map.\n",
...@@ -327,9 +366,14 @@ static int sock_get_port(struct cxgbi_sock *csk) ...@@ -327,9 +366,14 @@ static int sock_get_port(struct cxgbi_sock *csk)
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
} }
if (csk->saddr.sin_port) { if (csk->csk_family == AF_INET)
port = &csk->saddr.sin_port;
else /* ipv6 */
port = &csk->saddr6.sin6_port;
if (*port) {
pr_err("source port NON-ZERO %u.\n", pr_err("source port NON-ZERO %u.\n",
ntohs(csk->saddr.sin_port)); ntohs(*port));
return -EADDRINUSE; return -EADDRINUSE;
} }
...@@ -347,8 +391,7 @@ static int sock_get_port(struct cxgbi_sock *csk) ...@@ -347,8 +391,7 @@ static int sock_get_port(struct cxgbi_sock *csk)
idx = 0; idx = 0;
if (!pmap->port_csk[idx]) { if (!pmap->port_csk[idx]) {
pmap->used++; pmap->used++;
csk->saddr.sin_port = *port = htons(pmap->sport_base + idx);
htons(pmap->sport_base + idx);
pmap->next = idx; pmap->next = idx;
pmap->port_csk[idx] = csk; pmap->port_csk[idx] = csk;
spin_unlock_bh(&pmap->lock); spin_unlock_bh(&pmap->lock);
...@@ -374,16 +417,22 @@ static void sock_put_port(struct cxgbi_sock *csk) ...@@ -374,16 +417,22 @@ static void sock_put_port(struct cxgbi_sock *csk)
{ {
struct cxgbi_device *cdev = csk->cdev; struct cxgbi_device *cdev = csk->cdev;
struct cxgbi_ports_map *pmap = &cdev->pmap; struct cxgbi_ports_map *pmap = &cdev->pmap;
__be16 *port;
if (csk->saddr.sin_port) { if (csk->csk_family == AF_INET)
int idx = ntohs(csk->saddr.sin_port) - pmap->sport_base; port = &csk->saddr.sin_port;
else /* ipv6 */
port = &csk->saddr6.sin6_port;
csk->saddr.sin_port = 0; if (*port) {
int idx = ntohs(*port) - pmap->sport_base;
*port = 0;
if (idx < 0 || idx >= pmap->max_connect) { if (idx < 0 || idx >= pmap->max_connect) {
pr_err("cdev 0x%p, p#%u %s, port %u OOR.\n", pr_err("cdev 0x%p, p#%u %s, port %u OOR.\n",
cdev, csk->port_id, cdev, csk->port_id,
cdev->ports[csk->port_id]->name, cdev->ports[csk->port_id]->name,
ntohs(csk->saddr.sin_port)); ntohs(*port));
return; return;
} }
...@@ -479,17 +528,11 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) ...@@ -479,17 +528,11 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr)
int port = 0xFFFF; int port = 0xFFFF;
int err = 0; int err = 0;
if (daddr->sin_family != AF_INET) {
pr_info("address family 0x%x NOT supported.\n",
daddr->sin_family);
err = -EAFNOSUPPORT;
goto err_out;
}
rt = find_route_ipv4(&fl4, 0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0); rt = find_route_ipv4(&fl4, 0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0);
if (!rt) { if (!rt) {
pr_info("no route to ipv4 0x%x, port %u.\n", pr_info("no route to ipv4 0x%x, port %u.\n",
daddr->sin_addr.s_addr, daddr->sin_port); be32_to_cpu(daddr->sin_addr.s_addr),
be16_to_cpu(daddr->sin_port));
err = -ENETUNREACH; err = -ENETUNREACH;
goto err_out; goto err_out;
} }
...@@ -537,9 +580,12 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) ...@@ -537,9 +580,12 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr)
csk->port_id = port; csk->port_id = port;
csk->mtu = mtu; csk->mtu = mtu;
csk->dst = dst; csk->dst = dst;
csk->csk_family = AF_INET;
csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr; csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr;
csk->daddr.sin_port = daddr->sin_port; csk->daddr.sin_port = daddr->sin_port;
csk->daddr.sin_family = daddr->sin_family; csk->daddr.sin_family = daddr->sin_family;
csk->saddr.sin_family = daddr->sin_family;
csk->saddr.sin_addr.s_addr = fl4.saddr; csk->saddr.sin_addr.s_addr = fl4.saddr;
neigh_release(n); neigh_release(n);
...@@ -556,6 +602,121 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) ...@@ -556,6 +602,121 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr)
return ERR_PTR(err); return ERR_PTR(err);
} }
static struct rt6_info *find_route_ipv6(const struct in6_addr *saddr,
const struct in6_addr *daddr)
{
struct flowi6 fl;
if (saddr)
memcpy(&fl.saddr, saddr, sizeof(struct in6_addr));
if (daddr)
memcpy(&fl.daddr, daddr, sizeof(struct in6_addr));
return (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
}
static struct cxgbi_sock *cxgbi_check_route6(struct sockaddr *dst_addr)
{
struct sockaddr_in6 *daddr6 = (struct sockaddr_in6 *)dst_addr;
struct dst_entry *dst;
struct net_device *ndev;
struct cxgbi_device *cdev;
struct rt6_info *rt = NULL;
struct neighbour *n;
struct in6_addr pref_saddr;
struct cxgbi_sock *csk = NULL;
unsigned int mtu = 0;
int port = 0xFFFF;
int err = 0;
rt = find_route_ipv6(NULL, &daddr6->sin6_addr);
if (!rt) {
pr_info("no route to ipv6 %pI6 port %u\n",
daddr6->sin6_addr.s6_addr,
be16_to_cpu(daddr6->sin6_port));
err = -ENETUNREACH;
goto err_out;
}
dst = &rt->dst;
n = dst_neigh_lookup(dst, &daddr6->sin6_addr);
if (!n) {
pr_info("%pI6, port %u, dst no neighbour.\n",
daddr6->sin6_addr.s6_addr,
be16_to_cpu(daddr6->sin6_port));
err = -ENETUNREACH;
goto rel_rt;
}
ndev = n->dev;
if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
pr_info("multi-cast route %pI6 port %u, dev %s.\n",
daddr6->sin6_addr.s6_addr,
ntohs(daddr6->sin6_port), ndev->name);
err = -ENETUNREACH;
goto rel_rt;
}
cdev = cxgbi_device_find_by_netdev(ndev, &port);
if (!cdev)
cdev = cxgbi_device_find_by_mac(ndev, &port);
if (!cdev) {
pr_info("dst %pI6 %s, NOT cxgbi device.\n",
daddr6->sin6_addr.s6_addr, ndev->name);
err = -ENETUNREACH;
goto rel_rt;
}
log_debug(1 << CXGBI_DBG_SOCK,
"route to %pI6 :%u, ndev p#%d,%s, cdev 0x%p.\n",
daddr6->sin6_addr.s6_addr, ntohs(daddr6->sin6_port), port,
ndev->name, cdev);
csk = cxgbi_sock_create(cdev);
if (!csk) {
err = -ENOMEM;
goto rel_rt;
}
csk->cdev = cdev;
csk->port_id = port;
csk->mtu = mtu;
csk->dst = dst;
if (ipv6_addr_any(&rt->rt6i_prefsrc.addr)) {
struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt);
err = ipv6_dev_get_saddr(&init_net, idev ? idev->dev : NULL,
&daddr6->sin6_addr, 0, &pref_saddr);
if (err) {
pr_info("failed to get source address to reach %pI6\n",
&daddr6->sin6_addr);
goto rel_rt;
}
} else {
pref_saddr = rt->rt6i_prefsrc.addr;
}
csk->csk_family = AF_INET6;
csk->daddr6.sin6_addr = daddr6->sin6_addr;
csk->daddr6.sin6_port = daddr6->sin6_port;
csk->daddr6.sin6_family = daddr6->sin6_family;
csk->saddr6.sin6_addr = pref_saddr;
neigh_release(n);
return csk;
rel_rt:
if (n)
neigh_release(n);
ip6_rt_put(rt);
if (csk)
cxgbi_sock_closed(csk);
err_out:
return ERR_PTR(err);
}
void cxgbi_sock_established(struct cxgbi_sock *csk, unsigned int snd_isn, void cxgbi_sock_established(struct cxgbi_sock *csk, unsigned int snd_isn,
unsigned int opt) unsigned int opt)
{ {
...@@ -2194,6 +2355,34 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, ...@@ -2194,6 +2355,34 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn,
} }
EXPORT_SYMBOL_GPL(cxgbi_set_conn_param); EXPORT_SYMBOL_GPL(cxgbi_set_conn_param);
static inline int csk_print_port(struct cxgbi_sock *csk, char *buf)
{
int len;
cxgbi_sock_get(csk);
len = sprintf(buf, "%hu\n", ntohs(csk->daddr.sin_port));
cxgbi_sock_put(csk);
return len;
}
static inline int csk_print_ip(struct cxgbi_sock *csk, char *buf)
{
int len;
cxgbi_sock_get(csk);
if (csk->csk_family == AF_INET)
len = sprintf(buf, "%pI4",
&csk->daddr.sin_addr.s_addr);
else
len = sprintf(buf, "%pI6",
&csk->daddr6.sin6_addr);
cxgbi_sock_put(csk);
return len;
}
int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param, int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param,
char *buf) char *buf)
{ {
...@@ -2447,7 +2636,17 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost, ...@@ -2447,7 +2636,17 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost,
} }
} }
csk = cxgbi_check_route(dst_addr); if (dst_addr->sa_family == AF_INET) {
csk = cxgbi_check_route(dst_addr);
} else if (dst_addr->sa_family == AF_INET6) {
csk = cxgbi_check_route6(dst_addr);
} else {
pr_info("address family 0x%x NOT supported.\n",
dst_addr->sa_family);
err = -EAFNOSUPPORT;
return (struct iscsi_endpoint *)ERR_PTR(err);
}
if (IS_ERR(csk)) if (IS_ERR(csk))
return (struct iscsi_endpoint *)csk; return (struct iscsi_endpoint *)csk;
cxgbi_sock_get(csk); cxgbi_sock_get(csk);
......
...@@ -44,6 +44,15 @@ enum cxgbi_dbg_flag { ...@@ -44,6 +44,15 @@ enum cxgbi_dbg_flag {
pr_info(fmt, ##__VA_ARGS__); \ pr_info(fmt, ##__VA_ARGS__); \
} while (0) } while (0)
#define pr_info_ipaddr(fmt_trail, \
addr1, addr2, args_trail...) \
do { \
if (!((1 << CXGBI_DBG_SOCK) & dbg_level)) \
break; \
pr_info("%pISpc - %pISpc, " fmt_trail, \
addr1, addr2, args_trail); \
} while (0)
/* max. connections per adapter */ /* max. connections per adapter */
#define CXGBI_MAX_CONN 16384 #define CXGBI_MAX_CONN 16384
...@@ -202,8 +211,15 @@ struct cxgbi_sock { ...@@ -202,8 +211,15 @@ struct cxgbi_sock {
spinlock_t lock; spinlock_t lock;
struct kref refcnt; struct kref refcnt;
unsigned int state; unsigned int state;
struct sockaddr_in saddr; unsigned int csk_family;
struct sockaddr_in daddr; union {
struct sockaddr_in saddr;
struct sockaddr_in6 saddr6;
};
union {
struct sockaddr_in daddr;
struct sockaddr_in6 daddr6;
};
struct dst_entry *dst; struct dst_entry *dst;
struct sk_buff_head receive_queue; struct sk_buff_head receive_queue;
struct sk_buff_head write_queue; struct sk_buff_head write_queue;
...@@ -692,6 +708,7 @@ struct cxgbi_device *cxgbi_device_register(unsigned int, unsigned int); ...@@ -692,6 +708,7 @@ struct cxgbi_device *cxgbi_device_register(unsigned int, unsigned int);
void cxgbi_device_unregister(struct cxgbi_device *); void cxgbi_device_unregister(struct cxgbi_device *);
void cxgbi_device_unregister_all(unsigned int flag); void cxgbi_device_unregister_all(unsigned int flag);
struct cxgbi_device *cxgbi_device_find_by_lldev(void *); struct cxgbi_device *cxgbi_device_find_by_lldev(void *);
struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *, int *);
int cxgbi_hbas_add(struct cxgbi_device *, unsigned int, unsigned int, int cxgbi_hbas_add(struct cxgbi_device *, unsigned int, unsigned int,
struct scsi_host_template *, struct scsi_host_template *,
struct scsi_transport_template *); struct scsi_transport_template *);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册