packets: Introduce in6_addr_mapped_ipv4() and use where appropriate.
[cascardo/ovs.git] / ofproto / connmgr.c
index 5e2c9c9..ef2c06f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -39,8 +39,8 @@
 #include "simap.h"
 #include "stream.h"
 #include "timeval.h"
-#include "vconn.h"
-#include "vlog.h"
+#include "openvswitch/vconn.h"
+#include "openvswitch/vlog.h"
 
 #include "bundles.h"
 
@@ -60,7 +60,7 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 struct ofconn {
 /* Configuration that persists from one connection to the next. */
 
-    struct list node;           /* In struct connmgr's "all_conns" list. */
+    struct ovs_list node;       /* In struct connmgr's "all_conns" list. */
     struct hmap_node hmap_node; /* In struct connmgr's "controllers" map. */
 
     struct connmgr *connmgr;    /* Connection's manager. */
@@ -131,7 +131,7 @@ struct ofconn {
      *
      * When 'updates' is nonempty, 'sent_abbrev_update' is true if 'updates'
      * contains an update event of type NXFME_ABBREV and false otherwise.. */
-    struct list updates OVS_GUARDED_BY(ofproto_mutex);
+    struct ovs_list updates OVS_GUARDED_BY(ofproto_mutex);
     bool sent_abbrev_update OVS_GUARDED_BY(ofproto_mutex);
 
     /* Active bundles. Contains "struct ofp_bundle"s. */
@@ -162,7 +162,7 @@ static void ofconn_set_rate_limit(struct ofconn *, int rate, int burst);
 static void ofconn_send(const struct ofconn *, struct ofpbuf *,
                         struct rconn_packet_counter *);
 
-static void do_send_packet_ins(struct ofconn *, struct list *txq);
+static void do_send_packet_ins(struct ofconn *, struct ovs_list *txq);
 
 /* A listener for incoming OpenFlow "service" connections. */
 struct ofservice {
@@ -195,8 +195,8 @@ struct connmgr {
     char *local_port_name;
 
     /* OpenFlow connections. */
-    struct hmap controllers;   /* All OFCONN_PRIMARY controllers. */
-    struct list all_conns;     /* All controllers. */
+    struct hmap controllers;     /* All OFCONN_PRIMARY controllers. */
+    struct ovs_list all_conns;   /* All controllers. */
     uint64_t master_election_id; /* monotonically increasing sequence number
                                   * for master election */
     bool master_election_id_defined;
@@ -417,7 +417,7 @@ connmgr_get_memory_usage(const struct connmgr *mgr, struct simap *usage)
             struct pinsched_stats stats;
 
             pinsched_get_stats(ofconn->schedulers[i], &stats);
-            packets += stats.n_queued;;
+            packets += stats.n_queued;
         }
         packets += pktbuf_count_packets(ofconn->pktbuf);
     }
@@ -740,8 +740,7 @@ update_in_band_remotes(struct connmgr *mgr)
         } sa;
 
         if (ofconn->band == OFPROTO_IN_BAND
-            && stream_parse_target_with_default_port(target, OFP_OLD_PORT,
-                                                     &sa.ss)
+            && stream_parse_target_with_default_port(target, OFP_PORT, &sa.ss)
             && sa.ss.ss_family == AF_INET) {
             addrs[n_addrs++] = sa.in;
         }
@@ -996,6 +995,34 @@ void
 ofconn_set_protocol(struct ofconn *ofconn, enum ofputil_protocol protocol)
 {
     ofconn->protocol = protocol;
+    if (!(protocol & OFPUTIL_P_OF14_UP)) {
+        uint32_t *master = ofconn->master_async_config;
+        uint32_t *slave = ofconn->slave_async_config;
+
+        /* OFPR_ACTION_SET is not supported before OF1.4 */
+        master[OAM_PACKET_IN] &= ~(1u << OFPR_ACTION_SET);
+        slave [OAM_PACKET_IN] &= ~(1u << OFPR_ACTION_SET);
+
+        /* OFPR_GROUP is not supported before OF1.4 */
+        master[OAM_PACKET_IN] &= ~(1u << OFPR_GROUP);
+        slave [OAM_PACKET_IN] &= ~(1u << OFPR_GROUP);
+
+        /* OFPR_PACKET_OUT is not supported before OF1.4 */
+        master[OAM_PACKET_IN] &= ~(1u << OFPR_PACKET_OUT);
+        slave [OAM_PACKET_IN] &= ~(1u << OFPR_PACKET_OUT);
+
+        /* OFPRR_GROUP_DELETE is not supported before OF1.4 */
+        master[OAM_FLOW_REMOVED] &= ~(1u << OFPRR_GROUP_DELETE);
+        slave [OAM_FLOW_REMOVED] &= ~(1u << OFPRR_GROUP_DELETE);
+
+        /* OFPRR_METER_DELETE is not supported before OF1.4 */
+        master[OAM_FLOW_REMOVED] &= ~(1u << OFPRR_METER_DELETE);
+        slave [OAM_FLOW_REMOVED] &= ~(1u << OFPRR_METER_DELETE);
+
+        /* OFPRR_EVICTION is not supported before OF1.4 */
+        master[OAM_FLOW_REMOVED] &= ~(1u << OFPRR_EVICTION);
+        slave [OAM_FLOW_REMOVED] &= ~(1u << OFPRR_EVICTION);
+    }
 }
 
 /* Returns the currently configured packet in format for 'ofconn', one of
@@ -1056,6 +1083,13 @@ ofconn_get_async_config(struct ofconn *ofconn,
                         uint32_t *master_masks, uint32_t *slave_masks)
 {
     size_t size = sizeof ofconn->master_async_config;
+
+    /* Make sure we know the protocol version and the async_config
+     * masks are properly updated by calling ofconn_get_protocol() */
+    if (OFPUTIL_P_NONE == ofconn_get_protocol(ofconn)){
+        OVS_NOT_REACHED();
+    }
+
     memcpy(master_masks, ofconn->master_async_config, size);
     memcpy(slave_masks, ofconn->slave_async_config, size);
 }
@@ -1073,12 +1107,11 @@ ofconn_send_reply(const struct ofconn *ofconn, struct ofpbuf *msg)
 /* Sends each of the messages in list 'replies' on 'ofconn' in order,
  * accounting them as replies. */
 void
-ofconn_send_replies(const struct ofconn *ofconn, struct list *replies)
+ofconn_send_replies(const struct ofconn *ofconn, struct ovs_list *replies)
 {
-    struct ofpbuf *reply, *next;
+    struct ofpbuf *reply;
 
-    LIST_FOR_EACH_SAFE (reply, next, list_node, replies) {
-        list_remove(&reply->list_node);
+    LIST_FOR_EACH_POP (reply, list_node, replies) {
         ofconn_send_reply(ofconn, reply);
     }
 }
@@ -1114,7 +1147,7 @@ ofconn_send_error(const struct ofconn *ofconn,
 /* Same as pktbuf_retrieve(), using the pktbuf owned by 'ofconn'. */
 enum ofperr
 ofconn_pktbuf_retrieve(struct ofconn *ofconn, uint32_t id,
-                       struct ofpbuf **bufferp, ofp_port_t *in_port)
+                       struct dp_packet **bufferp, ofp_port_t *in_port)
 {
     return pktbuf_retrieve(ofconn->pktbuf, id, bufferp, in_port);
 }
@@ -1151,13 +1184,56 @@ ofconn_report_flow_mod(struct ofconn *ofconn,
     }
     ofconn->last_op = now;
 }
+\f
+/* OpenFlow 1.4 bundles. */
+
+static inline uint32_t
+bundle_hash(uint32_t id)
+{
+    return hash_int(id, 0);
+}
 
-struct hmap *
-ofconn_get_bundles(struct ofconn *ofconn)
+struct ofp_bundle *
+ofconn_get_bundle(struct ofconn *ofconn, uint32_t id)
 {
-    return &ofconn->bundles;
+    struct ofp_bundle *bundle;
+
+    HMAP_FOR_EACH_IN_BUCKET(bundle, node, bundle_hash(id), &ofconn->bundles) {
+        if (bundle->id == id) {
+            return bundle;
+        }
+    }
+
+    return NULL;
 }
 
