[ovs-dev] [PATCH 09/16] Add support for copy_ttl_out action
Simon Horman
horms at verge.net.au
Wed Feb 6 13:54:00 UTC 2013
This adds support for the OpenFlow 1.1+ copy_ttl_out action.
And also adds an NX copy_ttl_out action.
The implementation does not support copying in the case where the outermost
header is IP as it is unclear to me that Open vSwtich has a notion of an
inner IP header to copy the TLL from.
The handling of the TTL modification is entirely handled in userspace.
Reviewed-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Simon Horman <horms at verge.net.au>
---
v2.18
* No change
v2.17
* Rebase
- Update FLOW_WC_SEQ in compose_output_action__()
* As suggested by Ben Pfaff
- Rename compose_copy_ttl_out_action as execute_copy_ttl_out_action
v2.16
* No change
v2.15
* Rebase
* Mask off wc.masks.mpls_inner_lse in ofputil_normalize_match__()
v2.14
* No change
v2.13
* Remove bogus test. copy_ttl_out from IP to MPLS only makes sense
if the dl_type of the encapsulated frame is known, which implies
that the original frame was IP and an mpls_push action has been applied.
v2.10 - v2.12
* No change
v2.9
* Increment FLOW_WC_SEQ
* Update tests for upstream changes
v2.8
* No change
v2.7
* Encode action as OFP11 action in OFP11+ messages
v2.6
* Non-trivial rebase
v2.5
* First post
---
include/openflow/nicira-ext.h | 1 +
lib/flow.c | 15 +++++----------
lib/flow.h | 7 ++++---
lib/match.c | 2 +-
lib/nx-match.c | 2 +-
lib/ofp-actions.c | 23 +++++++++++++++++++++++
lib/ofp-actions.h | 1 +
lib/ofp-parse.c | 5 +++++
lib/ofp-util.c | 5 +++--
lib/ofp-util.def | 2 ++
ofproto/ofproto-dpif.c | 25 ++++++++++++++++++++++++-
tests/ofproto-dpif.at | 23 ++++++++++++++++++++++-
utilities/ovs-ofctl.8.in | 7 +++++++
13 files changed, 99 insertions(+), 19 deletions(-)
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index e34b5e6..a6930fd 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -306,6 +306,7 @@ enum nx_action_subtype {
NXAST_WRITE_METADATA, /* struct nx_action_write_metadata */
NXAST_PUSH_MPLS, /* struct nx_action_push_mpls */
NXAST_POP_MPLS, /* struct nx_action_pop_mpls */
+ NXAST_COPY_TTL_OUT, /* struct nx_action_header */
NXAST_SET_MPLS_TTL, /* struct nx_action_ttl */
NXAST_DEC_MPLS_TTL, /* struct nx_action_header */
};
diff --git a/lib/flow.c b/lib/flow.c
index fc8a30f..c8f6c82 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -99,9 +99,12 @@ parse_mpls(struct ofpbuf *b, struct flow *flow)
struct mpls_hdr *mh;
while ((mh = ofpbuf_try_pull(b, sizeof *mh))) {
- if (flow->mpls_depth++ == 0) {
+ if (flow->mpls_depth == 0) {
flow->mpls_lse = mh->mpls_lse;
+ } else if (flow->mpls_depth == 1) {
+ flow->inner_mpls_lse = mh->mpls_lse;
}
+ flow->mpls_depth++;
if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) {
break;
}
@@ -511,7 +514,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
void
flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
fmd->tun_id = flow->tunnel.tun_id;
fmd->metadata = flow->metadata;
@@ -843,14 +846,6 @@ flow_set_mpls_label(struct flow *flow, ovs_be32 label)
set_mpls_lse_label(&flow->mpls_lse, label);
}
-/* Sets the MPLS TTL that 'flow' matches to 'ttl', which should be in the
- * range 0...255. */
-void
-flow_set_mpls_ttl(struct flow *flow, uint8_t ttl)
-{
- set_mpls_lse_ttl(&flow->mpls_lse, ttl);
-}
-
/* Sets the MPLS TC that 'flow' matches to 'tc', which should be in the
* range 0...7. */
void
diff --git a/lib/flow.h b/lib/flow.h
index e6da480..5e88b57 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -36,7 +36,7 @@ struct ofpbuf;
/* This sequence number should be incremented whenever anything involving flows
* or the wildcarding of flows changes. This will cause build assertion
* failures in places which likely need to be updated. */
-#define FLOW_WC_SEQ 19
+#define FLOW_WC_SEQ 20
#define FLOW_N_REGS 8
BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
@@ -92,6 +92,7 @@ struct flow {
is the datapath port number. */
uint32_t skb_mark; /* Packet mark. */
ovs_be32 mpls_lse; /* MPLS label stack entry. */
+ ovs_be32 inner_mpls_lse; /* Inner MPLS label stack entry. */
uint16_t mpls_depth; /* Depth of MPLS stack. */
ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
ovs_be16 dl_type; /* Ethernet frame type. */
@@ -106,7 +107,7 @@ struct flow {
uint8_t arp_tha[6]; /* ARP/ND target hardware address. */
uint8_t nw_ttl; /* IP TTL/Hop Limit. */
uint8_t nw_frag; /* FLOW_FRAG_* flags. */
- uint8_t zeros[4];
+ uint8_t zeros[0];
};
BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
@@ -114,7 +115,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 160 &&
- FLOW_WC_SEQ == 19);
+ FLOW_WC_SEQ == 20);
/* Represents the metadata fields of struct flow. */
struct flow_metadata {
diff --git a/lib/match.c b/lib/match.c
index 2d359eb..c47c70a 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -850,7 +850,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
if (priority != OFP_DEFAULT_PRIORITY) {
ds_put_format(s, "priority=%u,", priority);
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 4ff516e..c83b99c 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -573,7 +573,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
int match_len;
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
/* Metadata. */
if (match->wc.masks.in_port) {
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 6dabc5a..74631e4 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -406,6 +406,10 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
break;
}
+ case OFPUTIL_NXAST_COPY_TTL_OUT:
+ ofpact_put_COPY_TTL_OUT(out);
+ break;
+
case OFPUTIL_NXAST_SET_MPLS_TTL: {
struct nx_action_mpls_ttl *nxamt = (struct nx_action_mpls_ttl *)a;
ofpact_put_SET_MPLS_TTL(out)->ttl = nxamt->ttl;
@@ -796,6 +800,10 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
return nxm_reg_load_from_openflow12_set_field(
(const struct ofp12_action_set_field *)a, out);
+ case OFPUTIL_OFPAT11_COPY_TTL_OUT:
+ ofpact_put_COPY_TTL_OUT(out);
+ break;
+
case OFPUTIL_OFPAT11_SET_MPLS_TTL: {
struct ofp11_action_mpls_ttl *oamt = (struct ofp11_action_mpls_ttl *)a;
ofpact_put_SET_MPLS_TTL(out)->ttl = oamt->mpls_ttl;
@@ -1156,6 +1164,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
}
case OFPACT_DEC_TTL:
+ case OFPACT_COPY_TTL_OUT:
case OFPACT_SET_MPLS_TTL:
case OFPACT_DEC_MPLS_TTL:
case OFPACT_SET_TUNNEL:
@@ -1405,6 +1414,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out);
break;
+ case OFPACT_COPY_TTL_OUT:
+ ofputil_put_NXAST_COPY_TTL_OUT(out);
+ break;
+
case OFPACT_SET_MPLS_TTL:
ofputil_put_NXAST_SET_MPLS_TTL(out)->ttl
= ofpact_get_SET_MPLS_TTL(a)->ttl;
@@ -1581,6 +1594,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
case OFPACT_REG_MOVE:
case OFPACT_REG_LOAD:
case OFPACT_DEC_TTL:
+ case OFPACT_COPY_TTL_OUT:
case OFPACT_SET_MPLS_TTL:
case OFPACT_DEC_MPLS_TTL:
case OFPACT_SET_TUNNEL:
@@ -1715,6 +1729,10 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out);
break;
+ case OFPACT_COPY_TTL_OUT:
+ ofputil_put_OFPAT11_COPY_TTL_OUT(out);
+ break;
+
case OFPACT_SET_MPLS_TTL:
ofputil_put_OFPAT11_SET_MPLS_TTL(out)->mpls_ttl
= ofpact_get_SET_MPLS_TTL(a)->ttl;
@@ -1868,6 +1886,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
case OFPACT_REG_MOVE:
case OFPACT_REG_LOAD:
case OFPACT_DEC_TTL:
+ case OFPACT_COPY_TTL_OUT:
case OFPACT_SET_MPLS_TTL:
case OFPACT_DEC_MPLS_TTL:
case OFPACT_SET_TUNNEL:
@@ -2092,6 +2111,10 @@ ofpact_format(const struct ofpact *a, struct ds *s)
print_dec_ttl(ofpact_get_DEC_TTL(a), s);
break;
+ case OFPACT_COPY_TTL_OUT:
+ ds_put_cstr(s, "copy_ttl_out");
+ break;
+
case OFPACT_SET_MPLS_TTL:
ds_put_format(s, "set_mpls_ttl(%"PRIu8")",
ofpact_get_SET_MPLS_TTL(a)->ttl);
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 2d934f9..d76073f 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -73,6 +73,7 @@
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) \
+ DEFINE_OFPACT(COPY_TTL_OUT, ofpact_null, ofpact) \
DEFINE_OFPACT(PUSH_MPLS, ofpact_push_mpls, ofpact) \
DEFINE_OFPACT(POP_MPLS, ofpact_pop_mpls, ofpact) \
\
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index f180204..69daa99 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -572,6 +572,11 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
ofpact_put_DEC_MPLS_TTL(ofpacts);
break;
+ case OFPUTIL_OFPAT11_COPY_TTL_OUT:
+ case OFPUTIL_NXAST_COPY_TTL_OUT:
+ ofpact_put_COPY_TTL_OUT(ofpacts);
+ break;
+
case OFPUTIL_NXAST_FIN_TIMEOUT:
parse_fin_timeout(ofpacts, arg);
break;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index cd51ef7..50267f2 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -84,7 +84,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
void
ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
@@ -1058,7 +1058,7 @@ ofputil_usable_protocols(const struct match *match)
{
const struct flow_wildcards *wc = &match->wc;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
/* tunnel params other than tun_id can't be sent in a flow_mod */
if (!tun_parms_fully_wildcarded(wc)) {
@@ -4391,6 +4391,7 @@ ofputil_normalize_match__(struct match *match, bool may_log)
}
if (!(may_match & MAY_MPLS)) {
wc.masks.mpls_lse = htonl(0);
+ wc.masks.inner_mpls_lse = htonl(0);
wc.masks.mpls_depth = 0;
}
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 439d34e..d3f6deb 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -30,6 +30,7 @@ OFPAT11_ACTION(OFPAT11_SET_NW_TOS, ofp_action_nw_tos, 0, "mod_nw_tos")
//OFPAT11_ACTION(OFPAT11_SET_NW_ECN, ofp11_action_nw_ecn, "0, mod_nw_ecn")
OFPAT11_ACTION(OFPAT11_SET_TP_SRC, ofp_action_tp_port, 0, "mod_tp_src")
OFPAT11_ACTION(OFPAT11_SET_TP_DST, ofp_action_tp_port, 0, "mod_tp_dst")
+OFPAT11_ACTION(OFPAT11_COPY_TTL_OUT, ofp_action_header, 0, "copy_ttl_out")
OFPAT11_ACTION(OFPAT11_SET_MPLS_TTL, ofp11_action_mpls_ttl, 0, "set_mpls_ttl")
OFPAT11_ACTION(OFPAT11_DEC_MPLS_TTL, ofp_action_header, 0, "dec_mpls_ttl")
OFPAT11_ACTION(OFPAT11_PUSH_VLAN, ofp11_action_push, 0, "push_vlan")
@@ -65,6 +66,7 @@ NXAST_ACTION(NXAST_CONTROLLER, nx_action_controller, 0, "controller")
NXAST_ACTION(NXAST_DEC_TTL_CNT_IDS, nx_action_cnt_ids, 1, NULL)
NXAST_ACTION(NXAST_WRITE_METADATA, nx_action_write_metadata, 0,
"write_metadata")
+NXAST_ACTION(NXAST_COPY_TTL_OUT, nx_action_header, 0, "copy_ttl_out")
NXAST_ACTION(NXAST_SET_MPLS_TTL, nx_action_mpls_ttl, 0, "set_mpls_ttl")
NXAST_ACTION(NXAST_DEC_MPLS_TTL, nx_action_header, 0, "dec_mpls_ttl")
NXAST_ACTION(NXAST_PUSH_MPLS, nx_action_push_mpls, 0, "push_mpls")
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 4fc03db..ebd75e9 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5831,7 +5831,7 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
/* If 'struct flow' gets additional metadata, we'll need to zero it out
* before traversing a patch port. */
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
if (!ofport) {
xlate_report(ctx, "Nonexistent output port");
@@ -6174,6 +6174,25 @@ compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
}
static void
+execute_copy_ttl_out_action(struct action_xlate_ctx *ctx)
+{
+ if (ctx->flow.dl_type != htons(ETH_TYPE_MPLS) &&
+ ctx->flow.dl_type != htons(ETH_TYPE_MPLS_MCAST)) {
+ /* Copying TTL to IP is not supported */
+ return;
+ }
+
+ if (ctx->flow.mpls_depth > 1) {
+ /* MPLS -> MPLS */
+ set_mpls_lse_ttl(&ctx->flow.mpls_lse,
+ mpls_lse_to_ttl(ctx->flow.inner_mpls_lse));
+ } else {
+ /* IP -> MPLS */
+ set_mpls_lse_ttl(&ctx->flow.mpls_lse, ctx->flow.nw_ttl);
+ }
+}
+
+static void
execute_set_mpls_ttl_action(struct action_xlate_ctx *ctx, uint8_t ttl)
{
if (eth_type_mpls(ctx->flow.dl_type)) {
@@ -6552,6 +6571,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
execute_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype);
break;
+ case OFPACT_COPY_TTL_OUT:
+ execute_copy_ttl_out_action(ctx);
+ break;
+
case OFPACT_SET_MPLS_TTL:
execute_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl);
break;
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index b3600ca..b6aaefd 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -237,6 +237,7 @@ cookie=0xa dl_src=40:44:44:44:44:45 actions=push_mpls:0x8847,load:10->OXM_OF_MPL
cookie=0xa dl_src=40:44:44:44:44:46 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),controller
cookie=0xa dl_src=40:44:44:44:44:47 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,set_mpls_ttl(10),controller
cookie=0xa dl_src=40:44:44:44:44:48 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),dec_mpls_ttl,controller
+cookie=0xa dl_src=40:44:44:44:44:49 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),dec_mpls_ttl,copy_ttl_out,controller
cookie=0xb dl_src=50:55:55:55:55:55 dl_type=0x8847 actions=load:1000->OXM_OF_MPLS_LABEL[[]],controller
cookie=0xd dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,controller
cookie=0xc dl_src=70:77:77:77:77:77 actions=push_mpls:0x8848,load:1000->OXM_OF_MPLS_LABEL[[]],load:7->OXM_OF_MPLS_TC[[]],controller
@@ -420,6 +421,26 @@ dnl Modified MPLS controller action.
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:49,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07
+])
+
+
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:48,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
done
@@ -473,7 +494,6 @@ NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len
mplsm(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07
])
-
dnl Modified MPLS pop action.
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
@@ -584,6 +604,7 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:46 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),CONTROLLER:65535
cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:47 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,set_mpls_ttl(10),CONTROLLER:65535
cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:48 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),dec_mpls_ttl,CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:49 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),dec_mpls_ttl,copy_ttl_out,CONTROLLER:65535
cookie=0xb, n_packets=3, n_bytes=180, dl_src=50:55:55:55:55:55,dl_type=0x8847 actions=load:0x3e8->OXM_OF_MPLS_LABEL[[]],CONTROLLER:65535
cookie=0xc, n_packets=3, n_bytes=180, dl_src=70:77:77:77:77:77 actions=push_mpls:0x8848,load:0x3e8->OXM_OF_MPLS_LABEL[[]],load:0x7->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=180, dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,CONTROLLER:65535
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 609df9f..a800996 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -1031,6 +1031,13 @@ Processing the current set of actions then stops. However, if the current
set of actions was reached through ``resubmit'' then remaining actions in
outer levels resume processing.
.
+.IP \fBcopy_ttl_out\fR
+Copy the TTL from the next-to-outermost to the outermost header with TTL.
+The implementation supports copying to an outer MPLS header from either the
+next-to-outermost MPLS header, or if the MPLS stack only has a depth of one
+the TTL of the outer-most IP header - the TTL of an IPv4 header or hop limit
+of an IPv6 header.
+.
.IP \fBnote:\fR[\fIhh\fR]...
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
--
1.7.10.4
More information about the dev
mailing list