netdev: Remove may_create/may_open flags.
[sliver-openvswitch.git] / vswitchd / bridge.c
index 7fcfd58..931f987 100644 (file)
@@ -20,6 +20,7 @@
 #include <arpa/inet.h>
 #include <ctype.h>
 #include <inttypes.h>
+#include <sys/socket.h>
 #include <net/if.h>
 #include <openflow/openflow.h>
 #include <signal.h>
@@ -122,7 +123,8 @@ struct port {
     struct bridge *bridge;
     size_t port_idx;
     int vlan;                   /* -1=trunk port, else a 12-bit VLAN ID. */
-    unsigned long *trunks;      /* Bitmap of trunked VLANs, if 'vlan' == -1. */
+    unsigned long *trunks;      /* Bitmap of trunked VLANs, if 'vlan' == -1.
+                                 * NULL if all VLANs are trunked. */
     char *name;
 
     /* An ordinary bridge port has 1 interface.
@@ -394,10 +396,6 @@ set_up_iface(const struct ovsrec_interface *iface_cfg, struct iface *iface,
         }
         netdev_options.args = &options;
         netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
-        netdev_options.may_create = true;
-        if (iface_is_internal(iface->port->bridge, iface_cfg->name)) {
-            netdev_options.may_open = true;
-        }
 
         error = netdev_open(&netdev_options, &iface->netdev);
 
@@ -1985,11 +1983,11 @@ bond_wait(struct bridge *br)
         for (j = 0; j < port->n_ifaces; j++) {
             struct iface *iface = port->ifaces[j];
             if (iface->delay_expires != LLONG_MAX) {
-                poll_timer_wait(iface->delay_expires - time_msec());
+                poll_timer_wait_until(iface->delay_expires);
             }
         }
         if (port->bond_fake_iface) {
-            poll_timer_wait(port->bond_next_fake_iface_update - time_msec());
+            poll_timer_wait_until(port->bond_next_fake_iface_update);
         }
     }
 }
@@ -2073,7 +2071,8 @@ dst_is_duplicate(const struct dst *dsts, size_t n_dsts,
 static bool
 port_trunks_vlan(const struct port *port, uint16_t vlan)
 {
-    return port->vlan < 0 && bitmap_is_set(port->trunks, vlan);
+    return (port->vlan < 0
+            && (!port->trunks || bitmap_is_set(port->trunks, vlan)));
 }
 
 static bool
@@ -2266,12 +2265,17 @@ update_learning_table(struct bridge *br, const flow_t *flow, int vlan,
     }
 }
 
+/* A VM broadcasts a gratuitous ARP to indicate that it has resumed after
+ * migration.  Older Citrix-patched Linux DomU used gratuitous ARP replies to
+ * indicate this; newer upstream kernels use gratuitous ARP requests. */
 static bool
-is_bcast_arp_reply(const flow_t *flow)
+is_gratuitous_arp(const flow_t *flow)
 {
     return (flow->dl_type == htons(ETH_TYPE_ARP)
-            && flow->nw_proto == ARP_OP_REPLY
-            && eth_addr_is_broadcast(flow->dl_dst));
+            && eth_addr_is_broadcast(flow->dl_dst)
+            && (flow->nw_proto == ARP_OP_REPLY
+                || (flow->nw_proto == ARP_OP_REQUEST
+                    && flow->nw_src == flow->nw_dst)));
 }
 
 /* Determines whether packets in 'flow' within 'br' should be forwarded or
@@ -2363,11 +2367,11 @@ is_admissible(struct bridge *br, const flow_t *flow, bool have_packet,
 
         /* Drop all packets for which we have learned a different input
          * port, because we probably sent the packet on one slave and got
-         * it back on the other.  Broadcast ARP replies are an exception
+         * it back on the other.  Gratuitous ARP packets are an exception
          * to this rule: the host has moved to another switch. */
         src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan);
         if (src_idx != -1 && src_idx != in_port->port_idx &&
-            !is_bcast_arp_reply(flow)) {
+            !is_gratuitous_arp(flow)) {
                 return false;
         }
     }
@@ -3354,7 +3358,7 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
 
     /* Get trunked VLANs. */
     trunks = NULL;
-    if (vlan < 0) {
+    if (vlan < 0 && cfg->n_trunks) {
         size_t n_errors;
         size_t i;
 
@@ -3373,17 +3377,14 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
                      port->name, cfg->n_trunks);
         }
         if (n_errors == cfg->n_trunks) {
-            if (n_errors) {
-                VLOG_ERR("port %s: no valid trunks, trunking all VLANs",
-                         port->name);
-            }
-            bitmap_set_multiple(trunks, 0, 4096, 1);
-        }
-    } else {
-        if (cfg->n_trunks) {
-            VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
+            VLOG_ERR("port %s: no valid trunks, trunking all VLANs",
                      port->name);
+            bitmap_free(trunks);
+            trunks = NULL;
         }
+    } else if (vlan >= 0 && cfg->n_trunks) {
+        VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
+                 port->name);
     }
     if (trunks == NULL
         ? port->trunks != NULL
@@ -3392,8 +3393,6 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
     }
     bitmap_free(port->trunks);
     port->trunks = trunks;
-
-    shash_destroy(&new_ifaces);
 }
 
 static void
@@ -3616,6 +3615,8 @@ iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
     iface->netdev = NULL;
     iface->cfg = if_cfg;
 
+    shash_add_assert(&br->iface_by_name, iface->name, iface);
+
     /* Attempt to create the network interface in case it doesn't exist yet. */
     if (!iface_is_internal(br, iface->name)) {
         error = set_up_iface(if_cfg, iface, true);
@@ -3623,14 +3624,13 @@ iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
             VLOG_WARN("could not create iface %s: %s", iface->name,
                       strerror(error));
 
+            shash_find_and_delete_assert(&br->iface_by_name, iface->name);
             free(iface->name);
             free(iface);
             return NULL;
         }
     }
 
-    shash_add_assert(&br->iface_by_name, iface->name, iface);
-
     if (port->n_ifaces >= port->allocated_ifaces) {
         port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,
                                   sizeof *port->ifaces);