X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fhns3%2Fhns3_ethdev_vf.c;h=5015fe0d5f7446bd812c8767ec22930000fe30f0;hb=b70e96833a753239454c660b71cbab6e0dcbbeae;hp=242ccf7f9f54a4ec8e8a4e15cf620911c8a8b735;hpb=ff6dc76e40b8d707df9c6273215d00fa46b628be;p=dpdk.git diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c index 242ccf7f9f..5015fe0d5f 100644 --- a/drivers/net/hns3/hns3_ethdev_vf.c +++ b/drivers/net/hns3/hns3_ethdev_vf.c @@ -10,12 +10,14 @@ #include #include "hns3_ethdev.h" +#include "hns3_common.h" #include "hns3_logs.h" #include "hns3_rxtx.h" #include "hns3_regs.h" #include "hns3_intr.h" #include "hns3_dcb.h" #include "hns3_mp.h" +#include "hns3_flow.h" #define HNS3VF_KEEP_ALIVE_INTERVAL 2000000 /* us */ #define HNS3VF_SERVICE_INTERVAL 1000000 /* us */ @@ -230,7 +232,7 @@ hns3vf_set_default_mac_addr(struct rte_eth_dev *dev, HNS3_TWO_ETHER_ADDR_LEN, true, NULL, 0); if (ret) { /* - * The hns3 VF PMD driver depends on the hns3 PF kernel ethdev + * The hns3 VF PMD depends on the hns3 PF kernel ethdev * driver. When user has configured a MAC address for VF device * by "ip link set ..." command based on the PF device, the hns3 * PF kernel ethdev driver does not allow VF driver to request @@ -240,7 +242,7 @@ hns3vf_set_default_mac_addr(struct rte_eth_dev *dev, if (ret == -EPERM) { hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE, old_addr); - hns3_warn(hw, "Has permanet mac addr(%s) for vf", + hns3_warn(hw, "Has permanent mac addr(%s) for vf", mac_str); } else { hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE, @@ -310,25 +312,25 @@ hns3vf_set_promisc_mode(struct hns3_hw *hw, bool en_bc_pmc, req = (struct hns3_mbx_vf_to_pf_cmd *)desc.data; /* - * The hns3 VF PMD driver depends on the hns3 PF kernel ethdev driver, + * The hns3 VF PMD depends on the hns3 PF kernel ethdev driver, * so there are some features for promiscuous/allmulticast mode in hns3 - * VF PMD driver as below: + * VF PMD as below: * 1. The promiscuous/allmulticast mode can be configured successfully * only based on the trusted VF device. If based on the non trusted * VF device, configuring promiscuous/allmulticast mode will fail. - * The hns3 VF device can be confiruged as trusted device by hns3 PF + * The hns3 VF device can be configured as trusted device by hns3 PF * kernel ethdev driver on the host by the following command: * "ip link set vf turst on" * 2. After the promiscuous mode is configured successfully, hns3 VF PMD - * driver can receive the ingress and outgoing traffic. In the words, + * can receive the ingress and outgoing traffic. This includes * all the ingress packets, all the packets sent from the PF and * other VFs on the same physical port. * 3. Note: Because of the hardware constraints, By default vlan filter * is enabled and couldn't be turned off based on VF device, so vlan * filter is still effective even in promiscuous mode. If upper * applications don't call rte_eth_dev_vlan_filter API function to - * set vlan based on VF device, hns3 VF PMD driver will can't receive - * the packets with vlan tag in promiscuoue mode. + * set vlan based on VF device, hns3 VF PMD will can't receive + * the packets with vlan tag in promiscuous mode. */ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MBX_VF_TO_PF, false); req->msg[0] = HNS3_MBX_SET_PROMISC_MODE; @@ -420,7 +422,7 @@ hns3vf_restore_promisc(struct hns3_adapter *hns) } static int -hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id, +hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint16_t vector_id, bool mmap, enum hns3_ring_type queue_type, uint16_t queue_id) { @@ -432,7 +434,7 @@ hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id, memset(&bind_msg, 0, sizeof(bind_msg)); code = mmap ? HNS3_MBX_MAP_RING_TO_VECTOR : HNS3_MBX_UNMAP_RING_TO_VECTOR; - bind_msg.vector_id = vector_id; + bind_msg.vector_id = (uint8_t)vector_id; if (queue_type == HNS3_RING_TYPE_RX) bind_msg.param[0].int_gl_index = HNS3_RING_GL_RX; @@ -452,62 +454,6 @@ hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id, return ret; } -static int -hns3vf_init_ring_with_vector(struct hns3_hw *hw) -{ - uint16_t vec; - int ret; - int i; - - /* - * In hns3 network engine, vector 0 is always the misc interrupt of this - * function, vector 1~N can be used respectively for the queues of the - * function. Tx and Rx queues with the same number share the interrupt - * vector. In the initialization clearing the all hardware mapping - * relationship configurations between queues and interrupt vectors is - * needed, so some error caused by the residual configurations, such as - * the unexpected Tx interrupt, can be avoid. - */ - vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */ - if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE) - vec = vec - 1; /* the last interrupt is reserved */ - hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num); - for (i = 0; i < hw->intr_tqps_num; i++) { - /* - * Set gap limiter/rate limiter/quanity limiter algorithm - * configuration for interrupt coalesce of queue's interrupt. - */ - hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX, - HNS3_TQP_INTR_GL_DEFAULT); - hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX, - HNS3_TQP_INTR_GL_DEFAULT); - hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT); - /* - * QL(quantity limiter) is not used currently, just set 0 to - * close it. - */ - hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT); - - ret = hns3vf_bind_ring_with_vector(hw, vec, false, - HNS3_RING_TYPE_TX, i); - if (ret) { - PMD_INIT_LOG(ERR, "VF fail to unbind TX ring(%d) with " - "vector: %u, ret=%d", i, vec, ret); - return ret; - } - - ret = hns3vf_bind_ring_with_vector(hw, vec, false, - HNS3_RING_TYPE_RX, i); - if (ret) { - PMD_INIT_LOG(ERR, "VF fail to unbind RX ring(%d) with " - "vector: %u, ret=%d", i, vec, ret); - return ret; - } - } - - return 0; -} - static int hns3vf_dev_configure(struct rte_eth_dev *dev) { @@ -607,9 +553,9 @@ hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) /* * The hns3 PF/VF devices on the same port share the hardware MTU * configuration. Currently, we send mailbox to inform hns3 PF kernel - * ethdev driver to finish hardware MTU configuration in hns3 VF PMD - * driver, there is no need to stop the port for hns3 VF device, and the - * MTU value issued by hns3 VF PMD driver must be less than or equal to + * ethdev driver to finish hardware MTU configuration in hns3 VF PMD, + * there is no need to stop the port for hns3 VF device, and the + * MTU value issued by hns3 VF PMD must be less than or equal to * PF's MTU. */ if (__atomic_load_n(&hw->reset.resetting, __ATOMIC_RELAXED)) { @@ -619,8 +565,8 @@ hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) /* * when Rx of scattered packets is off, we have some possibility of - * using vector Rx process function or simple Rx functions in hns3 PMD - * driver. If the input MTU is increased and the maximum length of + * using vector Rx process function or simple Rx functions in hns3 PMD. + * If the input MTU is increased and the maximum length of * received packets is greater than the length of a buffer for Rx * packet, the hardware network engine needs to use multiple BDs and * buffers to store these packets. This will cause problems when still @@ -647,103 +593,6 @@ hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) return 0; } -static int -hns3vf_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info) -{ - struct hns3_adapter *hns = eth_dev->data->dev_private; - struct hns3_hw *hw = &hns->hw; - uint16_t q_num = hw->tqps_num; - - /* - * In interrupt mode, 'max_rx_queues' is set based on the number of - * MSI-X interrupt resources of the hardware. - */ - if (hw->data->dev_conf.intr_conf.rxq == 1) - q_num = hw->intr_tqps_num; - - info->max_rx_queues = q_num; - info->max_tx_queues = hw->tqps_num; - info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */ - info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE; - info->max_mac_addrs = HNS3_VF_UC_MACADDR_NUM; - info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD; - info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE; - - info->rx_offload_capa = (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM | - RTE_ETH_RX_OFFLOAD_UDP_CKSUM | - RTE_ETH_RX_OFFLOAD_TCP_CKSUM | - RTE_ETH_RX_OFFLOAD_SCTP_CKSUM | - RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM | - RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM | - RTE_ETH_RX_OFFLOAD_SCATTER | - RTE_ETH_RX_OFFLOAD_VLAN_STRIP | - RTE_ETH_RX_OFFLOAD_VLAN_FILTER | - RTE_ETH_RX_OFFLOAD_RSS_HASH | - RTE_ETH_RX_OFFLOAD_TCP_LRO); - info->tx_offload_capa = (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM | - RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | - RTE_ETH_TX_OFFLOAD_TCP_CKSUM | - RTE_ETH_TX_OFFLOAD_UDP_CKSUM | - RTE_ETH_TX_OFFLOAD_SCTP_CKSUM | - RTE_ETH_TX_OFFLOAD_MULTI_SEGS | - RTE_ETH_TX_OFFLOAD_TCP_TSO | - RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO | - RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO | - RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO | - RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE | - hns3_txvlan_cap_get(hw)); - - if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM)) - info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM; - - if (hns3_dev_get_support(hw, INDEP_TXRX)) - info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP | - RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP; - info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP; - - info->rx_desc_lim = (struct rte_eth_desc_lim) { - .nb_max = HNS3_MAX_RING_DESC, - .nb_min = HNS3_MIN_RING_DESC, - .nb_align = HNS3_ALIGN_RING_DESC, - }; - - info->tx_desc_lim = (struct rte_eth_desc_lim) { - .nb_max = HNS3_MAX_RING_DESC, - .nb_min = HNS3_MIN_RING_DESC, - .nb_align = HNS3_ALIGN_RING_DESC, - .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT, - .nb_mtu_seg_max = hw->max_non_tso_bd_num, - }; - - info->default_rxconf = (struct rte_eth_rxconf) { - .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH, - /* - * If there are no available Rx buffer descriptors, incoming - * packets are always dropped by hardware based on hns3 network - * engine. - */ - .rx_drop_en = 1, - .offloads = 0, - }; - info->default_txconf = (struct rte_eth_txconf) { - .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH, - .offloads = 0, - }; - - info->reta_size = hw->rss_ind_tbl_size; - info->hash_key_size = HNS3_RSS_KEY_SIZE; - info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT; - - info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE; - info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE; - info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM; - info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM; - info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC; - info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC; - - return 0; -} - static void hns3vf_clear_event_cause(struct hns3_hw *hw, uint32_t regclr) { @@ -1632,7 +1481,7 @@ hns3vf_init_hardware(struct hns3_adapter *hns) * some error caused by the residual configurations, such as the * unexpected interrupt, can be avoid. */ - ret = hns3vf_init_ring_with_vector(hw); + ret = hns3_init_ring_with_vector(hw); if (ret) { PMD_INIT_LOG(ERR, "Failed to init ring intr vector: %d", ret); goto err_init_hardware; @@ -1819,41 +1668,6 @@ hns3vf_do_stop(struct hns3_adapter *hns) return 0; } -static void -hns3vf_unmap_rx_interrupt(struct rte_eth_dev *dev) -{ - struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); - struct rte_intr_handle *intr_handle = pci_dev->intr_handle; - uint8_t base = RTE_INTR_VEC_ZERO_OFFSET; - uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET; - uint16_t q_id; - - if (dev->data->dev_conf.intr_conf.rxq == 0) - return; - - /* unmap the ring with vector */ - if (rte_intr_allow_others(intr_handle)) { - vec = RTE_INTR_VEC_RXTX_OFFSET; - base = RTE_INTR_VEC_RXTX_OFFSET; - } - if (rte_intr_dp_is_en(intr_handle)) { - for (q_id = 0; q_id < hw->used_rx_queues; q_id++) { - (void)hns3vf_bind_ring_with_vector(hw, vec, false, - HNS3_RING_TYPE_RX, - q_id); - if (vec < base + rte_intr_nb_efd_get(intr_handle) - - 1) - vec++; - } - } - /* Clean datapath event and queue/vec mapping */ - rte_intr_efd_disable(intr_handle); - - /* Cleanup vector list */ - rte_intr_vec_list_free(intr_handle); -} - static int hns3vf_dev_stop(struct rte_eth_dev *dev) { @@ -1875,7 +1689,7 @@ hns3vf_dev_stop(struct rte_eth_dev *dev) if (__atomic_load_n(&hw->reset.resetting, __ATOMIC_RELAXED) == 0) { hns3_stop_tqps(hw); hns3vf_do_stop(hns); - hns3vf_unmap_rx_interrupt(dev); + hns3_unmap_rx_interrupt(dev); hw->adapter_state = HNS3_NIC_CONFIGURED; } hns3_rx_scattered_reset(dev); @@ -1916,34 +1730,6 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev) return ret; } -static int -hns3vf_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version, - size_t fw_size) -{ - struct hns3_adapter *hns = eth_dev->data->dev_private; - struct hns3_hw *hw = &hns->hw; - uint32_t version = hw->fw_version; - int ret; - - ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu", - hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M, - HNS3_FW_VERSION_BYTE3_S), - hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M, - HNS3_FW_VERSION_BYTE2_S), - hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M, - HNS3_FW_VERSION_BYTE1_S), - hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M, - HNS3_FW_VERSION_BYTE0_S)); - if (ret < 0) - return -EINVAL; - - ret += 1; /* add the size of '\0' */ - if (fw_size < (size_t)ret) - return ret; - else - return 0; -} - static int hns3vf_dev_link_update(struct rte_eth_dev *eth_dev, __rte_unused int wait_to_complete) @@ -2005,99 +1791,6 @@ hns3vf_do_start(struct hns3_adapter *hns, bool reset_queue) return ret; } -static int -hns3vf_map_rx_interrupt(struct rte_eth_dev *dev) -{ - struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); - struct rte_intr_handle *intr_handle = pci_dev->intr_handle; - struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint8_t base = RTE_INTR_VEC_ZERO_OFFSET; - uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET; - uint32_t intr_vector; - uint16_t q_id; - int ret; - - /* - * hns3 needs a separate interrupt to be used as event interrupt which - * could not be shared with task queue pair, so KERNEL drivers need - * support multiple interrupt vectors. - */ - if (dev->data->dev_conf.intr_conf.rxq == 0 || - !rte_intr_cap_multiple(intr_handle)) - return 0; - - rte_intr_disable(intr_handle); - intr_vector = hw->used_rx_queues; - /* It creates event fd for each intr vector when MSIX is used */ - if (rte_intr_efd_enable(intr_handle, intr_vector)) - return -EINVAL; - - /* Allocate vector list */ - if (rte_intr_vec_list_alloc(intr_handle, "intr_vec", - hw->used_rx_queues)) { - hns3_err(hw, "Failed to allocate %u rx_queues" - " intr_vec", hw->used_rx_queues); - ret = -ENOMEM; - goto vf_alloc_intr_vec_error; - } - - if (rte_intr_allow_others(intr_handle)) { - vec = RTE_INTR_VEC_RXTX_OFFSET; - base = RTE_INTR_VEC_RXTX_OFFSET; - } - - for (q_id = 0; q_id < hw->used_rx_queues; q_id++) { - ret = hns3vf_bind_ring_with_vector(hw, vec, true, - HNS3_RING_TYPE_RX, q_id); - if (ret) - goto vf_bind_vector_error; - - if (rte_intr_vec_list_index_set(intr_handle, q_id, vec)) - goto vf_bind_vector_error; - - /* - * If there are not enough efds (e.g. not enough interrupt), - * remaining queues will be bond to the last interrupt. - */ - if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1) - vec++; - } - rte_intr_enable(intr_handle); - return 0; - -vf_bind_vector_error: - rte_intr_vec_list_free(intr_handle); -vf_alloc_intr_vec_error: - rte_intr_efd_disable(intr_handle); - return ret; -} - -static int -hns3vf_restore_rx_interrupt(struct hns3_hw *hw) -{ - struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id]; - struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); - struct rte_intr_handle *intr_handle = pci_dev->intr_handle; - uint16_t q_id; - int ret; - - if (dev->data->dev_conf.intr_conf.rxq == 0) - return 0; - - if (rte_intr_dp_is_en(intr_handle)) { - for (q_id = 0; q_id < hw->used_rx_queues; q_id++) { - ret = hns3vf_bind_ring_with_vector(hw, - rte_intr_vec_list_index_get(intr_handle, - q_id), - true, HNS3_RING_TYPE_RX, q_id); - if (ret) - return ret; - } - } - - return 0; -} - static void hns3vf_restore_filter(struct rte_eth_dev *dev) { @@ -2123,7 +1816,7 @@ hns3vf_dev_start(struct rte_eth_dev *dev) rte_spinlock_unlock(&hw->lock); return ret; } - ret = hns3vf_map_rx_interrupt(dev); + ret = hns3_map_rx_interrupt(dev); if (ret) goto map_rx_inter_err; @@ -2382,7 +2075,7 @@ hns3vf_check_default_mac_change(struct hns3_hw *hw) * ethdev driver sets the MAC address for VF device after the * initialization of the related VF device, the PF driver will notify * VF driver to reset VF device to make the new MAC address effective - * immediately. The hns3 VF PMD driver should check whether the MAC + * immediately. The hns3 VF PMD should check whether the MAC * address has been changed by the PF kernel ethdev driver, if changed * VF driver should configure hardware using the new MAC address in the * recovering hardware configuration stage of the reset process. @@ -2440,7 +2133,7 @@ hns3vf_restore_conf(struct hns3_adapter *hns) if (ret) goto err_vlan_table; - ret = hns3vf_restore_rx_interrupt(hw); + ret = hns3_restore_rx_interrupt(hw); if (ret) goto err_vlan_table; @@ -2614,8 +2307,8 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = { .xstats_reset = hns3_dev_xstats_reset, .xstats_get_by_id = hns3_dev_xstats_get_by_id, .xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id, - .dev_infos_get = hns3vf_dev_infos_get, - .fw_version_get = hns3vf_fw_version_get, + .dev_infos_get = hns3_dev_infos_get, + .fw_version_get = hns3_fw_version_get, .rx_queue_setup = hns3_rx_queue_setup, .tx_queue_setup = hns3_tx_queue_setup, .rx_queue_release = hns3_dev_rx_queue_release, @@ -2664,6 +2357,7 @@ hns3vf_init_hw_ops(struct hns3_hw *hw) hw->ops.del_mc_mac_addr = hns3vf_remove_mc_mac_addr; hw->ops.add_uc_mac_addr = hns3vf_add_uc_mac_addr; hw->ops.del_uc_mac_addr = hns3vf_remove_uc_mac_addr; + hw->ops.bind_ring_with_vector = hns3vf_bind_ring_with_vector; } static int @@ -2722,12 +2416,12 @@ hns3vf_dev_init(struct rte_eth_dev *eth_dev) /* * The hns3 PF ethdev driver in kernel support setting VF MAC address * on the host by "ip link set ..." command. To avoid some incorrect - * scenes, for example, hns3 VF PMD driver fails to receive and send + * scenes, for example, hns3 VF PMD fails to receive and send * packets after user configure the MAC address by using the - * "ip link set ..." command, hns3 VF PMD driver keep the same MAC + * "ip link set ..." command, hns3 VF PMD keep the same MAC * address strategy as the hns3 kernel ethdev driver in the * initialization. If user configure a MAC address by the ip command - * for VF device, then hns3 VF PMD driver will start with it, otherwise + * for VF device, then hns3 VF PMD will start with it, otherwise * start with a random MAC address in the initialization. */ if (rte_is_zero_ether_addr((struct rte_ether_addr *)hw->mac.mac_addr))