2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-01 14:55:18 +00:00

ofp-print, ofp-parse: Add support for NXAST_REG_MOVE and NXAST_REG_LOAD.

This commit is contained in:
Ben Pfaff
2010-12-09 11:03:35 -08:00
parent 9aee07644c
commit f393f81e42
6 changed files with 256 additions and 14 deletions

View File

@@ -662,6 +662,8 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
/* nx_match_to_string() and helpers. */ /* nx_match_to_string() and helpers. */
static void format_nxm_field_name(struct ds *, uint32_t header);
char * char *
nx_match_to_string(const uint8_t *p, unsigned int match_len) nx_match_to_string(const uint8_t *p, unsigned int match_len)
{ {
@@ -678,20 +680,13 @@ nx_match_to_string(const uint8_t *p, unsigned int match_len)
unsigned int value_len = nxm_field_bytes(header); unsigned int value_len = nxm_field_bytes(header);
const uint8_t *value = p + 4; const uint8_t *value = p + 4;
const uint8_t *mask = value + value_len; const uint8_t *mask = value + value_len;
const struct nxm_field *f;
unsigned int i; unsigned int i;
if (s.length) { if (s.length) {
ds_put_cstr(&s, ", "); ds_put_cstr(&s, ", ");
} }
f = nxm_field_lookup(header); format_nxm_field_name(&s, header);
if (f) {
ds_put_cstr(&s, f->name);
} else {
ds_put_format(&s, "%d:%d", NXM_VENDOR(header), NXM_FIELD(header));
}
ds_put_char(&s, '('); ds_put_char(&s, '(');
for (i = 0; i < value_len; i++) { for (i = 0; i < value_len; i++) {
@@ -720,6 +715,17 @@ nx_match_to_string(const uint8_t *p, unsigned int match_len)
return ds_steal_cstr(&s); return ds_steal_cstr(&s);
} }
static void
format_nxm_field_name(struct ds *s, uint32_t header)
{
const struct nxm_field *f = nxm_field_lookup(header);
if (f) {
ds_put_cstr(s, f->name);
} else {
ds_put_format(s, "%d:%d", NXM_VENDOR(header), NXM_FIELD(header));
}
}
static uint32_t static uint32_t
parse_nxm_field_name(const char *name, int name_len) parse_nxm_field_name(const char *name, int name_len)
{ {
@@ -820,6 +826,167 @@ nx_match_from_string(const char *s, struct ofpbuf *b)
return match_len; return match_len;
} }
static const char *
parse_nxm_field_bits(const char *s, uint32_t *headerp, int *ofsp, int *n_bitsp)
{
const char *full_s = s;
const char *name;
uint32_t header;
int start, end;
int name_len;
int width;
name = s;
name_len = strcspn(s, "[");
if (s[name_len] != '[') {
ovs_fatal(0, "%s: missing [ looking for field name", full_s);
}
header = parse_nxm_field_name(name, name_len);
if (!header) {
ovs_fatal(0, "%s: unknown field `%.*s'", full_s, name_len, s);
}
width = nxm_field_bits(header);
s += name_len;
if (sscanf(s, "[%d..%d]", &start, &end) == 2) {
/* Nothing to do. */
} else if (sscanf(s, "[%d]", &start) == 1) {
end = start;
} else if (!strncmp(s, "[]", 2)) {
start = 0;
end = width - 1;
} else {
ovs_fatal(0, "%s: syntax error expecting [] or [<bit>] or "
"[<start>..<end>]", full_s);
}
s = strchr(s, ']') + 1;
if (start > end) {
ovs_fatal(0, "%s: starting bit %d is after ending bit %d",
full_s, start, end);
} else if (start >= width) {
ovs_fatal(0, "%s: starting bit %d is not valid because field is only "
"%d bits wide", full_s, start, width);
} else if (end >= width){
ovs_fatal(0, "%s: ending bit %d is not valid because field is only "
"%d bits wide", full_s, end, width);
}
*headerp = header;
*ofsp = start;
*n_bitsp = end - start + 1;
return s;
}
void
nxm_parse_reg_move(struct nx_action_reg_move *move, const char *s)
{
const char *full_s = s;
uint32_t src, dst;
int src_ofs, dst_ofs;
int src_n_bits, dst_n_bits;
s = parse_nxm_field_bits(s, &src, &src_ofs, &src_n_bits);
if (strncmp(s, "->", 2)) {
ovs_fatal(0, "%s: missing `->' following source", full_s);
}
s += 2;
s = parse_nxm_field_bits(s, &dst, &dst_ofs, &dst_n_bits);
if (*s != '\0') {
ovs_fatal(0, "%s: trailing garbage following destination", full_s);
}
if (src_n_bits != dst_n_bits) {
ovs_fatal(0, "%s: source field is %d bits wide but destination is "
"%d bits wide", full_s, src_n_bits, dst_n_bits);
}
move->type = htons(OFPAT_VENDOR);
move->len = htons(sizeof *move);
move->vendor = htonl(NX_VENDOR_ID);
move->subtype = htons(NXAST_REG_MOVE);
move->n_bits = htons(src_n_bits);
move->src_ofs = htons(src_ofs);
move->dst_ofs = htons(dst_ofs);
move->src = htonl(src);
move->dst = htonl(dst);
}
void
nxm_parse_reg_load(struct nx_action_reg_load *load, const char *s)
{
const char *full_s = s;
uint32_t dst;
int ofs, n_bits;
uint64_t value;
value = strtoull(s, (char **) &s, 0);
if (strncmp(s, "->", 2)) {
ovs_fatal(0, "%s: missing `->' following value", full_s);
}
s += 2;
s = parse_nxm_field_bits(s, &dst, &ofs, &n_bits);
if (*s != '\0') {
ovs_fatal(0, "%s: trailing garbage following destination", full_s);
}
if (n_bits < 64 && (value >> n_bits) != 0) {
ovs_fatal(0, "%s: value %llu does not fit into %d bits",
full_s, value, n_bits);
}
load->type = htons(OFPAT_VENDOR);
load->len = htons(sizeof *load);
load->vendor = htonl(NX_VENDOR_ID);
load->subtype = htons(NXAST_REG_LOAD);
load->ofs_nbits = htons((ofs << 6) | (n_bits - 1));
load->dst = htonl(dst);
load->value = htonll(value);
}
/* nxm_format_reg_move(), nxm_format_reg_load(). */
static void
format_nxm_field_bits(struct ds *s, uint32_t header, int ofs, int n_bits)
{
format_nxm_field_name(s, header);
if (n_bits != 1) {
ds_put_format(s, "[%d..%d]", ofs, ofs + n_bits - 1);
} else {
ds_put_format(s, "[%d]", ofs);
}
}
void
nxm_format_reg_move(const struct nx_action_reg_move *move, struct ds *s)
{
int n_bits = ntohs(move->n_bits);
int src_ofs = ntohs(move->src_ofs);
int dst_ofs = ntohs(move->dst_ofs);
uint32_t src = ntohl(move->src);
uint32_t dst = ntohl(move->dst);
ds_put_format(s, "move:");
format_nxm_field_bits(s, src, src_ofs, n_bits);
ds_put_cstr(s, "->");
format_nxm_field_bits(s, dst, dst_ofs, n_bits);
}
void
nxm_format_reg_load(const struct nx_action_reg_load *load, struct ds *s)
{
uint16_t ofs_nbits = ntohs(load->ofs_nbits);
int ofs = ofs_nbits >> 6;
int n_bits = (ofs_nbits & 0x3f) + 1;
uint32_t dst = ntohl(load->dst);
uint64_t value = ntohll(load->value);
ds_put_format(s, "load:%"PRIu64"->", value);
format_nxm_field_bits(s, dst, ofs, n_bits);
}
/* nxm_check_reg_move(), nxm_check_reg_load(). */ /* nxm_check_reg_move(), nxm_check_reg_load(). */
static bool static bool

View File

@@ -20,6 +20,7 @@
#include <stdint.h> #include <stdint.h>
struct cls_rule; struct cls_rule;
struct ds;
struct flow; struct flow;
struct ofpbuf; struct ofpbuf;
struct nx_action_reg_load; struct nx_action_reg_load;
@@ -37,6 +38,12 @@ int nx_put_match(struct ofpbuf *, const struct cls_rule *);
char *nx_match_to_string(const uint8_t *, unsigned int match_len); char *nx_match_to_string(const uint8_t *, unsigned int match_len);
int nx_match_from_string(const char *, struct ofpbuf *); int nx_match_from_string(const char *, struct ofpbuf *);
void nxm_parse_reg_move(struct nx_action_reg_move *, const char *);
void nxm_parse_reg_load(struct nx_action_reg_load *, const char *);
void nxm_format_reg_move(const struct nx_action_reg_move *, struct ds *);
void nxm_format_reg_load(const struct nx_action_reg_load *, struct ds *);
int nxm_check_reg_move(const struct nx_action_reg_move *, const struct flow *); int nxm_check_reg_move(const struct nx_action_reg_move *, const struct flow *);
int nxm_check_reg_load(const struct nx_action_reg_load *, const struct flow *); int nxm_check_reg_load(const struct nx_action_reg_load *, const struct flow *);

View File

@@ -25,6 +25,7 @@
#include "byte-order.h" #include "byte-order.h"
#include "dynamic-string.h" #include "dynamic-string.h"
#include "netdev.h" #include "netdev.h"
#include "nx-match.h"
#include "ofp-util.h" #include "ofp-util.h"
#include "ofpbuf.h" #include "ofpbuf.h"
#include "openflow/openflow.h" #include "openflow/openflow.h"
@@ -315,6 +316,14 @@ str_to_action(char *str, struct ofpbuf *b)
ofpbuf_put_zeros(b, OFP_ACTION_ALIGN - remainder); ofpbuf_put_zeros(b, OFP_ACTION_ALIGN - remainder);
} }
nan->len = htons(b->size - start_ofs); nan->len = htons(b->size - start_ofs);
} else if (!strcasecmp(act, "move")) {
struct nx_action_reg_move *move;
move = ofpbuf_put_uninit(b, sizeof *move);
nxm_parse_reg_move(move, arg);
} else if (!strcasecmp(act, "load")) {
struct nx_action_reg_load *load;
load = ofpbuf_put_uninit(b, sizeof *load);
nxm_parse_reg_load(load, arg);
} else if (!strcasecmp(act, "output")) { } else if (!strcasecmp(act, "output")) {
put_output_action(b, str_to_u32(arg)); put_output_action(b, str_to_u32(arg));
} else if (!strcasecmp(act, "enqueue")) { } else if (!strcasecmp(act, "enqueue")) {

View File

@@ -184,6 +184,7 @@ static void ofp_print_port_name(struct ds *string, uint16_t port)
ds_put_cstr(string, name); ds_put_cstr(string, name);
} }
static void static void
print_note(struct ds *string, const struct nx_action_note *nan) print_note(struct ds *string, const struct nx_action_note *nan)
{ {
@@ -200,15 +201,43 @@ print_note(struct ds *string, const struct nx_action_note *nan)
} }
} }
static int
nx_action_len(enum nx_action_subtype subtype)
{
switch (subtype) {
case NXAST_SNAT__OBSOLETE: return -1;
case NXAST_RESUBMIT: return sizeof(struct nx_action_resubmit);
case NXAST_SET_TUNNEL: return sizeof(struct nx_action_set_tunnel);
case NXAST_DROP_SPOOFED_ARP:
return sizeof(struct nx_action_drop_spoofed_arp);
case NXAST_SET_QUEUE: return sizeof(struct nx_action_set_queue);
case NXAST_POP_QUEUE: return sizeof(struct nx_action_pop_queue);
case NXAST_REG_MOVE: return sizeof(struct nx_action_reg_move);
case NXAST_REG_LOAD: return sizeof(struct nx_action_reg_load);
case NXAST_NOTE: return -1;
default: return -1;
}
}
static void static void
ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah) ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
{ {
uint16_t subtype = ntohs(nah->subtype); uint16_t subtype = ntohs(nah->subtype);
int required_len = nx_action_len(subtype);
int len = ntohs(nah->len);
if (required_len != -1 && required_len != len) {
ds_put_format(string, "***Nicira action %"PRIu16" wrong length: %d***",
subtype, len);
return;
}
if (subtype <= TYPE_MAXIMUM(enum nx_action_subtype)) { if (subtype <= TYPE_MAXIMUM(enum nx_action_subtype)) {
const struct nx_action_set_tunnel *nast; const struct nx_action_set_tunnel *nast;
const struct nx_action_set_queue *nasq; const struct nx_action_set_queue *nasq;
const struct nx_action_resubmit *nar; const struct nx_action_resubmit *nar;
const struct nx_action_reg_move *move;
const struct nx_action_reg_load *load;
switch ((enum nx_action_subtype) subtype) { switch ((enum nx_action_subtype) subtype) {
case NXAST_RESUBMIT: case NXAST_RESUBMIT:
@@ -240,8 +269,13 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
return; return;
case NXAST_REG_MOVE: case NXAST_REG_MOVE:
move = (const struct nx_action_reg_move *) nah;
nxm_format_reg_move(move, string);
return;
case NXAST_REG_LOAD: case NXAST_REG_LOAD:
/* XXX */ load = (const struct nx_action_reg_load *) nah;
nxm_format_reg_load(load, string);
return; return;
case NXAST_SNAT__OBSOLETE: case NXAST_SNAT__OBSOLETE:

View File

@@ -77,7 +77,7 @@ NXT_FLOW_MOD: ADD actions=drop
AT_CLEANUP AT_CLEANUP
AT_SETUP([ovs-ofctl -F nxm -mmm parse-flows]) AT_SETUP([ovs-ofctl -F nxm -mmm parse-flows])
AT_DATA([flows.txt], [ AT_DATA([flows.txt], [[
# comment # comment
tcp,tp_src=123,actions=flood tcp,tp_src=123,actions=flood
in_port=LOCAL dl_vlan=9 dl_src=00:0A:E4:25:6B:B0 actions=drop in_port=LOCAL dl_vlan=9 dl_src=00:0A:E4:25:6B:B0 actions=drop
@@ -89,10 +89,11 @@ cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
tun_id=0x1234,cookie=0x5678,actions=flood tun_id=0x1234,cookie=0x5678,actions=flood
actions=drop actions=drop
]) reg0=123,actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:55->NXM_NX_REG2[0..31],move:NXM_NX_REG0[0..31]->NXM_NX_TUN_ID[0..31],move:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[]
]])
AT_CHECK([ovs-ofctl -F nxm -mmm parse-flows flows.txt], [0], [stdout]) AT_CHECK([ovs-ofctl -F nxm -mmm parse-flows flows.txt], [0], [stdout])
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0],
NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC(007b) actions=FLOOD [[NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC(007b) actions=FLOOD
NXT_FLOW_MOD: ADD NXM_OF_IN_PORT(fffe), NXM_OF_ETH_SRC(000ae4256bb0), NXM_OF_VLAN_TCI_W(1009/1fff) actions=drop NXT_FLOW_MOD: ADD NXM_OF_IN_PORT(fffe), NXM_OF_ETH_SRC(000ae4256bb0), NXM_OF_VLAN_TCI_W(1009/1fff) actions=drop
NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_SPA(c0a80001) actions=drop_spoofed_arp,NORMAL NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_SPA(c0a80001) actions=drop_spoofed_arp,NORMAL
NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_VLAN_TCI_W(f000/f000), NXM_OF_IP_PROTO(11) idle:5 actions=strip_vlan,output:0 NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_VLAN_TCI_W(f000/f000), NXM_OF_IP_PROTO(11) idle:5 actions=strip_vlan,output:0
@@ -102,7 +103,8 @@ NXT_FLOW_MOD: ADD <any> cookie:0x123456789abcdef hard:10 pri:60000 actions=CONTR
NXT_FLOW_MOD: ADD <any> 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 <any> 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 NXM_NX_TUN_ID(0000000000001234) cookie:0x5678 actions=FLOOD NXT_FLOW_MOD: ADD NXM_NX_TUN_ID(0000000000001234) cookie:0x5678 actions=FLOOD
NXT_FLOW_MOD: ADD <any> actions=drop NXT_FLOW_MOD: ADD <any> actions=drop
]) NXT_FLOW_MOD: ADD NXM_NX_REG0(0000007b) actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:55->NXM_NX_REG2[0..31],move:NXM_NX_REG0[0..31]->NXM_NX_TUN_ID[0..31],move:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[0..15]
]])
AT_CLEANUP AT_CLEANUP
AT_SETUP([ovs-ofctl parse-nx-match]) AT_SETUP([ovs-ofctl parse-nx-match])

View File

@@ -521,6 +521,29 @@ actions were applied.
Does nothing at all. Any number of bytes represented as hex digits Does nothing at all. Any number of bytes represented as hex digits
\fIhh\fR may be included. Pairs of hex digits may be separated by \fIhh\fR may be included. Pairs of hex digits may be separated by
periods for readability. periods for readability.
.
.IP "\fBmove:\fIsrc\fB[\fIstart\fB..\fIend\fB]->\fIdst\fB[\fIstart\fB..\fIend\fB]\fR"
Copies the named bits from field \fIsrc\fR to field \fIdst\fR.
\fIsrc\fR and \fIdst\fR must be NXM field names as defined in
\fBnicira\-ext.h\fR, e.g. \fBNXM_OF_UDP_SRC\fR or \fBNXM_NX_REG0\fR.
Each \fIstart\fR and \fIend\fR pair, which are inclusive, must specify
the same number of bits and must fit within its respective field.
Shorthands for \fB[\fIstart\fB..\fIend\fB]\fR exist: use
\fB[\fIbit\fB]\fR to specify a single bit or \fB[]\fR to specify an
entire field.
.IP
Examples: \fBmove:NXM_NX_REG0[0..5]\->NXM_NX_REG1[26..31]\fR copies the
six bits numbered 0 through 5, inclusive, in register 0 into bits 26
through 31, inclusive;
\fBmove:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[]\fR copies the least
significant 16 bits of register 0 into the VLAN TCI field.
.
.IP "\fBload:\fIvalue\fB\->\fIdst\fB[\fIstart\fB..\fIend\fB]"
Writes \fIvalue\fR to bits \fIstart\fR through \fIend\fR, inclusive,
in field \fBdst\fR.
.IP
Example: \fBload:55\->NXM_NX_REG2[0..5]\fR loads value 55 (bit pattern
\fB110111\fR) into bits 0 through 5, inclusive, in register 2.
.RE .RE
. .
.IP .IP