meta-flow: Correctly set destination MAC in mf_set_flow_value().
[sliver-openvswitch.git] / ofproto / ofproto.c
index b6f9207..766646d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
  * Copyright (c) 2010 Jean Tourrilhes - HP-Labs.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -446,6 +446,16 @@ ofproto_set_forward_bpdu(struct ofproto *ofproto, bool forward_bpdu)
     }
 }
 
+/* Sets the MAC aging timeout for the OFPP_NORMAL action on 'ofproto' to
+ * 'idle_time', in seconds. */
+void
+ofproto_set_mac_idle_time(struct ofproto *ofproto, unsigned idle_time)
+{
+    if (ofproto->ofproto_class->set_mac_idle_time) {
+        ofproto->ofproto_class->set_mac_idle_time(ofproto, idle_time);
+    }
+}
+
 void
 ofproto_set_desc(struct ofproto *p,
                  const char *mfr_desc, const char *hw_desc,
@@ -903,8 +913,9 @@ process_port_change(struct ofproto *ofproto, int error, char *devname)
 int
 ofproto_run(struct ofproto *p)
 {
+    struct sset changed_netdevs;
+    const char *changed_netdev;
     struct ofport *ofport;
-    char *devname;
     int error;
 
     error = p->ofproto_class->run(p);
@@ -913,18 +924,31 @@ ofproto_run(struct ofproto *p)
     }
 
     if (p->ofproto_class->port_poll) {
+        char *devname;
+
         while ((error = p->ofproto_class->port_poll(p, &devname)) != EAGAIN) {
             process_port_change(p, error, devname);
         }
     }
 
+    /* Update OpenFlow port status for any port whose netdev has changed.
+     *
+     * Refreshing a given 'ofport' can cause an arbitrary ofport to be
+     * destroyed, so it's not safe to update ports directly from the
+     * HMAP_FOR_EACH loop, or even to use HMAP_FOR_EACH_SAFE.  Instead, we
+     * need this two-phase approach. */
+    sset_init(&changed_netdevs);
     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));
+            sset_add(&changed_netdevs, netdev_get_name(ofport->netdev));
         }
     }
+    SSET_FOR_EACH (changed_netdev, &changed_netdevs) {
+        update_port(p, changed_netdev);
+    }
+    sset_destroy(&changed_netdevs);
 
 
     switch (p->state) {
@@ -1347,8 +1371,8 @@ ofport_install(struct ofproto *p,
     shash_add(&p->port_by_name, netdev_name, ofport);
 
     if (!netdev_get_mtu(netdev, &dev_mtu)) {
-        set_internal_devs_mtu(p);
         ofport->mtu = dev_mtu;
+        set_internal_devs_mtu(p);
     } else {
         ofport->mtu = 0;
     }
@@ -2833,8 +2857,8 @@ static int
 handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
                              const struct ofp_header *oh)
 {
-    const struct nxt_flow_mod_table_id *msg
-        = (const struct nxt_flow_mod_table_id *) oh;
+    const struct nx_flow_mod_table_id *msg
+        = (const struct nx_flow_mod_table_id *) oh;
 
     ofconn_set_flow_mod_table_id(ofconn, msg->set != 0);
     return 0;
@@ -2843,8 +2867,8 @@ handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
 static int
 handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
 {
-    const struct nxt_set_flow_format *msg
-        = (const struct nxt_set_flow_format *) oh;
+    const struct nx_set_flow_format *msg
+        = (const struct nx_set_flow_format *) oh;
     uint32_t format;
 
     format = ntohl(msg->format);
@@ -2862,6 +2886,29 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
     return 0;
 }
 
+static int
+handle_nxt_set_packet_in_format(struct ofconn *ofconn,
+                                const struct ofp_header *oh)
+{
+    const struct nx_set_packet_in_format *msg;
+    uint32_t format;
+
+    msg = (const struct nx_set_packet_in_format *) oh;
+    format = ntohl(msg->format);
+    if (format != NXFF_OPENFLOW10 && format != NXPIF_NXM) {
+        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM);
+    }
+
+    if (format != ofconn_get_packet_in_format(ofconn)
+        && ofconn_has_pending_opgroups(ofconn)) {
+        /* Avoid sending async message in surprsing packet in format. */
+        return OFPROTO_POSTPONE;
+    }
+
+    ofconn_set_packet_in_format(ofconn, format);
+    return 0;
+}
+
 static int
 handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
@@ -2929,6 +2976,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPUTIL_NXT_SET_FLOW_FORMAT:
         return handle_nxt_set_flow_format(ofconn, oh);
 
+    case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
+        return handle_nxt_set_packet_in_format(ofconn, oh);
+
     case OFPUTIL_NXT_FLOW_MOD:
         return handle_flow_mod(ofconn, oh);
 
@@ -2972,6 +3022,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPUTIL_OFPST_AGGREGATE_REPLY:
     case OFPUTIL_NXT_ROLE_REPLY:
     case OFPUTIL_NXT_FLOW_REMOVED:
+    case OFPUTIL_NXT_PACKET_IN:
     case OFPUTIL_NXST_FLOW_REPLY:
     case OFPUTIL_NXST_AGGREGATE_REPLY:
     default:
@@ -3191,12 +3242,16 @@ ofoperation_complete(struct ofoperation *op, int error)
             if (op->victim) {
                 ofproto_rule_destroy__(op->victim);
             }
-            if (!(rule->cr.wc.vlan_tci_mask & htons(VLAN_VID_MASK))
-                && ofproto->vlan_bitmap) {
-                uint16_t vid = vlan_tci_to_vid(rule->cr.flow.vlan_tci);
-
-                if (!bitmap_is_set(ofproto->vlan_bitmap, vid)) {
-                    bitmap_set1(ofproto->vlan_bitmap, vid);
+            if ((rule->cr.wc.vlan_tci_mask & htons(VLAN_VID_MASK))
+                == htons(VLAN_VID_MASK)) {
+                if (ofproto->vlan_bitmap) {
+                    uint16_t vid = vlan_tci_to_vid(rule->cr.flow.vlan_tci);
+
+                    if (!bitmap_is_set(ofproto->vlan_bitmap, vid)) {
+                        bitmap_set1(ofproto->vlan_bitmap, vid);
+                        ofproto->vlans_changed = true;
+                    }
+                } else {
                     ofproto->vlans_changed = true;
                 }
             }
@@ -3336,7 +3391,8 @@ ofproto_get_vlan_usage(struct ofproto *ofproto, unsigned long int *vlan_bitmap)
         const struct cls_table *table;
 
         HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
-            if (!(table->wc.vlan_tci_mask & htons(VLAN_VID_MASK))) {
+            if ((table->wc.vlan_tci_mask & htons(VLAN_VID_MASK))
+                == htons(VLAN_VID_MASK)) {
                 const struct cls_rule *rule;
 
                 HMAP_FOR_EACH (rule, hmap_node, &table->rules) {