Merge branch '10GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net...
authorDavid S. Miller <davem@davemloft.net>
Thu, 1 Nov 2018 01:21:37 +0000 (18:21 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 1 Nov 2018 01:21:37 +0000 (18:21 -0700)
Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates 2018-10-31

This series contains a various collection of fixes.

Miroslav Lichvar from Red Hat or should I say IBM now?  Updates the PHC
timecounter interval for igb so that it gets updated at least once
every 550 seconds.

Ngai-Mint provides a fix for fm10k to prevent a soft lockup or system
crash by adding a new condition to determine if the SM mailbox is in the
correct state before proceeding.

Jake provides several fm10k fixes, first one marks complier aborts as
non-fatal since on some platforms trigger machine check errors when the
compile aborts.  Added missing device ids to the in-kernel driver.  Due
to the recent fixes, bumped the driver version.

I (Jeff Kirsher) fixed a XFRM_ALGO dependency for both ixgbe and
ixgbevf.  This fix was based on the original work from Arnd Bergmann,
which only fixed ixgbe.

Mitch provides a fix for i40e/avf to update the status codes, which
resolves an issue between a mis-match between i40e and the iavf driver,
which also supports the ice LAN driver.

Radoslaw fixes the ixgbe where the driver is logging a message about
spoofed packets detected when the VF is re-started with a different MAC
address.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
24 files changed:
drivers/net/ethernet/hisilicon/hns3/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/vhost/vhost.c
include/linux/bpf_verifier.h
include/net/af_unix.h
kernel/bpf/verifier.c
net/ipv4/tcp_bpf.c
tools/lib/bpf/libbpf.c
tools/testing/selftests/bpf/flow_dissector_load.c
tools/testing/selftests/bpf/test_skb_cgroup_id.sh
tools/testing/selftests/bpf/test_sock_addr.sh
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh

index e82e4ca206205da6562fa3449802869a975a86d3..055b40606dbc20f358f6445067b33f226d79554e 100644 (file)
@@ -316,8 +316,8 @@ struct hnae3_ae_ops {
        int (*set_loopback)(struct hnae3_handle *handle,
                            enum hnae3_loop loop_mode, bool en);
 
-       void (*set_promisc_mode)(struct hnae3_handle *handle, bool en_uc_pmc,
-                                bool en_mc_pmc);
+       int (*set_promisc_mode)(struct hnae3_handle *handle, bool en_uc_pmc,
+                               bool en_mc_pmc);
        int (*set_mtu)(struct hnae3_handle *handle, int new_mtu);
 
        void (*get_pauseparam)(struct hnae3_handle *handle,
@@ -391,7 +391,7 @@ struct hnae3_ae_ops {
                                      int vector_num,
                                      struct hnae3_ring_chain_node *vr_chain);
 
-       void (*reset_queue)(struct hnae3_handle *handle, u16 queue_id);
+       int (*reset_queue)(struct hnae3_handle *handle, u16 queue_id);
        u32 (*get_fw_version)(struct hnae3_handle *handle);
        void (*get_mdix_mode)(struct hnae3_handle *handle,
                              u8 *tp_mdix_ctrl, u8 *tp_mdix);
index 32f3aca814e78b530495956d7cafcb9017139176..3f96aa30068ec3dcf991bec4ed022b3e68d013e7 100644 (file)
@@ -509,16 +509,18 @@ static void hns3_nic_set_rx_mode(struct net_device *netdev)
        h->netdev_flags = new_flags;
 }
 
-void hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags)
+int hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags)
 {
        struct hns3_nic_priv *priv = netdev_priv(netdev);
        struct hnae3_handle *h = priv->ae_handle;
 
        if (h->ae_algo->ops->set_promisc_mode) {
-               h->ae_algo->ops->set_promisc_mode(h,
-                                                 promisc_flags & HNAE3_UPE,
-                                                 promisc_flags & HNAE3_MPE);
+               return h->ae_algo->ops->set_promisc_mode(h,
+                                               promisc_flags & HNAE3_UPE,
+                                               promisc_flags & HNAE3_MPE);
        }
+
+       return 0;
 }
 
 void hns3_enable_vlan_filter(struct net_device *netdev, bool enable)
@@ -1494,18 +1496,22 @@ static int hns3_vlan_rx_kill_vid(struct net_device *netdev,
        return ret;
 }
 
-static void hns3_restore_vlan(struct net_device *netdev)
+static int hns3_restore_vlan(struct net_device *netdev)
 {
        struct hns3_nic_priv *priv = netdev_priv(netdev);
+       int ret = 0;
        u16 vid;
-       int ret;
 
        for_each_set_bit(vid, priv->active_vlans, VLAN_N_VID) {
                ret = hns3_vlan_rx_add_vid(netdev, htons(ETH_P_8021Q), vid);
-               if (ret)
-                       netdev_warn(netdev, "Restore vlan: %d filter, ret:%d\n",
-                                   vid, ret);
+               if (ret) {
+                       netdev_err(netdev, "Restore vlan: %d filter, ret:%d\n",
+                                  vid, ret);
+                       return ret;
+               }
        }
+
+       return ret;
 }
 
 static int hns3_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
@@ -2727,7 +2733,7 @@ static int hns3_get_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
                        chain = devm_kzalloc(&pdev->dev, sizeof(*chain),
                                             GFP_KERNEL);
                        if (!chain)
-                               return -ENOMEM;
+                               goto err_free_chain;
 
                        cur_chain->next = chain;
                        chain->tqp_index = tx_ring->tqp->tqp_index;
@@ -2757,7 +2763,7 @@ static int hns3_get_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
        while (rx_ring) {
                chain = devm_kzalloc(&pdev->dev, sizeof(*chain), GFP_KERNEL);
                if (!chain)
-                       return -ENOMEM;
+                       goto err_free_chain;
 
                cur_chain->next = chain;
                chain->tqp_index = rx_ring->tqp->tqp_index;
@@ -2772,6 +2778,16 @@ static int hns3_get_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
        }
 
        return 0;
+
+err_free_chain:
+       cur_chain = head->next;
+       while (cur_chain) {
+               chain = cur_chain->next;
+               devm_kfree(&pdev->dev, chain);
+               cur_chain = chain;
+       }
+
+       return -ENOMEM;
 }
 
 static void hns3_free_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
@@ -2821,7 +2837,7 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv)
        struct hnae3_handle *h = priv->ae_handle;
        struct hns3_enet_tqp_vector *tqp_vector;
        int ret = 0;
-       u16 i;
+       int i;
 
        hns3_nic_set_cpumask(priv);
 
@@ -2868,13 +2884,19 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv)
                hns3_free_vector_ring_chain(tqp_vector, &vector_ring_chain);
 
                if (ret)
-                       return ret;
+                       goto map_ring_fail;
 
                netif_napi_add(priv->netdev, &tqp_vector->napi,
                               hns3_nic_common_poll, NAPI_POLL_WEIGHT);
        }
 
        return 0;
