Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2016, Mellanox Technologies, Ltd.  All rights reserved.
0003  *
0004  * This software is available to you under a choice of one of two
0005  * licenses.  You may choose to be licensed under the terms of the GNU
0006  * General Public License (GPL) Version 2, available from the file
0007  * COPYING in the main directory of this source tree, or the
0008  * OpenIB.org BSD license below:
0009  *
0010  *     Redistribution and use in source and binary forms, with or
0011  *     without modification, are permitted provided that the following
0012  *     conditions are met:
0013  *
0014  *      - Redistributions of source code must retain the above
0015  *        copyright notice, this list of conditions and the following
0016  *        disclaimer.
0017  *
0018  *      - Redistributions in binary form must reproduce the above
0019  *        copyright notice, this list of conditions and the following
0020  *        disclaimer in the documentation and/or other materials
0021  *        provided with the distribution.
0022  *
0023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0024  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0025  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0026  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0027  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0028  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0029  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0030  * SOFTWARE.
0031  */
0032 
0033 #include <linux/ip.h>
0034 #include <linux/udp.h>
0035 #include <net/udp.h>
0036 #include "en.h"
0037 #include "en/port.h"
0038 #include "eswitch.h"
0039 
0040 static int mlx5e_test_health_info(struct mlx5e_priv *priv)
0041 {
0042     struct mlx5_core_health *health = &priv->mdev->priv.health;
0043 
0044     return health->fatal_error ? 1 : 0;
0045 }
0046 
0047 static int mlx5e_test_link_state(struct mlx5e_priv *priv)
0048 {
0049     u8 port_state;
0050 
0051     if (!netif_carrier_ok(priv->netdev))
0052         return 1;
0053 
0054     port_state = mlx5_query_vport_state(priv->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0);
0055     return port_state == VPORT_STATE_UP ? 0 : 1;
0056 }
0057 
0058 static int mlx5e_test_link_speed(struct mlx5e_priv *priv)
0059 {
0060     u32 speed;
0061 
0062     if (!netif_carrier_ok(priv->netdev))
0063         return 1;
0064 
0065     return mlx5e_port_linkspeed(priv->mdev, &speed);
0066 }
0067 
0068 struct mlx5ehdr {
0069     __be32 version;
0070     __be64 magic;
0071 };
0072 
0073 #ifdef CONFIG_INET
0074 /* loopback test */
0075 #define MLX5E_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) +\
0076                  sizeof(struct udphdr) + sizeof(struct mlx5ehdr))
0077 #define MLX5E_TEST_MAGIC 0x5AEED15C001ULL
0078 
0079 static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
0080 {
0081     struct sk_buff *skb = NULL;
0082     struct mlx5ehdr *mlxh;
0083     struct ethhdr *ethh;
0084     struct udphdr *udph;
0085     struct iphdr *iph;
0086     int    iplen;
0087 
0088     skb = netdev_alloc_skb(priv->netdev, MLX5E_TEST_PKT_SIZE);
0089     if (!skb) {
0090         netdev_err(priv->netdev, "\tFailed to alloc loopback skb\n");
0091         return NULL;
0092     }
0093 
0094     net_prefetchw(skb->data);
0095     skb_reserve(skb, NET_IP_ALIGN);
0096 
0097     /*  Reserve for ethernet and IP header  */
0098     ethh = skb_push(skb, ETH_HLEN);
0099     skb_reset_mac_header(skb);
0100 
0101     skb_set_network_header(skb, skb->len);
0102     iph = skb_put(skb, sizeof(struct iphdr));
0103 
0104     skb_set_transport_header(skb, skb->len);
0105     udph = skb_put(skb, sizeof(struct udphdr));
0106 
0107     /* Fill ETH header */
0108     ether_addr_copy(ethh->h_dest, priv->netdev->dev_addr);
0109     eth_zero_addr(ethh->h_source);
0110     ethh->h_proto = htons(ETH_P_IP);
0111 
0112     /* Fill UDP header */
0113     udph->source = htons(9);
0114     udph->dest = htons(9); /* Discard Protocol */
0115     udph->len = htons(sizeof(struct mlx5ehdr) + sizeof(struct udphdr));
0116     udph->check = 0;
0117 
0118     /* Fill IP header */
0119     iph->ihl = 5;
0120     iph->ttl = 32;
0121     iph->version = 4;
0122     iph->protocol = IPPROTO_UDP;
0123     iplen = sizeof(struct iphdr) + sizeof(struct udphdr) +
0124         sizeof(struct mlx5ehdr);
0125     iph->tot_len = htons(iplen);
0126     iph->frag_off = 0;
0127     iph->saddr = 0;
0128     iph->daddr = 0;
0129     iph->tos = 0;
0130     iph->id = 0;
0131     ip_send_check(iph);
0132 
0133     /* Fill test header and data */
0134     mlxh = skb_put(skb, sizeof(*mlxh));
0135     mlxh->version = 0;
0136     mlxh->magic = cpu_to_be64(MLX5E_TEST_MAGIC);
0137 
0138     skb->csum = 0;
0139     skb->ip_summed = CHECKSUM_PARTIAL;
0140     udp4_hwcsum(skb, iph->saddr, iph->daddr);
0141 
0142     skb->protocol = htons(ETH_P_IP);
0143     skb->pkt_type = PACKET_HOST;
0144     skb->dev = priv->netdev;
0145 
0146     return skb;
0147 }
0148 
0149 struct mlx5e_lbt_priv {
0150     struct packet_type pt;
0151     struct completion comp;
0152     bool loopback_ok;
0153     bool local_lb;
0154 };
0155 
0156 static int
0157 mlx5e_test_loopback_validate(struct sk_buff *skb,
0158                  struct net_device *ndev,
0159                  struct packet_type *pt,
0160                  struct net_device *orig_ndev)
0161 {
0162     struct mlx5e_lbt_priv *lbtp = pt->af_packet_priv;
0163     struct mlx5ehdr *mlxh;
0164     struct ethhdr *ethh;
0165     struct udphdr *udph;
0166     struct iphdr *iph;
0167 
0168     /* We are only going to peek, no need to clone the SKB */
0169     if (MLX5E_TEST_PKT_SIZE - ETH_HLEN > skb_headlen(skb))
0170         goto out;
0171 
0172     ethh = (struct ethhdr *)skb_mac_header(skb);
0173     if (!ether_addr_equal(ethh->h_dest, orig_ndev->dev_addr))
0174         goto out;
0175 
0176     iph = ip_hdr(skb);
0177     if (iph->protocol != IPPROTO_UDP)
0178         goto out;
0179 
0180     /* Don't assume skb_transport_header() was set */
0181     udph = (struct udphdr *)((u8 *)iph + 4 * iph->ihl);
0182     if (udph->dest != htons(9))
0183         goto out;
0184 
0185     mlxh = (struct mlx5ehdr *)((char *)udph + sizeof(*udph));
0186     if (mlxh->magic != cpu_to_be64(MLX5E_TEST_MAGIC))
0187         goto out; /* so close ! */
0188 
0189     /* bingo */
0190     lbtp->loopback_ok = true;
0191     complete(&lbtp->comp);
0192 out:
0193     kfree_skb(skb);
0194     return 0;
0195 }
0196 
0197 static int mlx5e_test_loopback_setup(struct mlx5e_priv *priv,
0198                      struct mlx5e_lbt_priv *lbtp)
0199 {
0200     int err = 0;
0201 
0202     /* Temporarily enable local_lb */
0203     err = mlx5_nic_vport_query_local_lb(priv->mdev, &lbtp->local_lb);
0204     if (err)
0205         return err;
0206 
0207     if (!lbtp->local_lb) {
0208         err = mlx5_nic_vport_update_local_lb(priv->mdev, true);
0209         if (err)
0210             return err;
0211     }
0212 
0213     err = mlx5e_refresh_tirs(priv, true, false);
0214     if (err)
0215         goto out;
0216 
0217     lbtp->loopback_ok = false;
0218     init_completion(&lbtp->comp);
0219 
0220     lbtp->pt.type = htons(ETH_P_IP);
0221     lbtp->pt.func = mlx5e_test_loopback_validate;
0222     lbtp->pt.dev = priv->netdev;
0223     lbtp->pt.af_packet_priv = lbtp;
0224     dev_add_pack(&lbtp->pt);
0225 
0226     return 0;
0227 
0228 out:
0229     if (!lbtp->local_lb)
0230         mlx5_nic_vport_update_local_lb(priv->mdev, false);
0231 
0232     return err;
0233 }
0234 
0235 static void mlx5e_test_loopback_cleanup(struct mlx5e_priv *priv,
0236                     struct mlx5e_lbt_priv *lbtp)
0237 {
0238     if (!lbtp->local_lb)
0239         mlx5_nic_vport_update_local_lb(priv->mdev, false);
0240 
0241     dev_remove_pack(&lbtp->pt);
0242     mlx5e_refresh_tirs(priv, false, false);
0243 }
0244 
0245 static int mlx5e_cond_loopback(struct mlx5e_priv *priv)
0246 {
0247     if (is_mdev_switchdev_mode(priv->mdev))
0248         return -EOPNOTSUPP;
0249 
0250     return 0;
0251 }
0252 
0253 #define MLX5E_LB_VERIFY_TIMEOUT (msecs_to_jiffies(200))
0254 static int mlx5e_test_loopback(struct mlx5e_priv *priv)
0255 {
0256     struct mlx5e_lbt_priv *lbtp;
0257     struct sk_buff *skb = NULL;
0258     int err;
0259 
0260     if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
0261         netdev_err(priv->netdev,
0262                "\tCan't perform loopback test while device is down\n");
0263         return -ENODEV;
0264     }
0265 
0266     lbtp = kzalloc(sizeof(*lbtp), GFP_KERNEL);
0267     if (!lbtp)
0268         return -ENOMEM;
0269     lbtp->loopback_ok = false;
0270 
0271     err = mlx5e_test_loopback_setup(priv, lbtp);
0272     if (err)
0273         goto out;
0274 
0275     skb = mlx5e_test_get_udp_skb(priv);
0276     if (!skb) {
0277         err = -ENOMEM;
0278         goto cleanup;
0279     }
0280 
0281     skb_set_queue_mapping(skb, 0);
0282     err = dev_queue_xmit(skb);
0283     if (err) {
0284         netdev_err(priv->netdev,
0285                "\tFailed to xmit loopback packet err(%d)\n",
0286                err);
0287         goto cleanup;
0288     }
0289 
0290     wait_for_completion_timeout(&lbtp->comp, MLX5E_LB_VERIFY_TIMEOUT);
0291     err = !lbtp->loopback_ok;
0292 
0293 cleanup:
0294     mlx5e_test_loopback_cleanup(priv, lbtp);
0295 out:
0296     kfree(lbtp);
0297     return err;
0298 }
0299 #endif
0300 
0301 typedef int (*mlx5e_st_func)(struct mlx5e_priv *);
0302 
0303 struct mlx5e_st {
0304     char name[ETH_GSTRING_LEN];
0305     mlx5e_st_func st_func;
0306     mlx5e_st_func cond_func;
0307 };
0308 
0309 static struct mlx5e_st mlx5e_sts[] = {
0310     { "Link Test", mlx5e_test_link_state },
0311     { "Speed Test", mlx5e_test_link_speed },
0312     { "Health Test", mlx5e_test_health_info },
0313 #ifdef CONFIG_INET
0314     { "Loopback Test", mlx5e_test_loopback, mlx5e_cond_loopback },
0315 #endif
0316 };
0317 
0318 #define MLX5E_ST_NUM ARRAY_SIZE(mlx5e_sts)
0319 
0320 void mlx5e_self_test(struct net_device *ndev, struct ethtool_test *etest,
0321              u64 *buf)
0322 {
0323     struct mlx5e_priv *priv = netdev_priv(ndev);
0324     int i, count = 0;
0325 
0326     mutex_lock(&priv->state_lock);
0327     netdev_info(ndev, "Self test begin..\n");
0328 
0329     for (i = 0; i < MLX5E_ST_NUM; i++) {
0330         struct mlx5e_st st = mlx5e_sts[i];
0331 
0332         if (st.cond_func && st.cond_func(priv))
0333             continue;
0334         netdev_info(ndev, "\t[%d] %s start..\n", i, st.name);
0335         buf[count] = st.st_func(priv);
0336         netdev_info(ndev, "\t[%d] %s end: result(%lld)\n", i, st.name, buf[count]);
0337         count++;
0338     }
0339 
0340     mutex_unlock(&priv->state_lock);
0341 
0342     for (i = 0; i < count; i++) {
0343         if (buf[i]) {
0344             etest->flags |= ETH_TEST_FL_FAILED;
0345             break;
0346         }
0347     }
0348     netdev_info(ndev, "Self test out: status flags(0x%x)\n",
0349             etest->flags);
0350 }
0351 
0352 int mlx5e_self_test_fill_strings(struct mlx5e_priv *priv, u8 *data)
0353 {
0354     int i, count = 0;
0355 
0356     for (i = 0; i < MLX5E_ST_NUM; i++) {
0357         struct mlx5e_st st = mlx5e_sts[i];
0358 
0359         if (st.cond_func && st.cond_func(priv))
0360             continue;
0361         if (data)
0362             strcpy(data + count * ETH_GSTRING_LEN, st.name);
0363         count++;
0364     }
0365     return count;
0366 }
0367 
0368 int mlx5e_self_test_num(struct mlx5e_priv *priv)
0369 {
0370     return mlx5e_self_test_fill_strings(priv, NULL);
0371 }