From patchwork Wed Sep 9 08:37:42 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: niti1489@gmail.com X-Patchwork-Id: 515753 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (li376-54.members.linode.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 448DB140291 for ; Wed, 9 Sep 2015 18:38:15 +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=aQYkVidB; dkim-atps=neutral Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id 424CD10934; Wed, 9 Sep 2015 01:38:14 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v1.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id 363BE10932 for ; Wed, 9 Sep 2015 01:38:13 -0700 (PDT) Received: from bar3.cudamail.com (bar1 [192.168.15.1]) by mx3v1.cudamail.com (Postfix) with ESMTP id 65397618CA6 for ; Wed, 9 Sep 2015 02:38:12 -0600 (MDT) X-ASG-Debug-ID: 1441787889-03dd7b5ec5008b0001-byXFYA Received: from mx3-pf3.cudamail.com ([192.168.14.3]) by bar3.cudamail.com with ESMTP id JuFJljJIqsmoUr0e (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Wed, 09 Sep 2015 02:38:09 -0600 (MDT) X-Barracuda-Envelope-From: niti1489@gmail.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.3 Received: from unknown (HELO mail-pa0-f50.google.com) (209.85.220.50) by mx3-pf3.cudamail.com with ESMTPS (RC4-SHA encrypted); 9 Sep 2015 08:38:01 -0000 Received-SPF: pass (mx3-pf3.cudamail.com: SPF record at _netblocks.google.com designates 209.85.220.50 as permitted sender) X-Barracuda-Apparent-Source-IP: 209.85.220.50 X-Barracuda-RBL-IP: 209.85.220.50 Received: by padhy16 with SMTP id hy16so3854098pad.1 for ; Wed, 09 Sep 2015 01:38:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=Pv3ex2NbCji6w1XAjdAG+A/gi5ShPYtttvxigd2/dYU=; b=aQYkVidBXNj/K2LcrTkHIbqhIkAv4C1vMoSs1v+LQtJ2H8kjRSASCKCwaHzyI4tcRy SwgLoie8EbiBnZ1am+jozkwP28gTQ8CJN6blXg58XmF1jAez+s/64J3UsJgv7WHic+1s 69ufCpcxrwavhG6pfkCRyO3JJii+PLUQyGqxt/5+mOTYABNqM1OEOWEsgZ/5mI3+UdOE iayiTUpDtXfO/uORQc7BOSiZXeL1cOuXPmRNP4eSUZCT7oLrrWXd3snAcDy6ih6TuQwf 1vIGAnb/8zXaqNkbsjnhl4PJwyct+s3fd8Z7ofP3bkkw+oX5I7xQ8yWBMn7vIx9YseF9 V8Qw== X-Received: by 10.68.104.227 with SMTP id gh3mr69278288pbb.108.1441787880986; Wed, 09 Sep 2015 01:38:00 -0700 (PDT) Received: from localhost.localdomain ([117.247.166.121]) by smtp.gmail.com with ESMTPSA id ht7sm6150087pdb.1.2015.09.09.01.37.58 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 Sep 2015 01:37:59 -0700 (PDT) X-CudaMail-Envelope-Sender: niti1489@gmail.com From: niti1489@gmail.com X-Google-Original-From: niti.rohilla@tcs.com To: dev@openvswitch.org X-CudaMail-MID: CM-V3-908002821 X-CudaMail-DTE: 090915 X-CudaMail-Originating-IP: 209.85.220.50 Date: Wed, 9 Sep 2015 14:07:42 +0530 X-ASG-Orig-Subj: [##CM-V3-908002821##][PATCH v2] ofctl: This patch add support for setting the first egress table for egress processing. Message-Id: <1441787862-16227-1-git-send-email-niti.rohilla@tcs.com> X-Mailer: git-send-email 2.5.0 X-GBUdb-Analysis: 0, 209.85.220.50, Ugly c=0.461391 p=-0.431818 Source Normal X-MessageSniffer-Rules: 0-0-0-32767-c X-Barracuda-Connect: UNKNOWN[192.168.14.3] X-Barracuda-Start-Time: 1441787889 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-Barracuda-BRTS-Status: 1 X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-Spam-Score: 1.10 X-Barracuda-Spam-Status: No, SCORE=1.10 using per-user scores of TAG_LEVEL=3.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=3.0 tests=BSF_RULE7568M, BSF_SC5_MJ1963, DKIM_SIGNED, NO_REAL_NAME, RDNS_NONE X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.22366 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.00 NO_REAL_NAME From: does not include a real name 0.00 DKIM_SIGNED Domain Keys Identified Mail: message has a signature 0.50 BSF_RULE7568M Custom Rule 7568M 0.10 RDNS_NONE Delivered to trusted network by a host with no rDNS 0.50 BSF_SC5_MJ1963 Custom Rule MJ1963 Cc: deepankar.gupta@tcs.com, partha.datta@tcs.com Subject: [ovs-dev] [PATCH v2] ofctl: This patch add support for setting the first egress table for egress processing. 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" From: Niti Rohilla "ovs-ofctl set-first-egress-table " can be used to set first egress table. This patch enhances TABLE_FEATURES_REQUEST message to set the first egress table and TABLE_FEATURES_REPLY to identify the table which is configured as first egress table. Signed-off-by: Niti Rohilla --- Difference between v1->v2: - Rebased with latest master - Extra line has been removed include/openflow/openflow-1.5.h | 168 ++++++++++++++ lib/ofp-msgs.h | 16 +- lib/ofp-parse.c | 24 ++ lib/ofp-parse.h | 6 + lib/ofp-print.c | 6 + lib/ofp-util.c | 500 +++++++++++++++++++++++++++++++++++----- lib/ofp-util.h | 13 +- ofproto/ofproto-provider.h | 5 + ofproto/ofproto.c | 29 ++- tests/ofp-print.at | 222 ++++++++++++++++++ tests/ofproto.at | 227 ++++++++++++++++++ utilities/ovs-ofctl.c | 36 ++- 12 files changed, 1190 insertions(+), 62 deletions(-) diff --git a/include/openflow/openflow-1.5.h b/include/openflow/openflow-1.5.h index b3deb2d..20cc0b8 100644 --- a/include/openflow/openflow-1.5.h +++ b/include/openflow/openflow-1.5.h @@ -167,4 +167,172 @@ struct ofp15_group_desc_stats { }; OFP_ASSERT(sizeof(struct ofp15_group_desc_stats) == 16); +/* Table Features request commands */ +enum ofp15_table_features_command { + OFPTFC_REPLACE = 0, /* Replace full pipeline. */ + OFPTFC_MODIFY = 1, /* Modify flow tables capabilities. */ + OFPTFC_ENABLE = 2, /* Enable flow tables in the pipeline. */ + OFPTFC_DISABLE = 3, /* Disable flow tables in pipeline. */ +}; + +/* Flags of features supported by the table. */ +enum ofp15_table_feature_flag { + OFPTFF_INGRESS_TABLE = 1 << 0, /* Can be configured as ingress table. */ + OFPTFF_EGRESS_TABLE = 1 << 1, /* Can be configured as egress table. */ + OFPTFF_FIRST_EGRESS = 1 << 4, /* Is the first egress table. */ +}; + +/* Common header for all Table Feature Properties */ +struct ofp15_table_feature_prop_header { + ovs_be16 type; /* One of OFPTFPT_*. */ + ovs_be16 length; /* Length in bytes of this property. */ +}; +OFP_ASSERT(sizeof(struct ofp15_table_feature_prop_header) == 4); + +/* Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES./ + * Body of reply to OFPMP_TABLE_FEATURES request. */ +struct ofp15_table_features { + ovs_be16 length; /* Length is padded to 64 bits. */ + uint8_t table_id; /* Identifier of table. Lower numbered tables + * are consulted first. */ + uint8_t command; /* One of OFPTFC_*. */ + ovs_be32 features; /* Bitmap of OFPTFF_* values. */ + char name[OFP_MAX_TABLE_NAME_LEN]; + ovs_be64 metadata_match; /* Bits of metadata table can match. */ + ovs_be64 metadata_write; /* Bits of metadata table can write. */ + + /* In OF1.3 this field was named 'config' and it was useless because OF1.3 + * did not define any OFPTC_* bits. + * + * OF1.4 renamed this field to 'capabilities' and added OFPTC14_EVICTION + * and OFPTC14_VACANCY_EVENTS. */ + ovs_be32 capabilities; /* Bitmap of OFPTC_* values */ + + ovs_be32 max_entries; /* Max number of entries supported. */ + + /* Table Feature Property list */ + /* struct ofp15_table_feature_prop_header properties[0]; */ +}; +OFP_ASSERT(sizeof(struct ofp15_table_features) == 64); + +/* Table Feature property types. + * Low order bit cleared indicates a property for a regular Flow Entry. + * Low order bit set indicates a property for the Table-Miss Flow Entry. */ +enum ofp15_table_feature_prop_type { + OFPTFPT15_INSTRUCTIONS = 0, /* Instructions property. */ + OFPTFPT15_INSTRUCTIONS_MISS = 1, /* Instructions for table-miss. */ + OFPTFPT15_NEXT_TABLES = 2, /* Next Table property. */ + OFPTFPT15_NEXT_TABLES_MISS = 3, /* Next Table for table-miss. */ + OFPTFPT15_WRITE_ACTIONS = 4, /* Write Actions property. */ + OFPTFPT15_WRITE_ACTIONS_MISS = 5, /* Write Actions for table-miss. */ + OFPTFPT15_APPLY_ACTIONS = 6, /* Apply Actions property. */ + OFPTFPT15_APPLY_ACTIONS_MISS = 7, /* Apply Actions for table-miss. */ + OFPTFPT15_MATCH = 8, /* Match property. */ + OFPTFPT15_WILDCARDS = 10, /* Wildcards property. */ + OFPTFPT15_WRITE_SETFIELD = 12, /* Write Set-Field property. */ + OFPTFPT15_WRITE_SETFIELD_MISS = 13, /* Write Set-Field for table-miss. */ + OFPTFPT15_APPLY_SETFIELD = 14, /* Apply Set-Field property. */ + OFPTFPT15_APPLY_SETFIELD_MISS = 15, /* Apply Set-Field for table-miss. */ + OFPTFPT15_TABLE_SYNC_FROM = 16, /* Table synchronisation property. */ + OFPTFPT15_WRITE_COPYFIELD = 18, /* Write Copy-Field property. */ + OFPTFPT15_WRITE_COPYFIELD_MISS = 19, /* Write Copy-Field for table-miss. */ + OFPTFPT15_APPLY_COPYFIELD = 20, /* Apply Copy-Field property. */ + OFPTFPT15_APPLY_COPYFIELD_MISS = 21, /* Apply Copy-Field for table-miss. */ + OFPTFPT15_PACKET_TYPES = 22, /* Packet types property. */ + OFPTFPT15_EXPERIMENTER = 0xFFFE, /* Experimenter property. */ + OFPTFPT15_EXPERIMENTER_MISS = 0xFFFF, /* Experimenter for table-miss. */ +}; + +/* Instructions property */ +struct ofp15_table_feature_prop_instructions { + ovs_be16 type; /* One of OFPTFPT15_INSTRUCTIONS, + * OFPTFPT15_INSTRUCTIONS_MISS. */ + ovs_be16 length; /* Length in bytes of this property. */ + /* Followed by: + * - Exactly (length - 4) bytes containing the instruction ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + /* struct ofp11_instruction instruction_ids[0]; List of instructions + without any data */ +}; +OFP_ASSERT(sizeof(struct ofp15_table_feature_prop_instructions) == 4); + +/* Next Tables property */ +struct ofp15_table_feature_prop_next_tables { + ovs_be16 type; /* One of OFPTFPT15_NEXT_TABLES, + * OFPTFPT15_NEXT_TABLES_MISS. + * OFPTFPT15_TABLE_SYNC_FROM. */ + ovs_be16 length; /* Length in bytes of this property. */ + /* Followed by: + * - Exactly (length - 4) bytes containing the table_ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + /* uint8_t next_table_ids[0]; */ +}; +OFP_ASSERT(sizeof(struct ofp15_table_feature_prop_next_tables) == 4); + +/* Actions property */ +struct ofp15_table_feature_prop_actions { + ovs_be16 type; /* One of OFPTFPT15_WRITE_ACTIONS, + * OFPTFPT15_WRITE_ACTIONS_MISS, + * OFPTFPT15_APPLY_ACTIONS, + * OFPTFPT15_APPLY_ACTIONS_MISS. */ + ovs_be16 length; /* Length in bytes of this property. */ + /* Followed by: + * - Exactly (length - 4) bytes containing the action_ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + /* struct ofp_action_header action_ids[0]; List of actions + without any data */ +}; +OFP_ASSERT(sizeof(struct ofp15_table_feature_prop_actions) == 4); + +/* Match, Wildcard or Set-Field property */ +struct ofp15_table_feature_prop_oxm { + ovs_be16 type; /* One of OFPTFPT15_MATCH, OFPTFPT15_WILDCARDS, + * OFPTFPT15_WRITE_SETFIELD, + * OFPTFPT15_WRITE_SETFIELD_MISS, + * OFPTFPT15_APPLY_SETFIELD, + * OFPTFPT15_APPLY_SETFIELD_MISS. + * OFPTFPT15_WRITE_COPYFIELD, + * OFPTFPT15_WRITE_COPYFIELD_MISS, + * OFPTFPT15_APPLY_COPYFIELD, + * OFPTFPT15_APPLY_COPYFIELD_MISS. */ + ovs_be16 length; /* Length in bytes of this property. */ + /* Followed by: + * - Exactly (length - 4) bytes containing the oxm_ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + /* ovs_be32 oxm_ids[0]; Array of OXM headers */ +}; +OFP_ASSERT(sizeof(struct ofp15_table_feature_prop_oxm) == 4); + +/* Packet types property */ +struct ofp15_table_feature_prop_oxm_values { + ovs_be16 type; /* OFPTFPT15_PACKET_TYPES. */ + ovs_be16 length; /* Length in bytes of this property. */ + /* Followed by: + * - Exactly (length - 4) bytes containing the oxm values, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + /*uint32_t oxm_values[0]; Array of OXM values */ +}; +OFP_ASSERT(sizeof(struct ofp15_table_feature_prop_oxm_values) == 4); + +/* Experimenter table feature property */ +struct ofp15_table_feature_prop_experimenter { + ovs_be16 type; /* One of OFPTFPT15_EXPERIMENTER, + * OFPTFPT15_EXPERIMENTER_MISS. */ + ovs_be16 length; /* Length in bytes of this property. */ + ovs_be32 experimenter; /* Experimenter ID which takes the same form + * as in struct ofp_experimenter_header. */ + ovs_be32 exp_type; /* Experimenter defined. */ + /* Followed by: + * - Exactly (length - 12) bytes containing the experimenter data, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + /* ovs_be32 experimenter_data[0]; */ +}; +OFP_ASSERT(sizeof(struct ofp15_table_feature_prop_experimenter) == 12); + #endif /* openflow/openflow-1.5.h */ diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h index 8558e58..38b850f 100644 --- a/lib/ofp-msgs.h +++ b/lib/ofp-msgs.h @@ -369,12 +369,18 @@ enum ofpraw { /* OFPST 1.3+ (11): struct ofp13_meter_features. */ OFPRAW_OFPST13_METER_FEATURES_REPLY, - /* OFPST 1.3+ (12): void. */ + /* OFPST 1.3-1.4 (12): void. */ OFPRAW_OFPST13_TABLE_FEATURES_REQUEST, - /* OFPST 1.3+ (12): struct ofp13_table_features, uint8_t[8][]. */ + /* OFPST 1.5+ (12): struct ofp15_table_features[]. */ + OFPRAW_OFPST15_TABLE_FEATURES_REQUEST, + + /* OFPST 1.3-1.4 (12): struct ofp13_table_features, uint8_t[8][]. */ OFPRAW_OFPST13_TABLE_FEATURES_REPLY, + /* OFPST 1.5+ (12): struct ofp15_table_features, uint8_t[8][]. */ + OFPRAW_OFPST15_TABLE_FEATURES_REPLY, + /* OFPST 1.4+ (15): void. */ OFPRAW_OFPST14_TABLE_DESC_REQUEST, @@ -622,9 +628,11 @@ enum ofptype { OFPTYPE_METER_FEATURES_STATS_REPLY, /* OFPRAW_OFPST13_METER_FEATURES_REPLY. */ - OFPTYPE_TABLE_FEATURES_STATS_REQUEST, /* OFPRAW_OFPST13_TABLE_FEATURES_REQUEST. */ + OFPTYPE_TABLE_FEATURES_STATS_REQUEST, /* OFPRAW_OFPST13_TABLE_FEATURES_REQUEST. + * OFPRAW_OFPST15_TABLE_FEATURES_REQUEST. */ - OFPTYPE_TABLE_FEATURES_STATS_REPLY, /* OFPRAW_OFPST13_TABLE_FEATURES_REPLY. */ + OFPTYPE_TABLE_FEATURES_STATS_REPLY, /* OFPRAW_OFPST13_TABLE_FEATURES_REPLY. + * OFPRAW_OFPST15_TABLE_FEATURES_REPLY. */ OFPTYPE_TABLE_DESC_REQUEST, /* OFPRAW_OFPST14_TABLE_DESC_REQUEST. */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index eaaa8ba..10e15b2 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -1652,3 +1652,27 @@ parse_ofp_geneve_table_mod_str(struct ofputil_geneve_table_mod *gtm, return NULL; } + +/* Convert 'table_id' and table feature flag 'OFPTFF_FIRST_EGRESS' into 'tf' + * for sending a set_table_features command to a switch. + * + * Stores a bitmap of the OpenFlow versions that are usable for 'tf' into + * '*usable_versions'. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +char * OVS_WARN_UNUSED_RESULT +parse_ofp_table_features(struct ofputil_table_features *tf, const char *table_id, + uint32_t *usable_versions) +{ + char *error = str_to_u8(table_id, "table_id", &tf->table_id); + if (error) { + return error; + } + + *usable_versions = (1u << OFP15_VERSION); + + tf->features = OFPTFF_FIRST_EGRESS; + + return NULL; +} diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h index b64a32e..ca87303 100644 --- a/lib/ofp-parse.h +++ b/lib/ofp-parse.h @@ -36,6 +36,7 @@ struct ofputil_meter_mod; struct ofputil_table_mod; struct ofputil_geneve_table_mod; struct simap; +struct ofputil_table_features; enum ofputil_protocol; char *parse_ofp_str(struct ofputil_flow_mod *, int command, const char *str_, @@ -52,6 +53,11 @@ char *parse_ofp_table_mod(struct ofputil_table_mod *, uint32_t *usable_versions) OVS_WARN_UNUSED_RESULT; +char *parse_ofp_table_features(struct ofputil_table_features *tf, + const char *table_id, + uint32_t *usable_versions) + OVS_WARN_UNUSED_RESULT; + char *parse_ofp_flow_mod_file(const char *file_name, int command, struct ofputil_flow_mod **fms, size_t *n_fms, enum ofputil_protocol *usable_protocols) diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 6e32d4d..2a7bc37 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -2792,6 +2792,12 @@ ofp_print_table_features(struct ds *s, } + if(features->features >= 0) { + ds_put_format(s, " features: %s\n", + (features->features & OFPTFF_FIRST_EGRESS) ? + "first egress table" : "none"); + } + if (features->max_entries) { ds_put_format(s, " max_entries=%"PRIu32"\n", features->max_entries); } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 5331f8c..8100f54 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -4454,6 +4454,12 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, return b; } + +/* Variable to store the table-id of the first egress table. If it is set to + * 0 it means that egress processing is not enabled. + */ +int first_egress_table = 0; + /* Table features. */ @@ -4494,6 +4500,47 @@ parse_action_bitmap(struct ofpbuf *payload, enum ofp_version ofp_version, } static enum ofperr +parse15_action_bitmap(struct ofpbuf *payload, enum ofp_version ofp_version, + uint8_t table_id, uint64_t *ofpacts) +{ + uint32_t types = 0; + + while (payload->size > 0) { + uint16_t type; + enum ofperr error; + + error = ofputil_pull_property__(payload, NULL, 1, &type); + if (error) { + return error; + } + + /* If first egress table is set then flow tables used for egress + * processing must forbid the use of output actior group action in + * write-action instrcution and must advertise the same in flow table + * features as mentioned in the specification. + * + * OFPAT_* values, i.e. 0 for OFPACT_OUTPUT and 22 for OFPACT_GROUP is + * used for comparison as ofpact_type cannot be compared directly with + * 'type', which is of type ofpat. + */ + if (type < CHAR_BIT * sizeof types) { + if (first_egress_table && first_egress_table <= table_id) { + if (type == 0 || type == 22) { + continue; + } else { + types |= 1u << type; + } + } else { + types |= 1u << type; + } + } + } + + *ofpacts = ofpact_bitmap_from_openflow(htonl(types), ofp_version); + return 0; +} + +static enum ofperr parse_instruction_ids(struct ofpbuf *payload, bool loose, uint32_t *insts) { *insts = 0; @@ -4575,25 +4622,10 @@ parse_oxms(struct ofpbuf *payload, bool loose, return 0; } -/* Converts an OFPMP_TABLE_FEATURES request or reply in 'msg' into an abstract - * ofputil_table_features in 'tf'. - * - * If 'loose' is true, this function ignores properties and values that it does - * not understand, as a controller would want to do when interpreting - * capabilities provided by a switch. If 'loose' is false, this function - * treats unknown properties and values as an error, as a switch would want to - * do when interpreting a configuration request made by a controller. - * - * A single OpenFlow message can specify features for multiple tables. Calling - * this function multiple times for a single 'msg' iterates through the tables - * in the message. The caller must initially leave 'msg''s layer pointers null - * and not modify them between calls. - * - * Returns 0 if successful, EOF if no tables were left in this 'msg', otherwise - * a positive "enum ofperr" value. */ -int -ofputil_decode_table_features(struct ofpbuf *msg, - struct ofputil_table_features *tf, bool loose) +static int +ofputil_decode_ofpst13_table_features(struct ofpbuf *msg, + struct ofputil_table_features *tf, + bool loose) { const struct ofp_header *oh; struct ofp13_table_features *otf; @@ -4601,10 +4633,6 @@ ofputil_decode_table_features(struct ofpbuf *msg, unsigned int len; memset(tf, 0, sizeof *tf); - - if (!msg->header) { - ofpraw_pull_assert(msg); - } oh = msg->header; if (!msg->size) { @@ -4641,6 +4669,7 @@ ofputil_decode_table_features(struct ofpbuf *msg, tf->supports_vacancy_events = -1; } tf->max_entries = ntohl(otf->max_entries); + tf->features = -1; while (properties.size > 0) { struct ofpbuf payload; @@ -4742,10 +4771,242 @@ ofputil_decode_table_features(struct ofpbuf *msg, return 0; } +static int +ofputil_decode_ofpst15_table_features(struct ofpbuf *msg, + struct ofputil_table_features *tf, + bool loose, enum ofpraw raw) +{ + const struct ofp_header *oh; + struct ofp15_table_features *otf; + struct ofpbuf properties; + unsigned int len; + uint32_t features; + uint32_t caps; + + memset(tf, 0, sizeof *tf); + oh = msg->header; + + if (!msg->size) { + return EOF; + } + + if (msg->size < sizeof *otf) { + return OFPERR_OFPBPC_BAD_LEN; + } + + otf = msg->data; + len = ntohs(otf->length); + if (len < sizeof *otf || len % 8 || len > msg->size) { + return OFPERR_OFPBPC_BAD_LEN; + } + ofpbuf_use_const(&properties, ofpbuf_pull(msg, len), len); + ofpbuf_pull(&properties, sizeof *otf); + + tf->table_id = otf->table_id; + if (tf->table_id == OFPTT_ALL) { + return OFPERR_OFPTFFC_BAD_TABLE; + } + + if (raw == OFPRAW_OFPST15_TABLE_FEATURES_REQUEST) { + + /* Return an error if TABLE_FEATURES_REQUEST attempts to set table 0 + * as first egress table. */ + if (tf->table_id == 0) { + return OFPERR_OFPTFFC_BAD_TABLE; + } + + /* Return an error if TABLE_FEATURES_REQUEST contain properties. */ + if (properties.size > 0) { + return OFPERR_OFPBPC_BAD_LEN; + } + } + + ovs_strlcpy(tf->name, otf->name, OFP_MAX_TABLE_NAME_LEN); + tf->metadata_match = otf->metadata_match; + tf->metadata_write = otf->metadata_write; + tf->miss_config = OFPUTIL_TABLE_MISS_DEFAULT; + + caps = ntohl(otf->capabilities); + tf->supports_eviction = (caps & OFPTC14_EVICTION) != 0; + tf->supports_vacancy_events = (caps & OFPTC14_VACANCY_EVENTS) != 0; + + tf->max_entries = ntohl(otf->max_entries); + + /* Return an error if any flag other than OFPTFF_FIRST_EGRESS is set. */ + features = ntohl(otf->features); + if ((features & OFPTFF_FIRST_EGRESS) != 0) { + tf->features = OFPTFF_FIRST_EGRESS; + first_egress_table = tf->table_id; + } else if ((features & OFPTFF_INGRESS_TABLE) != 0 || + (features & OFPTFF_EGRESS_TABLE) != 0 ) { + return OFPERR_OFPBFC_BAD_FLAGS; + } + + while (properties.size > 0) { + struct ofpbuf payload; + enum ofperr error; + uint16_t type; + + error = pull_table_feature_property(&properties, &payload, &type); + if (error) { + return error; + } + + switch ((enum ofp15_table_feature_prop_type) type) { + case OFPTFPT15_INSTRUCTIONS: + error = parse_instruction_ids(&payload, loose, + &tf->nonmiss.instructions); + break; + + case OFPTFPT15_INSTRUCTIONS_MISS: + error = parse_instruction_ids(&payload, loose, + &tf->miss.instructions); + break; + + case OFPTFPT15_NEXT_TABLES: + error = parse_table_features_next_table(&payload, + tf->nonmiss.next); + break; + + case OFPTFPT15_NEXT_TABLES_MISS: + error = parse_table_features_next_table(&payload, tf->miss.next); + break; + + case OFPTFPT15_WRITE_ACTIONS: + error = parse15_action_bitmap(&payload, oh->version, tf->table_id, + &tf->nonmiss.write.ofpacts); + break; + + case OFPTFPT15_WRITE_ACTIONS_MISS: + error = parse15_action_bitmap(&payload, oh->version, tf->table_id, + &tf->miss.write.ofpacts); + break; + + case OFPTFPT15_APPLY_ACTIONS: + error = parse_action_bitmap(&payload, oh->version, + &tf->nonmiss.apply.ofpacts); + break; + + case OFPTFPT15_APPLY_ACTIONS_MISS: + error = parse_action_bitmap(&payload, oh->version, + &tf->miss.apply.ofpacts); + break; + + case OFPTFPT15_MATCH: + error = parse_oxms(&payload, loose, &tf->match, &tf->mask); + break; + + case OFPTFPT15_WILDCARDS: + error = parse_oxms(&payload, loose, &tf->wildcard, NULL); + break; + + case OFPTFPT15_WRITE_SETFIELD: + error = parse_oxms(&payload, loose, + &tf->nonmiss.write.set_fields, NULL); + break; + + case OFPTFPT15_WRITE_SETFIELD_MISS: + error = parse_oxms(&payload, loose, + &tf->miss.write.set_fields, NULL); + break; + + case OFPTFPT15_APPLY_SETFIELD: + error = parse_oxms(&payload, loose, + &tf->nonmiss.apply.set_fields, NULL); + break; + + case OFPTFPT15_APPLY_SETFIELD_MISS: + error = parse_oxms(&payload, loose, + &tf->miss.apply.set_fields, NULL); + break; + + case OFPTFPT15_TABLE_SYNC_FROM: + case OFPTFPT15_WRITE_COPYFIELD: + case OFPTFPT15_WRITE_COPYFIELD_MISS: + case OFPTFPT15_APPLY_COPYFIELD: + case OFPTFPT15_APPLY_COPYFIELD_MISS: + case OFPTFPT15_PACKET_TYPES: + log_property(loose, "unsupported table features property %"PRIu16, + type); + break; + + case OFPTFPT15_EXPERIMENTER: + case OFPTFPT15_EXPERIMENTER_MISS: + default: + log_property(loose, "unknown table features property %"PRIu16, + type); + error = loose ? 0 : OFPERR_OFPBPC_BAD_TYPE; + break; + } + if (error) { + return error; + } + } + + /* Fix inconsistencies: + * + * - Turn on 'match' bits that are set in 'mask', because maskable + * fields are matchable. + * + * - Turn on 'wildcard' bits that are set in 'mask', because a field + * that is arbitrarily maskable can be wildcarded entirely. + * + * - Turn off 'wildcard' bits that are not in 'match', because a field + * must be matchable for it to be meaningfully wildcarded. */ + bitmap_or(tf->match.bm, tf->mask.bm, MFF_N_IDS); + bitmap_or(tf->wildcard.bm, tf->mask.bm, MFF_N_IDS); + bitmap_and(tf->wildcard.bm, tf->match.bm, MFF_N_IDS); + + return 0; +} + +/* Converts an OFPMP_TABLE_FEATURES request or reply in 'msg' into an abstract + * ofputil_table_features in 'tf'. + * + * If 'loose' is true, this function ignores properties and values that it does + * not understand, as a controller would want to do when interpreting + * capabilities provided by a switch. If 'loose' is false, this function + * treats unknown properties and values as an error, as a switch would want to + * do when interpreting a configuration request made by a controller. + * + * A single OpenFlow message can specify features for multiple tables. Calling + * this function multiple times for a single 'msg' iterates through the tables + * in the message. The caller must initially leave 'msg''s layer pointers null + * and not modify them between calls. + * + * Returns 0 if successful, EOF if no tables were left in this 'msg', otherwise + * a positive "enum ofperr" value. */ +int +ofputil_decode_table_features(struct ofpbuf *msg, + struct ofputil_table_features *tf, bool loose) +{ + enum ofpraw raw; + enum ofperr error; + error = (msg->header ? ofpraw_decode(&raw, msg->header) + : ofpraw_pull(&raw, msg)); + if (error) { + return error; + } + + switch ((int)raw) { + case OFPRAW_OFPST13_TABLE_FEATURES_REQUEST: + case OFPRAW_OFPST13_TABLE_FEATURES_REPLY: + return ofputil_decode_ofpst13_table_features(msg, tf, loose); + + case OFPRAW_OFPST15_TABLE_FEATURES_REQUEST: + case OFPRAW_OFPST15_TABLE_FEATURES_REPLY: + return ofputil_decode_ofpst15_table_features(msg, tf, loose, raw); + + default: + OVS_NOT_REACHED(); + } +} + /* Encodes and returns a request to obtain the table features of a switch. * The message is encoded for OpenFlow version 'ofp_version'. */ struct ofpbuf * -ofputil_encode_table_features_request(enum ofp_version ofp_version) +ofputil_encode_table_features_request(const struct ofputil_table_features *tf, + enum ofp_version ofp_version) { struct ofpbuf *request = NULL; @@ -4757,10 +5018,22 @@ ofputil_encode_table_features_request(enum ofp_version ofp_version) "(\'-O OpenFlow13\')"); case OFP13_VERSION: case OFP14_VERSION: - case OFP15_VERSION: request = ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST, ofp_version, 0); break; + case OFP15_VERSION: { + struct ofp15_table_features *otf; + + request = ofpraw_alloc(OFPRAW_OFPST15_TABLE_FEATURES_REQUEST, + ofp_version, 0); + if (tf != NULL && (tf->features & OFPTFF_FIRST_EGRESS)) { + otf = ofpbuf_put_zeros(request, sizeof *otf); + otf->table_id = tf->table_id; + otf->features = htonl(tf->features); + otf->length = htons(sizeof *otf); + } + } + break; default: OVS_NOT_REACHED(); } @@ -4769,11 +5042,29 @@ ofputil_encode_table_features_request(enum ofp_version ofp_version) } static void -put_fields_property(struct ofpbuf *reply, - const struct mf_bitmap *fields, - const struct mf_bitmap *masks, - enum ofp13_table_feature_prop_type property, - enum ofp_version version) +put_ofpst13_fields_property(struct ofpbuf *reply, + const struct mf_bitmap *fields, + const struct mf_bitmap *masks, + enum ofp13_table_feature_prop_type property, + enum ofp_version version) +{ + size_t start_ofs; + int field; + + start_ofs = start_property(reply, property); + BITMAP_FOR_EACH_1 (field, MFF_N_IDS, fields->bm) { + nx_put_header(reply, field, version, + masks && bitmap_is_set(masks->bm, field)); + } + end_property(reply, start_ofs); +} + +static void +put_ofpst15_fields_property(struct ofpbuf *reply, + const struct mf_bitmap *fields, + const struct mf_bitmap *masks, + enum ofp15_table_feature_prop_type property, + enum ofp_version version) { size_t start_ofs; int field; @@ -4787,11 +5078,30 @@ put_fields_property(struct ofpbuf *reply, } static void -put_table_action_features(struct ofpbuf *reply, - const struct ofputil_table_action_features *taf, - enum ofp13_table_feature_prop_type actions_type, - enum ofp13_table_feature_prop_type set_fields_type, - int miss_offset, enum ofp_version version) +put_ofpst13_table_action_features( + struct ofpbuf *reply, const struct ofputil_table_action_features *taf, + enum ofp13_table_feature_prop_type actions_type, + enum ofp13_table_feature_prop_type set_fields_type, + int miss_offset, enum ofp_version version) +{ + size_t start_ofs; + + start_ofs = start_property(reply, actions_type + miss_offset); + put_bitmap_properties(reply, + ntohl(ofpact_bitmap_to_openflow(taf->ofpacts, + version))); + end_property(reply, start_ofs); + + put_ofpst13_fields_property(reply, &taf->set_fields, NULL, + set_fields_type + miss_offset, version); +} + +static void +put_ofpst15_table_action_features( + struct ofpbuf *reply, const struct ofputil_table_action_features *taf, + enum ofp15_table_feature_prop_type actions_type, + enum ofp15_table_feature_prop_type set_fields_type, + int miss_offset, enum ofp_version version) { size_t start_ofs; @@ -4801,12 +5111,12 @@ put_table_action_features(struct ofpbuf *reply, version))); end_property(reply, start_ofs); - put_fields_property(reply, &taf->set_fields, NULL, - set_fields_type + miss_offset, version); + put_ofpst15_fields_property(reply, &taf->set_fields, NULL, + set_fields_type + miss_offset, version); } static void -put_table_instruction_features( +put_ofpst13_table_instruction_features( struct ofpbuf *reply, const struct ofputil_table_instruction_features *tif, int miss_offset, enum ofp_version version) { @@ -4825,17 +5135,49 @@ put_table_instruction_features( } end_property(reply, start_ofs); - put_table_action_features(reply, &tif->write, - OFPTFPT13_WRITE_ACTIONS, - OFPTFPT13_WRITE_SETFIELD, miss_offset, version); - put_table_action_features(reply, &tif->apply, - OFPTFPT13_APPLY_ACTIONS, - OFPTFPT13_APPLY_SETFIELD, miss_offset, version); + put_ofpst13_table_action_features(reply, &tif->write, + OFPTFPT13_WRITE_ACTIONS, + OFPTFPT13_WRITE_SETFIELD, + miss_offset, version); + put_ofpst13_table_action_features(reply, &tif->apply, + OFPTFPT13_APPLY_ACTIONS, + OFPTFPT13_APPLY_SETFIELD, + miss_offset, version); } -void -ofputil_append_table_features_reply(const struct ofputil_table_features *tf, - struct ovs_list *replies) +static void +put_ofpst15_table_instruction_features( + struct ofpbuf *reply, const struct ofputil_table_instruction_features *tif, + int miss_offset, enum ofp_version version) +{ + size_t start_ofs; + uint8_t table_id; + + start_ofs = start_property(reply, OFPTFPT15_INSTRUCTIONS + miss_offset); + put_bitmap_properties(reply, + ntohl(ovsinst_bitmap_to_openflow(tif->instructions, + version))); + end_property(reply, start_ofs); + + start_ofs = start_property(reply, OFPTFPT15_NEXT_TABLES + miss_offset); + BITMAP_FOR_EACH_1 (table_id, 255, tif->next) { + ofpbuf_put(reply, &table_id, 1); + } + end_property(reply, start_ofs); + + put_ofpst15_table_action_features(reply, &tif->write, + OFPTFPT15_WRITE_ACTIONS, + OFPTFPT15_WRITE_SETFIELD, + miss_offset, version); + put_ofpst15_table_action_features(reply, &tif->apply, + OFPTFPT15_APPLY_ACTIONS, + OFPTFPT15_APPLY_SETFIELD, + miss_offset, version); +} + +static void +ofputil_ofpst13_table_features_reply(const struct ofputil_table_features *tf, + struct ovs_list *replies) { struct ofpbuf *reply = ofpbuf_from_list(list_back(replies)); enum ofp_version version = ofpmp_version(replies); @@ -4857,19 +5199,70 @@ ofputil_append_table_features_reply(const struct ofputil_table_features *tf, } otf->max_entries = htonl(tf->max_entries); - put_table_instruction_features(reply, &tf->nonmiss, 0, version); - put_table_instruction_features(reply, &tf->miss, 1, version); + put_ofpst13_table_instruction_features(reply, &tf->nonmiss, 0, version); + put_ofpst13_table_instruction_features(reply, &tf->miss, 1, version); - put_fields_property(reply, &tf->match, &tf->mask, - OFPTFPT13_MATCH, version); - put_fields_property(reply, &tf->wildcard, NULL, - OFPTFPT13_WILDCARDS, version); + put_ofpst13_fields_property(reply, &tf->match, &tf->mask, + OFPTFPT13_MATCH, version); + put_ofpst13_fields_property(reply, &tf->wildcard, NULL, + OFPTFPT13_WILDCARDS, version); otf = ofpbuf_at_assert(reply, start_ofs, sizeof *otf); otf->length = htons(reply->size - start_ofs); ofpmp_postappend(replies, start_ofs); } +static void +ofputil_ofpst15_table_features_reply(const struct ofputil_table_features *tf, + struct ovs_list *replies) +{ + struct ofpbuf *reply = ofpbuf_from_list(list_back(replies)); + enum ofp_version version = ofpmp_version(replies); + size_t start_ofs = reply->size; + struct ofp15_table_features *otf; + + otf = ofpbuf_put_zeros(reply, sizeof *otf); + otf->table_id = tf->table_id; + ovs_strlcpy(otf->name, tf->name, sizeof otf->name); + otf->metadata_match = tf->metadata_match; + otf->metadata_write = tf->metadata_write; + if (tf->supports_eviction) { + otf->capabilities |= htonl(OFPTC14_EVICTION); + } + if (tf->supports_vacancy_events) { + otf->capabilities |= htonl(OFPTC14_VACANCY_EVENTS); + } + otf->max_entries = htonl(tf->max_entries); + + if ((tf->features & OFPTFF_FIRST_EGRESS) != 0) { + otf->features = htonl(OFPTFF_FIRST_EGRESS); + } + put_ofpst15_table_instruction_features(reply, &tf->nonmiss, 0, version); + put_ofpst15_table_instruction_features(reply, &tf->miss, 1, version); + + put_ofpst15_fields_property(reply, &tf->match, &tf->mask, + OFPTFPT15_MATCH, version); + put_ofpst15_fields_property(reply, &tf->wildcard, NULL, + OFPTFPT15_WILDCARDS, version); + + otf = ofpbuf_at_assert(reply, start_ofs, sizeof *otf); + otf->length = htons(reply->size - start_ofs); + ofpmp_postappend(replies, start_ofs); +} + +void +ofputil_append_table_features_reply(const struct ofputil_table_features *tf, + struct ovs_list *replies) +{ + enum ofp_version version = ofpmp_version(replies); + + if (version < OFP15_VERSION) { + ofputil_ofpst13_table_features_reply(tf, replies); + } else { + ofputil_ofpst15_table_features_reply(tf, replies); + } +} + static enum ofperr parse_table_desc_eviction_property(struct ofpbuf *property, struct ofputil_table_desc *td) @@ -5770,6 +6163,7 @@ ofputil_decode_table_stats_reply(struct ofpbuf *msg, memset(features, 0, sizeof *features); features->supports_eviction = -1; features->supports_vacancy_events = -1; + features->features = -1; switch ((enum ofp_version) oh->version) { case OFP10_VERSION: diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 527a5ab..fc853c2 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -682,6 +682,15 @@ struct ofputil_table_features { int supports_eviction; /* OF1.4+ only. */ int supports_vacancy_events; /* OF1.4+ only. */ + /* The features field is a bitmap of OFPTFF_* values that defines how the + * flow table can be used and what are its basic features. + * + * 'features' is relevant only for Openflow 1.5 and later only. For 1.5, + * it will be OFPTFF_FIRST_EGRESS if first egress table is set, otherwise + * 0. For other versions, they are decoded as -1 and ignored for encoding. + */ + int features; /* OF1.5+ only. */ + /* Table features related to instructions. There are two instances: * * - 'miss' reports features available in the table miss flow. @@ -738,7 +747,9 @@ int ofputil_decode_table_desc(struct ofpbuf *, struct ofputil_table_desc *, enum ofp_version); -struct ofpbuf *ofputil_encode_table_features_request(enum ofp_version); +struct ofpbuf * +ofputil_encode_table_features_request(const struct ofputil_table_features *, + enum ofp_version); struct ofpbuf *ofputil_encode_table_desc_request(enum ofp_version); diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 117cd1f..ea4371e 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -258,6 +258,11 @@ struct oftable { atomic_ulong n_matched; atomic_ulong n_missed; + + /* This flag indicates that this flow table is the first egress table, when + * a packet is output to a port, egress processing will start with this flow + * table. */ + bool is_first_egress; }; /* Assigns TABLE to each oftable, in turn, in OFPROTO. diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index e6c0351..aeecb78 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -3163,6 +3163,9 @@ query_tables(struct ofproto *ofproto, f->match = match; f->mask = mask; f->wildcard = match; + if (ofproto->tables[i].is_first_egress) { + f->features = OFPTFF_FIRST_EGRESS; + } } if (statsp) { @@ -3553,12 +3556,34 @@ handle_table_features_request(struct ofconn *ofconn, struct ofputil_table_features *features; struct ovs_list replies; struct ofpbuf msg; + enum ofperr error = 0; size_t i; ofpbuf_use_const(&msg, request, ntohs(request->length)); ofpraw_pull_assert(&msg); - if (msg.size || ofpmp_more(request)) { - return OFPERR_OFPTFFC_EPERM; + + if (request->version < OFP15_VERSION) { + if (msg.size || ofpmp_more(request)) { + return OFPERR_OFPTFFC_EPERM; + } + } else { + if (msg.size) { + struct ofputil_table_features tf; + error = ofputil_decode_table_features(&msg, &tf, false); + if (error) { + return error; + } + if ((tf.features & OFPTFF_FIRST_EGRESS) != 0) { + for (i = 0; i < ofproto->n_tables; i++) { + if (ofproto->tables[i].is_first_egress) { + ofproto->tables[i].is_first_egress = false; + break; + } + } + ofproto->tables[tf.table_id].is_first_egress = true; + } + return 0; + } } query_tables(ofproto, &features, NULL); diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 35a6262..bd40aee 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -2475,6 +2475,228 @@ f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \ ]) AT_CLEANUP +AT_SETUP([OFPST_TABLE_FEATURES request - OF1.5]) +AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) +AT_CHECK([ovs-ofctl ofp-print "\ +06 13 09 40 00 00 00 d5 00 0c 00 01 00 00 00 00 \ +09 30 00 00 00 00 00 00 74 61 62 6c 65 30 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff \ +ff ff ff ff ff ff ff ff 00 00 00 03 00 0f 42 40 \ +00 00 00 2c 00 01 00 08 00 00 00 00 00 02 00 08 \ +00 00 00 00 00 03 00 08 00 00 00 00 00 04 00 08 \ +00 00 00 00 00 05 00 08 00 00 00 00 00 00 00 00 \ +00 01 00 2c 00 01 00 08 00 00 00 00 00 02 00 08 \ +00 00 00 00 00 03 00 08 00 00 00 00 00 04 00 08 \ +00 00 00 00 00 05 00 08 00 00 00 00 00 00 00 00 \ +00 02 01 01 01 02 03 04 05 06 07 08 09 0a 0b 0c \ +0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c \ +1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c \ +2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c \ +3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c \ +4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c \ +5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c \ +6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c \ +7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c \ +8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c \ +9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac \ +ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc \ +bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc \ +cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc \ +dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec \ +ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc \ +fd 00 00 00 00 00 00 00 00 03 01 01 01 02 03 04 \ +05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 \ +15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 \ +25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 \ +35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 \ +45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 \ +55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 \ +65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 \ +75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 \ +85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 \ +95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 \ +a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 \ +b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 \ +c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 \ +d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 \ +e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 \ +f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \ +00 04 00 84 00 00 00 08 00 00 00 00 00 0b 00 08 \ +00 00 00 00 00 0c 00 08 00 00 00 00 00 0f 00 08 \ +00 00 00 00 00 10 00 08 00 00 00 00 00 11 00 08 \ +00 00 00 00 00 12 00 08 00 00 00 00 00 13 00 08 \ +00 00 00 00 00 14 00 08 00 00 00 00 00 15 00 08 \ +00 00 00 00 00 16 00 08 00 00 00 00 00 17 00 08 \ +00 00 00 00 00 18 00 08 00 00 00 00 00 19 00 08 \ +00 00 00 00 00 1a 00 08 00 00 00 00 00 1b 00 08 \ +00 00 00 00 00 00 00 00 00 05 00 84 00 00 00 08 \ +00 00 00 00 00 0b 00 08 00 00 00 00 00 0c 00 08 \ +00 00 00 00 00 0f 00 08 00 00 00 00 00 10 00 08 \ +00 00 00 00 00 11 00 08 00 00 00 00 00 12 00 08 \ +00 00 00 00 00 13 00 08 00 00 00 00 00 14 00 08 \ +00 00 00 00 00 15 00 08 00 00 00 00 00 16 00 08 \ +00 00 00 00 00 17 00 08 00 00 00 00 00 18 00 08 \ +00 00 00 00 00 19 00 08 00 00 00 00 00 1a 00 08 \ +00 00 00 00 00 1b 00 08 00 00 00 00 00 00 00 00 \ +00 06 00 84 00 00 00 08 00 00 00 00 00 0b 00 08 \ +00 00 00 00 00 0c 00 08 00 00 00 00 00 0f 00 08 \ +00 00 00 00 00 10 00 08 00 00 00 00 00 11 00 08 \ +00 00 00 00 00 12 00 08 00 00 00 00 00 13 00 08 \ +00 00 00 00 00 14 00 08 00 00 00 00 00 15 00 08 \ +00 00 00 00 00 16 00 08 00 00 00 00 00 17 00 08 \ +00 00 00 00 00 18 00 08 00 00 00 00 00 19 00 08 \ +00 00 00 00 00 1a 00 08 00 00 00 00 00 1b 00 08 \ +00 00 00 00 00 00 00 00 00 07 00 84 00 00 00 08 \ +00 00 00 00 00 0b 00 08 00 00 00 00 00 0c 00 08 \ +00 00 00 00 00 0f 00 08 00 00 00 00 00 10 00 08 \ +00 00 00 00 00 11 00 08 00 00 00 00 00 12 00 08 \ +00 00 00 00 00 13 00 08 00 00 00 00 00 14 00 08 \ +00 00 00 00 00 15 00 08 00 00 00 00 00 16 00 08 \ +00 00 00 00 00 17 00 08 00 00 00 00 00 18 00 08 \ +00 00 00 00 00 19 00 08 00 00 00 00 00 1a 00 08 \ +00 00 00 00 00 1b 00 08 00 00 00 00 00 00 00 00 \ +00 08 00 dc 80 00 4c 08 00 01 3e 04 00 01 40 04 \ +80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \ +00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \ +00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \ +80 00 08 06 80 00 06 06 80 00 0a 02 00 00 08 02 \ +80 00 0c 02 80 00 0e 01 80 00 44 04 80 00 46 01 \ +80 00 48 01 80 00 16 04 80 00 18 04 80 00 34 10 \ +80 00 36 10 80 00 38 04 80 00 14 01 00 00 0a 01 \ +80 00 10 01 80 00 12 01 00 01 3a 01 00 01 34 01 \ +80 00 2a 02 80 00 2c 04 80 00 2e 04 80 00 30 06 \ +80 00 32 06 80 00 1a 02 80 00 1c 02 00 01 44 02 \ +80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \ +80 00 26 01 80 00 28 01 80 00 3a 01 80 00 3c 01 \ +80 00 3e 10 80 00 40 06 80 00 42 06 00 00 00 00 \ +00 0a 00 dc 80 00 4c 08 00 01 3e 04 00 01 40 04 \ +80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \ +00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \ +00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \ +80 00 08 06 80 00 06 06 80 00 0a 02 00 00 08 02 \ +80 00 0c 02 80 00 0e 01 80 00 44 04 80 00 46 01 \ +80 00 48 01 80 00 16 04 80 00 18 04 80 00 34 10 \ +80 00 36 10 80 00 38 04 80 00 14 01 00 00 0a 01 \ +80 00 10 01 80 00 12 01 00 01 3a 01 00 01 34 01 \ +80 00 2a 02 80 00 2c 04 80 00 2e 04 80 00 30 06 \ +80 00 32 06 80 00 1a 02 80 00 1c 02 00 01 44 02 \ +80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \ +80 00 26 01 80 00 28 01 80 00 3a 01 80 00 3c 01 \ +80 00 3e 10 80 00 40 06 80 00 42 06 00 00 00 00 \ +00 0c 00 a8 80 00 4c 08 00 01 3e 04 00 01 40 04 \ +80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \ +00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \ +00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \ +80 00 08 06 80 00 06 06 00 00 08 02 80 00 0c 02 \ +80 00 0e 01 80 00 44 04 80 00 46 01 80 00 16 04 \ +80 00 18 04 80 00 34 10 80 00 36 10 00 00 0a 01 \ +80 00 10 01 80 00 12 01 00 01 3a 01 80 00 2a 02 \ +80 00 2c 04 80 00 2e 04 80 00 30 06 80 00 32 06 \ +80 00 1a 02 80 00 1c 02 80 00 1e 02 80 00 20 02 \ +80 00 22 02 80 00 24 02 00 0d 00 a8 80 00 4c 08 \ +00 01 3e 04 00 01 40 04 80 00 04 08 00 00 00 02 \ +80 00 00 04 00 01 42 04 00 01 00 04 00 01 02 04 \ +00 01 04 04 00 01 06 04 00 01 08 04 00 01 0a 04 \ +00 01 0c 04 00 01 0e 04 80 00 08 06 80 00 06 06 \ +00 00 08 02 80 00 0c 02 80 00 0e 01 80 00 44 04 \ +80 00 46 01 80 00 16 04 80 00 18 04 80 00 34 10 \ +80 00 36 10 00 00 0a 01 80 00 10 01 80 00 12 01 \ +00 01 3a 01 80 00 2a 02 80 00 2c 04 80 00 2e 04 \ +80 00 30 06 80 00 32 06 80 00 1a 02 80 00 1c 02 \ +80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \ +00 0e 00 a8 80 00 4c 08 00 01 3e 04 00 01 40 04 \ +80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \ +00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \ +00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \ +80 00 08 06 80 00 06 06 00 00 08 02 80 00 0c 02 \ +80 00 0e 01 80 00 44 04 80 00 46 01 80 00 16 04 \ +80 00 18 04 80 00 34 10 80 00 36 10 00 00 0a 01 \ +80 00 10 01 80 00 12 01 00 01 3a 01 80 00 2a 02 \ +80 00 2c 04 80 00 2e 04 80 00 30 06 80 00 32 06 \ +80 00 1a 02 80 00 1c 02 80 00 1e 02 80 00 20 02 \ +80 00 22 02 80 00 24 02 00 0f 00 a8 80 00 4c 08 \ +00 01 3e 04 00 01 40 04 80 00 04 08 00 00 00 02 \ +80 00 00 04 00 01 42 04 00 01 00 04 00 01 02 04 \ +00 01 04 04 00 01 06 04 00 01 08 04 00 01 0a 04 \ +00 01 0c 04 00 01 0e 04 80 00 08 06 80 00 06 06 \ +00 00 08 02 80 00 0c 02 80 00 0e 01 80 00 44 04 \ +80 00 46 01 80 00 16 04 80 00 18 04 80 00 34 10 \ +80 00 36 10 00 00 0a 01 80 00 10 01 80 00 12 01 \ +00 01 3a 01 80 00 2a 02 80 00 2c 04 80 00 2e 04 \ +80 00 30 06 80 00 32 06 80 00 1a 02 80 00 1c 02 \ +80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \ +"], [0], [OFPST_TABLE_FEATURES reply (OF1.5) (xid=0xd5): + table 0 ("table0"): + metadata: match=0xffffffffffffffff write=0xffffffffffffffff + eviction: not supported + vacancy events: not supported + features: none + max_entries=1000000 + instructions (table miss and others): + next tables: 1-253 + instructions: apply_actions,clear_actions,write_actions,write_metadata,goto_table + Write-Actions and Apply-Actions features: + actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue + supported on Set-Field: tun_id tun_src tun_dst metadata in_port in_port_oxm pkt_mark reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst + matching: + tun_id: exact match or wildcard + tun_src: exact match or wildcard + tun_dst: exact match or wildcard + metadata: exact match or wildcard + in_port: exact match or wildcard + in_port_oxm: exact match or wildcard + pkt_mark: exact match or wildcard + reg0: exact match or wildcard + reg1: exact match or wildcard + reg2: exact match or wildcard + reg3: exact match or wildcard + reg4: exact match or wildcard + reg5: exact match or wildcard + reg6: exact match or wildcard + reg7: exact match or wildcard + eth_src: exact match or wildcard + eth_dst: exact match or wildcard + eth_type: exact match or wildcard + vlan_tci: exact match or wildcard + vlan_vid: exact match or wildcard + vlan_pcp: exact match or wildcard + mpls_label: exact match or wildcard + mpls_tc: exact match or wildcard + mpls_bos: exact match or wildcard + ip_src: exact match or wildcard + ip_dst: exact match or wildcard + ipv6_src: exact match or wildcard + ipv6_dst: exact match or wildcard + ipv6_label: exact match or wildcard + nw_proto: exact match or wildcard + nw_tos: exact match or wildcard + ip_dscp: exact match or wildcard + nw_ecn: exact match or wildcard + nw_ttl: exact match or wildcard + ip_frag: exact match or wildcard + arp_op: exact match or wildcard + arp_spa: exact match or wildcard + arp_tpa: exact match or wildcard + arp_sha: exact match or wildcard + arp_tha: exact match or wildcard + tcp_src: exact match or wildcard + tcp_dst: exact match or wildcard + tcp_flags: exact match or wildcard + udp_src: exact match or wildcard + udp_dst: exact match or wildcard + sctp_src: exact match or wildcard + sctp_dst: exact match or wildcard + icmp_type: exact match or wildcard + icmp_code: exact match or wildcard + icmpv6_type: exact match or wildcard + icmpv6_code: exact match or wildcard + nd_target: exact match or wildcard + nd_sll: exact match or wildcard + nd_tll: exact match or wildcard +]) +AT_CLEANUP + AT_SETUP([OFPT_BARRIER_REQUEST - OF1.0]) AT_KEYWORDS([ofp-print]) AT_CHECK([ovs-ofctl ofp-print '01 12 00 08 00 00 00 01'], [0], [dnl diff --git a/tests/ofproto.at b/tests/ofproto.at index e3f08a8..2d524d9 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -1721,6 +1721,233 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout]) OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto - table features (OpenFlow 1.5)]) +OVS_VSWITCHD_START +head_table () { + printf ' table 0 ("%s"): + metadata: match=0xffffffffffffffff write=0xffffffffffffffff + eviction: not supported + vacancy events: not supported + features: none + max_entries=1000000 + instructions (table miss and others): + next tables: 1-253 + instructions: meter,apply_actions,clear_actions,write_actions,write_metadata,goto_table + Write-Actions and Apply-Actions features: + actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue + supported on Set-Field: tun_id tun_src tun_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metad ata60 tun_metadata61 tun_metadata62 tun_metadata63 metadata in_port in_port_oxm pkt_mark reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst nd_target nd_sll nd_tll + matching: + dp_hash: arbitrary mask + recirc_id: exact match or wildcard + conj_id: exact match or wildcard + tun_id: arbitrary mask + tun_src: arbitrary mask + tun_dst: arbitrary mask + tun_flags: arbitrary mask + tun_gbp_id: arbitrary mask + tun_gbp_flags: arbitrary mask + tun_metadata0: arbitrary mask + tun_metadata1: arbitrary mask + tun_metadata2: arbitrary mask + tun_metadata3: arbitrary mask + tun_metadata4: arbitrary mask + tun_metadata5: arbitrary mask + tun_metadata6: arbitrary mask + tun_metadata7: arbitrary mask + tun_metadata8: arbitrary mask + tun_metadata9: arbitrary mask + tun_metadata10: arbitrary mask + tun_metadata11: arbitrary mask + tun_metadata12: arbitrary mask + tun_metadata13: arbitrary mask + tun_metadata14: arbitrary mask + tun_metadata15: arbitrary mask + tun_metadata16: arbitrary mask + tun_metadata17: arbitrary mask + tun_metadata18: arbitrary mask + tun_metadata19: arbitrary mask + tun_metadata20: arbitrary mask + tun_metadata21: arbitrary mask + tun_metadata22: arbitrary mask + tun_metadata23: arbitrary mask + tun_metadata24: arbitrary mask + tun_metadata25: arbitrary mask + tun_metadata26: arbitrary mask + tun_metadata27: arbitrary mask + tun_metadata28: arbitrary mask + tun_metadata29: arbitrary mask + tun_metadata30: arbitrary mask + tun_metadata31: arbitrary mask + tun_metadata32: arbitrary mask + tun_metadata33: arbitrary mask + tun_metadata34: arbitrary mask + tun_metadata35: arbitrary mask + tun_metadata36: arbitrary mask + tun_metadata37: arbitrary mask + tun_metadata38: arbitrary mask + tun_metadata39: arbitrary mask + tun_metadata40: arbitrary mask + tun_metadata41: arbitrary mask + tun_metadata42: arbitrary mask + tun_metadata43: arbitrary mask + tun_metadata44: arbitrary mask + tun_metadata45: arbitrary mask + tun_metadata46: arbitrary mask + tun_metadata47: arbitrary mask + tun_metadata48: arbitrary mask + tun_metadata49: arbitrary mask + tun_metadata50: arbitrary mask + tun_metadata51: arbitrary mask + tun_metadata52: arbitrary mask + tun_metadata53: arbitrary mask + tun_metadata54: arbitrary mask + tun_metadata55: arbitrary mask + tun_metadata56: arbitrary mask + tun_metadata57: arbitrary mask + tun_metadata58: arbitrary mask + tun_metadata59: arbitrary mask + tun_metadata60: arbitrary mask + tun_metadata61: arbitrary mask + tun_metadata62: arbitrary mask + tun_metadata63: arbitrary mask + metadata: arbitrary mask + in_port: exact match or wildcard + in_port_oxm: exact match or wildcard + actset_output: exact match or wildcard + pkt_mark: arbitrary mask + reg0: arbitrary mask + reg1: arbitrary mask + reg2: arbitrary mask + reg3: arbitrary mask + reg4: arbitrary mask + reg5: arbitrary mask + reg6: arbitrary mask + reg7: arbitrary mask + xreg0: arbitrary mask + xreg1: arbitrary mask + xreg2: arbitrary mask + xreg3: arbitrary mask + eth_src: arbitrary mask + eth_dst: arbitrary mask + eth_type: exact match or wildcard + vlan_tci: arbitrary mask + vlan_vid: arbitrary mask + vlan_pcp: exact match or wildcard + mpls_label: exact match or wildcard + mpls_tc: exact match or wildcard + mpls_bos: exact match or wildcard + ip_src: arbitrary mask + ip_dst: arbitrary mask + ipv6_src: arbitrary mask + ipv6_dst: arbitrary mask + ipv6_label: arbitrary mask + nw_proto: exact match or wildcard + nw_tos: exact match or wildcard + ip_dscp: exact match or wildcard + nw_ecn: exact match or wildcard + nw_ttl: exact match or wildcard + ip_frag: arbitrary mask + arp_op: exact match or wildcard + arp_spa: arbitrary mask + arp_tpa: arbitrary mask + arp_sha: arbitrary mask + arp_tha: arbitrary mask + tcp_src: arbitrary mask + tcp_dst: arbitrary mask + tcp_flags: arbitrary mask + udp_src: arbitrary mask + udp_dst: arbitrary mask + sctp_src: arbitrary mask + sctp_dst: arbitrary mask + icmp_type: exact match or wildcard + icmp_code: exact match or wildcard + icmpv6_type: exact match or wildcard + icmpv6_code: exact match or wildcard + nd_target: arbitrary mask + nd_sll: arbitrary mask + nd_tll: arbitrary mask + +' $1 +} +ditto() { + printf ' table %d ("%s"): + metadata: match=0xffffffffffffffff write=0xffffffffffffffff + eviction: not supported + vacancy events: not supported + features: none + max_entries=%d + instructions (table miss and others): + next tables: %d-253 + (same instructions) + (same actions) + (same matching) + +' $1 $2 $3 `expr $1 + 1` +} +tail_tables() { +echo ' table 252 ("table252"): + metadata: match=0xffffffffffffffff write=0xffffffffffffffff + eviction: not supported + vacancy events: not supported + features: none + max_entries=1000000 + instructions (table miss and others): + next tables: 253 + (same instructions) + (same actions) + (same matching) + + table 253 ("table253"): + metadata: match=0xffffffffffffffff write=0xffffffffffffffff + eviction: not supported + vacancy events: not supported + features: none + max_entries=1000000 + instructions (table miss and others): + instructions: meter,apply_actions,clear_actions,write_actions,write_metadata + (same actions) + (same matching) +' +} +first_egress_table() { +echo ' table 251 ("table251"): + metadata: match=0xffffffffffffffff write=0xffffffffffffffff + eviction: not supported + vacancy events: not supported + features: first egress table + max_entries=1000000 + instructions (table miss and others): + next tables: 252-253 + (same instructions) + Write-Actions features: + actions: set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue + supported on Set-Field: tun_id tun_src tun_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metad ata60 tun_metadata61 tun_metadata62 tun_metadata63 metadata in_port in_port_oxm pkt_mark reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst nd_target nd_sll nd_tll + Apply-Actions features: + actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue + supported on Set-Field: tun_id tun_src tun_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metad ata60 tun_metadata61 tun_metadata62 tun_metadata63 metadata in_port in_port_oxm pkt_mark reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst nd_target nd_sll nd_tll + (same matching) +' +} +(head_table classifier + for i in `seq 1 251`; do + ditto $i table$i 1000000 + done + tail_tables) > expout +AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0], [0], [expout]) +# Set first egress table. +ovs-ofctl -O Openflow15 set-first-egress-table br0 251 + +# Check that the configuration was updated. +(head_table classifier + for i in `seq 1 250`; do + ditto $i table$i 1000000 + done + first_egress_table + tail_tables) > expout +AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0], [0], [expout]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto - table description (OpenFlow 1.4)]) OVS_VSWITCHD_START (x=0 diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 75e84e2..1989137 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -338,6 +338,7 @@ usage(void) " dump-desc SWITCH print switch description\n" " dump-tables SWITCH print table stats\n" " dump-table-features SWITCH print table features\n" + " set-first-egress-table SWITCH TABLE set first egress table\n" " dump-table-desc SWITCH print table description (OF1.4+)\n" " mod-port SWITCH IFACE ACT modify port behavior\n" " mod-table SWITCH MOD modify flow table behavior\n" @@ -728,9 +729,9 @@ ofctl_dump_table_features(struct ovs_cmdl_context *ctx) { struct ofpbuf *request; struct vconn *vconn; - + struct ofputil_table_features *tf = NULL; open_vconn(ctx->argv[1], &vconn); - request = ofputil_encode_table_features_request(vconn_get_version(vconn)); + request = ofputil_encode_table_features_request(tf, vconn_get_version(vconn)); /* The following is similar to dump_trivial_stats_transaction(), but it * maintains the previous 'ofputil_table_features' from one stats reply @@ -803,6 +804,35 @@ ofctl_dump_table_features(struct ovs_cmdl_context *ctx) } static void +ofctl_set_first_egress_table(struct ovs_cmdl_context *ctx) +{ + uint32_t usable_versions; + struct ofputil_table_features tf; + struct vconn *vconn; + char *error; + + error = parse_ofp_table_features(&tf, ctx->argv[2], &usable_versions); + if (error) { + ovs_fatal(0, "%s", error); + } + + uint32_t allowed_versions = get_allowed_ofp_versions(); + if (!(allowed_versions & usable_versions)) { + struct ds versions = DS_EMPTY_INITIALIZER; + ofputil_format_version_bitmap_names(&versions, allowed_versions); + ovs_fatal(0, "set_first_egress_table '%s' requires one of the OpenFlow " + "versions %s but none is enabled (use -O)", + ctx->argv[2], ds_cstr(&versions)); + } + mask_allowed_ofp_versions(usable_versions); + + open_vconn(ctx->argv[1], &vconn); + transact_noreply(vconn, ofputil_encode_table_features_request(&tf, + vconn_get_version(vconn))); + vconn_close(vconn); +} + +static void ofctl_dump_table_desc(struct ovs_cmdl_context *ctx) { struct ofpbuf *request; @@ -3694,6 +3724,8 @@ static const struct ovs_cmdl_command all_commands[] = { 1, 1, ofctl_dump_tables }, { "dump-table-features", "switch", 1, 1, ofctl_dump_table_features }, + { "set-first-egress-table", "switch table", + 2, 2, ofctl_set_first_egress_table }, { "dump-table-desc", "switch", 1, 1, ofctl_dump_table_desc }, { "dump-flows", "switch",