+
+map_ring_fail:
+       while (i--)
+               netif_napi_del(&priv->tqp_vector[i].napi);
+
+       return ret;
 }
 
 static int hns3_nic_alloc_vector_data(struct hns3_nic_priv *priv)
@@ -3031,8 +3053,10 @@ static int hns3_queue_to_ring(struct hnae3_queue *tqp,
                return ret;
 
        ret = hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_RX);
-       if (ret)
+       if (ret) {
+               devm_kfree(priv->dev, priv->ring_data[tqp->tqp_index].ring);
                return ret;
+       }
 
        return 0;
 }
@@ -3059,6 +3083,12 @@ static int hns3_get_ring_config(struct hns3_nic_priv *priv)
 
        return 0;
 err:
+       while (i--) {
+               devm_kfree(priv->dev, priv->ring_data[i].ring);
+               devm_kfree(priv->dev,
+                          priv->ring_data[i + h->kinfo.num_tqps].ring);
+       }
+
        devm_kfree(&pdev->dev, priv->ring_data);
        return ret;
 }
@@ -3226,9 +3256,6 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv)
        int i;
 
        for (i = 0; i < h->kinfo.num_tqps; i++) {
-               if (h->ae_algo->ops->reset_queue)
-                       h->ae_algo->ops->reset_queue(h, i);
-
                hns3_fini_ring(priv->ring_data[i].ring);
                hns3_fini_ring(priv->ring_data[i + h->kinfo.num_tqps].ring);
        }
@@ -3236,11 +3263,12 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv)
 }
 
 /* Set mac addr if it is configured. or leave it to the AE driver */
-static void hns3_init_mac_addr(struct net_device *netdev, bool init)
+static int hns3_init_mac_addr(struct net_device *netdev, bool init)
 {
        struct hns3_nic_priv *priv = netdev_priv(netdev);
        struct hnae3_handle *h = priv->ae_handle;
        u8 mac_addr_temp[ETH_ALEN];
+       int ret = 0;
 
        if (h->ae_algo->ops->get_mac_addr && init) {
                h->ae_algo->ops->get_mac_addr(h, mac_addr_temp);
@@ -3255,8 +3283,9 @@ static void hns3_init_mac_addr(struct net_device *netdev, bool init)
        }
 
        if (h->ae_algo->ops->set_mac_addr)
-               h->ae_algo->ops->set_mac_addr(h, netdev->dev_addr, true);
+               ret = h->ae_algo->ops->set_mac_addr(h, netdev->dev_addr, true);
 
+       return ret;
 }
 
 static int hns3_restore_fd_rules(struct net_device *netdev)
@@ -3469,20 +3498,29 @@ err_out:
        return ret;
 }
 
-static void hns3_recover_hw_addr(struct net_device *ndev)
+static int hns3_recover_hw_addr(struct net_device *ndev)
 {
        struct netdev_hw_addr_list *list;
        struct netdev_hw_addr *ha, *tmp;
+       int ret = 0;
 
        /* go through and sync uc_addr entries to the device */
        list = &ndev->uc;
-       list_for_each_entry_safe(ha, tmp, &list->list, list)
-               hns3_nic_uc_sync(ndev, ha->addr);
+       list_for_each_entry_safe(ha, tmp, &list->list, list) {
+               ret = hns3_nic_uc_sync(ndev, ha->addr);
+               if (ret)
+                       return ret;
+       }
 
        /* go through and sync mc_addr entries to the device */
        list = &ndev->mc;
-       list_for_each_entry_safe(ha, tmp, &list->list, list)
-               hns3_nic_mc_sync(ndev, ha->addr);
+       list_for_each_entry_safe(ha, tmp, &list->list, list) {
+               ret = hns3_nic_mc_sync(ndev, ha->addr);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
 }
 
 static void hns3_remove_hw_addr(struct net_device *netdev)
@@ -3609,7 +3647,10 @@ int hns3_nic_reset_all_ring(struct hnae3_handle *h)
        int ret;
 
        for (i = 0; i < h->kinfo.num_tqps; i++) {
-               h->ae_algo->ops->reset_queue(h, i);
+               ret = h->ae_algo->ops->reset_queue(h, i);
+               if (ret)
+                       return ret;
+
                hns3_init_ring_hw(priv->ring_data[i].ring);
 
                /* We need to clear tx ring here because self test will
@@ -3701,18 +3742,30 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
        bool vlan_filter_enable;
        int ret;
 
-       hns3_init_mac_addr(netdev, false);
-       hns3_recover_hw_addr(netdev);
-       hns3_update_promisc_mode(netdev, handle->netdev_flags);
+       ret = hns3_init_mac_addr(netdev, false);
+       if (ret)
+               return ret;
+
+       ret = hns3_recover_hw_addr(netdev);
+       if (ret)
+               return ret;
+
+       ret = hns3_update_promisc_mode(netdev, handle->netdev_flags);
+       if (ret)
+               return ret;
+
        vlan_filter_enable = netdev->flags & IFF_PROMISC ? false : true;
        hns3_enable_vlan_filter(netdev, vlan_filter_enable);
 
-
        /* Hardware table is only clear when pf resets */
-       if (!(handle->flags & HNAE3_SUPPORT_VF))
-               hns3_restore_vlan(netdev);
+       if (!(handle->flags & HNAE3_SUPPORT_VF)) {
+               ret = hns3_restore_vlan(netdev);
+               return ret;
+       }
 
-       hns3_restore_fd_rules(netdev);
+       ret = hns3_restore_fd_rules(netdev);
+       if (ret)
+               return ret;
 
        /* Carrier off reporting is important to ethtool even BEFORE open */
        netif_carrier_off(netdev);
index 71cfca132d0bd044006f3a8e1a599973dbceb500..d3636d088aa3d960ae3bc2721d1257018286ae89 100644 (file)
@@ -640,7 +640,7 @@ void hns3_set_vector_coalesce_rl(struct hns3_enet_tqp_vector *tqp_vector,
                                 u32 rl_value);
 
 void hns3_enable_vlan_filter(struct net_device *netdev, bool enable);
-void hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags);
+int hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags);
 
 #ifdef CONFIG_HNS3_DCB
 void hns3_dcbnl_setup(struct hnae3_handle *handle);
index ac13cb2b168e5a6e67517837dd470e092a0db8f8..690f62ed87dcaa3b1997df510f0c06784e7c1eb6 100644 (file)
@@ -24,15 +24,15 @@ static int hclge_ring_space(struct hclge_cmq_ring *ring)
        return ring->desc_num - used - 1;
 }
 
-static int is_valid_csq_clean_head(struct hclge_cmq_ring *ring, int h)
+static int is_valid_csq_clean_head(struct hclge_cmq_ring *ring, int head)
 {
-       int u = ring->next_to_use;
-       int c = ring->next_to_clean;
+       int ntu = ring->next_to_use;
+       int ntc = ring->next_to_clean;
 
-       if (unlikely(h >= ring->desc_num))
-               return 0;
+       if (ntu > ntc)
+               return head >= ntc && head <= ntu;
 
-       return u > c ? (h > c && h <= u) : (h > c || h <= u);
+       return head >= ntc || head <= ntu;
 }
 
 static int hclge_alloc_cmd_desc(struct hclge_cmq_ring *ring)
@@ -304,6 +304,10 @@ int hclge_cmd_queue_init(struct hclge_dev *hdev)
 {
        int ret;
 
+       /* Setup the lock for command queue */
+       spin_lock_init(&hdev->hw.cmq.csq.lock);
+       spin_lock_init(&hdev->hw.cmq.crq.lock);
+
        /* Setup the queue entries for use cmd queue */
        hdev->hw.cmq.csq.desc_num = HCLGE_NIC_CMQ_DESC_NUM;
        hdev->hw.cmq.crq.desc_num = HCLGE_NIC_CMQ_DESC_NUM;
@@ -337,18 +341,20 @@ int hclge_cmd_init(struct hclge_dev *hdev)
        u32 version;
        int ret;
 
+       spin_lock_bh(&hdev->hw.cmq.csq.lock);
+       spin_lock_bh(&hdev->hw.cmq.crq.lock);
+
        hdev->hw.cmq.csq.next_to_clean = 0;
        hdev->hw.cmq.csq.next_to_use = 0;
        hdev->hw.cmq.crq.next_to_clean = 0;
        hdev->hw.cmq.crq.next_to_use = 0;
 
-       /* Setup the lock for command queue */
-       spin_lock_init(&hdev->hw.cmq.csq.lock);
-       spin_lock_init(&hdev->hw.cmq.crq.lock);
-
        hclge_cmd_init_regs(&hdev->hw);
        clear_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
 
+       spin_unlock_bh(&hdev->hw.cmq.crq.lock);
+       spin_unlock_bh(&hdev->hw.cmq.csq.lock);
+
        ret = hclge_cmd_query_firmware_version(&hdev->hw, &version);
        if (ret) {
                dev_err(&hdev->pdev->dev,
index dca6f2326c2672bf75f46613c2ed3389003090de..123c37e653f3eda4ad120970aa4cd19b094557f8 100644 (file)
@@ -751,7 +751,7 @@ static void hclge_process_ncsi_error(struct hclge_dev *hdev,
        ret = hclge_cmd_clear_error(hdev, &desc_wr, &desc_rd,
                                    HCLGE_NCSI_INT_CLR, 0);
        if (ret)
-               dev_err(dev, "failed(=%d) to clear NCSI intrerrupt status\n",
+               dev_err(dev, "failed(=%d) to clear NCSI interrupt status\n",
                        ret);
 }
 
index 5234b5373ed3b9257aad7ad3f480040694623721..ffdd96020860db0153d467814984d63efb01995e 100644 (file)
@@ -2236,7 +2236,7 @@ static irqreturn_t hclge_misc_irq_handle(int irq, void *data)
        }
 
        /* clear the source of interrupt if it is not cause by reset */
-       if (event_cause != HCLGE_VECTOR0_EVENT_RST) {
+       if (event_cause == HCLGE_VECTOR0_EVENT_MBX) {
                hclge_clear_event_cause(hdev, event_cause, clearval);
                hclge_enable_vector(&hdev->misc_vector, true);
        }
@@ -2470,14 +2470,17 @@ static void hclge_reset(struct hclge_dev *hdev)
        handle = &hdev->vport[0].nic;
        rtnl_lock();
        hclge_notify_client(hdev, HNAE3_DOWN_CLIENT);
+       rtnl_unlock();
 
        if (!hclge_reset_wait(hdev)) {
+               rtnl_lock();
                hclge_notify_client(hdev, HNAE3_UNINIT_CLIENT);
                hclge_reset_ae_dev(hdev->ae_dev);
                hclge_notify_client(hdev, HNAE3_INIT_CLIENT);
 
                hclge_clear_reset_cause(hdev);
        } else {
+               rtnl_lock();
                /* schedule again to check pending resets later */
                set_bit(hdev->reset_type, &hdev->reset_pending);
                hclge_reset_task_schedule(hdev);
@@ -3314,8 +3317,8 @@ void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc,
        param->vf_id = vport_id;
 }
 
-static void hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
-                                  bool en_mc_pmc)
+static int hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
+                                 bool en_mc_pmc)
 {
        struct hclge_vport *vport = hclge_get_vport(handle);
        struct hclge_dev *hdev = vport->back;
@@ -3323,7 +3326,7 @@ static void hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
 
        hclge_promisc_param_init(&param, en_uc_pmc, en_mc_pmc, true,
                                 vport->vport_id);
-       hclge_cmd_set_promisc_mode(hdev, &param);
+       return hclge_cmd_set_promisc_mode(hdev, &param);
 }
 
 static int hclge_get_fd_mode(struct hclge_dev *hdev, u8 *fd_mode)
@@ -6107,31 +6110,28 @@ static u16 hclge_covert_handle_qid_global(struct hnae3_handle *handle,
        return tqp->index;
 }
 
-void hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
+int hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
 {
        struct hclge_vport *vport = hclge_get_vport(handle);
        struct hclge_dev *hdev = vport->back;
        int reset_try_times = 0;
        int reset_status;
        u16 queue_gid;
-       int ret;
-
-       if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
-               return;
+       int ret = 0;
 
        queue_gid = hclge_covert_handle_qid_global(handle, queue_id);
 
        ret = hclge_tqp_enable(hdev, queue_id, 0, false);
        if (ret) {
-               dev_warn(&hdev->pdev->dev, "Disable tqp fail, ret = %d\n", ret);
-               return;
+               dev_err(&hdev->pdev->dev, "Disable tqp fail, ret = %d\n", ret);
+               return ret;
        }
 
        ret = hclge_send_reset_tqp_cmd(hdev, queue_gid, true);
        if (ret) {
-               dev_warn(&hdev->pdev->dev,
-                        "Send reset tqp cmd fail, ret = %d\n", ret);
-               return;
+               dev_err(&hdev->pdev->dev,
+                       "Send reset tqp cmd fail, ret = %d\n", ret);
+               return ret;
        }
 
        reset_try_times = 0;
@@ -6144,16 +6144,16 @@ void hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
        }
 
        if (reset_try_times >= HCLGE_TQP_RESET_TRY_TIMES) {
-               dev_warn(&hdev->pdev->dev, "Reset TQP fail\n");
-               return;
+               dev_err(&hdev->pdev->dev, "Reset TQP fail\n");
+               return ret;
        }
 
        ret = hclge_send_reset_tqp_cmd(hdev, queue_gid, false);
-       if (ret) {
-               dev_warn(&hdev->pdev->dev,
-                        "Deassert the soft reset fail, ret = %d\n", ret);
-               return;
-       }
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "Deassert the soft reset fail, ret = %d\n", ret);
+
+       return ret;
 }
 
 void hclge_reset_vf_queue(struct hclge_vport *vport, u16 queue_id)
index e3dfd654eca9a1c4b1f0af7a90b29d91c725ca1b..0d92154042699c94a41410ab6dc3aa38437c9b3a 100644 (file)
@@ -778,7 +778,7 @@ int hclge_rss_init_hw(struct hclge_dev *hdev);
 void hclge_rss_indir_init_cfg(struct hclge_dev *hdev);
 
 void hclge_mbx_handler(struct hclge_dev *hdev);
-void hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id);
+int hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id);
 void hclge_reset_vf_queue(struct hclge_vport *vport, u16 queue_id);
 int hclge_cfg_flowctrl(struct hclge_dev *hdev);
 int hclge_func_reset_cmd(struct hclge_dev *hdev, int func_id);
index 04462a347a94075bd28453b6db9088d77ef586c9..f890022938d9a15a96e98ab2c48cea04fc0dc784 100644 (file)
@@ -400,6 +400,12 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
 
        /* handle all the mailbox requests in the queue */
        while (!hclge_cmd_crq_empty(&hdev->hw)) {
+               if (test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state)) {
+                       dev_warn(&hdev->pdev->dev,
+                                "command queue needs re-initializing\n");
+                       return;
+               }
+
                desc = &crq->desc[crq->next_to_use];
                req = (struct hclge_mbx_vf_to_pf_cmd *)desc->data;
 
index 24b1f2a0c32afc328cbdc82b67d5adb5fae916cc..03018638f701b3f2824bb153864e13cf929bd06c 100644 (file)
@@ -52,7 +52,7 @@ static int hclge_mdio_write(struct mii_bus *bus, int phyid, int regnum,
        struct hclge_desc desc;
        int ret;
 
-       if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+       if (test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state))
                return 0;
 
        hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, false);
@@ -90,7 +90,7 @@ static int hclge_mdio_read(struct mii_bus *bus, int phyid, int regnum)
        struct hclge_desc desc;
        int ret;
 
-       if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+       if (test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state))
                return 0;
 
        hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, true);
index e0a86a58342c28dab0a6e044895f9c4635f46207..085edb945389c5fc8aba0d94f8ffe2c74f070f24 100644 (file)
@@ -925,12 +925,12 @@ static int hclgevf_cmd_set_promisc_mode(struct hclgevf_dev *hdev,
        return status;
 }
 
-static void hclgevf_set_promisc_mode(struct hnae3_handle *handle,
-                                    bool en_uc_pmc, bool en_mc_pmc)
+static int hclgevf_set_promisc_mode(struct hnae3_handle *handle,
+                                   bool en_uc_pmc, bool en_mc_pmc)
 {
        struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
 
-       hclgevf_cmd_set_promisc_mode(hdev, en_uc_pmc, en_mc_pmc);
+       return hclgevf_cmd_set_promisc_mode(hdev, en_uc_pmc, en_mc_pmc);
 }
 
 static int hclgevf_tqp_enable(struct hclgevf_dev *hdev, int tqp_id,
@@ -1080,7 +1080,7 @@ static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
                                    1, false, NULL, 0);
 }
 
-static void hclgevf_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
+static int hclgevf_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
 {
        struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
        u8 msg_data[2];
@@ -1091,10 +1091,10 @@ static void hclgevf_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
        /* disable vf queue before send queue reset msg to PF */
        ret = hclgevf_tqp_enable(hdev, queue_id, 0, false);
        if (ret)
-               return;
+               return ret;
 
-       hclgevf_send_mbx_msg(hdev, HCLGE_MBX_QUEUE_RESET, 0, msg_data,
-                            2, true, NULL, 0);
+       return hclgevf_send_mbx_msg(hdev, HCLGE_MBX_QUEUE_RESET, 0, msg_data,
+                                   2, true, NULL, 0);
 }
 
 static int hclgevf_notify_client(struct hclgevf_dev *hdev,
@@ -1170,6 +1170,8 @@ static int hclgevf_reset(struct hclgevf_dev *hdev)
        /* bring down the nic to stop any ongoing TX/RX */
        hclgevf_notify_client(hdev, HNAE3_DOWN_CLIENT);
 
+       rtnl_unlock();
+
        /* check if VF could successfully fetch the hardware reset completion
         * status from the hardware
         */
@@ -1181,12 +1183,15 @@ static int hclgevf_reset(struct hclgevf_dev *hdev)
                        ret);
 
                dev_warn(&hdev->pdev->dev, "VF reset failed, disabling VF!\n");
+               rtnl_lock();
                hclgevf_notify_client(hdev, HNAE3_UNINIT_CLIENT);
 
                rtnl_unlock();
                return ret;
        }
 
+       rtnl_lock();
+
        /* now, re-initialize the nic client and ae device*/
        ret = hclgevf_reset_stack(hdev);
        if (ret)
index 94224c22ecc310a87b6715051e335446f29bec03..79638dcbae78395fb723c9bf3fa877e7a42d91cd 100644 (file)
@@ -713,43 +713,15 @@ static inline void mlx5e_enable_ecn(struct mlx5e_rq *rq, struct sk_buff *skb)
        rq->stats->ecn_mark += !!rc;
 }
 
-static __be32 mlx5e_get_fcs(struct sk_buff *skb)
+static u32 mlx5e_get_fcs(const struct sk_buff *skb)
 {
-       int last_frag_sz, bytes_in_prev, nr_frags;
-       u8 *fcs_p1, *fcs_p2;
-       skb_frag_t *last_frag;
-       __be32 fcs_bytes;
+       const void *fcs_bytes;
+       u32 _fcs_bytes;
 
-       if (!skb_is_nonlinear(skb))
-               return *(__be32 *)(skb->data + skb->len - ETH_FCS_LEN);
+       fcs_bytes = skb_header_pointer(skb, skb->len - ETH_FCS_LEN,
+                                      ETH_FCS_LEN, &_fcs_bytes);
 
-       nr_frags = skb_shinfo(skb)->nr_frags;
-       last_frag = &skb_shinfo(skb)->frags[nr_frags - 1];
-       last_frag_sz = skb_frag_size(last_frag);
-
-       /* If all FCS data is in last frag */
-       if (last_frag_sz >= ETH_FCS_LEN)
-               return *(__be32 *)(skb_frag_address(last_frag) +
-                                  last_frag_sz - ETH_FCS_LEN);
-
-       fcs_p2 = (u8 *)skb_frag_address(last_frag);
-       bytes_in_prev = ETH_FCS_LEN - last_frag_sz;
-
-       /* Find where the other part of the FCS is - Linear or another frag */
-       if (nr_frags == 1) {
-               fcs_p1 = skb_tail_pointer(skb);
-       } else {
-               skb_frag_t *prev_frag = &skb_shinfo(skb)->frags[nr_frags - 2];
-
-               fcs_p1 = skb_frag_address(prev_frag) +
-                           skb_frag_size(prev_frag);
-       }
-       fcs_p1 -= bytes_in_prev;
-
-       memcpy(&fcs_bytes, fcs_p1, bytes_in_prev);
-       memcpy(((u8 *)&fcs_bytes) + bytes_in_prev, fcs_p2, last_frag_sz);
-
-       return fcs_bytes;
+       return __get_unaligned_cpu32(fcs_bytes);
 }
 
 static u8 get_ip_proto(struct sk_buff *skb, __be16 proto)
