+static struct egress_policer *
+egress_policer_get__(const struct netdev *netdev_)
+{
+ struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
+ return CONTAINER_OF(netdev->qos_conf, struct egress_policer, qos_conf);
+}
+
+static int
+egress_policer_qos_construct(struct netdev *netdev_,
+ const struct smap *details)
+{
+ struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
+ struct egress_policer *policer;
+ const char *cir_s;
+ const char *cbs_s;
+ int err = 0;
+
+ rte_spinlock_lock(&netdev->qos_lock);
+ policer = xmalloc(sizeof *policer);
+ qos_conf_init(&policer->qos_conf, &egress_policer_ops);
+ netdev->qos_conf = &policer->qos_conf;
+ cir_s = smap_get(details, "cir");
+ cbs_s = smap_get(details, "cbs");
+ policer->app_srtcm_params.cir = cir_s ? strtoull(cir_s, NULL, 10) : 0;
+ policer->app_srtcm_params.cbs = cbs_s ? strtoull(cbs_s, NULL, 10) : 0;
+ policer->app_srtcm_params.ebs = 0;
+ err = rte_meter_srtcm_config(&policer->egress_meter,
+ &policer->app_srtcm_params);
+ rte_spinlock_unlock(&netdev->qos_lock);
+
+ return err;
+}
+
+static void
+egress_policer_qos_destruct(struct netdev *netdev_ OVS_UNUSED,
+ struct qos_conf *conf)
+{
+ struct egress_policer *policer = CONTAINER_OF(conf, struct egress_policer,
+ qos_conf);
+ free(policer);
+}
+
+static int
+egress_policer_qos_get(const struct netdev *netdev, struct smap *details)
+{
+ struct egress_policer *policer = egress_policer_get__(netdev);
+ smap_add_format(details, "cir", "%llu",
+ 1ULL * policer->app_srtcm_params.cir);
+ smap_add_format(details, "cbs", "%llu",
+ 1ULL * policer->app_srtcm_params.cbs);
+ return 0;
+}
+
+static int
+egress_policer_qos_set(struct netdev *netdev_, const struct smap *details)
+{
+ struct egress_policer *policer;
+ const char *cir_s;
+ const char *cbs_s;
+ int err = 0;
+
+ policer = egress_policer_get__(netdev_);
+ cir_s = smap_get(details, "cir");
+ cbs_s = smap_get(details, "cbs");
+ policer->app_srtcm_params.cir = cir_s ? strtoull(cir_s, NULL, 10) : 0;
+ policer->app_srtcm_params.cbs = cbs_s ? strtoull(cbs_s, NULL, 10) : 0;
+ policer->app_srtcm_params.ebs = 0;
+ err = rte_meter_srtcm_config(&policer->egress_meter,
+ &policer->app_srtcm_params);
+
+ return err;
+}
+
+static inline bool
+egress_policer_pkt_handle__(struct rte_meter_srtcm *meter,
+ struct rte_mbuf *pkt, uint64_t time)
+{
+ uint32_t pkt_len = rte_pktmbuf_pkt_len(pkt) - sizeof(struct ether_hdr);
+
+ return rte_meter_srtcm_color_blind_check(meter, time, pkt_len) ==
+ e_RTE_METER_GREEN;
+}
+
+static int
+egress_policer_run(struct netdev *netdev_, struct rte_mbuf **pkts,
+ int pkt_cnt)
+{
+ int i = 0;
+ int cnt = 0;
+ struct egress_policer *policer = egress_policer_get__(netdev_);
+ struct rte_mbuf *pkt = NULL;
+ uint64_t current_time = rte_rdtsc();
+
+ for(i = 0; i < pkt_cnt; i++) {
+ pkt = pkts[i];
+ /* Handle current packet */
+ if (egress_policer_pkt_handle__(&policer->egress_meter, pkt,
+ current_time)) {
+ if (cnt != i) {
+ pkts[cnt] = pkt;
+ }
+ cnt++;
+ } else {
+ rte_pktmbuf_free(pkt);
+ }
+ }
+
+ return cnt;
+}
+
+static const struct dpdk_qos_ops egress_policer_ops = {
+ "egress-policer", /* qos_name */
+ egress_policer_qos_construct,
+ egress_policer_qos_destruct,
+ egress_policer_qos_get,
+ egress_policer_qos_set,
+ egress_policer_run
+};
+
+#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, MULTIQ, SEND, \
+ GET_CARRIER, GET_STATS, GET_FEATURES, GET_STATUS, RXQ_RECV) \
+{ \
+ NAME, \
+ INIT, /* init */ \
+ NULL, /* netdev_dpdk_run */ \
+ NULL, /* netdev_dpdk_wait */ \
+ \
+ netdev_dpdk_alloc, \
+ CONSTRUCT, \
+ DESTRUCT, \
+ netdev_dpdk_dealloc, \
+ netdev_dpdk_get_config, \
+ netdev_dpdk_set_config, \
+ NULL, /* get_tunnel_config */ \
+ NULL, /* build header */ \
+ NULL, /* push header */ \
+ NULL, /* pop header */ \
+ netdev_dpdk_get_numa_id, /* get_numa_id */ \
+ MULTIQ, /* set_multiq */ \
+ \
+ SEND, /* send */ \
+ NULL, /* send_wait */ \
+ \
+ netdev_dpdk_set_etheraddr, \
+ netdev_dpdk_get_etheraddr, \
+ netdev_dpdk_get_mtu, \
+ netdev_dpdk_set_mtu, \
+ netdev_dpdk_get_ifindex, \
+ GET_CARRIER, \
+ netdev_dpdk_get_carrier_resets, \
+ netdev_dpdk_set_miimon, \
+ GET_STATS, \
+ GET_FEATURES, \
+ NULL, /* set_advertisements */ \
+ \
+ NULL, /* set_policing */ \
+ netdev_dpdk_get_qos_types, \
+ NULL, /* get_qos_capabilities */ \
+ netdev_dpdk_get_qos, \
+ netdev_dpdk_set_qos, \
+ NULL, /* get_queue */ \
+ NULL, /* set_queue */ \
+ NULL, /* delete_queue */ \
+ NULL, /* get_queue_stats */ \
+ NULL, /* queue_dump_start */ \
+ NULL, /* queue_dump_next */ \
+ NULL, /* queue_dump_done */ \
+ NULL, /* dump_queue_stats */ \
+ \
+ NULL, /* get_in4 */ \
+ NULL, /* set_in4 */ \
+ NULL, /* get_in6 */ \
+ NULL, /* add_router */ \
+ NULL, /* get_next_hop */ \
+ GET_STATUS, \
+ NULL, /* arp_lookup */ \
+ \
+ netdev_dpdk_update_flags, \
+ \
+ netdev_dpdk_rxq_alloc, \
+ netdev_dpdk_rxq_construct, \
+ netdev_dpdk_rxq_destruct, \
+ netdev_dpdk_rxq_dealloc, \
+ RXQ_RECV, \
+ NULL, /* rx_wait */ \
+ NULL, /* rxq_drain */ \
+}
+
+static int
+process_vhost_flags(char *flag, char *default_val, int size,
+ char **argv, char **new_val)
+{
+ int changed = 0;
+
+ /* Depending on which version of vhost is in use, process the vhost-specific
+ * flag if it is provided on the vswitchd command line, otherwise resort to
+ * a default value.
+ *
+ * For vhost-user: Process "-vhost_sock_dir" to set the custom location of
+ * the vhost-user socket(s).
+ * For vhost-cuse: Process "-cuse_dev_name" to set the custom name of the
+ * vhost-cuse character device.
+ */
+ if (!strcmp(argv[1], flag) && (strlen(argv[2]) <= size)) {
+ changed = 1;
+ *new_val = xstrdup(argv[2]);
+ VLOG_INFO("User-provided %s in use: %s", flag, *new_val);
+ } else {
+ VLOG_INFO("No %s provided - defaulting to %s", flag, default_val);
+ *new_val = default_val;
+ }
+
+ return changed;
+}
+