2009-07-08 13:19:16 -07:00
|
|
|
|
/*
|
2019-04-30 15:07:07 -07:00
|
|
|
|
* Copyright (c) 2008-2017, 2019 Nicira, Inc.
|
2009-07-08 13:19:16 -07:00
|
|
|
|
*
|
2009-06-15 15:11:30 -07:00
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at:
|
2009-07-08 13:19:16 -07:00
|
|
|
|
*
|
2009-06-15 15:11:30 -07:00
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
2009-07-08 13:19:16 -07:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
2012-07-12 14:18:05 -07:00
|
|
|
|
#include <ctype.h>
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <getopt.h>
|
|
|
|
|
#include <inttypes.h>
|
2011-03-30 17:25:36 +02:00
|
|
|
|
#include <sys/socket.h>
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include <net/if.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
2014-03-12 14:35:10 -07:00
|
|
|
|
#include <fcntl.h>
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
2010-10-28 17:13:18 -07:00
|
|
|
|
#include "byte-order.h"
|
2010-11-09 17:00:59 -08:00
|
|
|
|
#include "classifier.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "command-line.h"
|
2011-12-20 15:31:34 -08:00
|
|
|
|
#include "daemon.h"
|
2016-03-02 15:56:17 +01:00
|
|
|
|
#include "colors.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "compiler.h"
|
|
|
|
|
#include "dirs.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "dp-packet.h"
|
2014-02-26 10:44:46 -08:00
|
|
|
|
#include "fatal-signal.h"
|
2010-11-09 17:00:59 -08:00
|
|
|
|
#include "nx-match.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "odp-util.h"
|
2012-11-19 14:59:32 +09:00
|
|
|
|
#include "ofp-version-opt.h"
|
2011-04-11 15:08:19 -07:00
|
|
|
|
#include "ofproto/ofproto.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "openflow/nicira-ext.h"
|
|
|
|
|
#include "openflow/openflow.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openvswitch/dynamic-string.h"
|
|
|
|
|
#include "openvswitch/meta-flow.h"
|
2016-04-14 15:20:19 -07:00
|
|
|
|
#include "openvswitch/ofp-actions.h"
|
2018-02-09 10:04:26 -08:00
|
|
|
|
#include "openvswitch/ofp-bundle.h"
|
2023-01-16 12:45:08 +01:00
|
|
|
|
#include "openvswitch/ofp-ct.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openvswitch/ofp-errors.h"
|
2018-02-09 10:04:26 -08:00
|
|
|
|
#include "openvswitch/ofp-group.h"
|
|
|
|
|
#include "openvswitch/ofp-match.h"
|
|
|
|
|
#include "openvswitch/ofp-meter.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openvswitch/ofp-msgs.h"
|
2018-02-09 10:04:26 -08:00
|
|
|
|
#include "openvswitch/ofp-monitor.h"
|
|
|
|
|
#include "openvswitch/ofp-port.h"
|
2016-04-14 15:20:21 -07:00
|
|
|
|
#include "openvswitch/ofp-print.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openvswitch/ofp-util.h"
|
|
|
|
|
#include "openvswitch/ofp-parse.h"
|
2018-02-09 10:04:26 -08:00
|
|
|
|
#include "openvswitch/ofp-queue.h"
|
|
|
|
|
#include "openvswitch/ofp-switch.h"
|
|
|
|
|
#include "openvswitch/ofp-table.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openvswitch/ofpbuf.h"
|
2017-05-31 16:06:12 -07:00
|
|
|
|
#include "openvswitch/shash.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openvswitch/vconn.h"
|
|
|
|
|
#include "openvswitch/vlog.h"
|
2012-01-25 16:30:28 -08:00
|
|
|
|
#include "packets.h"
|
2013-09-23 10:28:14 -07:00
|
|
|
|
#include "pcap-file.h"
|
2017-11-03 13:53:53 +08:00
|
|
|
|
#include "openvswitch/poll-loop.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "random.h"
|
2016-04-14 15:20:19 -07:00
|
|
|
|
#include "sort.h"
|
2010-01-06 14:35:20 -08:00
|
|
|
|
#include "stream-ssl.h"
|
2012-10-10 13:33:54 -07:00
|
|
|
|
#include "socket-util.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "timeval.h"
|
2011-12-20 15:31:34 -08:00
|
|
|
|
#include "unixctl.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "util.h"
|
|
|
|
|
|
2010-10-19 14:47:01 -07:00
|
|
|
|
VLOG_DEFINE_THIS_MODULE(ofctl);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2016-02-17 14:08:04 -08:00
|
|
|
|
/* --bundle: Use OpenFlow 1.3+ bundle for making the flow table change atomic.
|
|
|
|
|
* NOTE: If OpenFlow 1.3 or higher is not selected with the '-O' option,
|
|
|
|
|
* OpenFlow 1.4 will be implicitly selected. Also the flow mod will use
|
|
|
|
|
* OpenFlow 1.4, so the semantics may be different (see the comment in
|
|
|
|
|
* parse_options() for details).
|
2015-06-05 14:03:12 -07:00
|
|
|
|
*/
|
|
|
|
|
static bool bundle = false;
|
|
|
|
|
|
2016-03-02 15:56:16 +01:00
|
|
|
|
/* --color: Use color markers. */
|
|
|
|
|
static bool enable_color;
|
|
|
|
|
|
2016-08-15 18:47:29 +00:00
|
|
|
|
/* --read-only: Do not execute read only commands. */
|
|
|
|
|
static bool read_only;
|
|
|
|
|
|
2012-01-03 13:30:45 -08:00
|
|
|
|
/* --strict: Use strict matching for flow mod commands? Additionally governs
|
|
|
|
|
* use of nx_pull_match() instead of nx_pull_match_loose() in parse-nx-match.
|
|
|
|
|
*/
|
2009-10-23 11:49:39 -07:00
|
|
|
|
static bool strict;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
ofproto: Add relaxed group_mod command ADD_OR_MOD
This patch adds support for a new Group Mod command OFPGC_ADD_OR_MOD to
OVS for all OpenFlow versions that support groups (OF11 and higher).
The new ADD_OR_MOD creates a group that does not yet exist (like ADD)
and modifies an existing group (like MODIFY).
Rational: In OpenFlow 1.x the Group Mod commands OFPGC_ADD and
OFPGC_MODIFY have strict semantics: ADD fails if the group exists,
while MODIFY fails if the group does not exist. This requires a
controller to exactly know the state of the switch when programming a
group in order not run the risk of getting an OFP Error message in
response. This is hard to achieve and maintain at all times in view of
possible switch and controller restarts or other connection losses
between switch and controller.
Due to the un-acknowledged nature of the Group Mod message programming
groups safely and efficiently at the same time is virtually impossible
as the controller has to either query the existence of the group prior
to each Group Mod message or to insert a Barrier Request/Reply after
every group to be sure that no Error can be received at a later stage
and require a complicated roll-back of any dependent actions taken
between the failed Group Mod and the Error.
In the ovs-ofctl command line the ADD_OR_MOD command is made available
through the new option --may-create in the mod-group command:
$ ovs-ofctl -Oopenflow13 del-groups br-int group_id=100
$ ovs-ofctl -Oopenflow13 mod-group br-int
group_id=100,type=indirect,bucket=actions=2 OFPT_ERROR (OF1.3)
(xid=0x2): OFPGMFC_UNKNOWN_GROUP OFPT_GROUP_MOD (OF1.3) (xid=0x2):
MOD group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=2
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=3
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:3
Signed-off-by: Jan Scheurich <jan.scheurich at web.de>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-29 00:29:25 +02:00
|
|
|
|
/* --may-create: If true, the mod-group command creates a group that does not
|
|
|
|
|
* yet exist; otherwise, such a command has no effect. */
|
|
|
|
|
static bool may_create;
|
|
|
|
|
|
2012-01-26 13:39:38 -08:00
|
|
|
|
/* --readd: If true, on replace-flows, re-add even flows that have not changed
|
2011-07-27 14:58:10 -07:00
|
|
|
|
* (to reset flow counters). */
|
|
|
|
|
static bool readd;
|
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
/* -F, --flow-format: Allowed protocols. By default, any protocol is
|
|
|
|
|
* allowed. */
|
|
|
|
|
static enum ofputil_protocol allowed_protocols = OFPUTIL_P_ANY;
|
2010-12-07 13:32:01 -08:00
|
|
|
|
|
2011-12-09 15:48:26 -08:00
|
|
|
|
/* -P, --packet-in-format: Packet IN format to use in monitor and snoop
|
|
|
|
|
* commands. Either one of NXPIF_* to force a particular packet_in format, or
|
|
|
|
|
* -1 to let ovs-ofctl choose the default. */
|
|
|
|
|
static int preferred_packet_in_format = -1;
|
|
|
|
|
|
2010-11-23 14:34:21 -08:00
|
|
|
|
/* -m, --more: Additional verbosity for ofp-print functions. */
|
|
|
|
|
static int verbosity;
|
|
|
|
|
|
2012-02-07 16:17:13 -08:00
|
|
|
|
/* --timestamp: Print a timestamp before each received packet on "monitor" and
|
|
|
|
|
* "snoop" command? */
|
|
|
|
|
static bool timestamp;
|
|
|
|
|
|
2014-07-28 10:31:25 -07:00
|
|
|
|
/* --unixctl-path: Path to use for unixctl server, for "monitor" and "snoop"
|
|
|
|
|
commands. */
|
|
|
|
|
static char *unixctl_path;
|
|
|
|
|
|
2012-07-12 13:32:47 -07:00
|
|
|
|
/* --sort, --rsort: Sort order. */
|
|
|
|
|
enum sort_order { SORT_ASC, SORT_DESC };
|
|
|
|
|
struct sort_criterion {
|
|
|
|
|
const struct mf_field *field; /* NULL means to sort by priority. */
|
|
|
|
|
enum sort_order order;
|
|
|
|
|
};
|
|
|
|
|
static struct sort_criterion *criteria;
|
|
|
|
|
static size_t n_criteria, allocated_criteria;
|
|
|
|
|
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
/* --names, --no-names: Show port and table names in output and accept them in
|
|
|
|
|
* input. (When neither is specified, the default is to accept port names but,
|
|
|
|
|
* for backward compatibility, not to show them unless this is an interactive
|
|
|
|
|
* console session.) */
|
|
|
|
|
static int use_names = -1;
|
2017-05-31 16:06:12 -07:00
|
|
|
|
static const struct ofputil_port_map *ports_to_accept(const char *vconn_name);
|
|
|
|
|
static const struct ofputil_port_map *ports_to_show(const char *vconn_name);
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
static const struct ofputil_table_map *tables_to_accept(
|
|
|
|
|
const char *vconn_name);
|
|
|
|
|
static const struct ofputil_table_map *tables_to_show(const char *vconn_name);
|
|
|
|
|
static bool should_accept_names(void);
|
|
|
|
|
static bool should_show_names(void);
|
2017-05-31 16:06:12 -07:00
|
|
|
|
|
2017-06-13 17:09:05 -07:00
|
|
|
|
/* --stats, --no-stats: Show statistics in flow dumps? */
|
|
|
|
|
static int show_stats = 1;
|
|
|
|
|
|
2018-01-18 14:39:50 -08:00
|
|
|
|
/* --pcap: Makes "compose-packet" print a pcap on stdout. */
|
|
|
|
|
static int print_pcap = 0;
|
|
|
|
|
|
2018-02-14 14:40:12 -08:00
|
|
|
|
/* --raw: Makes "ofp-print" read binary data from stdin. */
|
|
|
|
|
static int raw = 0;
|
|
|
|
|
|
2015-03-16 12:01:55 -04:00
|
|
|
|
static const struct ovs_cmdl_command *get_all_commands(void);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2014-12-15 14:10:38 +01:00
|
|
|
|
OVS_NO_RETURN static void usage(void);
|
2009-10-23 11:49:39 -07:00
|
|
|
|
static void parse_options(int argc, char *argv[]);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2009-10-23 11:49:39 -07:00
|
|
|
|
int
|
|
|
|
|
main(int argc, char *argv[])
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
struct ovs_cmdl_context ctx = { .argc = 0, };
|
2009-07-08 13:19:16 -07:00
|
|
|
|
set_program_name(argv[0]);
|
2014-05-16 12:10:50 -07:00
|
|
|
|
service_start(&argc, &argv);
|
2009-10-23 11:49:39 -07:00
|
|
|
|
parse_options(argc, argv);
|
2014-02-26 10:44:46 -08:00
|
|
|
|
fatal_ignore_sigpipe();
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ctx.argc = argc - optind;
|
|
|
|
|
ctx.argv = argv + optind;
|
2015-09-11 11:26:39 -07:00
|
|
|
|
|
|
|
|
|
daemon_become_new_user(false);
|
2016-08-15 18:47:29 +00:00
|
|
|
|
if (read_only) {
|
|
|
|
|
ovs_cmdl_run_command_read_only(&ctx, get_all_commands());
|
|
|
|
|
} else {
|
|
|
|
|
ovs_cmdl_run_command(&ctx, get_all_commands());
|
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-12 13:32:47 -07:00
|
|
|
|
static void
|
|
|
|
|
add_sort_criterion(enum sort_order order, const char *field)
|
|
|
|
|
{
|
|
|
|
|
struct sort_criterion *sc;
|
|
|
|
|
|
|
|
|
|
if (n_criteria >= allocated_criteria) {
|
|
|
|
|
criteria = x2nrealloc(criteria, &allocated_criteria, sizeof *criteria);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sc = &criteria[n_criteria++];
|
|
|
|
|
if (!field || !strcasecmp(field, "priority")) {
|
|
|
|
|
sc->field = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
sc->field = mf_from_name(field);
|
|
|
|
|
if (!sc->field) {
|
|
|
|
|
ovs_fatal(0, "%s: unknown field name", field);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sc->order = order;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2009-10-23 11:49:39 -07:00
|
|
|
|
parse_options(int argc, char *argv[])
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
enum {
|
2010-01-04 18:55:00 -08:00
|
|
|
|
OPT_STRICT = UCHAR_MAX + 1,
|
2011-07-27 14:58:10 -07:00
|
|
|
|
OPT_READD,
|
2012-02-07 16:17:13 -08:00
|
|
|
|
OPT_TIMESTAMP,
|
2012-07-12 13:32:47 -07:00
|
|
|
|
OPT_SORT,
|
|
|
|
|
OPT_RSORT,
|
2014-07-28 10:31:25 -07:00
|
|
|
|
OPT_UNIXCTL,
|
2015-06-05 14:03:12 -07:00
|
|
|
|
OPT_BUNDLE,
|
2016-03-02 15:56:16 +01:00
|
|
|
|
OPT_COLOR,
|
ofproto: Add relaxed group_mod command ADD_OR_MOD
This patch adds support for a new Group Mod command OFPGC_ADD_OR_MOD to
OVS for all OpenFlow versions that support groups (OF11 and higher).
The new ADD_OR_MOD creates a group that does not yet exist (like ADD)
and modifies an existing group (like MODIFY).
Rational: In OpenFlow 1.x the Group Mod commands OFPGC_ADD and
OFPGC_MODIFY have strict semantics: ADD fails if the group exists,
while MODIFY fails if the group does not exist. This requires a
controller to exactly know the state of the switch when programming a
group in order not run the risk of getting an OFP Error message in
response. This is hard to achieve and maintain at all times in view of
possible switch and controller restarts or other connection losses
between switch and controller.
Due to the un-acknowledged nature of the Group Mod message programming
groups safely and efficiently at the same time is virtually impossible
as the controller has to either query the existence of the group prior
to each Group Mod message or to insert a Barrier Request/Reply after
every group to be sure that no Error can be received at a later stage
and require a complicated roll-back of any dependent actions taken
between the failed Group Mod and the Error.
In the ovs-ofctl command line the ADD_OR_MOD command is made available
through the new option --may-create in the mod-group command:
$ ovs-ofctl -Oopenflow13 del-groups br-int group_id=100
$ ovs-ofctl -Oopenflow13 mod-group br-int
group_id=100,type=indirect,bucket=actions=2 OFPT_ERROR (OF1.3)
(xid=0x2): OFPGMFC_UNKNOWN_GROUP OFPT_GROUP_MOD (OF1.3) (xid=0x2):
MOD group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=2
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=3
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:3
Signed-off-by: Jan Scheurich <jan.scheurich at web.de>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-29 00:29:25 +02:00
|
|
|
|
OPT_MAY_CREATE,
|
2016-08-15 18:47:29 +00:00
|
|
|
|
OPT_READ_ONLY,
|
2011-12-20 15:31:34 -08:00
|
|
|
|
DAEMON_OPTION_ENUMS,
|
2012-11-19 14:59:32 +09:00
|
|
|
|
OFP_VERSION_OPTION_ENUMS,
|
2016-10-06 16:21:33 -07:00
|
|
|
|
VLOG_OPTION_ENUMS,
|
|
|
|
|
SSL_OPTION_ENUMS,
|
2009-07-08 13:19:16 -07:00
|
|
|
|
};
|
2013-04-23 16:40:56 -07:00
|
|
|
|
static const struct option long_options[] = {
|
2011-05-04 13:49:42 -07:00
|
|
|
|
{"timeout", required_argument, NULL, 't'},
|
|
|
|
|
{"strict", no_argument, NULL, OPT_STRICT},
|
2011-07-27 14:58:10 -07:00
|
|
|
|
{"readd", no_argument, NULL, OPT_READD},
|
2011-05-04 13:49:42 -07:00
|
|
|
|
{"flow-format", required_argument, NULL, 'F'},
|
2011-12-09 15:48:26 -08:00
|
|
|
|
{"packet-in-format", required_argument, NULL, 'P'},
|
2011-05-04 13:49:42 -07:00
|
|
|
|
{"more", no_argument, NULL, 'm'},
|
2012-02-07 16:17:13 -08:00
|
|
|
|
{"timestamp", no_argument, NULL, OPT_TIMESTAMP},
|
2012-07-12 13:32:47 -07:00
|
|
|
|
{"sort", optional_argument, NULL, OPT_SORT},
|
|
|
|
|
{"rsort", optional_argument, NULL, OPT_RSORT},
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
{"names", no_argument, &use_names, 1},
|
|
|
|
|
{"no-names", no_argument, &use_names, 0},
|
2017-06-13 17:09:05 -07:00
|
|
|
|
{"stats", no_argument, &show_stats, 1},
|
|
|
|
|
{"no-stats", no_argument, &show_stats, 0},
|
2014-07-28 10:31:25 -07:00
|
|
|
|
{"unixctl", required_argument, NULL, OPT_UNIXCTL},
|
2011-05-04 13:49:42 -07:00
|
|
|
|
{"help", no_argument, NULL, 'h'},
|
2014-09-11 17:24:35 -07:00
|
|
|
|
{"option", no_argument, NULL, 'o'},
|
2015-06-05 14:03:12 -07:00
|
|
|
|
{"bundle", no_argument, NULL, OPT_BUNDLE},
|
2016-03-02 15:56:16 +01:00
|
|
|
|
{"color", optional_argument, NULL, OPT_COLOR},
|
ofproto: Add relaxed group_mod command ADD_OR_MOD
This patch adds support for a new Group Mod command OFPGC_ADD_OR_MOD to
OVS for all OpenFlow versions that support groups (OF11 and higher).
The new ADD_OR_MOD creates a group that does not yet exist (like ADD)
and modifies an existing group (like MODIFY).
Rational: In OpenFlow 1.x the Group Mod commands OFPGC_ADD and
OFPGC_MODIFY have strict semantics: ADD fails if the group exists,
while MODIFY fails if the group does not exist. This requires a
controller to exactly know the state of the switch when programming a
group in order not run the risk of getting an OFP Error message in
response. This is hard to achieve and maintain at all times in view of
possible switch and controller restarts or other connection losses
between switch and controller.
Due to the un-acknowledged nature of the Group Mod message programming
groups safely and efficiently at the same time is virtually impossible
as the controller has to either query the existence of the group prior
to each Group Mod message or to insert a Barrier Request/Reply after
every group to be sure that no Error can be received at a later stage
and require a complicated roll-back of any dependent actions taken
between the failed Group Mod and the Error.
In the ovs-ofctl command line the ADD_OR_MOD command is made available
through the new option --may-create in the mod-group command:
$ ovs-ofctl -Oopenflow13 del-groups br-int group_id=100
$ ovs-ofctl -Oopenflow13 mod-group br-int
group_id=100,type=indirect,bucket=actions=2 OFPT_ERROR (OF1.3)
(xid=0x2): OFPGMFC_UNKNOWN_GROUP OFPT_GROUP_MOD (OF1.3) (xid=0x2):
MOD group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=2
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=3
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:3
Signed-off-by: Jan Scheurich <jan.scheurich at web.de>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-29 00:29:25 +02:00
|
|
|
|
{"may-create", no_argument, NULL, OPT_MAY_CREATE},
|
2018-01-18 14:39:50 -08:00
|
|
|
|
{"pcap", no_argument, &print_pcap, 1},
|
2018-02-14 14:40:12 -08:00
|
|
|
|
{"raw", no_argument, &raw, 1},
|
2016-08-15 18:47:29 +00:00
|
|
|
|
{"read-only", no_argument, NULL, OPT_READ_ONLY},
|
2011-12-20 15:31:34 -08:00
|
|
|
|
DAEMON_LONG_OPTIONS,
|
2012-11-19 14:59:32 +09:00
|
|
|
|
OFP_VERSION_LONG_OPTIONS,
|
2010-01-04 18:55:00 -08:00
|
|
|
|
VLOG_LONG_OPTIONS,
|
2011-05-10 09:17:37 -07:00
|
|
|
|
STREAM_SSL_LONG_OPTIONS,
|
2011-05-04 13:49:42 -07:00
|
|
|
|
{NULL, 0, NULL, 0},
|
2009-07-08 13:19:16 -07:00
|
|
|
|
};
|
2015-03-16 12:01:55 -04:00
|
|
|
|
char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
|
2012-11-28 22:22:38 -08:00
|
|
|
|
uint32_t versions;
|
|
|
|
|
enum ofputil_protocol version_protocols;
|
2018-08-14 10:53:16 +03:00
|
|
|
|
unsigned int timeout = 0;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
Enable OpenFlow 1.0, 1.1, 1.2, and 1.3 by default.
The Open vSwitch software switch now supports all the required features of
OpenFlow 1.0 through 1.3, with one known trivial exception[*]. Enable them
by default in ovs-vswitchd.
For now, ovs-ofctl only enables OpenFlow 1.0 by default. This is
because ovs-ofctl implements command such as "add-flow" as raw
OpenFlow requests, but those requests have subtly different semantics
in different OpenFlow versions. For example:
- In OpenFlow 1.0, a "mod-flow" operation that does not find any
existing flow to modify adds a new flow.
- In OpenFlow 1.1, a "mod-flow" operation that does not find any
existing flow to modify adds a new flow, but only if the
mod-flow did not match on the flow cookie.
- In OpenFlow 1.2 and a later, a "mod-flow" operation never adds a
new flow.
[*] OpenFlow 1.1, but not any earlier or later version of OpenFlow,
requires support for VLANs introduced by Ethertype 0x88a8, but Open
vSwitch does not support this Ethertype.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Reviewed-by: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
2014-04-30 06:54:09 -07:00
|
|
|
|
/* For now, ovs-ofctl only enables OpenFlow 1.0 by default. This is
|
|
|
|
|
* because ovs-ofctl implements command such as "add-flow" as raw OpenFlow
|
|
|
|
|
* requests, but those requests have subtly different semantics in
|
|
|
|
|
* different OpenFlow versions. For example:
|
|
|
|
|
*
|
|
|
|
|
* - In OpenFlow 1.0, a "mod-flow" operation that does not find any
|
|
|
|
|
* existing flow to modify adds a new flow.
|
|
|
|
|
*
|
|
|
|
|
* - In OpenFlow 1.1, a "mod-flow" operation that does not find any
|
|
|
|
|
* existing flow to modify adds a new flow, but only if the mod-flow
|
|
|
|
|
* did not match on the flow cookie.
|
|
|
|
|
*
|
|
|
|
|
* - In OpenFlow 1.2 and a later, a "mod-flow" operation never adds a
|
|
|
|
|
* new flow.
|
|
|
|
|
*/
|
|
|
|
|
set_allowed_ofp_versions("OpenFlow10");
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
for (;;) {
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
|
|
c = getopt_long(argc, argv, short_options, long_options, NULL);
|
|
|
|
|
if (c == -1) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
case 't':
|
2018-08-14 10:53:15 +03:00
|
|
|
|
if (!str_to_uint(optarg, 10, &timeout) || !timeout) {
|
|
|
|
|
ovs_fatal(0, "value %s on -t or --timeout is invalid", optarg);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2010-12-07 13:32:01 -08:00
|
|
|
|
case 'F':
|
2012-02-10 13:30:23 -08:00
|
|
|
|
allowed_protocols = ofputil_protocols_from_string(optarg);
|
|
|
|
|
if (!allowed_protocols) {
|
|
|
|
|
ovs_fatal(0, "%s: invalid flow format(s)", optarg);
|
2010-12-07 13:32:01 -08:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2011-12-09 15:48:26 -08:00
|
|
|
|
case 'P':
|
|
|
|
|
preferred_packet_in_format =
|
|
|
|
|
ofputil_packet_in_format_from_string(optarg);
|
|
|
|
|
if (preferred_packet_in_format < 0) {
|
|
|
|
|
ovs_fatal(0, "unknown packet-in format `%s'", optarg);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2010-11-23 14:34:21 -08:00
|
|
|
|
case 'm':
|
|
|
|
|
verbosity++;
|
|
|
|
|
break;
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
case 'h':
|
|
|
|
|
usage();
|
|
|
|
|
|
2014-09-11 17:24:35 -07:00
|
|
|
|
case 'o':
|
2015-03-16 12:01:55 -04:00
|
|
|
|
ovs_cmdl_print_options(long_options);
|
2014-09-11 17:24:35 -07:00
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
|
|
2015-06-05 14:03:12 -07:00
|
|
|
|
case OPT_BUNDLE:
|
|
|
|
|
bundle = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
case OPT_STRICT:
|
2009-10-23 11:49:39 -07:00
|
|
|
|
strict = true;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2016-08-15 18:47:29 +00:00
|
|
|
|
case OPT_READ_ONLY:
|
|
|
|
|
read_only = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2011-07-27 14:58:10 -07:00
|
|
|
|
case OPT_READD:
|
|
|
|
|
readd = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2012-02-07 16:17:13 -08:00
|
|
|
|
case OPT_TIMESTAMP:
|
|
|
|
|
timestamp = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2012-07-12 13:32:47 -07:00
|
|
|
|
case OPT_SORT:
|
|
|
|
|
add_sort_criterion(SORT_ASC, optarg);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OPT_RSORT:
|
|
|
|
|
add_sort_criterion(SORT_DESC, optarg);
|
|
|
|
|
break;
|
|
|
|
|
|
2014-07-28 10:31:25 -07:00
|
|
|
|
case OPT_UNIXCTL:
|
|
|
|
|
unixctl_path = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
2016-03-02 15:56:16 +01:00
|
|
|
|
case OPT_COLOR:
|
|
|
|
|
if (optarg) {
|
|
|
|
|
if (!strcasecmp(optarg, "always")
|
|
|
|
|
|| !strcasecmp(optarg, "yes")
|
|
|
|
|
|| !strcasecmp(optarg, "force")) {
|
|
|
|
|
enable_color = true;
|
|
|
|
|
} else if (!strcasecmp(optarg, "never")
|
|
|
|
|
|| !strcasecmp(optarg, "no")
|
|
|
|
|
|| !strcasecmp(optarg, "none")) {
|
|
|
|
|
enable_color = false;
|
|
|
|
|
} else if (!strcasecmp(optarg, "auto")
|
|
|
|
|
|| !strcasecmp(optarg, "tty")
|
|
|
|
|
|| !strcasecmp(optarg, "if-tty")) {
|
|
|
|
|
/* Determine whether we need colors, i.e. whether standard
|
|
|
|
|
* output is a tty. */
|
|
|
|
|
enable_color = is_stdout_a_tty();
|
|
|
|
|
} else {
|
|
|
|
|
ovs_fatal(0, "incorrect value `%s' for --color", optarg);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
enable_color = is_stdout_a_tty();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
ofproto: Add relaxed group_mod command ADD_OR_MOD
This patch adds support for a new Group Mod command OFPGC_ADD_OR_MOD to
OVS for all OpenFlow versions that support groups (OF11 and higher).
The new ADD_OR_MOD creates a group that does not yet exist (like ADD)
and modifies an existing group (like MODIFY).
Rational: In OpenFlow 1.x the Group Mod commands OFPGC_ADD and
OFPGC_MODIFY have strict semantics: ADD fails if the group exists,
while MODIFY fails if the group does not exist. This requires a
controller to exactly know the state of the switch when programming a
group in order not run the risk of getting an OFP Error message in
response. This is hard to achieve and maintain at all times in view of
possible switch and controller restarts or other connection losses
between switch and controller.
Due to the un-acknowledged nature of the Group Mod message programming
groups safely and efficiently at the same time is virtually impossible
as the controller has to either query the existence of the group prior
to each Group Mod message or to insert a Barrier Request/Reply after
every group to be sure that no Error can be received at a later stage
and require a complicated roll-back of any dependent actions taken
between the failed Group Mod and the Error.
In the ovs-ofctl command line the ADD_OR_MOD command is made available
through the new option --may-create in the mod-group command:
$ ovs-ofctl -Oopenflow13 del-groups br-int group_id=100
$ ovs-ofctl -Oopenflow13 mod-group br-int
group_id=100,type=indirect,bucket=actions=2 OFPT_ERROR (OF1.3)
(xid=0x2): OFPGMFC_UNKNOWN_GROUP OFPT_GROUP_MOD (OF1.3) (xid=0x2):
MOD group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=2
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=3
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:3
Signed-off-by: Jan Scheurich <jan.scheurich at web.de>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-29 00:29:25 +02:00
|
|
|
|
case OPT_MAY_CREATE:
|
|
|
|
|
may_create = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2011-12-20 15:31:34 -08:00
|
|
|
|
DAEMON_OPTION_HANDLERS
|
2012-11-19 14:59:32 +09:00
|
|
|
|
OFP_VERSION_OPTION_HANDLERS
|
2010-01-04 18:55:00 -08:00
|
|
|
|
VLOG_OPTION_HANDLERS
|
2010-01-06 14:35:20 -08:00
|
|
|
|
STREAM_SSL_OPTION_HANDLERS
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
case '?':
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
case 0:
|
|
|
|
|
break;
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-07-12 13:32:47 -07:00
|
|
|
|
|
2018-08-14 10:53:16 +03:00
|
|
|
|
ctl_timeout_setup(timeout);
|
|
|
|
|
|
2012-07-12 13:32:47 -07:00
|
|
|
|
if (n_criteria) {
|
|
|
|
|
/* Always do a final sort pass based on priority. */
|
|
|
|
|
add_sort_criterion(SORT_DESC, "priority");
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
free(short_options);
|
2012-11-28 22:22:38 -08:00
|
|
|
|
|
2015-06-05 14:03:12 -07:00
|
|
|
|
/* Implicit OpenFlow 1.4 with the '--bundle' option. */
|
2016-02-17 14:08:04 -08:00
|
|
|
|
if (bundle && !(get_allowed_ofp_versions() &
|
|
|
|
|
ofputil_protocols_to_version_bitmap(OFPUTIL_P_OF13_UP))) {
|
2015-06-05 14:03:12 -07:00
|
|
|
|
/* Add implicit allowance for OpenFlow 1.4. */
|
|
|
|
|
add_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
|
|
|
|
|
OFPUTIL_P_OF14_OXM));
|
2016-02-17 14:08:04 -08:00
|
|
|
|
/* Remove all versions that do not support bundles. */
|
2015-10-19 15:00:39 -07:00
|
|
|
|
mask_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
|
2016-02-17 14:08:04 -08:00
|
|
|
|
OFPUTIL_P_OF13_UP));
|
2015-06-05 14:03:12 -07:00
|
|
|
|
}
|
2012-11-28 22:22:38 -08:00
|
|
|
|
versions = get_allowed_ofp_versions();
|
|
|
|
|
version_protocols = ofputil_protocols_from_version_bitmap(versions);
|
|
|
|
|
if (!(allowed_protocols & version_protocols)) {
|
|
|
|
|
char *protocols = ofputil_protocols_to_string(allowed_protocols);
|
|
|
|
|
struct ds version_s = DS_EMPTY_INITIALIZER;
|
|
|
|
|
|
|
|
|
|
ofputil_format_version_bitmap_names(&version_s, versions);
|
|
|
|
|
ovs_fatal(0, "None of the enabled OpenFlow versions (%s) supports "
|
|
|
|
|
"any of the enabled flow formats (%s). (Use -O to enable "
|
|
|
|
|
"additional OpenFlow versions or -F to enable additional "
|
|
|
|
|
"flow formats.)", ds_cstr(&version_s), protocols);
|
|
|
|
|
}
|
|
|
|
|
allowed_protocols &= version_protocols;
|
|
|
|
|
mask_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
|
|
|
|
|
allowed_protocols));
|
2016-03-02 15:56:17 +01:00
|
|
|
|
|
|
|
|
|
colors_init(enable_color);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
usage(void)
|
|
|
|
|
{
|
|
|
|
|
printf("%s: OpenFlow switch management utility\n"
|
|
|
|
|
"usage: %s [OPTIONS] COMMAND [ARG...]\n"
|
|
|
|
|
"\nFor OpenFlow switches:\n"
|
|
|
|
|
" show SWITCH show OpenFlow information\n"
|
|
|
|
|
" dump-desc SWITCH print switch description\n"
|
|
|
|
|
" dump-tables SWITCH print table stats\n"
|
2014-03-23 23:20:04 -07:00
|
|
|
|
" dump-table-features SWITCH print table features\n"
|
2015-07-02 20:35:44 -07:00
|
|
|
|
" dump-table-desc SWITCH print table description (OF1.4+)\n"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
" mod-port SWITCH IFACE ACT modify port behavior\n"
|
2013-09-07 03:02:32 -07:00
|
|
|
|
" mod-table SWITCH MOD modify flow table behavior\n"
|
2015-07-02 20:33:08 -07:00
|
|
|
|
" OF1.1/1.2 MOD: controller, continue, drop\n"
|
2015-11-24 17:49:42 +05:30
|
|
|
|
" OF1.4+ MOD: evict, noevict, vacancy:low,high, novacancy\n"
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
" get-frags SWITCH print fragment handling behavior\n"
|
|
|
|
|
" set-frags SWITCH FRAG_MODE set fragment handling behavior\n"
|
2015-07-02 20:33:08 -07:00
|
|
|
|
" FRAG_MODE: normal, drop, reassemble, nx-match\n"
|
2010-01-19 22:35:18 -08:00
|
|
|
|
" dump-ports SWITCH [PORT] print port statistics\n"
|
2014-05-07 23:18:46 -07:00
|
|
|
|
" dump-ports-desc SWITCH [PORT] print port descriptions\n"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
" dump-flows SWITCH print all flow entries\n"
|
|
|
|
|
" dump-flows SWITCH FLOW print matching FLOWs\n"
|
|
|
|
|
" dump-aggregate SWITCH print aggregate flow statistics\n"
|
|
|
|
|
" dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n"
|
2010-09-16 15:36:57 -07:00
|
|
|
|
" queue-stats SWITCH [PORT [QUEUE]] dump queue stats\n"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
" add-flow SWITCH FLOW add flow described by FLOW\n"
|
|
|
|
|
" add-flows SWITCH FILE add flows from FILE\n"
|
|
|
|
|
" mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
|
|
|
|
|
" del-flows SWITCH [FLOW] delete matching FLOWs\n"
|
2011-06-15 17:16:51 -07:00
|
|
|
|
" replace-flows SWITCH FILE replace flows with those in FILE\n"
|
2012-01-25 14:41:22 -08:00
|
|
|
|
" diff-flows SOURCE1 SOURCE2 compare flows from two sources\n"
|
2012-01-25 16:30:28 -08:00
|
|
|
|
" packet-out SWITCH IN_PORT ACTIONS PACKET...\n"
|
|
|
|
|
" execute ACTIONS on PACKET\n"
|
2012-07-12 14:18:05 -07:00
|
|
|
|
" monitor SWITCH [MISSLEN] [invalid_ttl] [watch:[...]]\n"
|
2012-01-25 14:41:22 -08:00
|
|
|
|
" print packets received from SWITCH\n"
|
|
|
|
|
" snoop SWITCH snoop on SWITCH and its controller\n"
|
2013-09-01 18:30:17 -07:00
|
|
|
|
" add-group SWITCH GROUP add group described by GROUP\n"
|
2014-09-24 13:43:19 +09:00
|
|
|
|
" add-groups SWITCH FILE add group from FILE\n"
|
ofproto: Add relaxed group_mod command ADD_OR_MOD
This patch adds support for a new Group Mod command OFPGC_ADD_OR_MOD to
OVS for all OpenFlow versions that support groups (OF11 and higher).
The new ADD_OR_MOD creates a group that does not yet exist (like ADD)
and modifies an existing group (like MODIFY).
Rational: In OpenFlow 1.x the Group Mod commands OFPGC_ADD and
OFPGC_MODIFY have strict semantics: ADD fails if the group exists,
while MODIFY fails if the group does not exist. This requires a
controller to exactly know the state of the switch when programming a
group in order not run the risk of getting an OFP Error message in
response. This is hard to achieve and maintain at all times in view of
possible switch and controller restarts or other connection losses
between switch and controller.
Due to the un-acknowledged nature of the Group Mod message programming
groups safely and efficiently at the same time is virtually impossible
as the controller has to either query the existence of the group prior
to each Group Mod message or to insert a Barrier Request/Reply after
every group to be sure that no Error can be received at a later stage
and require a complicated roll-back of any dependent actions taken
between the failed Group Mod and the Error.
In the ovs-ofctl command line the ADD_OR_MOD command is made available
through the new option --may-create in the mod-group command:
$ ovs-ofctl -Oopenflow13 del-groups br-int group_id=100
$ ovs-ofctl -Oopenflow13 mod-group br-int
group_id=100,type=indirect,bucket=actions=2 OFPT_ERROR (OF1.3)
(xid=0x2): OFPGMFC_UNKNOWN_GROUP OFPT_GROUP_MOD (OF1.3) (xid=0x2):
MOD group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=2
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=3
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:3
Signed-off-by: Jan Scheurich <jan.scheurich at web.de>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-29 00:29:25 +02:00
|
|
|
|
" [--may-create] mod-group SWITCH GROUP modify specific group\n"
|
2013-09-01 18:30:17 -07:00
|
|
|
|
" del-groups SWITCH [GROUP] delete matching GROUPs\n"
|
2014-11-13 11:53:29 +09:00
|
|
|
|
" insert-buckets SWITCH [GROUP] add buckets to GROUP\n"
|
|
|
|
|
" remove-buckets SWITCH [GROUP] remove buckets from GROUP\n"
|
2013-09-01 18:30:17 -07:00
|
|
|
|
" dump-group-features SWITCH print group features\n"
|
2014-05-07 23:49:00 -07:00
|
|
|
|
" dump-groups SWITCH [GROUP] print group description\n"
|
2013-09-01 18:30:17 -07:00
|
|
|
|
" dump-group-stats SWITCH [GROUP] print group statistics\n"
|
2016-01-07 08:57:44 -08:00
|
|
|
|
" queue-get-config SWITCH [PORT] print queue config for PORT\n"
|
2013-09-13 15:03:33 -07:00
|
|
|
|
" add-meter SWITCH METER add meter described by METER\n"
|
|
|
|
|
" mod-meter SWITCH METER modify specific METER\n"
|
2018-06-29 12:02:28 -07:00
|
|
|
|
" del-meters SWITCH [METER] delete meters matching METER\n"
|
|
|
|
|
" dump-meters SWITCH [METER] print METER configuration\n"
|
2013-09-13 15:03:33 -07:00
|
|
|
|
" meter-stats SWITCH [METER] print meter statistics\n"
|
|
|
|
|
" meter-features SWITCH print meter features\n"
|
2015-12-16 02:47:50 +08:00
|
|
|
|
" add-tlv-map SWITCH MAP add TLV option MAPpings\n"
|
|
|
|
|
" del-tlv-map SWITCH [MAP] delete TLV option MAPpings\n"
|
|
|
|
|
" dump-tlv-map SWITCH print TLV option mappings\n"
|
ipfix: Add support for exporting ipfix statistics.
It is meaningful for user to check the stats of IPFIX.
Using IPFIX stats, user can know how much flows the system
can support. It is also can be used for performance check
of IPFIX.
IPFIX stats is added for per IPFIX exporter. If bridge IPFIX is
enabled on the bridge, the whole bridge will have one exporter.
For flow IPFIX, the system keeps per id (column in
Flow_Sample_Collector_Set) per exporter.
1) Add 'ovs-ofctl dump-ipfix-bridge SWITCH' to export IPFIX stats of
the bridge which enable bridge IPFIX. The output format:
NXST_IPFIX_BRIDGE reply (xid=0x2):
bridge ipfix: flows=0, current flows=0, sampled pkts=0, \
ipv4 ok=0, ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
2) Add 'ovs-ofctl dump-ipfix-flow SWITCH' to export IPFIX stats of
the bridge which enable flow IPFIX. The output format:
NXST_IPFIX_FLOW reply (xid=0x2): 2 ids
id 1: flows=4, current flows=4, sampled pkts=14, ipv4 ok=13, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
id 2: flows=0, current flows=0, sampled pkts=0, ipv4 ok=0, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
flows: the number of total flow records, including those exported.
current flows: the number of current flow records cached.
sampled pkts: Successfully sampled packet count.
ipv4 ok: successfully sampled IPv4 flow packet count.
ipv6 ok: Successfully sampled IPv6 flow packet count.
tx pkts: the count of IPFIX exported packets sent to the collector(s).
pkts errs: count of packets failed when sampling, maybe not supported or other error.
ipv4 errs: Count of IPV4 flow packet in the error packets.
ipv6 errs: Count of IPV6 flow packet in the error packets.
tx errs: the count of IPFIX exported packets failed when sending to the collector(s).
Signed-off-by: Benli Ye <daniely@vmware.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-13 14:44:09 -07:00
|
|
|
|
" dump-ipfix-bridge SWITCH print ipfix stats of bridge\n"
|
|
|
|
|
" dump-ipfix-flow SWITCH print flow ipfix of a bridge\n"
|
2016-08-18 14:09:41 -07:00
|
|
|
|
" ct-flush-zone SWITCH ZONE flush conntrack entries in ZONE\n"
|
2023-01-16 12:45:08 +01:00
|
|
|
|
" ct-flush SWITCH [ZONE] [CT_ORIG_TUPLE [CT_REPLY_TUPLE]]\n"
|
|
|
|
|
" flush conntrack entries specified\n"
|
|
|
|
|
" by CT_ORIG/REPLY_TUPLE and ZONE\n"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
"\nFor OpenFlow switches and controllers:\n"
|
2011-11-30 13:07:38 -08:00
|
|
|
|
" probe TARGET probe whether TARGET is up\n"
|
|
|
|
|
" ping TARGET [N] latency of N-byte echos\n"
|
|
|
|
|
" benchmark TARGET N COUNT bandwidth of COUNT N-byte echos\n"
|
2013-08-06 09:45:07 -07:00
|
|
|
|
"SWITCH or TARGET is an active OpenFlow connection method.\n"
|
|
|
|
|
"\nOther commands:\n"
|
2013-11-22 13:17:23 -08:00
|
|
|
|
" ofp-parse FILE print messages read from FILE\n"
|
|
|
|
|
" ofp-parse-pcap PCAP print OpenFlow read from PCAP\n",
|
2009-07-08 13:19:16 -07:00
|
|
|
|
program_name, program_name);
|
|
|
|
|
vconn_usage(true, false, false);
|
2011-12-20 15:31:34 -08:00
|
|
|
|
daemon_usage();
|
2012-11-19 14:59:32 +09:00
|
|
|
|
ofp_version_usage();
|
2009-07-08 13:19:16 -07:00
|
|
|
|
vlog_usage();
|
|
|
|
|
printf("\nOther options:\n"
|
|
|
|
|
" --strict use strict match for flow commands\n"
|
2016-08-15 18:47:29 +00:00
|
|
|
|
" --read-only do not execute read/write commands\n"
|
2011-07-27 14:58:10 -07:00
|
|
|
|
" --readd replace flows that haven't changed\n"
|
2010-12-07 13:32:01 -08:00
|
|
|
|
" -F, --flow-format=FORMAT force particular flow format\n"
|
2011-12-09 15:48:26 -08:00
|
|
|
|
" -P, --packet-in-format=FRMT force particular packet in format\n"
|
2010-11-23 14:34:21 -08:00
|
|
|
|
" -m, --more be more verbose printing OpenFlow\n"
|
2012-02-07 16:17:13 -08:00
|
|
|
|
" --timestamp (monitor, snoop) print timestamps\n"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
" -t, --timeout=SECS give up after SECS seconds\n"
|
2012-07-12 13:32:47 -07:00
|
|
|
|
" --sort[=field] sort in ascending order\n"
|
|
|
|
|
" --rsort[=field] sort in descending order\n"
|
2017-05-31 16:06:12 -07:00
|
|
|
|
" --names show port names instead of numbers\n"
|
2018-04-04 02:30:09 -07:00
|
|
|
|
" --no-names show port numbers, but not names\n"
|
2014-07-28 10:31:25 -07:00
|
|
|
|
" --unixctl=SOCKET set control socket name\n"
|
2016-03-02 15:56:16 +01:00
|
|
|
|
" --color[=always|never|auto] control use of color in output\n"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
" -h, --help display this help message\n"
|
|
|
|
|
" -V, --version display version information\n");
|
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-20 15:31:34 -08:00
|
|
|
|
static void
|
|
|
|
|
ofctl_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
|
|
|
|
const char *argv[] OVS_UNUSED, void *exiting_)
|
|
|
|
|
{
|
|
|
|
|
bool *exiting = exiting_;
|
|
|
|
|
*exiting = true;
|
2012-02-14 20:53:59 -08:00
|
|
|
|
unixctl_command_reply(conn, NULL);
|
2011-12-20 15:31:34 -08:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void run(int retval, const char *message, ...)
|
2014-12-15 14:10:38 +01:00
|
|
|
|
OVS_PRINTF_FORMAT(2, 3);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2012-11-15 21:28:56 -08:00
|
|
|
|
static void
|
|
|
|
|
run(int retval, const char *message, ...)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
if (retval) {
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
va_start(args, message);
|
2011-03-31 14:50:58 -07:00
|
|
|
|
ovs_fatal_valist(retval, message, args);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generic commands. */
|
|
|
|
|
|
2012-10-10 13:33:54 -07:00
|
|
|
|
static int
|
2010-01-22 14:37:10 -05:00
|
|
|
|
open_vconn_socket(const char *name, struct vconn **vconnp)
|
|
|
|
|
{
|
|
|
|
|
char *vconn_name = xasprintf("unix:%s", name);
|
2012-10-10 13:33:54 -07:00
|
|
|
|
int error;
|
|
|
|
|
|
2013-01-02 17:10:43 -08:00
|
|
|
|
error = vconn_open(vconn_name, get_allowed_ofp_versions(), DSCP_DEFAULT,
|
|
|
|
|
vconnp);
|
2012-10-10 13:33:54 -07:00
|
|
|
|
if (error && error != ENOENT) {
|
|
|
|
|
ovs_fatal(0, "%s: failed to open socket (%s)", name,
|
2013-06-24 10:54:49 -07:00
|
|
|
|
ovs_strerror(error));
|
2012-10-10 13:33:54 -07:00
|
|
|
|
}
|
2010-01-22 14:37:10 -05:00
|
|
|
|
free(vconn_name);
|
2012-10-10 13:33:54 -07:00
|
|
|
|
|
|
|
|
|
return error;
|
2010-01-22 14:37:10 -05:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-04 12:41:01 -08:00
|
|
|
|
enum open_target { MGMT, SNOOP };
|
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
static enum ofputil_protocol
|
2013-01-04 12:41:01 -08:00
|
|
|
|
open_vconn__(const char *name, enum open_target target,
|
2010-05-11 12:44:58 -07:00
|
|
|
|
struct vconn **vconnp)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2013-01-04 12:41:01 -08:00
|
|
|
|
const char *suffix = target == MGMT ? "mgmt" : "snoop";
|
2011-04-11 15:08:19 -07:00
|
|
|
|
char *datapath_name, *datapath_type, *socket_name;
|
2012-02-10 13:30:23 -08:00
|
|
|
|
enum ofputil_protocol protocol;
|
2011-04-11 15:08:19 -07:00
|
|
|
|
char *bridge_path;
|
2012-02-10 13:30:23 -08:00
|
|
|
|
int ofp_version;
|
2012-10-10 13:33:54 -07:00
|
|
|
|
int error;
|
2010-01-22 14:37:10 -05:00
|
|
|
|
|
2013-01-04 12:41:01 -08:00
|
|
|
|
bridge_path = xasprintf("%s/%s.%s", ovs_rundir(), name, suffix);
|
2011-04-11 15:08:19 -07:00
|
|
|
|
|
|
|
|
|
ofproto_parse_name(name, &datapath_name, &datapath_type);
|
2013-01-04 12:41:01 -08:00
|
|
|
|
socket_name = xasprintf("%s/%s.%s", ovs_rundir(), datapath_name, suffix);
|
2011-04-11 15:08:19 -07:00
|
|
|
|
free(datapath_name);
|
|
|
|
|
free(datapath_type);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-07-21 11:12:45 -07:00
|
|
|
|
if (strchr(name, ':')) {
|
2013-01-04 12:37:17 -08:00
|
|
|
|
run(vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp),
|
2012-11-19 14:59:32 +09:00
|
|
|
|
"connecting to %s", name);
|
2012-10-10 13:33:54 -07:00
|
|
|
|
} else if (!open_vconn_socket(name, vconnp)) {
|
|
|
|
|
/* Fall Through. */
|
|
|
|
|
} else if (!open_vconn_socket(bridge_path, vconnp)) {
|
|
|
|
|
/* Fall Through. */
|
|
|
|
|
} else if (!open_vconn_socket(socket_name, vconnp)) {
|
|
|
|
|
/* Fall Through. */
|
2009-07-08 13:19:16 -07:00
|
|
|
|
} else {
|
2019-09-24 15:41:22 +02:00
|
|
|
|
free(bridge_path);
|
|
|
|
|
free(socket_name);
|
2011-07-20 14:31:54 -07:00
|
|
|
|
ovs_fatal(0, "%s is not a bridge or a socket", name);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2010-01-22 14:37:10 -05:00
|
|
|
|
|
2013-01-04 12:41:01 -08:00
|
|
|
|
if (target == SNOOP) {
|
|
|
|
|
vconn_set_recv_any_version(*vconnp);
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-22 14:37:10 -05:00
|
|
|
|
free(bridge_path);
|
2011-04-11 15:08:19 -07:00
|
|
|
|
free(socket_name);
|
2012-02-10 13:30:23 -08:00
|
|
|
|
|
2012-10-10 13:33:54 -07:00
|
|
|
|
VLOG_DBG("connecting to %s", vconn_get_name(*vconnp));
|
2019-01-09 20:30:17 +03:00
|
|
|
|
error = vconn_connect_block(*vconnp, -1);
|
2012-10-10 13:33:54 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s: failed to connect to socket (%s)", name,
|
2013-06-24 10:54:49 -07:00
|
|
|
|
ovs_strerror(error));
|
2012-10-10 13:33:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
ofp_version = vconn_get_version(*vconnp);
|
|
|
|
|
protocol = ofputil_protocol_from_ofp_version(ofp_version);
|
|
|
|
|
if (!protocol) {
|
|
|
|
|
ovs_fatal(0, "%s: unsupported OpenFlow version 0x%02x",
|
|
|
|
|
name, ofp_version);
|
|
|
|
|
}
|
|
|
|
|
return protocol;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
static enum ofputil_protocol
|
2010-05-11 12:44:58 -07:00
|
|
|
|
open_vconn(const char *name, struct vconn **vconnp)
|
|
|
|
|
{
|
2013-01-04 12:41:01 -08:00
|
|
|
|
return open_vconn__(name, MGMT, vconnp);
|
2010-05-11 12:44:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
|
|
|
|
send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer)
|
|
|
|
|
{
|
|
|
|
|
run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2012-11-19 14:59:32 +09:00
|
|
|
|
dump_transaction(struct vconn *vconn, struct ofpbuf *request)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2015-12-24 15:44:31 -08:00
|
|
|
|
const struct ofp_header *oh = request->data;
|
|
|
|
|
if (ofpmsg_is_stat_request(oh)) {
|
|
|
|
|
ovs_be32 send_xid = oh->xid;
|
|
|
|
|
enum ofpraw request_raw;
|
|
|
|
|
enum ofpraw reply_raw;
|
|
|
|
|
bool done = false;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2015-12-24 15:44:31 -08:00
|
|
|
|
ofpraw_decode_partial(&request_raw, request->data, request->size);
|
|
|
|
|
reply_raw = ofpraw_stats_request_to_reply(request_raw, oh->version);
|
2012-07-19 23:23:17 -07:00
|
|
|
|
|
2015-12-24 15:44:31 -08:00
|
|
|
|
send_openflow_buffer(vconn, request);
|
|
|
|
|
while (!done) {
|
|
|
|
|
ovs_be32 recv_xid;
|
|
|
|
|
struct ofpbuf *reply;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2015-12-24 15:44:31 -08:00
|
|
|
|
run(vconn_recv_block(vconn, &reply),
|
|
|
|
|
"OpenFlow packet receive failed");
|
|
|
|
|
recv_xid = ((struct ofp_header *) reply->data)->xid;
|
|
|
|
|
if (send_xid == recv_xid) {
|
2018-02-27 17:34:14 -08:00
|
|
|
|
enum ofpraw ofpraw;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_print(stdout, reply->data, reply->size,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ports_to_show(vconn_get_name(vconn)),
|
|
|
|
|
tables_to_show(vconn_get_name(vconn)),
|
|
|
|
|
verbosity + 1);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2018-02-27 17:34:14 -08:00
|
|
|
|
ofpraw_decode(&ofpraw, reply->data);
|
|
|
|
|
if (ofptype_from_ofpraw(ofpraw) == OFPTYPE_ERROR) {
|
2015-12-24 15:44:31 -08:00
|
|
|
|
done = true;
|
2018-02-27 17:34:14 -08:00
|
|
|
|
} else if (ofpraw == reply_raw) {
|
2015-12-24 15:44:31 -08:00
|
|
|
|
done = !ofpmp_more(reply->data);
|
|
|
|
|
} else {
|
|
|
|
|
ovs_fatal(0, "received bad reply: %s",
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_to_string(
|
|
|
|
|
reply->data, reply->size,
|
|
|
|
|
ports_to_show(vconn_get_name(vconn)),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_show(vconn_get_name(vconn)),
|
2017-05-31 16:06:12 -07:00
|
|
|
|
verbosity + 1));
|
2015-12-24 15:44:31 -08:00
|
|
|
|
}
|
2012-06-11 11:15:31 -07:00
|
|
|
|
} else {
|
2015-12-24 15:44:31 -08:00
|
|
|
|
VLOG_DBG("received reply with xid %08"PRIx32" "
|
|
|
|
|
"!= expected %08"PRIx32, recv_xid, send_xid);
|
2012-06-11 11:15:31 -07:00
|
|
|
|
}
|
2015-12-24 15:44:31 -08:00
|
|
|
|
ofpbuf_delete(reply);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2015-12-24 15:44:31 -08:00
|
|
|
|
} else {
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
|
|
|
|
|
run(vconn_transact(vconn, request, &reply), "talking to %s",
|
|
|
|
|
vconn_get_name(vconn));
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_print(stdout, reply->data, reply->size,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ports_to_show(vconn_get_name(vconn)),
|
|
|
|
|
tables_to_show(vconn_get_name(vconn)),
|
|
|
|
|
verbosity + 1);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
}
|
2012-07-03 10:25:35 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2018-02-27 17:34:14 -08:00
|
|
|
|
dump_trivial_transaction(const char *vconn_name, enum ofpraw ofpraw)
|
2012-07-03 10:25:35 -07:00
|
|
|
|
{
|
2012-08-21 13:55:37 +09:00
|
|
|
|
struct ofpbuf *request;
|
2012-07-03 10:25:35 -07:00
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
|
|
|
|
open_vconn(vconn_name, &vconn);
|
2018-02-27 17:34:14 -08:00
|
|
|
|
request = ofpraw_alloc(ofpraw, vconn_get_version(vconn), 0);
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, request);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-07 10:19:40 -07:00
|
|
|
|
/* Sends all of the 'requests', which should be requests that only have replies
|
|
|
|
|
* if an error occurs, and waits for them to succeed or fail. If an error does
|
|
|
|
|
* occur, prints it and exits with an error.
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
*
|
|
|
|
|
* Destroys all of the 'requests'. */
|
2010-11-16 10:50:52 -08:00
|
|
|
|
static void
|
2014-12-15 14:10:38 +01:00
|
|
|
|
transact_multiple_noreply(struct vconn *vconn, struct ovs_list *requests)
|
2010-11-16 10:50:52 -08:00
|
|
|
|
{
|
2015-06-05 14:03:12 -07:00
|
|
|
|
struct ofpbuf *reply;
|
2010-12-07 13:32:01 -08:00
|
|
|
|
|
|
|
|
|
run(vconn_transact_multiple_noreply(vconn, requests, &reply),
|
2010-11-16 10:50:52 -08:00
|
|
|
|
"talking to %s", vconn_get_name(vconn));
|
|
|
|
|
if (reply) {
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_print(stderr, reply->data, reply->size,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ports_to_show(vconn_get_name(vconn)),
|
|
|
|
|
tables_to_show(vconn_get_name(vconn)),
|
|
|
|
|
verbosity + 2);
|
2010-11-16 10:50:52 -08:00
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-29 16:52:03 -07:00
|
|
|
|
/* Frees the error messages as they are printed. */
|
2015-06-05 14:03:12 -07:00
|
|
|
|
static void
|
2017-05-31 16:06:12 -07:00
|
|
|
|
bundle_print_errors(struct ovs_list *errors, struct ovs_list *requests,
|
|
|
|
|
const char *vconn_name)
|
2015-06-05 14:03:12 -07:00
|
|
|
|
{
|
2022-03-23 12:56:14 +01:00
|
|
|
|
struct ofpbuf *error;
|
2016-07-29 16:52:03 -07:00
|
|
|
|
struct ofpbuf *bmsg;
|
|
|
|
|
|
|
|
|
|
INIT_CONTAINER(bmsg, requests, list_node);
|
|
|
|
|
|
2022-03-23 12:56:14 +01:00
|
|
|
|
LIST_FOR_EACH_SAFE (error, list_node, errors) {
|
2017-06-13 16:04:29 -07:00
|
|
|
|
const struct ofp_header *error_oh = error->data;
|
|
|
|
|
ovs_be32 error_xid = error_oh->xid;
|
2016-07-29 16:52:03 -07:00
|
|
|
|
enum ofperr ofperr;
|
|
|
|
|
struct ofpbuf payload;
|
|
|
|
|
|
2017-06-13 16:04:29 -07:00
|
|
|
|
ofperr = ofperr_decode_msg(error_oh, &payload);
|
2016-07-29 16:52:03 -07:00
|
|
|
|
if (!ofperr) {
|
|
|
|
|
fprintf(stderr, "***decode error***");
|
|
|
|
|
} else {
|
|
|
|
|
/* Default to the likely truncated message. */
|
|
|
|
|
const struct ofp_header *ofp_msg = payload.data;
|
|
|
|
|
size_t msg_len = payload.size;
|
|
|
|
|
|
|
|
|
|
/* Find the failing message from the requests list to be able to
|
|
|
|
|
* dump the whole message. We assume the errors are returned in
|
|
|
|
|
* the same order as in which the messages are sent to get O(n)
|
|
|
|
|
* rather than O(n^2) processing here. If this heuristics fails we
|
|
|
|
|
* may print the truncated hexdumps instead. */
|
|
|
|
|
LIST_FOR_EACH_CONTINUE (bmsg, list_node, requests) {
|
|
|
|
|
const struct ofp_header *oh = bmsg->data;
|
|
|
|
|
|
2017-06-13 16:04:29 -07:00
|
|
|
|
if (oh->xid == error_xid) {
|
2016-07-29 16:52:03 -07:00
|
|
|
|
ofp_msg = oh;
|
|
|
|
|
msg_len = bmsg->size;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fprintf(stderr, "Error %s for: ", ofperr_get_name(ofperr));
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_print(stderr, ofp_msg, msg_len, ports_to_show(vconn_name),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_show(vconn_name), verbosity + 1);
|
2016-07-29 16:52:03 -07:00
|
|
|
|
}
|
2016-11-21 13:42:41 -08:00
|
|
|
|
ofpbuf_uninit(&payload);
|
2017-06-13 16:04:29 -07:00
|
|
|
|
ofpbuf_delete(error);
|
2016-07-29 16:52:03 -07:00
|
|
|
|
}
|
2015-06-05 14:03:12 -07:00
|
|
|
|
fflush(stderr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bundle_transact(struct vconn *vconn, struct ovs_list *requests, uint16_t flags)
|
|
|
|
|
{
|
2016-07-29 16:52:03 -07:00
|
|
|
|
struct ovs_list errors;
|
|
|
|
|
int retval = vconn_bundle_transact(vconn, requests, flags, &errors);
|
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
bundle_print_errors(&errors, requests, vconn_get_name(vconn));
|
2016-07-29 16:52:03 -07:00
|
|
|
|
|
|
|
|
|
if (retval) {
|
|
|
|
|
ovs_fatal(retval, "talking to %s", vconn_get_name(vconn));
|
|
|
|
|
}
|
2015-06-05 14:03:12 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 13:32:01 -08:00
|
|
|
|
/* Sends 'request', which should be a request that only has a reply if an error
|
|
|
|
|
* occurs, and waits for it to succeed or fail. If an error does occur, prints
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
* it and exits with an error.
|
|
|
|
|
*
|
|
|
|
|
* Destroys 'request'. */
|
2010-12-07 13:32:01 -08:00
|
|
|
|
static void
|
|
|
|
|
transact_noreply(struct vconn *vconn, struct ofpbuf *request)
|
|
|
|
|
{
|
2014-12-15 14:10:38 +01:00
|
|
|
|
struct ovs_list requests;
|
2010-12-07 13:32:01 -08:00
|
|
|
|
|
2016-03-25 14:10:22 -07:00
|
|
|
|
ovs_list_init(&requests);
|
|
|
|
|
ovs_list_push_back(&requests, &request->list_node);
|
2010-12-07 13:32:01 -08:00
|
|
|
|
transact_multiple_noreply(vconn, &requests);
|
|
|
|
|
}
|
|
|
|
|
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
static void
|
2015-12-21 15:39:10 -08:00
|
|
|
|
fetch_switch_config(struct vconn *vconn, struct ofputil_switch_config *config)
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
{
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct ofpbuf *reply;
|
2012-07-19 23:23:17 -07:00
|
|
|
|
enum ofptype type;
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
|
2012-11-19 14:59:32 +09:00
|
|
|
|
request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST,
|
|
|
|
|
vconn_get_version(vconn), 0);
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
run(vconn_transact(vconn, request, &reply),
|
|
|
|
|
"talking to %s", vconn_get_name(vconn));
|
|
|
|
|
|
2015-12-21 15:39:10 -08:00
|
|
|
|
if (ofptype_decode(&type, reply->data)
|
|
|
|
|
|| type != OFPTYPE_GET_CONFIG_REPLY) {
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn));
|
|
|
|
|
}
|
2015-12-21 15:39:10 -08:00
|
|
|
|
ofputil_decode_get_config_reply(reply->data, config);
|
2012-02-03 12:33:06 -08:00
|
|
|
|
ofpbuf_delete(reply);
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-12-21 15:39:10 -08:00
|
|
|
|
set_switch_config(struct vconn *vconn,
|
|
|
|
|
const struct ofputil_switch_config *config)
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
{
|
2015-12-21 15:39:10 -08:00
|
|
|
|
enum ofp_version version = vconn_get_version(vconn);
|
|
|
|
|
transact_noreply(vconn, ofputil_encode_set_config(config, version));
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_show(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
const char *vconn_name = ctx->argv[1];
|
2014-05-08 21:20:22 -07:00
|
|
|
|
enum ofp_version version;
|
2012-05-04 17:27:16 -07:00
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct ofpbuf *reply;
|
2014-05-08 21:20:22 -07:00
|
|
|
|
bool has_ports;
|
2012-05-04 17:27:16 -07:00
|
|
|
|
|
|
|
|
|
open_vconn(vconn_name, &vconn);
|
2014-05-08 21:20:22 -07:00
|
|
|
|
version = vconn_get_version(vconn);
|
|
|
|
|
request = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, version, 0);
|
2012-05-04 17:27:16 -07:00
|
|
|
|
run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
|
|
|
|
|
|
2014-05-08 21:20:22 -07:00
|
|
|
|
has_ports = ofputil_switch_features_has_ports(reply);
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ofp_print(stdout, reply->data, reply->size, NULL, NULL, verbosity + 1);
|
2012-05-04 17:27:16 -07:00
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
|
2014-05-08 21:20:22 -07:00
|
|
|
|
if (!has_ports) {
|
2014-05-07 23:18:46 -07:00
|
|
|
|
request = ofputil_encode_port_desc_stats_request(version, OFPP_ANY);
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, request);
|
2012-05-04 17:27:16 -07:00
|
|
|
|
}
|
2012-07-19 23:23:17 -07:00
|
|
|
|
dump_trivial_transaction(vconn_name, OFPRAW_OFPT_GET_CONFIG_REQUEST);
|
2012-11-19 14:59:32 +09:00
|
|
|
|
vconn_close(vconn);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_desc(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_trivial_transaction(ctx->argv[1], OFPRAW_OFPST_DESC_REQUEST);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_tables(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_trivial_transaction(ctx->argv[1], OFPRAW_OFPST_TABLE_REQUEST);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-23 23:20:04 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_table_features(struct ovs_cmdl_context *ctx)
|
2014-03-23 23:20:04 -07:00
|
|
|
|
{
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
2014-03-23 23:20:04 -07:00
|
|
|
|
request = ofputil_encode_table_features_request(vconn_get_version(vconn));
|
2015-07-06 22:15:40 -07:00
|
|
|
|
|
2015-12-24 15:44:31 -08:00
|
|
|
|
/* The following is similar to dump_trivial_transaction(), but it
|
2015-07-06 22:15:40 -07:00
|
|
|
|
* maintains the previous 'ofputil_table_features' from one stats reply
|
|
|
|
|
* message to the next, which allows duplication to be eliminated in the
|
|
|
|
|
* output across messages. Otherwise the output is much larger and harder
|
|
|
|
|
* to read, because only 17 or so ofputil_table_features elements fit in a
|
|
|
|
|
* single 64 kB OpenFlow message and therefore you get a ton of repetition
|
|
|
|
|
* (every 17th element is printed in full instead of abbreviated). */
|
|
|
|
|
|
|
|
|
|
const struct ofp_header *request_oh = request->data;
|
|
|
|
|
ovs_be32 send_xid = request_oh->xid;
|
|
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
|
|
struct ofputil_table_features prev;
|
2018-08-27 14:43:39 -07:00
|
|
|
|
int first_ditto = -1, last_ditto = -1;
|
|
|
|
|
struct ds s = DS_EMPTY_INITIALIZER;
|
2015-07-06 22:15:40 -07:00
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
|
|
send_openflow_buffer(vconn, request);
|
|
|
|
|
while (!done) {
|
|
|
|
|
ovs_be32 recv_xid;
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
|
|
|
|
|
run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
|
|
|
|
|
recv_xid = ((struct ofp_header *) reply->data)->xid;
|
|
|
|
|
if (send_xid == recv_xid) {
|
|
|
|
|
enum ofptype type;
|
|
|
|
|
enum ofperr error;
|
|
|
|
|
error = ofptype_decode(&type, reply->data);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "decode error: %s", ofperr_get_name(error));
|
|
|
|
|
} else if (type == OFPTYPE_ERROR) {
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ofp_print(stdout, reply->data, reply->size, NULL, NULL,
|
2017-05-31 16:06:12 -07:00
|
|
|
|
verbosity + 1);
|
2015-07-06 22:15:40 -07:00
|
|
|
|
done = true;
|
|
|
|
|
} else if (type == OFPTYPE_TABLE_FEATURES_STATS_REPLY) {
|
|
|
|
|
done = !ofpmp_more(reply->data);
|
|
|
|
|
for (;;) {
|
|
|
|
|
struct ofputil_table_features tf;
|
2018-08-29 11:30:13 -07:00
|
|
|
|
struct ofpbuf raw_properties;
|
|
|
|
|
int retval = ofputil_decode_table_features(
|
|
|
|
|
reply, &tf, &raw_properties);
|
2015-07-06 22:15:40 -07:00
|
|
|
|
if (retval) {
|
|
|
|
|
if (retval != EOF) {
|
|
|
|
|
ovs_fatal(0, "decode error: %s",
|
|
|
|
|
ofperr_get_name(retval));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-16 14:03:51 -08:00
|
|
|
|
ofputil_table_features_format(
|
|
|
|
|
&s, &tf, n ? &prev : NULL, NULL, NULL,
|
2018-08-27 14:43:39 -07:00
|
|
|
|
&first_ditto, &last_ditto);
|
2015-07-06 22:15:40 -07:00
|
|
|
|
|
|
|
|
|
prev = tf;
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ovs_fatal(0, "received bad reply: %s",
|
|
|
|
|
ofp_to_string(reply->data, reply->size,
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ports_to_show(ctx->argv[1]),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_show(ctx->argv[1]),
|
2015-07-06 22:15:40 -07:00
|
|
|
|
verbosity + 1));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
VLOG_DBG("received reply with xid %08"PRIx32" "
|
|
|
|
|
"!= expected %08"PRIx32, recv_xid, send_xid);
|
|
|
|
|
}
|
|
|
|
|
ofpbuf_delete(reply);
|
2014-03-23 23:20:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-27 14:43:39 -07:00
|
|
|
|
ofputil_table_features_format_finish(&s, first_ditto, last_ditto);
|
|
|
|
|
const char *p = ds_cstr(&s);
|
|
|
|
|
puts(p + (*p == '\n'));
|
|
|
|
|
ds_destroy(&s);
|
|
|
|
|
|
2014-03-23 23:20:04 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 20:35:44 -07:00
|
|
|
|
static void
|
|
|
|
|
ofctl_dump_table_desc(struct ovs_cmdl_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
|
|
|
|
request = ofputil_encode_table_desc_request(vconn_get_version(vconn));
|
|
|
|
|
if (request) {
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, request);
|
2015-07-02 20:35:44 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-07 10:33:34 -07:00
|
|
|
|
static bool
|
2015-11-03 16:38:13 -08:00
|
|
|
|
str_to_ofp(const char *s, ofp_port_t *ofp_port)
|
2010-01-19 22:35:18 -08:00
|
|
|
|
{
|
2015-11-03 16:38:13 -08:00
|
|
|
|
bool ret;
|
|
|
|
|
uint32_t port_;
|
|
|
|
|
|
|
|
|
|
ret = str_to_uint(s, 10, &port_);
|
|
|
|
|
*ofp_port = u16_to_ofp(port_);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct port_iterator {
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
|
|
|
|
enum { PI_FEATURES, PI_PORT_DESC } variant;
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
ovs_be32 send_xid;
|
|
|
|
|
bool more;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
port_iterator_fetch_port_desc(struct port_iterator *pi)
|
|
|
|
|
{
|
|
|
|
|
pi->variant = PI_PORT_DESC;
|
|
|
|
|
pi->more = true;
|
|
|
|
|
|
|
|
|
|
struct ofpbuf *rq = ofputil_encode_port_desc_stats_request(
|
|
|
|
|
vconn_get_version(pi->vconn), OFPP_ANY);
|
|
|
|
|
pi->send_xid = ((struct ofp_header *) rq->data)->xid;
|
|
|
|
|
send_openflow_buffer(pi->vconn, rq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
port_iterator_fetch_features(struct port_iterator *pi)
|
|
|
|
|
{
|
|
|
|
|
pi->variant = PI_FEATURES;
|
2010-01-19 22:35:18 -08:00
|
|
|
|
|
2010-11-16 10:28:10 -08:00
|
|
|
|
/* Fetch the switch's ofp_switch_features. */
|
2015-11-03 16:38:13 -08:00
|
|
|
|
enum ofp_version version = vconn_get_version(pi->vconn);
|
|
|
|
|
struct ofpbuf *rq = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, version, 0);
|
|
|
|
|
run(vconn_transact(pi->vconn, rq, &pi->reply),
|
|
|
|
|
"talking to %s", vconn_get_name(pi->vconn));
|
2010-01-19 22:35:18 -08:00
|
|
|
|
|
2015-11-03 16:38:13 -08:00
|
|
|
|
enum ofptype type;
|
|
|
|
|
if (ofptype_decode(&type, pi->reply->data)
|
2012-07-19 23:23:17 -07:00
|
|
|
|
|| type != OFPTYPE_FEATURES_REPLY) {
|
2015-11-03 16:38:13 -08:00
|
|
|
|
ovs_fatal(0, "%s: received bad features reply",
|
|
|
|
|
vconn_get_name(pi->vconn));
|
2010-11-16 10:28:10 -08:00
|
|
|
|
}
|
2015-11-03 16:38:13 -08:00
|
|
|
|
if (!ofputil_switch_features_has_ports(pi->reply)) {
|
2014-05-08 21:20:22 -07:00
|
|
|
|
/* The switch features reply does not contain a complete list of ports.
|
|
|
|
|
* Probably, there are more ports than will fit into a single 64 kB
|
|
|
|
|
* OpenFlow message. Use OFPST_PORT_DESC to get a complete list of
|
|
|
|
|
* ports. */
|
2015-11-03 16:38:13 -08:00
|
|
|
|
ofpbuf_delete(pi->reply);
|
|
|
|
|
pi->reply = NULL;
|
|
|
|
|
port_iterator_fetch_port_desc(pi);
|
|
|
|
|
return;
|
2012-05-07 10:33:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 16:38:13 -08:00
|
|
|
|
struct ofputil_switch_features features;
|
2016-01-20 16:33:13 -08:00
|
|
|
|
enum ofperr error = ofputil_pull_switch_features(pi->reply, &features);
|
2012-02-15 16:33:04 -08:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s: failed to decode features reply (%s)",
|
2015-11-03 16:38:13 -08:00
|
|
|
|
vconn_get_name(pi->vconn), ofperr_to_string(error));
|
2012-02-15 16:33:04 -08:00
|
|
|
|
}
|
2015-11-03 16:38:13 -08:00
|
|
|
|
}
|
2010-11-16 10:28:10 -08:00
|
|
|
|
|
2015-11-03 16:38:13 -08:00
|
|
|
|
/* Initializes 'pi' to prepare for iterating through all of the ports on the
|
|
|
|
|
* OpenFlow switch to which 'vconn' is connected.
|
|
|
|
|
*
|
|
|
|
|
* During iteration, the client should not make other use of 'vconn', because
|
|
|
|
|
* that can cause other messages to be interleaved with the replies used by the
|
|
|
|
|
* iterator and thus some ports may be missed or a hang can occur. */
|
|
|
|
|
static void
|
|
|
|
|
port_iterator_init(struct port_iterator *pi, struct vconn *vconn)
|
|
|
|
|
{
|
|
|
|
|
memset(pi, 0, sizeof *pi);
|
|
|
|
|
pi->vconn = vconn;
|
|
|
|
|
if (vconn_get_version(vconn) < OFP13_VERSION) {
|
|
|
|
|
port_iterator_fetch_features(pi);
|
|
|
|
|
} else {
|
|
|
|
|
port_iterator_fetch_port_desc(pi);
|
2010-01-19 22:35:18 -08:00
|
|
|
|
}
|
2012-05-07 10:33:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 16:38:13 -08:00
|
|
|
|
/* Obtains the next port from 'pi'. On success, initializes '*pp' with the
|
|
|
|
|
* port's details and returns true, otherwise (if all the ports have already
|
|
|
|
|
* been seen), returns false. */
|
2012-05-07 10:33:34 -07:00
|
|
|
|
static bool
|
2015-11-03 16:38:13 -08:00
|
|
|
|
port_iterator_next(struct port_iterator *pi, struct ofputil_phy_port *pp)
|
2012-05-07 10:33:34 -07:00
|
|
|
|
{
|
2015-11-03 16:38:13 -08:00
|
|
|
|
for (;;) {
|
|
|
|
|
if (pi->reply) {
|
|
|
|
|
int retval = ofputil_pull_phy_port(vconn_get_version(pi->vconn),
|
|
|
|
|
pi->reply, pp);
|
|
|
|
|
if (!retval) {
|
|
|
|
|
return true;
|
|
|
|
|
} else if (retval != EOF) {
|
2012-05-07 10:33:34 -07:00
|
|
|
|
ovs_fatal(0, "received bad reply: %s",
|
2015-11-03 16:38:13 -08:00
|
|
|
|
ofp_to_string(pi->reply->data, pi->reply->size,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
NULL, NULL, verbosity + 1));
|
2012-05-07 10:33:34 -07:00
|
|
|
|
}
|
2015-11-03 16:38:13 -08:00
|
|
|
|
}
|
2012-05-07 10:33:34 -07:00
|
|
|
|
|
2015-11-03 16:38:13 -08:00
|
|
|
|
if (pi->variant == PI_FEATURES || !pi->more) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-05-07 10:33:34 -07:00
|
|
|
|
|
2015-11-03 16:38:13 -08:00
|
|
|
|
ovs_be32 recv_xid;
|
|
|
|
|
do {
|
|
|
|
|
ofpbuf_delete(pi->reply);
|
|
|
|
|
run(vconn_recv_block(pi->vconn, &pi->reply),
|
|
|
|
|
"OpenFlow receive failed");
|
|
|
|
|
recv_xid = ((struct ofp_header *) pi->reply->data)->xid;
|
|
|
|
|
} while (pi->send_xid != recv_xid);
|
|
|
|
|
|
|
|
|
|
struct ofp_header *oh = pi->reply->data;
|
|
|
|
|
enum ofptype type;
|
|
|
|
|
if (ofptype_pull(&type, pi->reply)
|
|
|
|
|
|| type != OFPTYPE_PORT_DESC_STATS_REPLY) {
|
|
|
|
|
ovs_fatal(0, "received bad reply: %s",
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_to_string(pi->reply->data, pi->reply->size, NULL,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
NULL, verbosity + 1));
|
2012-05-07 10:33:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 16:38:13 -08:00
|
|
|
|
pi->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0;
|
|
|
|
|
}
|
2012-05-07 10:33:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 16:38:13 -08:00
|
|
|
|
/* Destroys iterator 'pi'. */
|
|
|
|
|
static void
|
|
|
|
|
port_iterator_destroy(struct port_iterator *pi)
|
2013-06-19 16:58:44 -07:00
|
|
|
|
{
|
2015-11-03 16:38:13 -08:00
|
|
|
|
if (pi) {
|
|
|
|
|
while (pi->variant == PI_PORT_DESC && pi->more) {
|
|
|
|
|
/* Drain vconn's queue of any other replies for this request. */
|
|
|
|
|
struct ofputil_phy_port pp;
|
|
|
|
|
port_iterator_next(pi, &pp);
|
|
|
|
|
}
|
2013-06-19 16:58:44 -07:00
|
|
|
|
|
2015-11-03 16:38:13 -08:00
|
|
|
|
ofpbuf_delete(pi->reply);
|
|
|
|
|
}
|
2013-06-19 16:58:44 -07:00
|
|
|
|
}
|
2012-05-07 10:33:34 -07:00
|
|
|
|
|
|
|
|
|
/* Opens a connection to 'vconn_name', fetches the port structure for
|
|
|
|
|
* 'port_name' (which may be a port name or number), and copies it into
|
|
|
|
|
* '*pp'. */
|
|
|
|
|
static void
|
|
|
|
|
fetch_ofputil_phy_port(const char *vconn_name, const char *port_name,
|
|
|
|
|
struct ofputil_phy_port *pp)
|
|
|
|
|
{
|
2014-05-08 21:20:22 -07:00
|
|
|
|
struct vconn *vconn;
|
2013-06-19 16:58:44 -07:00
|
|
|
|
ofp_port_t port_no;
|
2015-11-03 16:38:13 -08:00
|
|
|
|
bool found = false;
|
2012-05-07 10:33:34 -07:00
|
|
|
|
|
|
|
|
|
/* Try to interpret the argument as a port number. */
|
2013-06-19 16:58:44 -07:00
|
|
|
|
if (!str_to_ofp(port_name, &port_no)) {
|
|
|
|
|
port_no = OFPP_NONE;
|
2012-05-07 10:33:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-08 21:20:22 -07:00
|
|
|
|
/* OpenFlow 1.0, 1.1, and 1.2 put the list of ports in the
|
|
|
|
|
* OFPT_FEATURES_REPLY message. OpenFlow 1.3 and later versions put it
|
|
|
|
|
* into the OFPST_PORT_DESC reply. Try it the correct way. */
|
|
|
|
|
open_vconn(vconn_name, &vconn);
|
2015-11-03 16:38:13 -08:00
|
|
|
|
struct port_iterator pi;
|
|
|
|
|
for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, pp); ) {
|
|
|
|
|
if (port_no != OFPP_NONE
|
|
|
|
|
? port_no == pp->port_no
|
|
|
|
|
: !strcmp(pp->name, port_name)) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
port_iterator_destroy(&pi);
|
2014-05-08 21:20:22 -07:00
|
|
|
|
vconn_close(vconn);
|
2012-05-07 10:33:34 -07:00
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
ovs_fatal(0, "%s: couldn't find port `%s'", vconn_name, port_name);
|
|
|
|
|
}
|
2010-11-16 10:28:10 -08:00
|
|
|
|
}
|
2010-01-19 22:35:18 -08:00
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
static const struct ofputil_port_map *
|
|
|
|
|
get_port_map(const char *vconn_name)
|
|
|
|
|
{
|
|
|
|
|
static struct shash port_maps = SHASH_INITIALIZER(&port_maps);
|
|
|
|
|
struct ofputil_port_map *map = shash_find_data(&port_maps, vconn_name);
|
|
|
|
|
if (!map) {
|
|
|
|
|
map = xmalloc(sizeof *map);
|
|
|
|
|
ofputil_port_map_init(map);
|
|
|
|
|
shash_add(&port_maps, vconn_name, map);
|
|
|
|
|
|
|
|
|
|
if (!strchr(vconn_name, ':') || !vconn_verify_name(vconn_name)) {
|
|
|
|
|
/* For an active vconn (which includes a vconn constructed from a
|
|
|
|
|
* bridge name), connect to it and pull down the port name-number
|
|
|
|
|
* mapping. */
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
open_vconn(vconn_name, &vconn);
|
|
|
|
|
|
|
|
|
|
struct port_iterator pi;
|
|
|
|
|
struct ofputil_phy_port pp;
|
|
|
|
|
for (port_iterator_init(&pi, vconn);
|
|
|
|
|
port_iterator_next(&pi, &pp); ) {
|
|
|
|
|
ofputil_port_map_put(map, pp.port_no, pp.name);
|
|
|
|
|
}
|
|
|
|
|
port_iterator_destroy(&pi);
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
} else {
|
|
|
|
|
/* Don't bother with passive vconns, since it could take a long
|
|
|
|
|
* time for the remote to try to connect to us. Don't bother with
|
|
|
|
|
* invalid vconn names either. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct ofputil_port_map *
|
|
|
|
|
ports_to_accept(const char *vconn_name)
|
|
|
|
|
{
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
return should_accept_names() ? get_port_map(vconn_name) : NULL;
|
2017-05-31 16:06:12 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct ofputil_port_map *
|
|
|
|
|
ports_to_show(const char *vconn_name)
|
|
|
|
|
{
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
return should_show_names() ? get_port_map(vconn_name) : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct table_iterator {
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
|
|
|
|
enum { TI_STATS, TI_FEATURES } variant;
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
ovs_be32 send_xid;
|
|
|
|
|
bool more;
|
|
|
|
|
|
|
|
|
|
struct ofputil_table_features features;
|
2018-08-29 11:30:13 -07:00
|
|
|
|
struct ofpbuf raw_properties;
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Initializes 'ti' to prepare for iterating through all of the tables on the
|
|
|
|
|
* OpenFlow switch to which 'vconn' is connected.
|
|
|
|
|
*
|
|
|
|
|
* During iteration, the client should not make other use of 'vconn', because
|
|
|
|
|
* that can cause other messages to be interleaved with the replies used by the
|
|
|
|
|
* iterator and thus some tables may be missed or a hang can occur. */
|
|
|
|
|
static void
|
|
|
|
|
table_iterator_init(struct table_iterator *ti, struct vconn *vconn)
|
|
|
|
|
{
|
|
|
|
|
memset(ti, 0, sizeof *ti);
|
|
|
|
|
ti->vconn = vconn;
|
|
|
|
|
ti->variant = (vconn_get_version(vconn) < OFP13_VERSION
|
|
|
|
|
? TI_STATS : TI_FEATURES);
|
|
|
|
|
ti->more = true;
|
|
|
|
|
|
2018-02-27 17:34:14 -08:00
|
|
|
|
enum ofpraw ofpraw = (ti->variant == TI_STATS
|
|
|
|
|
? OFPRAW_OFPST_TABLE_REQUEST
|
|
|
|
|
: OFPRAW_OFPST13_TABLE_FEATURES_REQUEST);
|
|
|
|
|
struct ofpbuf *rq = ofpraw_alloc(ofpraw, vconn_get_version(vconn), 0);
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ti->send_xid = ((struct ofp_header *) rq->data)->xid;
|
|
|
|
|
send_openflow_buffer(ti->vconn, rq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Obtains the next table from 'ti'. On success, returns the next table's
|
|
|
|
|
* features; on failure, returns NULL. */
|
|
|
|
|
static const struct ofputil_table_features *
|
|
|
|
|
table_iterator_next(struct table_iterator *ti)
|
|
|
|
|
{
|
|
|
|
|
for (;;) {
|
|
|
|
|
if (ti->reply) {
|
|
|
|
|
int retval;
|
|
|
|
|
if (ti->variant == TI_STATS) {
|
|
|
|
|
struct ofputil_table_stats ts;
|
|
|
|
|
retval = ofputil_decode_table_stats_reply(ti->reply,
|
|
|
|
|
&ts, &ti->features);
|
|
|
|
|
} else {
|
|
|
|
|
ovs_assert(ti->variant == TI_FEATURES);
|
|
|
|
|
retval = ofputil_decode_table_features(ti->reply,
|
|
|
|
|
&ti->features,
|
2018-08-29 11:30:13 -07:00
|
|
|
|
&ti->raw_properties);
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
}
|
|
|
|
|
if (!retval) {
|
|
|
|
|
return &ti->features;
|
|
|
|
|
} else if (retval != EOF) {
|
|
|
|
|
ovs_fatal(0, "received bad reply: %s",
|
|
|
|
|
ofp_to_string(ti->reply->data, ti->reply->size,
|
|
|
|
|
NULL, NULL, verbosity + 1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ti->more) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ovs_be32 recv_xid;
|
|
|
|
|
do {
|
|
|
|
|
ofpbuf_delete(ti->reply);
|
|
|
|
|
run(vconn_recv_block(ti->vconn, &ti->reply),
|
|
|
|
|
"OpenFlow receive failed");
|
|
|
|
|
recv_xid = ((struct ofp_header *) ti->reply->data)->xid;
|
|
|
|
|
} while (ti->send_xid != recv_xid);
|
|
|
|
|
|
|
|
|
|
struct ofp_header *oh = ti->reply->data;
|
|
|
|
|
enum ofptype type;
|
|
|
|
|
if (ofptype_pull(&type, ti->reply)
|
|
|
|
|
|| type != (ti->variant == TI_STATS
|
|
|
|
|
? OFPTYPE_TABLE_STATS_REPLY
|
|
|
|
|
: OFPTYPE_TABLE_FEATURES_STATS_REPLY)) {
|
|
|
|
|
ovs_fatal(0, "received bad reply: %s",
|
|
|
|
|
ofp_to_string(ti->reply->data, ti->reply->size, NULL,
|
|
|
|
|
NULL, verbosity + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ti->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Destroys iterator 'ti'. */
|
|
|
|
|
static void
|
|
|
|
|
table_iterator_destroy(struct table_iterator *ti)
|
|
|
|
|
{
|
|
|
|
|
if (ti) {
|
|
|
|
|
while (ti->more) {
|
|
|
|
|
/* Drain vconn's queue of any other replies for this request. */
|
|
|
|
|
table_iterator_next(ti);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ofpbuf_delete(ti->reply);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct ofputil_table_map *
|
|
|
|
|
get_table_map(const char *vconn_name)
|
|
|
|
|
{
|
|
|
|
|
static struct shash table_maps = SHASH_INITIALIZER(&table_maps);
|
|
|
|
|
struct ofputil_table_map *map = shash_find_data(&table_maps, vconn_name);
|
|
|
|
|
if (!map) {
|
|
|
|
|
map = xmalloc(sizeof *map);
|
|
|
|
|
ofputil_table_map_init(map);
|
|
|
|
|
shash_add(&table_maps, vconn_name, map);
|
|
|
|
|
|
|
|
|
|
if (!strchr(vconn_name, ':') || !vconn_verify_name(vconn_name)) {
|
|
|
|
|
/* For an active vconn (which includes a vconn constructed from a
|
|
|
|
|
* bridge name), connect to it and pull down the port name-number
|
|
|
|
|
* mapping. */
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
open_vconn(vconn_name, &vconn);
|
|
|
|
|
|
|
|
|
|
struct table_iterator ti;
|
|
|
|
|
table_iterator_init(&ti, vconn);
|
|
|
|
|
for (;;) {
|
|
|
|
|
const struct ofputil_table_features *tf
|
|
|
|
|
= table_iterator_next(&ti);
|
|
|
|
|
if (!tf) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (tf->name[0]) {
|
|
|
|
|
ofputil_table_map_put(map, tf->table_id, tf->name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
table_iterator_destroy(&ti);
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
} else {
|
|
|
|
|
/* Don't bother with passive vconns, since it could take a long
|
|
|
|
|
* time for the remote to try to connect to us. Don't bother with
|
|
|
|
|
* invalid vconn names either. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct ofputil_table_map *
|
|
|
|
|
tables_to_accept(const char *vconn_name)
|
|
|
|
|
{
|
|
|
|
|
return should_accept_names() ? get_table_map(vconn_name) : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct ofputil_table_map *
|
|
|
|
|
tables_to_show(const char *vconn_name)
|
|
|
|
|
{
|
|
|
|
|
return should_show_names() ? get_table_map(vconn_name) : NULL;
|
2017-05-31 16:06:12 -07:00
|
|
|
|
}
|
|
|
|
|
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
/* We accept port and table names unless the feature is turned off
|
|
|
|
|
* explicitly. */
|
2017-05-31 16:06:12 -07:00
|
|
|
|
static bool
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
should_accept_names(void)
|
2017-05-31 16:06:12 -07:00
|
|
|
|
{
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
return use_names != 0;
|
2017-05-31 16:06:12 -07:00
|
|
|
|
}
|
|
|
|
|
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
/* We show port and table names only if the feature is turned on explicitly, or
|
|
|
|
|
* if we're interacting with a user on the console. */
|
2017-05-31 16:06:12 -07:00
|
|
|
|
static bool
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
should_show_names(void)
|
2017-05-31 16:06:12 -07:00
|
|
|
|
{
|
|
|
|
|
static int interactive = -1;
|
|
|
|
|
if (interactive == -1) {
|
|
|
|
|
interactive = isatty(STDOUT_FILENO);
|
|
|
|
|
}
|
|
|
|
|
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
return use_names > 0 || (use_names == -1 && interactive);
|
2017-05-31 16:06:12 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-16 10:28:10 -08:00
|
|
|
|
/* Returns the port number corresponding to 'port_name' (which may be a port
|
|
|
|
|
* name or number) within the switch 'vconn_name'. */
|
2013-06-19 16:58:44 -07:00
|
|
|
|
static ofp_port_t
|
2010-11-16 10:28:10 -08:00
|
|
|
|
str_to_port_no(const char *vconn_name, const char *port_name)
|
|
|
|
|
{
|
2013-06-19 16:58:44 -07:00
|
|
|
|
ofp_port_t port_no;
|
2017-05-31 16:06:12 -07:00
|
|
|
|
if (ofputil_port_from_string(port_name, NULL, &port_no) ||
|
|
|
|
|
ofputil_port_from_string(port_name, ports_to_accept(vconn_name),
|
|
|
|
|
&port_no)) {
|
2010-11-16 10:28:10 -08:00
|
|
|
|
return port_no;
|
|
|
|
|
}
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ovs_fatal(0, "%s: unknown port `%s'", vconn_name, port_name);
|
2010-01-19 22:35:18 -08:00
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 13:32:01 -08:00
|
|
|
|
static bool
|
2012-02-10 13:30:23 -08:00
|
|
|
|
try_set_protocol(struct vconn *vconn, enum ofputil_protocol want,
|
|
|
|
|
enum ofputil_protocol *cur)
|
2010-12-07 13:32:01 -08:00
|
|
|
|
{
|
2012-02-10 13:30:23 -08:00
|
|
|
|
for (;;) {
|
|
|
|
|
struct ofpbuf *request, *reply;
|
|
|
|
|
enum ofputil_protocol next;
|
2010-12-07 13:32:01 -08:00
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
request = ofputil_encode_set_protocol(*cur, want, &next);
|
|
|
|
|
if (!request) {
|
2012-11-15 22:09:07 -08:00
|
|
|
|
return *cur == want;
|
2012-02-10 13:30:23 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
run(vconn_transact_noreply(vconn, request, &reply),
|
|
|
|
|
"talking to %s", vconn_get_name(vconn));
|
|
|
|
|
if (reply) {
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
char *s = ofp_to_string(reply->data, reply->size, NULL, NULL, 2);
|
2012-02-10 13:30:23 -08:00
|
|
|
|
VLOG_DBG("%s: failed to set protocol, switch replied: %s",
|
|
|
|
|
vconn_get_name(vconn), s);
|
|
|
|
|
free(s);
|
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*cur = next;
|
2010-12-07 13:32:01 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
static enum ofputil_protocol
|
|
|
|
|
set_protocol_for_flow_dump(struct vconn *vconn,
|
|
|
|
|
enum ofputil_protocol cur_protocol,
|
|
|
|
|
enum ofputil_protocol usable_protocols)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2012-02-10 13:30:23 -08:00
|
|
|
|
char *usable_s;
|
|
|
|
|
int i;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
for (i = 0; i < ofputil_n_flow_dump_protocols; i++) {
|
|
|
|
|
enum ofputil_protocol f = ofputil_flow_dump_protocols[i];
|
|
|
|
|
if (f & usable_protocols & allowed_protocols
|
|
|
|
|
&& try_set_protocol(vconn, f, &cur_protocol)) {
|
|
|
|
|
return f;
|
2011-03-10 11:07:10 -08:00
|
|
|
|
}
|
2012-02-10 13:30:23 -08:00
|
|
|
|
}
|
2011-03-10 11:07:10 -08:00
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
usable_s = ofputil_protocols_to_string(usable_protocols);
|
|
|
|
|
if (usable_protocols & allowed_protocols) {
|
|
|
|
|
ovs_fatal(0, "switch does not support any of the usable flow "
|
|
|
|
|
"formats (%s)", usable_s);
|
2017-05-31 16:06:12 -07:00
|
|
|
|
} else {
|
2012-02-10 13:30:23 -08:00
|
|
|
|
char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
|
|
|
|
|
ovs_fatal(0, "none of the usable flow formats (%s) is among the "
|
|
|
|
|
"allowed flow formats (%s)", usable_s, allowed_s);
|
2010-12-07 13:32:01 -08:00
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-12 13:32:47 -07:00
|
|
|
|
static struct vconn *
|
|
|
|
|
prepare_dump_flows(int argc, char *argv[], bool aggregate,
|
2016-12-28 09:31:42 -08:00
|
|
|
|
struct ofputil_flow_stats_request *fsr,
|
|
|
|
|
enum ofputil_protocol *protocolp)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2017-05-31 16:06:12 -07:00
|
|
|
|
const char *vconn_name = argv[1];
|
2012-02-10 13:30:23 -08:00
|
|
|
|
enum ofputil_protocol usable_protocols, protocol;
|
2010-12-07 13:32:01 -08:00
|
|
|
|
struct vconn *vconn;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
char *error;
|
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
const char *match = argc > 2 ? argv[2] : "";
|
|
|
|
|
const struct ofputil_port_map *port_map
|
|
|
|
|
= *match ? ports_to_accept(vconn_name) : NULL;
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
const struct ofputil_table_map *table_map
|
|
|
|
|
= *match ? tables_to_accept(vconn_name) : NULL;
|
2017-05-31 16:06:12 -07:00
|
|
|
|
error = parse_ofp_flow_stats_request_str(fsr, aggregate, match,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
port_map, table_map,
|
|
|
|
|
&usable_protocols);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
protocol = open_vconn(vconn_name, &vconn);
|
2016-12-28 09:31:42 -08:00
|
|
|
|
*protocolp = set_protocol_for_flow_dump(vconn, protocol, usable_protocols);
|
2012-07-12 13:32:47 -07:00
|
|
|
|
return vconn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofctl_dump_flows__(int argc, char *argv[], bool aggregate)
|
|
|
|
|
{
|
2016-12-28 09:31:42 -08:00
|
|
|
|
struct ofputil_flow_stats_request fsr;
|
|
|
|
|
enum ofputil_protocol protocol;
|
2012-07-12 13:32:47 -07:00
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
2016-12-28 09:31:42 -08:00
|
|
|
|
vconn = prepare_dump_flows(argc, argv, aggregate, &fsr, &protocol);
|
|
|
|
|
dump_transaction(vconn, ofputil_encode_flow_stats_request(&fsr, protocol));
|
2010-12-07 13:32:01 -08:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-29 10:54:19 -07:00
|
|
|
|
static void
|
|
|
|
|
get_match_field(const struct mf_field *field, const struct match *match,
|
|
|
|
|
union mf_value *value)
|
|
|
|
|
{
|
|
|
|
|
if (!match->tun_md.valid || (field->id < MFF_TUN_METADATA0 ||
|
|
|
|
|
field->id >= MFF_TUN_METADATA0 +
|
|
|
|
|
TUN_METADATA_NUM_OPTS)) {
|
|
|
|
|
mf_get_value(field, &match->flow, value);
|
|
|
|
|
} else {
|
|
|
|
|
const struct tun_metadata_loc *loc = &match->tun_md.entry[field->id -
|
|
|
|
|
MFF_TUN_METADATA0].loc;
|
|
|
|
|
|
|
|
|
|
/* Since we don't have a tunnel mapping table, extract the value
|
|
|
|
|
* from the locally allocated location in the match. */
|
|
|
|
|
memset(value, 0, field->n_bytes - loc->len);
|
|
|
|
|
memcpy(value->tun_metadata + field->n_bytes - loc->len,
|
|
|
|
|
match->flow.tunnel.metadata.opts.u8 + loc->c.offset, loc->len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-12 13:32:47 -07:00
|
|
|
|
static int
|
|
|
|
|
compare_flows(const void *afs_, const void *bfs_)
|
|
|
|
|
{
|
|
|
|
|
const struct ofputil_flow_stats *afs = afs_;
|
|
|
|
|
const struct ofputil_flow_stats *bfs = bfs_;
|
2012-08-07 15:28:18 -07:00
|
|
|
|
const struct match *a = &afs->match;
|
|
|
|
|
const struct match *b = &bfs->match;
|
2012-07-12 13:32:47 -07:00
|
|
|
|
const struct sort_criterion *sc;
|
|
|
|
|
|
|
|
|
|
for (sc = criteria; sc < &criteria[n_criteria]; sc++) {
|
|
|
|
|
const struct mf_field *f = sc->field;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (!f) {
|
2014-10-30 11:40:07 -07:00
|
|
|
|
int a_pri = afs->priority;
|
|
|
|
|
int b_pri = bfs->priority;
|
2012-08-07 15:28:18 -07:00
|
|
|
|
ret = a_pri < b_pri ? -1 : a_pri > b_pri;
|
2012-07-12 13:32:47 -07:00
|
|
|
|
} else {
|
|
|
|
|
bool ina, inb;
|
|
|
|
|
|
2016-07-29 16:52:03 -07:00
|
|
|
|
ina = mf_are_prereqs_ok(f, &a->flow, NULL)
|
|
|
|
|
&& !mf_is_all_wild(f, &a->wc);
|
|
|
|
|
inb = mf_are_prereqs_ok(f, &b->flow, NULL)
|
|
|
|
|
&& !mf_is_all_wild(f, &b->wc);
|
2012-07-12 13:32:47 -07:00
|
|
|
|
if (ina != inb) {
|
|
|
|
|
/* Skip the test for sc->order, so that missing fields always
|
|
|
|
|
* sort to the end whether we're sorting in ascending or
|
|
|
|
|
* descending order. */
|
|
|
|
|
return ina ? -1 : 1;
|
|
|
|
|
} else {
|
|
|
|
|
union mf_value aval, bval;
|
|
|
|
|
|
2016-08-29 10:54:19 -07:00
|
|
|
|
get_match_field(f, a, &aval);
|
|
|
|
|
get_match_field(f, b, &bval);
|
2012-07-12 13:32:47 -07:00
|
|
|
|
ret = memcmp(&aval, &bval, f->n_bytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
|
return sc->order == SORT_ASC ? ret : -ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-07 00:34:45 +03:00
|
|
|
|
return a < b ? -1 : 1;
|
2012-07-12 13:32:47 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 13:32:01 -08:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_flows(struct ovs_cmdl_context *ctx)
|
2010-12-07 13:32:01 -08:00
|
|
|
|
{
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
if (!n_criteria && !should_show_names() && show_stats) {
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_flows__(ctx->argc, ctx->argv, false);
|
2014-09-09 14:12:57 -07:00
|
|
|
|
return;
|
2012-07-12 13:32:47 -07:00
|
|
|
|
} else {
|
2016-12-28 09:31:42 -08:00
|
|
|
|
struct ofputil_flow_stats_request fsr;
|
|
|
|
|
enum ofputil_protocol protocol;
|
2012-07-12 13:32:47 -07:00
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
2016-12-28 09:31:42 -08:00
|
|
|
|
vconn = prepare_dump_flows(ctx->argc, ctx->argv, false,
|
|
|
|
|
&fsr, &protocol);
|
2012-07-12 13:32:47 -07:00
|
|
|
|
|
2016-12-28 09:31:42 -08:00
|
|
|
|
struct ofputil_flow_stats *fses;
|
|
|
|
|
size_t n_fses;
|
|
|
|
|
run(vconn_dump_flows(vconn, &fsr, protocol, &fses, &n_fses),
|
|
|
|
|
"dump flows");
|
2012-07-12 13:32:47 -07:00
|
|
|
|
|
2018-08-07 00:34:45 +03:00
|
|
|
|
if (n_criteria) {
|
|
|
|
|
qsort(fses, n_fses, sizeof *fses, compare_flows);
|
|
|
|
|
}
|
2012-07-12 13:32:47 -07:00
|
|
|
|
|
2016-12-28 09:31:42 -08:00
|
|
|
|
struct ds s = DS_EMPTY_INITIALIZER;
|
|
|
|
|
for (size_t i = 0; i < n_fses; i++) {
|
2012-07-12 13:32:47 -07:00
|
|
|
|
ds_clear(&s);
|
2018-02-16 14:03:51 -08:00
|
|
|
|
ofputil_flow_stats_format(&s, &fses[i],
|
|
|
|
|
ports_to_show(ctx->argv[1]),
|
|
|
|
|
tables_to_show(ctx->argv[1]),
|
|
|
|
|
show_stats);
|
2017-06-13 17:09:05 -07:00
|
|
|
|
printf(" %s\n", ds_cstr(&s));
|
2012-07-12 13:32:47 -07:00
|
|
|
|
}
|
|
|
|
|
ds_destroy(&s);
|
|
|
|
|
|
2016-12-28 09:31:42 -08:00
|
|
|
|
for (size_t i = 0; i < n_fses; i++) {
|
2014-04-29 15:50:38 -07:00
|
|
|
|
free(CONST_CAST(struct ofpact *, fses[i].ofpacts));
|
2012-07-12 13:32:47 -07:00
|
|
|
|
}
|
|
|
|
|
free(fses);
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
2010-12-07 13:32:01 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_aggregate(struct ovs_cmdl_context *ctx)
|
2010-12-07 13:32:01 -08:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_flows__(ctx->argc, ctx->argv, true);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-09-16 15:36:57 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_queue_stats(struct ovs_cmdl_context *ctx)
|
2010-09-16 15:36:57 -07:00
|
|
|
|
{
|
|
|
|
|
struct ofpbuf *request;
|
2012-08-21 13:55:37 +09:00
|
|
|
|
struct vconn *vconn;
|
2012-10-12 13:03:04 +09:00
|
|
|
|
struct ofputil_queue_stats_request oqs;
|
2010-09-16 15:36:57 -07:00
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
2010-09-16 15:36:57 -07:00
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
if (ctx->argc > 2 && ctx->argv[2][0] && strcasecmp(ctx->argv[2], "all")) {
|
|
|
|
|
oqs.port_no = str_to_port_no(ctx->argv[1], ctx->argv[2]);
|
2010-09-16 15:36:57 -07:00
|
|
|
|
} else {
|
2012-11-26 18:17:08 +02:00
|
|
|
|
oqs.port_no = OFPP_ANY;
|
2010-09-16 15:36:57 -07:00
|
|
|
|
}
|
2015-03-17 10:35:26 -04:00
|
|
|
|
if (ctx->argc > 3 && ctx->argv[3][0] && strcasecmp(ctx->argv[3], "all")) {
|
|
|
|
|
oqs.queue_id = atoi(ctx->argv[3]);
|
2010-09-16 15:36:57 -07:00
|
|
|
|
} else {
|
2012-10-12 13:03:04 +09:00
|
|
|
|
oqs.queue_id = OFPQ_ALL;
|
2010-09-16 15:36:57 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-10-12 13:03:04 +09:00
|
|
|
|
request = ofputil_encode_queue_stats_request(vconn_get_version(vconn), &oqs);
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, request);
|
2012-08-21 13:55:37 +09:00
|
|
|
|
vconn_close(vconn);
|
2010-09-16 15:36:57 -07:00
|
|
|
|
}
|
|
|
|
|
|
2013-10-24 15:54:03 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_queue_get_config(struct ovs_cmdl_context *ctx)
|
2013-10-24 15:54:03 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
const char *vconn_name = ctx->argv[1];
|
2016-01-18 16:00:05 -08:00
|
|
|
|
const char *port_name = ctx->argc > 2 ? ctx->argv[2] : "any";
|
|
|
|
|
ofp_port_t port = str_to_port_no(vconn_name, port_name);
|
|
|
|
|
const char *queue_name = ctx->argc > 3 ? ctx->argv[3] : "all";
|
|
|
|
|
uint32_t queue = (!strcasecmp(queue_name, "all")
|
|
|
|
|
? OFPQ_ALL
|
|
|
|
|
: atoi(queue_name));
|
2016-01-07 08:57:44 -08:00
|
|
|
|
struct vconn *vconn;
|
2016-01-18 16:00:05 -08:00
|
|
|
|
|
2016-01-07 08:57:44 -08:00
|
|
|
|
enum ofputil_protocol protocol = open_vconn(vconn_name, &vconn);
|
|
|
|
|
enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
|
|
|
|
|
if (port == OFPP_ANY && version == OFP10_VERSION) {
|
|
|
|
|
/* The user requested all queues on all ports. OpenFlow 1.0 only
|
|
|
|
|
* supports getting queues for an individual port, so to implement the
|
|
|
|
|
* user's request we have to get a list of all the ports.
|
|
|
|
|
*
|
|
|
|
|
* We use a second vconn to avoid having to accumulate a list of all of
|
|
|
|
|
* the ports. */
|
|
|
|
|
struct vconn *vconn2;
|
|
|
|
|
enum ofputil_protocol protocol2 = open_vconn(vconn_name, &vconn2);
|
|
|
|
|
enum ofp_version version2 = ofputil_protocol_to_ofp_version(protocol2);
|
|
|
|
|
|
|
|
|
|
struct port_iterator pi;
|
|
|
|
|
struct ofputil_phy_port pp;
|
|
|
|
|
for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, &pp); ) {
|
|
|
|
|
if (ofp_to_u16(pp.port_no) < ofp_to_u16(OFPP_MAX)) {
|
|
|
|
|
dump_transaction(vconn2,
|
|
|
|
|
ofputil_encode_queue_get_config_request(
|
2016-01-18 16:00:05 -08:00
|
|
|
|
version2, pp.port_no, queue));
|
2016-01-07 08:57:44 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
port_iterator_destroy(&pi);
|
|
|
|
|
vconn_close(vconn2);
|
|
|
|
|
} else {
|
|
|
|
|
dump_transaction(vconn, ofputil_encode_queue_get_config_request(
|
2016-01-18 16:00:05 -08:00
|
|
|
|
version, port, queue));
|
2016-01-07 08:57:44 -08:00
|
|
|
|
}
|
2013-10-24 15:54:03 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
static enum ofputil_protocol
|
2013-08-20 18:41:45 -07:00
|
|
|
|
open_vconn_for_flow_mod(const char *remote, struct vconn **vconnp,
|
|
|
|
|
enum ofputil_protocol usable_protocols)
|
2011-02-22 13:43:14 -08:00
|
|
|
|
{
|
2012-02-10 13:30:23 -08:00
|
|
|
|
enum ofputil_protocol cur_protocol;
|
|
|
|
|
char *usable_s;
|
|
|
|
|
int i;
|
2011-02-22 13:43:14 -08:00
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
if (!(usable_protocols & allowed_protocols)) {
|
|
|
|
|
char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
|
|
|
|
|
usable_s = ofputil_protocols_to_string(usable_protocols);
|
|
|
|
|
ovs_fatal(0, "none of the usable flow formats (%s) is among the "
|
|
|
|
|
"allowed flow formats (%s)", usable_s, allowed_s);
|
2011-02-22 13:43:14 -08:00
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
/* If the initial flow format is allowed and usable, keep it. */
|
|
|
|
|
cur_protocol = open_vconn(remote, vconnp);
|
|
|
|
|
if (usable_protocols & allowed_protocols & cur_protocol) {
|
|
|
|
|
return cur_protocol;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Otherwise try each flow format in turn. */
|
|
|
|
|
for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
|
|
|
|
|
enum ofputil_protocol f = 1 << i;
|
|
|
|
|
|
|
|
|
|
if (f != cur_protocol
|
|
|
|
|
&& f & usable_protocols & allowed_protocols
|
|
|
|
|
&& try_set_protocol(*vconnp, f, &cur_protocol)) {
|
|
|
|
|
return f;
|
|
|
|
|
}
|
2011-02-22 13:43:14 -08:00
|
|
|
|
}
|
2012-02-10 13:30:23 -08:00
|
|
|
|
|
|
|
|
|
usable_s = ofputil_protocols_to_string(usable_protocols);
|
|
|
|
|
ovs_fatal(0, "switch does not support any of the usable flow "
|
|
|
|
|
"formats (%s)", usable_s);
|
2011-02-22 13:43:14 -08:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-05 14:03:12 -07:00
|
|
|
|
static void
|
|
|
|
|
bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms,
|
|
|
|
|
size_t n_fms, enum ofputil_protocol usable_protocols)
|
|
|
|
|
{
|
|
|
|
|
enum ofputil_protocol protocol;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
struct ovs_list requests;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
2016-03-25 14:10:22 -07:00
|
|
|
|
ovs_list_init(&requests);
|
2015-06-05 14:03:12 -07:00
|
|
|
|
|
2016-02-17 14:08:04 -08:00
|
|
|
|
/* Bundles need OpenFlow 1.3+. */
|
|
|
|
|
usable_protocols &= OFPUTIL_P_OF13_UP;
|
2015-06-05 14:03:12 -07:00
|
|
|
|
protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_fms; i++) {
|
|
|
|
|
struct ofputil_flow_mod *fm = &fms[i];
|
|
|
|
|
struct ofpbuf *request = ofputil_encode_flow_mod(fm, protocol);
|
|
|
|
|
|
2016-03-25 14:10:22 -07:00
|
|
|
|
ovs_list_push_back(&requests, &request->list_node);
|
2015-06-05 14:03:12 -07:00
|
|
|
|
free(CONST_CAST(struct ofpact *, fm->ofpacts));
|
2019-09-11 14:18:30 -07:00
|
|
|
|
minimatch_destroy(&fm->match);
|
2015-06-05 14:03:12 -07:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-11 15:53:43 -07:00
|
|
|
|
bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC);
|
2016-01-04 16:18:40 -08:00
|
|
|
|
ofpbuf_list_delete(&requests);
|
2015-06-05 14:03:12 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2012-07-08 04:38:36 -07:00
|
|
|
|
ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms,
|
2013-08-20 18:41:45 -07:00
|
|
|
|
size_t n_fms, enum ofputil_protocol usable_protocols)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2012-02-10 13:30:23 -08:00
|
|
|
|
enum ofputil_protocol protocol;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
struct vconn *vconn;
|
2021-12-08 18:05:22 -05:00
|
|
|
|
struct ds ds = DS_EMPTY_INITIALIZER;
|
2012-02-10 13:30:23 -08:00
|
|
|
|
size_t i;
|
2011-03-11 13:19:12 -08:00
|
|
|
|
|
2015-06-05 14:03:12 -07:00
|
|
|
|
if (bundle) {
|
|
|
|
|
bundle_flow_mod__(remote, fms, n_fms, usable_protocols);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-20 18:41:45 -07:00
|
|
|
|
protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
|
2010-11-11 11:01:09 -08:00
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
for (i = 0; i < n_fms; i++) {
|
|
|
|
|
struct ofputil_flow_mod *fm = &fms[i];
|
2021-12-08 18:05:22 -05:00
|
|
|
|
struct ofpbuf *buf = ofputil_encode_flow_mod(fm, protocol);
|
|
|
|
|
|
|
|
|
|
/* If user has opted for verbosity of 5 or more dump the
|
|
|
|
|
* constructed OpenFlow packet in hex format */
|
|
|
|
|
if (verbosity == 5) {
|
|
|
|
|
ds_put_hex_dump(&ds, buf->data, buf->size, 0, true);
|
|
|
|
|
} else if (verbosity > 5) {
|
|
|
|
|
ds_put_hex(&ds, buf->data, buf->size);
|
|
|
|
|
ds_put_char(&ds, '\n');
|
|
|
|
|
}
|
|
|
|
|
transact_noreply(vconn, buf);
|
2014-04-29 15:50:38 -07:00
|
|
|
|
free(CONST_CAST(struct ofpact *, fm->ofpacts));
|
2018-03-19 22:01:47 -07:00
|
|
|
|
minimatch_destroy(&fm->match);
|
2011-03-11 13:19:12 -08:00
|
|
|
|
}
|
2021-12-08 18:05:22 -05:00
|
|
|
|
fputs(ds_cstr(&ds), stdout);
|
|
|
|
|
ds_destroy(&ds);
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
vconn_close(vconn);
|
2010-12-07 13:32:01 -08:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2015-06-05 14:03:12 -07:00
|
|
|
|
ofctl_flow_mod_file(int argc OVS_UNUSED, char *argv[], int command)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2013-08-20 18:41:45 -07:00
|
|
|
|
enum ofputil_protocol usable_protocols;
|
2012-02-10 13:30:23 -08:00
|
|
|
|
struct ofputil_flow_mod *fms = NULL;
|
|
|
|
|
size_t n_fms = 0;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
char *error;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2015-06-05 14:03:12 -07:00
|
|
|
|
if (command == OFPFC_ADD) {
|
|
|
|
|
/* Allow the file to specify a mix of commands. If none specified at
|
|
|
|
|
* the beginning of any given line, then the default is OFPFC_ADD, so
|
|
|
|
|
* this is backwards compatible. */
|
|
|
|
|
command = -2;
|
|
|
|
|
}
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
error = parse_ofp_flow_mod_file(argv[2], ports_to_accept(argv[1]),
|
|
|
|
|
tables_to_accept(argv[1]), command,
|
2017-05-31 16:06:12 -07:00
|
|
|
|
&fms, &n_fms, &usable_protocols);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
2013-08-20 18:41:45 -07:00
|
|
|
|
ofctl_flow_mod__(argv[1], fms, n_fms, usable_protocols);
|
2012-02-10 13:30:23 -08:00
|
|
|
|
free(fms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2012-07-08 04:38:36 -07:00
|
|
|
|
ofctl_flow_mod(int argc, char *argv[], uint16_t command)
|
2012-02-10 13:30:23 -08:00
|
|
|
|
{
|
2011-03-11 13:19:12 -08:00
|
|
|
|
if (argc > 2 && !strcmp(argv[2], "-")) {
|
2012-07-08 04:38:36 -07:00
|
|
|
|
ofctl_flow_mod_file(argc, argv, command);
|
2012-02-10 13:30:23 -08:00
|
|
|
|
} else {
|
|
|
|
|
struct ofputil_flow_mod fm;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
char *error;
|
2013-09-13 15:03:33 -07:00
|
|
|
|
enum ofputil_protocol usable_protocols;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
error = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "",
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ports_to_accept(argv[1]),
|
|
|
|
|
tables_to_accept(argv[1]), command,
|
2013-11-15 14:19:57 -08:00
|
|
|
|
&usable_protocols);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
2013-08-20 18:41:45 -07:00
|
|
|
|
ofctl_flow_mod__(argv[1], &fm, 1, usable_protocols);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2011-03-11 13:19:12 -08:00
|
|
|
|
}
|
2010-12-07 13:32:01 -08:00
|
|
|
|
|
2011-03-11 13:19:12 -08:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_add_flow(struct ovs_cmdl_context *ctx)
|
2011-03-11 13:19:12 -08:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_flow_mod(ctx->argc, ctx->argv, OFPFC_ADD);
|
2011-03-11 13:19:12 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_add_flows(struct ovs_cmdl_context *ctx)
|
2011-03-11 13:19:12 -08:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_flow_mod_file(ctx->argc, ctx->argv, OFPFC_ADD);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_mod_flows(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_flow_mod(ctx->argc, ctx->argv, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 13:32:01 -08:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_del_flows(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_flow_mod(ctx->argc, ctx->argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-19 15:31:37 -08:00
|
|
|
|
static bool
|
2011-12-09 15:48:26 -08:00
|
|
|
|
set_packet_in_format(struct vconn *vconn,
|
2018-02-16 11:43:56 -08:00
|
|
|
|
enum ofputil_packet_in_format packet_in_format,
|
2016-02-19 15:31:37 -08:00
|
|
|
|
bool must_succeed)
|
2011-12-09 15:48:26 -08:00
|
|
|
|
{
|
2012-10-04 11:41:16 +09:00
|
|
|
|
struct ofpbuf *spif;
|
|
|
|
|
|
2018-02-16 11:43:56 -08:00
|
|
|
|
spif = ofputil_encode_set_packet_in_format(vconn_get_version(vconn),
|
|
|
|
|
packet_in_format);
|
2016-02-19 15:31:37 -08:00
|
|
|
|
if (must_succeed) {
|
|
|
|
|
transact_noreply(vconn, spif);
|
|
|
|
|
} else {
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
|
|
|
|
|
run(vconn_transact_noreply(vconn, spif, &reply),
|
|
|
|
|
"talking to %s", vconn_get_name(vconn));
|
|
|
|
|
if (reply) {
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
char *s = ofp_to_string(reply->data, reply->size, NULL, NULL, 2);
|
2016-02-19 15:31:37 -08:00
|
|
|
|
VLOG_DBG("%s: failed to set packet in format to nx_packet_in, "
|
|
|
|
|
"controller replied: %s.",
|
|
|
|
|
vconn_get_name(vconn), s);
|
|
|
|
|
free(s);
|
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
VLOG_DBG("%s: using user-specified packet in format %s",
|
|
|
|
|
vconn_get_name(vconn),
|
|
|
|
|
ofputil_packet_in_format_to_string(packet_in_format));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2011-12-09 15:48:26 -08:00
|
|
|
|
}
|
|
|
|
|
|
2012-01-13 17:54:04 -08:00
|
|
|
|
static int
|
|
|
|
|
monitor_set_invalid_ttl_to_controller(struct vconn *vconn)
|
|
|
|
|
{
|
2015-12-21 15:39:10 -08:00
|
|
|
|
struct ofputil_switch_config config;
|
2012-01-13 17:54:04 -08:00
|
|
|
|
|
|
|
|
|
fetch_switch_config(vconn, &config);
|
2015-12-21 15:39:10 -08:00
|
|
|
|
if (!config.invalid_ttl_to_controller) {
|
|
|
|
|
config.invalid_ttl_to_controller = 1;
|
2012-01-13 17:54:04 -08:00
|
|
|
|
set_switch_config(vconn, &config);
|
|
|
|
|
|
|
|
|
|
/* Then retrieve the configuration to see if it really took. OpenFlow
|
2015-12-21 15:39:10 -08:00
|
|
|
|
* has ill-defined error reporting for bad flags, so this is about the
|
|
|
|
|
* best we can do. */
|
2012-01-13 17:54:04 -08:00
|
|
|
|
fetch_switch_config(vconn, &config);
|
2015-12-21 15:39:10 -08:00
|
|
|
|
if (!config.invalid_ttl_to_controller) {
|
2012-01-13 17:54:04 -08:00
|
|
|
|
ovs_fatal(0, "setting invalid_ttl_to_controller failed (this "
|
2015-12-21 15:39:10 -08:00
|
|
|
|
"switch probably doesn't support this flag)");
|
2012-01-13 17:54:04 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-09 13:30:53 -08:00
|
|
|
|
/* Converts hex digits in 'hex' to an OpenFlow message in '*msgp'. The
|
|
|
|
|
* caller must free '*msgp'. On success, returns NULL. On failure, returns
|
|
|
|
|
* an error message and stores NULL in '*msgp'. */
|
|
|
|
|
static const char *
|
|
|
|
|
openflow_from_hex(const char *hex, struct ofpbuf **msgp)
|
|
|
|
|
{
|
|
|
|
|
struct ofp_header *oh;
|
|
|
|
|
struct ofpbuf *msg;
|
|
|
|
|
|
|
|
|
|
msg = ofpbuf_new(strlen(hex) / 2);
|
|
|
|
|
*msgp = NULL;
|
|
|
|
|
|
|
|
|
|
if (ofpbuf_put_hex(msg, hex, NULL)[0] != '\0') {
|
|
|
|
|
ofpbuf_delete(msg);
|
|
|
|
|
return "Trailing garbage in hex data";
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 17:29:44 -08:00
|
|
|
|
if (msg->size < sizeof(struct ofp_header)) {
|
2012-02-09 13:30:53 -08:00
|
|
|
|
ofpbuf_delete(msg);
|
|
|
|
|
return "Message too short for OpenFlow";
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 17:29:44 -08:00
|
|
|
|
oh = msg->data;
|
|
|
|
|
if (msg->size != ntohs(oh->length)) {
|
2012-02-09 13:30:53 -08:00
|
|
|
|
ofpbuf_delete(msg);
|
|
|
|
|
return "Message size does not match length in OpenFlow header";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*msgp = msg;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofctl_send(struct unixctl_conn *conn, int argc,
|
|
|
|
|
const char *argv[], void *vconn_)
|
|
|
|
|
{
|
|
|
|
|
struct vconn *vconn = vconn_;
|
|
|
|
|
struct ds reply;
|
|
|
|
|
bool ok;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
ok = true;
|
|
|
|
|
ds_init(&reply);
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
|
const char *error_msg;
|
|
|
|
|
struct ofpbuf *msg;
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
error_msg = openflow_from_hex(argv[i], &msg);
|
|
|
|
|
if (error_msg) {
|
|
|
|
|
ds_put_format(&reply, "%s\n", error_msg);
|
|
|
|
|
ok = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "send: ");
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_print(stderr, msg->data, msg->size,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ports_to_show(vconn_get_name(vconn)),
|
|
|
|
|
tables_to_show(vconn_get_name(vconn)), verbosity);
|
2012-02-09 13:30:53 -08:00
|
|
|
|
|
|
|
|
|
error = vconn_send_block(vconn, msg);
|
|
|
|
|
if (error) {
|
|
|
|
|
ofpbuf_delete(msg);
|
2013-06-24 10:54:49 -07:00
|
|
|
|
ds_put_format(&reply, "%s\n", ovs_strerror(error));
|
2012-02-09 13:30:53 -08:00
|
|
|
|
ok = false;
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_cstr(&reply, "sent\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-02-14 20:53:59 -08:00
|
|
|
|
|
|
|
|
|
if (ok) {
|
|
|
|
|
unixctl_command_reply(conn, ds_cstr(&reply));
|
|
|
|
|
} else {
|
|
|
|
|
unixctl_command_reply_error(conn, ds_cstr(&reply));
|
|
|
|
|
}
|
2012-02-09 13:30:53 -08:00
|
|
|
|
ds_destroy(&reply);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-14 16:51:27 -07:00
|
|
|
|
static void
|
|
|
|
|
unixctl_packet_out(struct unixctl_conn *conn, int OVS_UNUSED argc,
|
|
|
|
|
const char *argv[], void *vconn_)
|
|
|
|
|
{
|
|
|
|
|
struct vconn *vconn = vconn_;
|
|
|
|
|
enum ofputil_protocol protocol
|
|
|
|
|
= ofputil_protocol_from_ofp_version(vconn_get_version(vconn));
|
|
|
|
|
struct ds reply = DS_EMPTY_INITIALIZER;
|
|
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
|
|
enum ofputil_protocol usable_protocols;
|
|
|
|
|
struct ofputil_packet_out po;
|
|
|
|
|
char *error_msg;
|
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
error_msg = parse_ofp_packet_out_str(
|
|
|
|
|
&po, argv[1], ports_to_accept(vconn_get_name(vconn)),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_accept(vconn_get_name(vconn)), &usable_protocols);
|
2016-09-14 16:51:27 -07:00
|
|
|
|
if (error_msg) {
|
|
|
|
|
ds_put_format(&reply, "%s\n", error_msg);
|
|
|
|
|
free(error_msg);
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ok && !(usable_protocols & protocol)) {
|
|
|
|
|
ds_put_format(&reply, "PACKET_OUT actions are incompatible with the OpenFlow connection.\n");
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ok) {
|
|
|
|
|
struct ofpbuf *msg = ofputil_encode_packet_out(&po, protocol);
|
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_print(stderr, msg->data, msg->size,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ports_to_show(vconn_get_name(vconn)),
|
|
|
|
|
tables_to_show(vconn_get_name(vconn)), verbosity);
|
2016-09-14 16:51:27 -07:00
|
|
|
|
|
|
|
|
|
int error = vconn_send_block(vconn, msg);
|
|
|
|
|
if (error) {
|
|
|
|
|
ofpbuf_delete(msg);
|
|
|
|
|
ds_put_format(&reply, "%s\n", ovs_strerror(error));
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ok) {
|
|
|
|
|
unixctl_command_reply(conn, ds_cstr(&reply));
|
|
|
|
|
} else {
|
|
|
|
|
unixctl_command_reply_error(conn, ds_cstr(&reply));
|
|
|
|
|
}
|
|
|
|
|
ds_destroy(&reply);
|
|
|
|
|
|
|
|
|
|
if (!error_msg) {
|
|
|
|
|
free(CONST_CAST(void *, po.packet));
|
|
|
|
|
free(po.ofpacts);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-26 13:41:48 -08:00
|
|
|
|
struct barrier_aux {
|
|
|
|
|
struct vconn *vconn; /* OpenFlow connection for sending barrier. */
|
|
|
|
|
struct unixctl_conn *conn; /* Connection waiting for barrier response. */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
|
|
|
|
const char *argv[] OVS_UNUSED, void *aux_)
|
|
|
|
|
{
|
|
|
|
|
struct barrier_aux *aux = aux_;
|
|
|
|
|
struct ofpbuf *msg;
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
if (aux->conn) {
|
2012-02-14 20:53:59 -08:00
|
|
|
|
unixctl_command_reply_error(conn, "already waiting for barrier reply");
|
2012-01-26 13:41:48 -08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-01 16:01:47 +09:00
|
|
|
|
msg = ofputil_encode_barrier_request(vconn_get_version(aux->vconn));
|
2012-01-26 13:41:48 -08:00
|
|
|
|
error = vconn_send_block(aux->vconn, msg);
|
|
|
|
|
if (error) {
|
|
|
|
|
ofpbuf_delete(msg);
|
2013-06-24 10:54:49 -07:00
|
|
|
|
unixctl_command_reply_error(conn, ovs_strerror(error));
|
2012-01-26 13:41:48 -08:00
|
|
|
|
} else {
|
|
|
|
|
aux->conn = conn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-26 15:45:34 -08:00
|
|
|
|
static void
|
|
|
|
|
ofctl_set_output_file(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
|
|
|
|
const char *argv[], void *aux OVS_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
fd = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, 0666);
|
|
|
|
|
if (fd < 0) {
|
2013-06-24 10:54:49 -07:00
|
|
|
|
unixctl_command_reply_error(conn, ovs_strerror(errno));
|
2012-01-26 15:45:34 -08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fflush(stderr);
|
|
|
|
|
dup2(fd, STDERR_FILENO);
|
|
|
|
|
close(fd);
|
2012-02-14 20:53:59 -08:00
|
|
|
|
unixctl_command_reply(conn, NULL);
|
2012-01-26 15:45:34 -08:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-12 14:18:05 -07:00
|
|
|
|
static void
|
|
|
|
|
ofctl_block(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
2012-07-12 16:32:56 -07:00
|
|
|
|
const char *argv[] OVS_UNUSED, void *blocked_)
|
2012-07-12 14:18:05 -07:00
|
|
|
|
{
|
2012-07-12 16:32:56 -07:00
|
|
|
|
bool *blocked = blocked_;
|
2012-07-12 14:18:05 -07:00
|
|
|
|
|
2012-07-12 16:32:56 -07:00
|
|
|
|
if (!*blocked) {
|
|
|
|
|
*blocked = true;
|
|
|
|
|
unixctl_command_reply(conn, NULL);
|
|
|
|
|
} else {
|
2012-07-12 14:18:05 -07:00
|
|
|
|
unixctl_command_reply(conn, "already blocking");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
2012-07-12 16:32:56 -07:00
|
|
|
|
const char *argv[] OVS_UNUSED, void *blocked_)
|
2012-07-12 14:18:05 -07:00
|
|
|
|
{
|
2012-07-12 16:32:56 -07:00
|
|
|
|
bool *blocked = blocked_;
|
2012-07-12 14:18:05 -07:00
|
|
|
|
|
2012-07-12 16:32:56 -07:00
|
|
|
|
if (*blocked) {
|
|
|
|
|
*blocked = false;
|
2012-07-12 14:18:05 -07:00
|
|
|
|
unixctl_command_reply(conn, NULL);
|
2012-07-12 16:32:56 -07:00
|
|
|
|
} else {
|
|
|
|
|
unixctl_command_reply(conn, "already unblocked");
|
2012-07-12 14:18:05 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
ofproto: Fix crash on flow monitor request with tun_metadata.
nx_put_match() needs a non-NULL tunnel metadata table, otherwise it will
crash if a flow matches on tunnel metadata.
This wasn't handled in ofputil_append_flow_update(), causing a crash
when the controller sent a flow monitor request.
To fix the problem, this commit changes ofputil_append_flow_update() to
behave like ofputil_append_flow_stats_reply().
Since ofputil_append_flow_update() now needs to temporarily modify the
match, this commits also embeds 'struct match' into 'struct
ofputil_flow_update', to be safer. This is more similar to
'struct ofputil_flow_stats'.
A regression test is added and a comment is updated in ovs-ofctl.c
#0 0x000055699bd82fa0 in memcpy_from_metadata (dst=0x7ffc770930d0, src=0x7ffc77093698, loc=0x18) at ../lib/tun-metadata.c:451
#1 0x000055699bd83c2e in metadata_loc_from_match_read (map=0x0, match=0x7ffc77093410, idx=0, mask=0x7ffc77093658, is_masked=0x7ffc77093287) at ../lib/tun-metadata.c:848
#2 0x000055699bd83d9b in tun_metadata_to_nx_match (b=0x55699d3f0300, oxm=0, match=0x7ffc77093410) at ../lib/tun-metadata.c:871
#3 0x000055699bce523d in nx_put_raw (b=0x55699d3f0300, oxm=0, match=0x7ffc77093410, cookie=0, cookie_mask=0) at ../lib/nx-match.c:1052
#4 0x000055699bce5580 in nx_put_match (b=0x55699d3f0300, match=0x7ffc77093410, cookie=0, cookie_mask=0) at ../lib/nx-match.c:1116
#5 0x000055699bd3926f in ofputil_append_flow_update (update=0x7ffc770940b0, replies=0x7ffc77094e00) at ../lib/ofp-util.c:6805
#6 0x000055699bc4b5a9 in ofproto_compose_flow_refresh_update (rule=0x55699d405b40, flags=(NXFMF_INITIAL | NXFMF_ACTIONS), msgs=0x7ffc77094e00) at ../ofproto/ofproto.c:5915
#7 0x000055699bc4b5f6 in ofmonitor_compose_refresh_updates (rules=0x7ffc77094e10, msgs=0x7ffc77094e00) at ../ofproto/ofproto.c:5929
#8 0x000055699bc4bafc in handle_flow_monitor_request (ofconn=0x55699d404090, oh=0x55699d404220) at ../ofproto/ofproto.c:6082
#9 0x000055699bc4f46d in handle_openflow__ (ofconn=0x55699d404090, msg=0x55699d404910) at ../ofproto/ofproto.c:7912
#10 0x000055699bc4f5df in handle_openflow (ofconn=0x55699d404090, ofp_msg=0x55699d404910) at ../ofproto/ofproto.c:8002
#11 0x000055699bc88154 in ofconn_run (ofconn=0x55699d404090, handle_openflow=0x55699bc4f5bc <handle_openflow>) at ../ofproto/connmgr.c:1427
#12 0x000055699bc85934 in connmgr_run (mgr=0x55699d3adb90, handle_openflow=0x55699bc4f5bc <handle_openflow>) at ../ofproto/connmgr.c:363
#13 0x000055699bc422c9 in ofproto_run (p=0x55699d3c85e0) at ../ofproto/ofproto.c:1798
#14 0x000055699bc31ec6 in bridge_run__ () at ../vswitchd/bridge.c:2881
#15 0x000055699bc320a6 in bridge_run () at ../vswitchd/bridge.c:2938
#16 0x000055699bc3784e in main (argc=10, argv=0x7ffc770952c8) at ../vswitchd/ovs-vswitchd.c:111
Fixes: 8d8ab6c2d574 ("tun-metadata: Manage tunnel TLV mapping table on a
per-bridge basis.")
Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
Acked-by: Ben Pfaff <blp@ovn.org>
2016-12-27 19:02:23 -08:00
|
|
|
|
/* Prints to stderr all of the messages received on 'vconn'.
|
2013-05-03 13:58:29 -07:00
|
|
|
|
*
|
|
|
|
|
* Iff 'reply_to_echo_requests' is true, sends a reply to any echo request
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
* received on 'vconn'.
|
|
|
|
|
*
|
|
|
|
|
* If 'resume_continuations' is true, sends an NXT_RESUME in reply to any
|
|
|
|
|
* NXT_PACKET_IN2 that includes a continuation. */
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests,
|
|
|
|
|
bool resume_continuations)
|
2010-05-11 12:44:58 -07:00
|
|
|
|
{
|
2012-01-26 13:41:48 -08:00
|
|
|
|
struct barrier_aux barrier_aux = { vconn, NULL };
|
2011-12-20 15:31:34 -08:00
|
|
|
|
struct unixctl_server *server;
|
|
|
|
|
bool exiting = false;
|
2012-07-12 16:32:56 -07:00
|
|
|
|
bool blocked = false;
|
2012-01-27 09:53:17 -08:00
|
|
|
|
int error;
|
2011-12-20 15:31:34 -08:00
|
|
|
|
|
2012-01-27 09:53:17 -08:00
|
|
|
|
daemon_save_fd(STDERR_FILENO);
|
2015-09-11 11:26:39 -07:00
|
|
|
|
daemonize_start(false);
|
2014-07-28 10:31:25 -07:00
|
|
|
|
error = unixctl_server_create(unixctl_path, &server);
|
2011-12-20 15:31:34 -08:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(error, "failed to create unixctl server");
|
|
|
|
|
}
|
|
|
|
|
unixctl_command_register("exit", "", 0, 0, ofctl_exit, &exiting);
|
2012-02-09 13:30:53 -08:00
|
|
|
|
unixctl_command_register("ofctl/send", "OFMSG...", 1, INT_MAX,
|
|
|
|
|
ofctl_send, vconn);
|
2016-09-14 16:51:27 -07:00
|
|
|
|
unixctl_command_register("ofctl/packet-out", "\"in_port=<port> packet=<hex data> actions=...\"", 1, 1,
|
|
|
|
|
unixctl_packet_out, vconn);
|
2012-01-26 13:41:48 -08:00
|
|
|
|
unixctl_command_register("ofctl/barrier", "", 0, 0,
|
|
|
|
|
ofctl_barrier, &barrier_aux);
|
2012-01-26 15:45:34 -08:00
|
|
|
|
unixctl_command_register("ofctl/set-output-file", "FILE", 1, 1,
|
|
|
|
|
ofctl_set_output_file, NULL);
|
2012-07-12 14:18:05 -07:00
|
|
|
|
|
2012-07-12 16:32:56 -07:00
|
|
|
|
unixctl_command_register("ofctl/block", "", 0, 0, ofctl_block, &blocked);
|
|
|
|
|
unixctl_command_register("ofctl/unblock", "", 0, 0, ofctl_unblock,
|
|
|
|
|
&blocked);
|
2012-07-12 14:18:05 -07:00
|
|
|
|
|
2011-12-20 15:31:34 -08:00
|
|
|
|
daemonize_complete();
|
|
|
|
|
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
enum ofp_version version = vconn_get_version(vconn);
|
|
|
|
|
enum ofputil_protocol protocol
|
|
|
|
|
= ofputil_protocol_from_ofp_version(version);
|
|
|
|
|
|
2010-05-11 12:44:58 -07:00
|
|
|
|
for (;;) {
|
|
|
|
|
struct ofpbuf *b;
|
2011-12-20 15:31:34 -08:00
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
unixctl_server_run(server);
|
2012-07-19 23:23:17 -07:00
|
|
|
|
|
2012-07-12 16:32:56 -07:00
|
|
|
|
while (!blocked) {
|
2012-07-19 23:23:17 -07:00
|
|
|
|
enum ofptype type;
|
2012-01-26 13:41:48 -08:00
|
|
|
|
|
2011-12-20 15:31:34 -08:00
|
|
|
|
retval = vconn_recv(vconn, &b);
|
|
|
|
|
if (retval == EAGAIN) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
run(retval, "vconn_recv");
|
2012-03-07 13:52:55 -08:00
|
|
|
|
|
2012-02-07 16:17:13 -08:00
|
|
|
|
if (timestamp) {
|
2013-09-12 18:19:04 -07:00
|
|
|
|
char *s = xastrftime_msec("%Y-%m-%d %H:%M:%S.###: ",
|
|
|
|
|
time_wall_msec(), true);
|
2012-02-07 16:17:13 -08:00
|
|
|
|
fputs(s, stderr);
|
2013-05-02 16:16:06 -07:00
|
|
|
|
free(s);
|
2012-02-07 16:17:13 -08:00
|
|
|
|
}
|
2012-03-07 13:52:55 -08:00
|
|
|
|
|
2015-03-02 17:29:44 -08:00
|
|
|
|
ofptype_decode(&type, b->data);
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_print(stderr, b->data, b->size,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ports_to_show(vconn_get_name(vconn)),
|
|
|
|
|
tables_to_show(vconn_get_name(vconn)), verbosity + 2);
|
2014-05-16 12:08:53 -07:00
|
|
|
|
fflush(stderr);
|
2012-01-26 13:41:48 -08:00
|
|
|
|
|
2013-05-03 13:58:29 -07:00
|
|
|
|
switch ((int) type) {
|
|
|
|
|
case OFPTYPE_BARRIER_REPLY:
|
|
|
|
|
if (barrier_aux.conn) {
|
|
|
|
|
unixctl_command_reply(barrier_aux.conn, NULL);
|
|
|
|
|
barrier_aux.conn = NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPTYPE_ECHO_REQUEST:
|
|
|
|
|
if (reply_to_echo_requests) {
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
|
2018-02-15 13:43:41 -08:00
|
|
|
|
reply = ofputil_encode_echo_reply(b->data);
|
2013-05-03 13:58:29 -07:00
|
|
|
|
retval = vconn_send_block(vconn, reply);
|
|
|
|
|
if (retval) {
|
|
|
|
|
ovs_fatal(retval, "failed to send echo reply");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
|
|
|
|
|
case OFPTYPE_PACKET_IN:
|
|
|
|
|
if (resume_continuations) {
|
|
|
|
|
struct ofputil_packet_in pin;
|
|
|
|
|
struct ofpbuf continuation;
|
|
|
|
|
|
2017-03-13 11:28:20 -07:00
|
|
|
|
error = ofputil_decode_packet_in(b->data, true, NULL, NULL,
|
|
|
|
|
&pin, NULL, NULL,
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
&continuation);
|
|
|
|
|
if (error) {
|
|
|
|
|
fprintf(stderr, "decoding packet-in failed: %s",
|
|
|
|
|
ofperr_to_string(error));
|
|
|
|
|
} else if (continuation.size) {
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
|
|
|
|
|
reply = ofputil_encode_resume(&pin, &continuation,
|
|
|
|
|
protocol);
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "send: ");
|
|
|
|
|
ofp_print(stderr, reply->data, reply->size,
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ports_to_show(vconn_get_name(vconn)),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_show(vconn_get_name(vconn)),
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
verbosity + 2);
|
|
|
|
|
fflush(stderr);
|
|
|
|
|
|
|
|
|
|
retval = vconn_send_block(vconn, reply);
|
|
|
|
|
if (retval) {
|
|
|
|
|
ovs_fatal(retval, "failed to send NXT_RESUME");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2012-01-26 13:41:48 -08:00
|
|
|
|
}
|
2013-05-03 13:58:29 -07:00
|
|
|
|
ofpbuf_delete(b);
|
2011-12-20 15:31:34 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exiting) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vconn_run(vconn);
|
|
|
|
|
vconn_run_wait(vconn);
|
2012-07-12 16:32:56 -07:00
|
|
|
|
if (!blocked) {
|
|
|
|
|
vconn_recv_wait(vconn);
|
|
|
|
|
}
|
2011-12-20 15:31:34 -08:00
|
|
|
|
unixctl_server_wait(server);
|
|
|
|
|
poll_block();
|
2010-05-11 12:44:58 -07:00
|
|
|
|
}
|
2012-02-03 12:33:06 -08:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
unixctl_server_destroy(server);
|
2010-05-11 12:44:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_monitor(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
struct vconn *vconn;
|
2012-07-12 14:18:05 -07:00
|
|
|
|
int i;
|
2021-12-08 18:05:22 -05:00
|
|
|
|
enum ofputil_protocol protocol;
|
2013-08-20 18:41:45 -07:00
|
|
|
|
enum ofputil_protocol usable_protocols;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2015-12-21 15:39:10 -08:00
|
|
|
|
/* If the user wants the invalid_ttl_to_controller feature, limit the
|
|
|
|
|
* OpenFlow versions to those that support that feature. (Support in
|
|
|
|
|
* OpenFlow 1.0 is an Open vSwitch extension.) */
|
|
|
|
|
for (i = 2; i < ctx->argc; i++) {
|
|
|
|
|
if (!strcmp(ctx->argv[i], "invalid_ttl")) {
|
|
|
|
|
uint32_t usable_versions = ((1u << OFP10_VERSION) |
|
|
|
|
|
(1u << OFP11_VERSION) |
|
|
|
|
|
(1u << OFP12_VERSION));
|
|
|
|
|
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,
|
|
|
|
|
usable_versions);
|
|
|
|
|
ovs_fatal(0, "invalid_ttl requires one of the OpenFlow "
|
|
|
|
|
"versions %s but none is enabled (use -O)",
|
|
|
|
|
ds_cstr(&versions));
|
|
|
|
|
}
|
|
|
|
|
mask_allowed_ofp_versions(usable_versions);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-08 18:05:22 -05:00
|
|
|
|
protocol = open_vconn(ctx->argv[1], &vconn);
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
bool resume_continuations = false;
|
2015-03-17 10:35:26 -04:00
|
|
|
|
for (i = 2; i < ctx->argc; i++) {
|
|
|
|
|
const char *arg = ctx->argv[i];
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2012-07-12 14:18:05 -07:00
|
|
|
|
if (isdigit((unsigned char) *arg)) {
|
2015-12-21 15:39:10 -08:00
|
|
|
|
struct ofputil_switch_config config;
|
2012-07-12 14:18:05 -07:00
|
|
|
|
|
|
|
|
|
fetch_switch_config(vconn, &config);
|
2015-12-21 15:39:10 -08:00
|
|
|
|
config.miss_send_len = atoi(arg);
|
2012-07-12 14:18:05 -07:00
|
|
|
|
set_switch_config(vconn, &config);
|
|
|
|
|
} else if (!strcmp(arg, "invalid_ttl")) {
|
2012-01-13 17:54:04 -08:00
|
|
|
|
monitor_set_invalid_ttl_to_controller(vconn);
|
2012-07-12 14:18:05 -07:00
|
|
|
|
} else if (!strncmp(arg, "watch:", 6)) {
|
|
|
|
|
struct ofputil_flow_monitor_request fmr;
|
|
|
|
|
struct ofpbuf *msg;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
char *error;
|
2012-07-12 14:18:05 -07:00
|
|
|
|
|
2013-08-20 18:41:45 -07:00
|
|
|
|
error = parse_flow_monitor_request(&fmr, arg + 6,
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ports_to_accept(ctx->argv[1]),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_accept(ctx->argv[1]),
|
2013-08-20 18:41:45 -07:00
|
|
|
|
&usable_protocols);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
2012-07-12 14:18:05 -07:00
|
|
|
|
|
2019-07-23 13:02:10 -07:00
|
|
|
|
if (!(usable_protocols & allowed_protocols)) {
|
|
|
|
|
char *allowed_s =
|
|
|
|
|
ofputil_protocols_to_string(allowed_protocols);
|
|
|
|
|
char *usable_s = ofputil_protocols_to_string(usable_protocols);
|
|
|
|
|
ovs_fatal(0, "none of the usable flow formats (%s) is among "
|
|
|
|
|
"the allowed flow formats (%s)", usable_s, allowed_s);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-12 14:18:05 -07:00
|
|
|
|
msg = ofpbuf_new(0);
|
2021-12-08 18:05:22 -05:00
|
|
|
|
ofputil_append_flow_monitor_request(&fmr, msg, protocol);
|
2021-12-08 18:05:23 -05:00
|
|
|
|
|
|
|
|
|
if (verbosity) {
|
|
|
|
|
ofpmsg_update_length(msg);
|
|
|
|
|
ofp_print(stdout, msg->data, msg->size, NULL,
|
|
|
|
|
NULL, verbosity + 2);
|
|
|
|
|
}
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, msg);
|
2014-05-16 12:08:53 -07:00
|
|
|
|
fflush(stdout);
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
} else if (!strcmp(arg, "resume")) {
|
|
|
|
|
/* This option is intentionally undocumented because it is meant
|
|
|
|
|
* only for testing. */
|
|
|
|
|
resume_continuations = true;
|
|
|
|
|
|
|
|
|
|
/* Set miss_send_len to ensure that we get packet-ins. */
|
|
|
|
|
struct ofputil_switch_config config;
|
|
|
|
|
fetch_switch_config(vconn, &config);
|
|
|
|
|
config.miss_send_len = UINT16_MAX;
|
|
|
|
|
set_switch_config(vconn, &config);
|
2012-07-12 14:18:05 -07:00
|
|
|
|
} else {
|
|
|
|
|
ovs_fatal(0, "%s: unsupported \"monitor\" argument", arg);
|
2012-01-13 17:54:04 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-07-12 14:18:05 -07:00
|
|
|
|
|
2012-01-27 09:22:41 -08:00
|
|
|
|
if (preferred_packet_in_format >= 0) {
|
2016-02-19 15:31:37 -08:00
|
|
|
|
/* A particular packet-in format was requested, so we must set it. */
|
|
|
|
|
set_packet_in_format(vconn, preferred_packet_in_format, true);
|
2012-01-27 09:22:41 -08:00
|
|
|
|
} else {
|
2016-02-19 15:31:37 -08:00
|
|
|
|
/* Otherwise, we always prefer NXT_PACKET_IN2. */
|
2018-02-16 11:43:56 -08:00
|
|
|
|
if (!set_packet_in_format(vconn, OFPUTIL_PACKET_IN_NXT2, false)) {
|
2016-02-19 15:31:37 -08:00
|
|
|
|
/* We can't get NXT_PACKET_IN2. For OpenFlow 1.0 only, request
|
|
|
|
|
* NXT_PACKET_IN. (Before 2.6, Open vSwitch will accept a request
|
|
|
|
|
* for NXT_PACKET_IN with OF1.1+, but even after that it still
|
|
|
|
|
* sends packet-ins in the OpenFlow native format.) */
|
|
|
|
|
if (vconn_get_version(vconn) == OFP10_VERSION) {
|
2018-02-16 11:43:56 -08:00
|
|
|
|
set_packet_in_format(vconn, OFPUTIL_PACKET_IN_NXT, false);
|
2012-11-19 14:59:34 +09:00
|
|
|
|
}
|
2012-01-27 09:22:41 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
monitor_vconn(vconn, true, resume_continuations);
|
2010-05-11 12:44:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_snoop(struct ovs_cmdl_context *ctx)
|
2010-05-11 12:44:58 -07:00
|
|
|
|
{
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
2018-04-20 15:28:38 -07:00
|
|
|
|
/* We can't use the snoop vconn to send table features request or port
|
|
|
|
|
* description request messages to show names, because ovs-vswitchd will
|
|
|
|
|
* not respond to these messages on snoop vconn. */
|
|
|
|
|
use_names = 0;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn__(ctx->argv[1], SNOOP, &vconn);
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
monitor_vconn(vconn, false, false);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_ports(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2010-01-19 22:35:18 -08:00
|
|
|
|
struct ofpbuf *request;
|
2012-08-21 13:55:37 +09:00
|
|
|
|
struct vconn *vconn;
|
2013-06-19 16:58:44 -07:00
|
|
|
|
ofp_port_t port;
|
2010-01-19 22:35:18 -08:00
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
|
|
|
|
port = ctx->argc > 2 ? str_to_port_no(ctx->argv[1], ctx->argv[2]) : OFPP_ANY;
|
2012-10-06 19:39:49 +09:00
|
|
|
|
request = ofputil_encode_dump_ports_request(vconn_get_version(vconn), port);
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, request);
|
2012-08-21 13:55:37 +09:00
|
|
|
|
vconn_close(vconn);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-04 14:42:04 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_ports_desc(struct ovs_cmdl_context *ctx)
|
2012-05-04 14:42:04 -07:00
|
|
|
|
{
|
2014-05-07 23:18:46 -07:00
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
ofp_port_t port;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
|
|
|
|
port = ctx->argc > 2 ? str_to_port_no(ctx->argv[1], ctx->argv[2]) : OFPP_ANY;
|
2014-05-07 23:18:46 -07:00
|
|
|
|
request = ofputil_encode_port_desc_stats_request(vconn_get_version(vconn),
|
|
|
|
|
port);
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, request);
|
2014-05-07 23:18:46 -07:00
|
|
|
|
vconn_close(vconn);
|
2012-05-04 14:42:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_probe(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
2018-02-15 13:43:41 -08:00
|
|
|
|
request = ofputil_encode_echo_request(vconn_get_version(vconn));
|
2015-03-17 10:35:26 -04:00
|
|
|
|
run(vconn_transact(vconn, request, &reply), "talking to %s", ctx->argv[1]);
|
2015-03-02 17:29:44 -08:00
|
|
|
|
if (reply->size != sizeof(struct ofp_header)) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ovs_fatal(0, "reply does not match request");
|
|
|
|
|
}
|
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-25 16:30:28 -08:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_packet_out(struct ovs_cmdl_context *ctx)
|
2012-01-25 16:30:28 -08:00
|
|
|
|
{
|
2016-09-14 16:51:27 -07:00
|
|
|
|
enum ofputil_protocol usable_protocols;
|
2012-08-08 12:19:57 +09:00
|
|
|
|
enum ofputil_protocol protocol;
|
2012-01-25 16:30:28 -08:00
|
|
|
|
struct ofputil_packet_out po;
|
|
|
|
|
struct vconn *vconn;
|
2016-09-14 16:51:27 -07:00
|
|
|
|
struct ofpbuf *opo;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
char *error;
|
2012-01-25 16:30:28 -08:00
|
|
|
|
|
2017-05-15 10:04:55 -07:00
|
|
|
|
match_init_catchall(&po.flow_metadata);
|
2016-09-14 16:51:27 -07:00
|
|
|
|
/* Use the old syntax when more than 4 arguments are given. */
|
|
|
|
|
if (ctx->argc > 4) {
|
|
|
|
|
struct ofpbuf ofpacts;
|
|
|
|
|
int i;
|
2012-01-25 16:30:28 -08:00
|
|
|
|
|
2016-09-14 16:51:27 -07:00
|
|
|
|
ofpbuf_init(&ofpacts, 64);
|
2018-01-12 12:56:12 -08:00
|
|
|
|
struct ofpact_parse_params pp = {
|
|
|
|
|
.port_map = ports_to_accept(ctx->argv[1]),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
.table_map = tables_to_accept(ctx->argv[1]),
|
2018-01-12 12:56:12 -08:00
|
|
|
|
.ofpacts = &ofpacts,
|
|
|
|
|
.usable_protocols = &usable_protocols
|
|
|
|
|
};
|
|
|
|
|
error = ofpacts_parse_actions(ctx->argv[3], &pp);
|
2016-09-14 16:51:27 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
2012-01-25 16:30:28 -08:00
|
|
|
|
|
2016-09-14 16:51:27 -07:00
|
|
|
|
po.buffer_id = UINT32_MAX;
|
2017-05-15 10:04:55 -07:00
|
|
|
|
match_set_in_port(&po.flow_metadata,
|
|
|
|
|
str_to_port_no(ctx->argv[1], ctx->argv[2]));
|
2016-09-14 16:51:27 -07:00
|
|
|
|
po.ofpacts = ofpacts.data;
|
|
|
|
|
po.ofpacts_len = ofpacts.size;
|
2017-06-23 16:48:47 +00:00
|
|
|
|
po.flow_metadata.flow.packet_type = htonl(PT_ETH);
|
2012-01-25 16:30:28 -08:00
|
|
|
|
|
2016-09-14 16:51:27 -07:00
|
|
|
|
protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn,
|
|
|
|
|
usable_protocols);
|
|
|
|
|
for (i = 4; i < ctx->argc; i++) {
|
|
|
|
|
struct dp_packet *packet;
|
|
|
|
|
const char *error_msg;
|
|
|
|
|
|
|
|
|
|
error_msg = eth_from_hex(ctx->argv[i], &packet);
|
|
|
|
|
if (error_msg) {
|
|
|
|
|
ovs_fatal(0, "%s", error_msg);
|
|
|
|
|
}
|
2012-01-25 16:30:28 -08:00
|
|
|
|
|
2016-09-14 16:51:27 -07:00
|
|
|
|
po.packet = dp_packet_data(packet);
|
|
|
|
|
po.packet_len = dp_packet_size(packet);
|
|
|
|
|
opo = ofputil_encode_packet_out(&po, protocol);
|
|
|
|
|
transact_noreply(vconn, opo);
|
|
|
|
|
dp_packet_delete(packet);
|
|
|
|
|
}
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
ofpbuf_uninit(&ofpacts);
|
|
|
|
|
} else if (ctx->argc == 3) {
|
2017-05-31 16:06:12 -07:00
|
|
|
|
error = parse_ofp_packet_out_str(&po, ctx->argv[2],
|
|
|
|
|
ports_to_accept(ctx->argv[1]),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_accept(ctx->argv[1]),
|
2017-05-31 16:06:12 -07:00
|
|
|
|
&usable_protocols);
|
2016-09-14 16:51:27 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn,
|
|
|
|
|
usable_protocols);
|
2012-08-08 12:19:57 +09:00
|
|
|
|
opo = ofputil_encode_packet_out(&po, protocol);
|
2012-01-25 16:30:28 -08:00
|
|
|
|
transact_noreply(vconn, opo);
|
2016-11-21 13:42:39 -08:00
|
|
|
|
vconn_close(vconn);
|
2016-09-14 16:51:27 -07:00
|
|
|
|
free(CONST_CAST(void *, po.packet));
|
|
|
|
|
free(po.ofpacts);
|
|
|
|
|
} else {
|
|
|
|
|
ovs_fatal(0, "Too many arguments (%d)", ctx->argc);
|
2012-01-25 16:30:28 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_mod_port(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2012-05-24 14:01:02 -07:00
|
|
|
|
struct ofp_config_flag {
|
|
|
|
|
const char *name; /* The flag's name. */
|
|
|
|
|
enum ofputil_port_config bit; /* Bit to turn on or off. */
|
|
|
|
|
bool on; /* Value to set the bit to. */
|
|
|
|
|
};
|
|
|
|
|
static const struct ofp_config_flag flags[] = {
|
|
|
|
|
{ "up", OFPUTIL_PC_PORT_DOWN, false },
|
|
|
|
|
{ "down", OFPUTIL_PC_PORT_DOWN, true },
|
|
|
|
|
{ "stp", OFPUTIL_PC_NO_STP, false },
|
|
|
|
|
{ "receive", OFPUTIL_PC_NO_RECV, false },
|
|
|
|
|
{ "receive-stp", OFPUTIL_PC_NO_RECV_STP, false },
|
|
|
|
|
{ "flood", OFPUTIL_PC_NO_FLOOD, false },
|
|
|
|
|
{ "forward", OFPUTIL_PC_NO_FWD, false },
|
|
|
|
|
{ "packet-in", OFPUTIL_PC_NO_PACKET_IN, false },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const struct ofp_config_flag *flag;
|
2012-02-15 16:33:04 -08:00
|
|
|
|
enum ofputil_protocol protocol;
|
|
|
|
|
struct ofputil_port_mod pm;
|
|
|
|
|
struct ofputil_phy_port pp;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
struct vconn *vconn;
|
2012-05-24 14:01:02 -07:00
|
|
|
|
const char *command;
|
|
|
|
|
bool not;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
fetch_ofputil_phy_port(ctx->argv[1], ctx->argv[2], &pp);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2012-02-15 16:33:04 -08:00
|
|
|
|
pm.port_no = pp.port_no;
|
2015-08-28 14:55:11 -07:00
|
|
|
|
pm.hw_addr = pp.hw_addr;
|
2012-02-15 16:33:04 -08:00
|
|
|
|
pm.config = 0;
|
|
|
|
|
pm.mask = 0;
|
|
|
|
|
pm.advertise = 0;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
if (!strncasecmp(ctx->argv[3], "no-", 3)) {
|
|
|
|
|
command = ctx->argv[3] + 3;
|
2012-05-24 14:01:02 -07:00
|
|
|
|
not = true;
|
2015-03-17 10:35:26 -04:00
|
|
|
|
} else if (!strncasecmp(ctx->argv[3], "no", 2)) {
|
|
|
|
|
command = ctx->argv[3] + 2;
|
2012-05-24 14:01:02 -07:00
|
|
|
|
not = true;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
} else {
|
2015-03-17 10:35:26 -04:00
|
|
|
|
command = ctx->argv[3];
|
2012-05-24 14:01:02 -07:00
|
|
|
|
not = false;
|
|
|
|
|
}
|
|
|
|
|
for (flag = flags; flag < &flags[ARRAY_SIZE(flags)]; flag++) {
|
|
|
|
|
if (!strcasecmp(command, flag->name)) {
|
|
|
|
|
pm.mask = flag->bit;
|
|
|
|
|
pm.config = flag->on ^ not ? flag->bit : 0;
|
|
|
|
|
goto found;
|
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ovs_fatal(0, "unknown mod-port command '%s'", ctx->argv[3]);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2012-05-24 14:01:02 -07:00
|
|
|
|
found:
|
2015-03-17 10:35:26 -04:00
|
|
|
|
protocol = open_vconn(ctx->argv[1], &vconn);
|
2012-02-15 16:33:04 -08:00
|
|
|
|
transact_noreply(vconn, ofputil_encode_port_mod(&pm, protocol));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-24 17:49:42 +05:30
|
|
|
|
/* This function uses OFPMP14_TABLE_DESC request to get the current
|
|
|
|
|
* table configuration from switch. The function then modifies
|
|
|
|
|
* only that table-config property, which has been requested. */
|
|
|
|
|
static void
|
|
|
|
|
fetch_table_desc(struct vconn *vconn, struct ofputil_table_mod *tm,
|
|
|
|
|
struct ofputil_table_desc *td)
|
|
|
|
|
{
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
ovs_be32 send_xid;
|
|
|
|
|
bool done = false;
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
|
|
request = ofputil_encode_table_desc_request(vconn_get_version(vconn));
|
|
|
|
|
send_xid = ((struct ofp_header *) request->data)->xid;
|
|
|
|
|
send_openflow_buffer(vconn, request);
|
|
|
|
|
while (!done) {
|
|
|
|
|
ovs_be32 recv_xid;
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
|
|
|
|
|
run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
|
|
|
|
|
recv_xid = ((struct ofp_header *) reply->data)->xid;
|
|
|
|
|
if (send_xid == recv_xid) {
|
|
|
|
|
struct ofp_header *oh = reply->data;
|
2016-02-18 15:13:09 -08:00
|
|
|
|
struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
|
2015-11-24 17:49:42 +05:30
|
|
|
|
|
2016-02-18 15:13:09 -08:00
|
|
|
|
enum ofptype type;
|
2015-11-24 17:49:42 +05:30
|
|
|
|
if (ofptype_pull(&type, &b)
|
|
|
|
|
|| type != OFPTYPE_TABLE_DESC_REPLY) {
|
|
|
|
|
ovs_fatal(0, "received bad reply: %s",
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ofp_to_string(reply->data, reply->size, NULL, NULL,
|
2015-11-24 17:49:42 +05:30
|
|
|
|
verbosity + 1));
|
|
|
|
|
}
|
2016-02-18 15:13:09 -08:00
|
|
|
|
uint16_t flags = ofpmp_flags(oh);
|
2015-11-24 17:49:42 +05:30
|
|
|
|
done = !(flags & OFPSF_REPLY_MORE);
|
|
|
|
|
if (found) {
|
|
|
|
|
/* We've already found the table desc consisting of current
|
|
|
|
|
* table configuration, but we need to drain the queue of
|
|
|
|
|
* any other replies for this request. */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
while (!ofputil_decode_table_desc(&b, td, oh->version)) {
|
|
|
|
|
if (td->table_id == tm->table_id) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
VLOG_DBG("received reply with xid %08"PRIx32" "
|
|
|
|
|
"!= expected %08"PRIx32, recv_xid, send_xid);
|
|
|
|
|
}
|
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
}
|
|
|
|
|
if (tm->eviction != OFPUTIL_TABLE_EVICTION_DEFAULT) {
|
|
|
|
|
tm->vacancy = td->vacancy;
|
|
|
|
|
tm->table_vacancy.vacancy_down = td->table_vacancy.vacancy_down;
|
|
|
|
|
tm->table_vacancy.vacancy_up = td->table_vacancy.vacancy_up;
|
|
|
|
|
} else if (tm->vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
|
|
|
|
|
tm->eviction = td->eviction;
|
|
|
|
|
tm->eviction_flags = td->eviction_flags;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-29 11:30:13 -07:00
|
|
|
|
static void
|
|
|
|
|
change_table_name(struct vconn *vconn, uint8_t table_id, const char *new_name)
|
|
|
|
|
{
|
|
|
|
|
/* Get all tables' features and properties. */
|
|
|
|
|
struct table {
|
|
|
|
|
struct ofputil_table_features tf;
|
|
|
|
|
struct ofpbuf *raw_properties;
|
|
|
|
|
} *tables[256];
|
|
|
|
|
memset(tables, 0, sizeof tables);
|
|
|
|
|
|
|
|
|
|
struct table_iterator ti;
|
|
|
|
|
table_iterator_init(&ti, vconn);
|
|
|
|
|
while (table_iterator_next(&ti)) {
|
|
|
|
|
struct table *t = tables[ti.features.table_id] = xmalloc(sizeof *t);
|
|
|
|
|
t->tf = ti.features;
|
|
|
|
|
t->raw_properties = ofpbuf_clone(&ti.raw_properties);
|
|
|
|
|
}
|
|
|
|
|
table_iterator_destroy(&ti);
|
|
|
|
|
|
|
|
|
|
/* Change the name for table 'table_id'. */
|
|
|
|
|
struct table *t = tables[table_id];
|
|
|
|
|
if (!t) {
|
|
|
|
|
ovs_fatal(0, "switch does not have table %"PRIu8, table_id);
|
|
|
|
|
}
|
|
|
|
|
ovs_strlcpy(t->tf.name, new_name, OFP_MAX_TABLE_NAME_LEN);
|
|
|
|
|
|
|
|
|
|
/* Compose the transaction. */
|
|
|
|
|
enum ofp_version version = vconn_get_version(vconn);
|
|
|
|
|
struct ovs_list requests = OVS_LIST_INITIALIZER(&requests);
|
|
|
|
|
struct ofpbuf *tfr = ofputil_encode_table_features_request(version);
|
|
|
|
|
ovs_list_push_back(&requests, &tfr->list_node);
|
|
|
|
|
if (version >= OFP15_VERSION) {
|
|
|
|
|
/* For OpenFlow 1.5, we can use a single OFPTFC15_MODIFY without any
|
|
|
|
|
* properties. */
|
|
|
|
|
t->tf.command = OFPTFC15_MODIFY;
|
|
|
|
|
t->tf.any_properties = false;
|
|
|
|
|
ofputil_append_table_features(&t->tf, NULL, &requests);
|
|
|
|
|
} else {
|
|
|
|
|
/* For OpenFlow 1.3 and 1.4, we have to regurgitate all of the tables
|
|
|
|
|
* and their properties. */
|
|
|
|
|
for (size_t i = 0; i < 256; i++) {
|
|
|
|
|
if (tables[i]) {
|
|
|
|
|
ofputil_append_table_features(&tables[i]->tf,
|
|
|
|
|
tables[i]->raw_properties,
|
|
|
|
|
&requests);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Transact.
|
|
|
|
|
*
|
|
|
|
|
* The reply repeats the entire new configuration of the tables, so we
|
|
|
|
|
* don't bother printing it unless there's an error. */
|
|
|
|
|
struct ovs_list replies;
|
|
|
|
|
struct ofpbuf *reply;
|
|
|
|
|
vconn_transact_multipart(vconn, &requests, &replies);
|
|
|
|
|
LIST_FOR_EACH (reply, list_node, &replies) {
|
|
|
|
|
enum ofptype type;
|
|
|
|
|
enum ofperr error = ofptype_decode(&type, reply->data);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "decode error: %s", ofperr_get_name(error));
|
|
|
|
|
} else if (type == OFPTYPE_ERROR) {
|
|
|
|
|
ofp_print(stderr, reply->data, reply->size, NULL, NULL,
|
|
|
|
|
verbosity + 1);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ofpbuf_list_delete(&replies);
|
|
|
|
|
|
|
|
|
|
/* Clean up. */
|
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(tables); i++) {
|
|
|
|
|
if (tables[i]) {
|
|
|
|
|
ofpbuf_delete(tables[i]->raw_properties);
|
|
|
|
|
free(tables[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-07 03:02:32 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_mod_table(struct ovs_cmdl_context *ctx)
|
2013-09-07 03:02:32 -07:00
|
|
|
|
{
|
2015-07-02 20:33:08 -07:00
|
|
|
|
uint32_t usable_versions;
|
2013-09-07 03:02:32 -07:00
|
|
|
|
struct ofputil_table_mod tm;
|
2018-08-29 11:30:13 -07:00
|
|
|
|
const char *name;
|
2013-09-07 03:02:32 -07:00
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
char *error;
|
2015-11-24 17:49:42 +05:30
|
|
|
|
int i;
|
2013-09-07 03:02:32 -07:00
|
|
|
|
|
2018-08-29 11:30:13 -07:00
|
|
|
|
error = parse_ofp_table_mod(&tm, &name, ctx->argv[2], ctx->argv[3],
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_accept(ctx->argv[1]),
|
2015-07-02 20:33:08 -07:00
|
|
|
|
&usable_versions);
|
2013-09-07 03:02:32 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 20:33:08 -07:00
|
|
|
|
uint32_t allowed_versions = get_allowed_ofp_versions();
|
|
|
|
|
if (!(allowed_versions & usable_versions)) {
|
|
|
|
|
struct ds versions = DS_EMPTY_INITIALIZER;
|
2015-11-24 17:49:42 +05:30
|
|
|
|
ofputil_format_version_bitmap_names(&versions, usable_versions);
|
2015-07-02 20:33:08 -07:00
|
|
|
|
ovs_fatal(0, "table_mod '%s' requires one of the OpenFlow "
|
2015-11-24 17:49:42 +05:30
|
|
|
|
"versions %s",
|
2015-07-02 20:33:08 -07:00
|
|
|
|
ctx->argv[3], ds_cstr(&versions));
|
2013-09-07 03:02:32 -07:00
|
|
|
|
}
|
2015-07-02 20:33:08 -07:00
|
|
|
|
mask_allowed_ofp_versions(usable_versions);
|
|
|
|
|
enum ofputil_protocol protocol = open_vconn(ctx->argv[1], &vconn);
|
2015-11-24 17:49:42 +05:30
|
|
|
|
|
2018-08-29 11:30:13 -07:00
|
|
|
|
if (name) {
|
|
|
|
|
change_table_name(vconn, tm.table_id, name);
|
|
|
|
|
} else {
|
|
|
|
|
/* For OpenFlow 1.4+, ovs-ofctl mod-table should not affect
|
|
|
|
|
* table-config properties that the user didn't ask to change, so it is
|
|
|
|
|
* necessary to restore the current configuration of table-config
|
|
|
|
|
* parameters using OFPMP14_TABLE_DESC request. */
|
|
|
|
|
if (allowed_versions & ((1u << OFP14_VERSION) |
|
2019-01-17 16:20:20 -08:00
|
|
|
|
(1u << OFP15_VERSION))) {
|
2018-08-29 11:30:13 -07:00
|
|
|
|
struct ofputil_table_desc td;
|
|
|
|
|
|
|
|
|
|
if (tm.table_id == OFPTT_ALL) {
|
|
|
|
|
for (i = 0; i < OFPTT_MAX; i++) {
|
|
|
|
|
tm.table_id = i;
|
|
|
|
|
fetch_table_desc(vconn, &tm, &td);
|
|
|
|
|
transact_noreply(vconn,
|
|
|
|
|
ofputil_encode_table_mod(&tm, protocol));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2015-11-24 17:49:42 +05:30
|
|
|
|
fetch_table_desc(vconn, &tm, &td);
|
2018-08-29 11:30:13 -07:00
|
|
|
|
transact_noreply(vconn, ofputil_encode_table_mod(&tm,
|
|
|
|
|
protocol));
|
2015-11-24 17:49:42 +05:30
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol));
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-09-07 03:02:32 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_get_frags(struct ovs_cmdl_context *ctx)
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
{
|
2015-12-21 15:39:10 -08:00
|
|
|
|
struct ofputil_switch_config config;
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
fetch_switch_config(vconn, &config);
|
2015-12-21 15:39:10 -08:00
|
|
|
|
puts(ofputil_frag_handling_to_string(config.frag));
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_set_frags(struct ovs_cmdl_context *ctx)
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
{
|
2015-12-21 15:39:10 -08:00
|
|
|
|
struct ofputil_switch_config config;
|
|
|
|
|
enum ofputil_frag_handling frag;
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
2015-12-21 15:39:10 -08:00
|
|
|
|
if (!ofputil_frag_handling_from_string(ctx->argv[2], &frag)) {
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ovs_fatal(0, "%s: unknown fragment handling mode", ctx->argv[2]);
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
}
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
fetch_switch_config(vconn, &config);
|
2015-12-21 15:39:10 -08:00
|
|
|
|
if (frag != config.frag) {
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
/* Set the configuration. */
|
2015-12-21 15:39:10 -08:00
|
|
|
|
config.frag = frag;
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
set_switch_config(vconn, &config);
|
|
|
|
|
|
|
|
|
|
/* Then retrieve the configuration to see if it really took. OpenFlow
|
2015-12-21 15:39:10 -08:00
|
|
|
|
* has ill-defined error reporting for bad flags, so this is about the
|
|
|
|
|
* best we can do. */
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
fetch_switch_config(vconn, &config);
|
2015-12-21 15:39:10 -08:00
|
|
|
|
if (frag != config.frag) {
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
ovs_fatal(0, "%s: setting fragment handling mode failed (this "
|
|
|
|
|
"switch probably doesn't support mode \"%s\")",
|
2015-12-21 15:39:10 -08:00
|
|
|
|
ctx->argv[1], ofputil_frag_handling_to_string(frag));
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-06 09:45:07 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_ofp_parse(struct ovs_cmdl_context *ctx)
|
2013-08-06 09:45:07 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
const char *filename = ctx->argv[1];
|
2013-08-06 09:45:07 -07:00
|
|
|
|
struct ofpbuf b;
|
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
|
|
file = !strcmp(filename, "-") ? stdin : fopen(filename, "r");
|
|
|
|
|
if (file == NULL) {
|
|
|
|
|
ovs_fatal(errno, "%s: open", filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ofpbuf_init(&b, 65536);
|
|
|
|
|
for (;;) {
|
|
|
|
|
struct ofp_header *oh;
|
|
|
|
|
size_t length, tail_len;
|
|
|
|
|
void *tail;
|
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
|
|
ofpbuf_clear(&b);
|
|
|
|
|
oh = ofpbuf_put_uninit(&b, sizeof *oh);
|
|
|
|
|
n = fread(oh, 1, sizeof *oh, file);
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
break;
|
|
|
|
|
} else if (n < sizeof *oh) {
|
|
|
|
|
ovs_fatal(0, "%s: unexpected end of file mid-message", filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length = ntohs(oh->length);
|
|
|
|
|
if (length < sizeof *oh) {
|
2013-11-25 23:38:48 -08:00
|
|
|
|
ovs_fatal(0, "%s: %"PRIuSIZE"-byte message is too short for OpenFlow",
|
2013-08-06 09:45:07 -07:00
|
|
|
|
filename, length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tail_len = length - sizeof *oh;
|
|
|
|
|
tail = ofpbuf_put_uninit(&b, tail_len);
|
|
|
|
|
n = fread(tail, 1, tail_len, file);
|
|
|
|
|
if (n < tail_len) {
|
|
|
|
|
ovs_fatal(0, "%s: unexpected end of file mid-message", filename);
|
|
|
|
|
}
|
|
|
|
|
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ofp_print(stdout, b.data, b.size, NULL, NULL, verbosity + 2);
|
2013-08-06 09:45:07 -07:00
|
|
|
|
}
|
|
|
|
|
ofpbuf_uninit(&b);
|
|
|
|
|
|
|
|
|
|
if (file != stdin) {
|
|
|
|
|
fclose(file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-22 13:17:23 -08:00
|
|
|
|
static bool
|
|
|
|
|
is_openflow_port(ovs_be16 port_, char *ports[])
|
|
|
|
|
{
|
|
|
|
|
uint16_t port = ntohs(port_);
|
|
|
|
|
if (ports[0]) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; ports[i]; i++) {
|
|
|
|
|
if (port == atoi(ports[i])) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
return port == OFP_PORT || port == OFP_OLD_PORT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_ofp_parse_pcap(struct ovs_cmdl_context *ctx)
|
2013-11-22 13:17:23 -08:00
|
|
|
|
{
|
|
|
|
|
struct tcp_reader *reader;
|
2018-10-05 12:52:40 -04:00
|
|
|
|
struct pcap_file *p_file;
|
2013-11-22 13:17:23 -08:00
|
|
|
|
int error;
|
|
|
|
|
bool first;
|
|
|
|
|
|
2018-10-05 12:52:40 -04:00
|
|
|
|
p_file = ovs_pcap_open(ctx->argv[1], "rb");
|
|
|
|
|
if (!p_file) {
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ovs_fatal(errno, "%s: open failed", ctx->argv[1]);
|
2013-11-22 13:17:23 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reader = tcp_reader_open();
|
|
|
|
|
first = true;
|
|
|
|
|
for (;;) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
struct dp_packet *packet;
|
2013-11-22 13:17:23 -08:00
|
|
|
|
long long int when;
|
|
|
|
|
struct flow flow;
|
|
|
|
|
|
2018-10-05 12:52:40 -04:00
|
|
|
|
error = ovs_pcap_read(p_file, &packet, &when);
|
2013-11-22 13:17:23 -08:00
|
|
|
|
if (error) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-06-30 19:19:40 -07:00
|
|
|
|
pkt_metadata_init(&packet->md, ODPP_NONE);
|
2015-02-22 03:21:09 -08:00
|
|
|
|
flow_extract(packet, &flow);
|
2013-11-22 13:17:23 -08:00
|
|
|
|
if (flow.dl_type == htons(ETH_TYPE_IP)
|
|
|
|
|
&& flow.nw_proto == IPPROTO_TCP
|
2015-03-17 10:35:26 -04:00
|
|
|
|
&& (is_openflow_port(flow.tp_src, ctx->argv + 2) ||
|
|
|
|
|
is_openflow_port(flow.tp_dst, ctx->argv + 2))) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
struct dp_packet *payload = tcp_reader_run(reader, &flow, packet);
|
2013-11-22 13:17:23 -08:00
|
|
|
|
if (payload) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
while (dp_packet_size(payload) >= sizeof(struct ofp_header)) {
|
2013-11-22 13:17:23 -08:00
|
|
|
|
const struct ofp_header *oh;
|
2015-02-22 03:21:09 -08:00
|
|
|
|
void *data = dp_packet_data(payload);
|
2013-11-22 13:17:23 -08:00
|
|
|
|
int length;
|
|
|
|
|
|
|
|
|
|
/* Align OpenFlow on 8-byte boundary for safe access. */
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_shift(payload, -((intptr_t) data & 7));
|
2013-11-22 13:17:23 -08:00
|
|
|
|
|
2015-02-22 03:21:09 -08:00
|
|
|
|
oh = dp_packet_data(payload);
|
2013-11-22 13:17:23 -08:00
|
|
|
|
length = ntohs(oh->length);
|
2018-07-31 13:28:29 -07:00
|
|
|
|
if (dp_packet_size(payload) < length
|
|
|
|
|
|| length < sizeof *oh) {
|
2013-11-22 13:17:23 -08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!first) {
|
|
|
|
|
putchar('\n');
|
|
|
|
|
}
|
|
|
|
|
first = false;
|
|
|
|
|
|
|
|
|
|
if (timestamp) {
|
|
|
|
|
char *s = xastrftime_msec("%H:%M:%S.### ", when, true);
|
|
|
|
|
fputs(s, stdout);
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf(IP_FMT".%"PRIu16" > "IP_FMT".%"PRIu16":\n",
|
|
|
|
|
IP_ARGS(flow.nw_src), ntohs(flow.tp_src),
|
|
|
|
|
IP_ARGS(flow.nw_dst), ntohs(flow.tp_dst));
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ofp_print(stdout, dp_packet_data(payload), length,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
NULL, NULL, verbosity + 1);
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_pull(payload, length);
|
2013-11-22 13:17:23 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_delete(packet);
|
2013-11-22 13:17:23 -08:00
|
|
|
|
}
|
|
|
|
|
tcp_reader_close(reader);
|
2018-10-05 12:52:40 -04:00
|
|
|
|
ovs_pcap_close(p_file);
|
2013-11-22 13:17:23 -08:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_ping(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
size_t max_payload = 65535 - sizeof(struct ofp_header);
|
|
|
|
|
unsigned int payload;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
int i;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
payload = ctx->argc > 2 ? atoi(ctx->argv[2]) : 64;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
if (payload > max_payload) {
|
2013-11-25 23:38:48 -08:00
|
|
|
|
ovs_fatal(0, "payload must be between 0 and %"PRIuSIZE" bytes", max_payload);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
|
|
|
struct timeval start, end;
|
|
|
|
|
struct ofpbuf *request, *reply;
|
2012-07-19 23:23:17 -07:00
|
|
|
|
const struct ofp_header *rpy_hdr;
|
|
|
|
|
enum ofptype type;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2012-11-19 14:59:32 +09:00
|
|
|
|
request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST,
|
|
|
|
|
vconn_get_version(vconn), payload);
|
2012-07-19 23:23:17 -07:00
|
|
|
|
random_bytes(ofpbuf_put_uninit(request, payload), payload);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-03-31 16:23:50 -07:00
|
|
|
|
xgettimeofday(&start);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
|
2011-03-31 16:23:50 -07:00
|
|
|
|
xgettimeofday(&end);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2015-03-02 17:29:44 -08:00
|
|
|
|
rpy_hdr = reply->data;
|
2012-07-19 23:23:17 -07:00
|
|
|
|
if (ofptype_pull(&type, reply)
|
|
|
|
|
|| type != OFPTYPE_ECHO_REPLY
|
2015-03-02 17:29:44 -08:00
|
|
|
|
|| reply->size != payload
|
|
|
|
|
|| memcmp(request->msg, reply->msg, payload)) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
printf("Reply does not match request. Request:\n");
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ofp_print(stdout, request, request->size, NULL, NULL,
|
|
|
|
|
verbosity + 2);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
printf("Reply:\n");
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ofp_print(stdout, reply, reply->size, NULL, NULL, verbosity + 2);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
lib/ofpbuf: Compact
This patch shrinks the struct ofpbuf from 104 to 48 bytes on 64-bit
systems, or from 52 to 36 bytes on 32-bit systems (counting in the
'l7' removal from an earlier patch). This may help contribute to
cache efficiency, and will speed up initializing, copying and
manipulating ofpbufs. This is potentially important for the DPDK
datapath, but the rest of the code base may also see a little benefit.
Changes are:
- Remove 'l7' pointer (previous patch).
- Use offsets instead of layer pointers for l2_5, l3, and l4 using
'l2' as basis. Usually 'data' is the same as 'l2', but this is not
always the case (e.g., when parsing or constructing a packet), so it
can not be easily used as the offset basis. Also, packet parsing is
faster if we do not need to maintain the offsets each time we pull
data from the ofpbuf.
- Use uint32_t for 'allocated' and 'size', as 2^32 is enough even for
largest possible messages/packets.
- Use packed enum for 'source'.
- Rearrange to avoid unnecessary padding.
- Remove 'private_p', which was used only in two cases, both of which
had the invariant ('l2' == 'data'), so we can temporarily use 'l2'
as a private pointer.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
2014-03-24 09:17:01 -07:00
|
|
|
|
printf("%"PRIu32" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
|
2015-03-17 10:35:26 -04:00
|
|
|
|
reply->size, ctx->argv[1], ntohl(rpy_hdr->xid),
|
2009-07-08 13:19:16 -07:00
|
|
|
|
(1000*(double)(end.tv_sec - start.tv_sec))
|
|
|
|
|
+ (.001*(end.tv_usec - start.tv_usec)));
|
|
|
|
|
ofpbuf_delete(request);
|
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
}
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_benchmark(struct ovs_cmdl_context *ctx)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
size_t max_payload = 65535 - sizeof(struct ofp_header);
|
|
|
|
|
struct timeval start, end;
|
|
|
|
|
unsigned int payload_size, message_size;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
double duration;
|
|
|
|
|
int count;
|
|
|
|
|
int i;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
payload_size = atoi(ctx->argv[2]);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
if (payload_size > max_payload) {
|
2013-11-25 23:38:48 -08:00
|
|
|
|
ovs_fatal(0, "payload must be between 0 and %"PRIuSIZE" bytes", max_payload);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
message_size = sizeof(struct ofp_header) + payload_size;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
count = atoi(ctx->argv[3]);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
printf("Sending %d packets * %u bytes (with header) = %u bytes total\n",
|
|
|
|
|
count, message_size, count * message_size);
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
2011-03-31 16:23:50 -07:00
|
|
|
|
xgettimeofday(&start);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
struct ofpbuf *request, *reply;
|
|
|
|
|
|
2012-11-19 14:59:32 +09:00
|
|
|
|
request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST,
|
|
|
|
|
vconn_get_version(vconn), payload_size);
|
2012-07-19 23:23:17 -07:00
|
|
|
|
ofpbuf_put_zeros(request, payload_size);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
run(vconn_transact(vconn, request, &reply), "transact");
|
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
}
|
2011-03-31 16:23:50 -07:00
|
|
|
|
xgettimeofday(&end);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
|
|
|
|
|
duration = ((1000*(double)(end.tv_sec - start.tv_sec))
|
|
|
|
|
+ (.001*(end.tv_usec - start.tv_usec)));
|
|
|
|
|
printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n",
|
|
|
|
|
duration, count / (duration / 1000.0),
|
|
|
|
|
count * message_size / (duration / 1000.0));
|
|
|
|
|
}
|
|
|
|
|
|
ipfix: Add support for exporting ipfix statistics.
It is meaningful for user to check the stats of IPFIX.
Using IPFIX stats, user can know how much flows the system
can support. It is also can be used for performance check
of IPFIX.
IPFIX stats is added for per IPFIX exporter. If bridge IPFIX is
enabled on the bridge, the whole bridge will have one exporter.
For flow IPFIX, the system keeps per id (column in
Flow_Sample_Collector_Set) per exporter.
1) Add 'ovs-ofctl dump-ipfix-bridge SWITCH' to export IPFIX stats of
the bridge which enable bridge IPFIX. The output format:
NXST_IPFIX_BRIDGE reply (xid=0x2):
bridge ipfix: flows=0, current flows=0, sampled pkts=0, \
ipv4 ok=0, ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
2) Add 'ovs-ofctl dump-ipfix-flow SWITCH' to export IPFIX stats of
the bridge which enable flow IPFIX. The output format:
NXST_IPFIX_FLOW reply (xid=0x2): 2 ids
id 1: flows=4, current flows=4, sampled pkts=14, ipv4 ok=13, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
id 2: flows=0, current flows=0, sampled pkts=0, ipv4 ok=0, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
flows: the number of total flow records, including those exported.
current flows: the number of current flow records cached.
sampled pkts: Successfully sampled packet count.
ipv4 ok: successfully sampled IPv4 flow packet count.
ipv6 ok: Successfully sampled IPv6 flow packet count.
tx pkts: the count of IPFIX exported packets sent to the collector(s).
pkts errs: count of packets failed when sampling, maybe not supported or other error.
ipv4 errs: Count of IPV4 flow packet in the error packets.
ipv6 errs: Count of IPV6 flow packet in the error packets.
tx errs: the count of IPFIX exported packets failed when sending to the collector(s).
Signed-off-by: Benli Ye <daniely@vmware.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-13 14:44:09 -07:00
|
|
|
|
static void
|
|
|
|
|
ofctl_dump_ipfix_bridge(struct ovs_cmdl_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
dump_trivial_transaction(ctx->argv[1], OFPRAW_NXST_IPFIX_BRIDGE_REQUEST);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-18 14:09:41 -07:00
|
|
|
|
static void
|
|
|
|
|
ofctl_ct_flush_zone(struct ovs_cmdl_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
uint16_t zone_id;
|
|
|
|
|
char *error = str_to_u16(ctx->argv[2], "zone_id", &zone_id);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
|
|
|
|
enum ofp_version version = vconn_get_version(vconn);
|
|
|
|
|
|
|
|
|
|
struct ofpbuf *msg = ofpraw_alloc(OFPRAW_NXT_CT_FLUSH_ZONE, version, 0);
|
|
|
|
|
struct nx_zone_id *nzi = ofpbuf_put_zeros(msg, sizeof *nzi);
|
|
|
|
|
nzi->zone_id = htons(zone_id);
|
|
|
|
|
|
|
|
|
|
transact_noreply(vconn, msg);
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 12:45:08 +01:00
|
|
|
|
static void
|
|
|
|
|
ofctl_ct_flush(struct ovs_cmdl_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
struct ofp_ct_match match = {0};
|
|
|
|
|
struct ds ds = DS_EMPTY_INITIALIZER;
|
|
|
|
|
uint16_t zone, *pzone = NULL;
|
|
|
|
|
int args = ctx->argc - 2;
|
|
|
|
|
|
|
|
|
|
/* Parse zone. */
|
|
|
|
|
if (args && !strncmp(ctx->argv[2], "zone=", 5)) {
|
|
|
|
|
if (!ovs_scan(ctx->argv[2], "zone=%"SCNu16, &zone)) {
|
|
|
|
|
ovs_fatal(0, "Failed to parse zone");
|
|
|
|
|
}
|
|
|
|
|
pzone = &zone;
|
|
|
|
|
args--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse ct tuples. */
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
|
if (!args) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ofp_ct_tuple *tuple =
|
|
|
|
|
i ? &match.tuple_reply : &match.tuple_orig;
|
|
|
|
|
const char *arg = ctx->argv[ctx->argc - args];
|
|
|
|
|
|
|
|
|
|
if (arg[0] && !ofp_ct_tuple_parse(tuple, arg, &ds, &match.ip_proto,
|
|
|
|
|
&match.l3_type)) {
|
|
|
|
|
ovs_fatal(0, "Failed to parse ct-tuple: %s", ds_cstr(&ds));
|
|
|
|
|
}
|
|
|
|
|
args--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
|
|
|
|
enum ofp_version version = vconn_get_version(vconn);
|
|
|
|
|
struct ofpbuf *msg = ofp_ct_match_encode(&match, pzone, version);
|
|
|
|
|
|
|
|
|
|
ds_destroy(&ds);
|
|
|
|
|
transact_noreply(vconn, msg);
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
ipfix: Add support for exporting ipfix statistics.
It is meaningful for user to check the stats of IPFIX.
Using IPFIX stats, user can know how much flows the system
can support. It is also can be used for performance check
of IPFIX.
IPFIX stats is added for per IPFIX exporter. If bridge IPFIX is
enabled on the bridge, the whole bridge will have one exporter.
For flow IPFIX, the system keeps per id (column in
Flow_Sample_Collector_Set) per exporter.
1) Add 'ovs-ofctl dump-ipfix-bridge SWITCH' to export IPFIX stats of
the bridge which enable bridge IPFIX. The output format:
NXST_IPFIX_BRIDGE reply (xid=0x2):
bridge ipfix: flows=0, current flows=0, sampled pkts=0, \
ipv4 ok=0, ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
2) Add 'ovs-ofctl dump-ipfix-flow SWITCH' to export IPFIX stats of
the bridge which enable flow IPFIX. The output format:
NXST_IPFIX_FLOW reply (xid=0x2): 2 ids
id 1: flows=4, current flows=4, sampled pkts=14, ipv4 ok=13, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
id 2: flows=0, current flows=0, sampled pkts=0, ipv4 ok=0, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
flows: the number of total flow records, including those exported.
current flows: the number of current flow records cached.
sampled pkts: Successfully sampled packet count.
ipv4 ok: successfully sampled IPv4 flow packet count.
ipv6 ok: Successfully sampled IPv6 flow packet count.
tx pkts: the count of IPFIX exported packets sent to the collector(s).
pkts errs: count of packets failed when sampling, maybe not supported or other error.
ipv4 errs: Count of IPV4 flow packet in the error packets.
ipv6 errs: Count of IPV6 flow packet in the error packets.
tx errs: the count of IPFIX exported packets failed when sending to the collector(s).
Signed-off-by: Benli Ye <daniely@vmware.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-13 14:44:09 -07:00
|
|
|
|
static void
|
|
|
|
|
ofctl_dump_ipfix_flow(struct ovs_cmdl_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
dump_trivial_transaction(ctx->argv[1], OFPRAW_NXST_IPFIX_FLOW_REQUEST);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-29 16:52:04 -07:00
|
|
|
|
static void
|
|
|
|
|
bundle_group_mod__(const char *remote, struct ofputil_group_mod *gms,
|
|
|
|
|
size_t n_gms, enum ofputil_protocol usable_protocols)
|
|
|
|
|
{
|
|
|
|
|
enum ofputil_protocol protocol;
|
|
|
|
|
enum ofp_version version;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
struct ovs_list requests;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
ovs_list_init(&requests);
|
|
|
|
|
|
|
|
|
|
/* Bundles need OpenFlow 1.3+. */
|
|
|
|
|
usable_protocols &= OFPUTIL_P_OF13_UP;
|
|
|
|
|
protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
|
|
|
|
|
version = ofputil_protocol_to_ofp_version(protocol);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_gms; i++) {
|
|
|
|
|
struct ofputil_group_mod *gm = &gms[i];
|
2018-09-25 14:06:37 -07:00
|
|
|
|
struct ofpbuf *request = ofputil_encode_group_mod(version, gm,
|
|
|
|
|
NULL, -1);
|
2016-07-29 16:52:04 -07:00
|
|
|
|
|
|
|
|
|
ovs_list_push_back(&requests, &request->list_node);
|
|
|
|
|
ofputil_uninit_group_mod(gm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC);
|
|
|
|
|
ofpbuf_list_delete(&requests);
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-01 18:30:17 -07:00
|
|
|
|
static void
|
|
|
|
|
ofctl_group_mod__(const char *remote, struct ofputil_group_mod *gms,
|
2014-11-05 15:55:47 -08:00
|
|
|
|
size_t n_gms, enum ofputil_protocol usable_protocols)
|
2013-09-01 18:30:17 -07:00
|
|
|
|
{
|
2014-11-05 15:55:47 -08:00
|
|
|
|
enum ofputil_protocol protocol;
|
2013-09-01 18:30:17 -07:00
|
|
|
|
struct ofputil_group_mod *gm;
|
2014-11-05 15:55:47 -08:00
|
|
|
|
enum ofp_version version;
|
2013-09-01 18:30:17 -07:00
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
2016-07-29 16:52:04 -07:00
|
|
|
|
if (bundle) {
|
|
|
|
|
bundle_group_mod__(remote, gms, n_gms, usable_protocols);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-05 15:55:47 -08:00
|
|
|
|
protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
|
|
|
|
|
version = ofputil_protocol_to_ofp_version(protocol);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_gms; i++) {
|
|
|
|
|
gm = &gms[i];
|
2018-09-25 14:06:37 -07:00
|
|
|
|
request = ofputil_encode_group_mod(version, gm, NULL, -1);
|
2016-07-29 16:52:04 -07:00
|
|
|
|
transact_noreply(vconn, request);
|
2016-07-29 16:52:04 -07:00
|
|
|
|
ofputil_uninit_group_mod(gm);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2016-07-29 16:52:04 -07:00
|
|
|
|
ofctl_group_mod_file(int argc OVS_UNUSED, char *argv[], int command)
|
2013-09-01 18:30:17 -07:00
|
|
|
|
{
|
|
|
|
|
struct ofputil_group_mod *gms = NULL;
|
|
|
|
|
enum ofputil_protocol usable_protocols;
|
|
|
|
|
size_t n_gms = 0;
|
|
|
|
|
char *error;
|
|
|
|
|
|
2016-07-29 16:52:04 -07:00
|
|
|
|
if (command == OFPGC11_ADD) {
|
|
|
|
|
/* Allow the file to specify a mix of commands. If none specified at
|
|
|
|
|
* the beginning of any given line, then the default is OFPGC11_ADD, so
|
|
|
|
|
* this is backwards compatible. */
|
|
|
|
|
command = -2;
|
|
|
|
|
}
|
2017-05-31 16:06:12 -07:00
|
|
|
|
error = parse_ofp_group_mod_file(argv[2], ports_to_accept(argv[1]),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_accept(argv[1]),
|
2017-05-31 16:06:12 -07:00
|
|
|
|
command, &gms, &n_gms, &usable_protocols);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
2014-11-05 15:55:47 -08:00
|
|
|
|
ofctl_group_mod__(argv[1], gms, n_gms, usable_protocols);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
free(gms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofctl_group_mod(int argc, char *argv[], uint16_t command)
|
|
|
|
|
{
|
|
|
|
|
if (argc > 2 && !strcmp(argv[2], "-")) {
|
|
|
|
|
ofctl_group_mod_file(argc, argv, command);
|
|
|
|
|
} else {
|
|
|
|
|
enum ofputil_protocol usable_protocols;
|
|
|
|
|
struct ofputil_group_mod gm;
|
|
|
|
|
char *error;
|
|
|
|
|
|
|
|
|
|
error = parse_ofp_group_mod_str(&gm, command, argc > 2 ? argv[2] : "",
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ports_to_accept(argv[1]),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_accept(argv[1]),
|
2013-09-01 18:30:17 -07:00
|
|
|
|
&usable_protocols);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
2014-11-05 15:55:47 -08:00
|
|
|
|
ofctl_group_mod__(argv[1], &gm, 1, usable_protocols);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_add_group(struct ovs_cmdl_context *ctx)
|
2013-09-01 18:30:17 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_group_mod(ctx->argc, ctx->argv, OFPGC11_ADD);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_add_groups(struct ovs_cmdl_context *ctx)
|
2013-09-01 18:30:17 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_group_mod_file(ctx->argc, ctx->argv, OFPGC11_ADD);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_mod_group(struct ovs_cmdl_context *ctx)
|
2013-09-01 18:30:17 -07:00
|
|
|
|
{
|
ofproto: Add relaxed group_mod command ADD_OR_MOD
This patch adds support for a new Group Mod command OFPGC_ADD_OR_MOD to
OVS for all OpenFlow versions that support groups (OF11 and higher).
The new ADD_OR_MOD creates a group that does not yet exist (like ADD)
and modifies an existing group (like MODIFY).
Rational: In OpenFlow 1.x the Group Mod commands OFPGC_ADD and
OFPGC_MODIFY have strict semantics: ADD fails if the group exists,
while MODIFY fails if the group does not exist. This requires a
controller to exactly know the state of the switch when programming a
group in order not run the risk of getting an OFP Error message in
response. This is hard to achieve and maintain at all times in view of
possible switch and controller restarts or other connection losses
between switch and controller.
Due to the un-acknowledged nature of the Group Mod message programming
groups safely and efficiently at the same time is virtually impossible
as the controller has to either query the existence of the group prior
to each Group Mod message or to insert a Barrier Request/Reply after
every group to be sure that no Error can be received at a later stage
and require a complicated roll-back of any dependent actions taken
between the failed Group Mod and the Error.
In the ovs-ofctl command line the ADD_OR_MOD command is made available
through the new option --may-create in the mod-group command:
$ ovs-ofctl -Oopenflow13 del-groups br-int group_id=100
$ ovs-ofctl -Oopenflow13 mod-group br-int
group_id=100,type=indirect,bucket=actions=2 OFPT_ERROR (OF1.3)
(xid=0x2): OFPGMFC_UNKNOWN_GROUP OFPT_GROUP_MOD (OF1.3) (xid=0x2):
MOD group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=2
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:2
$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=3
$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
group_id=100,type=indirect,bucket=actions=output:3
Signed-off-by: Jan Scheurich <jan.scheurich at web.de>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-29 00:29:25 +02:00
|
|
|
|
ofctl_group_mod(ctx->argc, ctx->argv,
|
|
|
|
|
may_create ? OFPGC11_ADD_OR_MOD : OFPGC11_MODIFY);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_del_groups(struct ovs_cmdl_context *ctx)
|
2013-09-01 18:30:17 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_group_mod(ctx->argc, ctx->argv, OFPGC11_DELETE);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 11:53:29 +09:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_insert_bucket(struct ovs_cmdl_context *ctx)
|
2014-11-13 11:53:29 +09:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_group_mod(ctx->argc, ctx->argv, OFPGC15_INSERT_BUCKET);
|
2014-11-13 11:53:29 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_remove_bucket(struct ovs_cmdl_context *ctx)
|
2014-11-13 11:53:29 +09:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_group_mod(ctx->argc, ctx->argv, OFPGC15_REMOVE_BUCKET);
|
2014-11-13 11:53:29 +09:00
|
|
|
|
}
|
|
|
|
|
|
2013-09-01 18:30:17 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_group_stats(struct ovs_cmdl_context *ctx)
|
2013-09-01 18:30:17 -07:00
|
|
|
|
{
|
|
|
|
|
enum ofputil_protocol usable_protocols;
|
|
|
|
|
struct ofputil_group_mod gm;
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
uint32_t group_id;
|
|
|
|
|
char *error;
|
|
|
|
|
|
|
|
|
|
memset(&gm, 0, sizeof gm);
|
|
|
|
|
|
|
|
|
|
error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE,
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ctx->argc > 2 ? ctx->argv[2] : "",
|
2017-05-31 16:06:12 -07:00
|
|
|
|
ports_to_accept(ctx->argv[1]),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_accept(ctx->argv[1]),
|
2013-09-01 18:30:17 -07:00
|
|
|
|
&usable_protocols);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
group_id = gm.group_id;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
request = ofputil_encode_group_stats_request(vconn_get_version(vconn),
|
|
|
|
|
group_id);
|
|
|
|
|
if (request) {
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, request);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_group_desc(struct ovs_cmdl_context *ctx)
|
2013-09-01 18:30:17 -07:00
|
|
|
|
{
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct vconn *vconn;
|
2014-05-07 23:49:00 -07:00
|
|
|
|
uint32_t group_id;
|
2013-09-01 18:30:17 -07:00
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
if (ctx->argc < 3 || !ofputil_group_from_string(ctx->argv[2], &group_id)) {
|
2015-11-24 10:01:23 -08:00
|
|
|
|
group_id = OFPG_ALL;
|
2014-05-07 23:49:00 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
request = ofputil_encode_group_desc_request(vconn_get_version(vconn),
|
|
|
|
|
group_id);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
if (request) {
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, request);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_group_features(struct ovs_cmdl_context *ctx)
|
2013-09-01 18:30:17 -07:00
|
|
|
|
{
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
open_vconn(ctx->argv[1], &vconn);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
request = ofputil_encode_group_features_request(vconn_get_version(vconn));
|
|
|
|
|
if (request) {
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, request);
|
2013-09-01 18:30:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-29 16:52:04 -07:00
|
|
|
|
static void
|
|
|
|
|
ofctl_bundle(struct ovs_cmdl_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
enum ofputil_protocol protocol, usable_protocols;
|
|
|
|
|
struct ofputil_bundle_msg *bms;
|
|
|
|
|
struct ovs_list requests;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
size_t n_bms;
|
|
|
|
|
char *error;
|
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
error = parse_ofp_bundle_file(ctx->argv[2], ports_to_accept(ctx->argv[1]),
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
tables_to_accept(ctx->argv[1]),
|
2017-05-31 16:06:12 -07:00
|
|
|
|
&bms, &n_bms, &usable_protocols);
|
2016-07-29 16:52:04 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Implicit OpenFlow 1.4. */
|
|
|
|
|
if (!(get_allowed_ofp_versions() &
|
|
|
|
|
ofputil_protocols_to_version_bitmap(OFPUTIL_P_OF13_UP))) {
|
|
|
|
|
|
|
|
|
|
/* Add implicit allowance for OpenFlow 1.4. */
|
|
|
|
|
add_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
|
|
|
|
|
OFPUTIL_P_OF14_OXM));
|
|
|
|
|
/* Remove all versions that do not support bundles. */
|
|
|
|
|
mask_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
|
|
|
|
|
OFPUTIL_P_OF13_UP));
|
|
|
|
|
allowed_protocols = ofputil_protocols_from_version_bitmap(
|
|
|
|
|
get_allowed_ofp_versions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Bundles need OpenFlow 1.3+. */
|
|
|
|
|
usable_protocols &= OFPUTIL_P_OF13_UP;
|
|
|
|
|
protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn, usable_protocols);
|
|
|
|
|
|
|
|
|
|
ovs_list_init(&requests);
|
|
|
|
|
ofputil_encode_bundle_msgs(bms, n_bms, &requests, protocol);
|
2016-09-14 16:51:27 -07:00
|
|
|
|
ofputil_free_bundle_msgs(bms, n_bms);
|
2016-07-29 16:52:04 -07:00
|
|
|
|
bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC);
|
|
|
|
|
ofpbuf_list_delete(&requests);
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
static void
|
2015-12-16 02:47:50 +08:00
|
|
|
|
ofctl_tlv_mod(struct ovs_cmdl_context *ctx, uint16_t command)
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
{
|
|
|
|
|
enum ofputil_protocol usable_protocols;
|
|
|
|
|
enum ofputil_protocol protocol;
|
2015-12-16 02:47:50 +08:00
|
|
|
|
struct ofputil_tlv_table_mod ttm;
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
char *error;
|
|
|
|
|
enum ofp_version version;
|
|
|
|
|
struct ofpbuf *request;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
2015-12-16 02:47:50 +08:00
|
|
|
|
error = parse_ofp_tlv_table_mod_str(&ttm, command, ctx->argc > 2 ?
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
ctx->argv[2] : "",
|
|
|
|
|
&usable_protocols);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn, usable_protocols);
|
|
|
|
|
version = ofputil_protocol_to_ofp_version(protocol);
|
|
|
|
|
|
2015-12-16 02:47:50 +08:00
|
|
|
|
request = ofputil_encode_tlv_table_mod(version, &ttm);
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
if (request) {
|
|
|
|
|
transact_noreply(vconn, request);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vconn_close(vconn);
|
2015-12-16 02:47:50 +08:00
|
|
|
|
ofputil_uninit_tlv_table(&ttm.mappings);
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-12-16 02:47:50 +08:00
|
|
|
|
ofctl_add_tlv_map(struct ovs_cmdl_context *ctx)
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
{
|
2015-12-16 02:47:50 +08:00
|
|
|
|
ofctl_tlv_mod(ctx, NXTTMC_ADD);
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-12-16 02:47:50 +08:00
|
|
|
|
ofctl_del_tlv_map(struct ovs_cmdl_context *ctx)
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
{
|
2015-12-16 02:47:50 +08:00
|
|
|
|
ofctl_tlv_mod(ctx, ctx->argc > 2 ? NXTTMC_DELETE : NXTTMC_CLEAR);
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-12-16 02:47:50 +08:00
|
|
|
|
ofctl_dump_tlv_map(struct ovs_cmdl_context *ctx)
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
{
|
2015-12-16 02:47:50 +08:00
|
|
|
|
dump_trivial_transaction(ctx->argv[1], OFPRAW_NXT_TLV_TABLE_REQUEST);
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-09 17:00:59 -08:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_help(struct ovs_cmdl_context *ctx OVS_UNUSED)
|
2010-11-09 17:00:59 -08:00
|
|
|
|
{
|
|
|
|
|
usage();
|
|
|
|
|
}
|
2014-10-16 13:27:32 -07:00
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_list_commands(struct ovs_cmdl_context *ctx OVS_UNUSED)
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{
|
2015-03-16 12:01:55 -04:00
|
|
|
|
ovs_cmdl_print_commands(get_all_commands());
|
2014-10-16 13:27:32 -07:00
|
|
|
|
}
|
2010-11-09 17:00:59 -08:00
|
|
|
|
|
2011-03-11 12:02:27 -08:00
|
|
|
|
/* replace-flows and diff-flows commands. */
|
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
struct flow_tables {
|
|
|
|
|
struct classifier tables[OFPTT_MAX + 1];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define FOR_EACH_TABLE(CLS, TABLES) \
|
|
|
|
|
for ((CLS) = (TABLES)->tables; \
|
|
|
|
|
(CLS) < &(TABLES)->tables[ARRAY_SIZE((TABLES)->tables)]; \
|
|
|
|
|
(CLS)++)
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
flow_tables_init(struct flow_tables *tables)
|
|
|
|
|
{
|
|
|
|
|
struct classifier *cls;
|
|
|
|
|
|
|
|
|
|
FOR_EACH_TABLE (cls, tables) {
|
|
|
|
|
classifier_init(cls, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
flow_tables_defer(struct flow_tables *tables)
|
|
|
|
|
{
|
|
|
|
|
struct classifier *cls;
|
|
|
|
|
|
|
|
|
|
FOR_EACH_TABLE (cls, tables) {
|
|
|
|
|
classifier_defer(cls);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
flow_tables_publish(struct flow_tables *tables)
|
|
|
|
|
{
|
|
|
|
|
struct classifier *cls;
|
|
|
|
|
|
|
|
|
|
FOR_EACH_TABLE (cls, tables) {
|
|
|
|
|
classifier_publish(cls);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-11 12:02:27 -08:00
|
|
|
|
/* A flow table entry, possibly with two different versions. */
|
|
|
|
|
struct fte {
|
|
|
|
|
struct cls_rule rule; /* Within a "struct classifier". */
|
|
|
|
|
struct fte_version *versions[2];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* One version of a Flow Table Entry. */
|
|
|
|
|
struct fte_version {
|
|
|
|
|
ovs_be64 cookie;
|
|
|
|
|
uint16_t idle_timeout;
|
|
|
|
|
uint16_t hard_timeout;
|
2014-11-07 18:18:48 +05:30
|
|
|
|
uint16_t importance;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
uint16_t flags;
|
2012-07-03 22:17:14 -07:00
|
|
|
|
struct ofpact *ofpacts;
|
|
|
|
|
size_t ofpacts_len;
|
2015-11-30 16:12:11 -08:00
|
|
|
|
uint8_t table_id;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
};
|
|
|
|
|
|
2016-04-19 18:36:04 -07:00
|
|
|
|
/* A FTE entry that has been queued for later insertion after all
|
|
|
|
|
* flows have been scanned to correctly allocation tunnel metadata. */
|
|
|
|
|
struct fte_pending {
|
2018-03-19 22:01:47 -07:00
|
|
|
|
struct minimatch match;
|
2016-04-19 18:36:04 -07:00
|
|
|
|
int priority;
|
|
|
|
|
struct fte_version *version;
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
struct ovs_list list_node;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Processing state during two stage processing of flow table entries.
|
|
|
|
|
* Tracks the maximum size seen for each tunnel metadata entry as well
|
|
|
|
|
* as a list of the pending FTE entries. */
|
|
|
|
|
struct fte_state {
|
|
|
|
|
int tun_metadata_size[TUN_METADATA_NUM_OPTS];
|
|
|
|
|
struct ovs_list fte_pending_list;
|
|
|
|
|
|
|
|
|
|
/* The final metadata table that we have constructed. */
|
|
|
|
|
struct tun_table *tun_tab;
|
2017-05-31 16:06:12 -07:00
|
|
|
|
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
/* Port and table map. There is only one of each, not one per source,
|
|
|
|
|
* because it only makes sense to display a single name for a given port
|
|
|
|
|
* or table number. */
|
2017-05-31 16:06:12 -07:00
|
|
|
|
const struct ofputil_port_map *port_map;
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
const struct ofputil_table_map *table_map;
|
2016-04-19 18:36:04 -07:00
|
|
|
|
};
|
|
|
|
|
|
2011-03-11 12:02:27 -08:00
|
|
|
|
/* Frees 'version' and the data that it owns. */
|
|
|
|
|
static void
|
|
|
|
|
fte_version_free(struct fte_version *version)
|
|
|
|
|
{
|
|
|
|
|
if (version) {
|
2014-04-29 15:50:38 -07:00
|
|
|
|
free(CONST_CAST(struct ofpact *, version->ofpacts));
|
2011-03-11 12:02:27 -08:00
|
|
|
|
free(version);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Returns true if 'a' and 'b' are the same, false if they differ.
|
|
|
|
|
*
|
|
|
|
|
* Ignores differences in 'flags' because there's no way to retrieve flags from
|
|
|
|
|
* an OpenFlow switch. We have to assume that they are the same. */
|
|
|
|
|
static bool
|
|
|
|
|
fte_version_equals(const struct fte_version *a, const struct fte_version *b)
|
|
|
|
|
{
|
|
|
|
|
return (a->cookie == b->cookie
|
|
|
|
|
&& a->idle_timeout == b->idle_timeout
|
|
|
|
|
&& a->hard_timeout == b->hard_timeout
|
2014-11-07 18:18:48 +05:30
|
|
|
|
&& a->importance == b->importance
|
2015-11-30 16:12:11 -08:00
|
|
|
|
&& a->table_id == b->table_id
|
2017-07-06 16:40:30 -07:00
|
|
|
|
&& ofpacts_equal_stringwise(a->ofpacts, a->ofpacts_len,
|
|
|
|
|
b->ofpacts, b->ofpacts_len));
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-23 10:16:31 -07:00
|
|
|
|
/* Clears 's', then if 's' has a version 'index', formats 'fte' and version
|
|
|
|
|
* 'index' into 's', followed by a new-line. */
|
2011-03-11 12:02:27 -08:00
|
|
|
|
static void
|
2016-04-19 18:36:04 -07:00
|
|
|
|
fte_version_format(const struct fte_state *fte_state, const struct fte *fte,
|
|
|
|
|
int index, struct ds *s)
|
2011-03-11 12:02:27 -08:00
|
|
|
|
{
|
2012-07-23 10:16:31 -07:00
|
|
|
|
const struct fte_version *version = fte->versions[index];
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2012-07-23 10:16:31 -07:00
|
|
|
|
ds_clear(s);
|
|
|
|
|
if (!version) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
if (version->table_id) {
|
|
|
|
|
ds_put_format(s, "table=%"PRIu8" ", version->table_id);
|
|
|
|
|
}
|
2017-05-31 16:06:12 -07:00
|
|
|
|
cls_rule_format(&fte->rule, fte_state->tun_tab, fte_state->port_map, s);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
if (version->cookie != htonll(0)) {
|
2012-07-23 10:16:31 -07:00
|
|
|
|
ds_put_format(s, " cookie=0x%"PRIx64, ntohll(version->cookie));
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
if (version->idle_timeout != OFP_FLOW_PERMANENT) {
|
2012-07-23 10:16:31 -07:00
|
|
|
|
ds_put_format(s, " idle_timeout=%"PRIu16, version->idle_timeout);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
if (version->hard_timeout != OFP_FLOW_PERMANENT) {
|
2012-07-23 10:16:31 -07:00
|
|
|
|
ds_put_format(s, " hard_timeout=%"PRIu16, version->hard_timeout);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
2014-11-07 18:18:48 +05:30
|
|
|
|
if (version->importance != 0) {
|
|
|
|
|
ds_put_format(s, " importance=%"PRIu16, version->importance);
|
|
|
|
|
}
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2013-10-14 14:08:20 -07:00
|
|
|
|
ds_put_cstr(s, " actions=");
|
2018-01-12 12:56:12 -08:00
|
|
|
|
struct ofpact_format_params fp = {
|
|
|
|
|
.port_map = fte_state->port_map,
|
|
|
|
|
.s = s,
|
|
|
|
|
};
|
|
|
|
|
ofpacts_format(version->ofpacts, version->ofpacts_len, &fp);
|
2012-07-23 10:16:31 -07:00
|
|
|
|
|
|
|
|
|
ds_put_char(s, '\n');
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct fte *
|
|
|
|
|
fte_from_cls_rule(const struct cls_rule *cls_rule)
|
|
|
|
|
{
|
|
|
|
|
return cls_rule ? CONTAINER_OF(cls_rule, struct fte, rule) : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Frees 'fte' and its versions. */
|
|
|
|
|
static void
|
|
|
|
|
fte_free(struct fte *fte)
|
|
|
|
|
{
|
|
|
|
|
if (fte) {
|
|
|
|
|
fte_version_free(fte->versions[0]);
|
|
|
|
|
fte_version_free(fte->versions[1]);
|
2012-08-20 11:29:43 -07:00
|
|
|
|
cls_rule_destroy(&fte->rule);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
free(fte);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
/* Frees all of the FTEs within 'tables'. */
|
2011-03-11 12:02:27 -08:00
|
|
|
|
static void
|
2015-11-30 16:12:11 -08:00
|
|
|
|
fte_free_all(struct flow_tables *tables)
|
2011-03-11 12:02:27 -08:00
|
|
|
|
{
|
2015-11-30 16:12:11 -08:00
|
|
|
|
struct classifier *cls;
|
|
|
|
|
|
|
|
|
|
FOR_EACH_TABLE (cls, tables) {
|
|
|
|
|
struct fte *fte;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
classifier_defer(cls);
|
|
|
|
|
CLS_FOR_EACH (fte, rule, cls) {
|
2018-01-30 13:00:31 -08:00
|
|
|
|
classifier_remove_assert(cls, &fte->rule);
|
2015-11-30 16:12:11 -08:00
|
|
|
|
ovsrcu_postpone(fte_free, fte);
|
|
|
|
|
}
|
|
|
|
|
classifier_destroy(cls);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
/* Searches 'tables' for an FTE matching 'rule', inserting a new one if
|
2011-03-11 12:02:27 -08:00
|
|
|
|
* necessary. Sets 'version' as the version of that rule with the given
|
|
|
|
|
* 'index', replacing any existing version, if any.
|
|
|
|
|
*
|
|
|
|
|
* Takes ownership of 'version'. */
|
|
|
|
|
static void
|
2018-03-19 22:01:47 -07:00
|
|
|
|
fte_insert(struct flow_tables *tables, const struct minimatch *match,
|
2014-10-30 11:40:07 -07:00
|
|
|
|
int priority, struct fte_version *version, int index)
|
2011-03-11 12:02:27 -08:00
|
|
|
|
{
|
2015-11-30 16:12:11 -08:00
|
|
|
|
struct classifier *cls = &tables->tables[version->table_id];
|
2011-03-11 12:02:27 -08:00
|
|
|
|
struct fte *old, *fte;
|
|
|
|
|
|
|
|
|
|
fte = xzalloc(sizeof *fte);
|
2018-03-19 22:01:47 -07:00
|
|
|
|
cls_rule_init_from_minimatch(&fte->rule, match, priority);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
fte->versions[index] = version;
|
|
|
|
|
|
2015-07-06 11:45:54 -07:00
|
|
|
|
old = fte_from_cls_rule(classifier_replace(cls, &fte->rule,
|
2016-07-29 16:52:01 -07:00
|
|
|
|
OVS_VERSION_MIN, NULL, 0));
|
2011-03-11 12:02:27 -08:00
|
|
|
|
if (old) {
|
|
|
|
|
fte->versions[!index] = old->versions[!index];
|
2014-11-13 11:54:31 -08:00
|
|
|
|
old->versions[!index] = NULL;
|
|
|
|
|
|
|
|
|
|
ovsrcu_postpone(fte_free, old);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-28 16:17:22 -07:00
|
|
|
|
/* Given a list of the field sizes for each tunnel metadata entry, install
|
|
|
|
|
* a mapping table for later operations. */
|
|
|
|
|
static void
|
|
|
|
|
generate_tun_metadata(struct fte_state *state)
|
|
|
|
|
{
|
|
|
|
|
struct ofputil_tlv_table_mod ttm;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
ttm.command = NXTTMC_ADD;
|
|
|
|
|
ovs_list_init(&ttm.mappings);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < TUN_METADATA_NUM_OPTS; i++) {
|
|
|
|
|
if (state->tun_metadata_size[i] != -1) {
|
|
|
|
|
struct ofputil_tlv_map *map = xmalloc(sizeof *map);
|
|
|
|
|
|
|
|
|
|
ovs_list_push_back(&ttm.mappings, &map->list_node);
|
|
|
|
|
|
|
|
|
|
/* We don't care about the actual option class and type since there
|
|
|
|
|
* won't be any lookup. We just need to make them unique. */
|
|
|
|
|
map->option_class = i / UINT8_MAX;
|
|
|
|
|
map->option_type = i;
|
|
|
|
|
map->option_len = ROUND_UP(state->tun_metadata_size[i], 4);
|
|
|
|
|
map->index = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-19 18:36:04 -07:00
|
|
|
|
tun_metadata_table_mod(&ttm, NULL, &state->tun_tab);
|
2016-08-28 16:17:22 -07:00
|
|
|
|
ofputil_uninit_tlv_table(&ttm.mappings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Once we have created a tunnel mapping table with a consistent overall
|
|
|
|
|
* allocation, we need to remap each flow to use this table from its own
|
|
|
|
|
* allocation. Since the mapping table has already been installed, we
|
|
|
|
|
* can just read the data from the match and rewrite it. On rewrite, it
|
|
|
|
|
* will use the new table. */
|
|
|
|
|
static void
|
2018-03-19 22:01:47 -07:00
|
|
|
|
remap_match(struct fte_state *state, struct minimatch *minimatch)
|
2016-08-28 16:17:22 -07:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2018-03-19 22:01:47 -07:00
|
|
|
|
if (!minimatch->tun_md || !minimatch->tun_md->valid) {
|
2016-08-28 16:17:22 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-19 22:01:47 -07:00
|
|
|
|
struct match match;
|
|
|
|
|
minimatch_expand(minimatch, &match);
|
|
|
|
|
|
|
|
|
|
struct tun_metadata flow = match.flow.tunnel.metadata;
|
|
|
|
|
struct tun_metadata flow_mask = match.wc.masks.tunnel.metadata;
|
|
|
|
|
memset(&match.flow.tunnel.metadata, 0, sizeof match.flow.tunnel.metadata);
|
|
|
|
|
memset(&match.wc.masks.tunnel.metadata, 0,
|
|
|
|
|
sizeof match.wc.masks.tunnel.metadata);
|
|
|
|
|
match.tun_md.valid = false;
|
2016-08-28 16:17:22 -07:00
|
|
|
|
|
2018-03-19 22:01:47 -07:00
|
|
|
|
match.flow.tunnel.metadata.tab = state->tun_tab;
|
|
|
|
|
match.wc.masks.tunnel.metadata.tab = match.flow.tunnel.metadata.tab;
|
2016-04-19 18:36:04 -07:00
|
|
|
|
|
2016-08-28 16:17:22 -07:00
|
|
|
|
ULLONG_FOR_EACH_1 (i, flow_mask.present.map) {
|
|
|
|
|
const struct mf_field *field = mf_from_id(MFF_TUN_METADATA0 + i);
|
2018-03-19 22:01:47 -07:00
|
|
|
|
int offset = match.tun_md.entry[i].loc.c.offset;
|
|
|
|
|
int len = match.tun_md.entry[i].loc.len;
|
2016-08-28 16:17:22 -07:00
|
|
|
|
union mf_value value, mask;
|
|
|
|
|
|
|
|
|
|
memset(&value, 0, field->n_bytes - len);
|
2018-03-19 22:01:47 -07:00
|
|
|
|
memset(&mask, match.tun_md.entry[i].masked ? 0 : 0xff,
|
2016-08-28 16:17:22 -07:00
|
|
|
|
field->n_bytes - len);
|
|
|
|
|
|
|
|
|
|
memcpy(value.tun_metadata + field->n_bytes - len,
|
|
|
|
|
flow.opts.u8 + offset, len);
|
|
|
|
|
memcpy(mask.tun_metadata + field->n_bytes - len,
|
|
|
|
|
flow_mask.opts.u8 + offset, len);
|
2018-03-19 22:01:47 -07:00
|
|
|
|
mf_set(field, &value, &mask, &match, NULL);
|
2016-08-28 16:17:22 -07:00
|
|
|
|
}
|
2018-03-19 22:01:47 -07:00
|
|
|
|
minimatch_destroy(minimatch);
|
|
|
|
|
minimatch_init(minimatch, &match);
|
2016-08-28 16:17:22 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* In order to correctly handle tunnel metadata, we need to have
|
|
|
|
|
* two passes over the flows. This happens because tunnel metadata
|
|
|
|
|
* doesn't have fixed locations in a flow entry but is instead dynamically
|
|
|
|
|
* allocated space. In the case of flows coming from a file, we don't
|
|
|
|
|
* even know the size of each field when we need to do the allocation.
|
|
|
|
|
* When the flows come in, each flow has an individual allocation based
|
|
|
|
|
* on its own fields. However, this allocation is not the same across
|
|
|
|
|
* different flows and therefore fields are not directly comparable.
|
|
|
|
|
*
|
|
|
|
|
* In the first pass, we record the maximum size of each tunnel metadata
|
|
|
|
|
* field as well as queue FTE entries for later processing.
|
|
|
|
|
*
|
|
|
|
|
* In the second pass, we use the metadata size information to create a
|
|
|
|
|
* tunnel mapping table and set that through the tunnel metadata processing
|
|
|
|
|
* code. We then remap all individual flows to use this common allocation
|
|
|
|
|
* scheme. Finally, we load the queued entries into the classifier for
|
|
|
|
|
* comparison.
|
|
|
|
|
*
|
|
|
|
|
* fte_state_init() should be called before processing any flows. */
|
|
|
|
|
static void
|
|
|
|
|
fte_state_init(struct fte_state *state)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < TUN_METADATA_NUM_OPTS; i++) {
|
|
|
|
|
state->tun_metadata_size[i] = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ovs_list_init(&state->fte_pending_list);
|
2016-04-19 18:36:04 -07:00
|
|
|
|
state->tun_tab = NULL;
|
2017-05-31 16:06:12 -07:00
|
|
|
|
state->port_map = NULL;
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
state->table_map = NULL;
|
2016-04-19 18:36:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
fte_state_destroy(struct fte_state *state)
|
|
|
|
|
{
|
|
|
|
|
tun_metadata_free(state->tun_tab);
|
2016-08-28 16:17:22 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The first pass of the processing described in the comment about
|
|
|
|
|
* fte_state_init(). fte_queue() is the first pass to be called as each
|
|
|
|
|
* flow is read from its source. */
|
|
|
|
|
static void
|
2018-03-19 22:01:47 -07:00
|
|
|
|
fte_queue(struct fte_state *state, const struct minimatch *match,
|
2016-08-28 16:17:22 -07:00
|
|
|
|
int priority, struct fte_version *version, int index)
|
|
|
|
|
{
|
|
|
|
|
struct fte_pending *pending = xmalloc(sizeof *pending);
|
|
|
|
|
int i;
|
|
|
|
|
|
2018-03-19 22:01:47 -07:00
|
|
|
|
minimatch_clone(&pending->match, match);
|
2016-08-28 16:17:22 -07:00
|
|
|
|
pending->priority = priority;
|
|
|
|
|
pending->version = version;
|
|
|
|
|
pending->index = index;
|
|
|
|
|
ovs_list_push_back(&state->fte_pending_list, &pending->list_node);
|
|
|
|
|
|
2018-03-19 22:01:47 -07:00
|
|
|
|
if (!match->tun_md || !match->tun_md->valid) {
|
2016-08-28 16:17:22 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-19 22:01:47 -07:00
|
|
|
|
uint64_t map = miniflow_get_tun_metadata_present_map(&match->mask->masks);
|
|
|
|
|
ULLONG_FOR_EACH_1 (i, map) {
|
|
|
|
|
if (match->tun_md->entry[i].loc.len > state->tun_metadata_size[i]) {
|
|
|
|
|
state->tun_metadata_size[i] = match->tun_md->entry[i].loc.len;
|
2016-08-28 16:17:22 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The second pass of the processing described in the comment about
|
|
|
|
|
* fte_state_init(). This should be called once all flows (from both
|
|
|
|
|
* sides of the comparison) have been added through fte_queue(). */
|
|
|
|
|
static void
|
|
|
|
|
fte_fill(struct fte_state *state, struct flow_tables *tables)
|
|
|
|
|
{
|
|
|
|
|
struct fte_pending *pending;
|
|
|
|
|
|
|
|
|
|
generate_tun_metadata(state);
|
|
|
|
|
|
|
|
|
|
flow_tables_init(tables);
|
|
|
|
|
flow_tables_defer(tables);
|
|
|
|
|
|
|
|
|
|
LIST_FOR_EACH_POP(pending, list_node, &state->fte_pending_list) {
|
2018-03-19 22:01:47 -07:00
|
|
|
|
remap_match(state, &pending->match);
|
|
|
|
|
fte_insert(tables, &pending->match, pending->priority,
|
|
|
|
|
pending->version, pending->index);
|
|
|
|
|
minimatch_destroy(&pending->match);
|
2016-08-28 16:17:22 -07:00
|
|
|
|
free(pending);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flow_tables_publish(tables);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
/* Reads the flows in 'filename' as flow table entries in 'tables' for the
|
|
|
|
|
* version with the specified 'index'. Returns the flow formats able to
|
|
|
|
|
* represent the flows that were read. */
|
2012-02-10 13:30:23 -08:00
|
|
|
|
static enum ofputil_protocol
|
2016-08-28 16:17:22 -07:00
|
|
|
|
read_flows_from_file(const char *filename, struct fte_state *state, int index)
|
2011-03-11 12:02:27 -08:00
|
|
|
|
{
|
2012-02-10 13:30:23 -08:00
|
|
|
|
enum ofputil_protocol usable_protocols;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
int line_number;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
struct ds s;
|
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
|
|
file = !strcmp(filename, "-") ? stdin : fopen(filename, "r");
|
|
|
|
|
if (file == NULL) {
|
|
|
|
|
ovs_fatal(errno, "%s: open", filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ds_init(&s);
|
2012-02-10 13:30:23 -08:00
|
|
|
|
usable_protocols = OFPUTIL_P_ANY;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
line_number = 0;
|
|
|
|
|
while (!ds_get_preprocessed_line(&s, file, &line_number)) {
|
2011-03-11 12:02:27 -08:00
|
|
|
|
struct fte_version *version;
|
2011-08-08 14:46:38 -07:00
|
|
|
|
struct ofputil_flow_mod fm;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
char *error;
|
2013-08-20 18:41:45 -07:00
|
|
|
|
enum ofputil_protocol usable;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2017-05-31 16:06:12 -07:00
|
|
|
|
error = parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), state->port_map,
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
state->table_map, &usable);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s:%d: %s", filename, line_number, error);
|
|
|
|
|
}
|
2013-08-20 18:41:45 -07:00
|
|
|
|
usable_protocols &= usable;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
|
|
|
|
version = xmalloc(sizeof *version);
|
2012-03-24 01:02:26 -07:00
|
|
|
|
version->cookie = fm.new_cookie;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
version->idle_timeout = fm.idle_timeout;
|
|
|
|
|
version->hard_timeout = fm.hard_timeout;
|
2014-11-07 18:18:48 +05:30
|
|
|
|
version->importance = fm.importance;
|
2013-08-26 16:23:50 -07:00
|
|
|
|
version->flags = fm.flags & (OFPUTIL_FF_SEND_FLOW_REM
|
|
|
|
|
| OFPUTIL_FF_EMERG);
|
2012-07-03 22:17:14 -07:00
|
|
|
|
version->ofpacts = fm.ofpacts;
|
|
|
|
|
version->ofpacts_len = fm.ofpacts_len;
|
2015-11-30 16:12:11 -08:00
|
|
|
|
version->table_id = fm.table_id != OFPTT_ALL ? fm.table_id : 0;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2016-08-28 16:17:22 -07:00
|
|
|
|
fte_queue(state, &fm.match, fm.priority, version, index);
|
2018-03-19 22:01:47 -07:00
|
|
|
|
|
|
|
|
|
minimatch_destroy(&fm.match);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
ds_destroy(&s);
|
|
|
|
|
|
|
|
|
|
if (file != stdin) {
|
|
|
|
|
fclose(file);
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
return usable_protocols;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reads the OpenFlow flow table from 'vconn', which has currently active flow
|
2015-11-30 16:12:11 -08:00
|
|
|
|
* format 'protocol', and adds them as flow table entries in 'tables' for the
|
2011-03-11 12:02:27 -08:00
|
|
|
|
* version with the specified 'index'. */
|
|
|
|
|
static void
|
2012-02-10 13:30:23 -08:00
|
|
|
|
read_flows_from_switch(struct vconn *vconn,
|
|
|
|
|
enum ofputil_protocol protocol,
|
2016-08-28 16:17:22 -07:00
|
|
|
|
struct fte_state *state, int index)
|
2011-03-11 12:02:27 -08:00
|
|
|
|
{
|
2011-08-08 14:48:48 -07:00
|
|
|
|
struct ofputil_flow_stats_request fsr;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
|
|
|
|
fsr.aggregate = false;
|
2012-08-07 15:28:18 -07:00
|
|
|
|
match_init_catchall(&fsr.match);
|
2012-11-26 18:17:08 +02:00
|
|
|
|
fsr.out_port = OFPP_ANY;
|
2015-10-19 15:00:39 -07:00
|
|
|
|
fsr.out_group = OFPG_ANY;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
fsr.table_id = 0xff;
|
2011-12-30 17:56:08 -08:00
|
|
|
|
fsr.cookie = fsr.cookie_mask = htonll(0);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2016-12-28 09:31:42 -08:00
|
|
|
|
struct ofputil_flow_stats *fses;
|
|
|
|
|
size_t n_fses;
|
|
|
|
|
run(vconn_dump_flows(vconn, &fsr, protocol, &fses, &n_fses),
|
|
|
|
|
"dump flows");
|
|
|
|
|
for (size_t i = 0; i < n_fses; i++) {
|
|
|
|
|
const struct ofputil_flow_stats *fs = &fses[i];
|
2012-07-03 11:31:03 -07:00
|
|
|
|
struct fte_version *version;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2012-07-03 11:31:03 -07:00
|
|
|
|
version = xmalloc(sizeof *version);
|
2016-12-28 09:31:42 -08:00
|
|
|
|
version->cookie = fs->cookie;
|
|
|
|
|
version->idle_timeout = fs->idle_timeout;
|
|
|
|
|
version->hard_timeout = fs->hard_timeout;
|
|
|
|
|
version->importance = fs->importance;
|
2012-07-03 11:31:03 -07:00
|
|
|
|
version->flags = 0;
|
2016-12-28 09:31:42 -08:00
|
|
|
|
version->ofpacts_len = fs->ofpacts_len;
|
|
|
|
|
version->ofpacts = xmemdup(fs->ofpacts, fs->ofpacts_len);
|
|
|
|
|
version->table_id = fs->table_id;
|
2012-07-03 11:31:03 -07:00
|
|
|
|
|
2018-03-19 22:01:47 -07:00
|
|
|
|
struct minimatch match;
|
|
|
|
|
minimatch_init(&match, &fs->match);
|
|
|
|
|
fte_queue(state, &match, fs->priority, version, index);
|
|
|
|
|
minimatch_destroy(&match);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
2017-02-08 07:03:54 -08:00
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < n_fses; i++) {
|
|
|
|
|
free(CONST_CAST(struct ofpact *, fses[i].ofpacts));
|
|
|
|
|
}
|
|
|
|
|
free(fses);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
fte_make_flow_mod(const struct fte *fte, int index, uint16_t command,
|
2014-12-15 14:10:38 +01:00
|
|
|
|
enum ofputil_protocol protocol, struct ovs_list *packets)
|
2011-03-11 12:02:27 -08:00
|
|
|
|
{
|
|
|
|
|
const struct fte_version *version = fte->versions[index];
|
|
|
|
|
struct ofpbuf *ofm;
|
|
|
|
|
|
2016-01-04 11:36:14 -08:00
|
|
|
|
struct ofputil_flow_mod fm = {
|
|
|
|
|
.priority = fte->rule.priority,
|
|
|
|
|
.new_cookie = version->cookie,
|
|
|
|
|
.modify_cookie = true,
|
|
|
|
|
.table_id = version->table_id,
|
|
|
|
|
.command = command,
|
|
|
|
|
.idle_timeout = version->idle_timeout,
|
|
|
|
|
.hard_timeout = version->hard_timeout,
|
|
|
|
|
.importance = version->importance,
|
|
|
|
|
.buffer_id = UINT32_MAX,
|
|
|
|
|
.out_port = OFPP_ANY,
|
|
|
|
|
.out_group = OFPG_ANY,
|
|
|
|
|
.flags = version->flags,
|
|
|
|
|
};
|
2018-03-19 22:01:47 -07:00
|
|
|
|
minimatch_clone(&fm.match, &fte->rule.match);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
if (command == OFPFC_ADD || command == OFPFC_MODIFY ||
|
|
|
|
|
command == OFPFC_MODIFY_STRICT) {
|
2012-07-03 22:17:14 -07:00
|
|
|
|
fm.ofpacts = version->ofpacts;
|
|
|
|
|
fm.ofpacts_len = version->ofpacts_len;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
} else {
|
2012-07-03 22:17:14 -07:00
|
|
|
|
fm.ofpacts = NULL;
|
|
|
|
|
fm.ofpacts_len = 0;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
2012-02-10 13:30:23 -08:00
|
|
|
|
ofm = ofputil_encode_flow_mod(&fm, protocol);
|
2018-03-19 22:01:47 -07:00
|
|
|
|
minimatch_destroy(&fm.match);
|
|
|
|
|
|
2016-03-25 14:10:22 -07:00
|
|
|
|
ovs_list_push_back(packets, &ofm->list_node);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_replace_flows(struct ovs_cmdl_context *ctx)
|
2011-03-11 12:02:27 -08:00
|
|
|
|
{
|
2017-05-31 16:06:12 -07:00
|
|
|
|
enum { FILE_IDX = 0, SWITCH_IDX = 1 };
|
2012-02-10 13:30:23 -08:00
|
|
|
|
enum ofputil_protocol usable_protocols, protocol;
|
2016-08-28 16:17:22 -07:00
|
|
|
|
struct fte_state fte_state;
|
2015-11-30 16:12:11 -08:00
|
|
|
|
struct flow_tables tables;
|
|
|
|
|
struct classifier *cls;
|
2014-12-15 14:10:38 +01:00
|
|
|
|
struct ovs_list requests;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
struct fte *fte;
|
|
|
|
|
|
2016-08-28 16:17:22 -07:00
|
|
|
|
fte_state_init(&fte_state);
|
2017-05-31 16:06:12 -07:00
|
|
|
|
fte_state.port_map = ports_to_accept(ctx->argv[1]);
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
fte_state.table_map = tables_to_accept(ctx->argv[1]);
|
2016-08-28 16:17:22 -07:00
|
|
|
|
usable_protocols = read_flows_from_file(ctx->argv[2], &fte_state, FILE_IDX);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
protocol = open_vconn(ctx->argv[1], &vconn);
|
2012-02-10 13:30:23 -08:00
|
|
|
|
protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols);
|
|
|
|
|
|
2016-08-28 16:17:22 -07:00
|
|
|
|
read_flows_from_switch(vconn, protocol, &fte_state, SWITCH_IDX);
|
|
|
|
|
|
|
|
|
|
fte_fill(&fte_state, &tables);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2016-03-25 14:10:22 -07:00
|
|
|
|
ovs_list_init(&requests);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
FOR_EACH_TABLE (cls, &tables) {
|
|
|
|
|
/* Delete flows that exist on the switch but not in the file. */
|
|
|
|
|
CLS_FOR_EACH (fte, rule, cls) {
|
|
|
|
|
struct fte_version *file_ver = fte->versions[FILE_IDX];
|
|
|
|
|
struct fte_version *sw_ver = fte->versions[SWITCH_IDX];
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
if (sw_ver && !file_ver) {
|
|
|
|
|
fte_make_flow_mod(fte, SWITCH_IDX, OFPFC_DELETE_STRICT,
|
|
|
|
|
protocol, &requests);
|
|
|
|
|
}
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
/* Add flows that exist in the file but not on the switch.
|
|
|
|
|
* Update flows that exist in both places but differ. */
|
|
|
|
|
CLS_FOR_EACH (fte, rule, cls) {
|
|
|
|
|
struct fte_version *file_ver = fte->versions[FILE_IDX];
|
|
|
|
|
struct fte_version *sw_ver = fte->versions[SWITCH_IDX];
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
if (file_ver &&
|
|
|
|
|
(readd || !sw_ver || !fte_version_equals(sw_ver, file_ver))) {
|
|
|
|
|
fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol,
|
|
|
|
|
&requests);
|
|
|
|
|
}
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-05 14:03:12 -07:00
|
|
|
|
if (bundle) {
|
2015-06-11 15:53:43 -07:00
|
|
|
|
bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC);
|
2015-06-05 14:03:12 -07:00
|
|
|
|
} else {
|
|
|
|
|
transact_multiple_noreply(vconn, &requests);
|
|
|
|
|
}
|
2016-01-04 16:18:40 -08:00
|
|
|
|
|
|
|
|
|
ofpbuf_list_delete(&requests);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
fte_free_all(&tables);
|
2016-04-19 18:36:04 -07:00
|
|
|
|
fte_state_destroy(&fte_state);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2016-08-28 16:17:22 -07:00
|
|
|
|
read_flows_from_source(const char *source, struct fte_state *state, int index)
|
2011-03-11 12:02:27 -08:00
|
|
|
|
{
|
|
|
|
|
struct stat s;
|
|
|
|
|
|
|
|
|
|
if (source[0] == '/' || source[0] == '.'
|
|
|
|
|
|| (!strchr(source, ':') && !stat(source, &s))) {
|
2016-08-28 16:17:22 -07:00
|
|
|
|
read_flows_from_file(source, state, index);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
} else {
|
2012-02-10 13:30:23 -08:00
|
|
|
|
enum ofputil_protocol protocol;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
protocol = open_vconn(source, &vconn);
|
|
|
|
|
protocol = set_protocol_for_flow_dump(vconn, protocol, OFPUTIL_P_ANY);
|
2016-08-28 16:17:22 -07:00
|
|
|
|
read_flows_from_switch(vconn, protocol, state, index);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
vconn_close(vconn);
|
2017-05-31 16:06:12 -07:00
|
|
|
|
|
|
|
|
|
if (!state->port_map) {
|
|
|
|
|
state->port_map = ports_to_show(source);
|
|
|
|
|
}
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_diff_flows(struct ovs_cmdl_context *ctx)
|
2011-03-11 12:02:27 -08:00
|
|
|
|
{
|
|
|
|
|
bool differences = false;
|
2016-08-28 16:17:22 -07:00
|
|
|
|
struct fte_state fte_state;
|
2015-11-30 16:12:11 -08:00
|
|
|
|
struct flow_tables tables;
|
|
|
|
|
struct classifier *cls;
|
2012-07-23 10:16:31 -07:00
|
|
|
|
struct ds a_s, b_s;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
struct fte *fte;
|
|
|
|
|
|
2016-08-28 16:17:22 -07:00
|
|
|
|
fte_state_init(&fte_state);
|
|
|
|
|
read_flows_from_source(ctx->argv[1], &fte_state, 0);
|
|
|
|
|
read_flows_from_source(ctx->argv[2], &fte_state, 1);
|
|
|
|
|
fte_fill(&fte_state, &tables);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2012-07-23 10:16:31 -07:00
|
|
|
|
ds_init(&a_s);
|
|
|
|
|
ds_init(&b_s);
|
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
FOR_EACH_TABLE (cls, &tables) {
|
|
|
|
|
CLS_FOR_EACH (fte, rule, cls) {
|
|
|
|
|
struct fte_version *a = fte->versions[0];
|
|
|
|
|
struct fte_version *b = fte->versions[1];
|
|
|
|
|
|
|
|
|
|
if (!a || !b || !fte_version_equals(a, b)) {
|
2016-04-19 18:36:04 -07:00
|
|
|
|
fte_version_format(&fte_state, fte, 0, &a_s);
|
|
|
|
|
fte_version_format(&fte_state, fte, 1, &b_s);
|
2017-07-06 16:40:30 -07:00
|
|
|
|
if (a_s.length) {
|
|
|
|
|
printf("-%s", ds_cstr(&a_s));
|
|
|
|
|
}
|
|
|
|
|
if (b_s.length) {
|
|
|
|
|
printf("+%s", ds_cstr(&b_s));
|
2012-07-23 10:16:31 -07:00
|
|
|
|
}
|
2017-07-06 16:40:30 -07:00
|
|
|
|
differences = true;
|
2011-03-11 12:02:27 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-23 10:16:31 -07:00
|
|
|
|
ds_destroy(&a_s);
|
|
|
|
|
ds_destroy(&b_s);
|
|
|
|
|
|
2015-11-30 16:12:11 -08:00
|
|
|
|
fte_free_all(&tables);
|
2016-04-19 18:36:04 -07:00
|
|
|
|
fte_state_destroy(&fte_state);
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
|
|
|
|
if (differences) {
|
|
|
|
|
exit(2);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-09-13 15:03:33 -07:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofctl_meter_mod__(const char *bridge, const char *str, int command)
|
|
|
|
|
{
|
|
|
|
|
struct ofputil_meter_mod mm;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
enum ofputil_protocol protocol;
|
|
|
|
|
enum ofputil_protocol usable_protocols;
|
|
|
|
|
enum ofp_version version;
|
|
|
|
|
|
2021-03-17 14:14:18 -04:00
|
|
|
|
memset(&mm, 0, sizeof mm);
|
2013-09-13 15:03:33 -07:00
|
|
|
|
if (str) {
|
|
|
|
|
char *error;
|
|
|
|
|
error = parse_ofp_meter_mod_str(&mm, str, command, &usable_protocols);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
usable_protocols = OFPUTIL_P_OF13_UP;
|
|
|
|
|
mm.command = command;
|
|
|
|
|
mm.meter.meter_id = OFPM13_ALL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols);
|
|
|
|
|
version = ofputil_protocol_to_ofp_version(protocol);
|
|
|
|
|
transact_noreply(vconn, ofputil_encode_meter_mod(version, &mm));
|
2017-06-27 17:12:00 -07:00
|
|
|
|
free(mm.meter.bands);
|
2013-09-13 15:03:33 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofctl_meter_request__(const char *bridge, const char *str,
|
|
|
|
|
enum ofputil_meter_request_type type)
|
|
|
|
|
{
|
|
|
|
|
struct ofputil_meter_mod mm;
|
|
|
|
|
struct vconn *vconn;
|
|
|
|
|
enum ofputil_protocol usable_protocols;
|
|
|
|
|
enum ofputil_protocol protocol;
|
|
|
|
|
enum ofp_version version;
|
|
|
|
|
|
2021-03-17 14:14:18 -04:00
|
|
|
|
memset(&mm, 0, sizeof mm);
|
2013-09-13 15:03:33 -07:00
|
|
|
|
if (str) {
|
|
|
|
|
char *error;
|
|
|
|
|
error = parse_ofp_meter_mod_str(&mm, str, -1, &usable_protocols);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
usable_protocols = OFPUTIL_P_OF13_UP;
|
|
|
|
|
mm.meter.meter_id = OFPM13_ALL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols);
|
|
|
|
|
version = ofputil_protocol_to_ofp_version(protocol);
|
2015-12-24 15:44:31 -08:00
|
|
|
|
dump_transaction(vconn, ofputil_encode_meter_request(version, type,
|
|
|
|
|
mm.meter.meter_id));
|
2017-06-27 17:12:00 -07:00
|
|
|
|
free(mm.meter.bands);
|
2013-09-13 15:03:33 -07:00
|
|
|
|
vconn_close(vconn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_add_meter(struct ovs_cmdl_context *ctx)
|
2013-09-13 15:03:33 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_meter_mod__(ctx->argv[1], ctx->argv[2], OFPMC13_ADD);
|
2013-09-13 15:03:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_mod_meter(struct ovs_cmdl_context *ctx)
|
2013-09-13 15:03:33 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_meter_mod__(ctx->argv[1], ctx->argv[2], OFPMC13_MODIFY);
|
2013-09-13 15:03:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_del_meters(struct ovs_cmdl_context *ctx)
|
2013-09-13 15:03:33 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_meter_mod__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL, OFPMC13_DELETE);
|
2013-09-13 15:03:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_dump_meters(struct ovs_cmdl_context *ctx)
|
2013-09-13 15:03:33 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_meter_request__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL,
|
2013-09-13 15:03:33 -07:00
|
|
|
|
OFPUTIL_METER_CONFIG);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_meter_stats(struct ovs_cmdl_context *ctx)
|
2013-09-13 15:03:33 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_meter_request__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL,
|
2013-09-13 15:03:33 -07:00
|
|
|
|
OFPUTIL_METER_STATS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_meter_features(struct ovs_cmdl_context *ctx)
|
2013-09-13 15:03:33 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_meter_request__(ctx->argv[1], NULL, OFPUTIL_METER_FEATURES);
|
2013-09-13 15:03:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-11 12:02:27 -08:00
|
|
|
|
|
2010-11-09 17:00:59 -08:00
|
|
|
|
/* Undocumented commands for unit testing. */
|
|
|
|
|
|
2011-02-22 16:24:19 -08:00
|
|
|
|
static void
|
2013-08-20 18:41:45 -07:00
|
|
|
|
ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms,
|
|
|
|
|
enum ofputil_protocol usable_protocols)
|
2011-02-22 16:24:19 -08:00
|
|
|
|
{
|
2012-02-10 13:30:23 -08:00
|
|
|
|
enum ofputil_protocol protocol = 0;
|
|
|
|
|
char *usable_s;
|
|
|
|
|
size_t i;
|
2011-02-22 16:24:19 -08:00
|
|
|
|
|
2012-02-10 13:30:23 -08:00
|
|
|
|
usable_s = ofputil_protocols_to_string(usable_protocols);
|
|
|
|
|
printf("usable protocols: %s\n", usable_s);
|
|
|
|
|
free(usable_s);
|
|
|
|
|
|
|
|
|
|
if (!(usable_protocols & allowed_protocols)) {
|
|
|
|
|
ovs_fatal(0, "no usable protocol");
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
|
|
|
|
|
protocol = 1 << i;
|
|
|
|
|
if (protocol & usable_protocols & allowed_protocols) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-02-01 14:55:14 -08:00
|
|
|
|
ovs_assert(is_pow2(protocol));
|
2012-02-10 13:30:23 -08:00
|
|
|
|
|
|
|
|
|
printf("chosen protocol: %s\n", ofputil_protocol_to_string(protocol));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_fms; i++) {
|
|
|
|
|
struct ofputil_flow_mod *fm = &fms[i];
|
|
|
|
|
struct ofpbuf *msg;
|
|
|
|
|
|
|
|
|
|
msg = ofputil_encode_flow_mod(fm, protocol);
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ofp_print(stdout, msg->data, msg->size, NULL, NULL, verbosity);
|
2012-02-10 13:30:23 -08:00
|
|
|
|
ofpbuf_delete(msg);
|
|
|
|
|
|
2014-04-29 15:50:38 -07:00
|
|
|
|
free(CONST_CAST(struct ofpact *, fm->ofpacts));
|
2018-03-19 22:01:47 -07:00
|
|
|
|
minimatch_destroy(&fm->match);
|
2011-02-22 16:24:19 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* "parse-flow FLOW": parses the argument as a flow (like add-flow) and prints
|
|
|
|
|
* it back to stdout. */
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_flow(struct ovs_cmdl_context *ctx)
|
2011-02-22 16:24:19 -08:00
|
|
|
|
{
|
2013-08-20 18:41:45 -07:00
|
|
|
|
enum ofputil_protocol usable_protocols;
|
2012-02-10 13:30:23 -08:00
|
|
|
|
struct ofputil_flow_mod fm;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
char *error;
|
2011-02-22 16:24:19 -08:00
|
|
|
|
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
error = parse_ofp_flow_mod_str(&fm, ctx->argv[1], NULL, NULL,
|
2017-05-31 16:06:12 -07:00
|
|
|
|
OFPFC_ADD, &usable_protocols);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
2013-08-20 18:41:45 -07:00
|
|
|
|
ofctl_parse_flows__(&fm, 1, usable_protocols);
|
2011-02-22 16:24:19 -08:00
|
|
|
|
}
|
|
|
|
|
|
2011-01-12 13:57:53 -08:00
|
|
|
|
/* "parse-flows FILENAME": reads the named file as a sequence of flows (like
|
|
|
|
|
* add-flows) and prints each of the flows back to stdout. */
|
2010-10-01 13:08:14 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_flows(struct ovs_cmdl_context *ctx)
|
2010-10-01 13:08:14 -07:00
|
|
|
|
{
|
2013-08-20 18:41:45 -07:00
|
|
|
|
enum ofputil_protocol usable_protocols;
|
2012-02-10 13:30:23 -08:00
|
|
|
|
struct ofputil_flow_mod *fms = NULL;
|
|
|
|
|
size_t n_fms = 0;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
char *error;
|
2010-10-01 13:08:14 -07:00
|
|
|
|
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
error = parse_ofp_flow_mod_file(ctx->argv[1], NULL, NULL, OFPFC_ADD,
|
2017-05-31 16:06:12 -07:00
|
|
|
|
&fms, &n_fms, &usable_protocols);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
2013-08-20 18:41:45 -07:00
|
|
|
|
ofctl_parse_flows__(fms, n_fms, usable_protocols);
|
2012-02-10 13:30:23 -08:00
|
|
|
|
free(fms);
|
2010-10-01 13:08:14 -07:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-30 15:07:07 -07:00
|
|
|
|
/* "parse-group GROUP": parses the argument as a group (like add-group) and
|
|
|
|
|
* prints it back to stdout. */
|
|
|
|
|
static void
|
|
|
|
|
ofctl_parse_group(struct ovs_cmdl_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
enum ofputil_protocol usable_protocols;
|
|
|
|
|
struct ofputil_group_mod gm;
|
|
|
|
|
char *error = parse_ofp_group_mod_str(&gm, OFPGC11_ADD, ctx->argv[1], NULL,
|
|
|
|
|
NULL, &usable_protocols);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *usable_s = ofputil_protocols_to_string(usable_protocols);
|
|
|
|
|
printf("usable protocols: %s\n", usable_s);
|
|
|
|
|
free(usable_s);
|
|
|
|
|
|
|
|
|
|
if (!(usable_protocols & allowed_protocols)) {
|
|
|
|
|
ovs_fatal(0, "no usable protocol");
|
|
|
|
|
}
|
|
|
|
|
enum ofputil_protocol protocol = 0;
|
|
|
|
|
for (int i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
|
|
|
|
|
protocol = 1 << i;
|
|
|
|
|
if (protocol & usable_protocols & allowed_protocols) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
|
|
|
|
|
printf("chosen version: %s\n", ofputil_version_to_string(version));
|
|
|
|
|
|
|
|
|
|
struct ofpbuf *msg = ofputil_encode_group_mod(version, &gm, NULL, false);
|
|
|
|
|
ofp_print(stdout, msg->data, msg->size, NULL, NULL, verbosity);
|
|
|
|
|
ofpbuf_delete(msg);
|
|
|
|
|
|
|
|
|
|
ofputil_uninit_group_mod(&gm);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2014-05-09 18:18:17 -07:00
|
|
|
|
ofctl_parse_nxm__(bool oxm, enum ofp_version version)
|
2010-11-09 17:00:59 -08:00
|
|
|
|
{
|
|
|
|
|
struct ds in;
|
|
|
|
|
|
|
|
|
|
ds_init(&in);
|
2012-05-09 12:15:11 -07:00
|
|
|
|
while (!ds_get_test_line(&in, stdin)) {
|
2010-11-09 17:00:59 -08:00
|
|
|
|
struct ofpbuf nx_match;
|
2012-08-07 15:28:18 -07:00
|
|
|
|
struct match match;
|
2011-12-23 12:23:24 -08:00
|
|
|
|
ovs_be64 cookie, cookie_mask;
|
2012-01-12 15:48:19 -08:00
|
|
|
|
enum ofperr error;
|
2010-11-09 17:00:59 -08:00
|
|
|
|
int match_len;
|
|
|
|
|
|
|
|
|
|
/* Convert string to nx_match. */
|
|
|
|
|
ofpbuf_init(&nx_match, 0);
|
2012-08-01 16:01:45 +09:00
|
|
|
|
if (oxm) {
|
|
|
|
|
match_len = oxm_match_from_string(ds_cstr(&in), &nx_match);
|
|
|
|
|
} else {
|
|
|
|
|
match_len = nx_match_from_string(ds_cstr(&in), &nx_match);
|
|
|
|
|
}
|
2010-11-09 17:00:59 -08:00
|
|
|
|
|
2012-08-07 15:28:18 -07:00
|
|
|
|
/* Convert nx_match to match. */
|
2012-01-03 13:30:45 -08:00
|
|
|
|
if (strict) {
|
2012-08-01 16:01:45 +09:00
|
|
|
|
if (oxm) {
|
ofproto: Add pipeline fields support for OF 1.5 packet-out
This patch decodes pipeline fields from a packet-out message, and populates
the pipeline fields into datapath. Error OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY
is returned if the match field of a packet-out messages contains any
non pipeline fields. Currently, the supported pipeline fields
are as following.
* metadata fields:
- in_port, in_port_oxm
* tunnel fields:
- tun_id, tun_src, tun_dst, tun_ipv6_src, tun_ipv6_dst
- tun_gbp_id, tun_gpb_flags, tun_flags
- tun_metadata0 - tun_metadata63
* register fields:
- metadata
- reg0 - reg-15, xreg0 - xreg7, xxreg0 - xxreg3
Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2017-05-15 10:04:57 -07:00
|
|
|
|
error = oxm_pull_match(&nx_match, false, NULL, NULL, &match);
|
2012-08-01 16:01:45 +09:00
|
|
|
|
} else {
|
ofproto: Add pipeline fields support for OF 1.5 packet-out
This patch decodes pipeline fields from a packet-out message, and populates
the pipeline fields into datapath. Error OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY
is returned if the match field of a packet-out messages contains any
non pipeline fields. Currently, the supported pipeline fields
are as following.
* metadata fields:
- in_port, in_port_oxm
* tunnel fields:
- tun_id, tun_src, tun_dst, tun_ipv6_src, tun_ipv6_dst
- tun_gbp_id, tun_gpb_flags, tun_flags
- tun_metadata0 - tun_metadata63
* register fields:
- metadata
- reg0 - reg-15, xreg0 - xreg7, xxreg0 - xxreg3
Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2017-05-15 10:04:57 -07:00
|
|
|
|
error = nx_pull_match(&nx_match, match_len, &match, &cookie,
|
|
|
|
|
&cookie_mask, false, NULL, NULL);
|
2012-08-01 16:01:45 +09:00
|
|
|
|
}
|
2012-01-03 13:30:45 -08:00
|
|
|
|
} else {
|
2012-08-01 16:01:45 +09:00
|
|
|
|
if (oxm) {
|
ofproto: Add pipeline fields support for OF 1.5 packet-out
This patch decodes pipeline fields from a packet-out message, and populates
the pipeline fields into datapath. Error OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY
is returned if the match field of a packet-out messages contains any
non pipeline fields. Currently, the supported pipeline fields
are as following.
* metadata fields:
- in_port, in_port_oxm
* tunnel fields:
- tun_id, tun_src, tun_dst, tun_ipv6_src, tun_ipv6_dst
- tun_gbp_id, tun_gpb_flags, tun_flags
- tun_metadata0 - tun_metadata63
* register fields:
- metadata
- reg0 - reg-15, xreg0 - xreg7, xxreg0 - xxreg3
Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2017-05-15 10:04:57 -07:00
|
|
|
|
error = oxm_pull_match_loose(&nx_match, false, NULL, &match);
|
2012-08-01 16:01:45 +09:00
|
|
|
|
} else {
|
2012-08-07 15:28:18 -07:00
|
|
|
|
error = nx_pull_match_loose(&nx_match, match_len, &match,
|
ofproto: Add pipeline fields support for OF 1.5 packet-out
This patch decodes pipeline fields from a packet-out message, and populates
the pipeline fields into datapath. Error OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY
is returned if the match field of a packet-out messages contains any
non pipeline fields. Currently, the supported pipeline fields
are as following.
* metadata fields:
- in_port, in_port_oxm
* tunnel fields:
- tun_id, tun_src, tun_dst, tun_ipv6_src, tun_ipv6_dst
- tun_gbp_id, tun_gpb_flags, tun_flags
- tun_metadata0 - tun_metadata63
* register fields:
- metadata
- reg0 - reg-15, xreg0 - xreg7, xxreg0 - xxreg3
Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2017-05-15 10:04:57 -07:00
|
|
|
|
&cookie, &cookie_mask, false,
|
|
|
|
|
NULL);
|
2012-08-01 16:01:45 +09:00
|
|
|
|
}
|
2012-01-03 13:30:45 -08:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-01 16:01:45 +09:00
|
|
|
|
|
2010-11-09 17:00:59 -08:00
|
|
|
|
if (!error) {
|
|
|
|
|
char *out;
|
|
|
|
|
|
2012-08-07 15:28:18 -07:00
|
|
|
|
/* Convert match back to nx_match. */
|
2010-11-09 17:00:59 -08:00
|
|
|
|
ofpbuf_uninit(&nx_match);
|
|
|
|
|
ofpbuf_init(&nx_match, 0);
|
2012-08-01 16:01:45 +09:00
|
|
|
|
if (oxm) {
|
2014-05-09 18:18:17 -07:00
|
|
|
|
match_len = oxm_put_match(&nx_match, &match, version);
|
2013-07-22 15:47:19 -07:00
|
|
|
|
out = oxm_match_to_string(&nx_match, match_len);
|
2012-08-01 16:01:45 +09:00
|
|
|
|
} else {
|
2012-08-07 15:28:18 -07:00
|
|
|
|
match_len = nx_put_match(&nx_match, &match,
|
2012-08-01 16:01:45 +09:00
|
|
|
|
cookie, cookie_mask);
|
2015-03-02 17:29:44 -08:00
|
|
|
|
out = nx_match_to_string(nx_match.data, match_len);
|
2012-08-01 16:01:45 +09:00
|
|
|
|
}
|
2010-11-09 17:00:59 -08:00
|
|
|
|
|
|
|
|
|
puts(out);
|
|
|
|
|
free(out);
|
nx-match: Add support for experimenter OXM.
OpenFlow 1.2+ defines a means for vendors to define vendor-specific OXM
fields, called "experimenter OXM". These OXM fields are expressed with a
64-bit OXM header instead of the 32-bit header used for standard OXM (and
NXM). Until now, OVS has not implemented experimenter OXM, and indeed we
have had little need to do so because of a pair of special 32-bit OXM classes
grandfathered to OVS as part of the OpenFlow 1.2 standardization process.
However, I want to prototype a feature for OpenFlow 1.5 that uses an
experimenter OXM as part of the prototype, so to do this OVS needs to
support experimenter OXM. This commit adds that support.
Most of this commit is a fairly straightforward change: it extends the type
used for OXM/NXM from 32 to 64 bits and adds code to encode and decode the
longer headers when necessary. Some other changes are necessary because
experimenter OXMs have a funny idea of the division between "header" and
"body": the extra 32 bits for experimenter OXMs are counted as part of the body
rather than the header according to the OpenFlow standard (even though this
does not entirely make sense), so arithmetic in various places has to be
adjusted, which is the reason for the new functions nxm_experimenter_len(),
nxm_payload_len(), and nxm_header_len().
Another change that calls for explanation is the new function mf_nxm_header()
that has been split from mf_oxm_header(). This function is used in actions
where the space for an NXM or OXM header is fixed so that there is no room
for a 64-bit experimenter type. An upcoming commit will add new variations
of these actions that can support experimenter OXM.
Testing experimenter OXM is tricky because I do not know of any in
widespread use. Two ONF proposals use experimenter OXMs: EXT-256 and
EXT-233. EXT-256 is not suitable to implement for testing because its use
of experimenter OXM is wrong and will be changed. EXT-233 is not suitable
to implement for testing because it requires adding a new field to struct
flow and I am not yet convinced that that field and the feature that it
supports is worth having in Open vSwitch. Thus, this commit assigns an
experimenter OXM code point to an existing OVS field that is currently
restricted from use by controllers, "dp_hash", and uses that for testing.
Because controllers cannot use it, this leaves future versions of OVS free
to drop the support for the experimenter OXM for this field without causing
backward compatibility problems.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jarno Rajahalme <jrajahalme@nicira.com>
2014-10-08 15:41:00 -07:00
|
|
|
|
|
|
|
|
|
if (verbosity > 0) {
|
2015-03-02 17:29:44 -08:00
|
|
|
|
ovs_hex_dump(stdout, nx_match.data, nx_match.size, 0, false);
|
nx-match: Add support for experimenter OXM.
OpenFlow 1.2+ defines a means for vendors to define vendor-specific OXM
fields, called "experimenter OXM". These OXM fields are expressed with a
64-bit OXM header instead of the 32-bit header used for standard OXM (and
NXM). Until now, OVS has not implemented experimenter OXM, and indeed we
have had little need to do so because of a pair of special 32-bit OXM classes
grandfathered to OVS as part of the OpenFlow 1.2 standardization process.
However, I want to prototype a feature for OpenFlow 1.5 that uses an
experimenter OXM as part of the prototype, so to do this OVS needs to
support experimenter OXM. This commit adds that support.
Most of this commit is a fairly straightforward change: it extends the type
used for OXM/NXM from 32 to 64 bits and adds code to encode and decode the
longer headers when necessary. Some other changes are necessary because
experimenter OXMs have a funny idea of the division between "header" and
"body": the extra 32 bits for experimenter OXMs are counted as part of the body
rather than the header according to the OpenFlow standard (even though this
does not entirely make sense), so arithmetic in various places has to be
adjusted, which is the reason for the new functions nxm_experimenter_len(),
nxm_payload_len(), and nxm_header_len().
Another change that calls for explanation is the new function mf_nxm_header()
that has been split from mf_oxm_header(). This function is used in actions
where the space for an NXM or OXM header is fixed so that there is no room
for a 64-bit experimenter type. An upcoming commit will add new variations
of these actions that can support experimenter OXM.
Testing experimenter OXM is tricky because I do not know of any in
widespread use. Two ONF proposals use experimenter OXMs: EXT-256 and
EXT-233. EXT-256 is not suitable to implement for testing because its use
of experimenter OXM is wrong and will be changed. EXT-233 is not suitable
to implement for testing because it requires adding a new field to struct
flow and I am not yet convinced that that field and the feature that it
supports is worth having in Open vSwitch. Thus, this commit assigns an
experimenter OXM code point to an existing OVS field that is currently
restricted from use by controllers, "dp_hash", and uses that for testing.
Because controllers cannot use it, this leaves future versions of OVS free
to drop the support for the experimenter OXM for this field without causing
backward compatibility problems.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jarno Rajahalme <jrajahalme@nicira.com>
2014-10-08 15:41:00 -07:00
|
|
|
|
}
|
2010-11-09 17:00:59 -08:00
|
|
|
|
} else {
|
2012-01-12 15:48:19 -08:00
|
|
|
|
printf("nx_pull_match() returned error %s\n",
|
|
|
|
|
ofperr_get_name(error));
|
2010-11-09 17:00:59 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ofpbuf_uninit(&nx_match);
|
|
|
|
|
}
|
|
|
|
|
ds_destroy(&in);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-06-11 09:56:12 -07:00
|
|
|
|
/* "parse-nxm": reads a series of NXM nx_match specifications as strings from
|
|
|
|
|
* stdin, does some internal fussing with them, and then prints them back as
|
|
|
|
|
* strings on stdout. */
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_nxm(struct ovs_cmdl_context *ctx OVS_UNUSED)
|
2012-06-11 09:56:12 -07:00
|
|
|
|
{
|
2014-09-09 14:12:57 -07:00
|
|
|
|
ofctl_parse_nxm__(false, 0);
|
2012-06-11 09:56:12 -07:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 18:18:17 -07:00
|
|
|
|
/* "parse-oxm VERSION": reads a series of OXM nx_match specifications as
|
|
|
|
|
* strings from stdin, does some internal fussing with them, and then prints
|
|
|
|
|
* them back as strings on stdout. VERSION must specify an OpenFlow version,
|
|
|
|
|
* e.g. "OpenFlow12". */
|
2012-06-11 09:56:12 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_oxm(struct ovs_cmdl_context *ctx)
|
2012-06-11 09:56:12 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
enum ofp_version version = ofputil_version_from_string(ctx->argv[1]);
|
2014-05-09 18:18:17 -07:00
|
|
|
|
if (version < OFP12_VERSION) {
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ovs_fatal(0, "%s: not a valid version for OXM", ctx->argv[1]);
|
2014-05-09 18:18:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-09 14:12:57 -07:00
|
|
|
|
ofctl_parse_nxm__(true, version);
|
2012-06-11 09:56:12 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-03 22:17:14 -07:00
|
|
|
|
static void
|
2012-07-17 09:39:23 -07:00
|
|
|
|
print_differences(const char *prefix,
|
|
|
|
|
const void *a_, size_t a_len,
|
2012-07-03 22:17:14 -07:00
|
|
|
|
const void *b_, size_t b_len)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t *a = a_;
|
|
|
|
|
const uint8_t *b = b_;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MIN(a_len, b_len); i++) {
|
|
|
|
|
if (a[i] != b[i]) {
|
2013-11-25 23:38:48 -08:00
|
|
|
|
printf("%s%2"PRIuSIZE": %02"PRIx8" -> %02"PRIx8"\n",
|
2012-07-17 09:39:23 -07:00
|
|
|
|
prefix, i, a[i], b[i]);
|
2012-07-03 22:17:14 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (i = a_len; i < b_len; i++) {
|
2013-11-25 23:38:48 -08:00
|
|
|
|
printf("%s%2"PRIuSIZE": (none) -> %02"PRIx8"\n", prefix, i, b[i]);
|
2012-07-03 22:17:14 -07:00
|
|
|
|
}
|
|
|
|
|
for (i = b_len; i < a_len; i++) {
|
2013-11-25 23:38:48 -08:00
|
|
|
|
printf("%s%2"PRIuSIZE": %02"PRIx8" -> (none)\n", prefix, i, a[i]);
|
2012-07-03 22:17:14 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-08-07 16:03:42 -07:00
|
|
|
|
ofctl_parse_actions__(const char *version_s, bool instructions)
|
2012-07-03 22:17:14 -07:00
|
|
|
|
{
|
2014-08-07 16:03:42 -07:00
|
|
|
|
enum ofp_version version;
|
2012-07-03 22:17:14 -07:00
|
|
|
|
struct ds in;
|
|
|
|
|
|
2014-08-07 16:03:42 -07:00
|
|
|
|
version = ofputil_version_from_string(version_s);
|
|
|
|
|
if (!version) {
|
|
|
|
|
ovs_fatal(0, "%s: not a valid OpenFlow version", version_s);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-03 22:17:14 -07:00
|
|
|
|
ds_init(&in);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
while (!ds_get_preprocessed_line(&in, stdin, NULL)) {
|
2014-08-07 16:03:42 -07:00
|
|
|
|
struct ofpbuf of_out;
|
|
|
|
|
struct ofpbuf of_in;
|
2012-07-03 22:17:14 -07:00
|
|
|
|
struct ofpbuf ofpacts;
|
2014-08-07 16:03:42 -07:00
|
|
|
|
const char *table_id;
|
|
|
|
|
char *actions;
|
2012-07-03 22:17:14 -07:00
|
|
|
|
enum ofperr error;
|
|
|
|
|
size_t size;
|
|
|
|
|
struct ds s;
|
|
|
|
|
|
2014-08-07 16:03:42 -07:00
|
|
|
|
/* Parse table_id separated with the follow-up actions by ",", if
|
|
|
|
|
* any. */
|
|
|
|
|
actions = ds_cstr(&in);
|
|
|
|
|
table_id = NULL;
|
|
|
|
|
if (strstr(actions, ",")) {
|
|
|
|
|
table_id = strsep(&actions, ",");
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-03 22:17:14 -07:00
|
|
|
|
/* Parse hex bytes. */
|
2014-08-07 16:03:42 -07:00
|
|
|
|
ofpbuf_init(&of_in, 0);
|
|
|
|
|
if (ofpbuf_put_hex(&of_in, actions, NULL)[0] != '\0') {
|
2012-07-03 22:17:14 -07:00
|
|
|
|
ovs_fatal(0, "Trailing garbage in hex data");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert to ofpacts. */
|
|
|
|
|
ofpbuf_init(&ofpacts, 0);
|
2015-03-02 17:29:44 -08:00
|
|
|
|
size = of_in.size;
|
2014-08-07 16:09:07 -07:00
|
|
|
|
error = (instructions
|
|
|
|
|
? ofpacts_pull_openflow_instructions
|
|
|
|
|
: ofpacts_pull_openflow_actions)(
|
2017-03-13 11:28:21 -07:00
|
|
|
|
&of_in, of_in.size, version, NULL, NULL, &ofpacts);
|
2014-08-07 16:03:42 -07:00
|
|
|
|
if (!error && instructions) {
|
|
|
|
|
/* Verify actions, enforce consistency. */
|
2018-06-15 16:29:22 -07:00
|
|
|
|
struct match match = MATCH_CATCHALL_INITIALIZER;
|
|
|
|
|
struct ofpact_check_params cp = {
|
|
|
|
|
.match = &match,
|
|
|
|
|
.max_ports = OFPP_MAX,
|
|
|
|
|
.table_id = table_id ? atoi(table_id) : 0,
|
|
|
|
|
.n_tables = OFPTT_MAX + 1,
|
|
|
|
|
};
|
|
|
|
|
error = ofpacts_check_consistency(
|
|
|
|
|
ofpacts.data, ofpacts.size,
|
|
|
|
|
ofputil_protocols_from_ofp_version(version), &cp);
|
2014-08-07 16:03:42 -07:00
|
|
|
|
}
|
2012-07-03 22:17:14 -07:00
|
|
|
|
if (error) {
|
2014-08-07 16:03:42 -07:00
|
|
|
|
printf("bad %s %s: %s\n\n",
|
|
|
|
|
version_s, instructions ? "instructions" : "actions",
|
|
|
|
|
ofperr_get_name(error));
|
2012-07-03 22:17:14 -07:00
|
|
|
|
ofpbuf_uninit(&ofpacts);
|
2014-08-07 16:03:42 -07:00
|
|
|
|
ofpbuf_uninit(&of_in);
|
2012-07-03 22:17:14 -07:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2014-08-07 16:03:42 -07:00
|
|
|
|
ofpbuf_push_uninit(&of_in, size);
|
2012-07-03 22:17:14 -07:00
|
|
|
|
|
|
|
|
|
/* Print cls_rule. */
|
|
|
|
|
ds_init(&s);
|
2013-10-14 14:08:20 -07:00
|
|
|
|
ds_put_cstr(&s, "actions=");
|
2018-01-12 12:56:12 -08:00
|
|
|
|
struct ofpact_format_params fp = { .s = &s };
|
|
|
|
|
ofpacts_format(ofpacts.data, ofpacts.size, &fp);
|
2012-07-03 22:17:14 -07:00
|
|
|
|
puts(ds_cstr(&s));
|
|
|
|
|
ds_destroy(&s);
|
|
|
|
|
|
|
|
|
|
/* Convert back to ofp10 actions and print differences from input. */
|
2014-08-07 16:03:42 -07:00
|
|
|
|
ofpbuf_init(&of_out, 0);
|
|
|
|
|
if (instructions) {
|
2015-03-02 17:29:44 -08:00
|
|
|
|
ofpacts_put_openflow_instructions(ofpacts.data, ofpacts.size,
|
|
|
|
|
&of_out, version);
|
2014-08-07 16:03:42 -07:00
|
|
|
|
} else {
|
2015-03-02 17:29:44 -08:00
|
|
|
|
ofpacts_put_openflow_actions(ofpacts.data, ofpacts.size,
|
2014-08-07 16:03:42 -07:00
|
|
|
|
&of_out, version);
|
|
|
|
|
}
|
2012-07-03 22:17:14 -07:00
|
|
|
|
|
2015-03-02 17:29:44 -08:00
|
|
|
|
print_differences("", of_in.data, of_in.size,
|
|
|
|
|
of_out.data, of_out.size);
|
2012-07-03 22:17:14 -07:00
|
|
|
|
putchar('\n');
|
|
|
|
|
|
|
|
|
|
ofpbuf_uninit(&ofpacts);
|
2014-08-07 16:03:42 -07:00
|
|
|
|
ofpbuf_uninit(&of_in);
|
|
|
|
|
ofpbuf_uninit(&of_out);
|
2012-07-03 22:17:14 -07:00
|
|
|
|
}
|
|
|
|
|
ds_destroy(&in);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-07 16:03:42 -07:00
|
|
|
|
/* "parse-actions VERSION": reads a series of action specifications for the
|
|
|
|
|
* given OpenFlow VERSION as hex bytes from stdin, converts them to ofpacts,
|
|
|
|
|
* prints them as strings on stdout, and then converts them back to hex bytes
|
|
|
|
|
* and prints any differences from the input. */
|
2014-08-07 16:09:07 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_actions(struct ovs_cmdl_context *ctx)
|
2014-08-07 16:09:07 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_actions__(ctx->argv[1], false);
|
2014-08-07 16:09:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-07 16:03:42 -07:00
|
|
|
|
/* "parse-actions VERSION": reads a series of instruction specifications for
|
|
|
|
|
* the given OpenFlow VERSION as hex bytes from stdin, converts them to
|
|
|
|
|
* ofpacts, prints them as strings on stdout, and then converts them back to
|
|
|
|
|
* hex bytes and prints any differences from the input. */
|
2014-08-07 16:09:07 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_instructions(struct ovs_cmdl_context *ctx)
|
2014-08-07 16:09:07 -07:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_actions__(ctx->argv[1], true);
|
2014-08-07 16:09:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-17 09:39:23 -07:00
|
|
|
|
/* "parse-ofp10-match": reads a series of ofp10_match specifications as hex
|
|
|
|
|
* bytes from stdin, converts them to cls_rules, prints them as strings on
|
|
|
|
|
* stdout, and then converts them back to hex bytes and prints any differences
|
2012-07-21 09:56:28 -07:00
|
|
|
|
* from the input.
|
|
|
|
|
*
|
|
|
|
|
* The input hex bytes may contain "x"s to represent "don't-cares", bytes whose
|
|
|
|
|
* values are ignored in the input and will be set to zero when OVS converts
|
|
|
|
|
* them back to hex bytes. ovs-ofctl actually sets "x"s to random bits when
|
|
|
|
|
* it does the conversion to hex, to ensure that in fact they are ignored. */
|
2012-07-17 09:39:23 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_ofp10_match(struct ovs_cmdl_context *ctx OVS_UNUSED)
|
2012-07-17 09:39:23 -07:00
|
|
|
|
{
|
2012-07-21 09:56:28 -07:00
|
|
|
|
struct ds expout;
|
2012-07-17 09:39:23 -07:00
|
|
|
|
struct ds in;
|
|
|
|
|
|
|
|
|
|
ds_init(&in);
|
2012-07-21 09:56:28 -07:00
|
|
|
|
ds_init(&expout);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
while (!ds_get_preprocessed_line(&in, stdin, NULL)) {
|
2012-07-21 09:56:28 -07:00
|
|
|
|
struct ofpbuf match_in, match_expout;
|
2012-07-17 09:39:23 -07:00
|
|
|
|
struct ofp10_match match_out;
|
|
|
|
|
struct ofp10_match match_normal;
|
2012-08-07 15:28:18 -07:00
|
|
|
|
struct match match;
|
2012-07-21 09:56:28 -07:00
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
/* Parse hex bytes to use for expected output. */
|
|
|
|
|
ds_clear(&expout);
|
|
|
|
|
ds_put_cstr(&expout, ds_cstr(&in));
|
|
|
|
|
for (p = ds_cstr(&expout); *p; p++) {
|
|
|
|
|
if (*p == 'x') {
|
|
|
|
|
*p = '0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ofpbuf_init(&match_expout, 0);
|
|
|
|
|
if (ofpbuf_put_hex(&match_expout, ds_cstr(&expout), NULL)[0] != '\0') {
|
|
|
|
|
ovs_fatal(0, "Trailing garbage in hex data");
|
|
|
|
|
}
|
2015-03-02 17:29:44 -08:00
|
|
|
|
if (match_expout.size != sizeof(struct ofp10_match)) {
|
lib/ofpbuf: Compact
This patch shrinks the struct ofpbuf from 104 to 48 bytes on 64-bit
systems, or from 52 to 36 bytes on 32-bit systems (counting in the
'l7' removal from an earlier patch). This may help contribute to
cache efficiency, and will speed up initializing, copying and
manipulating ofpbufs. This is potentially important for the DPDK
datapath, but the rest of the code base may also see a little benefit.
Changes are:
- Remove 'l7' pointer (previous patch).
- Use offsets instead of layer pointers for l2_5, l3, and l4 using
'l2' as basis. Usually 'data' is the same as 'l2', but this is not
always the case (e.g., when parsing or constructing a packet), so it
can not be easily used as the offset basis. Also, packet parsing is
faster if we do not need to maintain the offsets each time we pull
data from the ofpbuf.
- Use uint32_t for 'allocated' and 'size', as 2^32 is enough even for
largest possible messages/packets.
- Use packed enum for 'source'.
- Rearrange to avoid unnecessary padding.
- Remove 'private_p', which was used only in two cases, both of which
had the invariant ('l2' == 'data'), so we can temporarily use 'l2'
as a private pointer.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
2014-03-24 09:17:01 -07:00
|
|
|
|
ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE,
|
2015-03-02 17:29:44 -08:00
|
|
|
|
match_expout.size, sizeof(struct ofp10_match));
|
2012-07-21 09:56:28 -07:00
|
|
|
|
}
|
2012-07-17 09:39:23 -07:00
|
|
|
|
|
2012-07-21 09:56:28 -07:00
|
|
|
|
/* Parse hex bytes for input. */
|
|
|
|
|
for (p = ds_cstr(&in); *p; p++) {
|
|
|
|
|
if (*p == 'x') {
|
|
|
|
|
*p = "0123456789abcdef"[random_uint32() & 0xf];
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-07-17 09:39:23 -07:00
|
|
|
|
ofpbuf_init(&match_in, 0);
|
|
|
|
|
if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') {
|
|
|
|
|
ovs_fatal(0, "Trailing garbage in hex data");
|
|
|
|
|
}
|
2015-03-02 17:29:44 -08:00
|
|
|
|
if (match_in.size != sizeof(struct ofp10_match)) {
|
lib/ofpbuf: Compact
This patch shrinks the struct ofpbuf from 104 to 48 bytes on 64-bit
systems, or from 52 to 36 bytes on 32-bit systems (counting in the
'l7' removal from an earlier patch). This may help contribute to
cache efficiency, and will speed up initializing, copying and
manipulating ofpbufs. This is potentially important for the DPDK
datapath, but the rest of the code base may also see a little benefit.
Changes are:
- Remove 'l7' pointer (previous patch).
- Use offsets instead of layer pointers for l2_5, l3, and l4 using
'l2' as basis. Usually 'data' is the same as 'l2', but this is not
always the case (e.g., when parsing or constructing a packet), so it
can not be easily used as the offset basis. Also, packet parsing is
faster if we do not need to maintain the offsets each time we pull
data from the ofpbuf.
- Use uint32_t for 'allocated' and 'size', as 2^32 is enough even for
largest possible messages/packets.
- Use packed enum for 'source'.
- Rearrange to avoid unnecessary padding.
- Remove 'private_p', which was used only in two cases, both of which
had the invariant ('l2' == 'data'), so we can temporarily use 'l2'
as a private pointer.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
2014-03-24 09:17:01 -07:00
|
|
|
|
ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE,
|
2015-03-02 17:29:44 -08:00
|
|
|
|
match_in.size, sizeof(struct ofp10_match));
|
2012-07-17 09:39:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert to cls_rule and print. */
|
2015-03-02 17:29:44 -08:00
|
|
|
|
ofputil_match_from_ofp10_match(match_in.data, &match);
|
2017-05-31 16:06:12 -07:00
|
|
|
|
match_print(&match, NULL);
|
2012-07-17 09:39:23 -07:00
|
|
|
|
|
|
|
|
|
/* Convert back to ofp10_match and print differences from input. */
|
2012-08-07 15:28:18 -07:00
|
|
|
|
ofputil_match_to_ofp10_match(&match, &match_out);
|
2015-03-02 17:29:44 -08:00
|
|
|
|
print_differences("", match_expout.data, match_expout.size,
|
2012-07-17 09:39:23 -07:00
|
|
|
|
&match_out, sizeof match_out);
|
|
|
|
|
|
|
|
|
|
/* Normalize, then convert and compare again. */
|
2012-08-07 15:28:18 -07:00
|
|
|
|
ofputil_normalize_match(&match);
|
|
|
|
|
ofputil_match_to_ofp10_match(&match, &match_normal);
|
2012-07-17 09:39:23 -07:00
|
|
|
|
print_differences("normal: ", &match_out, sizeof match_out,
|
|
|
|
|
&match_normal, sizeof match_normal);
|
|
|
|
|
putchar('\n');
|
|
|
|
|
|
|
|
|
|
ofpbuf_uninit(&match_in);
|
2012-07-21 09:56:28 -07:00
|
|
|
|
ofpbuf_uninit(&match_expout);
|
2012-07-17 09:39:23 -07:00
|
|
|
|
}
|
|
|
|
|
ds_destroy(&in);
|
2012-07-21 09:56:28 -07:00
|
|
|
|
ds_destroy(&expout);
|
2012-07-17 09:39:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-06-09 15:49:16 -07:00
|
|
|
|
/* "parse-ofp11-match": reads a series of ofp11_match specifications as hex
|
2012-08-07 15:28:18 -07:00
|
|
|
|
* bytes from stdin, converts them to "struct match"es, prints them as strings
|
|
|
|
|
* on stdout, and then converts them back to hex bytes and prints any
|
|
|
|
|
* differences from the input. */
|
2012-06-09 15:49:16 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_ofp11_match(struct ovs_cmdl_context *ctx OVS_UNUSED)
|
2012-06-09 15:49:16 -07:00
|
|
|
|
{
|
|
|
|
|
struct ds in;
|
|
|
|
|
|
|
|
|
|
ds_init(&in);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
while (!ds_get_preprocessed_line(&in, stdin, NULL)) {
|
2012-06-09 15:49:16 -07:00
|
|
|
|
struct ofpbuf match_in;
|
|
|
|
|
struct ofp11_match match_out;
|
2012-08-07 15:28:18 -07:00
|
|
|
|
struct match match;
|
2012-06-09 15:49:16 -07:00
|
|
|
|
enum ofperr error;
|
|
|
|
|
|
|
|
|
|
/* Parse hex bytes. */
|
|
|
|
|
ofpbuf_init(&match_in, 0);
|
|
|
|
|
if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') {
|
|
|
|
|
ovs_fatal(0, "Trailing garbage in hex data");
|
|
|
|
|
}
|
2015-03-02 17:29:44 -08:00
|
|
|
|
if (match_in.size != sizeof(struct ofp11_match)) {
|
lib/ofpbuf: Compact
This patch shrinks the struct ofpbuf from 104 to 48 bytes on 64-bit
systems, or from 52 to 36 bytes on 32-bit systems (counting in the
'l7' removal from an earlier patch). This may help contribute to
cache efficiency, and will speed up initializing, copying and
manipulating ofpbufs. This is potentially important for the DPDK
datapath, but the rest of the code base may also see a little benefit.
Changes are:
- Remove 'l7' pointer (previous patch).
- Use offsets instead of layer pointers for l2_5, l3, and l4 using
'l2' as basis. Usually 'data' is the same as 'l2', but this is not
always the case (e.g., when parsing or constructing a packet), so it
can not be easily used as the offset basis. Also, packet parsing is
faster if we do not need to maintain the offsets each time we pull
data from the ofpbuf.
- Use uint32_t for 'allocated' and 'size', as 2^32 is enough even for
largest possible messages/packets.
- Use packed enum for 'source'.
- Rearrange to avoid unnecessary padding.
- Remove 'private_p', which was used only in two cases, both of which
had the invariant ('l2' == 'data'), so we can temporarily use 'l2'
as a private pointer.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
2014-03-24 09:17:01 -07:00
|
|
|
|
ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE,
|
2015-03-02 17:29:44 -08:00
|
|
|
|
match_in.size, sizeof(struct ofp11_match));
|
2012-06-09 15:49:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-07 15:28:18 -07:00
|
|
|
|
/* Convert to match. */
|
2015-03-02 17:29:44 -08:00
|
|
|
|
error = ofputil_match_from_ofp11_match(match_in.data, &match);
|
2012-06-09 15:49:16 -07:00
|
|
|
|
if (error) {
|
|
|
|
|
printf("bad ofp11_match: %s\n\n", ofperr_get_name(error));
|
|
|
|
|
ofpbuf_uninit(&match_in);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-07 15:28:18 -07:00
|
|
|
|
/* Print match. */
|
2017-05-31 16:06:12 -07:00
|
|
|
|
match_print(&match, NULL);
|
2012-06-09 15:49:16 -07:00
|
|
|
|
|
|
|
|
|
/* Convert back to ofp11_match and print differences from input. */
|
2012-08-07 15:28:18 -07:00
|
|
|
|
ofputil_match_to_ofp11_match(&match, &match_out);
|
2012-06-09 15:49:16 -07:00
|
|
|
|
|
2015-03-02 17:29:44 -08:00
|
|
|
|
print_differences("", match_in.data, match_in.size,
|
2012-07-03 22:14:29 -07:00
|
|
|
|
&match_out, sizeof match_out);
|
|
|
|
|
putchar('\n');
|
2012-06-09 15:49:16 -07:00
|
|
|
|
|
2012-07-03 22:14:29 -07:00
|
|
|
|
ofpbuf_uninit(&match_in);
|
|
|
|
|
}
|
|
|
|
|
ds_destroy(&in);
|
|
|
|
|
}
|
|
|
|
|
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
/* "parse-pcap PCAP...": read packets from each PCAP file and print their
|
|
|
|
|
* flows. */
|
2013-09-23 10:28:14 -07:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_parse_pcap(struct ovs_cmdl_context *ctx)
|
2013-09-23 10:28:14 -07:00
|
|
|
|
{
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
int error = 0;
|
|
|
|
|
for (int i = 1; i < ctx->argc; i++) {
|
|
|
|
|
const char *filename = ctx->argv[i];
|
2018-10-05 12:52:40 -04:00
|
|
|
|
struct pcap_file *pcap = ovs_pcap_open(filename, "rb");
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
if (!pcap) {
|
|
|
|
|
error = errno;
|
|
|
|
|
ovs_error(error, "%s: open failed", filename);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2013-09-23 10:28:14 -07:00
|
|
|
|
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
for (;;) {
|
|
|
|
|
struct dp_packet *packet;
|
|
|
|
|
struct flow flow;
|
|
|
|
|
int retval;
|
2013-09-23 10:28:14 -07:00
|
|
|
|
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
retval = ovs_pcap_read(pcap, &packet, NULL);
|
|
|
|
|
if (retval == EOF) {
|
|
|
|
|
break;
|
|
|
|
|
} else if (retval) {
|
|
|
|
|
error = retval;
|
|
|
|
|
ovs_error(error, "%s: read failed", filename);
|
2019-02-18 10:56:38 +08:00
|
|
|
|
break;
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
}
|
2013-09-23 10:28:14 -07:00
|
|
|
|
|
2016-06-03 13:15:01 -07:00
|
|
|
|
pkt_metadata_init(&packet->md, u32_to_odp(ofp_to_u16(OFPP_ANY)));
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
flow_extract(packet, &flow);
|
2017-05-31 16:06:12 -07:00
|
|
|
|
flow_print(stdout, &flow, NULL);
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
putchar('\n');
|
|
|
|
|
dp_packet_delete(packet);
|
2013-09-23 10:28:14 -07:00
|
|
|
|
}
|
2018-10-05 12:52:40 -04:00
|
|
|
|
ovs_pcap_close(pcap);
|
2013-09-23 10:28:14 -07:00
|
|
|
|
}
|
Implement serializing the state of packet traversal in "continuations".
One purpose of OpenFlow packet-in messages is to allow a controller to
interpose on the path of a packet through the flow tables. If, for
example, the controller needs to modify a packet in some way that the
switch doesn't directly support, the controller should be able to
program the switch to send it the packet, then modify the packet and
send it back to the switch to continue through the flow table.
That's the theory. In practice, this doesn't work with any but the
simplest flow tables. Packet-in messages simply don't include enough
context to allow the flow table traversal to continue. For example:
* Via "resubmit" actions, an Open vSwitch packet can have an
effective "call stack", but a packet-in can't describe it, and
so it would be lost.
* A packet-in can't preserve the stack used by NXAST_PUSH and
NXAST_POP actions.
* A packet-in can't preserve the OpenFlow 1.1+ action set.
* A packet-in can't preserve the state of Open vSwitch mirroring
or connection tracking.
This commit introduces a solution called "continuations". A continuation
is the state of a packet's traversal through OpenFlow flow tables. A
"controller" action with the "pause" flag, which is newly implemented in
this commit, generates a continuation and sends it to the OpenFlow
controller in a packet-in asynchronous message (only NXT_PACKET_IN2
supports continuations, so the controller must configure them with
NXT_SET_PACKET_IN_FORMAT). The controller processes the packet-in,
possibly modifying some of its data, and sends it back to the switch with
an NXT_RESUME request, which causes flow table traversal to continue. In
principle, a single packet can be paused and resumed multiple times.
Another way to look at it is:
- "pause" is an extension of the existing OFPAT_CONTROLLER
action. It sends the packet to the controller, with full
pipeline context (some of which is switch implementation
dependent, and may thus vary from switch to switch).
- A continuation is an extension of OFPT_PACKET_IN, allowing for
implementation dependent metadata.
- NXT_RESUME is an extension of OFPT_PACKET_OUT, with the
semantics that the pipeline processing is continued with the
original translation context from where it was left at the time
it was paused.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
2016-02-19 16:10:06 -08:00
|
|
|
|
exit(error);
|
2013-09-23 10:28:14 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-19 22:17:10 -07:00
|
|
|
|
/* "check-vlan VLAN_TCI VLAN_TCI_MASK": converts the specified vlan_tci and
|
|
|
|
|
* mask values to and from various formats and prints the results. */
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_check_vlan(struct ovs_cmdl_context *ctx)
|
2012-07-19 22:17:10 -07:00
|
|
|
|
{
|
2012-08-07 15:28:18 -07:00
|
|
|
|
struct match match;
|
2012-07-19 22:17:10 -07:00
|
|
|
|
|
|
|
|
|
char *string_s;
|
|
|
|
|
struct ofputil_flow_mod fm;
|
|
|
|
|
|
|
|
|
|
struct ofpbuf nxm;
|
2012-08-07 15:28:18 -07:00
|
|
|
|
struct match nxm_match;
|
2012-07-19 22:17:10 -07:00
|
|
|
|
int nxm_match_len;
|
|
|
|
|
char *nxm_s;
|
|
|
|
|
|
2012-08-07 15:28:18 -07:00
|
|
|
|
struct ofp10_match of10_raw;
|
|
|
|
|
struct match of10_match;
|
2012-07-19 22:17:10 -07:00
|
|
|
|
|
2012-08-07 15:28:18 -07:00
|
|
|
|
struct ofp11_match of11_raw;
|
|
|
|
|
struct match of11_match;
|
2012-07-19 22:17:10 -07:00
|
|
|
|
|
|
|
|
|
enum ofperr error;
|
2013-07-08 10:15:00 -07:00
|
|
|
|
char *error_s;
|
2012-07-19 22:17:10 -07:00
|
|
|
|
|
2013-08-20 18:41:45 -07:00
|
|
|
|
enum ofputil_protocol usable_protocols; /* Unused for now. */
|
|
|
|
|
|
2012-08-07 15:28:18 -07:00
|
|
|
|
match_init_catchall(&match);
|
2017-03-01 17:47:59 -05:00
|
|
|
|
match.flow.vlans[0].tci = htons(strtoul(ctx->argv[1], NULL, 16));
|
|
|
|
|
match.wc.masks.vlans[0].tci = htons(strtoul(ctx->argv[2], NULL, 16));
|
2012-07-19 22:17:10 -07:00
|
|
|
|
|
|
|
|
|
/* Convert to and from string. */
|
2017-05-31 16:06:12 -07:00
|
|
|
|
string_s = match_to_string(&match, NULL, OFP_DEFAULT_PRIORITY);
|
2012-07-19 22:17:10 -07:00
|
|
|
|
printf("%s -> ", string_s);
|
|
|
|
|
fflush(stdout);
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
error_s = parse_ofp_str(&fm, -1, string_s, NULL, NULL, &usable_protocols);
|
2013-07-08 10:15:00 -07:00
|
|
|
|
if (error_s) {
|
|
|
|
|
ovs_fatal(0, "%s", error_s);
|
|
|
|
|
}
|
2018-03-19 22:01:47 -07:00
|
|
|
|
struct match fm_match;
|
|
|
|
|
minimatch_expand(&fm.match, &fm_match);
|
2012-07-19 22:17:10 -07:00
|
|
|
|
printf("%04"PRIx16"/%04"PRIx16"\n",
|
2018-03-19 22:01:47 -07:00
|
|
|
|
ntohs(fm_match.flow.vlans[0].tci),
|
|
|
|
|
ntohs(fm_match.wc.masks.vlans[0].tci));
|
2012-08-17 13:59:46 -07:00
|
|
|
|
free(string_s);
|
2018-03-19 22:01:47 -07:00
|
|
|
|
minimatch_destroy(&fm.match);
|
2012-07-19 22:17:10 -07:00
|
|
|
|
|
|
|
|
|
/* Convert to and from NXM. */
|
|
|
|
|
ofpbuf_init(&nxm, 0);
|
2012-08-07 15:28:18 -07:00
|
|
|
|
nxm_match_len = nx_put_match(&nxm, &match, htonll(0), htonll(0));
|
2015-03-02 17:29:44 -08:00
|
|
|
|
nxm_s = nx_match_to_string(nxm.data, nxm_match_len);
|
ofproto: Add pipeline fields support for OF 1.5 packet-out
This patch decodes pipeline fields from a packet-out message, and populates
the pipeline fields into datapath. Error OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY
is returned if the match field of a packet-out messages contains any
non pipeline fields. Currently, the supported pipeline fields
are as following.
* metadata fields:
- in_port, in_port_oxm
* tunnel fields:
- tun_id, tun_src, tun_dst, tun_ipv6_src, tun_ipv6_dst
- tun_gbp_id, tun_gpb_flags, tun_flags
- tun_metadata0 - tun_metadata63
* register fields:
- metadata
- reg0 - reg-15, xreg0 - xreg7, xxreg0 - xxreg3
Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2017-05-15 10:04:57 -07:00
|
|
|
|
error = nx_pull_match(&nxm, nxm_match_len, &nxm_match, NULL, NULL, false,
|
|
|
|
|
NULL, NULL);
|
2012-07-19 22:17:10 -07:00
|
|
|
|
printf("NXM: %s -> ", nxm_s);
|
|
|
|
|
if (error) {
|
|
|
|
|
printf("%s\n", ofperr_to_string(error));
|
|
|
|
|
} else {
|
|
|
|
|
printf("%04"PRIx16"/%04"PRIx16"\n",
|
2017-03-01 17:47:59 -05:00
|
|
|
|
ntohs(nxm_match.flow.vlans[0].tci),
|
|
|
|
|
ntohs(nxm_match.wc.masks.vlans[0].tci));
|
2012-07-19 22:17:10 -07:00
|
|
|
|
}
|
|
|
|
|
free(nxm_s);
|
|
|
|
|
ofpbuf_uninit(&nxm);
|
|
|
|
|
|
2012-07-23 11:36:46 +09:00
|
|
|
|
/* Convert to and from OXM. */
|
|
|
|
|
ofpbuf_init(&nxm, 0);
|
2014-05-09 18:18:17 -07:00
|
|
|
|
nxm_match_len = oxm_put_match(&nxm, &match, OFP12_VERSION);
|
2013-07-22 15:47:19 -07:00
|
|
|
|
nxm_s = oxm_match_to_string(&nxm, nxm_match_len);
|
ofproto: Add pipeline fields support for OF 1.5 packet-out
This patch decodes pipeline fields from a packet-out message, and populates
the pipeline fields into datapath. Error OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY
is returned if the match field of a packet-out messages contains any
non pipeline fields. Currently, the supported pipeline fields
are as following.
* metadata fields:
- in_port, in_port_oxm
* tunnel fields:
- tun_id, tun_src, tun_dst, tun_ipv6_src, tun_ipv6_dst
- tun_gbp_id, tun_gpb_flags, tun_flags
- tun_metadata0 - tun_metadata63
* register fields:
- metadata
- reg0 - reg-15, xreg0 - xreg7, xxreg0 - xxreg3
Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2017-05-15 10:04:57 -07:00
|
|
|
|
error = oxm_pull_match(&nxm, false, NULL, NULL, &nxm_match);
|
2012-07-23 11:36:46 +09:00
|
|
|
|
printf("OXM: %s -> ", nxm_s);
|
|
|
|
|
if (error) {
|
|
|
|
|
printf("%s\n", ofperr_to_string(error));
|
|
|
|
|
} else {
|
2017-03-01 17:47:59 -05:00
|
|
|
|
uint16_t vid = ntohs(nxm_match.flow.vlans[0].tci) &
|
2012-07-23 11:36:46 +09:00
|
|
|
|
(VLAN_VID_MASK | VLAN_CFI);
|
2017-03-01 17:47:59 -05:00
|
|
|
|
uint16_t mask = ntohs(nxm_match.wc.masks.vlans[0].tci) &
|
2012-07-23 11:36:46 +09:00
|
|
|
|
(VLAN_VID_MASK | VLAN_CFI);
|
|
|
|
|
|
|
|
|
|
printf("%04"PRIx16"/%04"PRIx16",", vid, mask);
|
2017-03-01 17:47:59 -05:00
|
|
|
|
if (vid && vlan_tci_to_pcp(nxm_match.wc.masks.vlans[0].tci)) {
|
2017-03-17 13:38:55 -07:00
|
|
|
|
printf("%02d\n", vlan_tci_to_pcp(nxm_match.flow.vlans[0].tci));
|
2012-07-23 11:36:46 +09:00
|
|
|
|
} else {
|
|
|
|
|
printf("--\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(nxm_s);
|
|
|
|
|
ofpbuf_uninit(&nxm);
|
|
|
|
|
|
2012-07-19 22:17:10 -07:00
|
|
|
|
/* Convert to and from OpenFlow 1.0. */
|
2012-08-07 15:28:18 -07:00
|
|
|
|
ofputil_match_to_ofp10_match(&match, &of10_raw);
|
|
|
|
|
ofputil_match_from_ofp10_match(&of10_raw, &of10_match);
|
2012-07-19 22:17:10 -07:00
|
|
|
|
printf("OF1.0: %04"PRIx16"/%d,%02"PRIx8"/%d -> %04"PRIx16"/%04"PRIx16"\n",
|
2012-08-07 15:28:18 -07:00
|
|
|
|
ntohs(of10_raw.dl_vlan),
|
|
|
|
|
(of10_raw.wildcards & htonl(OFPFW10_DL_VLAN)) != 0,
|
|
|
|
|
of10_raw.dl_vlan_pcp,
|
|
|
|
|
(of10_raw.wildcards & htonl(OFPFW10_DL_VLAN_PCP)) != 0,
|
2017-03-01 17:47:59 -05:00
|
|
|
|
ntohs(of10_match.flow.vlans[0].tci),
|
|
|
|
|
ntohs(of10_match.wc.masks.vlans[0].tci));
|
2012-07-19 22:17:10 -07:00
|
|
|
|
|
|
|
|
|
/* Convert to and from OpenFlow 1.1. */
|
2012-08-07 15:28:18 -07:00
|
|
|
|
ofputil_match_to_ofp11_match(&match, &of11_raw);
|
|
|
|
|
ofputil_match_from_ofp11_match(&of11_raw, &of11_match);
|
2012-07-19 22:17:10 -07:00
|
|
|
|
printf("OF1.1: %04"PRIx16"/%d,%02"PRIx8"/%d -> %04"PRIx16"/%04"PRIx16"\n",
|
2012-08-07 15:28:18 -07:00
|
|
|
|
ntohs(of11_raw.dl_vlan),
|
|
|
|
|
(of11_raw.wildcards & htonl(OFPFW11_DL_VLAN)) != 0,
|
|
|
|
|
of11_raw.dl_vlan_pcp,
|
|
|
|
|
(of11_raw.wildcards & htonl(OFPFW11_DL_VLAN_PCP)) != 0,
|
2017-03-01 17:47:59 -05:00
|
|
|
|
ntohs(of11_match.flow.vlans[0].tci),
|
|
|
|
|
ntohs(of11_match.wc.masks.vlans[0].tci));
|
2012-07-19 22:17:10 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-03-26 13:46:35 -07:00
|
|
|
|
/* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow
|
|
|
|
|
* version. */
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_print_error(struct ovs_cmdl_context *ctx)
|
2012-03-26 13:46:35 -07:00
|
|
|
|
{
|
|
|
|
|
enum ofperr error;
|
|
|
|
|
int version;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
error = ofperr_from_name(ctx->argv[1]);
|
2012-03-26 13:46:35 -07:00
|
|
|
|
if (!error) {
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ovs_fatal(0, "unknown error \"%s\"", ctx->argv[1]);
|
2012-03-26 13:46:35 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (version = 0; version <= UINT8_MAX; version++) {
|
2012-08-01 16:01:49 +09:00
|
|
|
|
const char *name = ofperr_domain_get_name(version);
|
2013-06-24 13:49:40 -07:00
|
|
|
|
if (name) {
|
|
|
|
|
int vendor = ofperr_get_vendor(error, version);
|
|
|
|
|
int type = ofperr_get_type(error, version);
|
|
|
|
|
int code = ofperr_get_code(error, version);
|
|
|
|
|
|
|
|
|
|
if (vendor != -1 || type != -1 || code != -1) {
|
|
|
|
|
printf("%s: vendor %#x, type %d, code %d\n",
|
|
|
|
|
name, vendor, type, code);
|
|
|
|
|
}
|
2012-03-26 13:46:35 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-30 14:18:03 -08:00
|
|
|
|
/* "encode-error-reply ENUM REQUEST": Encodes an error reply to REQUEST for the
|
|
|
|
|
* error named ENUM and prints the error reply in hex. */
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_encode_error_reply(struct ovs_cmdl_context *ctx)
|
2012-11-30 14:18:03 -08:00
|
|
|
|
{
|
|
|
|
|
const struct ofp_header *oh;
|
|
|
|
|
struct ofpbuf request, *reply;
|
|
|
|
|
enum ofperr error;
|
|
|
|
|
|
2015-03-17 10:35:26 -04:00
|
|
|
|
error = ofperr_from_name(ctx->argv[1]);
|
2012-11-30 14:18:03 -08:00
|
|
|
|
if (!error) {
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ovs_fatal(0, "unknown error \"%s\"", ctx->argv[1]);
|
2012-11-30 14:18:03 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ofpbuf_init(&request, 0);
|
2015-03-17 10:35:26 -04:00
|
|
|
|
if (ofpbuf_put_hex(&request, ctx->argv[2], NULL)[0] != '\0') {
|
2012-11-30 14:18:03 -08:00
|
|
|
|
ovs_fatal(0, "Trailing garbage in hex data");
|
|
|
|
|
}
|
2015-03-02 17:29:44 -08:00
|
|
|
|
if (request.size < sizeof(struct ofp_header)) {
|
2012-11-30 14:18:03 -08:00
|
|
|
|
ovs_fatal(0, "Request too short");
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 17:29:44 -08:00
|
|
|
|
oh = request.data;
|
|
|
|
|
if (request.size != ntohs(oh->length)) {
|
2012-11-30 14:18:03 -08:00
|
|
|
|
ovs_fatal(0, "Request size inconsistent");
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 17:29:44 -08:00
|
|
|
|
reply = ofperr_encode_reply(error, request.data);
|
2012-11-30 14:18:03 -08:00
|
|
|
|
ofpbuf_uninit(&request);
|
|
|
|
|
|
2015-03-02 17:29:44 -08:00
|
|
|
|
ovs_hex_dump(stdout, reply->data, reply->size, 0, false);
|
2012-11-30 14:18:03 -08:00
|
|
|
|
ofpbuf_delete(reply);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-14 14:40:12 -08:00
|
|
|
|
/* Usage:
|
|
|
|
|
* ofp-print HEXSTRING [VERBOSITY]
|
|
|
|
|
* ofp-print - [VERBOSITY] < HEXSTRING_FILE
|
|
|
|
|
* ofp-print --raw - [VERBOSITY] < RAW_FILE
|
2014-06-18 11:12:36 -07:00
|
|
|
|
*
|
2018-02-14 14:40:12 -08:00
|
|
|
|
* Converts the hex digits in HEXSTRING into binary data, interpreting them as
|
|
|
|
|
* an OpenFlow message, and prints the OpenFlow message on stdout, at VERBOSITY
|
|
|
|
|
* (level 2 by default). With -, hex data is read from HEXSTRING_FILE, and
|
|
|
|
|
* with --raw -, raw binary data is read from RAW_FILE. */
|
2011-01-12 13:57:53 -08:00
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_ofp_print(struct ovs_cmdl_context *ctx)
|
2011-01-12 13:57:53 -08:00
|
|
|
|
{
|
2018-02-27 17:34:14 -08:00
|
|
|
|
int verbosity_ = ctx->argc > 2 ? atoi(ctx->argv[2]) : 2;
|
2014-06-18 11:12:36 -07:00
|
|
|
|
|
2018-02-14 14:40:12 -08:00
|
|
|
|
struct ofpbuf packet;
|
|
|
|
|
ofpbuf_init(&packet, 0);
|
2014-06-18 11:12:36 -07:00
|
|
|
|
|
2018-02-14 14:40:12 -08:00
|
|
|
|
char *buffer = NULL;
|
|
|
|
|
if (!strcmp(ctx->argv[1], "-")) {
|
|
|
|
|
if (raw) {
|
|
|
|
|
for (;;) {
|
|
|
|
|
int c = getchar();
|
|
|
|
|
if (c == EOF) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
ofpbuf_put(&packet, &c, 1);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
struct ds line = DS_EMPTY_INITIALIZER;
|
|
|
|
|
if (ds_get_line(&line, stdin)) {
|
|
|
|
|
VLOG_FATAL("Failed to read stdin");
|
|
|
|
|
}
|
|
|
|
|
buffer = ds_steal_cstr(&line);
|
2014-06-18 11:12:36 -07:00
|
|
|
|
}
|
2018-02-14 14:40:12 -08:00
|
|
|
|
} else {
|
|
|
|
|
buffer = xstrdup(ctx->argv[1]);
|
2014-06-18 11:12:36 -07:00
|
|
|
|
}
|
2018-02-14 14:40:12 -08:00
|
|
|
|
if (buffer && ofpbuf_put_hex(&packet, buffer, NULL)[0] != '\0') {
|
2011-01-12 13:57:53 -08:00
|
|
|
|
ovs_fatal(0, "trailing garbage following hex bytes");
|
|
|
|
|
}
|
2018-02-14 14:40:12 -08:00
|
|
|
|
free(buffer);
|
2018-02-27 17:34:14 -08:00
|
|
|
|
ofp_print(stdout, packet.data, packet.size, NULL, NULL, verbosity_);
|
2011-01-12 13:57:53 -08:00
|
|
|
|
ofpbuf_uninit(&packet);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-09 10:00:22 -08:00
|
|
|
|
/* "encode-hello BITMAP...": Encodes each BITMAP as an OpenFlow hello message
|
|
|
|
|
* and dumps each message in hex. */
|
|
|
|
|
static void
|
2015-03-17 10:35:26 -04:00
|
|
|
|
ofctl_encode_hello(struct ovs_cmdl_context *ctx)
|
2012-11-09 10:00:22 -08:00
|
|
|
|
{
|
2015-03-17 10:35:26 -04:00
|
|
|
|
uint32_t bitmap = strtol(ctx->argv[1], NULL, 0);
|
2012-11-09 10:00:22 -08:00
|
|
|
|
struct ofpbuf *hello;
|
|
|
|
|
|
|
|
|
|
hello = ofputil_encode_hello(bitmap);
|
2015-03-02 17:29:44 -08:00
|
|
|
|
ovs_hex_dump(stdout, hello->data, hello->size, 0, false);
|
Support accepting and displaying table names in OVS tools.
OpenFlow has little-known support for naming tables. Open vSwitch has
supported table names for ages, but it has never used or displayed them
outside of commands dedicated to table manipulation. This commit adds
support for table names in ovs-ofctl. When a table has a name, it displays
that name in flows and actions, so that, for example, the following:
table=1, arp, actions=resubmit(,2)
might become:
table=ingress_acl, arp, actions=resubmit(,mac_learning)
given appropriately named tables.
For backward compatibility, only interactive ovs-ofctl commands by default
display table names; to display them in scripts, use the new --names
option.
This feature was inspired by a talk that Kei Nohguchi presented at Open
vSwitch 2017 Fall Conference.
CC: Kei Nohguchi <kei@nohguchi.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
2018-01-05 16:59:13 -08:00
|
|
|
|
ofp_print(stdout, hello->data, hello->size, NULL, NULL, verbosity);
|
2012-11-09 10:00:22 -08:00
|
|
|
|
ofpbuf_delete(hello);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-13 14:53:01 -07:00
|
|
|
|
static void
|
|
|
|
|
ofctl_parse_key_value(struct ovs_cmdl_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 1; i < ctx->argc; i++) {
|
|
|
|
|
char *s = ctx->argv[i];
|
|
|
|
|
char *key, *value;
|
|
|
|
|
int j = 0;
|
|
|
|
|
while (ofputil_parse_key_value(&s, &key, &value)) {
|
|
|
|
|
if (j++) {
|
|
|
|
|
fputs(", ", stdout);
|
|
|
|
|
}
|
|
|
|
|
fputs(key, stdout);
|
|
|
|
|
if (value[0]) {
|
|
|
|
|
printf("=%s", value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
putchar('\n');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-18 14:39:50 -08:00
|
|
|
|
/* "compose-packet [--pcap] FLOW [L7]": Converts the OpenFlow flow
|
|
|
|
|
* specification FLOW to a packet with flow_compose() and prints the hex bytes
|
|
|
|
|
* in the packet on stdout. Also verifies that the flow extracted from that
|
|
|
|
|
* packet matches the original FLOW.
|
|
|
|
|
*
|
|
|
|
|
* With --pcap, prints the packet to stdout instead as a pcap file, so that you
|
2018-01-27 09:18:41 -08:00
|
|
|
|
* can do something like "ovs-ofctl --pcap compose-packet udp | tcpdump -vvvv
|
|
|
|
|
* -r-" to use another tool to dump the packet contents.
|
2018-01-18 14:39:50 -08:00
|
|
|
|
*
|
|
|
|
|
* If L7 is specified, draws the L7 payload data from it, otherwise defaults to
|
|
|
|
|
* 64 bytes of payload. */
|
|
|
|
|
static void
|
|
|
|
|
ofctl_compose_packet(struct ovs_cmdl_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
if (print_pcap && isatty(STDOUT_FILENO)) {
|
|
|
|
|
ovs_fatal(1, "not writing pcap data to stdout; redirect to a file "
|
|
|
|
|
"or pipe to tcpdump instead");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct flow flow1;
|
|
|
|
|
char *error = parse_ofp_exact_flow(&flow1, NULL, NULL, ctx->argv[1], NULL);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovs_fatal(0, "%s", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct dp_packet p;
|
|
|
|
|
memset(&p, 0, sizeof p);
|
|
|
|
|
dp_packet_init(&p, 0);
|
|
|
|
|
|
|
|
|
|
void *l7 = NULL;
|
|
|
|
|
size_t l7_len = 64;
|
|
|
|
|
if (ctx->argc > 2) {
|
|
|
|
|
struct dp_packet payload;
|
|
|
|
|
memset(&payload, 0, sizeof payload);
|
|
|
|
|
dp_packet_init(&payload, 0);
|
|
|
|
|
if (dp_packet_put_hex(&payload, ctx->argv[2], NULL)[0] != '\0') {
|
|
|
|
|
ovs_fatal(0, "%s: trailing garbage in packet data", ctx->argv[2]);
|
|
|
|
|
}
|
|
|
|
|
l7_len = dp_packet_size(&payload);
|
|
|
|
|
l7 = dp_packet_steal_data(&payload);
|
|
|
|
|
}
|
|
|
|
|
flow_compose(&p, &flow1, l7, l7_len);
|
|
|
|
|
free(l7);
|
|
|
|
|
|
|
|
|
|
if (print_pcap) {
|
2018-10-05 12:52:40 -04:00
|
|
|
|
struct pcap_file *p_file = ovs_pcap_stdout();
|
|
|
|
|
ovs_pcap_write_header(p_file);
|
|
|
|
|
ovs_pcap_write(p_file, &p);
|
|
|
|
|
ovs_pcap_close(p_file);
|
2018-01-18 14:39:50 -08:00
|
|
|
|
} else {
|
|
|
|
|
ovs_hex_dump(stdout, dp_packet_data(&p), dp_packet_size(&p), 0, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct flow flow2;
|
|
|
|
|
flow_extract(&p, &flow2);
|
|
|
|
|
flow2.in_port.ofp_port = OFPP_ANY;
|
|
|
|
|
|
|
|
|
|
dp_packet_uninit(&p);
|
|
|
|
|
|
|
|
|
|
if (!flow_equal(&flow1, &flow2)) {
|
|
|
|
|
fprintf(stderr, "specified and extracted flows differ:\n");
|
|
|
|
|
fputs("specified: ", stderr);
|
|
|
|
|
flow_print(stderr, &flow1, NULL);
|
|
|
|
|
fputs("\nextracted: ", stderr);
|
|
|
|
|
flow_print(stderr, &flow2, NULL);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-10 13:40:45 -07:00
|
|
|
|
/* "parse-packet" reads an Ethernet packet from stdin and prints it out its
|
|
|
|
|
* extracted flow fields. */
|
|
|
|
|
static void
|
|
|
|
|
ofctl_parse_packet(struct ovs_cmdl_context *ctx OVS_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
char packet[65535];
|
|
|
|
|
ssize_t size = read(STDIN_FILENO, packet, sizeof packet);
|
|
|
|
|
if (size < 0) {
|
|
|
|
|
ovs_fatal(errno, "failed to read packet from stdin");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make a copy of the packet in allocated memory to better allow Valgrind
|
|
|
|
|
* and Address Sanitizer to catch out-of-range access. */
|
|
|
|
|
void *packet_copy = xmemdup(packet, size);
|
|
|
|
|
ofp_print_packet(stdout, packet_copy, size, 0);
|
|
|
|
|
free(packet_copy);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-16 12:01:55 -04:00
|
|
|
|
static const struct ovs_cmdl_command all_commands[] = {
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "show", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_show, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "monitor", "switch [misslen] [invalid_ttl] [watch:[...]]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 3, ofctl_monitor, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "snoop", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_snoop, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-desc", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_dump_desc, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-tables", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_dump_tables, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-table-features", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_dump_table_features, OVS_RO },
|
2015-07-02 20:35:44 -07:00
|
|
|
|
{ "dump-table-desc", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_dump_table_desc, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-flows", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_dump_flows, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-aggregate", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_dump_aggregate, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "queue-stats", "switch [port [queue]]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 3, ofctl_queue_stats, OVS_RO },
|
2016-01-18 16:00:05 -08:00
|
|
|
|
{ "queue-get-config", "switch [port [queue]]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 3, ofctl_queue_get_config, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "add-flow", "switch flow",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_add_flow, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "add-flows", "switch file",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_add_flows, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "mod-flows", "switch flow",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_mod_flows, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "del-flows", "switch [flow]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_del_flows, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "replace-flows", "switch file",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_replace_flows, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "diff-flows", "source1 source2",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_diff_flows, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "add-meter", "switch meter",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_add_meter, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "mod-meter", "switch meter",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_mod_meter, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "del-meter", "switch meter",
|
2018-06-29 12:02:28 -07:00
|
|
|
|
1, 2, ofctl_del_meters, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "del-meters", "switch",
|
2018-06-29 12:02:28 -07:00
|
|
|
|
1, 2, ofctl_del_meters, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-meter", "switch meter",
|
2018-06-29 12:02:28 -07:00
|
|
|
|
1, 2, ofctl_dump_meters, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-meters", "switch",
|
2018-06-29 12:02:28 -07:00
|
|
|
|
1, 2, ofctl_dump_meters, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "meter-stats", "switch [meter]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_meter_stats, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "meter-features", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_meter_features, OVS_RO },
|
2016-09-14 16:51:27 -07:00
|
|
|
|
{ "packet-out", "switch \"in_port=<port> packet=<hex data> actions=...\"",
|
|
|
|
|
2, INT_MAX, ofctl_packet_out, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-ports", "switch [port]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_dump_ports, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-ports-desc", "switch [port]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_dump_ports_desc, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "mod-port", "switch iface act",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
3, 3, ofctl_mod_port, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "mod-table", "switch mod",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
3, 3, ofctl_mod_table, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "get-frags", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_get_frags, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "set-frags", "switch frag_mode",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_set_frags, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "probe", "target",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_probe, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "ping", "target [n]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_ping, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "benchmark", "target n count",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
3, 3, ofctl_benchmark, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
|
ipfix: Add support for exporting ipfix statistics.
It is meaningful for user to check the stats of IPFIX.
Using IPFIX stats, user can know how much flows the system
can support. It is also can be used for performance check
of IPFIX.
IPFIX stats is added for per IPFIX exporter. If bridge IPFIX is
enabled on the bridge, the whole bridge will have one exporter.
For flow IPFIX, the system keeps per id (column in
Flow_Sample_Collector_Set) per exporter.
1) Add 'ovs-ofctl dump-ipfix-bridge SWITCH' to export IPFIX stats of
the bridge which enable bridge IPFIX. The output format:
NXST_IPFIX_BRIDGE reply (xid=0x2):
bridge ipfix: flows=0, current flows=0, sampled pkts=0, \
ipv4 ok=0, ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
2) Add 'ovs-ofctl dump-ipfix-flow SWITCH' to export IPFIX stats of
the bridge which enable flow IPFIX. The output format:
NXST_IPFIX_FLOW reply (xid=0x2): 2 ids
id 1: flows=4, current flows=4, sampled pkts=14, ipv4 ok=13, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
id 2: flows=0, current flows=0, sampled pkts=0, ipv4 ok=0, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
flows: the number of total flow records, including those exported.
current flows: the number of current flow records cached.
sampled pkts: Successfully sampled packet count.
ipv4 ok: successfully sampled IPv4 flow packet count.
ipv6 ok: Successfully sampled IPv6 flow packet count.
tx pkts: the count of IPFIX exported packets sent to the collector(s).
pkts errs: count of packets failed when sampling, maybe not supported or other error.
ipv4 errs: Count of IPV4 flow packet in the error packets.
ipv6 errs: Count of IPV6 flow packet in the error packets.
tx errs: the count of IPFIX exported packets failed when sending to the collector(s).
Signed-off-by: Benli Ye <daniely@vmware.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-13 14:44:09 -07:00
|
|
|
|
{ "dump-ipfix-bridge", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_dump_ipfix_bridge, OVS_RO },
|
ipfix: Add support for exporting ipfix statistics.
It is meaningful for user to check the stats of IPFIX.
Using IPFIX stats, user can know how much flows the system
can support. It is also can be used for performance check
of IPFIX.
IPFIX stats is added for per IPFIX exporter. If bridge IPFIX is
enabled on the bridge, the whole bridge will have one exporter.
For flow IPFIX, the system keeps per id (column in
Flow_Sample_Collector_Set) per exporter.
1) Add 'ovs-ofctl dump-ipfix-bridge SWITCH' to export IPFIX stats of
the bridge which enable bridge IPFIX. The output format:
NXST_IPFIX_BRIDGE reply (xid=0x2):
bridge ipfix: flows=0, current flows=0, sampled pkts=0, \
ipv4 ok=0, ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
2) Add 'ovs-ofctl dump-ipfix-flow SWITCH' to export IPFIX stats of
the bridge which enable flow IPFIX. The output format:
NXST_IPFIX_FLOW reply (xid=0x2): 2 ids
id 1: flows=4, current flows=4, sampled pkts=14, ipv4 ok=13, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
id 2: flows=0, current flows=0, sampled pkts=0, ipv4 ok=0, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
flows: the number of total flow records, including those exported.
current flows: the number of current flow records cached.
sampled pkts: Successfully sampled packet count.
ipv4 ok: successfully sampled IPv4 flow packet count.
ipv6 ok: Successfully sampled IPv6 flow packet count.
tx pkts: the count of IPFIX exported packets sent to the collector(s).
pkts errs: count of packets failed when sampling, maybe not supported or other error.
ipv4 errs: Count of IPV4 flow packet in the error packets.
ipv6 errs: Count of IPV6 flow packet in the error packets.
tx errs: the count of IPFIX exported packets failed when sending to the collector(s).
Signed-off-by: Benli Ye <daniely@vmware.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-13 14:44:09 -07:00
|
|
|
|
{ "dump-ipfix-flow", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_dump_ipfix_flow, OVS_RO },
|
ipfix: Add support for exporting ipfix statistics.
It is meaningful for user to check the stats of IPFIX.
Using IPFIX stats, user can know how much flows the system
can support. It is also can be used for performance check
of IPFIX.
IPFIX stats is added for per IPFIX exporter. If bridge IPFIX is
enabled on the bridge, the whole bridge will have one exporter.
For flow IPFIX, the system keeps per id (column in
Flow_Sample_Collector_Set) per exporter.
1) Add 'ovs-ofctl dump-ipfix-bridge SWITCH' to export IPFIX stats of
the bridge which enable bridge IPFIX. The output format:
NXST_IPFIX_BRIDGE reply (xid=0x2):
bridge ipfix: flows=0, current flows=0, sampled pkts=0, \
ipv4 ok=0, ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
2) Add 'ovs-ofctl dump-ipfix-flow SWITCH' to export IPFIX stats of
the bridge which enable flow IPFIX. The output format:
NXST_IPFIX_FLOW reply (xid=0x2): 2 ids
id 1: flows=4, current flows=4, sampled pkts=14, ipv4 ok=13, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
id 2: flows=0, current flows=0, sampled pkts=0, ipv4 ok=0, \
ipv6 ok=0, tx pkts=0
pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
flows: the number of total flow records, including those exported.
current flows: the number of current flow records cached.
sampled pkts: Successfully sampled packet count.
ipv4 ok: successfully sampled IPv4 flow packet count.
ipv6 ok: Successfully sampled IPv6 flow packet count.
tx pkts: the count of IPFIX exported packets sent to the collector(s).
pkts errs: count of packets failed when sampling, maybe not supported or other error.
ipv4 errs: Count of IPV4 flow packet in the error packets.
ipv6 errs: Count of IPV6 flow packet in the error packets.
tx errs: the count of IPFIX exported packets failed when sending to the collector(s).
Signed-off-by: Benli Ye <daniely@vmware.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-06-13 14:44:09 -07:00
|
|
|
|
|
2016-08-18 14:09:41 -07:00
|
|
|
|
{ "ct-flush-zone", "switch zone",
|
|
|
|
|
2, 2, ofctl_ct_flush_zone, OVS_RO },
|
|
|
|
|
|
2023-01-16 12:45:08 +01:00
|
|
|
|
{ "ct-flush", "switch [zone=N] [ct-orig-tuple [ct-reply-tuple]]",
|
|
|
|
|
1, 4, ofctl_ct_flush, OVS_RO },
|
|
|
|
|
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "ofp-parse", "file",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_ofp_parse, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "ofp-parse-pcap", "pcap",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, INT_MAX, ofctl_ofp_parse_pcap, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
|
|
|
|
|
{ "add-group", "switch group",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_add_group, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "add-groups", "switch file",
|
2021-05-06 11:14:07 +08:00
|
|
|
|
2, 2, ofctl_add_groups, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "mod-group", "switch group",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_mod_group, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "del-groups", "switch [group]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_del_groups, OVS_RW },
|
2014-11-13 11:53:29 +09:00
|
|
|
|
{ "insert-buckets", "switch [group]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_insert_bucket, OVS_RW },
|
2014-11-13 11:53:29 +09:00
|
|
|
|
{ "remove-buckets", "switch [group]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_remove_bucket, OVS_RW },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-groups", "switch [group]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_dump_group_desc, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-group-stats", "switch [group]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_dump_group_stats, OVS_RO },
|
2014-10-16 13:27:32 -07:00
|
|
|
|
{ "dump-group-features", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_dump_group_features, OVS_RO },
|
2016-07-29 16:52:04 -07:00
|
|
|
|
|
|
|
|
|
{ "bundle", "switch file",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_bundle, OVS_RW },
|
2016-07-29 16:52:04 -07:00
|
|
|
|
|
2015-12-16 02:47:50 +08:00
|
|
|
|
{ "add-tlv-map", "switch map",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
2, 2, ofctl_add_tlv_map, OVS_RO },
|
2015-12-16 02:47:50 +08:00
|
|
|
|
{ "del-tlv-map", "switch [map]",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 2, ofctl_del_tlv_map, OVS_RO },
|
2015-12-16 02:47:50 +08:00
|
|
|
|
{ "dump-tlv-map", "switch",
|
2016-08-15 18:47:29 +00:00
|
|
|
|
1, 1, ofctl_dump_tlv_map, OVS_RO },
|
|
|
|
|
{ "help", NULL, 0, INT_MAX, ofctl_help, OVS_RO },
|
|
|
|
|
{ "list-commands", NULL, 0, INT_MAX, ofctl_list_commands, OVS_RO },
|
2010-11-09 17:00:59 -08:00
|
|
|
|
|
|
|
|
|
/* Undocumented commands for testing. */
|
2016-08-15 18:47:29 +00:00
|
|
|
|
{ "parse-flow", NULL, 1, 1, ofctl_parse_flow, OVS_RW },
|
|
|
|
|
{ "parse-flows", NULL, 1, 1, ofctl_parse_flows, OVS_RW },
|
2019-04-30 15:07:07 -07:00
|
|
|
|
{ "parse-group", NULL, 1, 1, ofctl_parse_group, OVS_RW },
|
2016-08-15 18:47:29 +00:00
|
|
|
|
{ "parse-nx-match", NULL, 0, 0, ofctl_parse_nxm, OVS_RW },
|
|
|
|
|
{ "parse-nxm", NULL, 0, 0, ofctl_parse_nxm, OVS_RW },
|
|
|
|
|
{ "parse-oxm", NULL, 1, 1, ofctl_parse_oxm, OVS_RW },
|
|
|
|
|
{ "parse-actions", NULL, 1, 1, ofctl_parse_actions, OVS_RW },
|
|
|
|
|
{ "parse-instructions", NULL, 1, 1, ofctl_parse_instructions, OVS_RW },
|
|
|
|
|
{ "parse-ofp10-match", NULL, 0, 0, ofctl_parse_ofp10_match, OVS_RW },
|
|
|
|
|
{ "parse-ofp11-match", NULL, 0, 0, ofctl_parse_ofp11_match, OVS_RW },
|
|
|
|
|
{ "parse-pcap", NULL, 1, INT_MAX, ofctl_parse_pcap, OVS_RW },
|
|
|
|
|
{ "check-vlan", NULL, 2, 2, ofctl_check_vlan, OVS_RW },
|
|
|
|
|
{ "print-error", NULL, 1, 1, ofctl_print_error, OVS_RW },
|
|
|
|
|
{ "encode-error-reply", NULL, 2, 2, ofctl_encode_error_reply, OVS_RW },
|
|
|
|
|
{ "ofp-print", NULL, 1, 2, ofctl_ofp_print, OVS_RW },
|
|
|
|
|
{ "encode-hello", NULL, 1, 1, ofctl_encode_hello, OVS_RW },
|
|
|
|
|
{ "parse-key-value", NULL, 1, INT_MAX, ofctl_parse_key_value, OVS_RW },
|
2018-01-18 14:39:50 -08:00
|
|
|
|
{ "compose-packet", NULL, 1, 2, ofctl_compose_packet, OVS_RO },
|
2018-07-10 13:40:45 -07:00
|
|
|
|
{ "parse-packet", NULL, 0, 0, ofctl_parse_packet, OVS_RO },
|
2016-08-15 18:47:29 +00:00
|
|
|
|
|
|
|
|
|
{ NULL, NULL, 0, 0, NULL, OVS_RO },
|
2009-07-08 13:19:16 -07:00
|
|
|
|
};
|
2013-07-19 10:04:47 -07:00
|
|
|
|
|
2015-03-16 12:01:55 -04:00
|
|
|
|
static const struct ovs_cmdl_command *get_all_commands(void)
|
2013-07-19 10:04:47 -07:00
|
|
|
|
{
|
|
|
|
|
return all_commands;
|
|
|
|
|
}
|