@@ -797,8 +769,9 @@ static inline void mlx5e_handle_csum(struct net_device *netdev,
                                                 network_depth - ETH_HLEN,
                                                 skb->csum);
                if (unlikely(netdev->features & NETIF_F_RXFCS))
-                       skb->csum = csum_add(skb->csum,
-                                            (__force __wsum)mlx5e_get_fcs(skb));
+                       skb->csum = csum_block_add(skb->csum,
+                                                  (__force __wsum)mlx5e_get_fcs(skb),
+                                                  skb->len - ETH_FCS_LEN);
                stats->csum_complete++;
                return;
        }
index 32cb6718bb173ff966639a2ffc63374e457b586a..db3d2790aeecf9c3b93fe4c66df7856d637dfc70 100644 (file)
@@ -3284,7 +3284,7 @@ static inline void mlxsw_reg_qtct_pack(char *payload, u8 local_port,
  * Configures the ETS elements.
  */
 #define MLXSW_REG_QEEC_ID 0x400D
-#define MLXSW_REG_QEEC_LEN 0x1C
+#define MLXSW_REG_QEEC_LEN 0x20
 
 MLXSW_REG_DEFINE(qeec, MLXSW_REG_QEEC_ID, MLXSW_REG_QEEC_LEN);
 
@@ -3326,6 +3326,15 @@ MLXSW_ITEM32(reg, qeec, element_index, 0x04, 0, 8);
  */
 MLXSW_ITEM32(reg, qeec, next_element_index, 0x08, 0, 8);
 
+/* reg_qeec_mise
+ * Min shaper configuration enable. Enables configuration of the min
+ * shaper on this ETS element
+ * 0 - Disable
+ * 1 - Enable
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qeec, mise, 0x0C, 31, 1);
+
 enum {
        MLXSW_REG_QEEC_BYTES_MODE,
        MLXSW_REG_QEEC_PACKETS_MODE,
@@ -3342,6 +3351,17 @@ enum {
  */
 MLXSW_ITEM32(reg, qeec, pb, 0x0C, 28, 1);
 
+/* The smallest permitted min shaper rate. */
+#define MLXSW_REG_QEEC_MIS_MIN 200000          /* Kbps */
+
+/* reg_qeec_min_shaper_rate
+ * Min shaper information rate.
+ * For CPU port, can only be configured for port hierarchy.
+ * When in bytes mode, value is specified in units of 1000bps.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qeec, min_shaper_rate, 0x0C, 0, 28);
+
 /* reg_qeec_mase
  * Max shaper configuration enable. Enables configuration of the max
  * shaper on this ETS element.
index 8a4983adae940a08b4d4d5ec39637522fb1bea46..a2df12b79f8e915702323f9258972260135c094c 100644 (file)
@@ -2740,6 +2740,21 @@ int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port,
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
 }
 
+static int mlxsw_sp_port_min_bw_set(struct mlxsw_sp_port *mlxsw_sp_port,
+                                   enum mlxsw_reg_qeec_hr hr, u8 index,
+                                   u8 next_index, u32 minrate)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+       char qeec_pl[MLXSW_REG_QEEC_LEN];
+
+       mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,
+                           next_index);
+       mlxsw_reg_qeec_mise_set(qeec_pl, true);
+       mlxsw_reg_qeec_min_shaper_rate_set(qeec_pl, minrate);
+
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
+}
+
 int mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port,
                              u8 switch_prio, u8 tclass)
 {
@@ -2817,6 +2832,16 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
                        return err;
        }
 
+       /* Configure the min shaper for multicast TCs. */
+       for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+               err = mlxsw_sp_port_min_bw_set(mlxsw_sp_port,
+                                              MLXSW_REG_QEEC_HIERARCY_TC,
+                                              i + 8, i,
+                                              MLXSW_REG_QEEC_MIS_MIN);
+               if (err)
+                       return err;
+       }
+
        /* Map all priorities to traffic class 0. */
        for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
                err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, 0);
index f52008bb8df76e2760dce41a656be7407aff4738..3a5f81a66d34f0b5d19d09d16f9e07451e7958ff 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/sched/mm.h>
 #include <linux/sched/signal.h>
 #include <linux/interval_tree_generic.h>
+#include <linux/nospec.h>
 
 #include "vhost.h"
 
@@ -1387,6 +1388,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
        if (idx >= d->nvqs)
                return -ENOBUFS;
 
+       idx = array_index_nospec(idx, d->nvqs);
        vq = d->vqs[idx];
 
        mutex_lock(&vq->mutex);
index 9e8056ec20faab8c3ffd4e99843a166ace95a0a1..d93e89761a8b429c2b5568688b7bf388e5b977d7 100644 (file)
@@ -51,6 +51,9 @@ struct bpf_reg_state {
                 *   PTR_TO_MAP_VALUE_OR_NULL
                 */
                struct bpf_map *map_ptr;
+
+               /* Max size from any of the above. */
+               unsigned long raw;
        };
        /* Fixed part of pointer offset, pointer types only */
        s32 off;
index e2695c4bf3580323d9df2edd100388cf7db7e256..ddbba838d048df8f7d2d080442b77fa89130b561 100644 (file)
@@ -13,7 +13,7 @@ void unix_notinflight(struct user_struct *user, struct file *fp);
 void unix_gc(void);
 void wait_for_unix_gc(void);
 struct sock *unix_get_socket(struct file *filp);
-struct sock *unix_peer_get(struct sock *);
+struct sock *unix_peer_get(struct sock *sk);
 
 #define UNIX_HASH_SIZE 256
 #define UNIX_HASH_BITS 8
@@ -40,7 +40,7 @@ struct unix_skb_parms {
        u32                     consumed;
 } __randomize_layout;
 
-#define UNIXCB(skb)    (*(struct unix_skb_parms *)&((skb)->cb))
+#define UNIXCB(skb)    (*(struct unix_skb_parms *)&((skb)->cb))
 
 #define unix_state_lock(s)     spin_lock(&unix_sk(s)->lock)
 #define unix_state_unlock(s)   spin_unlock(&unix_sk(s)->lock)
