diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | include/openflow/nicira-ext.h | 19 | ||||
-rw-r--r-- | lib/nx-match.c | 146 | ||||
-rw-r--r-- | lib/nx-match.h | 26 | ||||
-rw-r--r-- | lib/ofp-actions.c | 38 | ||||
-rw-r--r-- | lib/ofp-actions.h | 10 | ||||
-rw-r--r-- | lib/ofp-parse.c | 6 | ||||
-rw-r--r-- | lib/ofp-util.def | 2 | ||||
-rw-r--r-- | ofproto/ofproto-dpif.c | 19 | ||||
-rw-r--r-- | tests/ofproto-dpif.at | 20 | ||||
-rw-r--r-- | tests/ovs-ofctl.at | 2 | ||||
-rw-r--r-- | utilities/ovs-ofctl.8.in | 17 |
12 files changed, 307 insertions, 0 deletions
@@ -9,6 +9,8 @@ post-v1.10.0 - OpenFlow: * The "dec_mpls_ttl" and "set_mpls_ttl" actions from OpenFlow 1.1 and later are now implemented. + * New "stack" extension for use in actions, to push and pop from + NXM fields. v1.10.0 - xx xxx xxxx diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index cdb19520..f9b0af45 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -308,6 +308,8 @@ enum nx_action_subtype { NXAST_POP_MPLS, /* struct nx_action_pop_mpls */ NXAST_SET_MPLS_TTL, /* struct nx_action_ttl */ NXAST_DEC_MPLS_TTL, /* struct nx_action_header */ + NXAST_STACK_PUSH, /* struct nx_action_stack */ + NXAST_STACK_POP, /* struct nx_action_stack */ }; /* Header for Nicira-defined actions. */ @@ -562,6 +564,23 @@ struct nx_action_reg_load { }; OFP_ASSERT(sizeof(struct nx_action_reg_load) == 24); +/* Action structure for NXAST_STACK_PUSH and NXAST_STACK_POP. + * + * Pushes (or pops) field[offset: offset + n_bits] to (or from) + * top of the stack. + */ +struct nx_action_stack { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* Length is 16. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* NXAST_REG_PUSH or NXAST_REG_POP. */ + ovs_be16 offset; /* Bit offset into the field. */ + ovs_be32 field; /* The field used for push or pop. */ + ovs_be16 n_bits; /* (n_bits + 1) bits of the field. */ + uint8_t zero[6]; /* Reserved, must be zero. */ +}; +OFP_ASSERT(sizeof(struct nx_action_stack) == 24); + /* Action structure for NXAST_NOTE. * * This action has no effect. It is variable length. The switch does not diff --git a/lib/nx-match.c b/lib/nx-match.c index e5545dea..6efc94df 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1312,3 +1312,149 @@ nxm_reg_load(const struct mf_subfield *dst, uint64_t src_data, sizeof src_data_be * 8); mf_write_subfield_flow(dst, &src_subvalue, flow); } + +/* nxm_parse_stack_action, works for both push() and pop(). */ +void +nxm_parse_stack_action(struct ofpact_stack *stack_action, const char *s) +{ + s = mf_parse_subfield(&stack_action->subfield, s); + if (*s != '\0') { + ovs_fatal(0, "%s: trailing garbage following push or pop", s); + } +} + +void +nxm_format_stack_push(const struct ofpact_stack *push, struct ds *s) +{ + ds_put_cstr(s, "push:"); + mf_format_subfield(&push->subfield, s); +} + +void +nxm_format_stack_pop(const struct ofpact_stack *pop, struct ds *s) +{ + ds_put_cstr(s, "pop:"); + mf_format_subfield(&pop->subfield, s); +} + +/* Common set for both push and pop actions. */ +static void +stack_action_from_openflow__(const struct nx_action_stack *nasp, + struct ofpact_stack *stack_action) +{ + stack_action->subfield.field = mf_from_nxm_header(ntohl(nasp->field)); + stack_action->subfield.ofs = ntohs(nasp->offset); + stack_action->subfield.n_bits = ntohs(nasp->n_bits); +} + +static void +nxm_stack_to_nxast__(const struct ofpact_stack *stack_action, + struct nx_action_stack *nasp) +{ + nasp->offset = htons(stack_action->subfield.ofs); + nasp->n_bits = htons(stack_action->subfield.n_bits); + nasp->field = htonl(stack_action->subfield.field->nxm_header); +} + +enum ofperr +nxm_stack_push_from_openflow(const struct nx_action_stack *nasp, + struct ofpbuf *ofpacts) +{ + struct ofpact_stack *push; + + push = ofpact_put_STACK_PUSH(ofpacts); + stack_action_from_openflow__(nasp, push); + + return nxm_stack_push_check(push, NULL); +} + +enum ofperr +nxm_stack_pop_from_openflow(const struct nx_action_stack *nasp, + struct ofpbuf *ofpacts) +{ + struct ofpact_stack *pop; + + pop = ofpact_put_STACK_POP(ofpacts); + stack_action_from_openflow__(nasp, pop); + + return nxm_stack_pop_check(pop, NULL); +} + +enum ofperr +nxm_stack_push_check(const struct ofpact_stack *push, + const struct flow *flow) +{ + return mf_check_src(&push->subfield, flow); +} + +enum ofperr +nxm_stack_pop_check(const struct ofpact_stack *pop, + const struct flow *flow) +{ + return mf_check_dst(&pop->subfield, flow); +} + +void +nxm_stack_push_to_nxast(const struct ofpact_stack *stack, + struct ofpbuf *openflow) +{ + nxm_stack_to_nxast__(stack, ofputil_put_NXAST_STACK_PUSH(openflow)); +} + +void +nxm_stack_pop_to_nxast(const struct ofpact_stack *stack, + struct ofpbuf *openflow) +{ + nxm_stack_to_nxast__(stack, ofputil_put_NXAST_STACK_POP(openflow)); +} + +/* nxm_execute_stack_push(), nxm_execute_stack_pop(). */ +static void +nx_stack_push(struct ofpbuf *stack, union mf_subvalue *v) +{ + ofpbuf_put(stack, v, sizeof *v); +} + +static union mf_subvalue * +nx_stack_pop(struct ofpbuf *stack) +{ + union mf_subvalue *v = NULL; + + if (stack->size) { + stack->size -= sizeof *v; + v = (union mf_subvalue *) ofpbuf_tail(stack); + } + + return v; +} + +void +nxm_execute_stack_push(const struct ofpact_stack *push, + const struct flow *flow, struct ofpbuf *stack) +{ + union mf_subvalue dst_value; + + mf_read_subfield(&push->subfield, flow, &dst_value); + nx_stack_push(stack, &dst_value); +} + +void +nxm_execute_stack_pop(const struct ofpact_stack *pop, + struct flow *flow, struct ofpbuf *stack) +{ + union mf_subvalue *src_value; + + src_value = nx_stack_pop(stack); + + /* Only pop if stack is not empty. Otherwise, give warning. */ + if (src_value) { + mf_write_subfield_flow(&pop->subfield, src_value, flow); + } else { + if (!VLOG_DROP_WARN(&rl)) { + char *flow_str = flow_to_string(flow); + VLOG_WARN_RL(&rl, "Failed to pop from an empty stack. On flow \n" + " %s", flow_str); + free(flow_str); + } + } +} diff --git a/lib/nx-match.h b/lib/nx-match.h index 6a57297c..7d316d80 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -29,10 +29,12 @@ struct match; struct mf_subfield; struct ofpact_reg_move; struct ofpact_reg_load; +struct ofpact_stack; struct ofpbuf; struct nx_action_reg_load; struct nx_action_reg_move; + /* Nicira Extended Match (NXM) flexible flow match helper functions. * * See include/openflow/nicira-ext.h for NXM specification. @@ -83,6 +85,30 @@ void nxm_execute_reg_load(const struct ofpact_reg_load *, struct flow *); void nxm_reg_load(const struct mf_subfield *, uint64_t src_data, struct flow *); +void nxm_parse_stack_action(struct ofpact_stack *, const char *); + +void nxm_format_stack_push(const struct ofpact_stack *, struct ds *); +void nxm_format_stack_pop(const struct ofpact_stack *, struct ds *); + +enum ofperr nxm_stack_push_from_openflow(const struct nx_action_stack *, + struct ofpbuf *ofpacts); +enum ofperr nxm_stack_pop_from_openflow(const struct nx_action_stack *, + struct ofpbuf *ofpacts); +enum ofperr nxm_stack_push_check(const struct ofpact_stack *, + const struct flow *); +enum ofperr nxm_stack_pop_check(const struct ofpact_stack *, + const struct flow *); + +void nxm_stack_push_to_nxast(const struct ofpact_stack *, + struct ofpbuf *openflow); +void nxm_stack_pop_to_nxast(const struct ofpact_stack *, + struct ofpbuf *openflow); + +void nxm_execute_stack_push(const struct ofpact_stack *, + const struct flow *, struct ofpbuf *); +void nxm_execute_stack_pop(const struct ofpact_stack *, + struct flow *, struct ofpbuf *); + int nxm_field_bytes(uint32_t header); int nxm_field_bits(uint32_t header); diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 6dabc5a4..d405d2d4 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -339,6 +339,16 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, (const struct nx_action_reg_load *) a, out); break; + case OFPUTIL_NXAST_STACK_PUSH: + error = nxm_stack_push_from_openflow( + (const struct nx_action_stack *) a, out); + break; + + case OFPUTIL_NXAST_STACK_POP: + error = nxm_stack_pop_from_openflow( + (const struct nx_action_stack *) a, out); + break; + case OFPUTIL_NXAST_NOTE: nan = (const struct nx_action_note *) a; note_from_openflow(nan, out); @@ -1155,6 +1165,12 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports, return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow); } + case OFPACT_STACK_PUSH: + return nxm_stack_push_check(ofpact_get_STACK_PUSH(a), flow); + + case OFPACT_STACK_POP: + return nxm_stack_pop_check(ofpact_get_STACK_POP(a), flow); + case OFPACT_DEC_TTL: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: @@ -1401,6 +1417,14 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) nxm_reg_load_to_nxast(ofpact_get_REG_LOAD(a), out); break; + case OFPACT_STACK_PUSH: + nxm_stack_push_to_nxast(ofpact_get_STACK_PUSH(a), out); + break; + + case OFPACT_STACK_POP: + nxm_stack_pop_to_nxast(ofpact_get_STACK_POP(a), out); + break; + case OFPACT_DEC_TTL: ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out); break; @@ -1580,6 +1604,8 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out) case OFPACT_BUNDLE: case OFPACT_REG_MOVE: case OFPACT_REG_LOAD: + case OFPACT_STACK_PUSH: + case OFPACT_STACK_POP: case OFPACT_DEC_TTL: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: @@ -1748,6 +1774,8 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) case OFPACT_BUNDLE: case OFPACT_REG_MOVE: case OFPACT_REG_LOAD: + case OFPACT_STACK_PUSH: + case OFPACT_STACK_POP: case OFPACT_SET_TUNNEL: case OFPACT_POP_QUEUE: case OFPACT_FIN_TIMEOUT: @@ -1867,6 +1895,8 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port) case OFPACT_SET_L4_DST_PORT: case OFPACT_REG_MOVE: case OFPACT_REG_LOAD: + case OFPACT_STACK_PUSH: + case OFPACT_STACK_POP: case OFPACT_DEC_TTL: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: @@ -2088,6 +2118,14 @@ ofpact_format(const struct ofpact *a, struct ds *s) nxm_format_reg_load(ofpact_get_REG_LOAD(a), s); break; + case OFPACT_STACK_PUSH: + nxm_format_stack_push(ofpact_get_STACK_PUSH(a), s); + break; + + case OFPACT_STACK_POP: + nxm_format_stack_pop(ofpact_get_STACK_POP(a), s); + break; + case OFPACT_DEC_TTL: print_dec_ttl(ofpact_get_DEC_TTL(a), s); break; diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 2d934f98..0189c8ae 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -70,6 +70,8 @@ DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port, ofpact) \ DEFINE_OFPACT(REG_MOVE, ofpact_reg_move, ofpact) \ DEFINE_OFPACT(REG_LOAD, ofpact_reg_load, ofpact) \ + DEFINE_OFPACT(STACK_PUSH, ofpact_stack, ofpact) \ + DEFINE_OFPACT(STACK_POP, ofpact_stack, ofpact) \ DEFINE_OFPACT(DEC_TTL, ofpact_cnt_ids, cnt_ids) \ DEFINE_OFPACT(SET_MPLS_TTL, ofpact_mpls_ttl, ofpact) \ DEFINE_OFPACT(DEC_MPLS_TTL, ofpact_null, ofpact) \ @@ -304,6 +306,14 @@ struct ofpact_reg_move { struct mf_subfield dst; }; +/* OFPACT_STACK_PUSH. + * + * Used for NXAST_STACK_PUSH and NXAST_STACK_POP. */ +struct ofpact_stack { + struct ofpact ofpact; + struct mf_subfield subfield; +}; + /* OFPACT_REG_LOAD. * * Used for NXAST_REG_LOAD, OFPAT12_SET_FIELD. */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index f1802048..e8abc9f6 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -591,6 +591,12 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, ofpact_put_POP_MPLS(ofpacts)->ethertype = htons(str_to_u16(arg, "pop_mpls")); break; + case OFPUTIL_NXAST_STACK_PUSH: + nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg); + break; + case OFPUTIL_NXAST_STACK_POP: + nxm_parse_stack_action(ofpact_put_STACK_POP(ofpacts), arg); + break; } } diff --git a/lib/ofp-util.def b/lib/ofp-util.def index 439d34ed..b7dde483 100644 --- a/lib/ofp-util.def +++ b/lib/ofp-util.def @@ -50,6 +50,8 @@ NXAST_ACTION(NXAST_SET_QUEUE, nx_action_set_queue, 0, "set_queue") NXAST_ACTION(NXAST_POP_QUEUE, nx_action_pop_queue, 0, "pop_queue") NXAST_ACTION(NXAST_REG_MOVE, nx_action_reg_move, 0, "move") NXAST_ACTION(NXAST_REG_LOAD, nx_action_reg_load, 0, "load") +NXAST_ACTION(NXAST_STACK_PUSH, nx_action_stack, 0, "push") +NXAST_ACTION(NXAST_STACK_POP, nx_action_stack, 0, "pop") NXAST_ACTION(NXAST_NOTE, nx_action_note, 1, "note") NXAST_ACTION(NXAST_SET_TUNNEL64, nx_action_set_tunnel64, 0, "set_tunnel64") NXAST_ACTION(NXAST_MULTIPATH, nx_action_multipath, 0, "multipath") diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index f37d8406..10e4e23b 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -216,6 +216,11 @@ struct action_xlate_ctx { * this flow when actions change header fields. */ struct flow flow; + /* stack for the push and pop actions. + * Each stack element is of the type "union mf_subvalue". */ + struct ofpbuf stack; + union mf_subvalue init_stack[1024 / sizeof(union mf_subvalue)]; + /* The packet corresponding to 'flow', or a null pointer if we are * revalidating without a packet to refer to. */ const struct ofpbuf *packet; @@ -6404,6 +6409,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->flow); break; + case OFPACT_STACK_PUSH: + nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), &ctx->flow, + &ctx->stack); + break; + + case OFPACT_STACK_POP: + nxm_execute_stack_pop(ofpact_get_STACK_POP(a), &ctx->flow, + &ctx->stack); + break; + case OFPACT_PUSH_MPLS: execute_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)->ethertype); break; @@ -6573,6 +6588,8 @@ xlate_actions(struct action_xlate_ctx *ctx, ctx->table_id = 0; ctx->exit = false; + ofpbuf_use_stub(&ctx->stack, ctx->init_stack, sizeof ctx->init_stack); + if (ctx->ofproto->has_mirrors || hit_resubmit_limit) { /* Do this conditionally because the copy is expensive enough that it * shows up in profiles. */ @@ -6657,6 +6674,8 @@ xlate_actions(struct action_xlate_ctx *ctx, } fix_sflow_action(ctx); } + + ofpbuf_uninit(&ctx->stack); } /* Translates the 'ofpacts_len' bytes of "struct ofpact"s starting at 'ofpacts' diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index b795f561..7915792c 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -45,6 +45,7 @@ in_port=12 actions=load:0x10->NXM_NX_REG0[[]],load:0x11->NXM_NX_REG1[[]],load:0x in_port=13 actions=load:0x13->NXM_NX_REG3[[]],load:0x14->NXM_NX_REG4[[]],load:0x15->NXM_NX_REG5[[]] in_port=14 actions=load:0x16->NXM_NX_REG6[[]],load:0x17->NXM_NX_REG7[[]] in_port=15,reg0=0x10,reg1=0x11,reg2=0x12,reg3=0x13,reg4=0x14,reg5=0x15,reg6=0x16,reg7=0x17 actions=output:33 + ]) AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) @@ -54,6 +55,25 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif - push-pop]) +OVS_VSWITCHD_START +ADD_OF_PORTS([br0], [20], [21], [22], [33], [90]) +AT_DATA([flows.txt], [dnl +in_port=90 actions=load:20->NXM_NX_REG0[[0..7]],load:21->NXM_NX_REG1[[0..7]],load:22->NXM_NX_REG2[[0..7]], load:33->NXM_NX_REG3[[0..7]], push:NXM_NX_REG0[[]], push:NXM_NX_REG1[[0..7]],push:NXM_NX_REG2[[0..15]], push:NXM_NX_REG3[[]], resubmit:2, resubmit:3, resubmit:4, resubmit:5 +in_port=2 actions=pop:NXM_NX_REG0[[0..7]],output:NXM_NX_REG0[[]] +in_port=3 actions=pop:NXM_NX_REG1[[0..7]],output:NXM_NX_REG1[[]] +in_port=4 actions=pop:NXM_NX_REG2[[0..15]],output:NXM_NX_REG2[[]] +in_port=5 actions=pop:NXM_NX_REG3[[]],output:NXM_NX_REG3[[]] + +]) +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) +AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: 33,22,21,20 +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto-dpif - output]) OVS_VSWITCHD_START ADD_OF_PORTS([br0], [1], [9], [10], [11], [55], [66], [77], [88]) diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 7395fd14..075f2e49 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -243,6 +243,7 @@ tun_id=0x1234,cookie=0x5678,actions=flood 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[] actions=move:OXM_OF_ETH_DST[]->OXM_OF_ETH_SRC[] +actions=push:NXM_NX_REG0[0..31],pop:NXM_NX_REG0[] vlan_tci=0x1123/0x1fff,actions=drop ]]) AT_CHECK([ovs-ofctl -F nxm -mmm parse-flows flows.txt], [0], [stdout], [stderr]) @@ -271,6 +272,7 @@ NXT_FLOW_MOD: ADD NXM_NX_TUN_ID(0000000000001234) cookie:0x5678 actions=FLOOD 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:0x37->NXM_NX_REG2[],move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31],move:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[] NXT_FLOW_MOD: ADD <any> actions=move:NXM_OF_ETH_DST[]->NXM_OF_ETH_SRC[] +NXT_FLOW_MOD: ADD <any> actions=push:NXM_NX_REG0[],pop:NXM_NX_REG0[] NXT_FLOW_MOD: ADD NXM_OF_VLAN_TCI_W(1123/1fff) actions=drop ]]) AT_CLEANUP diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 609df9f2..e7d9cfb5 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -1063,6 +1063,23 @@ in field \fIdst\fR. 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. . +.IP "\fBpush:\fIsrc\fB[\fIstart\fB..\fIend\fB]" +Pushes \fIstart\fR to \fIend\fR bits inclusive, in fields +on top of the stack. +.IP +Example: \fBpush:NXM_NX_REG2[0..5]\fR push the value stored in register +2 bits 0 through 5, inclusive, on to the internal stack. +. +.IP "\fBpop:\fIdst\fB[\fIstart\fB..\fIend\fB]" +Pops from the top of the stack, retrieves the \fIstart\fR to \fIend\fR bits +inclusive, from the value popped and store them into the corresponding +bits in \fIdst\fR. +. +.IP +Example: \fBpop:NXM_NX_REG2[0..5]\fR pops the value from top of the stack. +Set register 2 bits 0 through 5, inclusive, based on bits 0 through 5 from the +value just popped. +. .IP "\fBset_field:\fIvalue\fB\->\fIdst" Writes the literal \fIvalue\fR into the field \fIdst\fR, which should be specified as a name used for matching. (This is similar to |