From 0f3f3c3db0a997ddb512bf9f0a9a1df7d5252f84 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 6 Mar 2013 16:08:12 +0900 Subject: [PATCH] Add support for set_mpls_ttl action This adds support for the OpenFlow 1.1+ set_mpls_ttl action. And also adds an NX set_mpls_ttl action. The handling of the TTL modification is entirely handled in userspace. Reviewed-by: Isaku Yamahata Signed-off-by: Simon Horman Signed-off-by: Ben Pfaff --- NEWS | 4 +-- include/openflow/nicira-ext.h | 12 +++++++ lib/ofp-actions.c | 30 +++++++++++++++++ lib/ofp-actions.h | 10 ++++++ lib/ofp-parse.c | 17 ++++++++++ lib/ofp-util.def | 2 ++ ofproto/ofproto-dpif.c | 17 ++++++++++ tests/ofproto-dpif.at | 63 +++++++++++++++++++++++++++++++++++ utilities/ovs-ofctl.8.in | 4 +++ 9 files changed, 157 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 1d67df8d5..7fb093269 100644 --- a/NEWS +++ b/NEWS @@ -7,8 +7,8 @@ post-v1.10.0 protocol (RFC 6830). An external control plane or manual flow setup is required for EID-to-RLOC mapping. - OpenFlow: - * The "dec_mpls_ttl" action from OpenFlow 1.1 and later is now - implemented. + * The "dec_mpls_ttl" and "set_mpls_ttl" actions from OpenFlow + 1.1 and later are now implemented. v1.10.0 - xx xxx xxxx diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index db96be902..cdb19520c 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_SET_MPLS_TTL, /* struct nx_action_ttl */ NXAST_DEC_MPLS_TTL, /* struct nx_action_header */ }; @@ -2193,4 +2194,15 @@ struct nx_action_pop_mpls { }; OFP_ASSERT(sizeof(struct nx_action_pop_mpls) == 16); +/* Action structure for NXAST_SET_MPLS_TTL. */ +struct nx_action_mpls_ttl { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* Length is 8. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* NXAST_SET_MPLS_TTL. */ + uint8_t ttl; /* TTL */ + uint8_t pad[5]; +}; +OFP_ASSERT(sizeof(struct nx_action_mpls_ttl) == 16); + #endif /* openflow/nicira-ext.h */ diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 2b655dcc5..6dabc5a49 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -406,6 +406,12 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, 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; + break; + } + case OFPUTIL_NXAST_DEC_MPLS_TTL: ofpact_put_DEC_MPLS_TTL(out); break; @@ -790,6 +796,12 @@ 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_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; + break; + } + case OFPUTIL_OFPAT11_DEC_MPLS_TTL: ofpact_put_DEC_MPLS_TTL(out); break; @@ -1144,6 +1156,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports, } case OFPACT_DEC_TTL: + case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: case OFPACT_SET_TUNNEL: case OFPACT_SET_QUEUE: @@ -1392,6 +1405,11 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out); break; + case OFPACT_SET_MPLS_TTL: + ofputil_put_NXAST_SET_MPLS_TTL(out)->ttl + = ofpact_get_SET_MPLS_TTL(a)->ttl; + break; + case OFPACT_DEC_MPLS_TTL: ofputil_put_NXAST_DEC_MPLS_TTL(out); break; @@ -1563,6 +1581,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_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: case OFPACT_SET_TUNNEL: case OFPACT_WRITE_METADATA: @@ -1696,6 +1715,11 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out); break; + case OFPACT_SET_MPLS_TTL: + ofputil_put_OFPAT11_SET_MPLS_TTL(out)->mpls_ttl + = ofpact_get_SET_MPLS_TTL(a)->ttl; + break; + case OFPACT_DEC_MPLS_TTL: ofputil_put_OFPAT11_DEC_MPLS_TTL(out); break; @@ -1844,6 +1868,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_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: case OFPACT_SET_TUNNEL: case OFPACT_WRITE_METADATA: @@ -2067,6 +2092,11 @@ ofpact_format(const struct ofpact *a, struct ds *s) print_dec_ttl(ofpact_get_DEC_TTL(a), s); break; + case OFPACT_SET_MPLS_TTL: + ds_put_format(s, "set_mpls_ttl(%"PRIu8")", + ofpact_get_SET_MPLS_TTL(a)->ttl); + break; + case OFPACT_DEC_MPLS_TTL: ds_put_cstr(s, "dec_mpls_ttl"); break; diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 5746a5a51..2d934f98c 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(SET_MPLS_TTL, ofpact_mpls_ttl, ofpact) \ DEFINE_OFPACT(DEC_MPLS_TTL, ofpact_null, ofpact) \ DEFINE_OFPACT(PUSH_MPLS, ofpact_push_mpls, ofpact) \ DEFINE_OFPACT(POP_MPLS, ofpact_pop_mpls, ofpact) \ @@ -441,6 +442,15 @@ struct ofpact_cnt_ids { uint16_t cnt_ids[]; }; +/* OFPACT_SET_MPLS_TTL. + * + * Used for NXAST_SET_MPLS_TTL */ +struct ofpact_mpls_ttl { + struct ofpact ofpact; + + uint8_t ttl; +}; + /* OFPACT_GOTO_TABLE * * Used for OFPIT11_GOTO_TABLE */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 7b881afcb..f1802048a 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -317,6 +317,18 @@ parse_dec_ttl(struct ofpbuf *b, char *arg) } } +static void +parse_set_mpls_ttl(struct ofpbuf *b, const char *arg) +{ + struct ofpact_mpls_ttl *mpls_ttl = ofpact_put_SET_MPLS_TTL(b); + + if (*arg == '\0') { + ovs_fatal(0, "parse_set_mpls_ttl: expected ttl."); + } + + mpls_ttl->ttl = atoi(arg); +} + static void set_field_parse(const char *arg, struct ofpbuf *ofpacts) { @@ -550,6 +562,11 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, parse_dec_ttl(ofpacts, arg); break; + case OFPUTIL_NXAST_SET_MPLS_TTL: + case OFPUTIL_OFPAT11_SET_MPLS_TTL: + parse_set_mpls_ttl(ofpacts, arg); + break; + case OFPUTIL_OFPAT11_DEC_MPLS_TTL: case OFPUTIL_NXAST_DEC_MPLS_TTL: ofpact_put_DEC_MPLS_TTL(ofpacts); diff --git a/lib/ofp-util.def b/lib/ofp-util.def index d55b1eba7..439d34ed5 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_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") OFPAT11_ACTION(OFPAT11_POP_VLAN, ofp_action_header, 0, "pop_vlan") @@ -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_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") NXAST_ACTION(NXAST_POP_MPLS, nx_action_pop_mpls, 0, "pop_mpls") diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index ea6104a83..ff7f6534b 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -6058,6 +6058,17 @@ compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids) } } +static bool +execute_set_mpls_ttl_action(struct action_xlate_ctx *ctx, uint8_t ttl) +{ + if (!eth_type_mpls(ctx->flow.dl_type)) { + return true; + } + + set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl); + return false; +} + static bool execute_dec_mpls_ttl_action(struct action_xlate_ctx *ctx) { @@ -6422,6 +6433,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_SET_MPLS_TTL: + if (execute_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl)) { + goto out; + } + break; + case OFPACT_DEC_MPLS_TTL: if (execute_dec_mpls_ttl_action(ctx)) { goto out; diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index cd08e2938..b795f5618 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -234,6 +234,9 @@ cookie=0xa dl_src=40:44:44:44:44:42 actions=push_mpls:0x8847,load:10->OXM_OF_MPL 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=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=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 @@ -375,6 +378,63 @@ NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len 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 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:46,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:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,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:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,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:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,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:47,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:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,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:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,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:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,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 + +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:9,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,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:9,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,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:9,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,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]) @@ -521,6 +581,9 @@ 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: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=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=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 40869c4ee..609df9f2f 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -1018,6 +1018,10 @@ 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 \fBset_mpls_ttl\fR:\fIttl\fR +Set the TTL of the outer MPLS label stack entry of a packet. +\fIttl\fR should be in the range 0 to 255 inclusive. +. .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 -- 2.20.1