@@ -506,6 +506,7 @@ struct ofpact_metadata {
struct ofpact_meter {
struct ofpact ofpact;
uint32_t meter_id;
+ uint32_t provider_meter_id;
};
/* OFPACT_WRITE_ACTIONS.
@@ -79,6 +79,8 @@ DEFINE_STATIC_PER_THREAD_DATA(uint32_t, recirc_depth, 0)
/* Configuration parameters. */
enum { MAX_FLOWS = 65536 }; /* Maximum number of flows in flow table. */
+enum { MAX_METERS = 65536 }; /* Maximum number of meters. */
+enum { MAX_BANDS = 8 }; /* Maximum number of bands / meter. */
/* Protects against changes to 'dp_netdevs'. */
static struct ovs_mutex dp_netdev_mutex = OVS_MUTEX_INITIALIZER;
@@ -170,6 +172,15 @@ static void dpcls_remove(struct dpcls *, struct dpcls_rule *);
static bool dpcls_lookup(const struct dpcls *cls,
const struct netdev_flow_key keys[],
struct dpcls_rule **rules, size_t cnt);
+
+/* Set of supported meter flags */
+#define DP_SUPPORTED_METER_FLAGS_MASK \
+ (OFPMF13_STATS | OFPMF13_PKTPS | OFPMF13_KBPS | OFPMF13_BURST)
+
+/* Set of supported meter band types */
+#define DP_SUPPORTED_METER_BAND_TYPES \
+ ( 1 << OFPMBT13_DROP )
+
/* Datapath based on the network device interface from netdev.h.
*
@@ -2908,6 +2919,28 @@ 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 = MAX_METERS;
+ features->band_types = DP_SUPPORTED_METER_BAND_TYPES;
+ features->capabilities = DP_SUPPORTED_METER_FLAGS_MASK;
+ features->max_bands = MAX_BANDS;
+ features->max_color = 0;
+}
+
+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
@@ -4258,6 +4291,8 @@ 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_del,
NULL, /* ct_dump_start */
NULL, /* ct_dump_next */
NULL, /* ct_dump_done */
@@ -68,6 +68,19 @@ enum { MAX_PORTS = USHRT_MAX };
* missing if we have old headers. */
#define ETH_FLAG_LRO (1 << 15) /* LRO is enabled */
+/* Configuration parameters. */
+enum { MAX_FLOWS = 65536 }; /* Maximum number of flows in flow table. */
+enum { MAX_METERS = 65536 }; /* Maximum number of meters. */
+enum { MAX_BANDS = 8 }; /* Maximum number of bands / meter. */
+
+/* Set of supported meter flags */
+#define DP_SUPPORTED_METER_FLAGS_MASK \
+ (OFPMF13_STATS | OFPMF13_PKTPS | OFPMF13_KBPS | OFPMF13_BURST)
+
+/* Set of supported meter band types */
+#define DP_SUPPORTED_METER_BAND_TYPES \
+ ( 1 << OFPMBT13_DROP )
+
struct dpif_netlink_dp {
/* Generic Netlink header. */
uint8_t cmd;
@@ -2274,6 +2287,27 @@ 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 = MAX_METERS;
+ features->band_types = DP_SUPPORTED_METER_BAND_TYPES;
+ features->capabilities = DP_SUPPORTED_METER_FLAGS_MASK;
+ features->max_bands = MAX_BANDS;
+ features->max_color = 0;
+}
+
+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 */
+}
+
struct dpif_netlink_ct_dump_state {
struct ct_dpif_dump_state up;
struct nl_ct_dump_state *nl_ct_dump;
@@ -2375,6 +2409,8 @@ 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_del,
dpif_netlink_ct_dump_start,
dpif_netlink_ct_dump_next,
dpif_netlink_ct_dump_done,
@@ -25,6 +25,7 @@
#include "openflow/openflow.h"
#include "dpif.h"
#include "util.h"
+#include "openvswitch/ofp-util.h"
#ifdef __cplusplus
extern "C" {
@@ -393,6 +394,21 @@ struct dpif_class {
* 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 *);
+
+ /* 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);
+
/* Conntrack entry dumping interface.
*
* These functions are used by ct-dpif.c to provide a datapath-agnostic
@@ -63,6 +63,7 @@ COVERAGE_DEFINE(dpif_flow_del);
COVERAGE_DEFINE(dpif_execute);
COVERAGE_DEFINE(dpif_purge);
COVERAGE_DEFINE(dpif_execute_with_help);
+COVERAGE_DEFINE(dpif_meter_del);
static const struct dpif_class *base_dpif_classes[] = {
#if defined(__linux__) || defined(_WIN32)
@@ -1743,3 +1744,40 @@ 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);
+ }
+}
+
+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;
+}
+
@@ -394,6 +394,7 @@
#include "ovs-numa.h"
#include "packets.h"
#include "util.h"
+#include "openvswitch/ofp-util.h"
#ifdef __cplusplus
extern "C" {
@@ -847,6 +848,13 @@ void dpif_enable_upcall(struct dpif *);
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_del(struct dpif *, ofproto_meter_id meter_id,
+ struct ofputil_meter_stats *, uint16_t n_bands);
+
/* Miscellaneous. */
@@ -48,7 +48,9 @@ ofproto_libofproto_la_SOURCES = \
ofproto/tunnel.c \
ofproto/tunnel.h \
ofproto/bundles.c \
- ofproto/bundles.h
+ ofproto/bundles.h \
+ ofproto/meter_tc.c \
+ ofproto/meter_tc.h
ofproto_libofproto_la_CPPFLAGS = $(AM_CPPFLAGS)
ofproto_libofproto_la_CFLAGS = $(AM_CFLAGS)
new file mode 100644
@@ -0,0 +1,74 @@
+#include <config.h>
+#include "meter_tc.h"
+
+VLOG_DEFINE_THIS_MODULE(meter_tc);
+
+enum ofperr flow_mod_to_tc(struct ofproto *ofproto,
+ struct ofputil_flow_mod ofm) {
+ FILE *fp;
+ ovs_be32 nw_src,nw_dst;
+ struct ofpact *a;
+ struct ofpact_meter *m_act;
+ struct ofport *ofport;
+ struct meter *meter;
+ uint32_t id,rate,rate_in_bytesps,burst_size,default_id;
+ char buffer[1024];
+ ofp_port_t port=0;
+ default_id=65535;
+ id=0;
+ struct ds nw_src_string = DS_EMPTY_INITIALIZER;
+ struct ds nw_dst_string = DS_EMPTY_INITIALIZER;
+ nw_src = ofm.match.flow.nw_src;
+ nw_dst = ofm.match.flow.nw_dst;
+ ds_put_format(&nw_src_string, IP_FMT, IP_ARGS(nw_src));
+ ds_put_format(&nw_dst_string, IP_FMT, IP_ARGS(nw_dst));
+ VLOG_INFO("Source IP : %s , Destination IP : %s",nw_src_string.string,
+ nw_dst_string.string);
+ OFPACT_FOR_EACH_FLATTENED (a, ofm.ofpacts, ofm.ofpacts_len) {
+ if (a->type == OFPACT_METER) {
+ m_act=ofpact_get_METER(a);
+ id=m_act->meter_id;
+ }
+ if(a->type == OFPACT_OUTPUT) {
+ port=ofpact_get_OUTPUT(a)->port;
+ }
+ }
+ VLOG_INFO("Output Port Number : %d",port);
+ ofport=ofproto_get_port(ofproto,port);
+ if(ofport==NULL) {
+ VLOG_INFO("The port numbers defined in the flow donot correspond to "
+ "any datapath port. try using ovs-ofctl show <br-name> to "
+ "get the list of ports. Add ports to the bridge first");
+ return OFPERR_OFPBRC_BAD_PORT;
+ }
+ VLOG_INFO("Output Port Name : %s",ofport->pp.name);
+ VLOG_INFO("Meter id : %d",id);
+ meter = ofproto->meters[id];
+ rate=meter->bands->rate;
+ rate_in_bytesps=(uint32_t)((float)(meter->bands->rate/8)*1000);
+ burst_size=meter->bands->burst_size;
+ VLOG_INFO("Rate in kbitsps : %d, burst size in kbits %d",rate,
+ burst_size);
+ snprintf(buffer,sizeof(buffer),"tc qdisc add dev %s root "
+ "handle 1: htb default %x",ofport->pp.name,default_id);
+ fp=popen(buffer,"r");
+ snprintf(buffer,sizeof(buffer),"tc class add dev %s parent 1:0 "
+ "classid 1:%x htb rate 20kbps ceil 100kbps prio 2",
+ ofport->pp.name,default_id);
+ fp = popen(buffer,"r");
+ pclose(fp);
+ snprintf(buffer,sizeof(buffer),"tc class add dev %s parent 1:0 classid "
+ "1:%x htb rate %dkbit ceil %dkbit prio 1 mtu %d000 ",
+ ofport->pp.name,id,rate,rate,burst_size);
+ fp = popen(buffer,"r");
+ pclose(fp);
+ snprintf(buffer,sizeof(buffer),"tc filter add dev %s protocol ip parent "
+ "1: prio 1 u32 match ip src %s match ip dst %s flowid 1:%x "
+ "police rate %dbps burst %d000 mpu 0 conform-exceed drop/ok",
+ ofport->pp.name,nw_src_string.string,nw_dst_string.string,
+ id,rate_in_bytesps,burst_size);
+ fp = popen(buffer,"r");
+ VLOG_INFO("Meter attached successfully to the flow");
+ pclose(fp);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,38 @@
+#ifndef METER_TC_H
+#define METER_TC_H
+#include<stdlib.h>
+#include<stdio.h>
+#include<string.h>
+#include "openvswitch/ofp-util.h"
+#include "include/openflow/openflow-1.3.h"
+#include "include/openvswitch/vlog.h"
+#include <config.h>
+#include "include/openvswitch/dynamic-string.h"
+#include "linux/pkt_sched.h"
+#include "openvswitch/packets.h"
+#include "openvswitch/match.h"
+#include "openvswitch/ofp-actions.h"
+#include "ofproto/ofproto-provider.h"
+#include "include/openvswitch/types.h"
+
+/* Meters implementation.
+ *
+ * Meter table entry, indexed by the OpenFlow meter_id.
+ * 'created' is used to compute the duration for meter stats.
+ * 'list rules' is needed so that we can delete the dependent rules when the
+ * meter table entry is deleted.
+ * 'provider_meter_id' is for the provider's private use.
+ */
+struct meter {
+ long long int created; /* Time created. */
+ struct ovs_list rules; /* List of "struct rule_dpif"s. */
+ ofproto_meter_id provider_meter_id;
+ uint16_t flags; /* Meter flags. */
+ uint16_t n_bands; /* Number of meter bands. */
+ struct ofputil_meter_band *bands;
+};
+
+/* Translates the add-flow command containing meter to the respective
+ * traffic control command. */
+enum ofperr flow_mod_to_tc(struct ofproto *, struct ofputil_flow_mod);
+#endif
@@ -5575,6 +5575,23 @@ 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 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 uuid *
ofproto_dpif_get_uuid(const struct ofproto_dpif *ofproto)
{
@@ -5667,10 +5684,10 @@ const struct ofproto_class ofproto_dpif_class = {
set_mac_table_config,
set_mcast_snooping,
set_mcast_snooping_port,
- NULL, /* meter_get_features */
+ meter_get_features, /* meter_get_features */
NULL, /* meter_set */
NULL, /* meter_get */
- NULL, /* meter_del */
+ meter_del, /* meter_del */
group_alloc, /* group_alloc */
group_construct, /* group_construct */
group_destruct, /* group_destruct */
@@ -62,6 +62,7 @@
#include "tun-metadata.h"
#include "unaligned.h"
#include "unixctl.h"
+#include "ofproto/meter_tc.h"
VLOG_DEFINE_THIS_MODULE(ofproto);
@@ -2957,8 +2958,8 @@ ofproto_group_unref(struct ofgroup *group)
}
}
-static uint32_t get_provider_meter_id(const struct ofproto *,
- uint32_t of_meter_id);
+static bool ofproto_fix_meter_action(const struct ofproto *,
+ struct ofpact_meter *);
/* Creates and returns a new 'struct rule_actions', whose actions are a copy
* of from the 'ofpacts_len' bytes of 'ofpacts'. */
@@ -3401,14 +3402,13 @@ ofproto_check_ofpacts(struct ofproto *ofproto,
const struct ofpact ofpacts[], size_t ofpacts_len)
{
const struct ofpact *a;
- uint32_t mid;
-
- mid = ofpacts_get_meter(ofpacts, ofpacts_len);
- if (mid && get_provider_meter_id(ofproto, mid) == UINT32_MAX) {
- return OFPERR_OFPMMFC_INVALID_METER;
- }
OFPACT_FOR_EACH_FLATTENED (a, ofpacts, ofpacts_len) {
+ if (a->type == OFPACT_METER &&
+ !ofproto_fix_meter_action(ofproto, ofpact_get_METER(a))) {
+ return OFPERR_OFPMMFC_INVALID_METER;
+ }
+
if (a->type == OFPACT_GROUP
&& !ofproto_group_exists(ofproto, ofpact_get_GROUP(a)->group_id)) {
return OFPERR_OFPBAC_BAD_OUT_GROUP;
@@ -4673,6 +4673,32 @@ add_flow_start(struct ofproto *ofproto, struct ofproto_flow_mod *ofm)
struct cls_conjunction *conjs;
size_t n_conjs;
enum ofperr error;
+ uint8_t size_=0;
+
+ /*
+ * If the actions in add-flow contain meter then flow_mod_to_tc is called.
+ * OFPACT_METER is the enum for meter as action in add-flow command.
+ */
+ if(ofm->fm.ofpacts->type == OFPACT_METER) {
+ error = flow_mod_to_tc(ofproto,ofm->fm);
+ if(error) {
+ return error;
+ }
+ /*
+ * ofpacts_len is the total length of all actions in the flow.
+ * ofpacts->len contain the length of particular action. The meters
+ * are not set in datapath, so when flow tries to fetch the meter id
+ * from the datapath, it gives error at runtime. To skip
+ * meter, and move the pointer to the next action in ofpacts the
+ * following code is written. Skipped meter action here
+ * because this work is done by flow_mod_to_tc().
+ */
+ ofm->fm.ofpacts_len = ofm->fm.ofpacts_len - ofm->fm.ofpacts->len;
+ ofm->fm.ofpacts[0].type = 0;
+ ofm->fm.ofpacts[0].raw = 0;
+ size_ = ofm->fm.ofpacts[0].len / sizeof(ofm->fm.ofpacts[0]);
+ ofm->fm.ofpacts = &ofm->fm.ofpacts[size_];
+ }
if (!check_table_id(ofproto, fm->table_id)) {
error = OFPERR_OFPBRC_BAD_TABLE_ID;
@@ -5821,38 +5847,28 @@ handle_flow_monitor_cancel(struct ofconn *ofconn, const struct ofp_header *oh)
return error;
}
-/* Meters implementation.
- *
- * Meter table entry, indexed by the OpenFlow meter_id.
- * 'created' is used to compute the duration for meter stats.
- * 'list rules' is needed so that we can delete the dependent rules when the
- * meter table entry is deleted.
- * 'provider_meter_id' is for the provider's private use.
- */
-struct meter {
- long long int created; /* Time created. */
- struct ovs_list rules; /* List of "struct rule_dpif"s. */
- ofproto_meter_id provider_meter_id;
- uint16_t flags; /* Meter flags. */
- uint16_t n_bands; /* Number of meter bands. */
- struct ofputil_meter_band *bands;
-};
-
/*
- * This is used in instruction validation at flow set-up time,
- * as flows may not use non-existing meters.
- * Return value of UINT32_MAX signifies an invalid meter.
+ * This is used in instruction validation at flow set-up time, to map
+ * the OpenFlow meter ID to the corresponding datapath provider meter
+ * ID. If either does not exist, returns false. Otherwise updates
+ * the meter action and returns true.
*/
-static uint32_t
-get_provider_meter_id(const struct ofproto *ofproto, uint32_t of_meter_id)
+static bool
+ofproto_fix_meter_action(const struct ofproto *ofproto,
+ struct ofpact_meter *ma)
{
- if (of_meter_id && of_meter_id <= ofproto->meter_features.max_meters) {
- const struct meter *meter = ofproto->meters[of_meter_id];
- if (meter) {
- return meter->provider_meter_id.uint32;
- }
+ if (ma->meter_id && ma->meter_id <= ofproto->meter_features.max_meters) {
+ const struct meter *meter = ofproto->meters[ma->meter_id];
+
+ if (meter && meter->provider_meter_id.uint32 != UINT32_MAX) {
+ /* Update the action with the provider's meter ID, so that we
+ * do not need any synchronization between ofproto_dpif_xlate
+ * and ofproto for meter table access. */
+ ma->provider_meter_id = meter->provider_meter_id.uint32;
+ return true;
+ }
}
- return UINT32_MAX;
+ return false;
}
/* Finds the meter invoked by 'rule''s actions and adds 'rule' to the meter's
@@ -5914,16 +5930,21 @@ meter_delete(struct ofproto *ofproto, uint32_t first, uint32_t last)
static enum ofperr
handle_add_meter(struct ofproto *ofproto, struct ofputil_meter_mod *mm)
{
- ofproto_meter_id provider_meter_id = { UINT32_MAX };
+ ofproto_meter_id provider_meter_id = {mm->meter.meter_id};
struct meter **meterp = &ofproto->meters[mm->meter.meter_id];
enum ofperr error;
if (*meterp) {
return OFPERR_OFPMMFC_METER_EXISTS;
}
-
- error = ofproto->ofproto_class->meter_set(ofproto, &provider_meter_id,
- &mm->meter);
+ error=0;
+ /*
+ * This line is deleted because meter_set() is declared in
+ * ofproto/ofproto-provider.h but it doesnot have implementaion
+ * in ofproto/ofproto-dpif.c in ofproto_dpif_class. This function
+ * will basically set meter in the datapath. To bypass this have
+ * deleted the line.
+ */
if (!error) {
ovs_assert(provider_meter_id.uint32 != UINT32_MAX);
*meterp = meter_create(&mm->meter, provider_meter_id);