[ovs-dev] [PATCH] support NXAST_SET_TUNNEL_DST action

Rich Lane rich.lane at bigswitch.com
Tue Dec 11 01:16:39 UTC 2012


This action allows the controller to change the destination IP of the
encapsulating packet. It just exposes the existing Linux datapath
functionality.

Tested by installing a flow with the new action and an output action to a GRE
tunnel port. The resulting packet had the correct destination IP.

Signed-off-by: Rich Lane <rich.lane at bigswitch.com>
---
I would have liked to put this in under the BSN vendor ID but there isn't any
existing support for actions from other vendors. Let me know if you'd like me
to add that.

I wasn't sure how to populate the tun_flags, ipv4_tos, and ipv4_ttl fields of
the struct ovs_key_ipv4_tunnel. Would you rather the new OpenFlow action set
all of them at once instead of just the destination IP?

 include/openflow/nicira-ext.h |   14 ++++++++++++++
 lib/odp-util.c                |   29 +++++++++++++++++++++++++++++
 lib/ofp-actions.c             |   25 +++++++++++++++++++++++++
 lib/ofp-actions.h             |    9 +++++++++
 lib/ofp-parse.c               |    5 +++++
 lib/ofp-util.def              |    1 +
 ofproto/ofproto-dpif.c        |    4 ++++
 tests/ofp-actions.at          |    3 +++
 tests/ofproto-dpif.at         |   19 +++++++++++++++++++
 tests/ovs-ofctl.at            |    2 ++
 10 files changed, 111 insertions(+)

diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 91c96b3..a82df9c 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -304,6 +304,7 @@ enum nx_action_subtype {
     NXAST_CONTROLLER,           /* struct nx_action_controller */
     NXAST_DEC_TTL_CNT_IDS,      /* struct nx_action_cnt_ids */
     NXAST_WRITE_METADATA,       /* struct nx_action_write_metadata */
+    NXAST_SET_TUNNEL_DST,       /* struct nx_action_set_tunnel_dst */
 };
 
 /* Header for Nicira-defined actions. */
@@ -2212,4 +2213,17 @@ struct nx_action_write_metadata {
 };
 OFP_ASSERT(sizeof(struct nx_action_write_metadata) == 32);
 
+/* Action structure for NXAST_SET_TUNNEL_DST.
+ *
+ * Sets the encapsulating tunnel destination IP. */
+struct nx_action_set_tunnel_dst {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 16. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_SET_TUNNEL_DST. */
+    uint8_t pad[2];
+    ovs_be32 tun_dst;               /* Destination IP. */
+};
+OFP_ASSERT(sizeof(struct nx_action_set_tunnel_dst) == 16);
+
 #endif /* openflow/nicira-ext.h */
diff --git a/lib/odp-util.c b/lib/odp-util.c
index de97fd2..8a2f76e 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -2138,6 +2138,34 @@ commit_set_skb_mark_action(const struct flow *flow, struct flow *base,
     commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK,
                       &base->skb_mark, sizeof(base->skb_mark));
 }
+
+static void
+commit_set_ipv4_tunnel_action(const struct flow *flow, struct flow *base,
+                              struct ofpbuf *odp_actions)
+{
+    struct ovs_key_ipv4_tunnel tmp;
+
+    /* Don't use the full ipv4_tunnel action if just tun_id changed. */
+    if (base->tunnel.ip_src == flow->tunnel.ip_src &&
+        base->tunnel.ip_dst == flow->tunnel.ip_dst) {
+        return;
+    }
+
+    base->tunnel.tun_id = flow->tunnel.tun_id;
+    base->tunnel.ip_dst = flow->tunnel.ip_dst;
+    base->tunnel.ip_dst = flow->tunnel.ip_dst;
+
+    tmp.tun_id = base->tunnel.tun_id;
+    tmp.tun_flags = OVS_TNL_F_KEY | OVS_TNL_F_DONT_FRAGMENT;
+    tmp.ipv4_src = base->tunnel.ip_src;
+    tmp.ipv4_dst = base->tunnel.ip_dst;
+    tmp.ipv4_tos = 0;
+    tmp.ipv4_ttl = 64;
+
+    commit_set_action(odp_actions, OVS_KEY_ATTR_IPV4_TUNNEL,
+                      &tmp, sizeof(tmp));
+}
+
 /* If any of the flow key data that ODP actions can modify are different in
  * 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow
  * key from 'base' into 'flow', and then changes 'base' the same way. */