index 171a2c88e77ddd28ea5f9d5ba135d424cd09714e..1971ca325fb4e765be7156299e7f02983687019f 100644 (file)
@@ -2852,10 +2852,6 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
                regs[BPF_REG_0].type = NOT_INIT;
        } else if (fn->ret_type == RET_PTR_TO_MAP_VALUE_OR_NULL ||
                   fn->ret_type == RET_PTR_TO_MAP_VALUE) {
-               if (fn->ret_type == RET_PTR_TO_MAP_VALUE)
-                       regs[BPF_REG_0].type = PTR_TO_MAP_VALUE;
-               else
-                       regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL;
                /* There is no offset yet applied, variable or fixed */
                mark_reg_known_zero(env, regs, BPF_REG_0);
                /* remember map_ptr, so that check_map_access()
@@ -2868,7 +2864,12 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
                        return -EINVAL;
                }
                regs[BPF_REG_0].map_ptr = meta.map_ptr;
-               regs[BPF_REG_0].id = ++env->id_gen;
+               if (fn->ret_type == RET_PTR_TO_MAP_VALUE) {
+                       regs[BPF_REG_0].type = PTR_TO_MAP_VALUE;
+               } else {
+                       regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL;
+                       regs[BPF_REG_0].id = ++env->id_gen;
+               }
        } else if (fn->ret_type == RET_PTR_TO_SOCKET_OR_NULL) {
                int id = acquire_reference_state(env, insn_idx);
                if (id < 0)
@@ -3046,7 +3047,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                        dst_reg->umax_value = umax_ptr;
                        dst_reg->var_off = ptr_reg->var_off;
                        dst_reg->off = ptr_reg->off + smin_val;
-                       dst_reg->range = ptr_reg->range;
+                       dst_reg->raw = ptr_reg->raw;
                        break;
                }
                /* A new variable offset is created.  Note that off_reg->off
@@ -3076,10 +3077,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                }
                dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off);
                dst_reg->off = ptr_reg->off;
+               dst_reg->raw = ptr_reg->raw;
                if (reg_is_pkt_pointer(ptr_reg)) {
                        dst_reg->id = ++env->id_gen;
                        /* something was added to pkt_ptr, set range to zero */
-                       dst_reg->range = 0;
+                       dst_reg->raw = 0;
                }
                break;
        case BPF_SUB:
@@ -3108,7 +3110,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                        dst_reg->var_off = ptr_reg->var_off;
                        dst_reg->id = ptr_reg->id;
                        dst_reg->off = ptr_reg->off - smin_val;
-                       dst_reg->range = ptr_reg->range;
+                       dst_reg->raw = ptr_reg->raw;
                        break;
                }
                /* A new variable offset is created.  If the subtrahend is known
@@ -3134,11 +3136,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                }
                dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off);
                dst_reg->off = ptr_reg->off;
+               dst_reg->raw = ptr_reg->raw;
                if (reg_is_pkt_pointer(ptr_reg)) {
                        dst_reg->id = ++env->id_gen;
                        /* something was added to pkt_ptr, set range to zero */
                        if (smin_val < 0)
-                               dst_reg->range = 0;
+                               dst_reg->raw = 0;
                }
                break;
        case BPF_AND:
index b7918d4caa300a15bec2858065b8f73d71cf6eb0..3b45fe530f91e2e1aa697888e11a78cf7e9d211e 100644 (file)
@@ -145,6 +145,7 @@ msg_bytes_ready:
                        ret = err;
                        goto out;
                }
+               copied = -EAGAIN;
        }
        ret = copied;
 out:
index b607be7236d3e580fda376f04cbe62302f698e4f..d6e62e90e8d44df2a3b710b6cfd875b32e20daec 100644 (file)
@@ -2084,19 +2084,19 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,
        prog->expected_attach_type = type;
 }
 
-#define BPF_PROG_SEC_IMPL(string, ptype, eatype, atype) \
-       { string, sizeof(string) - 1, ptype, eatype, atype }
+#define BPF_PROG_SEC_IMPL(string, ptype, eatype, is_attachable, atype) \
+       { string, sizeof(string) - 1, ptype, eatype, is_attachable, atype }
 
 /* Programs that can NOT be attached. */
-#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, -EINVAL)
+#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, 0, 0)
 
 /* Programs that can be attached. */
 #define BPF_APROG_SEC(string, ptype, atype) \
-       BPF_PROG_SEC_IMPL(string, ptype, 0, atype)
+       BPF_PROG_SEC_IMPL(string, ptype, 0, 1, atype)
 
 /* Programs that must specify expected attach type at load time. */
 #define BPF_EAPROG_SEC(string, ptype, eatype) \
