+ union mf_subvalue src_subvalue;
+ ovs_be64 src_data_be = htonll(src_data);
+
+ bitwise_copy(&src_data_be, sizeof src_data_be, 0,
+ &src_subvalue, sizeof src_subvalue, 0,
+ sizeof src_data_be * 8);
+ mf_write_subfield_flow(dst, &src_subvalue, flow);
+}
+\f
+/* 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);
+}