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 <yamah...@valinux.co.jp> Signed-off-by: Simon Horman <ho...@verge.net.au> --- 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.12 * No change v2.10 * 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 | 6 ++++-- 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 | 4 ++-- lib/ofp-util.def | 2 ++ ofproto/ofproto-dpif.c | 23 +++++++++++++++++++++++ tests/ofproto-dpif.at | 23 ++++++++++++++++++++++- utilities/ovs-ofctl.8.in | 7 +++++++ 13 files changed, 96 insertions(+), 10 deletions(-) diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index bc7fb1e..a682e60 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 2af94fa..674e451 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -100,7 +100,9 @@ parse_remaining_mpls(struct ofpbuf *b, struct flow *flow) struct mpls_hdr *mh; while ((mh = ofpbuf_try_pull(b, sizeof *mh)) && !(mh->mpls_lse & htonl(MPLS_BOS_MASK))) { - flow->mpls_depth++; + if (flow->mpls_depth++ == 1) { + flow->inner_mpls_lse = mh->mpls_lse; + } } } @@ -522,7 +524,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; diff --git a/lib/flow.h b/lib/flow.h index 3078332..07b9f8b 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 5cab7f0..3824a4b 100644 --- a/lib/match.c +++ b/lib/match.c @@ -851,7 +851,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 64b93a4..c364ea5 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 58eae55..f3bbc51 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -411,6 +411,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; @@ -801,6 +805,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; @@ -1161,6 +1169,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: @@ -1399,6 +1408,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; @@ -1579,6 +1592,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: @@ -1714,6 +1728,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: @@ -2094,6 +2113,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 f5f02ee..ed425f3 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, ofpact) \ DEFINE_OFPACT(POP_MPLS, ofpact_pop_mpls, ofpact) \ \ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index b7db256..af7a88f 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -577,6 +577,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 8de641f..83e50e4 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -85,7 +85,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); @@ -1059,7 +1059,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)) { diff --git a/lib/ofp-util.def b/lib/ofp-util.def index 83b5580..a598a02 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") @@ -66,6 +67,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, 0, "push_mpls") diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index f6939a4..3b2f9c0 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5809,6 +5809,25 @@ compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids) } static void +compose_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 compose_set_mpls_ttl_action(struct action_xlate_ctx *ctx, uint8_t ttl) { if (eth_type_mpls(ctx->flow.dl_type)) { @@ -6207,6 +6226,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, compose_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype); break; + case OFPACT_COPY_TTL_OUT: + compose_copy_ttl_out_action(ctx); + break; + case OFPACT_SET_MPLS_TTL: compose_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 06f082d..f8a5ad5 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -254,6 +254,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 @@ -397,6 +398,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 @@ -450,7 +471,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]) @@ -559,6 +579,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 06627fe..819d350 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -1022,6 +1022,13 @@ 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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev