From 0c3d5fc89a341d31774f24ddaf7360a5ba4a641f Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 25 Jan 2012 16:30:28 -0800 Subject: [PATCH] ovs-ofctl: Add "packet-out" command. I don't expect this to be widely useful. An upcoming commit will add a use in unit tests. Signed-off-by: Ben Pfaff --- lib/learn.c | 21 ++++++++++++++++---- lib/ofp-parse.c | 13 +++++++++++++ lib/ofp-parse.h | 5 ++++- utilities/ovs-ofctl.8.in | 9 +++++++++ utilities/ovs-ofctl.c | 41 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/lib/learn.c b/lib/learn.c index 16764621..8d947a31 100644 --- a/lib/learn.c +++ b/lib/learn.c @@ -384,6 +384,17 @@ learn_parse_spec(const char *orig, char *name, char *value, } } +/* Parses 'arg' as a set of arguments to the "learn" action and appends a + * matching NXAST_LEARN action to 'b'. The format parsed is described in + * ovs-ofctl(8). + * + * Prints an error on stderr and aborts the program if 'arg' syntax is invalid. + * + * If 'flow' is nonnull, then it should be the flow from a cls_rule that is + * the matching rule for the learning action. This helps to better validate + * the action's arguments. + * + * Modifies 'arg'. */ void learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow) { @@ -429,7 +440,7 @@ learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow) /* Check prerequisites. */ if (spec.src_type == NX_LEARN_SRC_FIELD - && !mf_are_prereqs_ok(spec.src.field, flow)) { + && flow && !mf_are_prereqs_ok(spec.src.field, flow)) { ovs_fatal(0, "%s: cannot specify source field %s because " "prerequisites are not satisfied", orig, spec.src.field->name); @@ -487,9 +498,11 @@ learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow) learn->len = htons(b->size - learn_ofs); /* In theory the above should have caught any errors, but... */ - error = learn_check(learn, flow); - if (error) { - ovs_fatal(0, "%s: %s", orig, ofperr_to_string(error)); + if (flow) { + error = learn_check(learn, flow); + if (error) { + ovs_fatal(0, "%s: %s", orig, ofperr_to_string(error)); + } } free(orig); } diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index d5502fab..f96f8170 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -625,6 +625,19 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, free(string); } +/* Parses 's' as a set of OpenFlow actions and appends the actions to + * 'actions'. + * + * Prints an error on stderr and aborts the program if 's' syntax is + * invalid. */ +void +parse_ofp_actions(const char *s_, struct ofpbuf *actions) +{ + char *s = xstrdup(s_); + str_to_action(NULL, s, actions); + free(s); +} + /* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command' * (one of OFPFC_*) and appends the parsed OpenFlow message to 'packets'. * '*cur_format' should initially contain the flow format currently configured diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h index 80fca97a..6eba0dda 100644 --- a/lib/ofp-parse.h +++ b/lib/ofp-parse.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011 Nicira Networks. + * Copyright (c) 2010, 2011, 2012 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,4 +42,7 @@ bool parse_ofp_flow_mod_file(struct list *packets, void parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *, bool aggregate, char *string); + +void parse_ofp_actions(const char *, struct ofpbuf *actions); + #endif /* ofp-parse.h */ diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 606aaa9c..afd86c56 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -216,6 +216,15 @@ For this command, an exit status of 0 means that no differences were found, 1 means that an error occurred, and 2 means that some differences were found. . +.IP "\fBpacket\-out \fIswitch in_port actions packet\fR..." +Connects to \fIswitch\fR and instructs it to execute the OpenFlow +\fIactions\fR on each \fIpacket\fR. For the purpose of executing the +actions, the packets are considered to have arrived on \fIin_port\fR, +which may be an OpenFlow assigned port number, an OpenFlow port name +(e.g. \fBeth0\fR), the keyword \fBlocal\fR for the OpenFlow ``local'' +port \fBOFPP_LOCAL\fR, or the keyword \fBnone\fR to indicate that the +packet was generated by the switch itself. +. .SS "OpenFlow Switch Monitoring Commands" . .IP "\fBsnoop \fIswitch\fR" diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 26bc1c3b..c565e864 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -45,6 +45,7 @@ #include "ofproto/ofproto.h" #include "openflow/nicira-ext.h" #include "openflow/openflow.h" +#include "packets.h" #include "poll-loop.h" #include "random.h" #include "stream-ssl.h" @@ -209,6 +210,8 @@ usage(void) " del-flows SWITCH [FLOW] delete matching FLOWs\n" " replace-flows SWITCH FILE replace flows with those in FILE\n" " diff-flows SOURCE1 SOURCE2 compare flows from two sources\n" + " packet-out SWITCH IN_PORT ACTIONS PACKET...\n" + " execute ACTIONS on PACKET\n" " monitor SWITCH [MISSLEN] [invalid_ttl]\n" " print packets received from SWITCH\n" " snoop SWITCH snoop on SWITCH and its controller\n" @@ -953,6 +956,43 @@ do_probe(int argc OVS_UNUSED, char *argv[]) vconn_close(vconn); } +static void +do_packet_out(int argc, char *argv[]) +{ + struct ofputil_packet_out po; + struct ofpbuf actions; + struct vconn *vconn; + int i; + + ofpbuf_init(&actions, sizeof(union ofp_action)); + parse_ofp_actions(argv[3], &actions); + + po.buffer_id = UINT32_MAX; + po.in_port = (!strcasecmp(argv[2], "none") ? OFPP_NONE + : !strcasecmp(argv[2], "local") ? OFPP_LOCAL + : str_to_port_no(argv[1], argv[2])); + po.actions = actions.data; + po.n_actions = actions.size / sizeof(union ofp_action); + + open_vconn(argv[1], &vconn); + for (i = 4; i < argc; i++) { + struct ofpbuf *packet, *opo; + const char *error_msg; + + error_msg = eth_from_hex(argv[i], &packet); + if (error_msg) { + ovs_fatal(0, "%s", error_msg); + } + + po.packet = packet->data; + po.packet_len = packet->size; + opo = ofputil_encode_packet_out(&po); + transact_noreply(vconn, opo); + ofpbuf_delete(packet); + } + vconn_close(vconn); +} + static void do_mod_port(int argc OVS_UNUSED, char *argv[]) { @@ -1682,6 +1722,7 @@ static const struct command all_commands[] = { { "del-flows", 1, 2, do_del_flows }, { "replace-flows", 2, 2, do_replace_flows }, { "diff-flows", 2, 2, do_diff_flows }, + { "packet-out", 4, INT_MAX, do_packet_out }, { "dump-ports", 1, 2, do_dump_ports }, { "mod-port", 3, 3, do_mod_port }, { "get-frags", 1, 1, do_get_frags }, -- 2.30.2