+enum ofperr
+ofconn_insert_bundle(struct ofconn *ofconn, struct ofp_bundle *bundle)
+{
+    /* XXX: Check the limit of open bundles */
+
+    hmap_insert(&ofconn->bundles, &bundle->node, bundle_hash(bundle->id));
+
+    return 0;
+}
+
+enum ofperr
+ofconn_remove_bundle(struct ofconn *ofconn, struct ofp_bundle *bundle)
+{
+    hmap_remove(&ofconn->bundles, &bundle->node);
+
+    return 0;
+}
+
+static void
+bundle_remove_all(struct ofconn *ofconn)
+{
+    struct ofp_bundle *b, *next;
+
+    HMAP_FOR_EACH_SAFE (b, next, node, &ofconn->bundles) {
+        ofp_bundle_remove__(ofconn, b, false);
+    }
+}
 \f
 /* Private ofconn functions. */
 
@@ -1235,20 +1311,32 @@ ofconn_flush(struct ofconn *ofconn)
         /* "master" and "other" roles get all asynchronous messages by default,
          * except that the controller needs to enable nonstandard "packet-in"
          * reasons itself. */
-        master[OAM_PACKET_IN] = (1u << OFPR_NO_MATCH) | (1u << OFPR_ACTION);
+        master[OAM_PACKET_IN] = ((1u << OFPR_NO_MATCH)
+                                 | (1u << OFPR_ACTION)
+                                 | (1u << OFPR_ACTION_SET)
+                                 | (1u << OFPR_GROUP)
+                                 | (1u << OFPR_PACKET_OUT));
         master[OAM_PORT_STATUS] = ((1u << OFPPR_ADD)
                                    | (1u << OFPPR_DELETE)
                                    | (1u << OFPPR_MODIFY));
         master[OAM_FLOW_REMOVED] = ((1u << OFPRR_IDLE_TIMEOUT)
                                     | (1u << OFPRR_HARD_TIMEOUT)
-                                    | (1u << OFPRR_DELETE));
-
+                                    | (1u << OFPRR_DELETE)
+                                    | (1u << OFPRR_GROUP_DELETE)
+                                    | (1u << OFPRR_METER_DELETE)
+                                    | (1u << OFPRR_EVICTION));
+        master[OAM_ROLE_STATUS] = 0;
+        master[OAM_TABLE_STATUS] = 0;
+        master[OAM_REQUESTFORWARD] = 0;
         /* "slave" role gets port status updates by default. */
         slave[OAM_PACKET_IN] = 0;
         slave[OAM_PORT_STATUS] = ((1u << OFPPR_ADD)
                                   | (1u << OFPPR_DELETE)
                                   | (1u << OFPPR_MODIFY));
         slave[OAM_FLOW_REMOVED] = 0;
+        slave[OAM_ROLE_STATUS] = 0;
+        slave[OAM_TABLE_STATUS] = 0;
+        slave[OAM_REQUESTFORWARD] = 0;
     } else {
         memset(ofconn->master_async_config, 0,
                sizeof ofconn->master_async_config);
@@ -1280,7 +1368,8 @@ ofconn_destroy(struct ofconn *ofconn)
         hmap_remove(&ofconn->connmgr->controllers, &ofconn->hmap_node);
     }
 
-    ofp_bundle_remove_all(ofconn);
+    bundle_remove_all(ofconn);
+    hmap_destroy(&ofconn->bundles);
 
     hmap_destroy(&ofconn->monitors);
     list_remove(&ofconn->node);
