From patchwork Tue Nov 24 12:20:49 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: saloni.jain12@gmail.com X-Patchwork-Id: 548038 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (unknown [IPv6:2600:3c00::f03c:91ff:fe6e:bdf7]) by ozlabs.org (Postfix) with ESMTP id 06F1F140316 for ; Tue, 24 Nov 2015 23:21:48 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=OMTY1qCi; dkim-atps=neutral Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id 1B333108D0; Tue, 24 Nov 2015 04:21:48 -0800 (PST) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v3.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id 2AB0E108C5 for ; Tue, 24 Nov 2015 04:21:46 -0800 (PST) Received: from bar3.cudamail.com (localhost [127.0.0.1]) by mx3v3.cudamail.com (Postfix) with ESMTPS id B5CD31619DC for ; Tue, 24 Nov 2015 05:21:45 -0700 (MST) X-ASG-Debug-ID: 1448367704-03dd7b46472d0280001-byXFYA Received: from mx3-pf1.cudamail.com ([192.168.14.2]) by bar3.cudamail.com with ESMTP id 7I5VJYM2rqd1cMGM (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 24 Nov 2015 05:21:44 -0700 (MST) X-Barracuda-Envelope-From: saloni.jain12@gmail.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.2 Received: from unknown (HELO mail-pa0-f48.google.com) (209.85.220.48) by mx3-pf1.cudamail.com with ESMTPS (RC4-SHA encrypted); 24 Nov 2015 12:21:37 -0000 Received-SPF: pass (mx3-pf1.cudamail.com: SPF record at _netblocks.google.com designates 209.85.220.48 as permitted sender) X-Barracuda-RBL-Trusted-Forwarder: 209.85.220.48 Received: by pabfh17 with SMTP id fh17so21982066pab.0 for ; Tue, 24 Nov 2015 04:21:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=bVp2Qw6KgaLo182C4/sShEvJHG2OuQI3dedkTQrY8xY=; b=OMTY1qCiZmvh4U4wzekafA0ywLi+3grsZYRD9P8QgWG6fPcnISck9a9L95x29cnKgw I07LUgjMDIqogM24XYxN7GOjSTCvVZbdCrHspQ9r2KIlnLaufV/Vm9lVzlZz0jWxHEyk Vz0j4lUeyYgm5r52gl9y22Yxyy91o2mtQ29Mz+7HGmA67Js23eDu+g5b34/l1CO7K18x 96pFtKo/vUCdGI/q4y1KsdfxmPzNk1JgK8RAq6QehGCxd/UU0A6xAyRAMUBBKniHX2J4 cOjWvFrTOWYb4Id1Nhoc8RlzVbRkA+HseNF97PylNUmvdElBGuRtnascP0L/y7tCLAum gMQQ== X-Received: by 10.98.17.131 with SMTP id 3mr22104662pfr.57.1448367696299; Tue, 24 Nov 2015 04:21:36 -0800 (PST) Received: from localhost.localdomain ([14.98.135.109]) by smtp.gmail.com with ESMTPSA id p26sm14152345pfi.94.2015.11.24.04.21.31 (version=TLS1_1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 24 Nov 2015 04:21:35 -0800 (PST) X-CudaMail-Envelope-Sender: saloni.jain12@gmail.com X-Barracuda-Apparent-Source-IP: 14.98.135.109 From: saloni.jain12@gmail.com X-Google-Original-From: saloni.jain@tcs.com To: dev@openvswitch.org X-CudaMail-MID: CM-V1-1123007583 X-CudaMail-DTE: 112415 X-CudaMail-Originating-IP: 209.85.220.48 Date: Tue, 24 Nov 2015 17:50:49 +0530 X-ASG-Orig-Subj: [##CM-V1-1123007583##][PATCH v5 3/3] Implement OFPT_TABLE_STATUS Message. Message-Id: <1448367649-12781-1-git-send-email-saloni.jain@tcs.com> X-Mailer: git-send-email 1.7.9.5 X-GBUdb-Analysis: 0, 209.85.220.48, Ugly c=0.446283 p=-0.421053 Source Normal X-MessageSniffer-Rules: 0-0-0-32588-c X-Barracuda-Connect: UNKNOWN[192.168.14.2] X-Barracuda-Start-Time: 1448367704 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 X-Barracuda-Spam-Score: 1.10 X-Barracuda-Spam-Status: No, SCORE=1.10 using per-user scores of TAG_LEVEL=3.5 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=4.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.24678 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, Rishi Bamba Subject: [ovs-dev] [PATCH v5 3/3] Implement OFPT_TABLE_STATUS Message. 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: Saloni Jain On change in a table state, the controller needs to be informed with the OFPT_TABLE_STATUS message. The message is sent with reason OFPTR_VACANCY_DOWN or OFPTR_VACANCY_UP in case of change in remaining space eventually crossing any one of the threshold. Signed-off-by: Saloni Jain Co-authored-by: Rishi Bamba Signed-off-by: Rishi Bamba --- Difference between v4 and v5: - Rebased with latest master include/openflow/openflow-1.4.h | 8 ++++ lib/learning-switch.c | 1 + lib/ofp-msgs.h | 6 +++ lib/ofp-print.c | 26 +++++++++++++ lib/ofp-util.c | 82 +++++++++++++++++++++++++++++++++++++++ lib/ofp-util.h | 12 ++++++ lib/rconn.c | 1 + ofproto/connmgr.c | 31 +++++++++++++++ ofproto/connmgr.h | 3 ++ ofproto/ofproto.c | 31 +++++++++++++++ tests/ofproto.at | 20 ++++++++-- 11 files changed, 218 insertions(+), 3 deletions(-) diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h index 9465b8e..01ab5fa 100644 --- a/include/openflow/openflow-1.4.h +++ b/include/openflow/openflow-1.4.h @@ -172,6 +172,14 @@ struct ofp14_table_desc { }; OFP_ASSERT(sizeof(struct ofp14_table_desc) == 8); +/* A table config has changed in the datapath */ +struct ofp14_table_status { + uint8_t reason; /* One of OFPTR_*. */ + uint8_t pad[7]; /* Pad to 64 bits */ + /* Followed by struct ofp14_table_desc */ +}; +OFP_ASSERT(sizeof(struct ofp14_table_status) == 8); + /* ## ---------------- ## */ /* ## ofp14_port_stats ## */ /* ## ---------------- ## */ diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 7ddf69b..6f92c42 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -420,6 +420,7 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg) case OFPTYPE_ROLE_REPLY: case OFPTYPE_ROLE_STATUS: case OFPTYPE_REQUESTFORWARD: + case OFPTYPE_TABLE_STATUS: case OFPTYPE_SET_FLOW_FORMAT: case OFPTYPE_FLOW_MOD_TABLE_ID: case OFPTYPE_SET_PACKET_IN_FORMAT: diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h index bce5283..81d086e 100644 --- a/lib/ofp-msgs.h +++ b/lib/ofp-msgs.h @@ -250,6 +250,9 @@ enum ofpraw { /* OFPT 1.4+ (32): struct ofp14_requestforward, uint8_t[8][]. */ OFPRAW_OFPT14_REQUESTFORWARD, + /* OFPT 1.4+ (31): struct ofp14_table_status, uint8_t[8][]. */ + OFPRAW_OFPT14_TABLE_STATUS, + /* OFPT 1.4+ (33): struct ofp14_bundle_ctrl_msg, uint8_t[8][]. */ OFPRAW_OFPT14_BUNDLE_CONTROL, @@ -565,6 +568,9 @@ enum ofptype { /* Request forwarding by the switch. */ OFPTYPE_REQUESTFORWARD, /* OFPRAW_OFPT14_REQUESTFORWARD. */ + /* Asynchronous messages. */ + OFPTYPE_TABLE_STATUS, /* OFPRAW_OFPT14_TABLE_STATUS. */ + OFPTYPE_BUNDLE_CONTROL, /* OFPRAW_OFPT14_BUNDLE_CONTROL. */ OFPTYPE_BUNDLE_ADD_MESSAGE, /* OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE. */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index e7b05fc..fdcbb0c 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1067,6 +1067,28 @@ ofp_print_table_desc(struct ds *string, const struct ofputil_table_desc *td) } static void +ofp_print_table_status_message(struct ds *string, const struct ofp_header *oh) +{ + struct ofputil_table_status ts; + enum ofperr error; + + error = ofputil_decode_table_status(oh, &ts); + if (error) { + ofp_print_error(string, error); + return; + } + + if (ts.reason == OFPTR_VACANCY_DOWN) { + ds_put_format(string, " reason=VACANCY_DOWN"); + } else if (ts.reason == OFPTR_VACANCY_UP) { + ds_put_format(string, " reason=VACANCY_UP"); + } + + ds_put_format(string, "\ntable_desc:-"); + ofp_print_table_desc(string, &ts.desc); +} + +static void ofp_print_queue_get_config_request(struct ds *string, const struct ofp_header *oh) { @@ -3255,6 +3277,10 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, ofp_print_requestforward(string, oh); break; + case OFPTYPE_TABLE_STATUS: + ofp_print_table_status_message(string, oh); + break; + case OFPTYPE_METER_STATS_REQUEST: case OFPTYPE_METER_CONFIG_STATS_REQUEST: ofp_print_stats(string, oh); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 819f0fd..65ac633 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -9285,6 +9285,7 @@ ofputil_is_bundlable(enum ofptype type) case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_ROLE_STATUS: case OFPTYPE_REQUESTFORWARD: + case OFPTYPE_TABLE_STATUS: case OFPTYPE_NXT_GENEVE_TABLE_REQUEST: case OFPTYPE_NXT_GENEVE_TABLE_REPLY: break; @@ -9713,3 +9714,84 @@ ofputil_encode_get_async_config(const struct ofp_header *oh, return buf; } + +static void +ofputil_put_ofp14_table_desc(const struct ofputil_table_desc *td, + struct ofpbuf *b, enum ofp_version version) +{ + struct ofp14_table_desc *otd; + struct ofp14_table_mod_prop_eviction *ote; + struct ofp14_table_mod_prop_vacancy *otv; + + ofpbuf_prealloc_tailroom(b, sizeof *otd + sizeof *ote + sizeof *otv); + + otd = ofpbuf_put_zeros(b, sizeof *otd); + otd->length = htons(sizeof *otd + sizeof *ote + sizeof *otv); + otd->table_id = td->table_id; + otd->config = ofputil_encode_table_config(OFPUTIL_TABLE_MISS_DEFAULT, + td->eviction, td->vacancy, + version); + + ote = ofpbuf_put_zeros(b, sizeof *ote); + ote->type = htons(OFPTMPT14_EVICTION); + ote->length = htons(sizeof *ote); + ote->flags = htonl(td->eviction_flags); + + otv = ofpbuf_put_zeros(b, sizeof *otv); + otv->type = htons(OFPTMPT14_VACANCY); + otv->length = htons(sizeof *otv); + otv->vacancy_down = td->table_vacancy.vacancy_down; + otv->vacancy_up = td->table_vacancy.vacancy_up; + otv->vacancy = td->table_vacancy.vacancy; +} + +/* Converts the abstract form of a "table status" message in '*ts' into an + * OpenFlow message suitable for 'protocol', and returns that encoded form in + * a buffer owned by the caller. */ +struct ofpbuf * +ofputil_encode_table_status(const struct ofputil_table_status *ts, + enum ofputil_protocol protocol) +{ + enum ofp_version version; + struct ofpbuf *b; + + version = ofputil_protocol_to_ofp_version(protocol); + if (version >= OFP14_VERSION) { + enum ofpraw raw; + struct ofp14_table_status *ots; + + raw = OFPRAW_OFPT14_TABLE_STATUS; + b = ofpraw_alloc_xid(raw, version, htonl(0), 0); + ots = ofpbuf_put_zeros(b, sizeof *ots); + ots->reason = ts->reason; + ofputil_put_ofp14_table_desc(&ts->desc, b, version); + ofpmsg_update_length(b); + + return b; + } else { + return NULL; + } +} + +/* Decodes the OpenFlow "table status" message in '*ots' into an abstract form + * in '*ts'. Returns 0 if successful, otherwise an OFPERR_* value. */ +enum ofperr +ofputil_decode_table_status(const struct ofp_header *oh, + struct ofputil_table_status *ts) +{ + const struct ofp14_table_status *ots; + struct ofpbuf b; + enum ofperr error; + + ofpbuf_use_const(&b, oh, ntohs(oh->length)); + ofpraw_pull_assert(&b); + ots = ofpbuf_pull(&b, sizeof *ots); + + if (ots->reason != OFPTR_VACANCY_DOWN && ots->reason != OFPTR_VACANCY_UP) { + return OFPERR_OFPBPC_BAD_VALUE; + } + ts->reason = ots->reason; + + error = ofputil_decode_table_desc(&b, &ts->desc, oh->version); + return error; +} diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 1b63b89..29d4150 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -1299,4 +1299,16 @@ enum ofperr ofputil_decode_requestforward(const struct ofp_header *, struct ofputil_requestforward *); void ofputil_destroy_requestforward(struct ofputil_requestforward *); +/* Abstract ofp14_table_status. */ +struct ofputil_table_status { + enum ofp14_table_reason reason; /* One of OFPTR_*. */ + struct ofputil_table_desc desc; /* New table config. */ +}; + +enum ofperr ofputil_decode_table_status(const struct ofp_header *oh, + struct ofputil_table_status *ts); + +struct ofpbuf * +ofputil_encode_table_status(const struct ofputil_table_status *ts, + enum ofputil_protocol protocol); #endif /* ofp-util.h */ diff --git a/lib/rconn.c b/lib/rconn.c index 0a9966a..53240fd 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -1404,6 +1404,7 @@ is_admitted_msg(const struct ofpbuf *b) case OFPTYPE_ROLE_REPLY: case OFPTYPE_ROLE_STATUS: case OFPTYPE_REQUESTFORWARD: + case OFPTYPE_TABLE_STATUS: case OFPTYPE_SET_FLOW_FORMAT: case OFPTYPE_FLOW_MOD_TABLE_ID: case OFPTYPE_SET_PACKET_IN_FORMAT: diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index ef2c06f..76dfaa9 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -1754,6 +1754,37 @@ connmgr_send_flow_removed(struct connmgr *mgr, } } +/* Sends an OFPT_TABLE_STATUS message with 'reason' to appropriate controllers + * managed by 'mgr'. When the table state changes, the controller needs to be + * informed with the OFPT_TABLE_STATUS message. The reason values + * OFPTR_VACANCY_DOWN and OFPTR_VACANCY_UP identify a vacancy message. The + * vacancy events are generated when the remaining space in the flow table + * changes and crosses one of the vacancy thereshold specified by + * OFPT_TABLE_MOD. */ +void +connmgr_send_table_status(struct connmgr *mgr, + const struct ofputil_table_desc *td, + uint8_t reason) +{ + struct ofputil_table_status ts; + struct ofconn *ofconn; + + ts.reason = reason; + ts.desc = *td; + + LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { + if (ofconn_receives_async_msg(ofconn, OAM_TABLE_STATUS, reason)) { + struct ofpbuf *msg; + + msg = ofputil_encode_table_status(&ts, + ofconn_get_protocol(ofconn)); + if (msg) { + ofconn_send(ofconn, msg, NULL); + } + } + } +} + /* Normally a send-to-controller action uses reason OFPR_ACTION. However, in * OpenFlow 1.3 and later, packet_ins generated by a send-to-controller action * in a "table-miss" flow (one with priority 0 and completely wildcarded) are diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h index 8048424..8b68f06 100644 --- a/ofproto/connmgr.h +++ b/ofproto/connmgr.h @@ -234,4 +234,7 @@ void ofmonitor_compose_refresh_updates(struct rule_collection *rules, struct ovs_list *msgs) OVS_REQUIRES(ofproto_mutex); +void connmgr_send_table_status(struct connmgr *, + const struct ofputil_table_desc *td, + uint8_t reason); #endif /* connmgr.h */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 86e6bf1..469f256 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -3645,6 +3645,24 @@ handle_table_desc_request(struct ofconn *ofconn, return 0; } +/* This function determines and sends the vacancy event, based on the value + * of current vacancy and threshold vacancy. If the current vacancy is less + * than vacancy_up, vacancy up events must be enabled, and when the current + * vacancy is greater or equal to vacancy_up, vacancy down events must be + * enabled. */ +static void +send_table_status(struct ofproto *ofproto, uint8_t table_id) +{ + struct ofputil_table_desc td; + + query_table_desc__(&td, ofproto, table_id); + if (td.table_vacancy.vacancy < td.table_vacancy.vacancy_up) { + connmgr_send_table_status(ofproto->connmgr, &td, OFPTR_VACANCY_UP); + } else { + connmgr_send_table_status(ofproto->connmgr, &td, OFPTR_VACANCY_DOWN); + } +} + static void append_port_stat(struct ofport *port, struct ovs_list *replies) { @@ -4681,6 +4699,12 @@ add_flow_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, req ? req->ofconn : NULL, req ? req->request->xid : 0, NULL); + /* Send Vacancy Events for OF1.4+ when there is change in flow table. + * Provided OFPTC14_VACANCY_EVENTS is set for the table. */ + if (ofproto->tables[fm->table_id].vacancy_enabled) { + send_table_status(ofproto, fm->table_id); + } + } send_buffered_packet(req, fm->buffer_id, new_rule); @@ -5077,6 +5101,12 @@ delete_flows_finish__(struct ofproto *ofproto, req ? req->ofconn : NULL, req ? req->request->xid : 0, NULL); + /* Send Vacancy Events for OF1.4+ when there is change in flow table. + * Provided OFPTC14_VACANCY_EVENTS is set for the table. */ + if (ofproto->tables[rule->table_id].vacancy_enabled) { + send_table_status(ofproto, rule->table_id); + } + ofproto_rule_remove__(ofproto, rule); learned_cookies_dec(ofproto, rule_get_actions(rule), &dead_cookies); @@ -7274,6 +7304,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_ROLE_STATUS: case OFPTYPE_REQUESTFORWARD: + case OFPTYPE_TABLE_STATUS: case OFPTYPE_NXT_GENEVE_TABLE_REPLY: default: if (ofpmsg_is_stat_request(oh)) { diff --git a/tests/ofproto.at b/tests/ofproto.at index e773ab3..e806c05 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -2663,7 +2663,7 @@ OFPT_PORT_STATUS (OF1.4): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x echo >>expout "OFPT_FLOW_REMOVED (OF1.4): reason=delete table_id=0" fi - # OFPT_FLOW_REMOVED, OFPRR_GROUP_DELETE + # OFPT_FLOW_REMOVED, OFPRR_GROUP_DELETE ovs-ofctl -O OpenFlow14 add-group br0 group_id=1234,type=all,bucket=output:10 ovs-ofctl -O OpenFlow14 add-flow br0 send_flow_rem,actions=group:1234 ovs-ofctl -O OpenFlow14 --strict del-groups br0 group_id=1234 @@ -2671,6 +2671,20 @@ OFPT_PORT_STATUS (OF1.4): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x echo >>expout "OFPT_FLOW_REMOVED (OF1.4): reason=group_delete table_id=0" fi + # OFPT_TABLE_STATUS, OFPTR_VACANCY_UP + if test X"$1" = X"OFPTR_VACANCY_UP"; then shift; + ovs-vsctl -- --id=@t1 create Flow_Table flow-limit=10 -- set bridge br0 flow_tables:1=@t1 + ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=1,actions=2 + ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=2,actions=2 + ovs-ofctl -O OpenFlow14 mod-table br0 1 vacancy:20,80 + ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=3,actions=2 + echo >>expout "OFPT_TABLE_STATUS (OF1.4): reason=VACANCY_UP +table_desc:- + table 1: + eviction=off eviction_flags=OTHER|IMPORTANCE|LIFETIME + vacancy=on vacancy_down=20% vacancy_up=80% vacancy=30%" + fi + AT_FAIL_IF([test X"$1" != X]) ovs-appctl -t ovs-ofctl ofctl/barrier @@ -2696,8 +2710,8 @@ ovs-appctl -t ovs-ofctl ofctl/send 051800180000000200000003000000000000000000000 check_async 3 OFPPR_ADD OFPPR_MODIFY OFPPR_DELETE # Use OF 1.4 OFPT_SET_ASYNC to enable a patchwork of asynchronous messages. -ovs-appctl -t ovs-ofctl ofctl/send 051c0038000000020000000800000005000100080000000200020008000000020003000800000005000400080000001c0005000800000005 -check_async 4 OFPR_INVALID_TTL OFPPR_DELETE OFPRR_DELETE OFPRR_GROUP_DELETE +ovs-appctl -t ovs-ofctl ofctl/send 051c0040000000020000000800000005000100080000000200020008000000020003000800000005000400080000001c00050008000000050008000800000010 +check_async 4 OFPR_INVALID_TTL OFPPR_DELETE OFPRR_DELETE OFPRR_GROUP_DELETE OFPTR_VACANCY_UP # Set controller ID 123. ovs-appctl -t ovs-ofctl ofctl/send 05040018000000030000232000000014000000000000007b