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 implementation does not support copying in the case where the outermost and next-to-otermost header is MPLS due to limitations in the current MPLS implementation which only supports modifying the outermost MPLS header. The handling of the TTL modification is entirely handled in userspace. Signed-off-by: Simon Horman <ho...@verge.net.au> --- v2.6 * Non-trivial rebase v2.5 * First post --- include/openflow/nicira-ext.h | 1 + lib/flow.c | 17 ++++++++++------- lib/match.c | 3 ++- lib/ofp-actions.c | 20 ++++++++++++++++++++ lib/ofp-actions.h | 1 + lib/ofp-parse.c | 5 +++++ lib/ofp-print.c | 5 ++++- lib/ofp-util.def | 2 ++ ofproto/ofproto-dpif.c | 22 ++++++++++++++++++++++ tests/ofproto-dpif.at | 21 +++++++++++++++++++++ utilities/ovs-ofctl.8.in | 5 +++++ 11 files changed, 93 insertions(+), 9 deletions(-) diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 0ff906f..201b9f4 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_IN, /* struct nx_action_header */ 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 70290b5..1d05ae6 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -368,6 +368,7 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, { struct ofpbuf b = *packet; struct eth_header *eth; + ovs_be16 dl_type; COVERAGE_INC(flow_extract); @@ -400,11 +401,11 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, if (eth->eth_type == htons(ETH_TYPE_VLAN)) { parse_vlan(&b, flow); } - flow->dl_type = parse_ethertype(&b); + dl_type = flow->dl_type = parse_ethertype(&b); /* Parse mpls, copy l3 ttl. */ - if (flow->dl_type == htons(ETH_TYPE_MPLS) || - flow->dl_type == htons(ETH_TYPE_MPLS_MCAST)) { + if (dl_type == htons(ETH_TYPE_MPLS) || + dl_type == htons(ETH_TYPE_MPLS_MCAST)) { struct ip_header *ih; struct ip6_hdr *ih6; @@ -419,15 +420,17 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, if (packet->size >= sizeof *ih && IP_VER(ih->ip_ihl_ver) == IP_VERSION) { flow->nw_ttl = ih->ip_ttl; + dl_type = htons(ETH_TYPE_IP); } else if (packet->size >= sizeof *ih6 && IP6_VER(ih6->ip6_vfc) == IP6_VERSION) { flow->nw_ttl = ih6->ip6_hlim; + dl_type = htons(ETH_TYPE_IPV6); } } /* Network layer. */ packet->l3 = b.data; - if (flow->dl_type == htons(ETH_TYPE_IP)) { + if (dl_type == htons(ETH_TYPE_IP)) { const struct ip_header *nh = pull_ip(&b); if (nh) { packet->l4 = b.data; @@ -460,7 +463,7 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, } } } - } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { + } else if (dl_type == htons(ETH_TYPE_IPV6)) { if (parse_ipv6(&b, flow)) { return; } @@ -475,8 +478,8 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, packet->l7 = b.data; } } - } else if (flow->dl_type == htons(ETH_TYPE_ARP) || - flow->dl_type == htons(ETH_TYPE_RARP)) { + } else if (dl_type == htons(ETH_TYPE_ARP) || + dl_type == htons(ETH_TYPE_RARP)) { const struct arp_eth_header *arp = pull_arp(&b); if (arp && arp->ar_hrd == htons(1) && arp->ar_pro == htons(ETH_TYPE_IP) diff --git a/lib/match.c b/lib/match.c index 1db5586..c42fb9b 100644 --- a/lib/match.c +++ b/lib/match.c @@ -867,7 +867,8 @@ match_format(const struct match *match, struct ds *s, unsigned int priority) if (f->dl_type == htons(ETH_TYPE_ARP) || f->dl_type == htons(ETH_TYPE_RARP)) { ds_put_format(s, "arp_op=%"PRIu8",", f->nw_proto); - } else { + } else if (f->dl_type != htons(ETH_TYPE_MPLS) && + f->dl_type != htons(ETH_TYPE_MPLS_MCAST)) { ds_put_format(s, "nw_proto=%"PRIu8",", f->nw_proto); } } diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 5d8e68d..9bb675f 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -412,6 +412,10 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, break; } + case OFPUTIL_NXAST_COPY_TTL_IN: + ofpact_put_COPY_TTL_IN(out); + break; + case OFPUTIL_NXAST_COPY_TTL_OUT: ofpact_put_COPY_TTL_OUT(out); break; @@ -802,6 +806,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_IN: + ofpact_put_COPY_TTL_IN(out); + break; + case OFPUTIL_OFPAT11_COPY_TTL_OUT: ofpact_put_COPY_TTL_OUT(out); break; @@ -1163,6 +1171,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports, } case OFPACT_DEC_TTL: + case OFPACT_COPY_TTL_IN: case OFPACT_COPY_TTL_OUT: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: @@ -1403,6 +1412,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_IN: + ofputil_put_NXAST_COPY_TTL_IN(out); + break; + case OFPACT_COPY_TTL_OUT: ofputil_put_NXAST_COPY_TTL_OUT(out); break; @@ -1587,6 +1600,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_IN: case OFPACT_COPY_TTL_OUT: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: @@ -1742,6 +1756,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) case OFPACT_BUNDLE: case OFPACT_REG_MOVE: case OFPACT_REG_LOAD: + case OFPACT_COPY_TTL_IN: case OFPACT_COPY_TTL_OUT: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: @@ -1867,6 +1882,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_IN: case OFPACT_COPY_TTL_OUT: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: @@ -2094,6 +2110,10 @@ ofpact_format(const struct ofpact *a, struct ds *s) print_dec_ttl(ofpact_get_DEC_TTL(a), s); break; + case OFPACT_COPY_TTL_IN: + ds_put_cstr(s, "copy_ttl_in"); + break; + case OFPACT_COPY_TTL_OUT: ds_put_cstr(s, "copy_ttl_out"); break; diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 381d9f6..dd1d96c 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_IN, 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 1e733a6..9942332 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_IN: + case OFPUTIL_NXAST_COPY_TTL_IN: + ofpact_put_COPY_TTL_IN(ofpacts); + break; + case OFPUTIL_OFPAT11_COPY_TTL_OUT: case OFPUTIL_NXAST_COPY_TTL_OUT: ofpact_put_COPY_TTL_OUT(ofpacts); diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 162bb33..fac06a9 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -66,7 +66,8 @@ ofp_packet_to_string(const void *data, size_t len) flow_extract(&buf, 0, NULL, 0, &flow); flow_format(&ds, &flow); - if (buf.l7) { + if (buf.l7 && flow.dl_type != htons(ETH_TYPE_MPLS) && + flow.dl_type != htons(ETH_TYPE_MPLS_MCAST)) { if (flow.nw_proto == IPPROTO_TCP) { struct tcp_header *th = buf.l4; ds_put_format(&ds, " tcp_csum:%"PRIx16, @@ -621,8 +622,10 @@ ofp10_match_to_string(const struct ofp10_match *om, int verbosity) ds_put_cstr(&f, "rarp,"); } else if (om->dl_type == htons(ETH_TYPE_MPLS)) { ds_put_cstr(&f, "mpls,"); + skip_proto = true; } else if (om->dl_type == htons(ETH_TYPE_MPLS_MCAST)) { ds_put_cstr(&f, "mplsm,"); + skip_proto = true; } else { skip_type = false; } diff --git a/lib/ofp-util.def b/lib/ofp-util.def index c278d14..97958ce 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_IN, ofp_action_header, 0, "copy_ttl_in") 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") @@ -67,6 +68,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_IN, nx_action_header, 0, "copy_ttl_in") 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") diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 51c2b57..ab96a66 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5671,6 +5671,24 @@ compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids) } static void +compose_copy_ttl_in_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 from IP is not supported */ + return; + } + + if (ctx->flow.mpls_depth > 1) { + /* Copying TTL from MPLS to MPLS is not supported */ + return; + } else { + /* MPLS -> IP */ + ctx->flow.nw_ttl = mpls_lse_to_ttl(ctx->flow.mpls_lse); + } +} + +static void compose_copy_ttl_out_action(struct action_xlate_ctx *ctx) { if (ctx->flow.dl_type != htons(ETH_TYPE_MPLS) && @@ -6090,6 +6108,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_IN: + compose_copy_ttl_in_action(ctx); + break; + case OFPACT_COPY_TTL_OUT: compose_copy_ttl_out_action(ctx); break; diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index fe554ad..ebeeb41 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -258,6 +258,7 @@ cookie=0xa dl_src=40:44:44:44:44:49 actions=push_mpls:0x8847,load:10->OXM_OF_MPL cookie=0xb dl_src=50:55:55:55:55:55 dl_type=0x8847 actions=load:1000->OXM_OF_MPLS_LABEL[[]],controller cookie=0xb dl_src=50:55:55:55:55:56 dl_type=0x8847 actions=load:1000->OXM_OF_MPLS_LABEL[[]],copy_ttl_out,controller cookie=0xd dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,controller +cookie=0xd dl_src=60:66:66:66:66:67 actions=copy_ttl_in,dec_ttl,pop_mpls:0x0800,dec_ttl,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 ]) AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) @@ -510,6 +511,25 @@ NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=56 in_port=1 (via action) data_len priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64 tcp_csum:0 ]) +dnl Modified MPLS pop 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=60:66:66:66:66:67,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=3,ttl=100,bos=1),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=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered) +priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:67,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=99 tcp_csum:0 +dnl +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered) +priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:67,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=99 tcp_csum:0 +dnl +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered) +priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:67,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=99 tcp_csum:0 +]) + dnl Checksum TCP. AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> ofctl_monitor.log]) @@ -604,6 +624,7 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl cookie=0xb, n_packets=3, n_bytes=180, dl_src=50:55:55:55:55:56,dl_type=0x8847 actions=load:0x3e8->OXM_OF_MPLS_LABEL[[]],copy_ttl_out,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 + cookie=0xd, n_packets=3, n_bytes=180, dl_src=60:66:66:66:66:67 actions=copy_ttl_in,dec_ttl(0),pop_mpls:0x0800,dec_ttl(0),CONTROLLER:65535 n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535 NXST_FLOW reply: ]) diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 4d097b7..84e5971 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -1022,6 +1022,11 @@ 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_in\fR +Copy the TTL from the outermost header to next-to-outermost with TTL. +The implementation supports copying to a next-to-outermost IP header +from an outermost MPLS header. +. .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 -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev