Skip to content

Commit e729e79

Browse files
author
Justin Pettit
committed
Add ability to restrict flow mods and flow stats requests to cookies.
With this commit, it is possible to limit flow deletions and modifications to specific cookies. It also provides the ability to dump flows based on their cookies. Signed-off-by: Justin Pettit <jpettit@nicira.com>
1 parent a8600e1 commit e729e79

12 files changed

Lines changed: 285 additions & 46 deletions

File tree

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
port-v1.4.0
22
------------------------
3+
- OpenFlow:
4+
- Added support for querying, modifying, and deleting flows
5+
based on flow cookie when using NXM.
36

47

58
v1.4.0 - xx xxx xxxx

include/openflow/nicira-ext.h

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,22 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
16411641
* Masking: Not maskable. */
16421642
#define NXM_NX_IP_TTL NXM_HEADER (0x0001, 29, 1)
16431643

1644+
/* Flow cookie.
1645+
*
1646+
* This may be used to gain the OpenFlow 1.1-like ability to restrict
1647+
* certain NXM-based Flow Mod and Flow Stats Request messages to flows
1648+
* with specific cookies. See the "nx_flow_mod" and "nx_flow_stats_request"
1649+
* structure definitions for more details. This match is otherwise not
1650+
* allowed.
1651+
*
1652+
* Prereqs: None.
1653+
*
1654+
* Format: 64-bit integer in network byte order.
1655+
*
1656+
* Masking: Arbitrary masks. */
1657+
#define NXM_NX_COOKIE NXM_HEADER (0x0001, 30, 8)
1658+
#define NXM_NX_COOKIE_W NXM_HEADER_W(0x0001, 30, 8)
1659+
16441660
/* ## --------------------- ## */
16451661
/* ## Requests and replies. ## */
16461662
/* ## --------------------- ## */
@@ -1659,7 +1675,14 @@ struct nxt_set_flow_format {
16591675
};
16601676
OFP_ASSERT(sizeof(struct nxt_set_flow_format) == 20);
16611677