@@ -1334,7 +1423,7 @@ ofconn_run(struct ofconn *ofconn,
     size_t i;
 
     for (i = 0; i < N_SCHEDULERS; i++) {
-        struct list txq;
+        struct ovs_list txq;
 
         pinsched_run(ofconn->schedulers[i], &txq);
         do_send_packet_ins(ofconn, &txq);
@@ -1435,7 +1524,7 @@ ofconn_log_flow_mods(struct ofconn *ofconn)
  * 'ofconn'. */
 static bool
 ofconn_receives_async_msg(const struct ofconn *ofconn,
-                          enum ofconn_async_msg_type type,
+                          enum ofputil_async_msg_type type,
                           unsigned int reason)
 {
     const uint32_t *async_config;
@@ -1484,14 +1573,11 @@ ofconn_wants_packet_in_on_miss(struct ofconn *ofconn,
         enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
 
         if (protocol != OFPUTIL_P_NONE
-            && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION) {
-            enum ofproto_table_config config;
-
-            config = ofproto_table_get_config(ofconn->connmgr->ofproto,
-                                              pin->up.table_id);
-            if (config == OFPROTO_TABLE_MISS_DEFAULT) {
-                return false;
-            }
+            && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION
+            && (ofproto_table_get_miss_config(ofconn->connmgr->ofproto,
+                                              pin->up.table_id)
+                == OFPUTIL_TABLE_MISS_DEFAULT)) {
+            return false;
         }
     }
     return true;
@@ -1623,6 +1709,28 @@ connmgr_send_port_status(struct connmgr *mgr, struct ofconn *source,
     }
 }
 
+/* Sends an OFPT_REQUESTFORWARD message with 'request' and 'reason' to
+ * appropriate controllers managed by 'mgr'.  For messages caused by a
+ * controller OFPT_GROUP_MOD and OFPT_METER_MOD, specify 'source' as the
+ * controller connection that sent the request; otherwise, specify 'source'
+ * as NULL. */
+void
+connmgr_send_requestforward(struct connmgr *mgr, const struct ofconn *source,
+                            const struct ofputil_requestforward *rf)
+{
+    struct ofconn *ofconn;
+
+    LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
+        if (ofconn_receives_async_msg(ofconn, OAM_REQUESTFORWARD, rf->reason)
+            && rconn_get_version(ofconn->rconn) >= OFP14_VERSION
+            && ofconn != source) {
+            enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
+            ofconn_send(ofconn, ofputil_encode_requestforward(rf, protocol),
+                        NULL);
+        }
+    }
+}
+
 /* Sends an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message based on 'fr' to
  * appropriate controllers managed by 'mgr'. */
 void
@@ -1654,16 +1762,31 @@ connmgr_send_flow_removed(struct connmgr *mgr,
 static enum ofp_packet_in_reason
 wire_reason(struct ofconn *ofconn, const struct ofproto_packet_in *pin)
 {
-    if (pin->miss_type == OFPROTO_PACKET_IN_MISS_FLOW
-        && pin->up.reason == OFPR_ACTION) {
-        enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
+    enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
 
-        if (protocol != OFPUTIL_P_NONE
-            && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION) {
-            return OFPR_NO_MATCH;
+    if (pin->miss_type == OFPROTO_PACKET_IN_MISS_FLOW
+        && pin->up.reason == OFPR_ACTION
+        && protocol != OFPUTIL_P_NONE
+        && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION) {
+        return OFPR_NO_MATCH;
+    }
+
+    switch (pin->up.reason) {
+    case OFPR_ACTION_SET:
+    case OFPR_GROUP:
+    case OFPR_PACKET_OUT:
+        if (!(protocol & OFPUTIL_P_OF14_UP)) {
+            /* Only supported in OF1.4+ */
+            return OFPR_ACTION;
         }
+        /* Fall through. */
+       case OFPR_NO_MATCH:
+       case OFPR_ACTION:
+       case OFPR_INVALID_TTL:
+       case OFPR_N_REASONS:
+    default:
+        return pin->up.reason;
     }
-    return pin->up.reason;
 }
 
 /* Given 'pin', sends an OFPT_PACKET_IN message to each OpenFlow controller as
@@ -1680,7 +1803,7 @@ connmgr_send_packet_in(struct connmgr *mgr,
         enum ofp_packet_in_reason reason = wire_reason(ofconn, pin);
 
         if (ofconn_wants_packet_in_on_miss(ofconn, pin)
-            && ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->up.reason)
+            && ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, reason)
             && ofconn->controller_id == pin->controller_id) {
             schedule_packet_in(ofconn, *pin, reason);
         }
@@ -1688,13 +1811,11 @@ connmgr_send_packet_in(struct connmgr *mgr,
 }
 
 static void
-do_send_packet_ins(struct ofconn *ofconn, struct list *txq)
+do_send_packet_ins(struct ofconn *ofconn, struct ovs_list *txq)
 {
-    struct ofpbuf *pin, *next_pin;
-
-    LIST_FOR_EACH_SAFE (pin, next_pin, list_node, txq) {
-        list_remove(&pin->list_node);
+    struct ofpbuf *pin;
 
+    LIST_FOR_EACH_POP (pin, list_node, txq) {
         if (rconn_send_with_limit(ofconn->rconn, pin,
                                   ofconn->packet_in_counter, 100) == EAGAIN) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
@@ -1713,7 +1834,7 @@ schedule_packet_in(struct ofconn *ofconn, struct ofproto_packet_in pin,
 {
     struct connmgr *mgr = ofconn->connmgr;
     uint16_t controller_max_len;
-    struct list txq;
+    struct ovs_list txq;
 
     pin.up.total_len = pin.up.packet_len;
 
@@ -1736,7 +1857,7 @@ schedule_packet_in(struct ofconn *ofconn, struct ofproto_packet_in pin,
     } else {
         pin.up.buffer_id = pktbuf_save(ofconn->pktbuf,
                                        pin.up.packet, pin.up.packet_len,
-                                       pin.up.fmd.in_port);
+                                       pin.up.flow_metadata.flow.in_port.ofp_port);
     }
 
     /* Figure out how much of the packet to send.
@@ -1749,7 +1870,7 @@ schedule_packet_in(struct ofconn *ofconn, struct ofproto_packet_in pin,
 
     /* Make OFPT_PACKET_IN and hand over to packet scheduler. */
     pinsched_send(ofconn->schedulers[pin.up.reason == OFPR_NO_MATCH ? 0 : 1],
-                  pin.up.fmd.in_port,
+                  pin.up.flow_metadata.flow.in_port.ofp_port,
                   ofputil_encode_packet_in(&pin.up,
                                            ofconn_get_protocol(ofconn),
                                            ofconn->packet_in_format),
@@ -1944,12 +2065,29 @@ connmgr_flushed(struct connmgr *mgr)
         ofpact_pad(&ofpacts);
 
         match_init_catchall(&match);
-        ofproto_add_flow(mgr->ofproto, &match, 0, ofpbuf_data(&ofpacts),
-                                                  ofpbuf_size(&ofpacts));
+        ofproto_add_flow(mgr->ofproto, &match, 0, ofpacts.data,
+                                                  ofpacts.size);
 
         ofpbuf_uninit(&ofpacts);
     }
 }
+
+/* Returns the number of hidden rules created by the in-band and fail-open
+ * implementations in table 0.  (Subtracting this count from the number of
+ * rules in the table 0 classifier, as maintained in struct oftable, yields
+ * the number of flows that OVS should report via OpenFlow for table 0.) */
+int
+connmgr_count_hidden_rules(const struct connmgr *mgr)
+{
+    int n_hidden = 0;
+    if (mgr->in_band) {
+        n_hidden += in_band_count_rules(mgr->in_band);
+    }
+    if (mgr->fail_open) {
+        n_hidden += fail_open_count_rules(mgr->fail_open);
+    }
+    return n_hidden;
+}
 \f
 /* Creates a new ofservice for 'target' in 'mgr'.  Returns 0 if successful,
  * otherwise a positive errno value.
@@ -2204,12 +2342,11 @@ ofmonitor_flush(struct connmgr *mgr)
     struct ofconn *ofconn;
 
     LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
-        struct ofpbuf *msg, *next;
+        struct ofpbuf *msg;
 
-        LIST_FOR_EACH_SAFE (msg, next, list_node, &ofconn->updates) {
+        LIST_FOR_EACH_POP (msg, list_node, &ofconn->updates) {
             unsigned int n_bytes;
 
-            list_remove(&msg->list_node);
             ofconn_send(ofconn, msg, ofconn->monitor_counter);
             n_bytes = rconn_packet_counter_n_bytes(ofconn->monitor_counter);
             if (!ofconn->monitor_paused && n_bytes > 128 * 1024) {
@@ -2232,7 +2369,7 @@ ofmonitor_resume(struct ofconn *ofconn)
     struct rule_collection rules;
     struct ofpbuf *resumed;
     struct ofmonitor *m;
-    struct list msgs;
+    struct ovs_list msgs;
 
     rule_collection_init(&rules);
     HMAP_FOR_EACH (m, ofconn_node, &ofconn->monitors) {