This adds support for the OpenFlow 1.1+ dec_mpls_ttl action. And also adds an NX dec_mpls_ttl action.
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.17 * Rebase * As suggested by Ben Pfaff - Use consistent terminology for MPLS. + Consistently refer to the MPLS component of a packet as the MPLS label stack and entries in the stack as MPLS label stack entries (LSE). An MPLS label is a component of an MPLS label stack entry. The other components are the traffic class (TC), time to live (TTL) and bottom of stack (BoS) bit. - Rename compose_dec_mpls_ttl_action as execute_dec_mpls_ttl_action v2.13 - v2.16 * No change v2.12 * Use eth_type_mpls() helper v2.11 - v2.10 * No change v2.9 * Update tests for upstream changes v2.8 * No change v2.7 * Encode action as OFP11 action in OFP11+ messages v2.6 * Rebase v2.5 * First post --- include/openflow/nicira-ext.h | 1 + lib/flow.c | 8 ++++++++ lib/ofp-actions.c | 23 +++++++++++++++++++++++ lib/ofp-actions.h | 1 + lib/ofp-parse.c | 5 +++++ lib/ofp-util.def | 2 ++ lib/packets.c | 2 +- lib/packets.h | 1 + ofproto/ofproto-dpif.c | 27 +++++++++++++++++++++++++++ tests/ofproto-dpif.at | 21 +++++++++++++++++++++ utilities/ovs-ofctl.8.in | 9 +++++++++ 11 files changed, 99 insertions(+), 1 deletion(-) diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index d6a99ce..61fb97e 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_DEC_MPLS_TTL, /* struct nx_action_header */ }; /* Header for Nicira-defined actions. */ diff --git a/lib/flow.c b/lib/flow.c index 5e7d1d4..fc8a30f 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -843,6 +843,14 @@ 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/ofp-actions.c b/lib/ofp-actions.c index f37bf5f..c52cf48 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_DEC_MPLS_TTL: + ofpact_put_DEC_MPLS_TTL(out); + break; + case OFPUTIL_NXAST_POP_MPLS: { struct nx_action_pop_mpls *nxapm = (struct nx_action_pop_mpls *)a; if (eth_type_mpls(nxapm->ethertype)) { @@ -792,6 +796,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_DEC_MPLS_TTL: + ofpact_put_DEC_MPLS_TTL(out); + break; + case OFPUTIL_OFPAT11_PUSH_MPLS: { struct ofp11_action_push *oap = (struct ofp11_action_push *)a; if (!eth_type_mpls(oap->ethertype)) { @@ -1142,6 +1150,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports, } case OFPACT_DEC_TTL: + case OFPACT_DEC_MPLS_TTL: case OFPACT_SET_TUNNEL: case OFPACT_SET_QUEUE: case OFPACT_POP_QUEUE: @@ -1393,6 +1402,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_DEC_MPLS_TTL: + ofputil_put_NXAST_DEC_MPLS_TTL(out); + break; + case OFPACT_SET_TUNNEL: ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out); break; @@ -1564,6 +1577,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_DEC_MPLS_TTL: case OFPACT_SET_TUNNEL: case OFPACT_WRITE_METADATA: case OFPACT_SET_QUEUE: @@ -1697,6 +1711,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_DEC_MPLS_TTL: + ofputil_put_OFPAT11_DEC_MPLS_TTL(out); + break; + case OFPACT_WRITE_METADATA: /* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */ break; @@ -1842,6 +1860,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_DEC_MPLS_TTL: case OFPACT_SET_TUNNEL: case OFPACT_WRITE_METADATA: case OFPACT_SET_QUEUE: @@ -2066,6 +2085,10 @@ ofpact_format(const struct ofpact *a, struct ds *s) print_dec_ttl(ofpact_get_DEC_TTL(a), s); break; + case OFPACT_DEC_MPLS_TTL: + ds_put_cstr(s, "dec_mpls_ttl"); + break; + case OFPACT_SET_TUNNEL: tunnel = ofpact_get_SET_TUNNEL(a); ds_put_format(s, "set_tunnel%s:%#"PRIx64, diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index fa307a1..4ca77da 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -71,6 +71,7 @@ DEFINE_OFPACT(REG_MOVE, ofpact_reg_move, ofpact) \ DEFINE_OFPACT(REG_LOAD, ofpact_reg_load, ofpact) \ DEFINE_OFPACT(DEC_TTL, ofpact_cnt_ids, cnt_ids) \ + DEFINE_OFPACT(DEC_MPLS_TTL, 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 464c73e..4b0f4e2 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -555,6 +555,11 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, parse_dec_ttl(ofpacts, arg); break; + case OFPUTIL_OFPAT11_DEC_MPLS_TTL: + case OFPUTIL_NXAST_DEC_MPLS_TTL: + ofpact_put_DEC_MPLS_TTL(ofpacts); + break; + case OFPUTIL_NXAST_FIN_TIMEOUT: parse_fin_timeout(ofpacts, arg); break; diff --git a/lib/ofp-util.def b/lib/ofp-util.def index 1a60194..18321db 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_DEC_MPLS_TTL, ofp_action_header, 0, "dec_mpls_ttl") OFPAT11_ACTION(OFPAT11_PUSH_VLAN, ofp11_action_push, 0, "push_vlan") OFPAT11_ACTION(OFPAT11_POP_VLAN, ofp_action_header, 0, "pop_vlan") OFPAT11_ACTION(OFPAT11_PUSH_MPLS, ofp11_action_push, 0, "push_mpls") @@ -64,6 +65,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_DEC_MPLS_TTL, nx_action_header, 0, "dec_mpls_ttl") NXAST_ACTION(NXAST_PUSH_MPLS, nx_action_push_mpls, 0, "push_mpls") NXAST_ACTION(NXAST_POP_MPLS, nx_action_pop_mpls, 0, "pop_mpls") diff --git a/lib/packets.c b/lib/packets.c index 68a516c..219d318 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -256,7 +256,7 @@ static bool is_mpls(struct ofpbuf *packet) } /* Set time to live (TTL) of an MPLS label stack entry (LSE). */ -static void +void set_mpls_lse_ttl(ovs_be32 *lse, uint8_t ttl) { *lse &= ~htonl(MPLS_TTL_MASK); diff --git a/lib/packets.h b/lib/packets.h index c2abb7c..d51178d 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -155,6 +155,7 @@ void set_mpls_lse(struct ofpbuf *, ovs_be32 label); void push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse); void pop_mpls(struct ofpbuf *, ovs_be16 ethtype); +void set_mpls_lse_ttl(ovs_be32 *lse, uint8_t ttl); void set_mpls_lse_tc(ovs_be32 *lse, uint8_t tc); void set_mpls_lse_label(ovs_be32 *lse, ovs_be32 label); void set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 40df4b1..f9ec8ee 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5958,6 +5958,27 @@ compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids) } } +static bool +execute_dec_mpls_ttl_action(struct action_xlate_ctx *ctx) +{ + uint8_t ttl = mpls_lse_to_ttl(ctx->flow.mpls_lse); + + if (!eth_type_mpls(ctx->flow.dl_type)) { + return false; + } + + if (ttl > 1) { + ttl--; + set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl); + return false; + } else { + execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0); + + /* Stop processing for current table. */ + return true; + } +} + static void xlate_output_action(struct action_xlate_ctx *ctx, uint16_t port, uint16_t max_len, bool may_packet_in) @@ -6328,6 +6349,12 @@ 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_DEC_MPLS_TTL: + if (execute_dec_mpls_ttl_action(ctx)) { + goto out; + } + break; + case OFPACT_DEC_TTL: if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) { goto out; diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 72a60aa..041abe6 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -252,6 +252,7 @@ cookie=0x9 table=7 in_port=86 actions=mod_tp_dst:86,controller,controller cookie=0xa dl_src=40:44:44:44:44:42 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller cookie=0xa dl_src=40:44:44:44:44:43 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller cookie=0xa dl_src=40:44:44:44:44:44 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller +cookie=0xa dl_src=40:44:44:44:44:45 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,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 @@ -374,6 +375,25 @@ NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,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:45,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:63,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,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:63,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,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:63,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07 +]) + dnl Modified MPLS actions. AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log]) @@ -519,6 +539,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:42 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535 cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:43 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535 cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:44 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535 + cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:45 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,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 8b06c88..e395051 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -1010,6 +1010,15 @@ invalid ttl packets. If controller ids are not specified, the ``packet_in'' message will be sent only to the controllers having controller id zero which have registered for the invalid ttl packets. . +.IP \fBdec_mpls_ttl\fR +Decrement TTL of the outer MPLS label stack entry of a packet. If the TTL +is initially zero, no decrement occurs. Instead, a ``packet-in'' message +with reason code \fBOFPR_INVALID_TTL\fR is sent to each connected +controller with controller id zer that has enabled receiving them. +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 \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