From patchwork Wed May 17 16:41:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SatyaValli X-Patchwork-Id: 763697 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wSg8F2YGSz9s7F for ; Thu, 18 May 2017 02:42:05 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="LgeKtLlX"; dkim-atps=neutral Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 56F4CB8F; Wed, 17 May 2017 16:42:02 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id B5F6EB6D for ; Wed, 17 May 2017 16:42:01 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f195.google.com (mail-pf0-f195.google.com [209.85.192.195]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 85DC520B for ; Wed, 17 May 2017 16:42:00 +0000 (UTC) Received: by mail-pf0-f195.google.com with SMTP id w69so2393448pfk.1 for ; Wed, 17 May 2017 09:42:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=hZzEIzYuXcWuTu/CXL9g67Gfgir+4u+sk4j6oeR5qxk=; b=LgeKtLlXwcRn7BKz+ZIdAShzffyRVTUAnXSU3ewc6vekcqeKdWsj3HyZVjKo8/Yqc9 Ym6NBie+hGw1UFQwzu2ZxlAr247m6Hc/QKHGbBVcrohWnaJgpcw+uV49eQigfOMjTxOh l8c3PABw/Efxsi+yS6MuW3p01J14AAynj6zo03Xi/8ysT/aMNqBuMB/9rz1Jf6xj5eKS PUBJZr6s4egtYcZmykyvd/3ki0P43XejkYsSiu1IyzQ4l64CbBMx+/DK31kpxXrDVs6/ P9PBn5J7NNfoKbZWvCsBfxIlnIRH+C3gYnGNo29f/ShvW6LcfEAbyFum42tDoO0TxEvd wd/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=hZzEIzYuXcWuTu/CXL9g67Gfgir+4u+sk4j6oeR5qxk=; b=l0TTmDqZ2rAzF2o5u7cXwp1XhnqOMvwfkjKd/zUTC4maPUZfYoZtoVoY4BWrgzR0xi C3thzxY6YATCqCwJl3rEpjSNLjkIbSe3ll/5EZ7fuDldD56Iw7vkpxkq8ttw/EKZEPOI hPR1RupEzb5FhZkdkelnaHxfoVUtf8jTW8BBT/GiWRFxvp7awNN76/AOhg8pwhMx9kLb As75MN1eS6ZO9vXrIACR6uwSo2UndjHti6dEI7R0AVBu6gEeFr+80ZPSPulnPyiirxyJ 9LUReaPdmyP72G/G3xDNYtg9SXC1/Fv3ZNbKhT4ovEp+kf4/b+22oG/w2Uf3jtNLeu7t OA+w== X-Gm-Message-State: AODbwcB1w4mUgXDFNkH+N6WpE/Frd0wwslMuT9NAoNT73u1/qE1lIRxQ jkWmy9CCYIG82g== X-Received: by 10.84.176.131 with SMTP id v3mr5318732plb.138.1495039319839; Wed, 17 May 2017 09:41:59 -0700 (PDT) Received: from localhost.localdomain ([14.96.47.117]) by smtp.gmail.com with ESMTPSA id i68sm6044837pfi.72.2017.05.17.09.41.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 17 May 2017 09:41:59 -0700 (PDT) From: satyavalli.rama@gmail.com X-Google-Original-From: satyavalli.rama@tcs.com To: dev@openvswitch.org, harivelam.lavanya@tcs.com Date: Wed, 17 May 2017 22:11:30 +0530 Message-Id: <1495039290-24399-1-git-send-email-satyavalli.rama@tcs.com> X-Mailer: git-send-email 1.9.1 X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: SatyaValli Subject: [ovs-dev] [PATCH 1/6] OF1.5/EXT-334 OXS/Individal Flow Statistics -1 X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org From: SatyaValli OpenFlow 1.5 introduces the Extensible Statistics (OXS) by redefining the existing flow entry statistics with OXS Fields. This Patch provides implementation for OXS fields encoding in TLV format. To support this implementation below two messages are newly added OFPST_OXS_FLOW_STATS_REQUEST OFPST_OXS_FLOW_STATS_REPLY OFPST_OXS_AGGREGATE_STATS_REQUEST OFPST_OXS_AGGREGATE_STATS_REPLY OFPST_FLOW_REMOVED As per the openflow specification-1.5, this enhancement should take place on the existing flow entry statistics with the OXS fields on all the messages that carries flow entry statistics. The current commit adds support for the new feature in flow statistics multipart messages, aggregate multipart messages and OXS flow statistics support for flow removal message. Some more fields are added to ovs-ofctl dump-flows command to support OpenFlow15 OXS stats. Below are Commands to display OXS stats field wise Flow Statistics Multipart ovs-ofctl dump-flows -O OpenFlow15 oxs-duration ovs-ofctl dump-flows -O OpenFlow15 oxs-idle_time ovs-ofctl dump-flows -O OpenFlow15 oxs-packet_count ovs-ofctl dump-flows -O OpenFlow15 oxs-byte_count Aggregate Flow Statistics Multipart ovs-ofctl dump-aggregate -O OpenFlow15 oxs-packet_count ovs-ofctl dump-aggregate -O OpenFlow15 oxs-byte_count ovs-ofctl dump-aggregate -O OpenFlow15 oxs-flow_count For feature vise verification please apply Patch 1 and 2 for OXS support for Flow multiplart stats support Patch 3 and 4 for OXS support for Aggregate multipart stats support Patch 5 and 6 for OXS support for Flow Removal Signed-off-by: Satya Valli Co-authored-by: Lavanya Harivelam --- include/openflow/openflow-1.5.h | 50 +++++++++ include/openvswitch/ofp-msgs.h | 6 + lib/automake.mk | 2 + lib/ofp-parse.c | 45 +++++++- lib/ofp-print.c | 10 ++ lib/ox-stat.c | 238 ++++++++++++++++++++++++++++++++++++++++ lib/ox-stat.h | 32 ++++++ lib/rconn.c | 2 + ofproto/ofproto.c | 4 + 9 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 lib/ox-stat.c create mode 100644 lib/ox-stat.h diff --git a/include/openflow/openflow-1.5.h b/include/openflow/openflow-1.5.h index 3649e6c..3b66f7f 100644 --- a/include/openflow/openflow-1.5.h +++ b/include/openflow/openflow-1.5.h @@ -150,4 +150,54 @@ struct ofp15_group_desc_stats { }; OFP_ASSERT(sizeof(struct ofp15_group_desc_stats) == 16); +struct ofp_oxs_stat { + ovs_be16 reserved; /* One of OFPST_* */ + ovs_be16 length; /* Stats Length */ +}; + +OFP_ASSERT(sizeof(struct ofp_oxs_stat) == 4); + +/* Body for ofp_multipart_request of type +* OFPMP_FLOW_DESC & OFPMP_FLOW_STATS. */ +struct ofp15_oxs_flow_stats_request { + uint8_t table_id; /* ID of table to read (from ofp_table_desc), + * OFPTT_ALL for all tables. */ + uint8_t pad[3]; /* Align to 32 bits. */ + ovs_be32 out_port; /* Require matching entries to include this as + * an output port. A value of OFP_ANY + * indicates no restriction. */ + ovs_be32 out_group; /* Require matching entries to include this as + * an output group. A value of OFPG_ANY + * indicates no restriction. */ + uint8_t pad2[4]; /* Align to 64 bits. */ + ovs_be64 cookie; /* Require matching entries to contain this + * cookie value */ + ovs_be64 cookie_mask; /* Mask used to restrict the cookie bits that + * must match. A value of 0 indicates no + * restriction. */ +}; + +OFP_ASSERT(sizeof(struct ofp15_oxs_flow_stats_request) == 32); + +/* Body of reply to OFPMP_FLOW_STATS request +* and body for OFPIT_STAT_TRIGGER generated status. */ +struct ofp15_oxs_flow_stats_reply { + ovs_be16 length; /* Length of this entry. */ + uint8_t pad2[2]; /* Align to 64-bits. */ + uint8_t table_id; /* ID of table flow came from. */ + uint8_t reason; /* One of OFPFSR_*. */ + ovs_be16 priority; /* Priority of the entry. */ +}; + +OFP_ASSERT(sizeof(struct ofp15_oxs_flow_stats_reply) == 8); + +/* OXS flow stat field types for OpenFlow basic class. */ +enum oxs_ofb_stat_fields { + OFPXST_OFB_DURATION = 0, /* Time flow entry has been alive. */ + OFPXST_OFB_IDLE_TIME = 1, /* Time flow entry has been idle. */ + OFPXST_OFB_FLOW_COUNT = 2, /* Number of aggregated flow entries. */ + OFPXST_OFB_PACKET_COUNT = 3, /* Number of packets in flow entry. */ + OFPXST_OFB_BYTE_COUNT = 4, /* Number of bytes in flow entry. */ +}; + #endif /* openflow/openflow-1.5.h */ diff --git a/include/openvswitch/ofp-msgs.h b/include/openvswitch/ofp-msgs.h index 34708f3..089db47 100644 --- a/include/openvswitch/ofp-msgs.h +++ b/include/openvswitch/ofp-msgs.h @@ -287,6 +287,8 @@ enum ofpraw { OFPRAW_OFPST10_FLOW_REQUEST, /* OFPST 1.1+ (1): struct ofp11_flow_stats_request, uint8_t[8][]. */ OFPRAW_OFPST11_FLOW_REQUEST, + /* OFPST 1.5+ (17): struct ofp15_oxs_flow_stats_request, uint8_t[8][]. */ + OFPRAW_OFPST15_OXS_FLOW_REQUEST, /* NXST 1.0 (0): struct nx_flow_stats_request, uint8_t[8][]. */ OFPRAW_NXST_FLOW_REQUEST, @@ -296,6 +298,8 @@ enum ofpraw { OFPRAW_OFPST11_FLOW_REPLY, /* OFPST 1.3+ (1): uint8_t[]. */ OFPRAW_OFPST13_FLOW_REPLY, + /* OFPST 1.5+ (17): uint8_t[]. */ + OFPRAW_OFPST15_OXS_FLOW_REPLY, /* NXST 1.0 (0): uint8_t[]. */ OFPRAW_NXST_FLOW_REPLY, @@ -628,6 +632,7 @@ enum ofptype { OFPTYPE_FLOW_STATS_REQUEST, /* OFPRAW_OFPST10_FLOW_REQUEST. * OFPRAW_OFPST11_FLOW_REQUEST. * OFPRAW_NXST_FLOW_REQUEST. */ + OFPTYPE_OXS_FLOW_STATS_REQUEST, /* OFPRAW_OFPST15_OXS_FLOW_REQUEST. */ OFPTYPE_FLOW_STATS_REPLY, /* OFPRAW_OFPST10_FLOW_REPLY. * OFPRAW_OFPST11_FLOW_REPLY. * OFPRAW_OFPST13_FLOW_REPLY. @@ -635,6 +640,7 @@ enum ofptype { OFPTYPE_AGGREGATE_STATS_REQUEST, /* OFPRAW_OFPST10_AGGREGATE_REQUEST. * OFPRAW_OFPST11_AGGREGATE_REQUEST. * OFPRAW_NXST_AGGREGATE_REQUEST. */ + OFPTYPE_OXS_FLOW_STATS_REPLY, /* OFPRAW_OFPST15_OXS_FLOW_REPLY. */ OFPTYPE_AGGREGATE_STATS_REPLY, /* OFPRAW_OFPST_AGGREGATE_REPLY. * OFPRAW_NXST_AGGREGATE_REPLY. */ OFPTYPE_TABLE_STATS_REQUEST, /* OFPRAW_OFPST_TABLE_REQUEST. */ diff --git a/lib/automake.mk b/lib/automake.mk index faace79..a9c402e 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -197,6 +197,8 @@ lib_libopenvswitch_la_SOURCES = \ lib/ovsdb-parser.h \ lib/ovsdb-types.c \ lib/ovsdb-types.h \ + lib/ox-stat.c \ + lib/ox-stat.h \ lib/packets.c \ lib/packets.h \ lib/pcap-file.c \ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index c8cac5b..78384c7 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -41,6 +41,8 @@ #include "socket-util.h" #include "util.h" +extern uint8_t oxs_field_set; + /* Parses 'str' as an 8-bit unsigned integer into '*valuep'. * * 'name' describes the value parsed in an error message, if any. @@ -188,6 +190,34 @@ str_to_connhelper(const char *str, uint16_t *alg) return xasprintf("invalid conntrack helper \"%s\"", str); } +struct ox_fields { + const char *name; + uint16_t fl_type; +}; + +static bool +parse_oxs_field(const char *name, const struct ox_fields **f_out) +{ + static const struct ox_fields fields[] = { + {"oxs-duration", OFPXST_OFB_DURATION}, + {"oxs-idle_time", OFPXST_OFB_IDLE_TIME}, + {"oxs-flow_count", OFPXST_OFB_FLOW_COUNT}, + {"oxs-packet_count", OFPXST_OFB_PACKET_COUNT}, + {"oxs-byte_count", OFPXST_OFB_BYTE_COUNT}, + }; + + const struct ox_fields *f; + + for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) { + if (!strcmp(f->name, name)) { + *f_out = f; + return true; + } + } + *f_out = NULL; + return false; +} + struct protocol { const char *name; uint16_t dl_type; @@ -406,10 +436,23 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string, while (ofputil_parse_key_value(&string, &name, &value)) { const struct protocol *p; + const struct ox_fields *f; const struct mf_field *mf; char *error = NULL; - if (parse_protocol(name, &p)) { + if (parse_oxs_field(name, &f)) { + if (f->fl_type == OFPXST_OFB_DURATION) { + oxs_field_set |= (1 << f->fl_type); + } else if (f->fl_type == OFPXST_OFB_IDLE_TIME) { + oxs_field_set |= (1 << f->fl_type); + } else if (f->fl_type == OFPXST_OFB_FLOW_COUNT) { + oxs_field_set |= (1 << f->fl_type); + } else if (f->fl_type == OFPXST_OFB_PACKET_COUNT) { + oxs_field_set |= (1 << f->fl_type); + } else if (f->fl_type == OFPXST_OFB_BYTE_COUNT) { + oxs_field_set |= (1 << f->fl_type); + } + } else if (parse_protocol(name, &p)) { match_set_dl_type(&fm->match, htons(p->dl_type)); if (p->nw_proto) { match_set_nw_proto(&fm->match, p->nw_proto); diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 7ca9531..0f855fa 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -3563,6 +3563,11 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, ofp_print_flow_stats_request(string, oh); break; + case OFPTYPE_OXS_FLOW_STATS_REQUEST: + ofp_print_stats(string, oh); + ofp_print_flow_stats_request(string, oh); + break; + case OFPTYPE_TABLE_STATS_REQUEST: ofp_print_stats(string, oh); break; @@ -3587,6 +3592,11 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, ofp_print_flow_stats_reply(string, oh); break; + case OFPTYPE_OXS_FLOW_STATS_REPLY: + ofp_print_stats(string, oh); + ofp_print_flow_stats_reply(string, oh); + break; + case OFPTYPE_QUEUE_STATS_REPLY: ofp_print_stats(string, oh); ofp_print_ofpst_queue_reply(string, oh, verbosity); diff --git a/lib/ox-stat.c b/lib/ox-stat.c new file mode 100644 index 0000000..96f019c --- /dev/null +++ b/lib/ox-stat.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "nx-match.h" +#include "ox-stat.h" +#include +#include "classifier.h" +#include "colors.h" +#include "openvswitch/hmap.h" +#include "openflow/nicira-ext.h" +#include "openvswitch/dynamic-string.h" +#include "openvswitch/meta-flow.h" +#include "openvswitch/ofp-actions.h" +#include "openvswitch/ofp-errors.h" +#include "openvswitch/ofp-util.h" +#include "openvswitch/ofpbuf.h" +#include "openvswitch/vlog.h" +#include "packets.h" +#include "openvswitch/shash.h" +#include "tun-metadata.h" +#include "unaligned.h" +#include "util.h" + +VLOG_DEFINE_THIS_MODULE(ox_stat); + +/* ## -------------------------- ## */ +/* ## OpenFlow Extensible Stats. ## */ +/* ## -------------------------- ## */ + +/* Components of a OXS TLV header. */ + +static struct ovs_list oxs_ox_map[OFPXST_OFB_BYTE_COUNT + 1]; +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + +static uint32_t +oxs_header_no_len(uint32_t header) +{ + return header & 0xffffff80; +} + +#define OXS_CLASS(HEADER) ((HEADER) >> 16) +#define OXS_FIELD(HEADER) (((HEADER) >> 9) & 0x7f) +#define OXS_TYPE(HEADER) (((HEADER) >> 9) & 0x7fffff) +#define OXS_RESERVED(HEADER) (((HEADER) >> 8) & 1) +#define OXS_LENGTH(HEADER) ((HEADER) & 0xff) + +/* Components of a OXS TLV header. */ +#define OXS_HEADER__(CLASS, FIELD, RESERVED, LENGTH) \ +(((CLASS) << 16) | ((FIELD) << 9) | ((RESERVED) << 8) | (LENGTH)) + +#define OXS_HEADER(CLASS, FIELD, LENGTH) \ + OXS_HEADER__(CLASS, FIELD, 0, LENGTH) + +/* OXS Class IDs. + * The high order bit differentiate reserved classes from member classes. + * Classes 0x0000 to 0x7FFF are member classes, allocated by ONF. + * Classes 0x8000 to 0xFFFE are reserved classes, reserved for + * standardisation. + */ + +enum ofp_oxs_class { + OFPXSC_OPENFLOW_BASIC = 0x8002, /* Basic stats class for OpenFlow */ + OFPXSC_EXPERIMENTER = 0xFFFF, /* Experimenter class */ +}; + +#define OFPXST_OFB_ALL ((UINT64_C(1) << 6) - 1) +#define OXS_OX_COOKIE OXS_HEADER (0x8002, 5 , 8) + +struct oxs_field { + uint32_t header; + enum ofp_version version; + const char *name; + enum oxs_ofb_stat_fields id; +}; + +struct oxs_field_index { + struct hmap_node header_node; + struct hmap_node name_node; + struct ovs_list ox_node; + const struct oxs_field fs; +}; + +#define OXS_STATS_DURATION_LEN 8 +#define OXS_STATS_IDLE_TIME_LEN 8 +#define OXS_STATS_FLOW_COUNT_LEN 4 +#define OXS_STATS_PACKET_COUNT_LEN 8 +#define OXS_STATS_BYTE_COUNT_LEN 8 + +#define OXS_OF_DURATION OXS_HEADER (0x8002, OFPXST_OFB_DURATION, \ + OXS_STATS_DURATION_LEN) +#define OXS_OF_IDLE_TIME OXS_HEADER (0x8002, OFPXST_OFB_IDLE_TIME, \ + OXS_STATS_IDLE_TIME_LEN) +#define OXS_OF_FLOW_COUNT OXS_HEADER (0x8002, OFPXST_OFB_FLOW_COUNT, \ + OXS_STATS_FLOW_COUNT_LEN) +#define OXS_OF_PACKET_COUNT OXS_HEADER (0x8002, OFPXST_OFB_PACKET_COUNT, \ + OXS_STATS_PACKET_COUNT_LEN) +#define OXS_OF_BYTE_COUNT OXS_HEADER (0x8002, OFPXST_OFB_BYTE_COUNT, \ + OXS_STATS_BYTE_COUNT_LEN) + +static struct oxs_field_index all_oxs_fields[] = { + {.fs = {OXS_OF_DURATION, OFP15_VERSION, "OFPXST_OFB_DURATION", + OFPXST_OFB_DURATION}}, + {.fs = {OXS_OF_IDLE_TIME, OFP15_VERSION, "OFPXST_OFB_IDLE_TIME", + OFPXST_OFB_IDLE_TIME}}, + {.fs = {OXS_OF_FLOW_COUNT, OFP15_VERSION, "OFPXST_OFB_FLOW_COUNT", + OFPXST_OFB_FLOW_COUNT}}, + {.fs = {OXS_OF_PACKET_COUNT, OFP15_VERSION, "OFPXST_OFB_PACKET_COUNT", + OFPXST_OFB_PACKET_COUNT}}, + {.fs = {OXS_OF_BYTE_COUNT, OFP15_VERSION, "OFPXST_OFB_BYTE_COUNT", + OFPXST_OFB_BYTE_COUNT}}, +}; + +uint8_t oxs_field_set; + +static const struct oxs_field *oxs_field_by_header(uint32_t header); +static const struct oxs_field *oxs_field_by_id(enum oxs_ofb_stat_fields, + enum ofp_version); +static bool is_experimenter_oxs(uint64_t header); +static int oxs_experimenter_len(uint64_t header); +static int oxs_payload_len (uint64_t header); +static int oxs_header_len (uint64_t header); +static uint64_t oxs_header_get(enum oxs_ofb_stat_fields id, + enum ofp_version version); +static int oxs_pull_header__(struct ofpbuf *b, uint64_t * header, + const struct oxs_field **field); +static void oxs_init(void); + +static bool +is_experimenter_oxs(uint64_t header) +{ + return OXS_CLASS(header) == OFPXSC_EXPERIMENTER; +} + +static int +oxs_experimenter_len(uint64_t header) +{ + return is_experimenter_oxs(header) ? 4 : 0; +} + +static int +oxs_payload_len(uint64_t header) +{ + return OXS_LENGTH(header) - oxs_experimenter_len(header); +} + +static int +oxs_header_len(uint64_t header) +{ + return 4 + oxs_experimenter_len(header); +} + +static uint64_t +oxs_header_get(enum oxs_ofb_stat_fields id, enum ofp_version version) +{ + const struct oxs_field *f = oxs_field_by_id(id, version); + + return f ? f->header : 0; +} + +static int +oxs_pull_header__(struct ofpbuf *b, uint64_t * header, + const struct oxs_field **field) +{ + if (b->size < 4) { + goto bad_len; + } + + *header = ((uint32_t) ntohl(get_unaligned_be32(b->data))); + if (is_experimenter_oxs(*header)) { + if (b->size < 8) { + goto bad_len; + } + + *header = ntohll(get_unaligned_be64(b->data)); + } + + if (OXS_LENGTH(*header) < oxs_experimenter_len(*header)) { + goto error; + } + + ofpbuf_pull(b, oxs_header_len(*header)); + + if (field) { + *field = oxs_field_by_header(*header); + if (!*field || (*field == NULL)) { + return OFPERR_OFPBMC_BAD_FIELD; + } + } + return 0; + +bad_len: + VLOG_DBG_RL(&rl, "encountered partial (%" PRIu32 "-byte) OXS entry", + b->size); +error: + *header = 0; + if (field) { + *field = NULL; + } + return OFPERR_OFPBMC_BAD_LEN; +} + +static void +oxs_init(void) +{ + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + + if (ovsthread_once_start(&once)) { + hmap_init(&oxs_header_map); + hmap_init(&oxs_name_map); + for (int i = 0; i < OFPXST_OFB_BYTE_COUNT + 1; i++) { + ovs_list_init(&oxs_ox_map[i]); + } + for (struct oxs_field_index * oxfs = all_oxs_fields; + oxfs < &all_oxs_fields[ARRAY_SIZE(all_oxs_fields)]; oxfs++) { + hmap_insert(&oxs_header_map, &oxfs->header_node, + hash_int(oxs_header_no_len(oxfs->fs.header), 0)); + hmap_insert(&oxs_name_map, &oxfs->name_node, + hash_string(oxfs->fs.name, 0)); + ovs_list_push_back(&oxs_ox_map[oxfs->fs.id], &oxfs->ox_node); + } + ovsthread_once_done(&once); + } +} + diff --git a/lib/ox-stat.h b/lib/ox-stat.h new file mode 100644 index 0000000..1dd8ab5 --- /dev/null +++ b/lib/ox-stat.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OX_STAT_H +#define OX_STAT_H 1 + +#include +#include +#include +#include "compiler.h" +#include "flow.h" +#include "openvswitch/meta-flow.h" +#include "openvswitch/ofp-errors.h" +#include "openvswitch/types.h" + +int oxs_put_stat(struct ofpbuf *, const struct ofputil_flow_stats *, + enum ofp_version ); + +#endif /* ox_stat.h */ diff --git a/lib/rconn.c b/lib/rconn.c index 8a29864..13890e7 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -1392,6 +1392,8 @@ is_admitted_msg(const struct ofpbuf *b) case OFPTYPE_DESC_STATS_REPLY: case OFPTYPE_FLOW_STATS_REQUEST: case OFPTYPE_FLOW_STATS_REPLY: + case OFPTYPE_OXS_FLOW_STATS_REQUEST: + case OFPTYPE_OXS_FLOW_STATS_REPLY: case OFPTYPE_AGGREGATE_STATS_REQUEST: case OFPTYPE_AGGREGATE_STATS_REPLY: case OFPTYPE_TABLE_STATS_REQUEST: diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index d5410fd..4b95c9d 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -8092,6 +8092,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_FLOW_STATS_REQUEST: return handle_flow_stats_request(ofconn, oh); + case OFPTYPE_OXS_FLOW_STATS_REQUEST: + return handle_flow_stats_request(ofconn, oh); + case OFPTYPE_AGGREGATE_STATS_REQUEST: return handle_aggregate_stats_request(ofconn, oh); @@ -8167,6 +8170,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_QUEUE_GET_CONFIG_REPLY: case OFPTYPE_DESC_STATS_REPLY: case OFPTYPE_FLOW_STATS_REPLY: + case OFPTYPE_OXS_FLOW_STATS_REPLY: case OFPTYPE_QUEUE_STATS_REPLY: case OFPTYPE_PORT_STATS_REPLY: case OFPTYPE_TABLE_STATS_REPLY: