int rw_piot_update_mtu(rw_piot_api_handle_t api_handle, uint32_t mtu) { rw_piot_device_t *rw_piot_dev = RWPIOT_GET_DEVICE(api_handle); ASSERT(RWPIOT_VALID_DEVICE(rw_piot_dev)); if (NULL == rw_piot_dev) { RW_PIOT_LOG(RTE_LOG_ERR, "PIOT Could not find device by handle\n"); return -1; } return(rte_eth_dev_set_mtu(rw_piot_dev->rte_port_id, mtu)); }
static int kni_change_mtu(uint8_t port_id, unsigned new_mtu) { int ret; if (port_id >= rte_eth_dev_count()) return -EINVAL; if (new_mtu > ETHER_MAX_LEN) return -EINVAL; /* Set new MTU */ ret = rte_eth_dev_set_mtu(port_id, new_mtu); if (ret < 0) return ret; return 0; }
/* * Initialize a given port using default settings and with the RX buffers * coming from the mbuf_pool passed as a parameter. * FIXME: Starting with assumption of one thread/core per port */ static inline int uhd_dpdk_port_init(struct uhd_dpdk_port *port, struct rte_mempool *rx_mbuf_pool, unsigned int mtu) { int retval; /* Check for a valid port */ if (port->id >= rte_eth_dev_count()) return -ENODEV; /* Set up Ethernet device with defaults (1 RX ring, 1 TX ring) */ retval = rte_eth_dev_set_mtu(port->id, mtu); if (retval) { uint16_t actual_mtu; RTE_LOG(WARNING, EAL, "%d: Could not set mtu to %d\n", retval, mtu); rte_eth_dev_get_mtu(port->id, &actual_mtu); RTE_LOG(WARNING, EAL, "Current mtu=%d\n", actual_mtu); mtu = actual_mtu; } // Require checksum offloads struct rte_eth_dev_info dev_info; rte_eth_dev_info_get(port->id, &dev_info); uint64_t rx_offloads = DEV_RX_OFFLOAD_IPV4_CKSUM; uint64_t tx_offloads = DEV_TX_OFFLOAD_IPV4_CKSUM; if ((dev_info.rx_offload_capa & rx_offloads) != rx_offloads) { RTE_LOG(WARNING, EAL, "%d: Only supports RX offloads 0x%0llx\n", port->id, dev_info.rx_offload_capa); rte_exit(EXIT_FAILURE, "Missing required RX offloads\n"); } if ((dev_info.tx_offload_capa & tx_offloads) != tx_offloads) { RTE_LOG(WARNING, EAL, "%d: Only supports TX offloads 0x%0llx\n", port->id, dev_info.tx_offload_capa); rte_exit(EXIT_FAILURE, "Missing required TX offloads\n"); } struct rte_eth_conf port_conf = { .rxmode = { .offloads = rx_offloads | DEV_RX_OFFLOAD_JUMBO_FRAME, .max_rx_pkt_len = mtu, .jumbo_frame = 1, .hw_ip_checksum = 1, .ignore_offload_bitfield = 0, }, .txmode = { .offloads = tx_offloads, } };
/* Init KNI RX queue */ struct vr_dpdk_queue * vr_dpdk_kni_rx_queue_init(unsigned lcore_id, struct vr_interface *vif, unsigned host_lcore_id) { struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id]; const unsigned socket_id = rte_lcore_to_socket_id(lcore_id); uint8_t port_id = 0; unsigned vif_idx = vif->vif_idx; struct vr_dpdk_queue *rx_queue = &lcore->lcore_rx_queues[vif_idx]; struct vr_dpdk_queue_params *rx_queue_params = &lcore->lcore_rx_queue_params[vif_idx]; if (vif->vif_type == VIF_TYPE_HOST) { port_id = (((struct vr_dpdk_ethdev *)(vif->vif_bridge->vif_os))-> ethdev_port_id); } /* init queue */ rx_queue->rxq_ops = dpdk_knidev_reader_ops; rx_queue->q_queue_h = NULL; rx_queue->q_vif = vrouter_get_interface(vif->vif_rid, vif_idx); /* create the queue */ struct dpdk_knidev_reader_params reader_params = { .kni = vif->vif_os, }; rx_queue->q_queue_h = rx_queue->rxq_ops.f_create(&reader_params, socket_id); if (rx_queue->q_queue_h == NULL) { RTE_LOG(ERR, VROUTER, " error creating KNI device %s RX queue" " at eth device %" PRIu8 "\n", vif->vif_name, port_id); return NULL; } /* store queue params */ rx_queue_params->qp_release_op = &dpdk_kni_rx_queue_release; return rx_queue; } /* Release KNI TX queue */ static void dpdk_kni_tx_queue_release(unsigned lcore_id, struct vr_interface *vif) { struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id]; struct vr_dpdk_queue *tx_queue = &lcore->lcore_tx_queues[vif->vif_idx]; struct vr_dpdk_queue_params *tx_queue_params = &lcore->lcore_tx_queue_params[vif->vif_idx]; tx_queue->txq_ops.f_tx = NULL; rte_wmb(); /* flush and free the queue */ if (tx_queue->txq_ops.f_free(tx_queue->q_queue_h)) { RTE_LOG(ERR, VROUTER, " error freeing lcore %u KNI device TX queue\n", lcore_id); } /* reset the queue */ vrouter_put_interface(tx_queue->q_vif); memset(tx_queue, 0, sizeof(*tx_queue)); memset(tx_queue_params, 0, sizeof(*tx_queue_params)); } /* Init KNI TX queue */ struct vr_dpdk_queue * vr_dpdk_kni_tx_queue_init(unsigned lcore_id, struct vr_interface *vif, unsigned host_lcore_id) { struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id]; const unsigned socket_id = rte_lcore_to_socket_id(lcore_id); uint8_t port_id = 0; unsigned vif_idx = vif->vif_idx; struct vr_dpdk_queue *tx_queue = &lcore->lcore_tx_queues[vif_idx]; struct vr_dpdk_queue_params *tx_queue_params = &lcore->lcore_tx_queue_params[vif_idx]; struct vr_dpdk_ethdev *ethdev; if (vif->vif_type == VIF_TYPE_HOST) { ethdev = vif->vif_bridge->vif_os; if (ethdev == NULL) { RTE_LOG(ERR, VROUTER, " error creating KNI device %s TX queue:" " bridge vif %u ethdev is not initialized\n", vif->vif_name, vif->vif_bridge->vif_idx); return NULL; } port_id = ethdev->ethdev_port_id; } /* init queue */ tx_queue->txq_ops = dpdk_knidev_writer_ops; tx_queue->q_queue_h = NULL; tx_queue->q_vif = vrouter_get_interface(vif->vif_rid, vif_idx); /* create the queue */ struct dpdk_knidev_writer_params writer_params = { .kni = vif->vif_os, .tx_burst_sz = VR_DPDK_TX_BURST_SZ, }; tx_queue->q_queue_h = tx_queue->txq_ops.f_create(&writer_params, socket_id); if (tx_queue->q_queue_h == NULL) { RTE_LOG(ERR, VROUTER, " error creating KNI device %s TX queue" " at eth device %" PRIu8 "\n", vif->vif_name, port_id); return NULL; } /* store queue params */ tx_queue_params->qp_release_op = &dpdk_kni_tx_queue_release; return tx_queue; } /* Change KNI MTU size callback */ static int dpdk_knidev_change_mtu(uint8_t port_id, unsigned new_mtu) { struct vrouter *router = vrouter_get(0); struct vr_interface *vif; int i, ret; uint8_t ethdev_port_id, slave_port_id; struct vr_dpdk_ethdev *ethdev = NULL; RTE_LOG(INFO, VROUTER, "Changing eth device %" PRIu8 " MTU to %u\n", port_id, new_mtu); if (port_id >= rte_eth_dev_count()) { RTE_LOG(ERR, VROUTER, "Error changing eth device %"PRIu8" MTU: invalid eth device\n", port_id); return -EINVAL; } /* * TODO: DPDK bond PMD does not implement mtu_set op, so we need to * set the MTU manually for all the slaves. */ /* Bond vif uses first slave port ID. */ if (router->vr_eth_if) { ethdev = (struct vr_dpdk_ethdev *)router->vr_eth_if->vif_os; if (ethdev && ethdev->ethdev_nb_slaves > 0) { for (i = 0; i < ethdev->ethdev_nb_slaves; i++) { if (port_id == ethdev->ethdev_slaves[i]) break; } /* Clear ethdev if no port match. */ if (i >= ethdev->ethdev_nb_slaves) ethdev = NULL; } } if (ethdev && ethdev->ethdev_nb_slaves > 0) { for (i = 0; i < ethdev->ethdev_nb_slaves; i++) { slave_port_id = ethdev->ethdev_slaves[i]; RTE_LOG(INFO, VROUTER, " changing bond member eth device %" PRIu8 " MTU to %u\n", slave_port_id, new_mtu); ret = rte_eth_dev_set_mtu(slave_port_id, new_mtu); if (ret < 0) { RTE_LOG(ERR, VROUTER, " error changing bond member eth device %" PRIu8 " MTU: %s (%d)\n", slave_port_id, rte_strerror(-ret), -ret); return ret; } } } else { ret = rte_eth_dev_set_mtu(port_id, new_mtu); if (ret < 0) { RTE_LOG(ERR, VROUTER, "Error changing eth device %" PRIu8 " MTU: %s (%d)\n", port_id, rte_strerror(-ret), -ret); } return ret; } /* On success, inform vrouter about new MTU */ for (i = 0; i < router->vr_max_interfaces; i++) { vif = __vrouter_get_interface(router, i); if (vif && (vif->vif_type == VIF_TYPE_PHYSICAL)) { ethdev_port_id = (((struct vr_dpdk_ethdev *)(vif->vif_os))-> ethdev_port_id); if (ethdev_port_id == port_id) { /* Ethernet header size */ new_mtu += sizeof(struct vr_eth); if (vr_dpdk.vlan_tag != VLAN_ID_INVALID) { /* 802.1q header size */ new_mtu += sizeof(uint32_t); } vif->vif_mtu = new_mtu; if (vif->vif_bridge) vif->vif_bridge->vif_mtu = new_mtu; } } } return 0; } /* Configure KNI state callback */ static int dpdk_knidev_config_network_if(uint8_t port_id, uint8_t if_up) { int ret = 0; RTE_LOG(INFO, VROUTER, "Configuring eth device %" PRIu8 " %s\n", port_id, if_up ? "UP" : "DOWN"); if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) { RTE_LOG(ERR, VROUTER, "Invalid eth device %" PRIu8 "\n", port_id); return -EINVAL; } if (if_up) ret = rte_eth_dev_start(port_id); else rte_eth_dev_stop(port_id); if (ret < 0) { RTE_LOG(ERR, VROUTER, "Configuring eth device %" PRIu8 " UP" "failed (%d)\n", port_id, ret); } return ret; } /* Init KNI */ int vr_dpdk_knidev_init(uint8_t port_id, struct vr_interface *vif) { int i; struct rte_eth_dev_info dev_info; struct rte_kni_conf kni_conf; struct rte_kni_ops kni_ops; struct rte_kni *kni; struct rte_config *rte_conf = rte_eal_get_configuration(); if (!vr_dpdk.kni_inited) { /* * If the host does not support KNIs (i.e. RedHat), we'll get * a panic here. */ rte_kni_init(VR_DPDK_MAX_KNI_INTERFACES); vr_dpdk.kni_inited = true; } /* get eth device info */ memset(&dev_info, 0, sizeof(dev_info)); rte_eth_dev_info_get(port_id, &dev_info); /* create KNI configuration */ memset(&kni_conf, 0, sizeof(kni_conf)); strncpy(kni_conf.name, (char *)vif->vif_name, sizeof(kni_conf.name) - 1); kni_conf.addr = dev_info.pci_dev->addr; kni_conf.id = dev_info.pci_dev->id; kni_conf.group_id = port_id; kni_conf.mbuf_size = VR_DPDK_MAX_PACKET_SZ; /* * Due to DPDK commit 41a6ebd, now to prevent packet reordering in KNI * we have to bind KNI kernel thread to a first online unused CPU. */ for (i = 0; i < RTE_MAX_LCORE; i++) { if (lcore_config[i].detected && rte_conf->lcore_role[VR_DPDK_FWD_LCORE_ID + i] == ROLE_OFF) { kni_conf.force_bind = 1; kni_conf.core_id = i; RTE_LOG(INFO, VROUTER, " bind KNI kernel thread to CPU %d\n", i); break; } } /* KNI options * * Changing state of the KNI interface can change state of the physical * interface. This is useful for the vhost, but not for the VLAN * forwarding interface. */ if (vif->vif_type == VIF_TYPE_VLAN) { memset(&kni_ops, 0, sizeof(kni_ops)); } else { kni_ops.port_id = port_id; kni_ops.change_mtu = dpdk_knidev_change_mtu; kni_ops.config_network_if = dpdk_knidev_config_network_if; } /* allocate KNI device */ kni = rte_kni_alloc(vr_dpdk.rss_mempool, &kni_conf, &kni_ops); if (kni == NULL) { RTE_LOG(ERR, VROUTER, " error allocation KNI device %s" " at eth device %" PRIu8 "\n", vif->vif_name, port_id); return -ENOMEM; } /* store pointer to KNI for further use */ vif->vif_os = kni; /* add interface to the table of KNIs */ for (i = 0; i < VR_DPDK_MAX_KNI_INTERFACES; i++) { if (vr_dpdk.knis[i] == NULL) { vr_dpdk.knis[i] = vif->vif_os; break; } } return 0; }
lagopus_result_t dpdk_configure_interface(struct interface *ifp) { unsigned socket; uint32_t lcore; uint8_t queue; int ret; uint32_t n_rx_queues, n_tx_queues; uint8_t portid; struct rte_mempool *pool; portid = ifp->info.eth.port_number; n_rx_queues = app_get_nic_rx_queues_per_port(portid); n_tx_queues = app.nic_tx_port_mask[portid]; if ((n_rx_queues == 0) && (n_tx_queues == 0)) { return LAGOPUS_RESULT_INVALID_ARGS; } if (ifp->info.eth_dpdk_phy.mtu < 64 || ifp->info.eth_dpdk_phy.mtu > MAX_PACKET_SZ) { return LAGOPUS_RESULT_OUT_OF_RANGE; } rte_eth_dev_info_get(portid, &ifp->devinfo); /* Init port */ printf("Initializing NIC port %u ...\n", (unsigned) portid); ret = rte_eth_dev_configure(portid, (uint8_t) n_rx_queues, (uint8_t) n_tx_queues, &port_conf); if (ret < 0) { rte_panic("Cannot init NIC port %u (%s)\n", (unsigned) portid, strerror(-ret)); } ret = rte_eth_dev_set_mtu(portid, ifp->info.eth_dpdk_phy.mtu); if (ret < 0) { rte_panic("Cannot set MTU(%d) for port %d (%d)\n", ifp->info.eth_dpdk_phy.mtu, portid, ret); } rte_eth_promiscuous_enable(portid); /* Init RX queues */ for (queue = 0; queue < APP_MAX_RX_QUEUES_PER_NIC_PORT; queue ++) { struct app_lcore_params_io *lp; uint8_t i; if (app.nic_rx_queue_mask[portid][queue] == NIC_RX_QUEUE_UNCONFIGURED) { continue; } app_get_lcore_for_nic_rx(portid, queue, &lcore); lp = &app.lcore_params[lcore].io; socket = rte_lcore_to_socket_id(lcore); pool = app.lcore_params[lcore].pool; printf("Initializing NIC port %u RX queue %u ...\n", (unsigned) portid, (unsigned) queue); ret = rte_eth_rx_queue_setup(portid, queue, (uint16_t) app.nic_rx_ring_size, socket, #if defined(RTE_VERSION_NUM) && RTE_VERSION >= RTE_VERSION_NUM(1, 8, 0, 0) &ifp->devinfo.default_rxconf, #else &rx_conf, #endif /* RTE_VERSION_NUM */ pool); if (ret < 0) { rte_panic("Cannot init RX queue %u for port %u (%d)\n", (unsigned) queue, (unsigned) portid, ret); } for (i = 0; i < lp->rx.n_nic_queues; i++) { if (lp->rx.nic_queues[i].port != portid || lp->rx.nic_queues[i].queue != queue) { continue; } lp->rx.nic_queues[i].enabled = true; break; } } /* Init TX queues */ if (app.nic_tx_port_mask[portid] == 1) { app_get_lcore_for_nic_tx(portid, &lcore); socket = rte_lcore_to_socket_id(lcore); printf("Initializing NIC port %u TX queue 0 ...\n", (unsigned) portid); ret = rte_eth_tx_queue_setup(portid, 0, (uint16_t) app.nic_tx_ring_size, socket, #if defined(RTE_VERSION_NUM) && RTE_VERSION >= RTE_VERSION_NUM(1, 8, 0, 0) &ifp->devinfo.default_txconf #else &tx_conf #endif /* RTE_VERSION_NUM */ ); if (ret < 0) { rte_panic("Cannot init TX queue 0 for port %d (%d)\n", portid, ret); } } ifp->stats = port_stats; dpdk_interface_set_index(ifp); return LAGOPUS_RESULT_OK; }