[ovs-dev] [PATCH 8/8] Add support for copy_ttl_in action

Simon Horman horms at verge.net.au
Sat Oct 27 06:06:02 UTC 2012


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 <horms at verge.net.au>
---
 include/openflow/nicira-ext.h |    1 +
 lib/flow.c                    |   15 +++++++++------
 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, 92 insertions(+), 8 deletions(-)

diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index c43c51a..81df350 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 d44050d..def0305 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,7 +478,7 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority,
                 packet->l7 = b.data;
             }
         }
-    } else if (flow->dl_type == htons(ETH_TYPE_ARP)) {
+    } else if (dl_type == htons(ETH_TYPE_ARP)) {
         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 6f28378..5a51312 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -861,7 +861,8 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
     if (!skip_proto && wc->masks.nw_proto) {
         if (f->dl_type == htons(ETH_TYPE_ARP)) {
             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 d51114d..10ed312 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;
@@ -793,6 +797,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;
@@ -1149,6 +1157,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_COPY_TTL_IN:
     case OFPACT_COPY_TTL_OUT:
     case OFPACT_SET_MPLS_TTL:
     case OFPACT_DEC_MPLS_TTL:
@@ -1380,6 +1389,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;
@@ -1562,6 +1575,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:
@@ -1711,6 +1725,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:
@@ -1835,6 +1850,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:
@@ -2057,6 +2073,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 c2c8d54..9d194b7 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -72,6 +72,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 7f7fc1f..5987b2f 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -562,6 +562,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 aea92e4..7d6e732 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,
@@ -619,8 +620,10 @@ ofp10_match_to_string(const struct ofp10_match *om, int verbosity)
             ds_put_cstr(&f, "arp,");
         } 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 b58cb0c..7362086 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 4a9ee8c..f554aa4 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5264,6 +5264,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) &&
@@ -5676,6 +5694,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 e03251c..24f04d4 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -259,6 +259,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 actions=load:1000->OXM_OF_MPLS_LABEL[[]],controller
 cookie=0xb dl_src=50:55:55:55:55:56 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])
@@ -511,6 +512,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])
 
@@ -605,6 +625,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 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 a9df039..663e230 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -1006,6 +1006,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




More information about the dev mailing list