From: Pravin B Shelar Date: Sat, 14 Jan 2012 01:54:04 +0000 (-0800) Subject: ofproto: New action TTL decrement. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f0fd1a1772665ea57662281d9cccadb0f0146196;p=openvswitch ofproto: New action TTL decrement. Following patch implements dec_ttl as vendor action with similar semantics as OpenFlow 1.2. If TTL reaches zero while procession actions in current table, the remaining actions in previous tables are processed. A configuration parameter is added to make TTL decrement to zero generate packet in. Feature #8758 Signed-off-by: Pravin B Shelar --- diff --git a/NEWS b/NEWS index b628e29a..4f29e19b 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ v1.5.0 - xx xxx xxxx - Added support for querying, modifying, and deleting flows based on flow cookie when using NXM. - Added new NXM_PACKET_IN format. + - Added new NXAST_DEC_TTL action. - ovs-ofctl: - Added daemonization support to the monitor and snoop commands. - ovs-vsctl: diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index f00f9940..e17b313c 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -361,7 +361,8 @@ enum nx_action_subtype { NXAST_RESUBMIT_TABLE, /* struct nx_action_resubmit */ NXAST_OUTPUT_REG, /* struct nx_action_output_reg */ NXAST_LEARN, /* struct nx_action_learn */ - NXAST_EXIT /* struct nx_action_header */ + NXAST_EXIT, /* struct nx_action_header */ + NXAST_DEC_TTL, /* struct nx_action_header */ }; /* Header for Nicira-defined actions. */ diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index f68a140b..cd30d325 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -136,7 +136,11 @@ enum ofp_config_flags { OFPC_FRAG_DROP = 1, /* Drop fragments. */ OFPC_FRAG_REASM = 2, /* Reassemble (only if OFPC_IP_REASM set). */ OFPC_FRAG_NX_MATCH = 3, /* Make first fragments available for matching. */ - OFPC_FRAG_MASK = 3 + OFPC_FRAG_MASK = 3, + + /* TTL processing - applicable for IP and MPLS packets. */ + OFPC_INVALID_TTL_TO_CONTROLLER = 1 << 2, /* Send packets with invalid TTL + to the controller. */ }; /* Switch configuration. */ @@ -289,7 +293,8 @@ OFP_ASSERT(sizeof(struct ofp_port_mod) == 32); /* Why is this packet being sent to the controller? */ enum ofp_packet_in_reason { OFPR_NO_MATCH, /* No matching flow. */ - OFPR_ACTION /* Action explicitly output to controller. */ + OFPR_ACTION, /* Action explicitly output to controller. */ + OFPR_INVALID_TTL /* Packet has invalid TTL. */ }; /* Packet received on port (datapath -> controller). */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 38c3dabd..5321364b 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -364,6 +364,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, case OFPUTIL_NXAST_EXIT: ofputil_put_NXAST_EXIT(b); break; + + case OFPUTIL_NXAST_DEC_TTL: + ofputil_put_NXAST_DEC_TTL(b); + break; } } diff --git a/lib/ofp-print.c b/lib/ofp-print.c index aff12b6e..7bc26c9d 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -120,10 +120,19 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, } } - if (pin.reason == OFPR_ACTION) { + switch (pin.reason) { + case OFPR_NO_MATCH: + ds_put_cstr(string, " (via no_match)"); + break; + case OFPR_ACTION: ds_put_cstr(string, " (via action)"); - } else if (pin.reason != OFPR_NO_MATCH) { + break; + case OFPR_INVALID_TTL: + ds_put_cstr(string, " (via invalid_ttl)"); + break; + default: ds_put_format(string, " (***reason %"PRIu8"***)", pin.reason); + break; } ds_put_format(string, " data_len=%zu", pin.packet_len); @@ -333,6 +342,10 @@ ofp_print_action(struct ds *s, const union ofp_action *a, learn_format((const struct nx_action_learn *) a, s); break; + case OFPUTIL_NXAST_DEC_TTL: + ds_put_cstr(s, "dec_ttl"); + break; + case OFPUTIL_NXAST_EXIT: ds_put_cstr(s, "exit"); break; @@ -599,13 +612,18 @@ ofp_print_switch_features(struct ds *string, static void ofp_print_switch_config(struct ds *string, const struct ofp_switch_config *osc) { - uint16_t flags; + enum ofp_config_flags flags; flags = ntohs(osc->flags); ds_put_format(string, " frags=%s", ofputil_frag_handling_to_string(flags)); flags &= ~OFPC_FRAG_MASK; + if (flags & OFPC_INVALID_TTL_TO_CONTROLLER) { + ds_put_format(string, " invalid_ttl_to_controller"); + flags &= ~OFPC_INVALID_TTL_TO_CONTROLLER; + } + if (flags) { ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags); } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index b20d3fb6..6fe1611e 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -2436,6 +2436,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions, case OFPUTIL_NXAST_NOTE: case OFPUTIL_NXAST_SET_TUNNEL64: case OFPUTIL_NXAST_EXIT: + case OFPUTIL_NXAST_DEC_TTL: break; } diff --git a/lib/ofp-util.def b/lib/ofp-util.def index 2958eb6e..d05ec9dc 100644 --- a/lib/ofp-util.def +++ b/lib/ofp-util.def @@ -36,4 +36,5 @@ NXAST_ACTION(NXAST_RESUBMIT_TABLE, nx_action_resubmit, 0, NULL) NXAST_ACTION(NXAST_OUTPUT_REG, nx_action_output_reg, 0, NULL) NXAST_ACTION(NXAST_LEARN, nx_action_learn, 1, "learn") NXAST_ACTION(NXAST_EXIT, nx_action_header, 0, "exit") +NXAST_ACTION(NXAST_DEC_TTL, nx_action_header, 0, "dec_ttl") #undef NXAST_ACTION diff --git a/lib/ofp-util.h b/lib/ofp-util.h index d01e17a5..422c14a7 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -227,7 +227,7 @@ struct ofputil_packet_in { const void *packet; size_t packet_len; - uint8_t reason; /* One of OFPR_*. */ + enum ofp_packet_in_reason reason; /* One of OFPRR_*. */ uint8_t table_id; ovs_be64 cookie; diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index 28d9488d..887080ac 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -71,6 +71,8 @@ struct ofconn { /* type == OFCONN_PRIMARY only. */ enum nx_role role; /* Role. */ + bool invalid_ttl_to_controller; /* Send packets with invalid TTL + to the controller. */ struct hmap_node hmap_node; /* In struct connmgr's "controllers" map. */ enum ofproto_band band; /* In-band or out-of-band? */ }; @@ -754,6 +756,18 @@ ofconn_set_role(struct ofconn *ofconn, enum nx_role role) ofconn->role = role; } +void +ofconn_set_invalid_ttl_to_controller(struct ofconn *ofconn, bool val) +{ + ofconn->invalid_ttl_to_controller = val; +} + +bool +ofconn_get_invalid_ttl_to_controller(struct ofconn *ofconn) +{ + return ofconn->invalid_ttl_to_controller; +} + /* Returns the currently configured flow format for 'ofconn', one of NXFF_*. * * The default, if no other format has been set, is NXFF_OPENFLOW10. */ @@ -931,6 +945,7 @@ ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type) ofconn->pktbuf = NULL; ofconn->miss_send_len = 0; ofconn->reply_counter = rconn_packet_counter_create (); + ofconn->invalid_ttl_to_controller = false; return ofconn; } @@ -1054,11 +1069,9 @@ ofconn_wait(struct ofconn *ofconn, bool handling_openflow) /* Returns true if 'ofconn' should receive asynchronous messages. */ static bool -ofconn_receives_async_msgs(const struct ofconn *ofconn) +ofconn_receives_async_msgs__(const struct ofconn *ofconn) { - if (!rconn_is_connected(ofconn->rconn)) { - return false; - } else if (ofconn->type == OFCONN_PRIMARY) { + if (ofconn->type == OFCONN_PRIMARY) { /* Primary controllers always get asynchronous messages unless they * have configured themselves as "slaves". */ return ofconn->role != NX_ROLE_SLAVE; @@ -1069,6 +1082,29 @@ ofconn_receives_async_msgs(const struct ofconn *ofconn) } } +static bool +ofconn_receives_async_msgs(const struct ofconn *ofconn) +{ + if (!rconn_is_connected(ofconn->rconn)) { + return false; + } else { + return ofconn_receives_async_msgs__(ofconn); + } +} + +static bool +ofconn_interested_in_packet(const struct ofconn *ofconn, + const struct ofputil_packet_in *pin) +{ + if (!rconn_is_connected(ofconn->rconn)) { + return false; + } else if (pin->reason == OFPR_INVALID_TTL) { + return ofconn->invalid_ttl_to_controller; + } else { + return ofconn_receives_async_msgs__(ofconn); + } +} + /* Returns a human-readable name for an OpenFlow connection between 'mgr' and * 'target', suitable for use in log messages for identifying the connection. * @@ -1178,7 +1214,7 @@ connmgr_send_packet_in(struct connmgr *mgr, struct ofconn *ofconn; LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { - if (ofconn_receives_async_msgs(ofconn)) { + if (ofconn_interested_in_packet(ofconn, pin)) { schedule_packet_in(ofconn, *pin, flow); } } diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h index bbee7f4f..8ff89f36 100644 --- a/ofproto/connmgr.h +++ b/ofproto/connmgr.h @@ -92,6 +92,9 @@ void ofconn_set_packet_in_format(struct ofconn *, enum nx_packet_in_format); bool ofconn_get_flow_mod_table_id(const struct ofconn *); void ofconn_set_flow_mod_table_id(struct ofconn *, bool enable); +void ofconn_set_invalid_ttl_to_controller(struct ofconn *, bool); +bool ofconn_get_invalid_ttl_to_controller(struct ofconn *); + int ofconn_get_miss_send_len(const struct ofconn *); void ofconn_set_miss_send_len(struct ofconn *, int miss_send_len); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 6ecf71b8..567240de 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4291,7 +4291,8 @@ flood_packets(struct action_xlate_ctx *ctx, bool all) } static void -execute_controller_action(struct action_xlate_ctx *ctx, int len) +execute_controller_action(struct action_xlate_ctx *ctx, int len, + enum ofp_packet_in_reason reason) { struct ofputil_packet_in pin; struct ofpbuf *packet; @@ -4336,7 +4337,7 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len) pin.packet = packet->data; pin.packet_len = packet->size; - pin.reason = OFPR_ACTION; + pin.reason = reason; pin.table_id = ctx->table_id; pin.cookie = ctx->cookie; @@ -4349,6 +4350,25 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len) ofpbuf_delete(packet); } +static bool +compose_dec_ttl(struct action_xlate_ctx *ctx) +{ + if (ctx->flow.dl_type != htons(ETH_TYPE_IP) && + ctx->flow.dl_type != htons(ETH_TYPE_IPV6)) { + return false; + } + + if (ctx->flow.nw_ttl > 1) { + ctx->flow.nw_ttl--; + return false; + } else { + execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL); + + /* Stop processing for current table. */ + return true; + } +} + static void xlate_output_action__(struct action_xlate_ctx *ctx, uint16_t port, uint16_t max_len) @@ -4374,7 +4394,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx, flood_packets(ctx, true); break; case OFPP_CONTROLLER: - execute_controller_action(ctx, max_len); + execute_controller_action(ctx, max_len, OFPR_ACTION); break; case OFPP_LOCAL: compose_output_action(ctx, OFPP_LOCAL); @@ -4730,12 +4750,19 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, } break; + case OFPUTIL_NXAST_DEC_TTL: + if (compose_dec_ttl(ctx)) { + goto out; + } + break; + case OFPUTIL_NXAST_EXIT: ctx->exit = true; break; } } +out: /* We've let OFPP_NORMAL and the learning action look at the packet, * so drop it now if forwarding is disabled. */ if (port && !stp_forward_in_state(port->stp_state)) { @@ -4799,6 +4826,9 @@ xlate_actions(struct action_xlate_ctx *ctx, case OFPC_FRAG_NX_MATCH: /* Nothing to do. */ break; + + case OFPC_INVALID_TTL_TO_CONTROLLER: + NOT_REACHED(); } } diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 29259e40..05040261 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1746,11 +1746,16 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh) { struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofp_switch_config *osc; + enum ofp_config_flags flags; struct ofpbuf *buf; /* Send reply. */ osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf); - osc->flags = htons(ofproto->frag_handling); + flags = ofproto->frag_handling; + if (ofconn_get_invalid_ttl_to_controller(ofconn)) { + flags |= OFPC_INVALID_TTL_TO_CONTROLLER; + } + osc->flags = htons(flags); osc->miss_send_len = htons(ofconn_get_miss_send_len(ofconn)); ofconn_send_reply(ofconn, buf); @@ -1779,6 +1784,8 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc) } } } + ofconn_set_invalid_ttl_to_controller(ofconn, + (flags & OFPC_INVALID_TTL_TO_CONTROLLER)); ofconn_set_miss_send_len(ofconn, ntohs(osc->miss_send_len)); diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 0619e986..85562b6a 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -269,7 +269,7 @@ AT_CHECK([ovs-ofctl ofp-print "\ c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \ 50 00 02 00 26 e8 00 00 00 00 00 00 00 00 \ "], [0], [dnl -OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=3 data_len=60 buffer=0x00000111 +OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111 priority:0,tunnel:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:06) type:0800 proto:6 tos:0 ttl:64 ip(192.168.0.1->192.168.0.2) port(10031->0) tcp_csum:26e8 ]) AT_CLEANUP diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 2c4e7c4b..bb00714e 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -62,6 +62,38 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif - dec_ttl]) +OVS_VSWITCHD_START +AT_DATA([flows.txt], [dnl +table=0 in_port=1 action=dec_ttl,output:2,resubmit(1,1),output:4 +table=1 in_port=1 action=dec_ttl,output:3 +]) +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) +AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout]) +AT_CHECK([tail -2 stdout], [0], + [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=1,frag=no)),2,4 +This flow is not cachable. +]) +AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=3,frag=no)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)),2,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=1,frag=no)),3,4 +]) +AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=127,frag=no)),2,set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=126,frag=no)),3,4 +]) + +AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --pidfile 2> ofctl_monitor.log]) +AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout]) +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +AT_CHECK([cat ofctl_monitor.log], [0], [dnl +NXT_PACKET_IN (xid=0x0): table_id=1 total_len=42 in_port=1 tun_id=0x0 reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 (via invalid_ttl) data_len=42 (unbuffered) +priority:0,tunnel:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:1 tos:0 ttl:1 ip(192.168.0.1->192.168.0.2) +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + + AT_SETUP([ofproto-dpif - output, OFPP_NONE ingress port]) OVS_VSWITCHD_START( [add-port br0 p1 -- set Interface p1 type=dummy --\ @@ -209,13 +241,13 @@ done OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 data_len=60 (unbuffered) +OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0 dnl -OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 data_len=60 (unbuffered) +OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0 dnl -OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 data_len=60 (unbuffered) +OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) priority:0,tunnel:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0 ]) diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 4bfd5436..2a20a2f4 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -243,7 +243,7 @@ If a switch has no controller configured, or if the configured controller is disconnected, no traffic is sent, so monitoring will not show any traffic. . -.IP "\fBmonitor \fIswitch\fR [\fImiss-len\fR]" +.IP "\fBmonitor \fIswitch\fR [\fImiss-len\fR] [\fIinvalid_ttl\fR]" Connects to \fIswitch\fR and prints to the console all OpenFlow messages received. Usually, \fIswitch\fR should specify the name of a bridge in the \fBovs\-vswitchd\fR database. @@ -256,6 +256,13 @@ does not send these and other asynchronous messages to an specified on this argument. (Thus, if \fImiss\-len\fR is not specified, very little traffic will ordinarily be printed.) .IP +.IP +If \fBinvalid_ttl\fR is passed, \fBovs\-ofctl\fR sends an OpenFlow ``set +configuration'' message at connection setup time that requests +\fIINVALID_TTL_TO_CONTROLLER\fR, so that \fBovs\-ofctl monitor\fR can +receive ``packets-in'' messages when TTL reaches zero on \fBdec_ttl\fR action. +.IP + This command may be useful for debugging switch or controller implementations. . @@ -778,6 +785,16 @@ OpenFlow implementations do not support queuing at all. Restores the queue to the value it was before any \fBset_queue\fR actions were applied. . +.IP \fBdec_ttl\fR +Decrement TTL of IPv4 packet or hop limit of IPv6 packet. If the +TTL or hop limit is initially zero, no decrement occurs. Instead, +a ``packet-in'' message with reason code \fBOFPR_INVALID_TTL\fR is +sent to each connected controller that has enabled receiving them, +if any. Processing the current set of actions then stops. +However, if the current set of actions was reached through +``resubmit'' then remaining actions in outer levels resume +processing. +. .IP \fBnote:\fR[\fIhh\fR]... Does nothing at all. Any number of bytes represented as hex digits \fIhh\fR may be included. Pairs of hex digits may be separated by diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 6219f94a..8a8b8b2d 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -794,6 +794,35 @@ set_packet_in_format(struct vconn *vconn, ofputil_packet_in_format_to_string(packet_in_format)); } +static int +monitor_set_invalid_ttl_to_controller(struct vconn *vconn) +{ + struct ofp_switch_config config; + enum ofp_config_flags flags; + + fetch_switch_config(vconn, &config); + flags = ntohs(config.flags); + if (!(flags & OFPC_INVALID_TTL_TO_CONTROLLER)) { + /* Set the invalid ttl config. */ + flags |= OFPC_INVALID_TTL_TO_CONTROLLER; + + config.flags = htons(flags); + set_switch_config(vconn, &config); + + /* Then retrieve the configuration to see if it really took. OpenFlow + * doesn't define error reporting for bad modes, so this is all we can + * do. */ + fetch_switch_config(vconn, &config); + flags = ntohs(config.flags); + if (!(flags & OFPC_INVALID_TTL_TO_CONTROLLER)) { + ovs_fatal(0, "setting invalid_ttl_to_controller failed (this " + "switch probably doesn't support mode)"); + return -EOPNOTSUPP; + } + } + return 0; +} + static void monitor_vconn(struct vconn *vconn) { @@ -876,6 +905,11 @@ do_monitor(int argc, char *argv[]) config.miss_send_len = htons(atoi(argv[2])); set_switch_config(vconn, &config); } + if (argc > 3) { + if (!strcmp(argv[3], "invalid_ttl")) { + monitor_set_invalid_ttl_to_controller(vconn); + } + } monitor_vconn(vconn); } @@ -1634,7 +1668,7 @@ do_ofp_print(int argc, char *argv[]) static const struct command all_commands[] = { { "show", 1, 1, do_show }, - { "monitor", 1, 2, do_monitor }, + { "monitor", 1, 3, do_monitor }, { "snoop", 1, 1, do_snoop }, { "dump-desc", 1, 1, do_dump_desc }, { "dump-tables", 1, 1, do_dump_tables },