debian: Update changelog for 1.1.0~pre2.g1.bbe8d06e-1 upload
[openvswitch] / vswitchd / bridge.c
index c0984361ba117f64afdcf522745bc17f2cd6a1ab..d505b533c9ecc8e774962740454fa61c7758dfcc 100644 (file)
@@ -45,6 +45,7 @@
 #include "list.h"
 #include "mac-learning.h"
 #include "netdev.h"
+#include "netlink.h"
 #include "odp-util.h"
 #include "ofp-print.h"
 #include "ofpbuf.h"
@@ -81,6 +82,16 @@ struct dst {
     uint16_t dp_ifidx;
 };
 
+struct dst_set {
+    struct dst builtin[32];
+    struct dst *dsts;
+    size_t n, allocated;
+};
+
+static void dst_set_init(struct dst_set *);
+static void dst_set_add(struct dst_set *, const struct dst *);
+static void dst_set_free(struct dst_set *);
+
 struct iface {
     /* These members are always valid. */
     struct port *port;          /* Containing port. */
@@ -162,7 +173,6 @@ struct port {
     bool is_mirror_output_port; /* Does port mirroring send frames here? */
 };
 
-#define DP_MAX_PORTS 255
 struct bridge {
     struct list node;           /* Node in global list of bridges. */
     char *name;                 /* User-specified arbitrary name. */
@@ -307,6 +317,17 @@ bridge_init(const char *remote)
     bond_init();
 }
 
+void
+bridge_exit(void)
+{
+    struct bridge *br, *next_br;
+
+    LIST_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
+        bridge_destroy(br);
+    }
+    ovsdb_idl_destroy(idl);
+}
+
 /* Performs configuration that is only necessary once at ovs-vswitchd startup,
  * but for which the ovs-vswitchd configuration 'cfg' is required. */
 static void
@@ -374,30 +395,6 @@ bridge_configure_once(const struct ovsrec_open_vswitch *cfg)
     svec_destroy(&dpif_types);
 }
 
-/* Initializes 'options' and fills it with the options for 'if_cfg'. Merges
- * keys from "options" and "other_config", preferring "options" keys over
- * "other_config" keys. */
-static void
-iface_get_options(const struct ovsrec_interface *if_cfg, struct shash *options)
-{
-    size_t i;
-
-    shash_from_ovs_idl_map(if_cfg->key_options, if_cfg->value_options,
-                           if_cfg->n_options, options);
-
-    for (i = 0; i < if_cfg->n_other_config; i++) {
-        char *key = if_cfg->key_other_config[i];
-        char *value = if_cfg->value_other_config[i];
-
-        if (!shash_find_data(options, key)) {
-            shash_add(options, key, value);
-        } else {
-            VLOG_WARN("%s: ignoring \"other_config\" key %s that conflicts "
-                      "with \"options\" key %s", if_cfg->name, key, key);
-        }
-    }
-}
-
 /* Callback for iterate_and_prune_ifaces(). */
 static bool
 check_iface(struct bridge *br, struct iface *iface, void *aux OVS_UNUSED)
@@ -674,7 +671,9 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 
                 shash_init(&args);
                 if (iface) {
-                    iface_get_options(iface->cfg, &args);
+                    shash_from_ovs_idl_map(iface->cfg->key_options, 
+                                           iface->cfg->value_options,
+                                           iface->cfg->n_options, &args);
                 }
                 error = netdev_open(&options, &netdev);
                 shash_destroy(&args);
@@ -712,7 +711,9 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
                 struct shash args;
 
                 shash_init(&args);
-                iface_get_options(iface->cfg, &args);
+                shash_from_ovs_idl_map(iface->cfg->key_options, 
+                                       iface->cfg->value_options,
+                                       iface->cfg->n_options, &args);
                 netdev_reconfigure(iface->netdev, &args);
                 shash_destroy(&args);
             }
@@ -1100,6 +1101,14 @@ dpid_from_hash(const void *data, size_t n)
     return eth_addr_to_uint64(hash);
 }
 
+static void
+iface_refresh_tunnel_egress(struct iface *iface)
+{
+    const char *name = netdev_get_tnl_iface(iface->netdev);
+
+    ovsrec_interface_set_tunnel_egress_iface(iface->cfg, name);
+}
+
 static void
 iface_refresh_cfm_stats(struct iface *iface)
 {
@@ -1309,6 +1318,7 @@ bridge_run(void)
                         struct iface *iface = port->ifaces[j];
                         iface_refresh_stats(iface);
                         iface_refresh_cfm_stats(iface);
+                        iface_refresh_tunnel_egress(iface);
                     }
                 }
             }
@@ -2226,16 +2236,16 @@ bond_wait(struct bridge *br)
 }
 
 static bool
-set_dst(struct dst *p, const struct flow *flow,
+set_dst(struct dst *dst, const struct flow *flow,
         const struct port *in_port, const struct port *out_port,
         tag_type *tags)
 {
-    p->vlan = (out_port->vlan >= 0 ? OFP_VLAN_NONE
+    dst->vlan = (out_port->vlan >= 0 ? OFP_VLAN_NONE
               : in_port->vlan >= 0 ? in_port->vlan
               : flow->vlan_tci == 0 ? OFP_VLAN_NONE
               : vlan_tci_to_vid(flow->vlan_tci));
-    return choose_output_iface(out_port, flow->dl_src, p->vlan,
-                               &p->dp_ifidx, tags);
+    return choose_output_iface(out_port, flow->dl_src, dst->vlan,
+                               &dst->dp_ifidx, tags);
 }
 
 static void
@@ -2252,10 +2262,10 @@ swap_dst(struct dst *p, struct dst *q)
  * vlan, but in most cases there are at most two different vlan tags so that's
  * possibly overkill.) */
 static void
-partition_dsts(struct dst *dsts, size_t n_dsts, int vlan)
+partition_dsts(struct dst_set *set, int vlan)
 {
-    struct dst *first = dsts;
-    struct dst *last = dsts + n_dsts;
+    struct dst *first = set->dsts;
+    struct dst *last = set->dsts + set->n;
 
     while (first != last) {
         /* Invariants:
@@ -2290,13 +2300,48 @@ mirror_mask_ffs(mirror_mask_t mask)
     return ffs(mask);
 }
 
+static void
+dst_set_init(struct dst_set *set)
+{
+    set->dsts = set->builtin;
+    set->n = 0;
+    set->allocated = ARRAY_SIZE(set->builtin);
+}
+
+static void
+dst_set_add(struct dst_set *set, const struct dst *dst)
+{
+    if (set->n >= set->allocated) {
+        size_t new_allocated;
+        struct dst *new_dsts;
+
+        new_allocated = set->allocated * 2;
+        new_dsts = xmalloc(new_allocated * sizeof *new_dsts);
+        memcpy(new_dsts, set->dsts, set->n * sizeof *new_dsts);
+
+        dst_set_free(set);
+
+        set->dsts = new_dsts;
+        set->allocated = new_allocated;
+    }
+    set->dsts[set->n++] = *dst;
+}
+
+static void
+dst_set_free(struct dst_set *set)
+{
+    if (set->dsts != set->builtin) {
+        free(set->dsts);
+    }
+}
+
 static bool
-dst_is_duplicate(const struct dst *dsts, size_t n_dsts,
-                 const struct dst *test)
+dst_is_duplicate(const struct dst_set *set, const struct dst *test)
 {
     size_t i;
-    for (i = 0; i < n_dsts; i++) {
-        if (dsts[i].vlan == test->vlan && dsts[i].dp_ifidx == test->dp_ifidx) {
+    for (i = 0; i < set->n; i++) {
+        if (set->dsts[i].vlan == test->vlan
+            && set->dsts[i].dp_ifidx == test->dp_ifidx) {
             return true;
         }
     }
@@ -2330,14 +2375,14 @@ port_is_floodable(const struct port *port)
     return true;
 }
 
-static size_t
+static void
 compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan,
              const struct port *in_port, const struct port *out_port,
-             struct dst dsts[], tag_type *tags, uint16_t *nf_output_iface)
+             struct dst_set *set, tag_type *tags, uint16_t *nf_output_iface)
 {
     mirror_mask_t mirrors = in_port->src_mirrors;
+    struct dst dst;
     int flow_vlan;
-    struct dst *dst = dsts;
     size_t i;
 
     flow_vlan = vlan_tci_to_vid(flow->vlan_tci);
@@ -2346,45 +2391,42 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan,
     }
 
     if (out_port == FLOOD_PORT) {
-        /* XXX use ODP_FLOOD if no vlans or bonding. */
-        /* XXX even better, define each VLAN as a datapath port group */
         for (i = 0; i < br->n_ports; i++) {
             struct port *port = br->ports[i];
             if (port != in_port
                 && port_is_floodable(port)
                 && port_includes_vlan(port, vlan)
                 && !port->is_mirror_output_port
-                && set_dst(dst, flow, in_port, port, tags)) {
+                && set_dst(&dst, flow, in_port, port, tags)) {
                 mirrors |= port->dst_mirrors;
-                dst++;
+                dst_set_add(set, &dst);
             }
         }
         *nf_output_iface = NF_OUT_FLOOD;
-    } else if (out_port && set_dst(dst, flow, in_port, out_port, tags)) {
-        *nf_output_iface = dst->dp_ifidx;
+    } else if (out_port && set_dst(&dst, flow, in_port, out_port, tags)) {
+        dst_set_add(set, &dst);
+        *nf_output_iface = dst.dp_ifidx;
         mirrors |= out_port->dst_mirrors;
-        dst++;
     }
 
     while (mirrors) {
         struct mirror *m = br->mirrors[mirror_mask_ffs(mirrors) - 1];
         if (!m->n_vlans || vlan_is_mirrored(m, vlan)) {
             if (m->out_port) {
-                if (set_dst(dst, flow, in_port, m->out_port, tags)
-                    && !dst_is_duplicate(dsts, dst - dsts, dst)) {
-                    dst++;
+                if (set_dst(&dst, flow, in_port, m->out_port, tags)
+                    && !dst_is_duplicate(set, &dst)) {
+                    dst_set_add(set, &dst);
                 }
             } else {
                 for (i = 0; i < br->n_ports; i++) {
                     struct port *port = br->ports[i];
                     if (port_includes_vlan(port, m->out_vlan)
-                        && set_dst(dst, flow, in_port, port, tags))
+                        && set_dst(&dst, flow, in_port, port, tags))
                     {
-
                         if (port->vlan < 0) {
-                            dst->vlan = m->out_vlan;
+                            dst.vlan = m->out_vlan;
                         }
-                        if (dst_is_duplicate(dsts, dst - dsts, dst)) {
+                        if (dst_is_duplicate(set, &dst)) {
                             continue;
                         }
 
@@ -2394,11 +2436,11 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan,
                          * tagging tags place. This is necessary because
                          * dst->vlan is the final vlan, after removing implicit
                          * tags. */
-                        if (port == in_port && dst->vlan == flow_vlan) {
+                        if (port == in_port && dst.vlan == flow_vlan) {
                             /* Don't send out input port on same VLAN. */
                             continue;
                         }
-                        dst++;
+                        dst_set_add(set, &dst);
                     }
                 }
             }
@@ -2406,17 +2448,20 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan,
         mirrors &= mirrors - 1;
     }
 
-    partition_dsts(dsts, dst - dsts, flow_vlan);
-    return dst - dsts;
+    partition_dsts(set, flow_vlan);
 }
 
 static void OVS_UNUSED
-print_dsts(const struct dst *dsts, size_t n)
+print_dsts(const struct dst_set *set)
 {
-    for (; n--; dsts++) {
-        printf(">p%"PRIu16, dsts->dp_ifidx);
-        if (dsts->vlan != OFP_VLAN_NONE) {
-            printf("v%"PRIu16, dsts->vlan);
+    size_t i;
+
+    for (i = 0; i < set->n; i++) {
+        const struct dst *dst = &set->dsts[i];
+
+        printf(">p%"PRIu16, dst->dp_ifidx);
+        if (dst->vlan != OFP_VLAN_NONE) {
+            printf("v%"PRIu16, dst->vlan);
         }
     }
 }
@@ -2424,36 +2469,37 @@ print_dsts(const struct dst *dsts, size_t n)
 static void
 compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan,
                 const struct port *in_port, const struct port *out_port,
-                tag_type *tags, struct odp_actions *actions,
+                tag_type *tags, struct ofpbuf *actions,
                 uint16_t *nf_output_iface)
 {
-    struct dst dsts[DP_MAX_PORTS * (MAX_MIRRORS + 1)];
-    size_t n_dsts;
-    const struct dst *p;
+    struct dst_set set;
     uint16_t cur_vlan;
+    size_t i;
 
-    n_dsts = compose_dsts(br, flow, vlan, in_port, out_port, dsts, tags,
-                          nf_output_iface);
+    dst_set_init(&set);
+    compose_dsts(br, flow, vlan, in_port, out_port, &set, tags,
+                 nf_output_iface);
 
     cur_vlan = vlan_tci_to_vid(flow->vlan_tci);
     if (cur_vlan == 0) {
         cur_vlan = OFP_VLAN_NONE;
     }
-    for (p = dsts; p < &dsts[n_dsts]; p++) {
-        union odp_action *a;
-        if (p->vlan != cur_vlan) {
-            if (p->vlan == OFP_VLAN_NONE) {
-                odp_actions_add(actions, ODPAT_STRIP_VLAN);
+    for (i = 0; i < set.n; i++) {
+        const struct dst *dst = &set.dsts[i];
+        if (dst->vlan != cur_vlan) {
+            if (dst->vlan == OFP_VLAN_NONE) {
+                nl_msg_put_flag(actions, ODPAT_STRIP_VLAN);
             } else {
-                a = odp_actions_add(actions, ODPAT_SET_DL_TCI);
-                a->dl_tci.tci = htons(p->vlan & VLAN_VID_MASK);
-                a->dl_tci.tci |= flow->vlan_tci & htons(VLAN_PCP_MASK);
+                ovs_be16 tci;
+                tci = htons(dst->vlan & VLAN_VID_MASK);
+                tci |= flow->vlan_tci & htons(VLAN_PCP_MASK);
+                nl_msg_put_be16(actions, ODPAT_SET_DL_TCI, tci);
             }
-            cur_vlan = p->vlan;
+            cur_vlan = dst->vlan;
         }
-        a = odp_actions_add(actions, ODPAT_OUTPUT);
-        a->output.port = p->dp_ifidx;
+        nl_msg_put_u32(actions, ODPAT_OUTPUT, dst->dp_ifidx);
     }
+    dst_set_free(&set);
 }
 
 /* Returns the effective vlan of a packet, taking into account both the
@@ -2645,7 +2691,7 @@ is_admissible(struct bridge *br, const struct flow *flow, bool have_packet,
  * not at all, if 'packet' was NULL. */
 static bool
 process_flow(struct bridge *br, const struct flow *flow,
-             const struct ofpbuf *packet, struct odp_actions *actions,
+             const struct ofpbuf *packet, struct ofpbuf *actions,
              tag_type *tags, uint16_t *nf_output_iface)
 {
     struct port *in_port;
@@ -2696,7 +2742,7 @@ done:
 
 static bool
 bridge_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet,
-                        struct odp_actions *actions, tag_type *tags,
+                        struct ofpbuf *actions, tag_type *tags,
                         uint16_t *nf_output_iface, void *br_)
 {
     struct iface *iface;
@@ -2718,14 +2764,15 @@ bridge_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet,
 
 static void
 bridge_account_flow_ofhook_cb(const struct flow *flow, tag_type tags,
-                              const union odp_action *actions,
-                              size_t n_actions, unsigned long long int n_bytes,
-                              void *br_)
+                              const struct nlattr *actions,
+                              size_t actions_len,
+                              unsigned long long int n_bytes, void *br_)
 {
     struct bridge *br = br_;
-    const union odp_action *a;
+    const struct nlattr *a;
     struct port *in_port;
     tag_type dummy = 0;
+    unsigned int left;
     int vlan;
 
     /* Feed information from the active flows back into the learning table to
@@ -2743,9 +2790,9 @@ bridge_account_flow_ofhook_cb(const struct flow *flow, tag_type tags,
     if (!br->has_bonded_ports) {
         return;
     }
-    for (a = actions; a < &actions[n_actions]; a++) {
-        if (a->type == ODPAT_OUTPUT) {
-            struct port *out_port = port_from_dp_ifidx(br, a->output.port);
+    NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) {
+        if (nl_attr_type(a) == ODPAT_OUTPUT) {
+            struct port *out_port = port_from_dp_ifidx(br, nl_attr_get_u32(a));
             if (out_port && out_port->n_ifaces >= 2) {
                 uint16_t vlan = (flow->vlan_tci
                                  ? vlan_tci_to_vid(flow->vlan_tci)
@@ -2942,7 +2989,7 @@ bond_shift_load(struct slave_balance *from, struct slave_balance *to,
 static void
 bond_rebalance_port(struct port *port)
 {
-    struct slave_balance bals[DP_MAX_PORTS];
+    struct slave_balance *bals;
     size_t n_bals;
     struct bond_entry *hashes[BOND_MASK + 1];
     struct slave_balance *b, *from, *to;
@@ -2960,6 +3007,7 @@ bond_rebalance_port(struct port *port)
      * become contiguous in memory, and then we point each 'hashes' members of
      * a slave_balance structure to the start of a contiguous group. */
     n_bals = port->n_ifaces;
+    bals = xmalloc(n_bals * sizeof *bals);
     for (b = bals; b < &bals[n_bals]; b++) {
         b->iface = port->ifaces[b - bals];
         b->tx_bytes = 0;
@@ -2989,7 +3037,7 @@ bond_rebalance_port(struct port *port)
     while (!bals[n_bals - 1].iface->enabled) {
         n_bals--;
         if (!n_bals) {
-            return;
+            goto exit;
         }
     }
 
@@ -3081,6 +3129,9 @@ bond_rebalance_port(struct port *port)
     for (e = &port->bond_hash[0]; e <= &port->bond_hash[BOND_MASK]; e++) {
         e->tx_bytes /= 2;
     }
+
+exit:
+    free(bals);
 }
 
 static void