1662-
/* NXT_FLOW_MOD (analogous to OFPT_FLOW_MOD). */
1678+
/* NXT_FLOW_MOD (analogous to OFPT_FLOW_MOD).
1679+
*
1680+
* It is possible to limit flow deletions and modifications to certain
1681+
* cookies by using the NXM_NX_COOKIE and NXM_NX_COOKIE_W matches. For
1682+
* these commands, the "cookie" field is always ignored. Flow additions
1683+
* make use of the "cookie" field and ignore any NXM_NX_COOKIE*
1684+
* definitions.
1685+
*/
16631686
struct nx_flow_mod {
16641687
struct nicira_header nxh;
16651688
ovs_be64 cookie; /* Opaque controller-issued identifier. */
@@ -1708,7 +1731,11 @@ struct nx_flow_removed {
17081731
OFP_ASSERT(sizeof(struct nx_flow_removed) == 56);
17091732

17101733
/* Nicira vendor stats request of type NXST_FLOW (analogous to OFPST_FLOW
1711-
* request). */
1734+
* request).
1735+
*
1736+
* It is possible to limit matches to certain cookies by using the
1737+
* NXM_NX_COOKIE and NXM_NX_COOKIE_W matches.
1738+
*/
17121739
struct nx_flow_stats_request {
17131740
struct nicira_stats_msg nsm;
17141741
ovs_be16 out_port; /* Require matching entries to include this

lib/nx-match.c

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,24 @@ nx_entry_ok(const void *p, unsigned int match_len)
9696
return header;
9797
}
9898

99+
/* Parses the nx_match formatted match description in 'b' with length
100+
* 'match_len'. The results are stored in 'rule', which is initialized
101+
* with 'priority'. If 'cookie' and 'cookie_mask' contain valid
102+
* pointers, then the cookie and mask will be stored in them if a
103+
* "NXM_NX_COOKIE*" match is defined. Otherwise, 0 is stored in both.
104+
*
105+
* Returns 0 if successful, otherwise an OpenFlow error code.
106+
*/
99107
int
100108
nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
101-
struct cls_rule *rule)
109+
struct cls_rule *rule,
110+
ovs_be64 *cookie, ovs_be64 *cookie_mask)
102111
{
103112
uint32_t header;
104113
uint8_t *p;
105114

115+
assert((cookie != NULL) == (cookie_mask != NULL));
116+
106117
p = ofpbuf_try_pull(b, ROUND_UP(match_len, 8));
107118
if (!p) {
108119
VLOG_DBG_RL(&rl, "nx_match length %u, rounded up to a "
@@ -112,6 +123,9 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
112123
}
113124

114125
cls_rule_init_catchall(rule, priority);
126+
if (cookie) {
127+
*cookie = *cookie_mask = htonll(0);
128+
}
115129
while ((header = nx_entry_ok(p, match_len)) != 0) {
116130
unsigned length = NXM_LENGTH(header);
117131
const struct mf_field *mf;
@@ -147,6 +161,23 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
147161
}
148162
}
149163

164+
/* Check if the match is for a cookie rather than a classifier rule. */
165+
if ((header == NXM_NX_COOKIE || header == NXM_NX_COOKIE_W) && cookie) {
166+
if (*cookie_mask) {
167+
error = NXM_DUP_TYPE;
168+
} else {
169+
unsigned int width = sizeof *cookie;
170+
171+
memcpy(cookie, p + 4, width);
172+
if (NXM_HASMASK(header)) {
173+
memcpy(cookie_mask, p + 4 + width, width);
174+
} else {
175+
*cookie_mask = htonll(UINT64_MAX);
176+
}
177+
error = 0;
178+
}
179+
}
180+
150181
if (error) {
151182
char *msg = ofputil_error_to_string(error);
152183
VLOG_DBG_RL(&rl, "bad nxm_entry %#08"PRIx32" (vendor=%"PRIu32", "
@@ -367,7 +398,9 @@ nxm_put_frag(struct ofpbuf *b, const struct cls_rule *cr)
367398

368399
/* Appends to 'b' the nx_match format that expresses 'cr' (except for
369400
* 'cr->priority', because priority is not part of nx_match), plus enough
370-
* zero bytes to pad the nx_match out to a multiple of 8.
401+
* zero bytes to pad the nx_match out to a multiple of 8. For Flow Mod
402+
* and Flow Stats Requests messages, a 'cookie' and 'cookie_mask' may be
403+
* supplied. Otherwise, 'cookie_mask' should be zero.
371404
*
372405
* This function can cause 'b''s data to be reallocated.
373406
*
@@ -376,7 +409,8 @@ nxm_put_frag(struct ofpbuf *b, const struct cls_rule *cr)
376409
* If 'cr' is a catch-all rule that matches every packet, then this function
377410
* appends nothing to 'b' and returns 0. */
378411
int
379-
nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
412+
nx_put_match(struct ofpbuf *b, const struct cls_rule *cr,
413+
ovs_be64 cookie, ovs_be64 cookie_mask)
380414
{
381415
const flow_wildcards_t wc = cr->wc.wildcards;
382416
const struct flow *flow = &cr->flow;
@@ -556,6 +590,9 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
556590
htonl(flow->regs[i]), htonl(cr->wc.reg_masks[i]));
557591
}
558592

593+
/* Cookie. */
594+
nxm_put_64m(b, NXM_NX_COOKIE, cookie, cookie_mask);
595+
559596
match_len = b->size - start_len;
560597
ofpbuf_put_zeros(b, ROUND_UP(match_len, 8) - match_len);
561598
return match_len;
@@ -625,6 +662,10 @@ format_nxm_field_name(struct ds *s, uint32_t header)
625662
if (NXM_HASMASK(header)) {
626663
ds_put_cstr(s, "_W");
627664
}
665+
} else if (header == NXM_NX_COOKIE) {
666+
ds_put_cstr(s, "NXM_NX_COOKIE");
667+
} else if (header == NXM_NX_COOKIE_W) {
668+
ds_put_cstr(s, "NXM_NX_COOKIE_W");
628669
} else {
629670
ds_put_format(s, "%d:%d", NXM_VENDOR(header), NXM_FIELD(header));
630671
}
@@ -641,6 +682,7 @@ parse_nxm_field_name(const char *name, int name_len)
641682
if (wild) {
642683
name_len -= 2;
643684
}
685+
644686
for (i = 0; i < MFF_N_IDS; i++) {
645687
const struct mf_field *mf = mf_from_id(i);
646688

@@ -655,6 +697,15 @@ parse_nxm_field_name(const char *name, int name_len)
655697
}
656698
}
657699

700+
if (!strncmp("NXM_NX_COOKIE", name, name_len)
701+
&& (name_len == strlen("NXM_NX_COOKIE"))) {
702+
if (!wild) {
703+
return NXM_NX_COOKIE;
704+
} else {
705+
return NXM_NX_COOKIE_W;
706+
}
707+
}
708+
658709
/* Check whether it's a 32-bit field header value as hex.
659710
* (This isn't ordinarily useful except for testing error behavior.) */
660711
if (name_len == 8) {

lib/nx-match.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ struct nx_action_reg_move;
3535
*/
3636

3737
int nx_pull_match(struct ofpbuf *, unsigned int match_len, uint16_t priority,
38-
struct cls_rule *);
39-
int nx_put_match(struct ofpbuf *, const struct cls_rule *);
38+
struct cls_rule *, ovs_be64 *cookie, ovs_be64 *cookie_mask);
39+
int nx_put_match(struct ofpbuf *, const struct cls_rule *,
40+
ovs_be64 cookie, ovs_be64 cookie_mask);
4041