-       BPF_PROG_SEC_IMPL(string, ptype, eatype, eatype)
+       BPF_PROG_SEC_IMPL(string, ptype, eatype, 1, eatype)
 
 /* Programs that can be attached but attach type can't be identified by section
  * name. Kept for backward compatibility.
@@ -2108,6 +2108,7 @@ static const struct {
        size_t len;
        enum bpf_prog_type prog_type;
        enum bpf_attach_type expected_attach_type;
+       int is_attachable;
        enum bpf_attach_type attach_type;
 } section_names[] = {
        BPF_PROG_SEC("socket",                  BPF_PROG_TYPE_SOCKET_FILTER),
@@ -2198,7 +2199,7 @@ int libbpf_attach_type_by_name(const char *name,
        for (i = 0; i < ARRAY_SIZE(section_names); i++) {
                if (strncmp(name, section_names[i].sec, section_names[i].len))
                        continue;
-               if (section_names[i].attach_type == -EINVAL)
+               if (!section_names[i].is_attachable)
                        return -EINVAL;
                *attach_type = section_names[i].attach_type;
                return 0;
index d3273b5b3173e123d087c624a34f5b834395da54..ae8180b11d5fe6dde18f822a262405e07479bc68 100644 (file)
@@ -11,6 +11,8 @@
 #include <bpf/bpf.h>
 #include <bpf/libbpf.h>
 
+#include "bpf_rlimit.h"
+
 const char *cfg_pin_path = "/sys/fs/bpf/flow_dissector";
 const char *cfg_map_name = "jmp_table";
 bool cfg_attach = true;
index 42544a969abc63b734267e696c78d2b338be0ca7..a9bc6f82abc163d47876d4af1f2dcbe540a6c814 100755 (executable)
@@ -10,7 +10,7 @@ wait_for_ip()
        echo -n "Wait for testing link-local IP to become available "
        for _i in $(seq ${MAX_PING_TRIES}); do
                echo -n "."
-               if ping -6 -q -c 1 -W 1 ff02::1%${TEST_IF} >/dev/null 2>&1; then
+               if $PING6 -c 1 -W 1 ff02::1%${TEST_IF} >/dev/null 2>&1; then
                        echo " OK"
                        return
                fi
@@ -58,5 +58,6 @@ BPF_PROG_OBJ="${DIR}/test_skb_cgroup_id_kern.o"
 BPF_PROG_SECTION="cgroup_id_logger"
 BPF_PROG_ID=0
 PROG="${DIR}/test_skb_cgroup_id_user"
+type ping6 >/dev/null 2>&1 && PING6="ping6" || PING6="ping -6"
 
 main
index 9832a875a828979be26b8756cbd589d5cf5e44f1..3b9fdb8094aa28b5e5abbe99f15b1e4502869a68 100755 (executable)
@@ -4,7 +4,8 @@ set -eu
 
 ping_once()
 {
-       ping -${1} -q -c 1 -W 1 ${2%%/*} >/dev/null 2>&1
+       type ping${1} >/dev/null 2>&1 && PING="ping${1}" || PING="ping -${1}"
+       $PING -q -c 1 -W 1 ${2%%/*} >/dev/null 2>&1
 }
 
 wait_for_ip()
index 36f3d3009d1a079e57032b47b57bc306d045a3a8..6f61df62f690c69adceb2c328b231ab39b8b9c49 100644 (file)
@@ -76,7 +76,7 @@ struct bpf_test {
        int fixup_percpu_cgroup_storage[MAX_FIXUPS];
        const char *errstr;
        const char *errstr_unpriv;
-       uint32_t retval;
+       uint32_t retval, retval_unpriv;
        enum {
                UNDEF,
                ACCEPT,
@@ -3084,6 +3084,8 @@ static struct bpf_test tests[] = {
                .fixup_prog1 = { 2 },
                .result = ACCEPT,
                .retval = 42,
+               /* Verifier rewrite for unpriv skips tail call here. */
+               .retval_unpriv = 2,
        },
        {
                "stack pointer arithmetic",
@@ -6454,6 +6456,256 @@ static struct bpf_test tests[] = {
                .errstr = "R1 min value is negative",
                .prog_type = BPF_PROG_TYPE_TRACEPOINT,
        },
+       {
+               "map access: known scalar += value_ptr",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_MOV64_IMM(BPF_REG_1, 4),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = ACCEPT,
+               .retval = 1,
+       },
+       {
+               "map access: value_ptr += known scalar",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_MOV64_IMM(BPF_REG_1, 4),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = ACCEPT,
+               .retval = 1,
+       },
+       {
+               "map access: unknown scalar += value_ptr",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = ACCEPT,
+               .retval = 1,
+       },
+       {
+               "map access: value_ptr += unknown scalar",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = ACCEPT,
+               .retval = 1,
+       },
+       {
+               "map access: value_ptr += value_ptr",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_0),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = REJECT,
+               .errstr = "R0 pointer += pointer prohibited",
+       },
+       {
+               "map access: known scalar -= value_ptr",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_MOV64_IMM(BPF_REG_1, 4),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_0),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = REJECT,
+               .errstr = "R1 tried to subtract pointer from scalar",
+       },
+       {
+               "map access: value_ptr -= known scalar",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_MOV64_IMM(BPF_REG_1, 4),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = REJECT,
+               .errstr = "R0 min value is outside of the array range",
+       },
+       {
+               "map access: value_ptr -= known scalar, 2",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
+                       BPF_MOV64_IMM(BPF_REG_1, 6),
+                       BPF_MOV64_IMM(BPF_REG_2, 4),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_2),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = ACCEPT,
+               .retval = 1,
+       },
+       {
+               "map access: unknown scalar -= value_ptr",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_0),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = REJECT,
+               .errstr = "R1 tried to subtract pointer from scalar",
+       },
+       {
+               "map access: value_ptr -= unknown scalar",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = REJECT,
+               .errstr = "R0 min value is negative",
+       },
+       {
+               "map access: value_ptr -= unknown scalar, 2",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 8),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
+                       BPF_ALU64_IMM(BPF_OR, BPF_REG_1, 0x7),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x7),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = ACCEPT,
+               .retval = 1,
+       },
+       {
+               "map access: value_ptr -= value_ptr",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_0),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map_array_48b = { 3 },
+               .result = REJECT,
+               .errstr = "R0 invalid mem access 'inv'",
+               .errstr_unpriv = "R0 pointer -= pointer prohibited",
+       },
        {
                "map lookup helper access to map",
                .insns = {
@@ -13899,6 +14151,33 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type,
        }
 }
 
+static int set_admin(bool admin)
+{
+       cap_t caps;
+       const cap_value_t cap_val = CAP_SYS_ADMIN;
+       int ret = -1;
+
+       caps = cap_get_proc();
+       if (!caps) {
+               perror("cap_get_proc");
+               return -1;
+       }
+       if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_val,
+                               admin ? CAP_SET : CAP_CLEAR)) {
+               perror("cap_set_flag");
+               goto out;
+       }
+       if (cap_set_proc(caps)) {
+               perror("cap_set_proc");
+               goto out;
+       }
+       ret = 0;
+out:
+       if (cap_free(caps))
+               perror("cap_free");
+       return ret;
+}
+
 static void do_test_single(struct bpf_test *test, bool unpriv,
                           int *passes, int *errors)
 {
@@ -13907,6 +14186,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
        struct bpf_insn *prog = test->insns;
        int map_fds[MAX_NR_MAPS];
        const char *expected_err;
+       uint32_t expected_val;
        uint32_t retval;
        int i, err;
 
@@ -13926,6 +14206,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
                       test->result_unpriv : test->result;
        expected_err = unpriv && test->errstr_unpriv ?
                       test->errstr_unpriv : test->errstr;
+       expected_val = unpriv && test->retval_unpriv ?
+                      test->retval_unpriv : test->retval;
 
        reject_from_alignment = fd_prog < 0 &&
                                (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) &&
@@ -13959,16 +14241,20 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
                __u8 tmp[TEST_DATA_LEN << 2];
                __u32 size_tmp = sizeof(tmp);
 
+               if (unpriv)
+                       set_admin(true);
                err = bpf_prog_test_run(fd_prog, 1, test->data,
                                        sizeof(test->data), tmp, &size_tmp,
                                        &retval, NULL);
+               if (unpriv)
+                       set_admin(false);
                if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) {
                        printf("Unexpected bpf_prog_test_run error\n");
                        goto fail_log;
                }
-               if (!err && retval != test->retval &&
-                   test->retval != POINTER_VALUE) {
-                       printf("FAIL retval %d != %d\n", retval, test->retval);
+               if (!err && retval != expected_val &&
+                   expected_val != POINTER_VALUE) {
+                       printf("FAIL retval %d != %d\n", retval, expected_val);
                        goto fail_log;
                }
        }
@@ -14011,33 +14297,6 @@ static bool is_admin(void)
        return (sysadmin == CAP_SET);
 }
 