@@ -2145,6 +2173,7 @@ void
 commit_odp_actions(const struct flow *flow, struct flow *base,
                    struct ofpbuf *odp_actions)
 {
+    commit_set_ipv4_tunnel_action(flow, base, odp_actions);
     commit_set_tun_id_action(flow, base, odp_actions);
     commit_set_ether_addr_action(flow, base, odp_actions);
     commit_vlan_action(flow, base, odp_actions);
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index b758c7c..256a982 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -294,6 +294,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     const struct nx_action_note *nan;
     const struct nx_action_set_tunnel64 *nast64;
     const struct nx_action_write_metadata *nawm;
+    const struct nx_action_set_tunnel_dst *nastd;
     struct ofpact_tunnel *tunnel;
     enum ofperr error = 0;
 
@@ -401,6 +402,11 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     case OFPUTIL_NXAST_CONTROLLER:
         controller_from_openflow((const struct nx_action_controller *) a, out);
         break;
+
+    case OFPUTIL_NXAST_SET_TUNNEL_DST:
+        nastd = (const struct nx_action_set_tunnel_dst *) a;
+        ofpact_put_SET_TUNNEL_DST(out)->tun_dst = nastd->tun_dst;
+        break;
     }
 
     return error;
@@ -1103,6 +1109,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
     case OFPACT_RESUBMIT:
+    case OFPACT_SET_TUNNEL_DST:
         return 0;
 
     case OFPACT_LEARN:
@@ -1297,6 +1304,13 @@ ofpact_fin_timeout_to_nxast(const struct ofpact_fin_timeout *fin_timeout,
 }
 
 static void
+ofpact_set_tunnel_dst_to_nxast(const struct ofpact_tunnel_dst *tunnel_dst,
+                               struct ofpbuf *out)
+{
+    ofputil_put_NXAST_SET_TUNNEL_DST(out)->tun_dst = tunnel_dst->tun_dst;
+}
+
+static void
 ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
 {
     switch (a->type) {
@@ -1369,6 +1383,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         ofputil_put_NXAST_EXIT(out);
         break;
 
+    case OFPACT_SET_TUNNEL_DST:
+        ofpact_set_tunnel_dst_to_nxast(ofpact_get_SET_TUNNEL_DST(a), out);
+        break;
+
     case OFPACT_OUTPUT:
     case OFPACT_ENQUEUE:
     case OFPACT_SET_VLAN_VID:
@@ -1496,6 +1514,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_SET_TUNNEL_DST:
         ofpact_to_nxast(a, out);
         break;
     }
@@ -1638,6 +1657,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_SET_TUNNEL_DST:
         ofpact_to_nxast(a, out);
         break;
     }
@@ -1763,6 +1783,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_EXIT:
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
+    case OFPACT_SET_TUNNEL_DST:
     default:
         return false;
     }
@@ -2059,6 +2080,10 @@ ofpact_format(const struct ofpact *a, struct ds *s)
                           OVSINST_OFPIT11_GOTO_TABLE),
                       ofpact_get_GOTO_TABLE(a)->table_id);
         break;
+
+    case OFPACT_SET_TUNNEL_DST:
+        ds_put_format(s, "set_tunnel_dst:"IP_FMT, IP_ARGS(&ofpact_get_SET_TUNNEL_DST(a)->tun_dst));
+        break;
     }
 }
 
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index b6cf4ba..4ddced4 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -74,6 +74,7 @@
                                                                     \
     /* Metadata. */                                                 \
     DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,        ofpact)    \
+    DEFINE_OFPACT(SET_TUNNEL_DST,  ofpact_tunnel_dst,    ofpact)    \
     DEFINE_OFPACT(SET_QUEUE,       ofpact_queue,         ofpact)    \
     DEFINE_OFPACT(POP_QUEUE,       ofpact_null,          ofpact)    \
     DEFINE_OFPACT(FIN_TIMEOUT,     ofpact_fin_timeout,   ofpact)    \
@@ -318,6 +319,14 @@ struct ofpact_tunnel {
     uint64_t tun_id;
 };
 
+/* OFPACT_SET_TUNNEL_DST.
+ *
+ * Used for NXAST_SET_TUNNEL_DST. */
+struct ofpact_tunnel_dst {
+    struct ofpact ofpact;
+    ovs_be32 tun_dst;
+};
+
 /* OFPACT_SET_QUEUE.
  *
  * Used for NXAST_SET_QUEUE. */
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 65f023a..2338e6a 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,
     case OFPUTIL_NXAST_CONTROLLER:
         parse_controller(ofpacts, arg);
         break;
+
+    case OFPUTIL_NXAST_SET_TUNNEL_DST:
+        str_to_ip(arg, &ip);
+        ofpact_put_SET_TUNNEL_DST(ofpacts)->tun_dst = ip;
+        break;
     }
 }
 
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 6d08d8a..d22672b 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -62,6 +62,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_TUNNEL_DST,  nx_action_set_tunnel_dst, 0, "set_tunnel_dst")
 
 #undef OFPAT10_ACTION
 #undef OFPAT11_ACTION
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index ca0a065..968274b 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -6051,6 +6051,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             xlate_table_action(ctx, ctx->flow.in_port, ogt->table_id, true);
             break;
         }
+
+        case OFPACT_SET_TUNNEL_DST:
+            ctx->flow.tunnel.ip_dst = ofpact_get_SET_TUNNEL_DST(a)->tun_dst;
+            break;
         }
     }
 
diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at
index 30fcf51..7146b70 100644
--- a/tests/ofp-actions.at
+++ b/tests/ofp-actions.at
@@ -118,6 +118,9 @@ ffff 0010 00002320 0014 04d2 162e 02 00
 # actions=dec_ttl(32768,12345,90,765,1024)
 ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000
 
+# actions=set_tunnel_dst:192.168.1.1
+ffff 0010 00002320 0017 0000 C0A80101
+
 ])
 sed '/^[[#&]]/d' < test-data > input.txt
 sed -n 's/^# //p; /^$/p' < test-data > expout
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 6a4dc23..f2a7728 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -231,6 +231,25 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - set_tunnel_dst])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1], [2], [3], [4], [5], [90])
+AT_DATA([flows.txt], [dnl
+in_port=90 actions=resubmit:1,resubmit:2,resubmit:3,resubmit:4,resubmit:5
+in_port=1 actions=set_tunnel_dst:192.168.1.1,output:1
+in_port=2 actions=set_tunnel_dst:192.168.1.1,output:2
+in_port=3 actions=set_tunnel_dst:192.168.1.2,set_tunnel_dst:192.168.1.3,output:3
+in_port=4 actions=set_tunnel_dst:192.168.1.4,set_tunnel_dst:192.168.1.3,output:4
+in_port=5 actions=set_tunnel_dst:192.168.1.5
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace br0 'tun_id(0x1),in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: set(ipv4_tunnel(tun_id=0x1,src=0.0.0.0,dst=192.168.1.1,tos=0x0,ttl=64,flags(df,key))),1,2,set(ipv4_tunnel(tun_id=0x1,src=0.0.0.0,dst=192.168.1.3,tos=0x0,ttl=64,flags(df,key))),3,4
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - controller])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index 7b8f38f..bd1a143 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -86,6 +86,7 @@ cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
 actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
 tcp,tp_src=0x1230/0xfff0,tun_id=0x1234,cookie=0x5678,actions=flood
 actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel:0x123456789
+actions=set_tunnel_dst:192.168.1.1
 actions=multipath(eth_src, 50, hrw, 12, 0, NXM_NX_REG0[0..3]),multipath(symmetric_l4, 1024, iter_hash, 5000, 5050, NXM_NX_REG0[0..12])
 table=1,actions=drop
 tun_id=0x1234000056780000/0xffff0000ffff0000,actions=drop
@@ -120,6 +121,7 @@ NXT_FLOW_MOD: ADD table:255 priority=60000 cookie:0x123456789abcdef hard:10 acti
 NXT_FLOW_MOD: ADD table:255 actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
 NXT_FLOW_MOD: ADD table:255 tcp,tun_id=0x1234,tp_src=0x1230/0xfff0 cookie:0x5678 actions=FLOOD
 NXT_FLOW_MOD: ADD table:255 actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel64:0x123456789
+NXT_FLOW_MOD: ADD table:255 actions=set_tunnel_dst:192.168.1.1
 NXT_FLOW_MOD: ADD table:255 actions=multipath(eth_src,50,hrw,12,0,NXM_NX_REG0[0..3]),multipath(symmetric_l4,1024,iter_hash,5000,5050,NXM_NX_REG0[0..12])
 NXT_FLOW_MOD: ADD table:1 actions=drop
 NXT_FLOW_MOD: ADD table:255 tun_id=0x1234000056780000/0xffff0000ffff0000 actions=drop
-- 
1.7.9.5




More information about the dev mailing list