2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-23 14:57:06 +00:00

ovs-ofctl: Add NXM support.

This commit is contained in:
Ben Pfaff
2010-12-07 13:32:01 -08:00
parent 7fa9111326
commit 88ca35eed0
8 changed files with 458 additions and 147 deletions

View File

@@ -537,18 +537,24 @@ parse_reg_value(struct cls_rule *rule, int reg_idx, const char *value)
/* Convert 'string' (as described in the Flow Syntax section of the ovs-ofctl
* man page) into 'pf'. If 'actions' is specified, an action must be in
* 'string' and may be expanded or reallocated. */
void
parse_ofp_str(struct parsed_flow *pf, struct ofpbuf *actions, char *string)
static void
parse_ofp_str(struct flow_mod *fm, uint8_t *table_idx,
struct ofpbuf *actions, char *string)
{
char *save_ptr = NULL;
char *name;
cls_rule_init_catchall(&pf->rule, OFP_DEFAULT_PRIORITY);
pf->table_idx = 0xff;
pf->out_port = OFPP_NONE;
pf->idle_timeout = OFP_FLOW_PERMANENT;
pf->hard_timeout = OFP_FLOW_PERMANENT;
pf->cookie = 0;
if (table_idx) {
*table_idx = 0xff;
}
cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY);
fm->cookie = htonll(0);
fm->command = UINT16_MAX;
fm->idle_timeout = OFP_FLOW_PERMANENT;
fm->hard_timeout = OFP_FLOW_PERMANENT;
fm->buffer_id = UINT32_MAX;
fm->out_port = OFPP_NONE;
fm->flags = 0;
if (actions) {
char *act_str = strstr(string, "action");
if (!act_str) {
@@ -564,15 +570,20 @@ parse_ofp_str(struct parsed_flow *pf, struct ofpbuf *actions, char *string)
act_str++;
str_to_action(act_str, actions);
fm->actions = actions->data;
fm->n_actions = actions->size / sizeof(union ofp_action);
} else {
fm->actions = NULL;
fm->n_actions = 0;
}
for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name;
name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
const struct protocol *p;
if (parse_protocol(name, &p)) {
cls_rule_set_dl_type(&pf->rule, htons(p->dl_type));
cls_rule_set_dl_type(&fm->cr, htons(p->dl_type));
if (p->nw_proto) {
cls_rule_set_nw_proto(&pf->rule, p->nw_proto);
cls_rule_set_nw_proto(&fm->cr, p->nw_proto);
}
} else {
const struct field *f;
@@ -583,43 +594,43 @@ parse_ofp_str(struct parsed_flow *pf, struct ofpbuf *actions, char *string)
ovs_fatal(0, "field %s missing value", name);
}
if (!strcmp(name, "table")) {
pf->table_idx = atoi(value);
if (table_idx && !strcmp(name, "table")) {
*table_idx = atoi(value);
} else if (!strcmp(name, "out_port")) {
pf->out_port = atoi(value);
fm->out_port = atoi(value);
} else if (!strcmp(name, "priority")) {
pf->rule.priority = atoi(value);
fm->cr.priority = atoi(value);
} else if (!strcmp(name, "idle_timeout")) {
pf->idle_timeout = atoi(value);
fm->idle_timeout = atoi(value);
} else if (!strcmp(name, "hard_timeout")) {
pf->hard_timeout = atoi(value);
fm->hard_timeout = atoi(value);
} else if (!strcmp(name, "cookie")) {
pf->cookie = str_to_u64(value);
fm->cookie = htonll(str_to_u64(value));
} else if (parse_field_name(name, &f)) {
if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
if (f->wildcard) {
pf->rule.wc.wildcards |= f->wildcard;
cls_rule_zero_wildcarded_fields(&pf->rule);
fm->cr.wc.wildcards |= f->wildcard;
cls_rule_zero_wildcarded_fields(&fm->cr);
} else if (f->index == F_NW_SRC) {
cls_rule_set_nw_src_masked(&pf->rule, 0, 0);
cls_rule_set_nw_src_masked(&fm->cr, 0, 0);
} else if (f->index == F_NW_DST) {
cls_rule_set_nw_dst_masked(&pf->rule, 0, 0);
cls_rule_set_nw_dst_masked(&fm->cr, 0, 0);
} else if (f->index == F_DL_VLAN) {
cls_rule_set_any_vid(&pf->rule);
cls_rule_set_any_vid(&fm->cr);
} else if (f->index == F_DL_VLAN_PCP) {
cls_rule_set_any_pcp(&pf->rule);
cls_rule_set_any_pcp(&fm->cr);
} else {
NOT_REACHED();
}
} else {
parse_field_value(&pf->rule, f->index, value);
parse_field_value(&fm->cr, f->index, value);
}
} else if (!strncmp(name, "reg", 3) && isdigit(name[3])) {
unsigned int reg_idx = atoi(name + 3);
if (reg_idx >= FLOW_N_REGS) {
ovs_fatal(0, "only %d registers supported", FLOW_N_REGS);
}
parse_reg_value(&pf->rule, reg_idx, value);
parse_reg_value(&fm->cr, reg_idx, value);
} else {
ovs_fatal(0, "unknown keyword %s", name);
}
@@ -627,42 +638,48 @@ parse_ofp_str(struct parsed_flow *pf, struct ofpbuf *actions, char *string)
}
}
/* Parses 'string' as an OFPT_FLOW_MOD with command 'command' (one of OFPFC_*)
* and returns an ofpbuf that contains it. */
struct ofpbuf *
parse_ofp_flow_mod_str(char *string, uint16_t command)
/* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command'
* (one of OFPFC_*) and appends the parsed OpenFlow message to 'packets'.
* '*cur_format' should initially contain the flow format currently configured
* on the connection; this function will add a message to change the flow
* format and update '*cur_format', if this is necessary to add the parsed
* flow. */
void
parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format,
char *string, uint16_t command)
{
struct parsed_flow pf;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
enum nx_flow_format min_format, next_format;
struct ofpbuf actions;
struct ofpbuf *ofm;
struct flow_mod fm;
/* parse_ofp_str() will expand and reallocate the data in 'buffer', so we
* can't keep pointers to across the parse_ofp_str() call. */
make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
parse_ofp_str(&pf, buffer, string);
ofpbuf_init(&actions, 64);
parse_ofp_str(&fm, NULL, &actions, string);
fm.command = command;
ofm = buffer->data;
ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &ofm->match);
ofm->command = htons(command);
ofm->cookie = htonll(pf.cookie);
ofm->idle_timeout = htons(pf.idle_timeout);
ofm->hard_timeout = htons(pf.hard_timeout);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->out_port = htons(pf.out_port);
ofm->priority = htons(pf.rule.priority);
update_openflow_length(buffer);
return buffer;
min_format = ofputil_min_flow_format(&fm.cr, true, fm.cookie);
next_format = MAX(*cur_format, min_format);
if (next_format != *cur_format) {
struct ofpbuf *sff = ofputil_make_set_flow_format(next_format);
list_push_back(packets, &sff->list_node);
*cur_format = next_format;
}
/* Parses an OFPT_FLOW_MOD with subtype OFPFC_ADD from 'stream' and returns an
* ofpbuf that contains it. Returns a null pointer if end-of-file is reached
* before reading a flow. */
struct ofpbuf *
parse_ofp_add_flow_file(FILE *stream)
ofm = ofputil_encode_flow_mod(&fm, *cur_format);
list_push_back(packets, &ofm->list_node);
ofpbuf_uninit(&actions);
}
/* Similar to parse_ofp_flow_mod_str(), except that the string is read from
* 'stream' and the command is always OFPFC_ADD. Returns false if end-of-file
* is reached before reading a flow, otherwise true. */
bool
parse_ofp_add_flow_file(struct list *packets, enum nx_flow_format *cur,
FILE *stream)
{
struct ofpbuf *b = NULL;
struct ds s = DS_EMPTY_INITIALIZER;
bool ok = false;
while (!ds_get_line(&s, stream)) {
char *line = ds_cstr(&s);
@@ -679,10 +696,26 @@ parse_ofp_add_flow_file(FILE *stream)
continue;
}
b = parse_ofp_flow_mod_str(line, OFPFC_ADD);
parse_ofp_flow_mod_str(packets, cur, line, OFPFC_ADD);
ok = true;
break;
}
ds_destroy(&s);
return b;
return ok;
}
void
parse_ofp_flow_stats_request_str(struct flow_stats_request *fsr,
bool aggregate, char *string)
{
struct flow_mod fm;
uint8_t table_id;
parse_ofp_str(&fm, &table_id, NULL, string);
fsr->aggregate = aggregate;
fsr->match = fm.cr;
fsr->out_port = fm.out_port;
fsr->table_id = table_id;
}

View File

@@ -19,22 +19,22 @@
#ifndef OFP_PARSE_H
#define OFP_PARSE_H 1
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "openflow/nicira-ext.h"
#include "classifier.h"
struct flow_mod;
struct flow_stats_request;
struct list;
struct ofpbuf;
struct parsed_flow {
struct cls_rule rule;
uint8_t table_idx;
uint16_t out_port;
uint16_t idle_timeout;
uint16_t hard_timeout;
uint64_t cookie;
};
void parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur,
char *string, uint16_t command);
bool parse_ofp_add_flow_file(struct list *packets, enum nx_flow_format *cur,
FILE *);
void parse_ofp_str(struct parsed_flow *, struct ofpbuf *actions, char *string);
struct ofpbuf *parse_ofp_flow_mod_str(char *string, uint16_t command);
struct ofpbuf *parse_ofp_add_flow_file(FILE *);
void parse_ofp_flow_stats_request_str(struct flow_stats_request *,
bool aggregate, char *string);
#endif /* ofp-parse.h */

View File

@@ -786,6 +786,91 @@ ofputil_flow_format_to_string(enum nx_flow_format flow_format)
}
}
int
ofputil_flow_format_from_string(const char *s)
{
return (!strcmp(s, "openflow10") ? NXFF_OPENFLOW10
: !strcmp(s, "tun_id_from_cookie") ? NXFF_TUN_ID_FROM_COOKIE
: !strcmp(s, "nxm") ? NXFF_NXM
: -1);
}
static bool
regs_fully_wildcarded(const struct flow_wildcards *wc)
{
int i;
for (i = 0; i < FLOW_N_REGS; i++) {
if (wc->reg_masks[i] != 0) {
return false;
}
}
return true;
}
/* Returns the minimum nx_flow_format to use for sending 'rule' to a switch
* (e.g. to add or remove a flow). 'cookie_support' should be true if the
* command to be sent includes a flow cookie (as OFPT_FLOW_MOD does, for
* example) or false if the command does not (OFPST_FLOW and OFPST_AGGREGATE do
* not, for example). If 'cookie_support' is true, then 'cookie' should be the
* cookie to be sent; otherwise its value is ignored.
*
* The "best" flow format is chosen on this basis:
*
* - It must be capable of expressing the rule. NXFF_OPENFLOW10 flows can't
* handle tunnel IDs. NXFF_TUN_ID_FROM_COOKIE flows can't handle registers
* or fixing the Ethernet multicast bit, and can't handle tunnel IDs that
* conflict with the high 32 bits of the cookie or commands that don't
* support cookies.
*
* - Otherwise, the chosen format should be as backward compatible as
* possible. (NXFF_OPENFLOW10 is more backward compatible than
* NXFF_TUN_ID_FROM_COOKIE, which is more backward compatible than
* NXFF_NXM.)
*/
enum nx_flow_format
ofputil_min_flow_format(const struct cls_rule *rule, bool cookie_support,
ovs_be64 cookie)
{
const struct flow_wildcards *wc = &rule->wc;
ovs_be32 cookie_hi = htonl(ntohll(cookie) >> 32);
if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)
|| !regs_fully_wildcarded(wc)
|| (!(wc->wildcards & FWW_TUN_ID)
&& (!cookie_support
|| (cookie_hi && cookie_hi != rule->flow.tun_id)))) {
return NXFF_NXM;
} else if (!(wc->wildcards & FWW_TUN_ID)) {
return NXFF_TUN_ID_FROM_COOKIE;
} else {
return NXFF_OPENFLOW10;
}
}
/* Returns an OpenFlow message that can be used to set the flow format to
* 'flow_format'. */
struct ofpbuf *
ofputil_make_set_flow_format(enum nx_flow_format flow_format)
{
struct ofpbuf *msg;
if (flow_format == NXFF_OPENFLOW10
|| flow_format == NXFF_TUN_ID_FROM_COOKIE) {
struct nxt_tun_id_cookie *tic;
tic = make_nxmsg(sizeof *tic, NXT_TUN_ID_FROM_COOKIE, &msg);
tic->set = flow_format == NXFF_TUN_ID_FROM_COOKIE;
} else {
struct nxt_set_flow_format *sff;
sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg);
sff->format = htonl(flow_format);
}
return msg;
}
/* Converts an OFPT_FLOW_MOD or NXT_FLOW_MOD message 'oh' into an abstract
* flow_mod in 'fm'. Returns 0 if successful, otherwise an OpenFlow error
* code.
@@ -901,7 +986,14 @@ ofputil_encode_flow_mod(const struct flow_mod *fm,
msg = ofpbuf_new(sizeof *ofm + actions_len);
ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
ofputil_cls_rule_to_match(&fm->cr, flow_format, &ofm->match);
if (flow_format != NXFF_TUN_ID_FROM_COOKIE
|| fm->cr.wc.wildcards & FWW_TUN_ID) {
ofm->cookie = fm->cookie;
} else {
uint32_t cookie_lo = ntohll(fm->cookie);
uint32_t cookie_hi = ntohl(fm->cr.flow.tun_id);
ofm->cookie = htonll(cookie_lo | ((uint64_t) cookie_hi << 32));
}
ofm->command = htons(fm->command);
ofm->idle_timeout = htons(fm->idle_timeout);
ofm->hard_timeout = htons(fm->hard_timeout);

View File

@@ -115,6 +115,12 @@ char *ofp_match_to_literal_string(const struct ofp_match *match);
/* Flow formats. */
bool ofputil_flow_format_is_valid(enum nx_flow_format);
const char *ofputil_flow_format_to_string(enum nx_flow_format);
int ofputil_flow_format_from_string(const char *);
enum nx_flow_format ofputil_min_flow_format(const struct cls_rule *,
bool cookie_support,
ovs_be64 cookie);
struct ofpbuf *ofputil_make_set_flow_format(enum nx_flow_format);
/* Flow format independent flow_mod. */
struct flow_mod {

View File

@@ -11,19 +11,68 @@ tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
tun_id=0x1234,cookie=0x5678,actions=flood
actions=drop
])
AT_CHECK([ovs-ofctl parse-flows flows.txt], [0], [stdout])
AT_CHECK([ovs-ofctl parse-flows flows.txt], [0], [stdout], [stderr])
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl
OFPT_FLOW_MOD: tcp,tp_src=123, ADD: actions=FLOOD
OFPT_FLOW_MOD: in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0, ADD: actions=drop
OFPT_FLOW_MOD: arp,nw_src=192.168.0.1, ADD: actions=drop_spoofed_arp,NORMAL
OFPT_FLOW_MOD: udp,dl_vlan_pcp=7, ADD: idle:5 actions=strip_vlan,output:0
OFPT_FLOW_MOD: tcp,nw_src=192.168.0.3,tp_dst=80, ADD: actions=set_queue:37,output:1
OFPT_FLOW_MOD: udp,nw_src=192.168.0.3,tp_dst=53, ADD: actions=pop_queue,output:1
OFPT_FLOW_MOD: ADD: cookie:0x123456789abcdef hard:10 pri:60000 actions=CONTROLLER:65535
OFPT_FLOW_MOD: ADD: actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
OFPT_FLOW_MOD: ADD: actions=drop
OFPT_FLOW_MOD: ADD tcp,tp_src=123 actions=FLOOD
OFPT_FLOW_MOD: ADD in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0 actions=drop
OFPT_FLOW_MOD: ADD arp,nw_src=192.168.0.1 actions=drop_spoofed_arp,NORMAL
OFPT_FLOW_MOD: ADD udp,dl_vlan_pcp=7 idle:5 actions=strip_vlan,output:0
OFPT_FLOW_MOD: ADD tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
OFPT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
OFPT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
NXT_TUN_ID_FROM_COOKIE: set=1
OFPT_FLOW_MOD: ADD cookie:0x123400005678 actions=FLOOD
OFPT_FLOW_MOD: ADD actions=drop
])
AT_CHECK([sed 's/.*|//' stderr], [0], [dnl
normalization changed ofp_match, details:
pre: wildcards= 0x3820f8 in_port=65534 dl_src=00:0a:e4:25:6b:b0 dl_dst=00:00:00:00:00:00 dl_vlan= 9 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
post: wildcards= 0x3ffff8 in_port=65534 dl_src=00:0a:e4:25:6b:b0 dl_dst=00:00:00:00:00:00 dl_vlan= 9 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
normalization changed ofp_match, details:
pre: wildcards= 0x3820ff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
post: wildcards= 0x3fffff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
normalization changed ofp_match, details:
pre: wildcards= 0x3820ff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
post: wildcards= 0x3fffff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
normalization changed ofp_match, details:
pre: wildcards= 0x3820ff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
post: wildcards= 0x3fffff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
normalization changed ofp_match, details:
pre: wildcards= 0x23820ff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
post: wildcards= 0x23fffff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
])
AT_CLEANUP
AT_SETUP([ovs-ofctl -F nxm parse-flows])
AT_DATA([flows.txt], [
# comment
tcp,tp_src=123,actions=flood
in_port=LOCAL dl_vlan=9 dl_src=00:0A:E4:25:6B:B0 actions=drop
arp,nw_src=192.168.0.1 actions=drop_spoofed_arp,NORMAL
udp dl_vlan_pcp=7 idle_timeout=5 actions=strip_vlan output:0
tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
tun_id=0x1234,cookie=0x5678,actions=flood
actions=drop
])
AT_CHECK([ovs-ofctl -F nxm parse-flows flows.txt], [0], [stdout])
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl
NXT_FLOW_MOD: ADD tcp,tp_src=123 actions=FLOOD
NXT_FLOW_MOD: ADD in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0 actions=drop
NXT_FLOW_MOD: ADD arp,nw_src=192.168.0.1 actions=drop_spoofed_arp,NORMAL
NXT_FLOW_MOD: ADD udp,dl_vlan_pcp=7 idle:5 actions=strip_vlan,output:0
NXT_FLOW_MOD: ADD tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
NXT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
NXT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
NXT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
NXT_FLOW_MOD: ADD tun_id=0x1234 cookie:0x5678 actions=FLOOD
NXT_FLOW_MOD: ADD actions=drop
])
AT_CLEANUP