4142
char *nx_match_to_string(const uint8_t *, unsigned int match_len);
4243
int nx_match_from_string(const char *, struct ofpbuf *);

lib/ofp-parse.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,6 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
488488
enum {
489489
F_OUT_PORT = 1 << 0,
490490
F_ACTIONS = 1 << 1,
491-
F_COOKIE = 1 << 2,
492491
F_TIMEOUT = 1 << 3,
493492
F_PRIORITY = 1 << 4
494493
} fields;
@@ -503,7 +502,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
503502
break;
504503

505504
case OFPFC_ADD:
506-
fields = F_ACTIONS | F_COOKIE | F_TIMEOUT | F_PRIORITY;
505+
fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY;
507506
break;
508507

509508
case OFPFC_DELETE:
@@ -515,11 +514,11 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
515514
break;
516515

517516
case OFPFC_MODIFY:
518-
fields = F_ACTIONS | F_COOKIE;
517+
fields = F_ACTIONS;
519518
break;
520519

521520
case OFPFC_MODIFY_STRICT:
522-
fields = F_ACTIONS | F_COOKIE | F_PRIORITY;
521+
fields = F_ACTIONS | F_PRIORITY;
523522
break;
524523

525524
default:
@@ -528,6 +527,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
528527

529528
cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY);
530529
fm->cookie = htonll(0);
530+
fm->cookie_mask = htonll(0);
531531
fm->table_id = 0xff;
532532
fm->command = command;
533533
fm->idle_timeout = OFP_FLOW_PERMANENT;
@@ -576,7 +576,18 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
576576
fm->idle_timeout = str_to_u16(value, name);
577577
} else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) {
578578
fm->hard_timeout = str_to_u16(value, name);
579-
} else if (fields & F_COOKIE && !strcmp(name, "cookie")) {
579+
} else if (!strcmp(name, "cookie")) {
580+
char *mask = strchr(value, '/');
581+
if (mask) {
582+
if (command == OFPFC_ADD) {
583+
ofp_fatal(str_, verbose, "flow additions cannot use "
584+
"a cookie mask");
585+
}
586+
*mask = '\0';
587+
fm->cookie_mask = htonll(str_to_u64(mask+1));
588+
} else {
589+
fm->cookie_mask = htonll(UINT64_MAX);
590+
}
580591
fm->cookie = htonll(str_to_u64(value));
581592
} else if (mf_from_name(name)) {
582593
parse_field(mf_from_name(name), value, &fm->cr);
@@ -625,6 +636,9 @@ parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format,
625636
parse_ofp_str(&fm, command, string, verbose);
626637

627638
min_format = ofputil_min_flow_format(&fm.cr);
639+
if (command != OFPFC_ADD && fm.cookie_mask != htonll(0)) {
640+
min_format = NXFF_NXM;
641+
}
628642
next_format = MAX(*cur_format, min_format);
629643
if (next_format != *cur_format) {
630644
struct ofpbuf *sff = ofputil_make_set_flow_format(next_format);
@@ -678,6 +692,8 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
678692

679693
parse_ofp_str(&fm, -1, string, false);
680694
fsr->aggregate = aggregate;
695+
fsr->cookie = fm.cookie;
696+
fsr->cookie_mask = fm.cookie_mask;
681697
fsr->match = fm.cr;
682698
fsr->out_port = fm.out_port;
683699
fsr->table_id = fm.table_id;

lib/ofp-util.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
987987

988988
/* Translate the message. */
989989
fm->cookie = ofm->cookie;
990+
fm->cookie_mask = htonll(UINT64_MAX);
990991
command = ntohs(ofm->command);
991992
fm->idle_timeout = ntohs(ofm->idle_timeout);
992993
fm->hard_timeout = ntohs(ofm->hard_timeout);
@@ -1001,7 +1002,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
10011002
/* Dissect the message. */
10021003
nfm = ofpbuf_pull(&b, sizeof *nfm);
10031004
error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority),
1004-
&fm->cr);
1005+
&fm->cr, &fm->cookie, &fm->cookie_mask);
10051006
if (error) {
10061007
return error;
10071008
}
@@ -1011,8 +1012,18 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
10111012
}
10121013