-static int set_admin(bool admin)
-{
-       cap_t caps;
-       const cap_value_t cap_val = CAP_SYS_ADMIN;
-       int ret = -1;
-
-       caps = cap_get_proc();
-       if (!caps) {
-               perror("cap_get_proc");
-               return -1;
-       }
-       if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_val,
-                               admin ? CAP_SET : CAP_CLEAR)) {
-               perror("cap_set_flag");
-               goto out;
-       }
-       if (cap_set_proc(caps)) {
-               perror("cap_set_proc");
-               goto out;
-       }
-       ret = 0;
-out:
-       if (cap_free(caps))
-               perror("cap_free");
-       return ret;
-}
-
 static void get_unpriv_disabled()
 {
        char buf[2];
index 0150bb2741eb1a0f2a3c219e7316b37753a17298..117f6f35d72fac57ad87f0ed4772a50511d45cb4 100755 (executable)
 # Thus we set MTU to 10K on all involved interfaces. Then both unicast and
 # multicast traffic uses 8K frames.
 #
-# +-----------------------+                +----------------------------------+
-# | H1                    |                |                               H2 |
-# |                       |                |  unicast --> + $h2.111           |
-# |                       |                |  traffic     | 192.0.2.129/28    |
-# |          multicast    |                |              | e-qos-map 0:1     |
-# |          traffic      |                |              |                   |
-# | $h1 + <-----          |                |              + $h2               |
-# +-----|-----------------+                +--------------|-------------------+
-#       |                                                 |
-# +-----|-------------------------------------------------|-------------------+
-# |     + $swp1                                           + $swp2             |
-# |     | >1Gbps                                          | >1Gbps            |
-# | +---|----------------+                     +----------|----------------+  |
-# | |   + $swp1.1        |                     |          + $swp2.111      |  |
+# +---------------------------+            +----------------------------------+
+# | H1                        |            |                               H2 |
+# |                           |            |  unicast --> + $h2.111           |
+# |                 multicast |            |  traffic     | 192.0.2.129/28    |
+# |                 traffic   |            |              | e-qos-map 0:1     |
+# |           $h1 + <-----    |            |              |                   |
+# | 192.0.2.65/28 |           |            |              + $h2               |
+# +---------------|-----------+            +--------------|-------------------+
+#                 |                                       |
+# +---------------|---------------------------------------|-------------------+
+# |         $swp1 +                                       + $swp2             |
+# |        >1Gbps |                                       | >1Gbps            |
+# | +-------------|------+                     +----------|----------------+  |
+# | |     $swp1.1 +      |                     |          + $swp2.111      |  |
 # | |                BR1 |             SW      | BR111                     |  |
-# | |   + $swp3.1        |                     |          + $swp3.111      |  |
-# | +---|----------------+                     +----------|----------------+  |
-# |     \_________________________________________________/                   |
+# | |     $swp3.1 +      |                     |          + $swp3.111      |  |
+# | +-------------|------+                     +----------|----------------+  |
+# |               \_______________________________________/                   |
 # |                                    |                                      |
 # |                                    + $swp3                                |
 # |                                    | 1Gbps bottleneck                     |
@@ -51,6 +51,7 @@
 #                                      |
 #                                   +--|-----------------+
 #                                   |  + $h3          H3 |
+#                                   |  | 192.0.2.66/28   |
 #                                   |  |                 |
 #                                   |  + $h3.111         |
 #                                   |    192.0.2.130/28  |
@@ -59,6 +60,7 @@
 ALL_TESTS="
        ping_ipv4
        test_mc_aware
+       test_uc_aware
 "
 
 lib_dir=$(dirname $0)/../../../net/forwarding
@@ -68,14 +70,14 @@ source $lib_dir/lib.sh
 
 h1_create()
 {
-       simple_if_init $h1
+       simple_if_init $h1 192.0.2.65/28
        mtu_set $h1 10000
 }
 
 h1_destroy()
 {
        mtu_restore $h1
-       simple_if_fini $h1
+       simple_if_fini $h1 192.0.2.65/28
 }
 
 h2_create()
@@ -97,7 +99,7 @@ h2_destroy()
 
 h3_create()
 {
-       simple_if_init $h3
+       simple_if_init $h3 192.0.2.66/28
        mtu_set $h3 10000
 
        vlan_create $h3 111 v$h3 192.0.2.130/28
@@ -108,7 +110,7 @@ h3_destroy()
        vlan_destroy $h3 111
 
        mtu_restore $h3
-       simple_if_fini $h3
+       simple_if_fini $h3 192.0.2.66/28
 }
 
 switch_create()
@@ -251,7 +253,7 @@ measure_uc_rate()
        # average ingress rate to somewhat mitigate this.
        local min_ingress=2147483648
 
-       mausezahn $h2.111 -p 8000 -A 192.0.2.129 -B 192.0.2.130 -c 0 \
+       $MZ $h2.111 -p 8000 -A 192.0.2.129 -B 192.0.2.130 -c 0 \
                -a own -b $h3mac -t udp -q &
        sleep 1
 
@@ -291,7 +293,7 @@ test_mc_aware()
        check_err $? "Could not get high enough UC-only ingress rate"
        local ucth1=${uc_rate[1]}
 
-       mausezahn $h1 -p 8000 -c 0 -a own -b bc -t udp -q &
+       $MZ $h1 -p 8000 -c 0 -a own -b bc -t udp -q &
 
        local d0=$(date +%s)
        local t0=$(ethtool_stats_get $h3 rx_octets_prio_0)
@@ -311,7 +313,7 @@ test_mc_aware()
                        ret = 100 * ($ucth1 - $ucth2) / $ucth1
                        if (ret > 0) { ret } else { 0 }
                    ")
-       check_err $(bc <<< "$deg > 10")
+       check_err $(bc <<< "$deg > 25")
 
        local interval=$((d1 - d0))
        local mc_ir=$(rate $u0 $u1 $interval)
@@ -335,6 +337,51 @@ test_mc_aware()
        echo "    egress UC throughput  $(humanize ${uc_rate_2[1]})"
        echo "    ingress MC throughput $(humanize $mc_ir)"
        echo "    egress MC throughput  $(humanize $mc_er)"
+       echo
+}
+
+test_uc_aware()
+{
+       RET=0
+
+       $MZ $h2.111 -p 8000 -A 192.0.2.129 -B 192.0.2.130 -c 0 \
+               -a own -b $h3mac -t udp -q &
+
+       local d0=$(date +%s)
+       local t0=$(ethtool_stats_get $h3 rx_octets_prio_1)
+       local u0=$(ethtool_stats_get $swp2 rx_octets_prio_1)
+       sleep 1
+
+       local attempts=50
+       local passes=0
+       local i
+
+       for ((i = 0; i < attempts; ++i)); do
+               if $ARPING -c 1 -I $h1 -b 192.0.2.66 -q -w 0.1; then
+                       ((passes++))
+               fi
+
+               sleep 0.1
+       done
+
+       local d1=$(date +%s)
+       local t1=$(ethtool_stats_get $h3 rx_octets_prio_1)
+       local u1=$(ethtool_stats_get $swp2 rx_octets_prio_1)
+
+       local interval=$((d1 - d0))
+       local uc_ir=$(rate $u0 $u1 $interval)
+       local uc_er=$(rate $t0 $t1 $interval)
+
+       ((attempts == passes))
+       check_err $?
+
+       # Suppress noise from killing mausezahn.
+       { kill %% && wait; } 2>/dev/null
+
+       log_test "MC performace under UC overload"
+       echo "    ingress UC throughput $(humanize ${uc_ir})"
+       echo "    egress UC throughput  $(humanize ${uc_er})"
+       echo "    sent $attempts BC ARPs, got $passes responses"
 }
 
 trap cleanup EXIT