ofp-util: Simplify logic for computing vlan_tci and vlan_tci_mask.
[openvswitch] / ofproto / ofproto.c
index 6ba5561ab09e8d0e85132ec6127c095d017ba7cf..5ab4d3a82097e40adb2a1607649093734bf98cd7 100644 (file)
@@ -64,7 +64,8 @@ COVERAGE_DEFINE(ofproto_update_port);
 static void ofport_destroy__(struct ofport *);
 static void ofport_destroy(struct ofport *);
 
-static int rule_create(struct ofproto *, const struct cls_rule *,
+static int rule_create(struct ofproto *,
+                       const struct cls_rule *, uint8_t table_id,
                        const union ofp_action *, size_t n_actions,
                        uint16_t idle_timeout, uint16_t hard_timeout,
                        ovs_be64 flow_cookie, bool send_flow_removed,
@@ -258,7 +259,6 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     ofproto->sw_desc = xstrdup(DEFAULT_SW_DESC);
     ofproto->serial_desc = xstrdup(DEFAULT_SERIAL_DESC);
     ofproto->dp_desc = xstrdup(DEFAULT_DP_DESC);
-    ofproto->netdev_monitor = netdev_monitor_create();
     hmap_init(&ofproto->ports);
     shash_init(&ofproto->port_by_name);
     ofproto->tables = NULL;
@@ -432,7 +432,7 @@ ofproto_port_clear_cfm(struct ofproto *ofproto, uint16_t ofp_port)
 {
     struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
     if (ofport && ofproto->ofproto_class->set_cfm) {
-        ofproto->ofproto_class->set_cfm(ofport, NULL, NULL, 0);
+        ofproto->ofproto_class->set_cfm(ofport, NULL);
     }
 }
 
@@ -444,7 +444,7 @@ ofproto_port_clear_cfm(struct ofproto *ofproto, uint16_t ofp_port)
  * This function has no effect if 'ofproto' does not have a port 'ofp_port'. */
 void
 ofproto_port_set_cfm(struct ofproto *ofproto, uint16_t ofp_port,
-                     const struct cfm *cfm, uint16_t remote_mpid)
+                     const struct cfm_settings *s)
 {
     struct ofport *ofport;
     int error;
@@ -460,7 +460,7 @@ ofproto_port_set_cfm(struct ofproto *ofproto, uint16_t ofp_port,
      * outside of the CFM module.  It's not clear if this is the correct long
      * term solution or not. */
     error = (ofproto->ofproto_class->set_cfm
-             ? ofproto->ofproto_class->set_cfm(ofport, cfm, &remote_mpid, 1)
+             ? ofproto->ofproto_class->set_cfm(ofport, s)
              : EOPNOTSUPP);
     if (error) {
         VLOG_WARN("%s: CFM configuration on port %"PRIu16" (%s) failed (%s)",
@@ -469,22 +469,6 @@ ofproto_port_set_cfm(struct ofproto *ofproto, uint16_t ofp_port,
     }
 }
 
-/* Returns the connectivity fault management object associated with 'ofp_port'
- * within 'ofproto', or a null pointer if 'ofproto' does not have a port
- * 'ofp_port' or if that port does not have CFM configured.  The caller must
- * not modify or destroy the returned object. */
-const struct cfm *
-ofproto_port_get_cfm(struct ofproto *ofproto, uint16_t ofp_port)
-{
-    struct ofport *ofport;
-    const struct cfm *cfm;
-
-    ofport = ofproto_get_port(ofproto, ofp_port);
-    return (ofport
-            && ofproto->ofproto_class->get_cfm
-            && !ofproto->ofproto_class->get_cfm(ofport, &cfm)) ? cfm : NULL;
-}
-
 /* Checks the status of LACP negotiation for 'ofp_port' within ofproto.
  * Returns 1 if LACP partner information for 'ofp_port' is up-to-date,
  * 0 if LACP partner information is not current (generally indicating a
@@ -602,7 +586,6 @@ ofproto_destroy__(struct ofproto *ofproto)
     free(ofproto->sw_desc);
     free(ofproto->serial_desc);
     free(ofproto->dp_desc);
-    netdev_monitor_destroy(ofproto->netdev_monitor);
     hmap_destroy(&ofproto->ports);
     shash_destroy(&ofproto->port_by_name);
 
@@ -661,6 +644,7 @@ process_port_change(struct ofproto *ofproto, int error, char *devname)
 int
 ofproto_run(struct ofproto *p)
 {
+    struct ofport *ofport;
     char *devname;
     int error;
 
@@ -680,9 +664,13 @@ ofproto_run(struct ofproto *p)
             process_port_change(p, error, devname);
         }
     }
-    while ((error = netdev_monitor_poll(p->netdev_monitor,
-                                        &devname)) != EAGAIN) {
-        process_port_change(p, error, devname);
+
+    HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
+        unsigned int change_seq = netdev_change_seq(ofport->netdev);
+        if (ofport->change_seq != change_seq) {
+            ofport->change_seq = change_seq;
+            update_port(p, netdev_get_name(ofport->netdev));
+        }
     }
 
     connmgr_run(p->connmgr, handle_openflow);
@@ -693,11 +681,18 @@ ofproto_run(struct ofproto *p)
 void
 ofproto_wait(struct ofproto *p)
 {
+    struct ofport *ofport;
+
     p->ofproto_class->wait(p);
     if (p->ofproto_class->port_poll_wait) {
         p->ofproto_class->port_poll_wait(p);
     }
-    netdev_monitor_poll_wait(p->netdev_monitor);
+
+    HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
+        if (ofport->change_seq != netdev_change_seq(ofport->netdev)) {
+            poll_immediate_wake();
+        }
+    }
     connmgr_wait(p->connmgr);
 }
 
@@ -887,7 +882,7 @@ ofproto_add_flow(struct ofproto *p, const struct cls_rule *cls_rule,
                  const union ofp_action *actions, size_t n_actions)
 {
     struct rule *rule;
-    rule_create(p, cls_rule, actions, n_actions, 0, 0, 0, false, &rule);
+    rule_create(p, cls_rule, 0, actions, n_actions, 0, 0, 0, false, &rule);
 }
 
 /* Searches for a rule with matching criteria exactly equal to 'target' in
@@ -1036,11 +1031,11 @@ ofport_install(struct ofproto *p,
     }
     ofport->ofproto = p;
     ofport->netdev = netdev;
+    ofport->change_seq = netdev_change_seq(netdev);
     ofport->opp = *opp;
     ofport->ofp_port = ntohs(opp->port_no);
 
     /* Add port to 'p'. */
-    netdev_monitor_add(p->netdev_monitor, ofport->netdev);
     hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->ofp_port, 0));
     shash_add(&p->port_by_name, netdev_name, ofport);
 
@@ -1107,7 +1102,7 @@ ofproto_port_unregister(struct ofproto *ofproto, uint16_t ofp_port)
     struct ofport *port = ofproto_get_port(ofproto, ofp_port);
     if (port) {
         if (port->ofproto->ofproto_class->set_cfm) {
-            port->ofproto->ofproto_class->set_cfm(port, NULL, NULL, 0);
+            port->ofproto->ofproto_class->set_cfm(port, NULL);
         }
         if (port->ofproto->ofproto_class->bundle_remove) {
             port->ofproto->ofproto_class->bundle_remove(port);
@@ -1121,7 +1116,6 @@ ofport_destroy__(struct ofport *port)
     struct ofproto *ofproto = port->ofproto;
     const char *name = netdev_get_name(port->netdev);
 
-    netdev_monitor_remove(ofproto->netdev_monitor, port->netdev);
     hmap_remove(&ofproto->ports, &port->hmap_node);
     shash_delete(&ofproto->port_by_name,
                  shash_find(&ofproto->port_by_name, name));
@@ -1180,9 +1174,8 @@ update_port(struct ofproto *ofproto, const char *name)
             /* Install the newly opened netdev in case it has changed.
              * Don't close the old netdev yet in case port_modified has to
              * remove a retained reference to it.*/
-            netdev_monitor_remove(ofproto->netdev_monitor, port->netdev);
-            netdev_monitor_add(ofproto->netdev_monitor, netdev);
             port->netdev = netdev;
+            port->change_seq = netdev_change_seq(netdev);
 
             if (port->ofproto->ofproto_class->port_modified) {
                 port->ofproto->ofproto_class->port_modified(port);
@@ -1238,7 +1231,8 @@ init_ports(struct ofproto *p)
  * flow table, and stores the new rule into '*rulep'.  Returns 0 on success,
  * otherwise a positive errno value or OpenFlow error code. */
 static int
-rule_create(struct ofproto *ofproto, const struct cls_rule *cls_rule,
+rule_create(struct ofproto *ofproto,
+            const struct cls_rule *cls_rule, uint8_t table_id,
             const union ofp_action *actions, size_t n_actions,
             uint16_t idle_timeout, uint16_t hard_timeout,
             ovs_be64 flow_cookie, bool send_flow_removed,
@@ -1247,6 +1241,20 @@ rule_create(struct ofproto *ofproto, const struct cls_rule *cls_rule,
     struct rule *rule;
     int error;
 
+    if (table_id == 0xff) {
+        if (ofproto->n_tables > 1) {
+            error = ofproto->ofproto_class->rule_choose_table(ofproto,
+                                                              cls_rule,
+                                                              &table_id);
+            if (error) {
+                return error;
+            }
+            assert(table_id < ofproto->n_tables);
+        } else {
+            table_id = 0;
+        }
+    }
+
     rule = ofproto->ofproto_class->rule_alloc();
     if (!rule) {
         error = ENOMEM;
@@ -1255,6 +1263,7 @@ rule_create(struct ofproto *ofproto, const struct cls_rule *cls_rule,
 
     rule->ofproto = ofproto;
     rule->cr = *cls_rule;
+    rule->table_id = table_id;
     rule->flow_cookie = flow_cookie;
     rule->created = time_msec();
     rule->idle_timeout = idle_timeout;
@@ -2003,6 +2012,18 @@ ofproto_get_netflow_ids(const struct ofproto *ofproto,
     ofproto->ofproto_class->get_netflow_ids(ofproto, engine_type, engine_id);
 }
 
+/* Checks the fault status of CFM for 'ofp_port' within 'ofproto'.  Returns 1
+ * if CFM is faulted (generally indiciating a connectivity problem), 0 if CFM
+ * is not faulted, and -1 if CFM is not enabled on 'ofp_port'. */
+int
+ofproto_port_get_cfm_fault(const struct ofproto *ofproto, uint16_t ofp_port)
+{
+    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
+    return (ofport && ofproto->ofproto_class->get_cfm_fault
+            ? ofproto->ofproto_class->get_cfm_fault(ofport)
+            : -1);
+}
+
 static void
 query_aggregate_stats(struct ofproto *ofproto, struct cls_rule *target,
                       ovs_be16 out_port, uint8_t table_id,
@@ -2213,7 +2234,7 @@ add_flow(struct ofconn *ofconn, struct flow_mod *fm)
     }
 
     buf_err = ofconn_pktbuf_retrieve(ofconn, fm->buffer_id, &packet, &in_port);
-    error = rule_create(p, &fm->cr, fm->actions, fm->n_actions,
+    error = rule_create(p, &fm->cr, fm->table_id, fm->actions, fm->n_actions,
                         fm->idle_timeout, fm->hard_timeout, fm->cookie,
                         fm->flags & OFPFF_SEND_FLOW_REM, &rule);
     if (error) {