View File

@@ -260,7 +260,7 @@ do_switching(struct switch_ *sw)
static void
read_flow_file(const char *name)
{
struct ofpbuf *b;
enum nx_flow_format flow_format;
FILE *stream;
stream = fopen(optarg, "r");
@@ -268,8 +268,9 @@ read_flow_file(const char *name)
ovs_fatal(errno, "%s: open", name);
}
while ((b = parse_ofp_add_flow_file(stream)) != NULL) {
list_push_back(&default_flows, &b->list_node);
flow_format = NXFF_OPENFLOW10;
while (parse_ofp_add_flow_file(&default_flows, &flow_format, stream)) {
continue;
}
fclose(stream);

View File

@@ -354,9 +354,10 @@ unavailable for other use, and specifying \fBtun_id\fR on
.RE
.IP
When \fBtun_id\fR is specified, \fBovs\-ofctl\fR will automatically
attempt to negotiate use of one of these extensions, preferring NXM.
If the switch does not support either extension, then \fBovs\-ofctl\fR
will report a fatal error.
attempt to negotiate use of one of these extensions. It will use the
``tunnel ID from cookie'' extension if neither caveat applies and NXM
otherwise. If the switch does not support the needed extension, then
\fBovs\-ofctl\fR will report a fatal error.
.IP "\fBreg\fIidx\fB=\fIvalue\fR[\fB/\fImask\fR]"
Matches \fIvalue\fR either exactly or with optional \fImask\fR in
register number \fIidx\fR. The valid range of \fIidx\fR depends on
@@ -620,6 +621,37 @@ described in \fBFlow Syntax\fR, above.
\fB\-\-strict\fR
Uses strict matching when running flow modification commands.
.
.IP "\fB\-F \fIformat\fR"
.IQ "\fB\-\-flow\-format=\fIformat\fR"
\fBovs\-ofctl\fR supports the following flow formats, in order of
increasing capability:
.RS
.IP "\fBopenflow10\fR"
This is the standard OpenFlow 1.0 flow format. It should be supported
by all OpenFlow switches.
.
.IP "\fBtun_id_from_cookie\fR"
This Nicira extension to OpenFlow adds minimal and limited support for
\fBtun_id\fR, but it does not support any other Nicira flow
extensions. (This flow format is deprecated.)
.
.IP "\fBnxm\fR (Nicira Extended Match)"
This Nicira extension to OpenFlow is flexible and extensible. It
supports all of the Nicira flow extensions, such as \fBtun_id\fR and
registers.
.RE
.IP
Usually, \fBovs\-ofctl\fR picks the correct format automatically. For
commands that modify the flow table, \fBovs\-ofctl\fR by default uses
the most widely supported flow format that supports the flows being
added. For commands that query the flow table, \fBovs\-ofctl\fR by
default queries and uses the most advanced format supported by the
switch.
.IP
This option, where \fIformat\fR is one of the formats listed in the
above table, overrides \fBovs\-ofctl\fR's default choice of flow
format. If a command cannot work as requested using the requested
flow format, \fBovs\-ofctl\fR will report a fatal error.
.SS "Public Key Infrastructure Options"
.so lib/ssl.man
.so lib/vlog.man

View File

@@ -51,9 +51,13 @@
VLOG_DEFINE_THIS_MODULE(ofctl);
/* Use strict matching for flow mod commands? */
/* --strict: Use strict matching for flow mod commands? */
static bool strict;
/* -F, --flow-format: Flow format to use. Either one of NXFF_* to force a
* particular flow format or -1 to let ovs-ofctl choose intelligently. */
static int preferred_flow_format = -1;
static const struct command all_commands[];
static void usage(void) NO_RETURN;
@@ -79,6 +83,7 @@ parse_options(int argc, char *argv[])
static struct option long_options[] = {
{"timeout", required_argument, 0, 't'},
{"strict", no_argument, 0, OPT_STRICT},
{"flow-format", required_argument, 0, 'F'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
VLOG_LONG_OPTIONS,
@@ -107,6 +112,13 @@ parse_options(int argc, char *argv[])
}
break;
case 'F':
preferred_flow_format = ofputil_flow_format_from_string(optarg);
if (preferred_flow_format < 0) {
ovs_fatal(0, "unknown flow format `%s'", optarg);
}
break;
case 'h':
usage();
@@ -163,6 +175,7 @@ usage(void)
vlog_usage();
printf("\nOther options:\n"
" --strict use strict match for flow commands\n"
" -F, --flow-format=FORMAT force particular flow format\n"
" -t, --timeout=SECS give up after SECS seconds\n"
" -h, --help display this help message\n"
" -V, --version display version information\n");
@@ -341,12 +354,15 @@ dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
* occurs, and waits for it to succeed or fail. If an error does occur, prints
* it and exits with an error. */
static void
dump_noreply_transaction(struct vconn *vconn, struct ofpbuf *request)
transact_multiple_noreply(struct vconn *vconn, struct list *requests)
{
struct ofpbuf *reply;
struct ofpbuf *request, *reply;
LIST_FOR_EACH (request, list_node, requests) {
update_openflow_length(request);
run(vconn_transact_noreply(vconn, request, &reply),
}
run(vconn_transact_multiple_noreply(vconn, requests, &reply),
"talking to %s", vconn_get_name(vconn));
if (reply) {
ofp_print(stderr, reply->data, reply->size, 2);
@@ -355,6 +371,19 @@ dump_noreply_transaction(struct vconn *vconn, struct ofpbuf *request)
ofpbuf_delete(reply);
}
/* 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
* it and exits with an error. */
static void
transact_noreply(struct vconn *vconn, struct ofpbuf *request)
{
struct list requests;
list_init(&requests);
list_push_back(&requests, &request->list_node);
transact_multiple_noreply(vconn, &requests);
}
static void
do_show(int argc OVS_UNUSED, char *argv[])
{
@@ -467,38 +496,97 @@ str_to_port_no(const char *vconn_name, const char *port_name)
}
}
static bool
try_set_flow_format(struct vconn *vconn, enum nx_flow_format flow_format)
{
struct ofpbuf *sff, *reply;
sff = ofputil_make_set_flow_format(flow_format);
run(vconn_transact_noreply(vconn, sff, &reply),
"talking to %s", vconn_get_name(vconn));
if (reply) {
char *s = ofp_to_string(reply->data, reply->size, 2);
VLOG_DBG("%s: failed to set flow format %s, controller replied: %s",
vconn_get_name(vconn),
ofputil_flow_format_to_string(flow_format),
s);
free(s);
ofpbuf_delete(reply);
return false;
}
return true;
}
static void
set_flow_format(struct vconn *vconn, enum nx_flow_format flow_format)
{
struct ofpbuf *sff = ofputil_make_set_flow_format(flow_format);
transact_noreply(vconn, sff);
VLOG_DBG("%s: using user-specified flow format %s",
vconn_get_name(vconn),
ofputil_flow_format_to_string(flow_format));
}
static enum nx_flow_format
negotiate_highest_flow_format(struct vconn *vconn, const struct cls_rule *rule,
bool cookie_support, ovs_be64 cookie)
{
int flow_format;
if (preferred_flow_format != -1) {
enum nx_flow_format min_format;
min_format = ofputil_min_flow_format(rule, cookie_support, cookie);
if (preferred_flow_format >= min_format) {
set_flow_format(vconn, preferred_flow_format);
return preferred_flow_format;
}
VLOG_WARN("%s: cannot use requested flow format %s for "
"specified flow", vconn_get_name(vconn),
ofputil_flow_format_to_string(min_format));
}
if (try_set_flow_format(vconn, NXFF_NXM)) {
flow_format = NXFF_NXM;
} else if (try_set_flow_format(vconn, NXFF_TUN_ID_FROM_COOKIE)) {
flow_format = NXFF_TUN_ID_FROM_COOKIE;
} else {
flow_format = NXFF_OPENFLOW10;
}
VLOG_DBG("%s: negotiated flow format %s", vconn_get_name(vconn),
ofputil_flow_format_to_string(flow_format));
return flow_format;
}
static void
do_dump_flows__(int argc, char *argv[], bool aggregate)
{
enum nx_flow_format flow_format;
struct flow_stats_request fsr;
struct ofpbuf *request;
struct vconn *vconn;
parse_ofp_flow_stats_request_str(&fsr, aggregate, argc > 2 ? argv[2] : "");
open_vconn(argv[1], &vconn);
flow_format = negotiate_highest_flow_format(vconn, &fsr.match, false, 0);
request = ofputil_encode_flow_stats_request(&fsr, flow_format);
dump_stats_transaction(argv[1], request);
vconn_close(vconn);
}
static void
do_dump_flows(int argc, char *argv[])
{
struct ofp_flow_stats_request *req;
struct parsed_flow pf;
struct ofpbuf *request;
req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : "");
ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
memset(&req->pad, 0, sizeof req->pad);
req->table_id = pf.table_idx;
req->out_port = htons(pf.out_port);
dump_stats_transaction(argv[1], request);
return do_dump_flows__(argc, argv, false);
}
static void
do_dump_aggregate(int argc, char *argv[])
{
struct ofp_aggregate_stats_request *req;
struct ofpbuf *request;
struct parsed_flow pf;
req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : "");
ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
memset(&req->pad, 0, sizeof req->pad);
req->table_id = pf.table_idx;
req->out_port = htons(pf.out_port);
dump_stats_transaction(argv[1], request);
return do_dump_flows__(argc, argv, true);
}
static void
@@ -526,23 +614,33 @@ do_queue_stats(int argc, char *argv[])
}
static void
do_add_flow(int argc OVS_UNUSED, char *argv[])
do_flow_mod__(int argc OVS_UNUSED, char *argv[], uint16_t command)
{
enum nx_flow_format flow_format;
struct list requests;
struct vconn *vconn;
struct ofpbuf *request;
request = parse_ofp_flow_mod_str(argv[2], OFPFC_ADD);
list_init(&requests);
flow_format = NXFF_OPENFLOW10;
parse_ofp_flow_mod_str(&requests, &flow_format, argv[2], command);
open_vconn(argv[1], &vconn);
dump_noreply_transaction(vconn, request);
transact_multiple_noreply(vconn, &requests);
vconn_close(vconn);
}
static void
do_add_flow(int argc, char *argv[])
{
do_flow_mod__(argc, argv, OFPFC_ADD);
}
static void
do_add_flows(int argc OVS_UNUSED, char *argv[])
{
enum nx_flow_format flow_format;
struct list requests;
struct vconn *vconn;
struct ofpbuf *b;
FILE *file;
file = fopen(argv[2], "r");
@@ -550,40 +648,28 @@ do_add_flows(int argc OVS_UNUSED, char *argv[])
ovs_fatal(errno, "%s: open", argv[2]);
}
list_init(&requests);
flow_format = NXFF_OPENFLOW10;
open_vconn(argv[1], &vconn);
while ((b = parse_ofp_add_flow_file(file)) != NULL) {
dump_noreply_transaction(vconn, b);
while (parse_ofp_add_flow_file(&requests, &flow_format, file)) {
transact_multiple_noreply(vconn, &requests);
}
vconn_close(vconn);
fclose(file);
}
static void
do_mod_flows(int argc OVS_UNUSED, char *argv[])
do_mod_flows(int argc, char *argv[])
{
struct vconn *vconn;
struct ofpbuf *buffer;
uint16_t command;
command = strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY;
buffer = parse_ofp_flow_mod_str(argv[2], command);
open_vconn(argv[1], &vconn);
dump_noreply_transaction(vconn, buffer);
vconn_close(vconn);
do_flow_mod__(argc, argv, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY);
}
static void do_del_flows(int argc, char *argv[])
static void
do_del_flows(int argc, char *argv[])
{
struct vconn *vconn;
struct ofpbuf *buffer;
uint16_t command;
command = strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE;
buffer = parse_ofp_flow_mod_str(argc > 2 ? argv[2] : "", command);
open_vconn(argv[1], &vconn);
dump_noreply_transaction(vconn, buffer);
vconn_close(vconn);
do_flow_mod__(argc, argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE);
}
static void
@@ -610,7 +696,7 @@ do_monitor(int argc, char *argv[])
osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf);
osc->miss_send_len = htons(miss_send_len);
dump_noreply_transaction(vconn, buf);
transact_noreply(vconn, buf);
}
monitor_vconn(vconn);
}
@@ -686,7 +772,7 @@ do_mod_port(int argc OVS_UNUSED, char *argv[])
}
open_vconn(argv[1], &vconn);
dump_noreply_transaction(vconn, request);
transact_noreply(vconn, request);
vconn_close(vconn);
}
@@ -791,7 +877,8 @@ do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
static void
do_parse_flows(int argc OVS_UNUSED, char *argv[])
{
struct ofpbuf *b;
enum nx_flow_format flow_format;
struct list packets;
FILE *file;
file = fopen(argv[1], "r");
@@ -799,9 +886,20 @@ do_parse_flows(int argc OVS_UNUSED, char *argv[])
ovs_fatal(errno, "%s: open", argv[2]);
}
while ((b = parse_ofp_add_flow_file(file)) != NULL) {
ofp_print(stdout, b->data, b->size, 0);
ofpbuf_delete(b);
list_init(&packets);
flow_format = NXFF_OPENFLOW10;
if (preferred_flow_format > 0) {
flow_format = preferred_flow_format;
}
while (parse_ofp_add_flow_file(&packets, &flow_format, file)) {
struct ofpbuf *packet, *next;
LIST_FOR_EACH_SAFE (packet, next, list_node, &packets) {
ofp_print(stdout, packet->data, packet->size, 0);
list_remove(&packet->list_node);
ofpbuf_delete(packet);
}
}
fclose(file);
}