10131014
/* Translate the message. */
1014-
fm->cookie = nfm->cookie;
10151015
command = ntohs(nfm->command);
1016+
if (command == OFPFC_ADD) {
1017+
if (fm->cookie_mask) {
1018+
/* The "NXM_NX_COOKIE*" matches are not valid for flow
1019+
* additions. Additions must use the "cookie" field of
1020+
* the "nx_flow_mod" structure. */
1021+
return ofp_mkerr(OFPET_BAD_REQUEST, NXBRC_NXM_INVALID);
1022+
} else {
1023+
fm->cookie = nfm->cookie;
1024+
fm->cookie_mask = htonll(UINT64_MAX);
1025+
}
1026+
}
10161027
fm->idle_timeout = ntohs(nfm->idle_timeout);
10171028
fm->hard_timeout = ntohs(nfm->hard_timeout);
10181029
fm->buffer_id = ntohl(nfm->buffer_id);
@@ -1071,11 +1082,16 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
10711082

10721083
msg = ofpbuf_new(sizeof *nfm + NXM_TYPICAL_LEN + actions_len);
10731084
put_nxmsg(sizeof *nfm, NXT_FLOW_MOD, msg);
1074-
match_len = nx_put_match(msg, &fm->cr);
1075-
10761085
nfm = msg->data;
1077-
nfm->cookie = fm->cookie;
10781086
nfm->command = htons(command);
1087+
if (command == OFPFC_ADD) {
1088+
nfm->cookie = fm->cookie;
1089+
match_len = nx_put_match(msg, &fm->cr, 0, 0);
1090+
} else {
1091+
nfm->cookie = 0;
1092+
match_len = nx_put_match(msg, &fm->cr,
1093+
fm->cookie, fm->cookie_mask);
1094+
}
10791095
nfm->idle_timeout = htons(fm->idle_timeout);
10801096
nfm->hard_timeout = htons(fm->hard_timeout);
10811097
nfm->priority = htons(fm->cr.priority);
@@ -1104,6 +1120,7 @@ ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
11041120
ofputil_cls_rule_from_match(&ofsr->match, 0, &fsr->match);
11051121
fsr->out_port = ntohs(ofsr->out_port);
11061122
fsr->table_id = ofsr->table_id;
1123+
fsr->cookie = fsr->cookie_mask = htonll(0);
11071124

11081125
return 0;
11091126
}
@@ -1120,7 +1137,8 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
11201137
ofpbuf_use_const(&b, oh, ntohs(oh->length));
11211138

11221139
nfsr = ofpbuf_pull(&b, sizeof *nfsr);
1123-
error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &fsr->match);
1140+
error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &fsr->match,
1141+
&fsr->cookie, &fsr->cookie_mask);
11241142
if (error) {
11251143
return error;
11261144
}
@@ -1194,7 +1212,8 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
11941212

11951213
subtype = fsr->aggregate ? NXST_AGGREGATE : NXST_FLOW;
11961214
ofputil_make_stats_request(sizeof *nfsr, OFPST_VENDOR, subtype, &msg);
1197-
match_len = nx_put_match(msg, &fsr->match);
1215+
match_len = nx_put_match(msg, &fsr->match,
1216+
fsr->cookie, fsr->cookie_mask);
11981217

11991218
nfsr = msg->data;
12001219
nfsr->out_port = htons(fsr->out_port);
@@ -1290,7 +1309,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
12901309
"claims invalid length %zu", match_len, length);
12911310
return EINVAL;
12921311
}
1293-
if (nx_pull_match(msg, match_len, ntohs(nfs->priority), &fs->rule)) {
1312+
if (nx_pull_match(msg, match_len, ntohs(nfs->priority), &fs->rule,
1313+
NULL, NULL)) {
12941314
return EINVAL;
12951315
}
12961316

@@ -1374,7 +1394,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
13741394
nfs->priority = htons(fs->rule.priority);
13751395
nfs->idle_timeout = htons(fs->idle_timeout);
13761396
nfs->hard_timeout = htons(fs->hard_timeout);
1377-
nfs->match_len = htons(nx_put_match(msg, &fs->rule));
1397+
nfs->match_len = htons(nx_put_match(msg, &fs->rule, 0, 0));
13781398
memset(nfs->pad2, 0, sizeof nfs->pad2);
13791399
nfs->cookie = fs->cookie;
13801400
nfs->packet_count = htonll(fs->packet_count);
@@ -1453,7 +1473,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
14531473

14541474
nfr = ofpbuf_pull(&b, sizeof *nfr);
14551475
error = nx_pull_match(&b, ntohs(nfr->match_len), ntohs(nfr->priority),
1456-
&fr->rule);
1476+
&fr->rule, NULL, NULL);
14571477
if (error) {
14581478
return error;
14591479
}
@@ -1503,7 +1523,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
15031523
int match_len;
15041524

15051525
make_nxmsg_xid(sizeof *nfr, NXT_FLOW_REMOVED, htonl(0), &msg);
1506-
match_len = nx_put_match(msg, &fr->rule);
1526+
match_len = nx_put_match(msg, &fr->rule, 0, 0);
15071527

15081528
nfr = msg->data;
15091529
nfr->cookie = fr->cookie;

0 commit comments

Comments
 (0)