net/mlx4: Implement promiscuous mode with device managed flow-steering
authorHadar Hen Zion <hadarh@mellanox.co.il>
Thu, 5 Jul 2012 04:03:48 +0000 (04:03 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 7 Jul 2012 23:23:06 +0000 (16:23 -0700)
The device managed flow steering API has three promiscuous modes:

1. Uplink - captures all the packets that arrive to the port.
2. Allmulti - captures all multicast packets arriving to the port.
3. Function port - for future use, this mode is not implemented yet.

Use these modes with the flow_attach and flow_detach firmware commands
according to the promiscuous state of the netdevice.

Signed-off-by: Hadar Hen Zion <hadarh@mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/mcg.c
include/linux/mlx4/device.h

index eb5ed8e398735de7cd8a2a5d5b548f0693998a7c..b7945a80ad15057603e7aa4409762e069553aea6 100644 (file)
@@ -301,6 +301,16 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
 
                        /* Enable promiscouos mode */
                        switch (mdev->dev->caps.steering_mode) {
+                       case MLX4_STEERING_MODE_DEVICE_MANAGED:
+                               err = mlx4_flow_steer_promisc_add(mdev->dev,
+                                                                 priv->port,
+                                                                 priv->base_qpn,
+                                                                 MLX4_FS_PROMISC_UPLINK);
+                               if (err)
+                                       en_err(priv, "Failed enabling promiscuous mode\n");
+                               priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
+                               break;
+
                        case MLX4_STEERING_MODE_B0:
                                err = mlx4_unicast_promisc_add(mdev->dev,
                                                               priv->base_qpn,
@@ -357,6 +367,15 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
 
                /* Disable promiscouos mode */
                switch (mdev->dev->caps.steering_mode) {
+               case MLX4_STEERING_MODE_DEVICE_MANAGED:
+                       err = mlx4_flow_steer_promisc_remove(mdev->dev,
+                                                            priv->port,
+                                                            MLX4_FS_PROMISC_UPLINK);
+                       if (err)
+                               en_err(priv, "Failed disabling promiscuous mode\n");
+                       priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+                       break;
+
                case MLX4_STEERING_MODE_B0:
                        err = mlx4_unicast_promisc_remove(mdev->dev,
                                                          priv->base_qpn,
@@ -399,6 +418,13 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                /* Add the default qp number as multicast promisc */
                if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) {
                        switch (mdev->dev->caps.steering_mode) {
+                       case MLX4_STEERING_MODE_DEVICE_MANAGED:
+                               err = mlx4_flow_steer_promisc_add(mdev->dev,
+                                                                 priv->port,
+                                                                 priv->base_qpn,
+                                                                 MLX4_FS_PROMISC_ALL_MULTI);
+                               break;
+
                        case MLX4_STEERING_MODE_B0:
                                err = mlx4_multicast_promisc_add(mdev->dev,
                                                                 priv->base_qpn,
@@ -416,6 +442,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                /* Disable Multicast promisc */
                if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
                        switch (mdev->dev->caps.steering_mode) {
+                       case MLX4_STEERING_MODE_DEVICE_MANAGED:
+                               err = mlx4_flow_steer_promisc_remove(mdev->dev,
+                                                                    priv->port,
+                                                                    MLX4_FS_PROMISC_ALL_MULTI);
+                               break;
+
                        case MLX4_STEERING_MODE_B0:
                                err = mlx4_multicast_promisc_remove(mdev->dev,
                                                                    priv->base_qpn,
@@ -839,6 +871,15 @@ int mlx4_en_start_port(struct net_device *dev)
 
        /* Must redo promiscuous mode setup. */
        priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC);
+       if (mdev->dev->caps.steering_mode ==
+           MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               mlx4_flow_steer_promisc_remove(mdev->dev,
+                                              priv->port,
+                                              MLX4_FS_PROMISC_UPLINK);
+               mlx4_flow_steer_promisc_remove(mdev->dev,
+                                              priv->port,
+                                              MLX4_FS_PROMISC_ALL_MULTI);
+       }
 
        /* Schedule multicast task to populate multicast list */
        queue_work(mdev->workqueue, &priv->mcast_task);
index 768a2a4530e84eb102d1911551af839336f73085..bc62f536ffaeaac3dcdbaa48501792b4116f1ef7 100644 (file)
@@ -1295,6 +1295,66 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
 }
 EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
 
+int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
+                               u32 qpn, enum mlx4_net_trans_promisc_mode mode)
+{
+       struct mlx4_net_trans_rule rule;
+       u64 *regid_p;
+
+       switch (mode) {
+       case MLX4_FS_PROMISC_UPLINK:
+       case MLX4_FS_PROMISC_FUNCTION_PORT:
+               regid_p = &dev->regid_promisc_array[port];
+               break;
+       case MLX4_FS_PROMISC_ALL_MULTI:
+               regid_p = &dev->regid_allmulti_array[port];
+               break;
+       default:
+               return -1;
+       }
+
+       if (*regid_p != 0)
+               return -1;
+
+       rule.promisc_mode = mode;
+       rule.port = port;
+       rule.qpn = qpn;
+       INIT_LIST_HEAD(&rule.list);
+       mlx4_err(dev, "going promisc on %x\n", port);
+
+       return  mlx4_flow_attach(dev, &rule, regid_p);
+}
+EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add);
+
+int mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port,
+                                  enum mlx4_net_trans_promisc_mode mode)
+{
+       int ret;
+       u64 *regid_p;
+
+       switch (mode) {
+       case MLX4_FS_PROMISC_UPLINK:
+       case MLX4_FS_PROMISC_FUNCTION_PORT:
+               regid_p = &dev->regid_promisc_array[port];
+               break;
+       case MLX4_FS_PROMISC_ALL_MULTI:
+               regid_p = &dev->regid_allmulti_array[port];
+               break;
+       default:
+               return -1;
+       }
+
+       if (*regid_p == 0)
+               return -1;
+
+       ret =  mlx4_flow_detach(dev, *regid_p);
+       if (ret == 0)
+               *regid_p = 0;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove);
+
 int mlx4_unicast_attach(struct mlx4_dev *dev,
                        struct mlx4_qp *qp, u8 gid[16],
                        int block_mcast_loopback, enum mlx4_protocol prot)
index e45fc20bd01f47af4b3adacc060b84fe6ae6873e..6f0d133cc7ada41e8796f6797e736d27a5f73d78 100644 (file)
@@ -542,6 +542,8 @@ struct mlx4_dev {
        u8                      rev_id;
        char                    board_id[MLX4_BOARD_ID_LEN];
        int                     num_vfs;
+       u64                     regid_promisc_array[MLX4_MAX_PORTS + 1];
+       u64                     regid_allmulti_array[MLX4_MAX_PORTS + 1];
 };
 
 struct mlx4_init_port_param {
@@ -681,6 +683,7 @@ enum mlx4_net_trans_rule_id {
 enum mlx4_net_trans_promisc_mode {
        MLX4_FS_PROMISC_NONE = 0,
        MLX4_FS_PROMISC_UPLINK,
+       /* For future use. Not implemented yet */
        MLX4_FS_PROMISC_FUNCTION_PORT,
        MLX4_FS_PROMISC_ALL_MULTI,
 };
@@ -744,6 +747,10 @@ struct mlx4_net_trans_rule {
        u32     qpn;
 };
 
+int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port, u32 qpn,
+                               enum mlx4_net_trans_promisc_mode mode);
+int mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port,
+                                  enum mlx4_net_trans_promisc_mode mode);
 int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port);
 int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port);
 int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port);