From patchwork Tue Nov 24 04:54:32 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarno Rajahalme X-Patchwork-Id: 547819 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (unknown [IPv6:2600:3c00::f03c:91ff:fe6e:bdf7]) by ozlabs.org (Postfix) with ESMTP id A2FBC1402B8 for ; Tue, 24 Nov 2015 15:56:12 +1100 (AEDT) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id 8DAFC1086D; Mon, 23 Nov 2015 20:55:55 -0800 (PST) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v3.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id E51071076A for ; Mon, 23 Nov 2015 20:55:52 -0800 (PST) Received: from bar4.cudamail.com (localhost [127.0.0.1]) by mx3v3.cudamail.com (Postfix) with ESMTPS id 79B94161604 for ; Mon, 23 Nov 2015 21:55:52 -0700 (MST) X-ASG-Debug-ID: 1448340951-03dc217b9d238630001-byXFYA Received: from mx3-pf2.cudamail.com ([192.168.14.1]) by bar4.cudamail.com with ESMTP id gLEdUMi6AXCMWrHS (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 23 Nov 2015 21:55:52 -0700 (MST) X-Barracuda-Envelope-From: jarno@ovn.org X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.1 Received: from unknown (HELO relay4-d.mail.gandi.net) (217.70.183.196) by mx3-pf2.cudamail.com with ESMTPS (DHE-RSA-AES256-SHA encrypted); 24 Nov 2015 04:55:51 -0000 Received-SPF: pass (mx3-pf2.cudamail.com: SPF record at ovn.org designates 217.70.183.196 as permitted sender) X-Barracuda-Apparent-Source-IP: 217.70.183.196 X-Barracuda-RBL-IP: 217.70.183.196 Received: from mfilter17-d.gandi.net (mfilter17-d.gandi.net [217.70.178.145]) by relay4-d.mail.gandi.net (Postfix) with ESMTP id D2E3B1720AC; Tue, 24 Nov 2015 05:55:47 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mfilter17-d.gandi.net Received: from relay4-d.mail.gandi.net ([IPv6:::ffff:217.70.183.196]) by mfilter17-d.gandi.net (mfilter17-d.gandi.net [::ffff:10.0.15.180]) (amavisd-new, port 10024) with ESMTP id PVGPOnpptIVO; Tue, 24 Nov 2015 05:55:45 +0100 (CET) X-Originating-IP: 208.91.1.34 Received: from sc9-mailhost1.vmware.com (unknown [208.91.1.34]) (Authenticated sender: jarno@ovn.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 2038C1720A3; Tue, 24 Nov 2015 05:55:44 +0100 (CET) X-CudaMail-Envelope-Sender: jarno@ovn.org From: Jarno Rajahalme To: dev@openvswitch.org X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-V2-1122072613 X-CudaMail-DTE: 112315 X-CudaMail-Originating-IP: 217.70.183.196 Date: Mon, 23 Nov 2015 20:54:32 -0800 X-ASG-Orig-Subj: [##CM-V2-1122072613##][PATCH v3 1/4] dpif: Meter framework. Message-Id: <1448340875-2070-2-git-send-email-jarno@ovn.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1448340875-2070-1-git-send-email-jarno@ovn.org> References: <1448340875-2070-1-git-send-email-jarno@ovn.org> X-Barracuda-Connect: UNKNOWN[192.168.14.1] X-Barracuda-Start-Time: 1448340952 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-ASG-Whitelist: Header =?UTF-8?B?eFwtY3VkYW1haWxcLXdoaXRlbGlzdFwtdG8=?= X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 Subject: [ovs-dev] [PATCH v3 1/4] dpif: Meter framework. X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" Add DPIF-level infrastructure for meters. Allow meter_set to modify the meter configuration (e.g. set the burst size if unspecified). Signed-off-by: Jarno Rajahalme --- datapath/linux/compat/include/linux/openvswitch.h | 8 ++- lib/dpif-netdev.c | 45 ++++++++++++ lib/dpif-netlink.c | 44 ++++++++++++ lib/dpif-provider.h | 29 ++++++++ lib/dpif.c | 88 +++++++++++++++++++++++ lib/dpif.h | 11 +++ lib/odp-execute.c | 5 ++ lib/odp-util.c | 14 ++++ ofproto/ofproto-dpif-sflow.c | 1 + ofproto/ofproto-dpif.c | 60 ++++++++++++++-- ofproto/ofproto-provider.h | 13 ++-- ofproto/ofproto.c | 2 +- 12 files changed, 306 insertions(+), 14 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index dae2e5b..1313d49 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -729,13 +729,14 @@ enum ovs_ct_attr { * fields within a header are modifiable, e.g. the IPv4 protocol and fragment * type may not be changed. * - * * @OVS_ACTION_ATTR_SET_TO_MASKED: Kernel internal masked set action translated * from the @OVS_ACTION_ATTR_SET. * @OVS_ACTION_ATTR_TUNNEL_PUSH: Push tunnel header described by struct * ovs_action_push_tnl. * @OVS_ACTION_ATTR_TUNNEL_POP: Lookup tunnel port by port-no passed and pop * tunnel header. + * @OVS_ACTION_ATTR_METER: Run packet through a meter, which may drop the + * packet, or modify the packet (e.g., change the DSCP field). */ enum ovs_action_attr { @@ -757,8 +758,9 @@ enum ovs_action_attr { OVS_ACTION_ATTR_CT, /* Nested OVS_CT_ATTR_* . */ #ifndef __KERNEL__ - OVS_ACTION_ATTR_TUNNEL_PUSH, /* struct ovs_action_push_tnl*/ - OVS_ACTION_ATTR_TUNNEL_POP, /* u32 port number. */ + OVS_ACTION_ATTR_TUNNEL_PUSH, /* struct ovs_action_push_tnl. */ + OVS_ACTION_ATTR_TUNNEL_POP, /* u32 port number. */ + OVS_ACTION_ATTR_METER, /* u32 meter number. */ #endif __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted * from userspace. */ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 47fa9e2..10d94e9 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -2714,6 +2714,46 @@ dp_netdev_disable_upcall(struct dp_netdev *dp) fat_rwlock_wrlock(&dp->upcall_rwlock); } + +/* Meters */ +static void +dpif_netdev_meter_get_features(const struct dpif * dpif OVS_UNUSED, + struct ofputil_meter_features *features) +{ + features->max_meters = 0; + features->band_types = 0; + features->capabilities = 0; + features->max_bands = 0; + features->max_color = 0; +} + +static int +dpif_netdev_meter_set(struct dpif *dpif OVS_UNUSED, + ofproto_meter_id *meter_id OVS_UNUSED, + struct ofputil_meter_config *config OVS_UNUSED) +{ + return EFBIG; /* meter_id out of range */ +} + +static int +dpif_netdev_meter_get(const struct dpif *dpif OVS_UNUSED, + ofproto_meter_id meter_id OVS_UNUSED, + struct ofputil_meter_stats *stats OVS_UNUSED, + uint16_t n_bands OVS_UNUSED) +{ + return EFBIG; /* meter_id out of range */ +} + +static int +dpif_netdev_meter_del(struct dpif *dpif OVS_UNUSED, + ofproto_meter_id meter_id OVS_UNUSED, + struct ofputil_meter_stats *stats OVS_UNUSED, + uint16_t n_bands OVS_UNUSED) +{ + return EFBIG; /* meter_id out of range */ +} + + static void dpif_netdev_disable_upcall(struct dpif *dpif) OVS_NO_THREAD_SAFETY_ANALYSIS @@ -3619,6 +3659,7 @@ dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt, VLOG_WARN("Cannot execute conntrack action in userspace."); break; + case OVS_ACTION_ATTR_METER: case OVS_ACTION_ATTR_PUSH_VLAN: case OVS_ACTION_ATTR_POP_VLAN: case OVS_ACTION_ATTR_PUSH_MPLS: @@ -3687,6 +3728,10 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_enable_upcall, dpif_netdev_disable_upcall, dpif_netdev_get_datapath_version, + dpif_netdev_meter_get_features, + dpif_netdev_meter_set, + dpif_netdev_meter_get, + dpif_netdev_meter_del, }; static void diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index c195042..aed4aaf 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -2279,6 +2279,46 @@ dpif_netlink_get_datapath_version(void) return version_str; } + +/* Meters */ +static void +dpif_netlink_meter_get_features(const struct dpif * dpif OVS_UNUSED, + struct ofputil_meter_features *features) +{ + features->max_meters = 0; + features->band_types = 0; + features->capabilities = 0; + features->max_bands = 0; + features->max_color = 0; +} + +static int +dpif_netlink_meter_set(struct dpif *dpif OVS_UNUSED, + ofproto_meter_id *meter_id OVS_UNUSED, + struct ofputil_meter_config *config OVS_UNUSED) +{ + return EFBIG; /* meter_id out of range */ +} + +static int +dpif_netlink_meter_get(const struct dpif *dpif OVS_UNUSED, + ofproto_meter_id meter_id OVS_UNUSED, + struct ofputil_meter_stats *stats OVS_UNUSED, + uint16_t n_bands OVS_UNUSED) +{ + return EFBIG; /* meter_id out of range */ +} + +static int +dpif_netlink_meter_del(struct dpif *dpif OVS_UNUSED, + ofproto_meter_id meter_id OVS_UNUSED, + struct ofputil_meter_stats *stats OVS_UNUSED, + uint16_t n_bands OVS_UNUSED) +{ + return EFBIG; /* meter_id out of range */ +} + + const struct dpif_class dpif_netlink_class = { "system", NULL, /* init */ @@ -2319,6 +2359,10 @@ const struct dpif_class dpif_netlink_class = { NULL, /* enable_upcall */ NULL, /* disable_upcall */ dpif_netlink_get_datapath_version, /* get_datapath_version */ + dpif_netlink_meter_get_features, + dpif_netlink_meter_set, + dpif_netlink_meter_get, + dpif_netlink_meter_del, }; static int diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 5415897..15b7892 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -390,6 +390,35 @@ struct dpif_class { /* Get datapath version. Caller is responsible for freeing the string * returned. */ char *(*get_datapath_version)(void); + + /* Meters */ + + /* Queries 'dpif' for supported meter features. + * NULL pointer means no meter features are supported. */ + void (*meter_get_features)(const struct dpif *, + struct ofputil_meter_features *); + + /* Adds or modifies 'meter' in 'dpif'. If '*meter_id' is UINT32_MAX, + * adds a new meter, otherwise modifies an existing meter. + * + * If meter is successfully added, sets '*meter_id' to the new meter's + * meter id selected by 'dpif'. */ + int (*meter_set)(struct dpif *, ofproto_meter_id *meter_id, + struct ofputil_meter_config *); + + /* Queries 'dpif' for meter stats with the given 'meter_id'. Stores + * maximum of 'n_bands' meter statistics, returning the number of band + * stats returned in 'stats->n_bands' if successful. */ + int (*meter_get)(const struct dpif *, ofproto_meter_id meter_id, + struct ofputil_meter_stats *, uint16_t n_bands); + + /* Removes meter 'meter_id' from 'dpif'. Stores meter and band statistics + * (for maximum of 'n_bands', returning the number of band stats returned + * in 'stats->n_bands' if successful. 'stats' may be passed in as NULL if + * no stats are needed, in which case 'n_bands' must be passed in as + * zero. */ + int (*meter_del)(struct dpif *, ofproto_meter_id meter_id, + struct ofputil_meter_stats *, uint16_t n_bands); }; extern const struct dpif_class dpif_netlink_class; diff --git a/lib/dpif.c b/lib/dpif.c index 3d6ac6e..06669d3 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -63,6 +63,9 @@ COVERAGE_DEFINE(dpif_flow_del); COVERAGE_DEFINE(dpif_execute); COVERAGE_DEFINE(dpif_purge); COVERAGE_DEFINE(dpif_execute_with_help); +COVERAGE_DEFINE(dpif_meter_set); +COVERAGE_DEFINE(dpif_meter_get); +COVERAGE_DEFINE(dpif_meter_del); static const struct dpif_class *base_dpif_classes[] = { #if defined(__linux__) || defined(_WIN32) @@ -1137,6 +1140,7 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet **packets, int cnt, } case OVS_ACTION_ATTR_HASH: + case OVS_ACTION_ATTR_METER: case OVS_ACTION_ATTR_PUSH_VLAN: case OVS_ACTION_ATTR_POP_VLAN: case OVS_ACTION_ATTR_PUSH_MPLS: @@ -1719,3 +1723,87 @@ dpif_supports_tnl_push_pop(const struct dpif *dpif) { return dpif_is_netdev(dpif); } + +/* Meters */ +void +dpif_meter_get_features(const struct dpif *dpif, + struct ofputil_meter_features *features) +{ + memset(features, 0, sizeof *features); + if (dpif->dpif_class->meter_get_features) { + dpif->dpif_class->meter_get_features(dpif, features); + } +} + +/* Adds or modifies meter identified by 'meter_id' in 'dpif'. If '*meter_id' + * is UINT32_MAX, adds a new meter, otherwise modifies an existing meter. + * + * If meter is successfully added, sets '*meter_id' to the new meter's + * meter number. */ +int +dpif_meter_set(struct dpif *dpif, ofproto_meter_id *meter_id, + struct ofputil_meter_config *config) +{ + int error; + + COVERAGE_INC(dpif_meter_set); + + error = dpif->dpif_class->meter_set(dpif, meter_id, config); + if (!error) { + VLOG_DBG_RL(&dpmsg_rl, "%s: DPIF meter %"PRIu32" set", + dpif_name(dpif), meter_id->uint32); + } else { + VLOG_WARN_RL(&error_rl, "%s: failed to set DPIF meter %"PRIu32": %s", + dpif_name(dpif), meter_id->uint32, ovs_strerror(error)); + meter_id->uint32 = UINT32_MAX; + } + return error; +} + +int +dpif_meter_get(const struct dpif *dpif, ofproto_meter_id meter_id, + struct ofputil_meter_stats *stats, uint16_t n_bands) +{ + int error; + + COVERAGE_INC(dpif_meter_get); + + error = dpif->dpif_class->meter_get(dpif, meter_id, stats, n_bands); + if (!error) { + VLOG_DBG_RL(&dpmsg_rl, "%s: DPIF meter %"PRIu32" get stats", + dpif_name(dpif), meter_id.uint32); + } else { + VLOG_WARN_RL(&error_rl, + "%s: failed to get DPIF meter %"PRIu32" stats: %s", + dpif_name(dpif), meter_id.uint32, ovs_strerror(error)); + stats->packet_in_count = ~0; + stats->byte_in_count = ~0; + stats->n_bands = 0; + } + return error; +} + +int +dpif_meter_del(struct dpif *dpif, ofproto_meter_id meter_id, + struct ofputil_meter_stats *stats, uint16_t n_bands) +{ + int error; + + COVERAGE_INC(dpif_meter_del); + + error = dpif->dpif_class->meter_del(dpif, meter_id, stats, n_bands); + if (!error) { + VLOG_DBG_RL(&dpmsg_rl, "%s: DPIF meter %"PRIu32" deleted", + dpif_name(dpif), meter_id.uint32); + } else { + VLOG_WARN_RL(&error_rl, + "%s: failed to delete DPIF meter %"PRIu32": %s", + dpif_name(dpif), meter_id.uint32, ovs_strerror(error)); + if (stats) { + stats->packet_in_count = ~0; + stats->byte_in_count = ~0; + stats->n_bands = 0; + } + } + return error; +} diff --git a/lib/dpif.h b/lib/dpif.h index 50174ee..55a2fc4 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -390,6 +390,7 @@ #include #include "netdev.h" #include "dp-packet.h" +#include "ofp-util.h" #include "openflow/openflow.h" #include "ovs-numa.h" #include "packets.h" @@ -847,6 +848,16 @@ void dpif_disable_upcall(struct dpif *); void dpif_print_packet(struct dpif *, struct dpif_upcall *); +/* Meters. */ +void dpif_meter_get_features(const struct dpif *, + struct ofputil_meter_features *); +int dpif_meter_set(struct dpif *, ofproto_meter_id *meter_id, + struct ofputil_meter_config *); +int dpif_meter_get(const struct dpif *, ofproto_meter_id meter_id, + struct ofputil_meter_stats *, uint16_t n_bands); +int dpif_meter_del(struct dpif *, ofproto_meter_id meter_id, + struct ofputil_meter_stats *, uint16_t n_bands); + /* Miscellaneous. */ void dpif_get_netflow_ids(const struct dpif *, diff --git a/lib/odp-execute.c b/lib/odp-execute.c index b5204b2..0d56354 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -493,6 +493,7 @@ requires_datapath_assistance(const struct nlattr *a) case OVS_ACTION_ATTR_USERSPACE: case OVS_ACTION_ATTR_RECIRC: case OVS_ACTION_ATTR_CT: + case OVS_ACTION_ATTR_METER: return true; case OVS_ACTION_ATTR_SET: @@ -623,6 +624,10 @@ odp_execute_actions(void *dp, struct dp_packet **packets, int cnt, bool steal, } break; + case OVS_ACTION_ATTR_METER: + /* Not implemented yet. */ + break; + case OVS_ACTION_ATTR_OUTPUT: case OVS_ACTION_ATTR_TUNNEL_PUSH: case OVS_ACTION_ATTR_TUNNEL_POP: diff --git a/lib/odp-util.c b/lib/odp-util.c index 9b9792d..aeb14db 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -108,6 +108,7 @@ odp_action_len(uint16_t type) case OVS_ACTION_ATTR_OUTPUT: return sizeof(uint32_t); case OVS_ACTION_ATTR_TUNNEL_PUSH: return ATTR_LEN_VARIABLE; case OVS_ACTION_ATTR_TUNNEL_POP: return sizeof(uint32_t); + case OVS_ACTION_ATTR_METER: return sizeof(uint32_t); case OVS_ACTION_ATTR_USERSPACE: return ATTR_LEN_VARIABLE; case OVS_ACTION_ATTR_PUSH_VLAN: return sizeof(struct ovs_action_push_vlan); case OVS_ACTION_ATTR_POP_VLAN: return 0; @@ -618,6 +619,9 @@ format_odp_action(struct ds *ds, const struct nlattr *a) } switch (type) { + case OVS_ACTION_ATTR_METER: + ds_put_format(ds, "meter(%"PRIu32")", nl_attr_get_u32(a)); + break; case OVS_ACTION_ATTR_OUTPUT: ds_put_format(ds, "%"PRIu32, nl_attr_get_u32(a)); break; @@ -1245,6 +1249,16 @@ parse_odp_action(const char *s, const struct simap *port_names, } { + unsigned long long int meter_id; + int n = -1; + + if (sscanf(s, "meter(%lli)%n", &meter_id, &n) > 0 && n > 0) { + nl_msg_put_u32(actions, OVS_ACTION_ATTR_METER, meter_id); + return n; + } + } + + { double percentage; int n = -1; diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c index f11699c..e3fbe57 100644 --- a/ofproto/ofproto-dpif-sflow.c +++ b/ofproto/ofproto-dpif-sflow.c @@ -1142,6 +1142,7 @@ dpif_sflow_read_actions(const struct flow *flow, case OVS_ACTION_ATTR_RECIRC: case OVS_ACTION_ATTR_HASH: case OVS_ACTION_ATTR_CT: + case OVS_ACTION_ATTR_METER: break; case OVS_ACTION_ATTR_SET_MASKED: diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 49001e8..e40bc3c 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5661,6 +5661,58 @@ ofproto_dpif_delete_internal_flow(struct ofproto_dpif *ofproto, return 0; } +static void +meter_get_features(const struct ofproto *ofproto_, + struct ofputil_meter_features *features) +{ + const struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + + dpif_meter_get_features(ofproto->backer->dpif, features); +} + +static enum ofperr +meter_set(struct ofproto *ofproto_, ofproto_meter_id *meter_id, + struct ofputil_meter_config *config) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + + switch (dpif_meter_set(ofproto->backer->dpif, meter_id, config)) { + case 0: + return 0; + case EFBIG: /* meter_id out of range */ + case ENOMEM: /* Cannot allocate meter */ + return OFPERR_OFPMMFC_OUT_OF_METERS; + case EBADF: /* Unsupported flags */ + return OFPERR_OFPMMFC_BAD_FLAGS; + case EINVAL: /* Too many bands */ + return OFPERR_OFPMMFC_OUT_OF_BANDS; + case ENODEV: /* Unsupported band type */ + return OFPERR_OFPMMFC_BAD_BAND; + default: + return OFPERR_OFPMMFC_UNKNOWN; + } +} + +static enum ofperr +meter_get(const struct ofproto *ofproto_, ofproto_meter_id meter_id, + struct ofputil_meter_stats *stats, uint16_t n_bands) +{ + const struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + + if (!dpif_meter_get(ofproto->backer->dpif, meter_id, stats, n_bands)) { + return 0; + } + return OFPERR_OFPMMFC_UNKNOWN_METER; +} + +static void +meter_del(struct ofproto *ofproto_, ofproto_meter_id meter_id) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + + dpif_meter_del(ofproto->backer->dpif, meter_id, NULL, 0); +} + const struct ofproto_class ofproto_dpif_class = { init, enumerate_types, @@ -5746,10 +5798,10 @@ const struct ofproto_class ofproto_dpif_class = { set_mcast_snooping, set_mcast_snooping_port, set_realdev, - NULL, /* meter_get_features */ - NULL, /* meter_set */ - NULL, /* meter_get */ - NULL, /* meter_del */ + meter_get_features, + meter_set, + meter_get, + meter_del, group_alloc, /* group_alloc */ group_construct, /* group_construct */ group_destruct, /* group_destruct */ diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 98d439e..dd45ee8 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -1713,16 +1713,17 @@ struct ofproto_class { * leaving '*id' unchanged. On failure, the existing meter configuration * is left intact. */ enum ofperr (*meter_set)(struct ofproto *ofproto, ofproto_meter_id *id, - const struct ofputil_meter_config *config); + struct ofputil_meter_config *config); /* Gets the meter and meter band packet and byte counts for maximum of - * 'stats->n_bands' bands for the meter with provider ID 'id' within - * 'ofproto'. The caller fills in the other stats values. The band stats - * are copied to memory at 'stats->bands' provided by the caller. The - * number of returned band stats is returned in 'stats->n_bands'. */ + * 'n_bands' bands for the meter with provider ID 'id' within 'ofproto'. + * The caller fills in the other stats values. The band stats are copied + * to memory at 'stats->bands' provided by the caller. The number of + * returned band stats is returned in 'stats->n_bands'. */ enum ofperr (*meter_get)(const struct ofproto *ofproto, ofproto_meter_id id, - struct ofputil_meter_stats *stats); + struct ofputil_meter_stats *stats, + uint16_t n_bands); /* Deletes a meter, making the 'ofproto_meter_id' invalid for any * further calls. */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 2cdc8d4..8e4495b 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -6000,7 +6000,7 @@ handle_meter_request(struct ofconn *ofconn, const struct ofp_header *request, if (!ofproto->ofproto_class->meter_get(ofproto, meter->provider_meter_id, - &stats)) { + &stats, meter->n_bands)) { ofputil_append_meter_stats(&replies, &stats); } } else { /* type == OFPTYPE_METER_CONFIG_REQUEST */