diff options
-rw-r--r-- | include/openflow/openflow-1.4.h | 6 | ||||
-rw-r--r-- | lib/learning-switch.c | 1 | ||||
-rw-r--r-- | lib/ofp-msgs.h | 6 | ||||
-rw-r--r-- | lib/ofp-print.c | 108 | ||||
-rw-r--r-- | lib/ofp-util.c | 120 | ||||
-rw-r--r-- | lib/ofp-util.h | 21 | ||||
-rw-r--r-- | lib/rconn.c | 1 | ||||
-rw-r--r-- | ofproto/connmgr.c | 22 | ||||
-rw-r--r-- | ofproto/connmgr.h | 3 | ||||
-rw-r--r-- | ofproto/ofproto.c | 33 | ||||
-rw-r--r-- | tests/ofp-print.at | 46 | ||||
-rw-r--r-- | tests/ofproto.at | 91 |
12 files changed, 422 insertions, 36 deletions
diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h index 1ed4e392a..9465b8eb8 100644 --- a/include/openflow/openflow-1.4.h +++ b/include/openflow/openflow-1.4.h @@ -355,6 +355,12 @@ struct ofp14_role_prop_experimenter { }; OFP_ASSERT(sizeof(struct ofp14_role_prop_experimenter) == 12); +/* Group/Meter request forwarding. */ +struct ofp14_requestforward { + struct ofp_header request; /* Request being forwarded. */ +}; +OFP_ASSERT(sizeof(struct ofp14_requestforward) == 8); + /* Bundle control message types */ enum ofp14_bundle_ctrl_type { OFPBCT_OPEN_REQUEST = 0, diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 1753ceac0..7ddf69b9d 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -419,6 +419,7 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg) case OFPTYPE_ROLE_REQUEST: case OFPTYPE_ROLE_REPLY: case OFPTYPE_ROLE_STATUS: + case OFPTYPE_REQUESTFORWARD: 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 8558e580c..132e405be 100644 --- a/lib/ofp-msgs.h +++ b/lib/ofp-msgs.h @@ -247,6 +247,9 @@ enum ofpraw { /* OFPT 1.4+ (30): struct ofp14_role_status, uint8_t[8][]. */ OFPRAW_OFPT14_ROLE_STATUS, + /* OFPT 1.4+ (32): struct ofp14_requestforward, uint8_t[8][]. */ + OFPRAW_OFPT14_REQUESTFORWARD, + /* OFPT 1.4+ (33): struct ofp14_bundle_ctrl_msg, uint8_t[8][]. */ OFPRAW_OFPT14_BUNDLE_CONTROL, @@ -559,6 +562,9 @@ enum ofptype { /* Controller role change event messages. */ OFPTYPE_ROLE_STATUS, /* OFPRAW_OFPT14_ROLE_STATUS. */ + /* Request forwarding by the switch. */ + OFPTYPE_REQUESTFORWARD, /* OFPRAW_OFPT14_REQUESTFORWARD. */ + 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 6e32d4d3a..d0c94cec3 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1185,21 +1185,9 @@ ofp_print_meter_config(struct ds *s, const struct ofputil_meter_config *mc) } static void -ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh) +ofp_print_meter_mod__(struct ds *s, const struct ofputil_meter_mod *mm) { - struct ofputil_meter_mod mm; - struct ofpbuf bands; - enum ofperr error; - - ofpbuf_init(&bands, 64); - error = ofputil_decode_meter_mod(oh, &mm, &bands); - if (error) { - ofpbuf_uninit(&bands); - ofp_print_error(s, error); - return; - } - - switch (mm.command) { + switch (mm->command) { case OFPMC13_ADD: ds_put_cstr(s, " ADD "); break; @@ -1210,10 +1198,26 @@ ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh) ds_put_cstr(s, " DEL "); break; default: - ds_put_format(s, " cmd:%d ", mm.command); + ds_put_format(s, " cmd:%d ", mm->command); } - ofp_print_meter_config(s, &mm.meter); + ofp_print_meter_config(s, &mm->meter); +} + +static void +ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh) +{ + struct ofputil_meter_mod mm; + struct ofpbuf bands; + enum ofperr error; + + ofpbuf_init(&bands, 64); + error = ofputil_decode_meter_mod(oh, &mm, &bands); + if (error) { + ofp_print_error(s, error); + } else { + ofp_print_meter_mod__(s, &mm); + } ofpbuf_uninit(&bands); } @@ -2333,7 +2337,8 @@ ofp_print_bucket_id(struct ds *s, const char *label, uint32_t bucket_id, static void ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, - struct ovs_list *p_buckets, struct ofputil_group_props *props, + const struct ovs_list *p_buckets, + const struct ofputil_group_props *props, enum ofp_version ofp_version, bool suppress_type) { struct ofputil_bucket *bucket; @@ -2529,22 +2534,15 @@ ofp_print_group_features(struct ds *string, const struct ofp_header *oh) } static void -ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) +ofp_print_group_mod__(struct ds *s, enum ofp_version ofp_version, + const struct ofputil_group_mod *gm) { - struct ofputil_group_mod gm; - int error; bool bucket_command = false; - error = ofputil_decode_group_mod(oh, &gm); - if (error) { - ofp_print_error(s, error); - return; - } - ds_put_char(s, '\n'); ds_put_char(s, ' '); - switch (gm.command) { + switch (gm->command) { case OFPGC11_ADD: ds_put_cstr(s, "ADD"); break; @@ -2568,17 +2566,31 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) break; default: - ds_put_format(s, "cmd:%"PRIu16"", gm.command); + ds_put_format(s, "cmd:%"PRIu16"", gm->command); } ds_put_char(s, ' '); if (bucket_command) { ofp_print_bucket_id(s, "command_bucket_id:", - gm.command_bucket_id, oh->version); + gm->command_bucket_id, ofp_version); } - ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, &gm.props, - oh->version, bucket_command); + ofp_print_group(s, gm->group_id, gm->type, &gm->buckets, &gm->props, + ofp_version, bucket_command); +} + +static void +ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) +{ + struct ofputil_group_mod gm; + int error; + + error = ofputil_decode_group_mod(oh, &gm); + if (error) { + ofp_print_error(s, error); + return; + } + ofp_print_group_mod__(s, oh->version, &gm); ofputil_bucket_list_destroy(&gm.buckets); } @@ -3050,6 +3062,36 @@ ofp_print_geneve_table_reply(struct ds *s, const struct ofp_header *oh) ofputil_uninit_geneve_table(>r.mappings); } +/* This function will print the request forward message. The reason for + * request forward is taken from rf.request.type */ +static void +ofp_print_requestforward(struct ds *string, const struct ofp_header *oh) +{ + struct ofputil_requestforward rf; + enum ofperr error; + + error = ofputil_decode_requestforward(oh, &rf); + if (error) { + ofp_print_error(string, error); + return; + } + + ds_put_cstr(string, " reason="); + + switch (rf.reason) { + case OFPRFR_GROUP_MOD: + ds_put_cstr(string, "group_mod"); + ofp_print_group_mod__(string, oh->version, rf.group_mod); + break; + + case OFPRFR_METER_MOD: + ds_put_cstr(string, "meter_mod"); + ofp_print_meter_mod__(string, rf.meter_mod); + break; + } + ofputil_destroy_requestforward(&rf); +} + static void ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, struct ds *string, int verbosity) @@ -3179,6 +3221,10 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, ofp_print_role_status_message(string, oh); break; + case OFPTYPE_REQUESTFORWARD: + ofp_print_requestforward(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 5331f8ce4..d90cca894 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -5376,6 +5376,125 @@ ofputil_decode_role_status(const struct ofp_header *oh, return 0; } +/* Encodes 'rf' according to 'protocol', and returns the encoded message. + * 'protocol' must be for OpenFlow 1.4 or later. */ +struct ofpbuf * +ofputil_encode_requestforward(const struct ofputil_requestforward *rf, + enum ofputil_protocol protocol) +{ + enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol); + struct ofpbuf *inner; + + switch (rf->reason) { + case OFPRFR_GROUP_MOD: + inner = ofputil_encode_group_mod(ofp_version, rf->group_mod); + break; + + case OFPRFR_METER_MOD: + inner = ofputil_encode_meter_mod(ofp_version, rf->meter_mod); + break; + + default: + OVS_NOT_REACHED(); + } + + struct ofp_header *inner_oh = inner->data; + inner_oh->xid = rf->xid; + inner_oh->length = htons(inner->size); + + struct ofpbuf *outer = ofpraw_alloc_xid(OFPRAW_OFPT14_REQUESTFORWARD, + ofp_version, htonl(0), + inner->size); + ofpbuf_put(outer, inner->data, inner->size); + ofpbuf_delete(inner); + + return outer; +} + +/* Decodes OFPT_REQUESTFORWARD message 'outer'. On success, puts the decoded + * form into '*rf' and returns 0, and the caller is later responsible for + * freeing the content of 'rf', with ofputil_destroy_requestforward(rf). On + * failure, returns an ofperr and '*rf' is indeterminate. */ +enum ofperr +ofputil_decode_requestforward(const struct ofp_header *outer, + struct ofputil_requestforward *rf) +{ + struct ofpbuf b; + enum ofperr error; + + ofpbuf_use_const(&b, outer, ntohs(outer->length)); + + /* Skip past outer message. */ + enum ofpraw outer_raw = ofpraw_pull_assert(&b); + ovs_assert(outer_raw == OFPRAW_OFPT14_REQUESTFORWARD); + + /* Validate inner message. */ + if (b.size < sizeof(struct ofp_header)) { + return OFPERR_OFPBFC_MSG_BAD_LEN; + } + const struct ofp_header *inner = b.data; + unsigned int inner_len = ntohs(inner->length); + if (inner_len < sizeof(struct ofp_header) || inner_len > b.size) { + return OFPERR_OFPBFC_MSG_BAD_LEN; + } + if (inner->version != outer->version) { + return OFPERR_OFPBRC_BAD_VERSION; + } + + /* Parse inner message. */ + enum ofptype type; + error = ofptype_decode(&type, inner); + if (error) { + return error; + } + + rf->xid = inner->xid; + if (type == OFPTYPE_GROUP_MOD) { + rf->reason = OFPRFR_GROUP_MOD; + rf->group_mod = xmalloc(sizeof *rf->group_mod); + error = ofputil_decode_group_mod(inner, rf->group_mod); + if (error) { + free(rf->group_mod); + return error; + } + } else if (type == OFPTYPE_METER_MOD) { + rf->reason = OFPRFR_METER_MOD; + rf->meter_mod = xmalloc(sizeof *rf->meter_mod); + ofpbuf_init(&rf->bands, 64); + error = ofputil_decode_meter_mod(inner, rf->meter_mod, &rf->bands); + if (error) { + free(rf->meter_mod); + ofpbuf_uninit(&rf->bands); + return error; + } + } else { + return OFPERR_OFPBFC_MSG_UNSUP; + } + + return 0; +} + +/* Frees the content of 'rf', which should have been initialized through a + * successful call to ofputil_decode_requestforward(). */ +void +ofputil_destroy_requestforward(struct ofputil_requestforward *rf) +{ + if (!rf) { + return; + } + + switch (rf->reason) { + case OFPRFR_GROUP_MOD: + ofputil_uninit_group_mod(rf->group_mod); + free(rf->group_mod); + break; + + case OFPRFR_METER_MOD: + ofpbuf_uninit(&rf->bands); + free(rf->meter_mod); + } +} + /* Table stats. */ /* OpenFlow 1.0 and 1.1 don't distinguish between a field that cannot be @@ -9057,6 +9176,7 @@ ofputil_is_bundlable(enum ofptype type) case OFPTYPE_TABLE_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_ROLE_STATUS: + case OFPTYPE_REQUESTFORWARD: case OFPTYPE_NXT_GENEVE_TABLE_REQUEST: case OFPTYPE_NXT_GENEVE_TABLE_REPLY: break; diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 527a5ab23..cbd617514 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -1239,4 +1239,25 @@ struct ofpbuf *ofputil_encode_get_async_config(const struct ofp_header *, uint32_t master[OAM_N_TYPES], uint32_t slave[OAM_N_TYPES]); +struct ofputil_requestforward { + ovs_be32 xid; + enum ofp14_requestforward_reason reason; + union { + /* reason == OFPRFR_METER_MOD. */ + struct ofputil_meter_mod *meter_mod; + + /* reason == OFPRFR_GROUP_MOD. */ + struct { + struct ofputil_group_mod *group_mod; + struct ofpbuf bands; + }; + }; +}; + +struct ofpbuf *ofputil_encode_requestforward( + const struct ofputil_requestforward *, enum ofputil_protocol); +enum ofperr ofputil_decode_requestforward(const struct ofp_header *, + struct ofputil_requestforward *); +void ofputil_destroy_requestforward(struct ofputil_requestforward *); + #endif /* ofp-util.h */ diff --git a/lib/rconn.c b/lib/rconn.c index 37adfa2d5..0a9966aab 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -1403,6 +1403,7 @@ is_admitted_msg(const struct ofpbuf *b) case OFPTYPE_ROLE_REQUEST: case OFPTYPE_ROLE_REPLY: case OFPTYPE_ROLE_STATUS: + case OFPTYPE_REQUESTFORWARD: 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 b1ba0c697..ef2c06fc4 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -1709,6 +1709,28 @@ connmgr_send_port_status(struct connmgr *mgr, struct ofconn *source, } } +/* Sends an OFPT_REQUESTFORWARD message with 'request' and 'reason' to + * appropriate controllers managed by 'mgr'. For messages caused by a + * controller OFPT_GROUP_MOD and OFPT_METER_MOD, specify 'source' as the + * controller connection that sent the request; otherwise, specify 'source' + * as NULL. */ +void +connmgr_send_requestforward(struct connmgr *mgr, const struct ofconn *source, + const struct ofputil_requestforward *rf) +{ + struct ofconn *ofconn; + + LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { + if (ofconn_receives_async_msg(ofconn, OAM_REQUESTFORWARD, rf->reason) + && rconn_get_version(ofconn->rconn) >= OFP14_VERSION + && ofconn != source) { + enum ofputil_protocol protocol = ofconn_get_protocol(ofconn); + ofconn_send(ofconn, ofputil_encode_requestforward(rf, protocol), + NULL); + } + } +} + /* Sends an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message based on 'fr' to * appropriate controllers managed by 'mgr'. */ void diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h index 7ef583ad8..8048424b7 100644 --- a/ofproto/connmgr.h +++ b/ofproto/connmgr.h @@ -168,6 +168,9 @@ void connmgr_send_packet_in(struct connmgr *, void ofconn_send_role_status(struct ofconn *ofconn, uint32_t role, uint8_t reason); +void connmgr_send_requestforward(struct connmgr *, const struct ofconn *source, + const struct ofputil_requestforward *); + /* Fail-open settings. */ enum ofproto_fail_mode connmgr_get_fail_mode(const struct connmgr *); void connmgr_set_fail_mode(struct connmgr *, enum ofproto_fail_mode); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index e6c03516e..c1301b5c1 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -5908,6 +5908,14 @@ handle_meter_mod(struct ofconn *ofconn, const struct ofp_header *oh) break; } + if (!error) { + struct ofputil_requestforward rf; + rf.xid = oh->xid; + rf.reason = OFPRFR_METER_MOD; + rf.meter_mod = &mm; + connmgr_send_requestforward(ofproto->connmgr, ofconn, &rf); + } + exit_free_bands: ofpbuf_uninit(&bands); return error; @@ -6575,20 +6583,25 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh) switch (gm.command) { case OFPGC11_ADD: - return add_group(ofproto, &gm); + error = add_group(ofproto, &gm); + break; case OFPGC11_MODIFY: - return modify_group(ofproto, &gm); + error = modify_group(ofproto, &gm); + break; case OFPGC11_DELETE: delete_group(ofproto, gm.group_id); - return 0; + error = 0; + break; case OFPGC15_INSERT_BUCKET: - return modify_group(ofproto, &gm); + error = modify_group(ofproto, &gm); + break; case OFPGC15_REMOVE_BUCKET: - return modify_group(ofproto, &gm); + error = modify_group(ofproto, &gm); + break; default: if (gm.command > OFPGC11_DELETE) { @@ -6597,6 +6610,15 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh) } return OFPERR_OFPGMFC_BAD_COMMAND; } + + if (!error) { + struct ofputil_requestforward rf; + rf.xid = oh->xid; + rf.reason = OFPRFR_GROUP_MOD; + rf.group_mod = &gm; + connmgr_send_requestforward(ofproto->connmgr, ofconn, &rf); + } + return error; } enum ofputil_table_miss @@ -7211,6 +7233,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_TABLE_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_ROLE_STATUS: + case OFPTYPE_REQUESTFORWARD: case OFPTYPE_NXT_GENEVE_TABLE_REPLY: default: if (ofpmsg_is_stat_request(oh)) { diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 35a626246..8cdceade0 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -2675,6 +2675,52 @@ OFPT_ROLE_STATUS (OF1.4) (xid=0xa): role=master generation_id=16 reason=configur ]) AT_CLEANUP +AT_SETUP([OFP_REQUESTFORWARD - OF1.4]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 20 00 18 00 00 00 02 \ +05 0f 00 10 02 00 00 00 \ +00 00 00 00 00 00 00 01 \ +"], [0], [dnl +OFPT_REQUESTFORWARD (OF1.4) (xid=0x2): reason=group_mod + ADD group_id=1,type=all +]) +AT_CLEANUP + +AT_SETUP([OFP_REQUESTFORWARD - OF1.4]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 20 00 18 00 00 00 02 \ +05 0f 00 10 02 00 00 00 \ +00 01 01 00 00 00 00 01 \ +"], [0], [dnl +OFPT_REQUESTFORWARD (OF1.4) (xid=0x2): reason=group_mod + MOD group_id=1,type=select +]) +AT_CLEANUP + +AT_SETUP([OFP_REQUESTFORWARD - OF1.4]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 20 00 18 00 00 00 02 \ +05 1d 00 10 02 00 00 00 \ +00 00 00 00 00 00 00 01 \ +"], [0], [dnl +OFPT_REQUESTFORWARD (OF1.4) (xid=0x2): reason=meter_mod ADD meter=1 bands= +]) +AT_CLEANUP + +AT_SETUP([OFP_REQUESTFORWARD - OF1.4]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 20 00 18 00 00 00 02 \ +05 1d 00 10 02 00 00 00 \ +00 01 01 00 00 00 00 01 \ +"], [0], [dnl +OFPT_REQUESTFORWARD (OF1.4) (xid=0x2): reason=meter_mod MOD meter=1 flags:0x100 bands= +]) +AT_CLEANUP + AT_SETUP([NXT_SET_PACKET_IN]) AT_KEYWORDS([ofp-print]) AT_CHECK([ovs-ofctl ofp-print "\ diff --git a/tests/ofproto.at b/tests/ofproto.at index 507fe91d1..7e80293cf 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -2899,6 +2899,97 @@ done OVS_VSWITCHD_STOP AT_CLEANUP +dnl This test checks the Group and meter notifications when a group mod +dnl command is sent from one controller and the reply is received by +dnl other controllers. +AT_SETUP([ofproto - requestforward (OpenFlow 1.4)]) +OVS_VSWITCHD_START +on_exit 'kill `cat c1.pid c2.pid c3.pid`' + +# Start two ovs-ofctl controller processes. +AT_CAPTURE_FILE([monitor1.log]) +AT_CAPTURE_FILE([expout1]) +AT_CAPTURE_FILE([monitor2.log]) +AT_CAPTURE_FILE([expout2]) +AT_CAPTURE_FILE([monitor3.log]) +AT_CAPTURE_FILE([expout3]) + +ovs-ofctl -O OpenFlow15 monitor br0 --detach --no-chdir --pidfile=`pwd`/c1.pid --unixctl=`pwd`/c1 +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile=`pwd`/c2.pid --unixctl=`pwd`/c2 +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile=`pwd`/c3.pid --unixctl=`pwd`/c3 + +check_async () { + for i in 1 3; do + ovs-appctl -t `pwd`/c$i ofctl/barrier + ovs-appctl -t `pwd`/c$i ofctl/set-output-file monitor$i.log + : > expout$i + done + + printf '\n\n--- check_async %d ---\n\n\n' $1 + INDEX=$1 + shift + + # OFPGC_ADD + ovs-appctl -t `pwd`/c2 ofctl/send 050f0010000000020000000000000001 + if test X"$1" = X"OFPGC_ADD"; then shift; + echo >>expout2 "send: OFPT_GROUP_MOD (OF1.4): + ADD group_id=1,type=all" + echo >>expout1 "OFPT_REQUESTFORWARD (OF1.5): reason=group_mod + ADD group_id=1,type=all" + echo >>expout3 "OFPT_REQUESTFORWARD (OF1.4): reason=group_mod + ADD group_id=1,type=all" + fi + + # OFPGC_MODIFY + ovs-appctl -t `pwd`/c2 ofctl/send 050f0010000000020001010000000001 + if test X"$1" = X"OFPGC_MODIFY"; then shift; + echo >>expout2 "send: OFPT_GROUP_MOD (OF1.4): + MOD group_id=1,type=select" + echo >>expout1 "OFPT_REQUESTFORWARD (OF1.5): reason=group_mod + MOD group_id=1,type=select" + echo >>expout3 "OFPT_REQUESTFORWARD (OF1.4): reason=group_mod + MOD group_id=1,type=select" + fi + + ovs-appctl -t `pwd`/c1 ofctl/barrier + echo >>expout1 "OFPT_BARRIER_REPLY (OF1.5):" + ovs-appctl -t `pwd`/c2 ofctl/barrier + echo >>expout2 "OFPT_BARRIER_REPLY (OF1.4):" + ovs-appctl -t `pwd`/c3 ofctl/barrier + echo >>expout3 "OFPT_BARRIER_REPLY (OF1.4):" + + # Check output. + for i in 1 3; do + cp expout$i expout + AT_CHECK( + [[sed ' +s/ (xid=0x[0-9a-fA-F]*)//'< monitor$i.log]], + [0], [expout]) + done +} + +# controller 1: Become slave +ovs-appctl -t `pwd`/c1 ofctl/send 061800180000000300000003000000008000000000000002 + +# controller 2: Become master +ovs-appctl -t `pwd`/c2 ofctl/send 051800180000000300000002000000008000000000000003 + +# controller 1: Become slave +ovs-appctl -t `pwd`/c3 ofctl/send 051800180000000300000003000000008000000000000004 + +# controller 1: Enabled requestforward using set Asynchronous message +ovs-appctl -t `pwd`/c1 ofctl/send 061c00280000000200000008000000050002000800000002000400080000001a000a000800000003 + +# controller 2: Enabled requestforward using set Asynchronous message +ovs-appctl -t `pwd`/c2 ofctl/send 051c002800000002000100080000000200030008000000050005000800000005000b000800000003 + +# controller 1: Enabled requestforward using set Asynchronous message +ovs-appctl -t `pwd`/c3 ofctl/send 051c00280000000200000008000000050002000800000002000400080000001a000a000800000003 +check_async 1 OFPGC_ADD OFPGC_MODIFY + +OVS_VSWITCHD_STOP +AT_CLEANUP + dnl This test checks that OFPT_PACKET_OUT accepts both OFPP_NONE (as dnl specified by OpenFlow 1.0) and OFPP_CONTROLLER (used by some dnl controllers despite the spec) as meaning a packet that was generated |