This option allows some control over the output interface for tunnels.  It
is similar to the 'link' option for Linux network-device based GRE tunnels.
I didn't, however, make 'link' part of the tunnel key as with those
tunnels, which means that two tunnels cannot be distinguished on the basis
of 'link' alone.  That would slightly complicate tnl_find_port() and didn't
seem the effort overall.

I'm not sure that this is really needed at all, to be honest, but it seemed
like a missing bit of feature parity between ip_gre and OVS tunnels.

Signed-off-by: Ben Pfaff <b...@nicira.com>
---
 datapath/tunnel.c    |    7 +++++++
 datapath/tunnel.h    |    1 +
 lib/netdev-vport.c   |   19 +++++++++++++++++++
 vswitchd/vswitch.xml |    6 ++++++
 4 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 6fde389..ef7891f 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -966,6 +966,7 @@ static struct rtable *__find_route(const struct 
tnl_mutable_config *mutable,
 #else
        struct flowi4 fl = { .daddr = mutable->key.daddr,
                             .saddr = mutable->key.saddr,
+                            .flowi4_oif = mutable->link,
                             .flowi4_tos = tos,
                             .flowi4_proto = ipproto };
 
@@ -1312,6 +1313,7 @@ static const struct nla_policy 
tnl_policy[OVS_TUNNEL_ATTR_MAX + 1] = {
        [OVS_TUNNEL_ATTR_IN_KEY]   = { .type = NLA_U64 },
        [OVS_TUNNEL_ATTR_TOS]      = { .type = NLA_U8 },
        [OVS_TUNNEL_ATTR_TTL]      = { .type = NLA_U8 },
+       [OVS_TUNNEL_ATTR_LINK]     = { .type = NLA_U32 },
 };
 
 /* Sets OVS_TUNNEL_ATTR_* fields in 'mutable', which must initially be zeroed. 
*/
@@ -1363,6 +1365,9 @@ static int tnl_set_config(struct nlattr *options, const 
struct tnl_ops *tnl_ops,
        else
                mutable->out_key = nla_get_be64(a[OVS_TUNNEL_ATTR_OUT_KEY]);
 
+       if (a[OVS_TUNNEL_ATTR_LINK])
+               mutable->link = nla_get_u32(a[OVS_TUNNEL_ATTR_LINK]);
+
        mutable->tunnel_hlen = tnl_ops->hdr_len(mutable);
        if (mutable->tunnel_hlen < 0)
                return mutable->tunnel_hlen;
@@ -1504,6 +1509,8 @@ int tnl_get_options(const struct vport *vport, struct 
sk_buff *skb)
                NLA_PUT_U8(skb, OVS_TUNNEL_ATTR_TOS, mutable->tos);
        if (mutable->ttl)
                NLA_PUT_U8(skb, OVS_TUNNEL_ATTR_TTL, mutable->ttl);
+       if (mutable->link)
+               NLA_PUT_U32(skb, OVS_TUNNEL_ATTR_LINK, mutable->link);
 
        return 0;
 
diff --git a/datapath/tunnel.h b/datapath/tunnel.h
index 1e707a9..dcc6747 100644
--- a/datapath/tunnel.h
+++ b/datapath/tunnel.h
@@ -89,6 +89,7 @@ struct tnl_mutable_config {
        u32     flags;
        u8      tos;
        u8      ttl;
+       int     link;
 
        /* Multicast configuration. */
        int     mlink;
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 301bb43..0cf5257 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -618,6 +618,15 @@ parse_tunnel_config(const char *name, const char *type,
             } else {
                 nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TTL, atoi(node->data));
             }
+        } else if (!strcmp(node->name, "link")) {
+            const char *ifname = node->data;
+            int ifindex = if_nametoindex(ifname);
+            if (ifindex) {
+                nl_msg_put_u32(options, OVS_TUNNEL_ATTR_LINK, ifindex);
+            } else {
+                VLOG_WARN("%s: network device \"%s\" does not exist, "
+                          "cannot link", name, ifname);
+            }
         } else if (!strcmp(node->name, "csum") && is_gre) {
             if (!strcmp(node->data, "true")) {
                 flags |= TNL_F_CSUM;
@@ -724,6 +733,7 @@ tnl_port_config_from_nlattr(const struct nlattr *options, 
size_t options_len,
         [OVS_TUNNEL_ATTR_OUT_KEY] = { .type = NL_A_BE64, .optional = true },
         [OVS_TUNNEL_ATTR_TOS] = { .type = NL_A_U8, .optional = true },
         [OVS_TUNNEL_ATTR_TTL] = { .type = NL_A_U8, .optional = true },
+        [OVS_TUNNEL_ATTR_LINK] = { .type = NL_A_U32, .optional = true },
     };
     struct ofpbuf buf;
 
@@ -807,6 +817,15 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const 
char *type OVS_UNUSED,
         shash_add(args, "tos", xasprintf("%d", tos));
     }
 
+    if (a[OVS_TUNNEL_ATTR_LINK]) {
+        int ifindex = nl_attr_get_u32(a[OVS_TUNNEL_ATTR_LINK]);
+        char ifname[IFNAMSIZ];
+
+        if (if_indextoname(ifindex, ifname)) {
+            smap_add(args, "link", ifname);
+        }
+    }
+
     if (flags & TNL_F_CSUM) {
         smap_add(args, "csum", "true");
     }
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index d09ade4..dc154e1 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -1043,6 +1043,12 @@
         from the inner packet if it is IPv4 or IPv6 (otherwise it will be the
         system default, typically 64).  Default is the system default TTL.
       </column>
+
+      <column name="options" key="link">
+        Optional.  The name of the network device to use for tunnel output,
+        superseding the decision that the kernel would ordinarily make through
+        routing.
+      </column>
       
       <column name="options" key="df_inherit" type='{"type": "boolean"}'>
         Optional.  If enabled, the Don't Fragment bit will be copied from the
-- 
1.7.4.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to