In OpenFlow 1.1, we add support for OFPIT_WRITE_METADATA. This allows us to write to the metadata field. Internally it is represented using ofpact_metadata.
We introduce NXAST_WRITE_METADATA to handle writing to the metadata field in OpenFlow 1.0+. This structure reflects OFPIT_WRITE_METADATA. When writing out the structure to OpenFlow 1.1, it uses the OFPIT_WRITE_METADATA instruction only, and not the new NXAST action (which would be redundant). Signed-off-by: Joe Stringer <j...@wand.net.nz> --- v2: Dropped unused function --- NEWS | 1 + include/openflow/nicira-ext.h | 15 +++++++ lib/ofp-actions.c | 84 ++++++++++++++++++++++++++++++++++++++++- lib/ofp-actions.h | 13 ++++++ lib/ofp-parse.c | 22 +++++++++++ lib/ofp-util.def | 2 + lib/ofp-util.h | 1 + ofproto/ofproto-dpif.c | 8 ++++ tests/ofp-actions.at | 55 ++++++++++++++++++++++++-- tests/ofproto.at | 6 +++ utilities/ovs-ofctl.8.in | 16 ++++++++ 11 files changed, 217 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 84f1ec1..9b67872 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ post-v1.7.0 the multicast bit in the destination address could be individually masked.) - New field OXM_OF_METADATA, to align with OpenFlow 1.1. + - Adds support for writing to the metadata field for a flow. - The OFPST_QUEUE request now reports an error if a specified port or queue does not exist, or for requests for a specific queue on all ports, if the specified queue does not exist on any port. (Previous diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 82deeb0..2e42dcb 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -341,6 +341,7 @@ enum nx_action_subtype { NXAST_DEC_TTL, /* struct nx_action_header */ NXAST_FIN_TIMEOUT, /* struct nx_action_fin_timeout */ NXAST_CONTROLLER, /* struct nx_action_controller */ + NXAST_WRITE_METADATA, /* struct nx_action_write_metadata */ }; /* Header for Nicira-defined actions. */ @@ -1977,4 +1978,18 @@ struct nx_action_controller { }; OFP_ASSERT(sizeof(struct nx_action_controller) == 16); +/* Action structure for NXAST_WRITE_METADATA. + * + * Modifies the 'mask' bits of the metadata value. */ +struct nx_action_write_metadata { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* Length is 32. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* NXAST_WRITE_METADATA. */ + uint8_t pad[6]; + ovs_be64 metadata; /* Metadata register. */ + ovs_be64 mask; /* Metadata mask. */ +}; +OFP_ASSERT(sizeof(struct nx_action_write_metadata) == 32); + #endif /* openflow/nicira-ext.h */ diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 93f6bf7..bafaf1e 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -136,6 +136,17 @@ controller_from_openflow(const struct nx_action_controller *nac, } static void +metadata_from_openflow(const struct nx_action_write_metadata *nawm, + struct ofpbuf *out) +{ + struct ofpact_metadata *om; + + om = ofpact_put_WRITE_METADATA(out); + om->metadata = ntohll(nawm->metadata); + om->mask = ntohll(nawm->mask); +} + +static void note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out) { struct ofpact_note *note; @@ -224,6 +235,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, const struct nx_action_set_queue *nasq; const struct nx_action_note *nan; const struct nx_action_set_tunnel64 *nast64; + const struct nx_action_write_metadata *nawm; struct ofpact_tunnel *tunnel; enum ofperr error = 0; @@ -245,6 +257,11 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, tunnel->tun_id = ntohl(nast->tun_id); break; + case OFPUTIL_NXAST_WRITE_METADATA: + nawm = (const struct nx_action_write_metadata *) a; + metadata_from_openflow(nawm, out); + break; + case OFPUTIL_NXAST_SET_QUEUE: nasq = (const struct nx_action_set_queue *) a; ofpact_put_SET_QUEUE(out)->queue_id = ntohl(nasq->queue_id); @@ -889,12 +906,21 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow, if (error) { goto exit; } + } else if (insts[OVSINST_OFPIT11_WRITE_METADATA]) { + const struct ofp11_instruction_write_metadata *oiwm; + struct ofpact_metadata *om; + + oiwm = (const struct ofp11_instruction_write_metadata *) + insts[OVSINST_OFPIT11_WRITE_METADATA]; + + om = (struct ofpact_metadata *)ofpact_put_WRITE_METADATA(ofpacts); + om->metadata = ntohll(oiwm->metadata); + om->mask = ntohll(oiwm->metadata_mask); } ofpact_pad(ofpacts); if (insts[OVSINST_OFPIT11_GOTO_TABLE] || - insts[OVSINST_OFPIT11_WRITE_METADATA] || insts[OVSINST_OFPIT11_WRITE_ACTIONS] || insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) { error = OFPERR_OFPBIC_UNSUP_INST; @@ -955,6 +981,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports) case OFPACT_DEC_TTL: case OFPACT_SET_TUNNEL: + case OFPACT_WRITE_METADATA: case OFPACT_SET_QUEUE: case OFPACT_POP_QUEUE: case OFPACT_FIN_TIMEOUT: @@ -1043,6 +1070,17 @@ ofpact_set_tunnel_to_nxast(const struct ofpact_tunnel *tunnel, } static void +ofpact_write_metadata_to_nxast(const struct ofpact_metadata *om, + struct ofpbuf *out) +{ + struct nx_action_write_metadata *nawm; + + nawm = ofputil_put_NXAST_WRITE_METADATA(out); + nawm->metadata = htonll(om->metadata); + nawm->mask = htonll(om->mask); +} + +static void ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out) { size_t start_ofs = out->size; @@ -1117,6 +1155,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out); break; + case OFPACT_WRITE_METADATA: + ofpact_write_metadata_to_nxast(ofpact_get_WRITE_METADATA(a), out); + break; + case OFPACT_SET_QUEUE: ofputil_put_NXAST_SET_QUEUE(out)->queue_id = htonl(ofpact_get_SET_QUEUE(a)->queue_id); @@ -1262,6 +1304,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out) case OFPACT_REG_LOAD: case OFPACT_DEC_TTL: case OFPACT_SET_TUNNEL: + case OFPACT_WRITE_METADATA: case OFPACT_SET_QUEUE: case OFPACT_POP_QUEUE: case OFPACT_FIN_TIMEOUT: @@ -1363,6 +1406,10 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) = htons(ofpact_get_SET_L4_DST_PORT(a)->port); break; + case OFPACT_WRITE_METADATA: + /* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */ + break; + case OFPACT_CONTROLLER: case OFPACT_OUTPUT_REG: case OFPACT_BUNDLE: @@ -1398,6 +1445,29 @@ ofpacts_put_openflow11_actions(const struct ofpact ofpacts[], } } +/* Searches for a write-metadata instruction in 'ofpacts' and if found, + * converts to the OpenFlow 1.1 instruction format, appending the instruction + * to any existing data in 'openflow'. */ +void +ofpacts_put_openflow11_write_metadata(const struct ofpact ofpacts[], + size_t ofpacts_len, + struct ofpbuf *openflow) +{ + struct ofp11_instruction_write_metadata *oiwm; + const struct ofpact *a; + const struct ofpact_metadata *om; + + OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { + if (a->type == OFPACT_WRITE_METADATA) { + om = ofpact_get_WRITE_METADATA(a); + oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow); + oiwm->metadata = htonll(om->metadata); + oiwm->metadata_mask = htonll(om->mask); + return; + } + } +} + void ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[], size_t ofpacts_len, @@ -1418,6 +1488,8 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[], } else { openflow->size = ofs; } + + ofpacts_put_openflow11_write_metadata(ofpacts, ofpacts_len, openflow); } /* Returns true if 'action' outputs to 'port', false otherwise. */ @@ -1448,6 +1520,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port) case OFPACT_REG_LOAD: case OFPACT_DEC_TTL: case OFPACT_SET_TUNNEL: + case OFPACT_WRITE_METADATA: case OFPACT_SET_QUEUE: case OFPACT_POP_QUEUE: case OFPACT_FIN_TIMEOUT: @@ -1527,6 +1600,7 @@ ofpact_format(const struct ofpact *a, struct ds *s) const struct ofpact_autopath *autopath; const struct ofpact_controller *controller; const struct ofpact_tunnel *tunnel; + const struct ofpact_metadata *metadata; uint16_t port; switch (a->type) { @@ -1649,6 +1723,14 @@ ofpact_format(const struct ofpact *a, struct ds *s) tunnel->tun_id); break; + case OFPACT_WRITE_METADATA: + metadata = ofpact_get_WRITE_METADATA(a); + ds_put_format(s, "write_metadata:%#"PRIx64, metadata->metadata); + if (metadata->mask != UINT64_MAX) { + ds_put_format(s, "/%#"PRIx64, metadata->mask); + } + break; + case OFPACT_SET_QUEUE: ds_put_format(s, "set_queue:%"PRIu32, ofpact_get_SET_QUEUE(a)->queue_id); diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 7c9cb05..58942bc 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -73,6 +73,7 @@ \ /* Metadata. */ \ DEFINE_OFPACT(SET_TUNNEL, ofpact_tunnel, ofpact) \ + DEFINE_OFPACT(WRITE_METADATA, ofpact_metadata, ofpact) \ DEFINE_OFPACT(SET_QUEUE, ofpact_queue, ofpact) \ DEFINE_OFPACT(POP_QUEUE, ofpact_null, ofpact) \ DEFINE_OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact) \ @@ -303,6 +304,15 @@ struct ofpact_fin_timeout { uint16_t fin_hard_timeout; }; +/* OFPACT_WRITE_METADATA. + * + * Used for NXAST_WRITE_METADATA. */ +struct ofpact_metadata { + struct ofpact ofpact; + uint64_t metadata; + uint64_t mask; +}; + /* OFPACT_RESUBMIT. * * Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */ @@ -398,6 +408,9 @@ void ofpacts_put_openflow10(const struct ofpact[], size_t ofpacts_len, struct ofpbuf *openflow); void ofpacts_put_openflow11_actions(const struct ofpact[], size_t ofpacts_len, struct ofpbuf *openflow); +void ofpacts_put_openflow11_write_metadata(const struct ofpact ofpacts[], + size_t ofpacts_len, + struct ofpbuf *openflow); void ofpacts_put_openflow11_instructions(const struct ofpact[], size_t ofpacts_len, struct ofpbuf *openflow); diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 922e296..5e7185d 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -279,6 +279,24 @@ parse_controller(struct ofpbuf *b, char *arg) } static void +parse_metadata(struct ofpbuf *b, char *arg) +{ + struct ofpact_metadata *om; + char *mask = strchr(arg, '/'); + + om = ofpact_put_WRITE_METADATA(b); + + if (mask) { + *mask = '\0'; + om->mask = str_to_u64(mask + 1); + } else { + om->mask = UINT64_MAX; + } + + om->metadata = str_to_u64(arg); +} + +static void parse_named_action(enum ofputil_action_code code, const struct flow *flow, char *arg, struct ofpbuf *ofpacts) { @@ -375,6 +393,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, tunnel->tun_id = str_to_u64(arg); break; + case OFPUTIL_NXAST_WRITE_METADATA: + parse_metadata(ofpacts, arg); + break; + case OFPUTIL_NXAST_SET_QUEUE: ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg); break; diff --git a/lib/ofp-util.def b/lib/ofp-util.def index 974cd8f..e5aa046 100644 --- a/lib/ofp-util.def +++ b/lib/ofp-util.def @@ -58,6 +58,8 @@ NXAST_ACTION(NXAST_EXIT, nx_action_header, 0, "exit") NXAST_ACTION(NXAST_DEC_TTL, nx_action_header, 0, "dec_ttl") NXAST_ACTION(NXAST_FIN_TIMEOUT, nx_action_fin_timeout, 0, "fin_timeout") NXAST_ACTION(NXAST_CONTROLLER, nx_action_controller, 0, "controller") +NXAST_ACTION(NXAST_WRITE_METADATA, nx_action_write_metadata, 0, + "write_metadata") #undef OFPAT10_ACTION #undef OFPAT11_ACTION diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 703de50..ba2a393 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -578,6 +578,7 @@ bool ofputil_frag_handling_from_string(const char *, enum ofp_config_flags *); * OFPUTIL_OFPAT10_ENQUEUE * OFPUTIL_NXAST_RESUBMIT * OFPUTIL_NXAST_SET_TUNNEL + * OFPUTIL_NXAST_SET_METADATA * OFPUTIL_NXAST_SET_QUEUE * OFPUTIL_NXAST_POP_QUEUE * OFPUTIL_NXAST_REG_MOVE diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 2451d44..c6754a5 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5381,6 +5381,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, const struct ofport_dpif *port; bool was_evictable = true; const struct ofpact *a; + const struct ofpact_metadata *om; port = get_ofp_port(ctx->ofproto, ctx->flow.in_port); if (port && !may_receive(port, ctx)) { @@ -5476,6 +5477,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, ctx->flow.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id); break; + case OFPACT_WRITE_METADATA: + om = ofpact_get_WRITE_METADATA(a); + ctx->flow.metadata &= htonll(~om->mask); + ctx->flow.metadata |= htonll(om->metadata & om->mask); + break; + case OFPACT_SET_QUEUE: xlate_set_queue_action(ctx, ofpact_get_SET_QUEUE(a)->queue_id); break; @@ -5559,6 +5566,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx, ctx->flow = *flow; ctx->base_flow = ctx->flow; ctx->base_flow.tun_id = 0; + ctx->base_flow.metadata = 0; ctx->base_flow.vlan_tci = initial_tci; ctx->rule = rule; ctx->packet = packet; diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at index ba8d309..044430c 100644 --- a/tests/ofp-actions.at +++ b/tests/ofp-actions.at @@ -1,7 +1,7 @@ AT_BANNER([OpenFlow actions]) AT_SETUP([OpenFlow 1.0 action translation]) -AT_KEYWORDS([OF1.0]) +AT_KEYWORDS([ofp-actions OF1.0]) AT_DATA([test-data], [dnl # actions=LOCAL 0000 0008 fffe 04d2 @@ -69,6 +69,12 @@ ffff 0018 00002320 0009 000000000000 c426384d49c53d60 # actions=set_tunnel64:0x885f3298 ffff 0018 00002320 0009 000000000000 00000000885f3298 +# actions=write_metadata:0xfedcba9876543210 +ffff 0020 00002320 0015 000000000000 fedcba9876543210 ffffffffffffffff + +# actions=write_metadata:0xfedcba9876543210/0xffff0000ffff0000 +ffff 0020 00002320 0015 000000000000 fedcba9876543210 ffff0000ffff0000 + # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[]) ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004 @@ -121,7 +127,7 @@ AT_CHECK( AT_CLEANUP AT_SETUP([OpenFlow 1.1 action translation]) -AT_KEYWORDS([OF1.1]) +AT_KEYWORDS([ofp-actions OF1.1]) AT_DATA([test-data], [dnl # actions=LOCAL 0000 0010 fffffffe 04d2 000000000000 @@ -183,6 +189,43 @@ ffff 0018 00002320 0009 000000000000 c426384d49c53d60 # actions=set_tunnel64:0x885f3298 ffff 0018 00002320 0009 000000000000 00000000885f3298 +dnl OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express the NXAST_WRITE_METADATA +dnl action instead, so parse-ofp11-actions will recognise and drop this action. +# actions=write_metadata:0xfedcba9876543210 +# 0: ff -> (none) +# 1: ff -> (none) +# 2: 00 -> (none) +# 3: 20 -> (none) +# 4: 00 -> (none) +# 5: 00 -> (none) +# 6: 23 -> (none) +# 7: 20 -> (none) +# 8: 00 -> (none) +# 9: 15 -> (none) +# 10: 00 -> (none) +# 11: 00 -> (none) +# 12: 00 -> (none) +# 13: 00 -> (none) +# 14: 00 -> (none) +# 15: 00 -> (none) +# 16: fe -> (none) +# 17: dc -> (none) +# 18: ba -> (none) +# 19: 98 -> (none) +# 20: 76 -> (none) +# 21: 54 -> (none) +# 22: 32 -> (none) +# 23: 10 -> (none) +# 24: ff -> (none) +# 25: ff -> (none) +# 26: ff -> (none) +# 27: ff -> (none) +# 28: ff -> (none) +# 29: ff -> (none) +# 30: ff -> (none) +# 31: ff -> (none) +ffff 0020 00002320 0015 000000000000 fedcba9876543210 ffffffffffffffff + # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[]) ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004 @@ -235,7 +278,7 @@ AT_CHECK( AT_CLEANUP AT_SETUP([OpenFlow 1.1 instruction translation]) -AT_KEYWORDS([OF1.1]) +AT_KEYWORDS([ofp-actions OF1.1]) AT_DATA([test-data], [dnl # actions=LOCAL 0004 0018 00000000 dnl @@ -269,10 +312,12 @@ dnl Goto-Table not supported yet. # bad OF1.1 instructions: OFPBIC_UNSUP_INST 0001 0008 01 000000 -dnl Write-Metadata not supported yet. -# bad OF1.1 instructions: OFPBIC_UNSUP_INST +# actions=write_metadata:0xfedcba9876543210 0002 0018 00000000 fedcba9876543210 ffffffffffffffff +# actions=write_metadata:0xfedcba9876543210/0xff00ff00ff00ff00 +0002 0018 00000000 fedcba9876543210 ff00ff00ff00ff00 + dnl Write-Metadata too short. # bad OF1.1 instructions: OFPBIC_BAD_LEN 0002 0010 00000000 fedcba9876543210 diff --git a/tests/ofproto.at b/tests/ofproto.at index d703fa8..4d423bd 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -723,6 +723,8 @@ AT_CAPTURE_FILE([monitor.log]) # Send a packet-out with a load action to set some metadata, and forward to controller AT_CHECK([ovs-ofctl packet-out br0 none 'load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]), controller' '0001020304050010203040501234']) +AT_CHECK([ovs-ofctl packet-out br0 none 'write_metadata(0xfafafafa5a5a5a5a), controller' '0001020304050010203040501234']) +AT_CHECK([ovs-ofctl packet-out br0 none 'write_metadata(0x1234ffff5678ffff/0xffff0000ffff0000), controller' '0001020304050010203040501234']) # Stop the monitor and check its output. ovs-appctl -t ovs-ofctl ofctl/barrier @@ -731,6 +733,10 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl NXT_PACKET_IN: total_len=14 in_port=NONE tun_id=0x0 metadata=0xfafafafa5a5a5a5a reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0 (via action) data_len=14 (unbuffered) priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0) +NXT_PACKET_IN: total_len=14 in_port=NONE tun_id=0x0 metadata=0xfafafafa5a5a5a5a reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0 (via action) data_len=14 (unbuffered) +priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0) +NXT_PACKET_IN: total_len=14 in_port=NONE tun_id=0x0 metadata=0x1234000056780000 reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0 (via action) data_len=14 (unbuffered) +priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0) OFPT_BARRIER_REPLY: ]) diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 3ca217b..8353841 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -577,6 +577,14 @@ When this field is specified in \fBadd-flow\fR, \fBadd-flows\fR, extension to OpenFlow, which as of this writing is only known to be implemented by Open vSwitch. . +.IP \fBmetadata=\fIvalue\fR[\fB/\fImask\fR] +Matches \fIvalue\fR either exactly or with optional \fImask\fR in the metadata +field. \fIvalue\fR and \fImask\fR are 64-bit integers, by default in decimal +(use a \fB0x\fR prefix to specify hexadecimal). Arbitrary \fImask\fR values +are allowed: a 1-bit in \fImask\fR indicates that the corresponding bit in +\fIvalue\fR must match exactly, and a 0-bit wildcards that bit. Matching on +metadata was added in Open vSwitch 1.8. +. .PP The following shorthand notations are also available: . @@ -867,6 +875,14 @@ Sets the IPv4 ToS/DSCP field to \fItos\fR. Valid values are between 0 and 255, inclusive. Note that the two lower reserved bits are never modified. . +.IP \fBwrite_metadata\fB:\fIvalue\fR[/\fImask\fR] +Updates the metadata field for the flow. If \fImask\fR is omitted, the +metadata field is set exactly to \fIvalue\fR; if \fImask\fR is specified, then +a 1-bit in \fImask\fR indicates that the corresponding bit in the metadata +field will be replaced with the corresponding bit from \fIvalue\fR. Both +\fIvalue\fR and \fImask\fR are 64-bit values that are decimal by default; use +a \fB0x\fR prefix to specify them in hexadecimal. This action was added in Open +vSwitch 1.8. .RE .IP The following actions are Nicira vendor extensions that, as of this writing, are -- 1.7.2.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev