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 decrement is entirely handled in userspace. Signed-off-by: Simon Horman <ho...@verge.net.au> --- include/openflow/nicira-ext.h | 1 + lib/flow.c | 8 ++++++++ lib/ofp-actions.c | 34 ++++++++++++++++++++++++++++++++++ lib/ofp-actions.h | 7 ++++--- lib/ofp-parse.c | 20 ++++++++++++++++++++ lib/ofp-util.def | 2 ++ lib/packets.c | 2 +- lib/packets.h | 1 + ofproto/ofproto-dpif.c | 34 ++++++++++++++++++++++++++++++++++ tests/ofproto-dpif.at | 10 +++++----- 10 files changed, 110 insertions(+), 9 deletions(-) diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 8199516..46ac0e1 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -305,6 +305,7 @@ enum nx_action_subtype { NXAST_DEC_TTL_CNT_IDS, /* struct nx_action_cnt_ids */ 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 d88dd49..16aab3f 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -887,6 +887,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 13eb367..d19d590 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -165,6 +165,20 @@ dec_ttl_from_openflow(struct ofpbuf *out) } static enum ofperr +dec_mpls_ttl_from_openflow(struct ofpbuf *out) +{ + uint16_t id = 0; + struct ofpact_cnt_ids *ids; + + ids = ofpact_put_DEC_MPLS_TTL(out); + ids->n_controllers = 1; + ofpbuf_put(out, &id, sizeof id); + ids = out->l2; + ofpact_update_len(out, &ids->ofpact); + return 0; +} + +static enum ofperr dec_ttl_cnt_ids_from_openflow(const struct nx_action_cnt_ids *nac_ids, struct ofpbuf *out) { @@ -389,6 +403,10 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, break; } + case OFPUTIL_NXAST_DEC_MPLS_TTL: + error = dec_mpls_ttl_from_openflow(out); + break; + case OFPUTIL_NXAST_POP_MPLS: { struct nx_action_pop_mpls *nxapm = (struct nx_action_pop_mpls *)a; if (nxapm->ethertype == htons(ETH_TYPE_MPLS) || @@ -742,6 +760,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 (oap->ethertype != htons(ETH_TYPE_MPLS) && @@ -1074,6 +1096,7 @@ ofpact_check__(const struct ofpact *a, int max_ports) return nxm_reg_load_check(ofpact_get_REG_LOAD(a)); case OFPACT_DEC_TTL: + case OFPACT_DEC_MPLS_TTL: case OFPACT_SET_TUNNEL: case OFPACT_SET_QUEUE: case OFPACT_POP_QUEUE: @@ -1261,6 +1284,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; @@ -1426,6 +1453,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_SET_QUEUE: case OFPACT_POP_QUEUE: @@ -1550,6 +1578,7 @@ ofpact_to_openflow11(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_SET_QUEUE: case OFPACT_POP_QUEUE: @@ -1663,6 +1692,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_SET_QUEUE: case OFPACT_POP_QUEUE: @@ -1880,6 +1910,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 4c7ae7e..bfbaf5b 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -70,6 +70,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_cnt_ids, cnt_ids) \ DEFINE_OFPACT(PUSH_MPLS, ofpact_push, ofpact) \ DEFINE_OFPACT(POP_MPLS, ofpact_pop_mpls, ofpact) \ \ @@ -178,8 +179,8 @@ ofpact_end(const struct ofpact *ofpacts, size_t ofpacts_len) /* OFPACT_STRIP_VLAN, OFPACT_POP_QUEUE, OFPACT_EXIT, OFPACT_CLEAR_ACTIONS. * - * Used for OFPAT10_STRIP_VLAN, NXAST_DEC_TTL, NXAST_POP_QUEUE, NXAST_EXIT, - * OFPIT11_CLEAR_ACTIONS. + * Used for OFPAT10_STRIP_VLAN, NXAST_DEC_TTL, NXAST_DEC_MPLS_TTL, + * NXAST_POP_QUEUE, NXAST_EXIT, OFPIT11_CLEAR_ACTIONS. * * Action structure for actions that do not have any extra data beyond the * action type. */ @@ -430,7 +431,7 @@ struct ofpact_note { /* OFPACT_DEC_TTL. * - * Used for NXAST_DEC_TTL and NXAST_DEC_TTL_CNT_IDS. */ + * Used for NXAST_DEC_TTL, NXAST_DEC_MPLS_TTL and NXAST_DEC_TTL_CNT_IDS. */ struct ofpact_cnt_ids { struct ofpact ofpact; diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 339739c..21e62a0 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -315,6 +315,18 @@ parse_dec_ttl(struct ofpbuf *b, char *arg) } static void +parse_dec_mpls_ttl(struct ofpbuf *b) +{ + struct ofpact_cnt_ids *ids = ofpact_put_DEC_MPLS_TTL(b); + uint16_t id = 0; + + ofpbuf_put(b, &id, sizeof id); + ids = b->l2; + ids->n_controllers++; + ofpact_update_len(b, &ids->ofpact); +} + +static void set_field_parse(const char *arg, struct ofpbuf *ofpacts) { char *orig = xstrdup(arg); @@ -510,6 +522,14 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, parse_dec_ttl(ofpacts, arg); break; + case OFPUTIL_NXAST_DEC_MPLS_TTL: + parse_dec_mpls_ttl(ofpacts); + break; + + case OFPUTIL_OFPAT11_DEC_MPLS_TTL: + parse_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 2fc22d1..5c82d84 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") @@ -62,6 +63,7 @@ NXAST_ACTION(NXAST_DEC_TTL, nx_action_header, 0, "dec_ttl") NXAST_ACTION(NXAST_FIN_TIMEOUT, nx_action_fin_timeout, 0, "fin_timeout") 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_DEC_MPLS_TTL, nx_action_header, 0, "dec_mpls_ttl") NXAST_ACTION(NXAST_PUSH_MPLS, nx_action_push, 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 363749f..18a8633 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -263,7 +263,7 @@ get_ethertype(struct ofpbuf *packet) } /* Set MPLS tag time-to-live. */ -static void +void set_mpls_lse_ttl(ovs_be32 *tag, uint8_t ttl) { *tag &= ~htonl(MPLS_TTL_MASK); diff --git a/lib/packets.h b/lib/packets.h index 172f1a6..8160fbc 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); void pop_mpls(struct ofpbuf *, ovs_be16 ethtype); +void set_mpls_lse_ttl(ovs_be32 *tag, uint8_t ttl); void set_mpls_lse_tc(ovs_be32 *tag, uint8_t tc); void set_mpls_lse_label(ovs_be32 *tag, ovs_be32 label); void set_mpls_lse_bos(ovs_be32 *tag, uint8_t bos); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 46da68a..b6affa5 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5253,6 +5253,34 @@ compose_mpls_pop_action(struct action_xlate_ctx *ctx, ovs_be16 eth_type) } static bool +compose_dec_mpls_ttl_action(struct action_xlate_ctx *ctx, + struct ofpact_cnt_ids *ids) +{ + uint8_t ttl = mpls_lse_to_ttl(ctx->flow.mpls_lse); + + if (ctx->flow.dl_type != htons(ETH_TYPE_MPLS) && + ctx->flow.dl_type != htons(ETH_TYPE_MPLS_MCAST)) { + return false; + } + + if (ttl > 1) { + ttl--; + set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl); + return false; + } else { + size_t i; + + for (i = 0; i < ids->n_controllers; i++) { + execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, + ids->cnt_ids[i]); + } + + /* Stop processing for current table. */ + return true; + } +} + +static bool compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids) { if (ctx->flow.dl_type != htons(ETH_TYPE_IP) && @@ -5638,6 +5666,12 @@ 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_DEC_MPLS_TTL: + if (compose_dec_mpls_ttl_action(ctx, ofpact_get_DEC_MPLS_TTL(a))) { + 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 545a838..aa84b45 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -250,7 +250,7 @@ cookie=0x6 table=4 in_port=83 actions=load:4->NXM_NX_REG3[[]],mod_nw_src:83.83.8 cookie=0x7 table=5 in_port=84 actions=load:5->NXM_NX_REG4[[]],load:6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,controller,resubmit(85,6) cookie=0x8 table=6 in_port=85 actions=mod_tp_src:85,controller,resubmit(86,7) cookie=0x9 table=7 in_port=86 actions=mod_tp_dst:86,controller,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:44 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 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 @@ -324,13 +324,13 @@ 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) -priority:0,metadata:0,in_port:0000,tci(0) mac(40:44:44:44:44:44->50:54:00:00:00:07) type:8847,mpls(label:10,tc:3,ttl:64,bos:1) +priority:0,metadata:0,in_port:0000,tci(0) mac(40:44:44:44:44:44->50:54:00:00:00:07) type:8847,mpls(label:10,tc:3,ttl:63,bos:1) dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -priority:0,metadata:0,in_port:0000,tci(0) mac(40:44:44:44:44:44->50:54:00:00:00:07) type:8847,mpls(label:10,tc:3,ttl:64,bos:1) +priority:0,metadata:0,in_port:0000,tci(0) mac(40:44:44:44:44:44->50:54:00:00:00:07) type:8847,mpls(label:10,tc:3,ttl:63,bos:1) dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -priority:0,metadata:0,in_port:0000,tci(0) mac(40:44:44:44:44:44->50:54:00:00:00:07) type:8847,mpls(label:10,tc:3,ttl:64,bos:1) +priority:0,metadata:0,in_port:0000,tci(0) mac(40:44:44:44:44:44->50:54:00:00:00:07) type:8847,mpls(label:10,tc:3,ttl:63,bos:1) ]) dnl Modified MPLS actions. @@ -475,7 +475,7 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl cookie=0x7, table=5, n_packets=2, n_bytes=120, in_port=84 actions=load:0x5->NXM_NX_REG4[[]],load:0x6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,CONTROLLER:65535,resubmit(85,6) cookie=0x8, table=6, n_packets=2, n_bytes=120, in_port=85 actions=mod_tp_src:85,CONTROLLER:65535,resubmit(86,7) cookie=0x9, table=7, n_packets=2, n_bytes=120, in_port=86 actions=mod_tp_dst:86,CONTROLLER:65535,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:44 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 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 -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev