[ovs-dev] [RFC PATCH 09/13] tunneling: ofproto-dpif: prevent IPv6 loops

Jiri Benc jbenc at redhat.com
Thu May 14 18:12:40 UTC 2015


Store the original IP address similarly to IPv4.

Change the is_tunnel boolean to the outer protocol; null protocol indicates
no tunnel.

Signed-off-by: Jiri Benc <jbenc at redhat.com>
---
 ofproto/ofproto-dpif-xlate.c | 27 +++++++++++++++++----------
 ofproto/ofproto-dpif-xlate.h |  2 +-
 ofproto/ofproto-dpif.c       | 28 +++++++++++++++-------------
 3 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index f73787744db3..0307982c9c19 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -159,7 +159,8 @@ struct xport {
     struct hmap skb_priorities;      /* Map of 'skb_priority_to_dscp's. */
 
     bool may_enable;                 /* May be enabled in bonds. */
-    bool is_tunnel;                  /* Is a tunnel port. */
+    uint16_t tunnel_protocol;        /* Tunnel underlying protocol.
+                                      * 0 when not a tunnel port. */
 
     struct cfm *cfm;                 /* CFM handle or null. */
     struct bfd *bfd;                 /* BFD handle or null. */
@@ -182,6 +183,7 @@ struct xlate_ctx {
      * if a tunnel is marked as 'ip_remote=flow', and the flow does not
      * actually set the tun_dst field. */
     ovs_be32 orig_tunnel_ip_dst;
+    struct in6_addr orig_tunnel_ipv6_dst;
 
     /* Stack for the push and pop actions.  Each stack element is of type
      * "union mf_subvalue". */
@@ -506,7 +508,8 @@ static void xlate_xport_set(struct xport *xport, odp_port_t odp_port,
                             const struct bfd *bfd, const struct lldp *lldp,
                             int stp_port_no, const struct rstp_port *rstp_port,
                             enum ofputil_port_config config,
-                            enum ofputil_port_state state, bool is_tunnel,
+                            enum ofputil_port_state state,
+                            uint16_t tunnel_protocol,
                             bool may_enable);
 static void xlate_xbridge_remove(struct xlate_cfg *, struct xbridge *);
 static void xlate_xbundle_remove(struct xlate_cfg *, struct xbundle *);
@@ -649,12 +652,12 @@ xlate_xport_set(struct xport *xport, odp_port_t odp_port,
                 const struct bfd *bfd, const struct lldp *lldp, int stp_port_no,
                 const struct rstp_port* rstp_port,
                 enum ofputil_port_config config, enum ofputil_port_state state,
-                bool is_tunnel, bool may_enable)
+                uint16_t tunnel_protocol, bool may_enable)
 {
     xport->config = config;
     xport->state = state;
     xport->stp_port_no = stp_port_no;
-    xport->is_tunnel = is_tunnel;
+    xport->tunnel_protocol = tunnel_protocol;
     xport->may_enable = may_enable;
     xport->odp_port = odp_port;
 
@@ -747,7 +750,7 @@ xlate_xport_copy(struct xbridge *xbridge, struct xbundle *xbundle,
     xlate_xport_set(new_xport, xport->odp_port, xport->netdev, xport->cfm,
                     xport->bfd, xport->lldp, xport->stp_port_no,
                     xport->rstp_port, xport->config, xport->state,
-                    xport->is_tunnel, xport->may_enable);
+                    xport->tunnel_protocol, xport->may_enable);
 
     if (xport->peer) {
         struct xport *peer = xport_lookup(new_xcfg, xport->peer->ofport);
@@ -987,7 +990,7 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
                  int stp_port_no, const struct rstp_port *rstp_port,
                  const struct ofproto_port_queue *qdscp_list, size_t n_qdscp,
                  enum ofputil_port_config config,
-                 enum ofputil_port_state state, bool is_tunnel,
+                 enum ofputil_port_state state, uint16_t tunnel_protocol,
                  bool may_enable)
 {
     size_t i;
@@ -1008,7 +1011,7 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
     ovs_assert(xport->ofp_port == ofp_port);
 
     xlate_xport_set(xport, odp_port, netdev, cfm, bfd, lldp,
-                    stp_port_no, rstp_port, config, state, is_tunnel,
+                    stp_port_no, rstp_port, config, state, tunnel_protocol,
                     may_enable);
 
     if (xport->peer) {
@@ -2904,7 +2907,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         }
     }
 
-    if (xport->is_tunnel) {
+    if (xport->tunnel_protocol) {
          /* Save tunnel metadata so that changes made due to
           * the Logical (tunnel) Port are not visible for any further
           * matches, while explicit set actions on tunnel metadata are.
@@ -2915,7 +2918,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
             xlate_report(ctx, "Tunneling decided against output");
             goto out; /* restore flow_nw_tos */
         }
-        if (flow->tunnel.ip_dst == ctx->orig_tunnel_ip_dst) {
+        if ((xport->tunnel_protocol == ETH_TYPE_IP &&
+             flow->tunnel.ip_dst == ctx->orig_tunnel_ip_dst) ||
+            (xport->tunnel_protocol == ETH_TYPE_IPV6 &&
+             ipv6_addr_equals(&flow->tunnel.ipv6_dst, &ctx->orig_tunnel_ipv6_dst))) {
             xlate_report(ctx, "Not tunneling to our own address");
             goto out; /* restore flow_nw_tos */
         }
@@ -4734,6 +4740,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     ctx.base_flow = *flow;
     memset(&ctx.base_flow.tunnel, 0, sizeof ctx.base_flow.tunnel);
     ctx.orig_tunnel_ip_dst = flow->tunnel.ip_dst;
+    ctx.orig_tunnel_ipv6_dst = flow->tunnel.ipv6_dst;
 
     if (!xin->skip_wildcards) {
         wc = &xout->wc;
@@ -4893,7 +4900,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     }
 
     /* Tunnel stats only for non-recirculated packets. */
-    if (!xin->recirc && in_port && in_port->is_tunnel) {
+    if (!xin->recirc && in_port && in_port->tunnel_protocol) {
         if (ctx.xin->resubmit_stats) {
             netdev_vport_inc_rx(in_port->netdev, ctx.xin->resubmit_stats);
             if (in_port->bfd) {
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index 6c8ade308c77..84b9a02cc295 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -231,7 +231,7 @@ void xlate_ofport_set(struct ofproto_dpif *, struct ofbundle *,
                       int stp_port_no, const struct rstp_port *rstp_port,
                       const struct ofproto_port_queue *qdscp,
                       size_t n_qdscp, enum ofputil_port_config,
-                      enum ofputil_port_state, bool is_tunnel,
+                      enum ofputil_port_state, uint16_t tunnel_protocol,
                       bool may_enable);
 void xlate_ofport_remove(struct ofport_dpif *);
 
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index bf893214b524..1d17761134cb 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -164,8 +164,8 @@ struct ofport_dpif {
     struct cfm *cfm;            /* Connectivity Fault Management, if any. */
     struct bfd *bfd;            /* BFD, if any. */
     struct lldp *lldp;          /* lldp, if any. */
+    uint16_t tunnel_protocol;   /* Tunnel underlaying protocol or 0. */
     bool may_enable;            /* May be enabled in bonds. */
-    bool is_tunnel;             /* This port is a tunnel. */
     bool is_layer3;             /* This is a layer 3 port. */
     long long int carrier_seq;  /* Carrier status changes. */
     struct ofport_dpif *peer;   /* Peer if patch port. */
@@ -579,7 +579,7 @@ type_run(const char *type)
                 char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
                 const char *dp_port;
 
-                if (!iter->is_tunnel) {
+                if (!iter->tunnel_protocol) {
                     continue;
                 }
 
@@ -669,7 +669,7 @@ type_run(const char *type)
                                  ofport->lldp, ofport->peer, stp_port,
                                  ofport->rstp_port, ofport->qdscp,
                                  ofport->n_qdscp, ofport->up.pp.config,
-                                 ofport->up.pp.state, ofport->is_tunnel,
+                                 ofport->up.pp.state, ofport->tunnel_protocol,
                                  ofport->may_enable);
             }
             xlate_txn_commit();
@@ -1641,6 +1641,7 @@ port_construct(struct ofport *port_)
     struct ofport_dpif *port = ofport_dpif_cast(port_);
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
     const struct netdev *netdev = port->up.netdev;
+    const struct netdev_tunnel_config *tnl_cfg;
     char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
     struct dpif_port dpif_port;
     int error;
@@ -1655,7 +1656,7 @@ port_construct(struct ofport *port_)
     port->stp_state = STP_DISABLED;
     port->rstp_port = NULL;
     port->rstp_state = RSTP_DISABLED;
-    port->is_tunnel = false;
+    port->tunnel_protocol = 0;
     port->peer = NULL;
     port->qdscp = NULL;
     port->n_qdscp = 0;
@@ -1685,11 +1686,12 @@ port_construct(struct ofport *port_)
 
     port->odp_port = dpif_port.port_no;
 
-    if (netdev_get_tunnel_config(netdev)) {
+    tnl_cfg = netdev_get_tunnel_config(netdev);
+    if (tnl_cfg) {
         atomic_count_inc(&ofproto->backer->tnl_count);
         tnl_port_add(port, port->up.netdev, port->odp_port,
                      ovs_native_tunneling_is_on(ofproto), namebuf);
-        port->is_tunnel = true;
+        port->tunnel_protocol = tnl_cfg->protocol;
         if (ofproto->ipfix) {
            dpif_ipfix_add_tunnel_port(ofproto->ipfix, port_, port->odp_port);
         }
@@ -1738,7 +1740,7 @@ port_destruct(struct ofport *port_)
          * happens when the ofproto is being destroyed, since the caller
          * assumes that removal of attached ports will happen as part of
          * destruction. */
-        if (!port->is_tunnel) {
+        if (!port->tunnel_protocol) {
             dpif_port_del(ofproto->backer->dpif, port->odp_port);
         }
     }
@@ -1748,17 +1750,17 @@ port_destruct(struct ofport *port_)
         port->peer = NULL;
     }
 
-    if (port->odp_port != ODPP_NONE && !port->is_tunnel) {
+    if (port->odp_port != ODPP_NONE && !port->tunnel_protocol) {
         ovs_rwlock_wrlock(&ofproto->backer->odp_to_ofport_lock);
         hmap_remove(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node);
         ovs_rwlock_unlock(&ofproto->backer->odp_to_ofport_lock);
     }
 
-    if (port->is_tunnel) {
+    if (port->tunnel_protocol) {
         atomic_count_dec(&ofproto->backer->tnl_count);
     }
 
-    if (port->is_tunnel && ofproto->ipfix) {
+    if (port->tunnel_protocol && ofproto->ipfix) {
        dpif_ipfix_del_tunnel_port(ofproto->ipfix, port->odp_port);
     }
 
@@ -1804,7 +1806,7 @@ port_modified(struct ofport *port_)
 
     netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
 
-    if (port->is_tunnel) {
+    if (port->tunnel_protocol) {
         struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
 
         if (tnl_port_reconfigure(port, netdev, port->odp_port,
@@ -1893,7 +1895,7 @@ set_ipfix(
         if (new_di == true) {
             struct ofport_dpif *ofport;
             HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
-                if (ofport->is_tunnel == true) {
+                if (ofport->tunnel_protocol) {
                     dpif_ipfix_add_tunnel_port(di, &ofport->up, ofport->odp_port);
                 }
             }
@@ -3397,7 +3399,7 @@ port_del(struct ofproto *ofproto_, ofp_port_t ofp_port)
     sset_find_and_delete(&ofproto->ghost_ports,
                          netdev_get_name(ofport->up.netdev));
     ofproto->backer->need_revalidate = REV_RECONFIGURE;
-    if (!ofport->is_tunnel && !netdev_vport_is_patch(ofport->up.netdev)) {
+    if (!ofport->tunnel_protocol && !netdev_vport_is_patch(ofport->up.netdev)) {
         error = dpif_port_del(ofproto->backer->dpif, ofport->odp_port);
         if (!error) {
             /* The caller is going to close ofport->up.netdev.  If this is a
-- 
1.8.3.1




More information about the dev mailing list