Modify OpenFlow commands related to ports to be more expressive.
authorJustin Pettit <jpettit@nicira.com>
Mon, 22 Sep 2008 22:18:22 +0000 (15:18 -0700)
committerJustin Pettit <jpettit@nicira.com>
Mon, 22 Sep 2008 22:18:22 +0000 (15:18 -0700)
This new OpenFlow message format provides a cleaner interface and greater
detail and control over ports.  It is now possible to see what features
the switch's port is currently configured as having, what it's advertising,
and what it's capable of handling.  It is also possible to return the
features advertised by the port's peer.

12 files changed:
datapath/datapath.c
datapath/datapath.h
datapath/dp_notify.c
datapath/forward.c
include/netdev.h
include/openflow.h
lib/learning-switch.c
lib/netdev.c
lib/ofp-print.c
secchan/secchan.c
switch/datapath.c
utilities/dpctl.c

index 564d303..056f186 100644 (file)
@@ -506,12 +506,12 @@ static inline unsigned packet_length(const struct sk_buff *skb)
 static int
 output_all(struct datapath *dp, struct sk_buff *skb, int flood)
 {
-       u32 disable = flood ? OFPPFL_NO_FLOOD : 0;
+       u32 disable = flood ? OFPPC_NO_FLOOD : 0;
        struct net_bridge_port *p;
        int prev_port = -1;
 
        list_for_each_entry_rcu (p, &dp->port_list, node) {
-               if (skb->dev == p->dev || p->flags & disable)
+               if (skb->dev == p->dev || p->config & disable)
                        continue;
                if (prev_port != -1) {
                        struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
@@ -613,7 +613,7 @@ int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port,
                                printk("can't directly forward to input port\n");
                        return -EINVAL;
                }
-               if (p->flags & OFPPFL_NO_FWD && !ignore_no_fwd) {
+               if (p->config & OFPPC_NO_FWD && !ignore_no_fwd) {
                        kfree_skb(skb);
                        return 0;
                }
@@ -681,12 +681,14 @@ static void fill_port_desc(struct net_bridge_port *p, struct ofp_phy_port *desc)
        strncpy(desc->name, p->dev->name, OFP_MAX_PORT_NAME_LEN);
        desc->name[OFP_MAX_PORT_NAME_LEN-1] = '\0';
        memcpy(desc->hw_addr, p->dev->dev_addr, ETH_ALEN);
-       desc->flags = 0;
-       desc->features = 0;
-       desc->speed = 0;
+       desc->curr = 0;
+       desc->supported = 0;
+       desc->advertised = 0;
+       desc->peer = 0;
 
        spin_lock_irqsave(&p->lock, flags);
-       desc->flags = htonl(p->flags | p->status);
+       desc->config = htonl(p->config);
+       desc->state = htonl(p->state);
        spin_unlock_irqrestore(&p->lock, flags);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,24)
@@ -694,27 +696,86 @@ static void fill_port_desc(struct net_bridge_port *p, struct ofp_phy_port *desc)
                struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
 
                if (!p->dev->ethtool_ops->get_settings(p->dev, &ecmd)) {
+                       /* Set the supported features */
                        if (ecmd.supported & SUPPORTED_10baseT_Half) 
-                               desc->features |= OFPPF_10MB_HD;
+                               desc->supported |= OFPPF_10MB_HD;
                        if (ecmd.supported & SUPPORTED_10baseT_Full)
-                               desc->features |= OFPPF_10MB_FD;
+                               desc->supported |= OFPPF_10MB_FD;
                        if (ecmd.supported & SUPPORTED_100baseT_Half) 
-                               desc->features |= OFPPF_100MB_HD;
+                               desc->supported |= OFPPF_100MB_HD;
                        if (ecmd.supported & SUPPORTED_100baseT_Full)
-                               desc->features |= OFPPF_100MB_FD;
+                               desc->supported |= OFPPF_100MB_FD;
                        if (ecmd.supported & SUPPORTED_1000baseT_Half)
-                               desc->features |= OFPPF_1GB_HD;
+                               desc->supported |= OFPPF_1GB_HD;
                        if (ecmd.supported & SUPPORTED_1000baseT_Full)
-                               desc->features |= OFPPF_1GB_FD;
-                       /* 10Gbps half-duplex doesn't exist... */
+                               desc->supported |= OFPPF_1GB_FD;
                        if (ecmd.supported & SUPPORTED_10000baseT_Full)
-                               desc->features |= OFPPF_10GB_FD;
-
-                       desc->speed = htonl(ecmd.speed);
+                               desc->supported |= OFPPF_10GB_FD;
+                       if (ecmd.supported & SUPPORTED_TP)
+                               desc->supported |= OFPPF_COPPER;
+                       if (ecmd.supported & SUPPORTED_FIBRE)
+                               desc->supported |= OFPPF_FIBER;
+                       if (ecmd.supported & SUPPORTED_Autoneg)
+                               desc->supported |= OFPPF_AUTONEG;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+                       if (ecmd.supported & SUPPORTED_Pause)
+                               desc->supported |= OFPPF_PAUSE;
+                       if (ecmd.supported & SUPPORTED_Asym_Pause)
+                               desc->supported |= OFPPF_PAUSE_ASYM;
+#endif /* kernel >= 2.6.14 */
+
+                       /* Set the advertised features */
+                       if (ecmd.advertising & ADVERTISED_10baseT_Half) 
+                               desc->advertised |= OFPPF_10MB_HD;
+                       if (ecmd.advertising & ADVERTISED_10baseT_Full)
+                               desc->advertised |= OFPPF_10MB_FD;
+                       if (ecmd.advertising & ADVERTISED_100baseT_Half) 
+                               desc->advertised |= OFPPF_100MB_HD;
+                       if (ecmd.advertising & ADVERTISED_100baseT_Full)
+                               desc->advertised |= OFPPF_100MB_FD;
+                       if (ecmd.advertising & ADVERTISED_1000baseT_Half)
+                               desc->advertised |= OFPPF_1GB_HD;
+                       if (ecmd.advertising & ADVERTISED_1000baseT_Full)
+                               desc->advertised |= OFPPF_1GB_FD;
+                       if (ecmd.advertising & ADVERTISED_10000baseT_Full)
+                               desc->advertised |= OFPPF_10GB_FD;
+                       if (ecmd.advertising & ADVERTISED_TP)
+                               desc->advertised |= OFPPF_COPPER;
+                       if (ecmd.advertising & ADVERTISED_FIBRE)
+                               desc->advertised |= OFPPF_FIBER;
+                       if (ecmd.advertising & ADVERTISED_Autoneg)
+                               desc->advertised |= OFPPF_AUTONEG;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+                       if (ecmd.advertising & ADVERTISED_Pause)
+                               desc->advertised |= OFPPF_PAUSE;
+                       if (ecmd.advertising & ADVERTISED_Asym_Pause)
+                               desc->advertised |= OFPPF_PAUSE_ASYM;
+#endif /* kernel >= 2.6.14 */
+
+                       /* Set the current features */
+                       if (ecmd.speed == SPEED_10)
+                               desc->curr = (ecmd.duplex) ? OFPPF_10MB_FD : OFPPF_10MB_HD;
+                       else if (ecmd.speed == SPEED_100)
+                               desc->curr = (ecmd.duplex) ? OFPPF_100MB_FD : OFPPF_100MB_HD;
+                       else if (ecmd.speed == SPEED_1000)
+                               desc->curr = (ecmd.duplex) ? OFPPF_1GB_FD : OFPPF_1GB_HD;
+                       else if (ecmd.speed == SPEED_10000)
+                               desc->curr = OFPPF_10GB_FD;
+
+                       if (ecmd.port == PORT_TP) 
+                               desc->curr |= OFPPF_COPPER;
+                       else if (ecmd.port == PORT_FIBRE) 
+                               desc->curr |= OFPPF_FIBER;
+
+                       if (ecmd.autoneg)
+                               desc->curr |= OFPPF_AUTONEG;
                }
        }
 #endif
-       desc->features = htonl(desc->features);
+       desc->curr = htonl(desc->curr);
+       desc->supported = htonl(desc->supported);
+       desc->advertised = htonl(desc->advertised);
+       desc->peer = htonl(desc->peer);
 }
 
 static int 
@@ -815,7 +876,7 @@ down_port_cb(struct work_struct *work)
                if (net_ratelimit())
                        printk("problem bringing up port %s\n", p->dev->name);
        rtnl_unlock();
-       p->status |= OFPPFL_PORT_DOWN;
+       p->config |= OFPPC_PORT_DOWN;
 }
 
 /* Callback function for a workqueue to enable an interface */
@@ -830,42 +891,40 @@ up_port_cb(struct work_struct *work)
                if (net_ratelimit())
                        printk("problem bringing down port %s\n", p->dev->name);
        rtnl_unlock();
-       p->status &= ~OFPPFL_PORT_DOWN;
+       p->config &= ~OFPPC_PORT_DOWN;
 }
 
 int
 dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm)
 {
        unsigned long int flags;
-       const struct ofp_phy_port *opp = &opm->desc;
-       int port_no = ntohs(opp->port_no);
+       int port_no = ntohs(opm->port_no);
        struct net_bridge_port *p = (port_no < OFPP_MAX ? dp->ports[port_no]
                                     : port_no == OFPP_LOCAL ? dp->local_port
                                     : NULL);
-       uint32_t flag_mask;
 
        /* Make sure the port id hasn't changed since this was sent */
-       if (!p || memcmp(opp->hw_addr, p->dev->dev_addr, ETH_ALEN))
+       if (!p || memcmp(opm->hw_addr, p->dev->dev_addr, ETH_ALEN))
                return -1;
 
        spin_lock_irqsave(&p->lock, flags);
-       flag_mask = ntohl(opm->mask) & PORT_FLAG_BITS;
-       if (flag_mask) {
-               p->flags &= ~flag_mask;
-               p->flags |= ntohl(opp->flags) & flag_mask;
+       if (opm->mask) {
+               uint32_t config_mask = ntohl(opm->mask);
+               p->config &= ~config_mask;
+               p->config |= ntohl(opm->config) & config_mask;
        }
 
        /* Modifying the status of an interface requires taking a lock
         * that cannot be done from here.  For this reason, we use a shared 
         * workqueue, which will cause it to be executed from a safer 
         * context. */
-       if (opm->mask & htonl(OFPPFL_PORT_DOWN)) {
-               if ((opp->flags & htonl(OFPPFL_PORT_DOWN))
-                   && (p->status & OFPPFL_PORT_DOWN) == 0) {
+       if (opm->mask & htonl(OFPPC_PORT_DOWN)) {
+               if ((opm->config & htonl(OFPPC_PORT_DOWN))
+                   && (p->config & OFPPC_PORT_DOWN) == 0) {
                        PREPARE_WORK(&p->port_task, down_port_cb);
                        schedule_work(&p->port_task);
-               } else if ((opp->flags & htonl(OFPPFL_PORT_DOWN)) == 0
-                          && (p->status & OFPPFL_PORT_DOWN)) {
+               } else if ((opm->config & htonl(OFPPC_PORT_DOWN)) == 0
+                          && (p->config & OFPPC_PORT_DOWN)) {
                        PREPARE_WORK(&p->port_task, up_port_cb);
                        schedule_work(&p->port_task);
                }
@@ -884,14 +943,14 @@ init_port_status(struct net_bridge_port *p)
        spin_lock_irqsave(&p->lock, flags);
 
        if (p->dev->flags & IFF_UP) 
-               p->status &= ~OFPPFL_PORT_DOWN;
+               p->config &= ~OFPPC_PORT_DOWN;
        else
-               p->status |= OFPPFL_PORT_DOWN;
+               p->config |= OFPPC_PORT_DOWN;
 
        if (netif_carrier_ok(p->dev))
-               p->status &= ~OFPPFL_LINK_DOWN;
+               p->state &= ~OFPPS_LINK_DOWN;
        else
-               p->status |= OFPPFL_LINK_DOWN;
+               p->state |= OFPPS_LINK_DOWN;
 
        spin_unlock_irqrestore(&p->lock, flags);
 }
index 4339539..621906b 100644 (file)
@@ -69,13 +69,10 @@ struct sender {
        uint32_t seq;           /* Netlink sequence ID of request. */
 };
 
-#define PORT_STATUS_BITS (OFPPFL_PORT_DOWN | OFPPFL_LINK_DOWN)
-#define PORT_FLAG_BITS (~PORT_STATUS_BITS)
-
 struct net_bridge_port {
        u16     port_no;
-       u32 flags;              /* Some subset of PORT_FLAG_BITS. */
-       u32 status;             /* Some subset of PORT_STATUS_BITS. */
+       u32 config;             /* Some subset of OFPPC_* flags. */
+       u32 state;              /* Some subset of OFPPS_* flags. */
        spinlock_t lock;
        struct work_struct port_task;
        struct datapath *dp;
index 2885e7f..9bf491d 100644 (file)
@@ -17,7 +17,7 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
        struct net_device *dev = ptr;
        struct net_bridge_port *p = dev->br_port;
        unsigned long int flags;
-       uint32_t orig_status;
+       uint32_t orig_state, orig_config;
 
 
        /* Check if monitored port */
@@ -25,26 +25,26 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
                return NOTIFY_DONE;
 
        spin_lock_irqsave(&p->lock, flags);
-       orig_status = p->status;
+       orig_state = p->state;
+       orig_config = p->config;
 
        switch (event) {
                case NETDEV_CHANGE:
                        if (netif_carrier_ok(p->dev))
-                               p->status &= ~OFPPFL_LINK_DOWN;
+                               p->state &= ~OFPPS_LINK_DOWN;
                        else
-                               p->status |= OFPPFL_LINK_DOWN;
+                               p->state |= OFPPS_LINK_DOWN;
                        break;
 
                case NETDEV_DOWN:
-                       p->status |= OFPPFL_PORT_DOWN;
+                       p->config |= OFPPC_PORT_DOWN;
                        break;
 
                case NETDEV_UP:
-                       p->status &= ~OFPPFL_PORT_DOWN;
+                       p->config &= ~OFPPC_PORT_DOWN;
                        break;
 
                case NETDEV_UNREGISTER:
-                       /* xxx Make sure this is correct */
                        spin_unlock_irqrestore(&p->lock, flags);
                        dp_del_switch_port(p);
                        return NOTIFY_DONE;
@@ -52,8 +52,8 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
        }
        spin_unlock_irqrestore(&p->lock, flags);
 
-       if (orig_status != p->status) 
-               dp_send_port_status(p, OFPPR_MOD);
+       if ((orig_state != p->state) || (orig_config != p->config))
+               dp_send_port_status(p, OFPPR_MODIFY);
 
        return NOTIFY_DONE;
 }
index b63dfef..ddae5d7 100644 (file)
@@ -47,9 +47,9 @@ int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb,
                kfree_skb(skb);
                return 0;
        }
-       if (p && p->flags & (OFPPFL_NO_RECV | OFPPFL_NO_RECV_STP) &&
-           p->flags & (compare_ether_addr(key.dl_dst, stp_eth_addr)
-                       ? OFPPFL_NO_RECV : OFPPFL_NO_RECV_STP)) {
+       if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
+           p->config & (compare_ether_addr(key.dl_dst, stp_eth_addr)
+                       ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) {
                kfree_skb(skb);
                return 0;
        }
index 8663b33..f36b920 100644 (file)
@@ -47,6 +47,13 @@ struct ofpbuf;
 struct in_addr;
 struct in6_addr;
 
+enum netdev_feature_type {
+    NETDEV_FEAT_CURRENT,
+    NETDEV_FEAT_ADVERTISED,
+    NETDEV_FEAT_SUPPORTED,
+    NETDEV_FEAT_PEER
+};
+
 enum netdev_flags {
     NETDEV_UP = 0x0001,         /* Device enabled? */
     NETDEV_PROMISC = 0x0002     /* Promiscuous mode? */
@@ -68,9 +75,8 @@ int netdev_send(struct netdev *, const struct ofpbuf *);
 const uint8_t *netdev_get_etheraddr(const struct netdev *);
 const char *netdev_get_name(const struct netdev *);
 int netdev_get_mtu(const struct netdev *);
-int netdev_get_speed(const struct netdev *);
 int netdev_get_link_status(const struct netdev *);
-uint32_t netdev_get_features(const struct netdev *);
+uint32_t netdev_get_features(struct netdev *, int);
 bool netdev_get_in4(const struct netdev *, struct in_addr *);
 int netdev_set_in4(struct netdev *, struct in_addr addr, struct in_addr mask);
 int netdev_add_router(struct netdev *, struct in_addr router);
index c81cea3..e34c601 100644 (file)
@@ -63,7 +63,7 @@
 /* The most significant bit being set in the version field indicates an
  * experimental OpenFlow version.  
  */
-#define OFP_VERSION   0x92
+#define OFP_VERSION   0x93
 
 #define OFP_MAX_TABLE_NAME_LEN 32
 #define OFP_MAX_PORT_NAME_LEN  16
@@ -167,65 +167,80 @@ OFP_ASSERT(sizeof(struct ofp_switch_config) == 12);
 
 /* Capabilities supported by the datapath. */
 enum ofp_capabilities {
-    OFPC_FLOW_STATS   = 1 << 0, /* Flow statistics. */
-    OFPC_TABLE_STATS  = 1 << 1, /* Table statistics. */
-    OFPC_PORT_STATS   = 1 << 2, /* Port statistics. */
-    OFPC_STP          = 1 << 3, /* 802.11d spanning tree. */
-    OFPC_MULTI_PHY_TX = 1 << 4, /* Supports transmitting through multiple
-                                   physical interfaces */
-    OFPC_IP_REASM     = 1 << 5  /* Can reassemble IP fragments. */
-};
-
-/* Flags to indicate behavior of the physical port. */
-enum ofp_port_flags {
-    /* Read/write bits. */
-    OFPPFL_PORT_DOWN    = 1 << 1, /* Port is configured down. */
-    OFPPFL_NO_STP       = 1 << 3, /* Disable 802.1D spanning tree on port. */
-    OFPPFL_NO_RECV      = 1 << 4, /* Drop most packets received on port. */
-    OFPPFL_NO_RECV_STP  = 1 << 5, /* Drop received 802.1D STP packets. */
-    OFPPFL_NO_FWD       = 1 << 6, /* Drop packets forwarded to port. */
-    OFPPFL_NO_PACKET_IN = 1 << 7, /* Do not send packet-in msgs for port. */
-
-    /* Read-only bits. */
-    OFPPFL_LINK_DOWN    = 1 << 2, /* No physical link present. */
-
-    /* Read-only when STP is enabled (when OFPPFL_NO_STP is not set).
-     * Read/write when STP is disabled (when OFPPFL_NO_STP is set).
-     *
-     * The OFPPFL_STP_* bits have no effect on switch operation.  The
+    OFPC_FLOW_STATS     = 1 << 0,  /* Flow statistics. */
+    OFPC_TABLE_STATS    = 1 << 1,  /* Table statistics. */
+    OFPC_PORT_STATS     = 1 << 2,  /* Port statistics. */
+    OFPC_STP            = 1 << 3,  /* 802.1d spanning tree. */
+    OFPC_MULTI_PHY_TX   = 1 << 4,  /* Supports transmitting through multiple
+                                      physical interfaces */
+    OFPC_IP_REASM       = 1 << 5   /* Can reassemble IP fragments. */
+};
+
+/* Flags to indicate behavior of the physical port.  These flags are
+ * used in ofp_phy_port to describe the current configuration.  They are
+ * used in the ofp_port_mod message to configure the port's behavior. 
+ */
+enum ofp_port_config {
+    OFPPC_PORT_DOWN    = 1 << 0,  /* Port is administratively down. */
+
+    OFPPC_NO_STP       = 1 << 1,  /* Disable 802.1D spanning tree on port. */
+    OFPPC_NO_RECV      = 1 << 2,  /* Drop most packets received on port. */
+    OFPPC_NO_RECV_STP  = 1 << 3,  /* Drop received 802.1D STP packets. */
+    OFPPC_NO_FLOOD     = 1 << 4,  /* Do not include this port when flooding. */
+    OFPPC_NO_FWD       = 1 << 5,  /* Drop packets forwarded to port. */
+    OFPPC_NO_PACKET_IN = 1 << 6   /* Do not send packet-in msgs for port. */
+};
+
+/* Current state of the physical port.  These are not configurable from
+ * the controller.
+ */
+enum ofp_port_state {
+    OFPPS_LINK_DOWN   = 1 << 0, /* No physical link present. */
+
+    /* The OFPPFL_STP_* bits have no effect on switch operation.  The
      * controller must adjust OFPPFL_NO_RECV, OFPPFL_NO_FWD, and
      * OFPPFL_NO_PACKET_IN appropriately to fully implement an 802.1D spanning
      * tree. */
-    OFPPFL_NO_FLOOD     = 1 << 0, /* Do not include this port when flooding. */
-    OFPPFL_STP_LISTEN   = 0 << 8, /* Not learning or relaying frames. */
-    OFPPFL_STP_LEARN    = 1 << 8, /* Learning but not relaying frames. */
-    OFPPFL_STP_FORWARD  = 2 << 8, /* Learning and relaying frames. */
-    OFPPFL_STP_BLOCK    = 3 << 8, /* Not part of spanning tree. */
-    OFPPFL_STP_MASK     = 3 << 8, /* Bit mask for OFPPFL_STP_* values. */
+    OFPPS_STP_LISTEN  = 0 << 8, /* Not learning or relaying frames. */
+    OFPPS_STP_LEARN   = 1 << 8, /* Learning but not relaying frames. */
+    OFPPS_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */
+    OFPPS_STP_BLOCK   = 3 << 8, /* Not part of spanning tree. */
+    OFPPS_STP_MASK    = 3 << 8  /* Bit mask for OFPPFL_STP_* values. */
 };
 
 /* Features of physical ports available in a datapath. */
 enum ofp_port_features {
-    OFPPF_10MB_HD    = 1 << 0, /* 10 Mb half-duplex rate support. */
-    OFPPF_10MB_FD    = 1 << 1, /* 10 Mb full-duplex rate support. */
-    OFPPF_100MB_HD   = 1 << 2, /* 100 Mb half-duplex rate support. */
-    OFPPF_100MB_FD   = 1 << 3, /* 100 Mb full-duplex rate support. */
-    OFPPF_1GB_HD     = 1 << 4, /* 1 Gb half-duplex rate support. */
-    OFPPF_1GB_FD     = 1 << 5, /* 1 Gb full-duplex rate support. */
-    OFPPF_10GB_FD    = 1 << 6, /* 10 Gb full-duplex rate support. */
+    OFPPF_10MB_HD    = 1 << 0,  /* 10 Mb half-duplex rate support. */
+    OFPPF_10MB_FD    = 1 << 1,  /* 10 Mb full-duplex rate support. */
+    OFPPF_100MB_HD   = 1 << 2,  /* 100 Mb half-duplex rate support. */
+    OFPPF_100MB_FD   = 1 << 3,  /* 100 Mb full-duplex rate support. */
+    OFPPF_1GB_HD     = 1 << 4,  /* 1 Gb half-duplex rate support. */
+    OFPPF_1GB_FD     = 1 << 5,  /* 1 Gb full-duplex rate support. */
+    OFPPF_10GB_FD    = 1 << 6,  /* 10 Gb full-duplex rate support. */
+    OFPPF_COPPER     = 1 << 7,  /* Copper medium */
+    OFPPF_FIBER      = 1 << 8,  /* Fiber medium */
+    OFPPF_AUTONEG    = 1 << 9,  /* Auto-negotiation */
+    OFPPF_PAUSE      = 1 << 10, /* Pause */
+    OFPPF_PAUSE_ASYM = 1 << 11  /* Asymmetric pause */
 };
 
-
 /* Description of a physical port */
 struct ofp_phy_port {
     uint16_t port_no;
     uint8_t hw_addr[OFP_ETH_ALEN];
     uint8_t name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */
-    uint32_t flags;         /* Bitmap of "ofp_port_flags". */
-    uint32_t speed;         /* Current speed in Mbps */
-    uint32_t features;      /* Bitmap of supported "ofp_port_features"s. */
+
+    uint32_t config;        /* Bitmap of OFPPC_* flags. */
+    uint32_t state;         /* Bitmap of OFPPS_* flags. */
+
+    /* Bitmaps of OFPPF_* that describe features.  All bits zeroed if
+     * unsupported or unavailable. */
+    uint32_t curr;          /* Current features. */
+    uint32_t advertised;    /* Features being advertised by the port. */
+    uint32_t supported;     /* Features supported by the port. */
+    uint32_t peer;          /* Features advertised by peer. */
 };
-OFP_ASSERT(sizeof(struct ofp_phy_port) == 36);
+OFP_ASSERT(sizeof(struct ofp_phy_port) == 48);
 
 /* Switch features. */
 struct ofp_switch_features {
@@ -253,26 +268,36 @@ OFP_ASSERT(sizeof(struct ofp_switch_features) == 32);
 enum ofp_port_reason {
     OFPPR_ADD,              /* The port was added */
     OFPPR_DELETE,           /* The port was removed */
-    OFPPR_MOD               /* Some attribute of the port has changed */
+    OFPPR_MODIFY            /* Some attribute of the port has changed */
 };
 
 /* A physical port has changed in the datapath */
 struct ofp_port_status {
     struct ofp_header header;
     uint8_t reason;          /* One of OFPPR_* */
-    uint8_t pad[3];          /* Align to 32-bits */
+    uint8_t pad[7];          /* Align to 64-bits */
     struct ofp_phy_port desc;
 };
-OFP_ASSERT(sizeof(struct ofp_port_status) == 48);
+OFP_ASSERT(sizeof(struct ofp_port_status) == 64);
 
 /* Modify behavior of the physical port */
 struct ofp_port_mod {
     struct ofp_header header;
-    uint32_t mask;         /* Bitmap of "ofp_port_flags" that should be 
-                              changed. */
-    struct ofp_phy_port desc;
+    uint16_t port_no;
+    uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not 
+                                      configurable.  This is used to 
+                                      sanity-check the request, so it must 
+                                      be the same as returned in an
+                                      ofp_phy_port struct. */
+
+    uint32_t config;        /* Bitmap of OFPPC_* flags. */
+    uint32_t mask;          /* Bitmap of OFPPC_* flags to be changed. */
+
+    uint32_t advertise;     /* Bitmap of "ofp_port_features"s.  Zero all 
+                               bits to prevent any action taking place. */
+    uint8_t pad[4];         /* Pad to 64-bits. */
 };
-OFP_ASSERT(sizeof(struct ofp_port_mod) == 48);
+OFP_ASSERT(sizeof(struct ofp_port_mod) == 32);
 
 /* Why is this packet being sent to the controller? */
 enum ofp_packet_in_reason {
@@ -539,7 +564,7 @@ struct ofp_stats_request {
 OFP_ASSERT(sizeof(struct ofp_stats_request) == 12);
 
 enum ofp_stats_reply_flags {
-    OFPSF_REPLY_MORE  = 1 << 0, /* More replies to follow */
+    OFPSF_REPLY_MORE  = 1 << 0  /* More replies to follow */
 };
 
 struct ofp_stats_reply {
index 25c2c59..f89706a 100644 (file)
@@ -292,41 +292,44 @@ process_phy_port(struct lswitch *sw, struct rconn *rconn,
                  const struct ofp_phy_port *opp)
 {
     if (sw->capabilities & OFPC_STP && ntohs(opp->port_no) < OFPP_MAX) {
-        uint32_t flags = ntohl(opp->flags);
-        uint32_t new_flags = flags & ~(OFPPFL_NO_RECV | OFPPFL_NO_RECV_STP
-                                       | OFPPFL_NO_FWD | OFPPFL_NO_PACKET_IN);
-        if (!(flags & (OFPPFL_NO_STP | OFPPFL_PORT_DOWN | OFPPFL_LINK_DOWN))) {
+        uint32_t config = ntohl(opp->config);
+        uint32_t state = ntohl(opp->state);
+        uint32_t new_config = config & ~(OFPPC_NO_RECV | OFPPC_NO_RECV_STP
+                                         | OFPPC_NO_FWD | OFPPC_NO_PACKET_IN);
+        if (!(config & (OFPPC_NO_STP | OFPPC_PORT_DOWN))
+                    && !(state & OFPPS_LINK_DOWN)) {
             bool forward = false;
             bool learn = false;
-            switch (flags & OFPPFL_STP_MASK) {
-            case OFPPFL_STP_LISTEN:
-            case OFPPFL_STP_BLOCK:
+            switch (state & OFPPS_STP_MASK) {
+            case OFPPS_STP_LISTEN:
+            case OFPPS_STP_BLOCK:
                 break;
-            case OFPPFL_STP_LEARN:
+            case OFPPS_STP_LEARN:
                 learn = true;
                 break;
-            case OFPPFL_STP_FORWARD:
+            case OFPPS_STP_FORWARD:
                 forward = learn = true;
                 break;
             }
             if (!forward) {
-                new_flags |= OFPPFL_NO_RECV | OFPPFL_NO_FWD;
+                new_config |= OFPPC_NO_RECV | OFPPC_NO_FWD;
             }
             if (!learn) {
-                new_flags |= OFPPFL_NO_PACKET_IN;
+                new_config |= OFPPC_NO_PACKET_IN;
             }
         }
-        if (flags != new_flags) {
+        if (config != new_config) {
             struct ofp_port_mod *opm;
             struct ofpbuf *b;
             int retval;
 
-            VLOG_WARN("port %d: flags=%x new_flags=%x",
-                      ntohs(opp->port_no), flags, new_flags);
+            VLOG_WARN("port %d: config=%x new_config=%x",
+                      ntohs(opp->port_no), config, new_config);
             opm = make_openflow(sizeof *opm, OFPT_PORT_MOD, &b);
-            opm->mask = htonl(flags ^ new_flags);
-            opm->desc = *opp;
-            opm->desc.flags = htonl(new_flags);
+            memcpy(opm->hw_addr, opp->hw_addr, OFP_ETH_ALEN);
+            opm->config = htonl(new_config);
+            opm->mask = htonl(config ^ new_config);
+            opm->advertise = htonl(0);
             retval = rconn_send(rconn, b, NULL);
             if (retval) {
                 if (retval != ENOTCONN) {
index 7b55aec..ba11b6a 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/types.h>
 #include <linux/ethtool.h>
 #include <linux/sockios.h>
+#include <linux/version.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
@@ -74,7 +75,14 @@ struct netdev {
     uint8_t etheraddr[ETH_ADDR_LEN];
     int speed;
     int mtu;
-    uint32_t features;
+
+    /* Bitmaps of OFPPF_* that describe features.  All bits disabled if
+     * unsupported or unavailable. */
+    uint32_t curr;              /* Current features. */
+    uint32_t advertised;        /* Features being advertised by the port. */
+    uint32_t supported;         /* Features supported by the port. */
+    uint32_t peer;              /* Features advertised by the peer. */
+
     struct in6_addr in6;
     int save_flags;             /* Initial device flags. */
     int changed_flags;          /* Flags that we changed. */
@@ -138,8 +146,10 @@ do_ethtool(struct netdev *netdev)
     struct ifreq ifr;
     struct ethtool_cmd ecmd;
 
-    netdev->speed = 0;
-    netdev->features = 0;
+    netdev->curr = 0;
+    netdev->supported = 0;
+    netdev->advertised = 0;
+    netdev->peer = 0;
 
     memset(&ifr, 0, sizeof ifr);
     strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name);
@@ -149,48 +159,107 @@ do_ethtool(struct netdev *netdev)
     ecmd.cmd = ETHTOOL_GSET;
     if (ioctl(netdev->fd, SIOCETHTOOL, &ifr) == 0) {
         if (ecmd.supported & SUPPORTED_10baseT_Half) {
-            netdev->features |= OFPPF_10MB_HD;
+            netdev->supported |= OFPPF_10MB_HD;
         }
         if (ecmd.supported & SUPPORTED_10baseT_Full) {
-            netdev->features |= OFPPF_10MB_FD;
+            netdev->supported |= OFPPF_10MB_FD;
         }
         if (ecmd.supported & SUPPORTED_100baseT_Half)  {
-            netdev->features |= OFPPF_100MB_HD;
+            netdev->supported |= OFPPF_100MB_HD;
         }
         if (ecmd.supported & SUPPORTED_100baseT_Full) {
-            netdev->features |= OFPPF_100MB_FD;
+            netdev->supported |= OFPPF_100MB_FD;
         }
         if (ecmd.supported & SUPPORTED_1000baseT_Half) {
-            netdev->features |= OFPPF_1GB_HD;
+            netdev->supported |= OFPPF_1GB_HD;
         }
         if (ecmd.supported & SUPPORTED_1000baseT_Full) {
-            netdev->features |= OFPPF_1GB_FD;
+            netdev->supported |= OFPPF_1GB_FD;
         }
-        /* 10Gbps half-duplex doesn't exist... */
         if (ecmd.supported & SUPPORTED_10000baseT_Full) {
-            netdev->features |= OFPPF_10GB_FD;
+            netdev->supported |= OFPPF_10GB_FD;
         }
+        if (ecmd.supported & SUPPORTED_TP) {
+            netdev->supported |= OFPPF_COPPER;
+        }
+        if (ecmd.supported & SUPPORTED_FIBRE) {
+            netdev->supported |= OFPPF_FIBER;
+        }
+        if (ecmd.supported & SUPPORTED_Autoneg) {
+            netdev->supported |= OFPPF_AUTONEG;
+        }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+        if (ecmd.supported & SUPPORTED_Pause) {
+            netdev->supported |= OFPPF_PAUSE;
+        }
+        if (ecmd.supported & SUPPORTED_Asym_Pause) {
+            netdev->supported |= OFPPF_PAUSE_ASYM;
+        }
+#endif /* kernel >= 2.6.14 */
 
-        switch (ecmd.speed) {
-        case SPEED_10:
-            netdev->speed = 10;
-            break;
-
-        case SPEED_100:
-            netdev->speed = 100;
-            break;
+        /* Set the advertised features */
+        if (ecmd.advertising & ADVERTISED_10baseT_Half) {
+            netdev->advertised |= OFPPF_10MB_HD;
+        }
+        if (ecmd.advertising & ADVERTISED_10baseT_Full) {
+            netdev->advertised |= OFPPF_10MB_FD;
+        }
+        if (ecmd.advertising & ADVERTISED_100baseT_Half) {
+            netdev->advertised |= OFPPF_100MB_HD;
+        }
+        if (ecmd.advertising & ADVERTISED_100baseT_Full) {
+            netdev->advertised |= OFPPF_100MB_FD;
+        }
+        if (ecmd.advertising & ADVERTISED_1000baseT_Half) {
+            netdev->advertised |= OFPPF_1GB_HD;
+        }
+        if (ecmd.advertising & ADVERTISED_1000baseT_Full) {
+            netdev->advertised |= OFPPF_1GB_FD;
+        }
+        if (ecmd.advertising & ADVERTISED_10000baseT_Full) {
+            netdev->advertised |= OFPPF_10GB_FD;
+        }
+        if (ecmd.advertising & ADVERTISED_TP) {
+            netdev->advertised |= OFPPF_COPPER;
+        }
+        if (ecmd.advertising & ADVERTISED_FIBRE) {
+            netdev->advertised |= OFPPF_FIBER;
+        }
+        if (ecmd.advertising & ADVERTISED_Autoneg) {
+            netdev->advertised |= OFPPF_AUTONEG;
+        }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+        if (ecmd.advertising & ADVERTISED_Pause) {
+            netdev->advertised |= OFPPF_PAUSE;
+        }
+        if (ecmd.advertising & ADVERTISED_Asym_Pause) {
+            netdev->advertised |= OFPPF_PAUSE_ASYM;
+        }
+#endif /* kernel >= 2.6.14 */
 
-        case SPEED_1000:
-            netdev->speed = 1000;
-            break;
+        /* Set the current features */
+        if (ecmd.speed == SPEED_10) {
+            netdev->curr = (ecmd.duplex) ? OFPPF_10MB_FD : OFPPF_10MB_HD;
+        }
+        else if (ecmd.speed == SPEED_100) {
+            netdev->curr = (ecmd.duplex) ? OFPPF_100MB_FD : OFPPF_100MB_HD;
+        }
+        else if (ecmd.speed == SPEED_1000) {
+            netdev->curr = (ecmd.duplex) ? OFPPF_1GB_FD : OFPPF_1GB_HD;
+        }
+        else if (ecmd.speed == SPEED_10000) {
+            netdev->curr = OFPPF_10GB_FD;
+        }
 
-        case SPEED_2500:
-            netdev->speed = 2500;
-            break;
+        if (ecmd.port == PORT_TP) {
+            netdev->curr |= OFPPF_COPPER;
+        }
+        else if (ecmd.port == PORT_FIBRE) {
+            netdev->curr |= OFPPF_FIBER;
+        }
 
-        case SPEED_10000:
-            netdev->speed = 10000;
-            break;
+        if (ecmd.autoneg) {
+            netdev->curr |= OFPPF_AUTONEG;
         }
     } else {
         VLOG_DBG("ioctl(SIOCETHTOOL) failed: %s", strerror(errno));
@@ -495,14 +564,6 @@ netdev_get_mtu(const struct netdev *netdev)
     return netdev->mtu;
 }
 
-/* Returns the current speed of the network device that 'netdev' represents, in
- * megabits per second, or 0 if the speed is unknown. */
-int
-netdev_get_speed(const struct netdev *netdev) 
-{
-    return netdev->speed;
-}
-
 /* Checks the link status.  Returns 1 or 0 to indicate the link is active 
  * or not, respectively.  Any other return value indicates an error. */
 int
@@ -528,12 +589,25 @@ netdev_get_link_status(const struct netdev *netdev)
     return -1;
 }
 
-/* Returns the features supported by 'netdev', as a bitmap of bits from enum
- * ofp_phy_port, in host byte order. */
+/* Returns the features supported by 'netdev' of type 'type', as a bitmap 
+ * of bits from enum ofp_phy_features, in host byte order. */
 uint32_t
-netdev_get_features(const struct netdev *netdev
+netdev_get_features(struct netdev *netdev, int type
 {
-    return netdev->features;
+    do_ethtool(netdev);
+    switch (type) {
+    case NETDEV_FEAT_CURRENT:
+        return netdev->curr;
+    case NETDEV_FEAT_ADVERTISED:
+        return netdev->advertised;
+    case NETDEV_FEAT_SUPPORTED:
+        return netdev->supported;
+    case NETDEV_FEAT_PEER:
+        return netdev->peer;
+    default:
+        VLOG_WARN("Unknown feature type: %d\n", type);
+        return 0;
+    }
 }
 
 /* If 'netdev' has an assigned IPv4 address, sets '*in4' to that address (if
index cd0630d..07ae4a4 100644 (file)
@@ -377,6 +377,51 @@ compare_ports(const void *a_, const void *b_)
     return ap < bp ? -1 : ap > bp;
 }
 
+static void ofp_print_port_features(struct ds *string, uint32_t features)
+{
+    if (features == 0) {
+        ds_put_cstr(string, "Unsupported\n");
+        return;
+    }
+    if (features & OFPPF_10MB_HD) {
+        ds_put_cstr(string, "10MB-HD ");
+    }
+    if (features & OFPPF_10MB_FD) {
+        ds_put_cstr(string, "10MB-FD ");
+    }
+    if (features & OFPPF_100MB_HD) {
+        ds_put_cstr(string, "100MB-HD ");
+    }
+    if (features & OFPPF_100MB_FD) {
+        ds_put_cstr(string, "100MB-FD ");
+    }
+    if (features & OFPPF_1GB_HD) {
+        ds_put_cstr(string, "1GB-HD ");
+    }
+    if (features & OFPPF_1GB_FD) {
+        ds_put_cstr(string, "1GB-FD ");
+    }
+    if (features & OFPPF_10GB_FD) {
+        ds_put_cstr(string, "10GB-FD ");
+    }
+    if (features & OFPPF_COPPER) {
+        ds_put_cstr(string, "COPPER ");
+    }
+    if (features & OFPPF_FIBER) {
+        ds_put_cstr(string, "FIBER ");
+    }
+    if (features & OFPPF_AUTONEG) {
+        ds_put_cstr(string, "AUTO_NEG ");
+    }
+    if (features & OFPPF_PAUSE) {
+        ds_put_cstr(string, "AUTO_PAUSE ");
+    }
+    if (features & OFPPF_PAUSE_ASYM) {
+        ds_put_cstr(string, "AUTO_PAUSE_ASYM ");
+    }
+    ds_put_char(string, '\n');
+}
+
 static void
 ofp_print_phy_port(struct ds *string, const struct ofp_phy_port *port)
 {
@@ -393,10 +438,25 @@ ofp_print_phy_port(struct ds *string, const struct ofp_phy_port *port)
 
     ds_put_char(string, ' ');
     ofp_print_port_name(string, ntohs(port->port_no));
-    ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT", speed:%d, flags:%#x, "
-            "feat:%#x\n", name, 
-            ETH_ADDR_ARGS(port->hw_addr), ntohl(port->speed),
-            ntohl(port->flags), ntohl(port->features));
+    ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT", config: %#x, state:%#x\n",
+            name, ETH_ADDR_ARGS(port->hw_addr), ntohl(port->config),
+            ntohl(port->state));
+    if (port->curr) {
+        ds_put_format(string, "     current:    ");
+        ofp_print_port_features(string, ntohl(port->curr));
+    }
+    if (port->advertised) {
+        ds_put_format(string, "     advertised: ");
+        ofp_print_port_features(string, ntohl(port->advertised));
+    }
+    if (port->supported) {
+        ds_put_format(string, "     supported:  ");
+        ofp_print_port_features(string, ntohl(port->supported));
+    }
+    if (port->peer) {
+        ds_put_format(string, "     peer:       ");
+        ofp_print_port_features(string, ntohl(port->peer));
+    }
 }
 
 /* Pretty-print the struct ofp_switch_features of 'len' bytes at 'oh' to
@@ -704,7 +764,7 @@ ofp_print_port_status(struct ds *string, const void *oh, size_t len,
         ds_put_format(string, " ADD:");
     } else if (ops->reason == OFPPR_DELETE) {
         ds_put_format(string, " DEL:");
-    } else if (ops->reason == OFPPR_MOD) {
+    } else if (ops->reason == OFPPR_MODIFY) {
         ds_put_format(string, " MOD:");
     }
 
index 2f81ef7..1451cd8 100644 (file)
@@ -191,10 +191,11 @@ struct port_watcher;
 static struct hook port_watcher_create(struct rconn *local,
                                        struct rconn *remote,
                                        struct port_watcher **);
-static uint32_t port_watcher_get_flags(const struct port_watcher *,
+static uint32_t port_watcher_get_config(const struct port_watcher *,
                                        int port_no);
-static void port_watcher_set_flags(struct port_watcher *,
-                                   int port_no, uint32_t flags, uint32_t mask);
+static void port_watcher_set_flags(struct port_watcher *, int port_no, 
+                                   uint32_t config, uint32_t c_mask,
+                                   uint32_t state, uint32_t s_mask);
 
 static struct hook stp_hook_create(const struct settings *,
                                    struct port_watcher *,
@@ -616,13 +617,16 @@ struct port_watcher {
 static int
 opp_differs(const struct ofp_phy_port *a, const struct ofp_phy_port *b)
 {
-    BUILD_ASSERT_DECL(sizeof *a == 36); /* Trips when we add or remove fields. */
+    BUILD_ASSERT_DECL(sizeof *a == 48); /* Trips when we add or remove fields. */
     return ((a->port_no != b->port_no)
             + (memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) != 0)
             + (memcmp(a->name, b->name, sizeof a->name) != 0)
-            + (a->flags != b->flags)
-            + (a->speed != b->speed)
-            + (a->features != b->features));
+            + (a->config != b->config)
+            + (a->state != b->state)
+            + (a->curr != b->curr)
+            + (a->advertised != b->advertised)
+            + (a->supported != b->supported)
+            + (a->peer != b->peer));
 }
 
 static void
@@ -687,7 +691,7 @@ update_phy_port(struct port_watcher *pw, struct ofp_phy_port *opp,
     if (reason == OFPPR_DELETE) {
         memset(pw_opp, 0, sizeof *pw_opp);
         pw_opp->port_no = htons(OFPP_NONE);
-    } else if (reason == OFPPR_MOD || reason == OFPPR_ADD) {
+    } else if (reason == OFPPR_MODIFY || reason == OFPPR_ADD) {
         *pw_opp = *opp;
         sanitize_opp(pw_opp);
     }
@@ -716,7 +720,7 @@ port_watcher_local_packet_cb(struct relay *r, void *pw_)
                    / sizeof *osf->ports);
         for (i = 0; i < n_ports; i++) {
             struct ofp_phy_port *opp = &osf->ports[i];
-            update_phy_port(pw, opp, OFPPR_MOD, seen);
+            update_phy_port(pw, opp, OFPPR_MODIFY, seen);
         }
 
         /* Delete all the ports not included in the message. */
@@ -743,14 +747,14 @@ port_watcher_remote_packet_cb(struct relay *r, void *pw_)
     if (oh->type == OFPT_PORT_MOD
         && msg->size >= sizeof(struct ofp_port_mod)) {
         struct ofp_port_mod *opm = msg->data;
-        uint16_t port_no = ntohs(opm->desc.port_no);
+        uint16_t port_no = ntohs(opm->port_no);
         int idx = port_no_to_pw_idx(port_no);
         if (idx >= 0) {
             struct ofp_phy_port *pw_opp = &pw->ports[idx];
             if (pw_opp->port_no != htons(OFPP_NONE)) {
                 struct ofp_phy_port old = *pw_opp;
-                pw_opp->flags = ((pw_opp->flags & ~opm->mask)
-                                 | (opm->desc.flags & opm->mask));
+                pw_opp->config = ((pw_opp->config & ~opm->mask)
+                                 | (opm->config & opm->mask));
                 call_port_changed_callbacks(pw, port_no, &old, pw_opp);
             }
         }
@@ -786,6 +790,31 @@ put_duplexes(struct ds *ds, const char *name, uint32_t features,
     }
 }
 
+static void
+put_features(struct ds *ds, const char *name, uint32_t features) {
+    if (features & (OFPPF_10MB_HD | OFPPF_10MB_FD
+                    | OFPPF_100MB_HD | OFPPF_100MB_FD
+                    | OFPPF_1GB_HD | OFPPF_1GB_FD | OFPPF_10GB_FD)) {
+        ds_put_cstr(ds, name);
+        put_duplexes(ds, "10M", features, OFPPF_10MB_HD, OFPPF_10MB_FD);
+        put_duplexes(ds, "100M", features,
+                     OFPPF_100MB_HD, OFPPF_100MB_FD);
+        put_duplexes(ds, "1G", features, OFPPF_100MB_HD, OFPPF_100MB_FD);
+        if (features & OFPPF_10GB_FD) {
+            ds_put_cstr(ds, " 10G");
+        }
+        if (features & OFPPF_AUTONEG) {
+            ds_put_cstr(ds, " AUTO_NEG");
+        }
+        if (features & OFPPF_PAUSE) {
+            ds_put_cstr(ds, " PAUSE");
+        }
+        if (features & OFPPF_PAUSE_ASYM) {
+            ds_put_cstr(ds, " PAUSE_ASYM");
+        }
+    }
+}
+
 static void
 log_port_status(uint16_t port_no,
                 const struct ofp_phy_port *old,
@@ -795,10 +824,12 @@ log_port_status(uint16_t port_no,
     if (VLOG_IS_DBG_ENABLED()) {
         bool was_enabled = old->port_no != htons(OFPP_NONE);
         bool now_enabled = new->port_no != htons(OFPP_NONE);
-        uint32_t features = ntohl(new->features);
+        uint32_t curr = ntohl(new->curr);
+        uint32_t supported = ntohl(new->supported);
         struct ds ds;
 
-        if (old->flags != new->flags && opp_differs(old, new) == 1) {
+        if (((old->config != new->config) || (old->state != new->state))
+                && opp_differs(old, new) == 1) {
             /* Don't care if only flags changed. */
             return;
         }
@@ -806,20 +837,11 @@ log_port_status(uint16_t port_no,
         ds_init(&ds);
         ds_put_format(&ds, "\"%s\", "ETH_ADDR_FMT, new->name,
                       ETH_ADDR_ARGS(new->hw_addr));
-        if (ntohl(new->speed)) {
-            ds_put_format(&ds, ", speed %"PRIu32, ntohl(new->speed));
+        if (curr) {
+            put_features(&ds, ", current", curr);
         }
-        if (features & (OFPPF_10MB_HD | OFPPF_10MB_FD
-                        | OFPPF_100MB_HD | OFPPF_100MB_FD
-                        | OFPPF_1GB_HD | OFPPF_1GB_FD | OFPPF_10GB_FD)) {
-            ds_put_cstr(&ds, ", supports");
-            put_duplexes(&ds, "10M", features, OFPPF_10MB_HD, OFPPF_10MB_FD);
-            put_duplexes(&ds, "100M", features,
-                         OFPPF_100MB_HD, OFPPF_100MB_FD);
-            put_duplexes(&ds, "1G", features, OFPPF_100MB_HD, OFPPF_100MB_FD);
-            if (features & OFPPF_10GB_FD) {
-                ds_put_cstr(&ds, " 10G");
-            }
+        if (supported) {
+            put_features(&ds, ", supports", supported);
         }
         if (was_enabled != now_enabled) {
             if (now_enabled) {
@@ -846,15 +868,16 @@ port_watcher_register_callback(struct port_watcher *pw,
 }
 
 static uint32_t
-port_watcher_get_flags(const struct port_watcher *pw, int port_no)
+port_watcher_get_config(const struct port_watcher *pw, int port_no)
 {
     int idx = port_no_to_pw_idx(port_no);
-    return idx >= 0 ? ntohl(pw->ports[idx].flags) : 0;
+    return idx >= 0 ? ntohl(pw->ports[idx].config) : 0;
 }
 
 static void
-port_watcher_set_flags(struct port_watcher *pw,
-                       int port_no, uint32_t flags, uint32_t mask)
+port_watcher_set_flags(struct port_watcher *pw, int port_no, 
+                       uint32_t config, uint32_t c_mask,
+                       uint32_t state, uint32_t s_mask)
 {
     struct ofp_phy_port old;
     struct ofp_phy_port *p;
@@ -869,24 +892,29 @@ port_watcher_set_flags(struct port_watcher *pw,
     }
 
     p = &pw->ports[idx];
-    if (!((ntohl(p->flags) ^ flags) & mask)) {
+    if (!((ntohl(p->state) ^ state) & s_mask) 
+            && (!((ntohl(p->config) ^ config) & c_mask))) {
         return;
     }
     old = *p;
 
     /* Update our idea of the flags. */
-    p->flags = htonl((ntohl(p->flags) & ~mask) | (flags & mask));
+    p->config = htonl((ntohl(p->config) & ~c_mask) | (config & c_mask));
+    p->state = htonl((ntohl(p->state) & ~s_mask) | (state & s_mask));
     call_port_changed_callbacks(pw, port_no, &old, p);
 
     /* Change the flags in the datapath. */
     opm = make_openflow(sizeof *opm, OFPT_PORT_MOD, &b);
-    opm->mask = htonl(mask);
-    opm->desc = *p;
+    opm->port_no = p->port_no;
+    memcpy(opm->hw_addr, p->hw_addr, OFP_ETH_ALEN);
+    opm->config = p->config;
+    opm->mask = htonl(c_mask);
+    opm->advertise = htonl(0);
     rconn_send(pw->local_rconn, b, NULL);
 
     /* Notify the controller that the flags changed. */
     ops = make_openflow(sizeof *ops, OFPT_PORT_STATUS, &b);
-    ops->reason = OFPPR_MOD;
+    ops->reason = OFPPR_MODIFY;
     ops->desc = *p;
     rconn_send(pw->remote_rconn, b, NULL);
 }
@@ -964,7 +992,7 @@ stp_local_packet_cb(struct relay *r, void *stp_)
         /* STP only supports 255 ports. */
         return false;
     }
-    if (port_watcher_get_flags(stp->pw, port_no) & OFPPFL_NO_STP) {
+    if (port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP) {
         /* We're not doing STP on this port. */
         return false;
     }
@@ -1027,39 +1055,41 @@ stp_periodic_cb(void *stp_)
 
     while (stp_get_changed_port(stp->stp, &p)) {
         int port_no = stp_port_no(p);
-        enum stp_state state = stp_port_get_state(p);
+        enum stp_state s_state = stp_port_get_state(p);
 
-        if (state != STP_DISABLED) {
+        if (s_state != STP_DISABLED) {
             VLOG_WARN("STP: Port %d entered %s state",
-                      port_no, stp_state_name(state));
+                      port_no, stp_state_name(s_state));
         }
-        if (!(port_watcher_get_flags(stp->pw, port_no) & OFPPFL_NO_STP)) {
-            uint32_t flags;
-            switch (state) {
+        if (!(port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP)) {
+            uint32_t p_config = 0;
+            uint32_t p_state;
+            switch (s_state) {
             case STP_LISTENING:
-                flags = OFPPFL_STP_LISTEN;
+                p_state = OFPPS_STP_LISTEN;
                 break;
             case STP_LEARNING:
-                flags = OFPPFL_STP_LEARN;
+                p_state = OFPPS_STP_LEARN;
                 break;
             case STP_DISABLED:
             case STP_FORWARDING:
-                flags = OFPPFL_STP_FORWARD;
+                p_state = OFPPS_STP_FORWARD;
                 break;
             case STP_BLOCKING:
-                flags = OFPPFL_STP_BLOCK;
+                p_state = OFPPS_STP_BLOCK;
                 break;
             default:
                 VLOG_DBG_RL(&vrl, "STP: Port %d has bad state %x",
-                            port_no, state);
-                flags = OFPPFL_STP_FORWARD;
+                            port_no, s_state);
+                p_state = OFPPS_STP_FORWARD;
                 break;
             }
-            if (!stp_forward_in_state(state)) {
-                flags |= OFPPFL_NO_FLOOD;
+            if (!stp_forward_in_state(s_state)) {
+                p_config = OFPPC_NO_FLOOD;
             }
-            port_watcher_set_flags(stp->pw, port_no, flags,
-                                   OFPPFL_STP_MASK | OFPPFL_NO_FLOOD);
+            port_watcher_set_flags(stp->pw, port_no, 
+                                   p_config, OFPPC_NO_FLOOD,
+                                   p_state, OFPPS_STP_MASK);
         } else {
             /* We don't own those flags. */
         }
@@ -1125,11 +1155,21 @@ stp_port_changed_cb(uint16_t port_no,
 
     p = stp_get_port(stp->stp, port_no);
     if (new->port_no == htons(OFPP_NONE)
-        || new->flags & htonl(OFPPFL_NO_STP)) {
+        || new->config & htonl(OFPPC_NO_STP)) {
         stp_port_disable(p);
     } else {
+        int speed = 0;
         stp_port_enable(p);
-        stp_port_set_speed(p, new->speed);
+        if (new->curr & (OFPPF_10MB_HD | OFPPF_10MB_FD)) {
+            speed = 10;
+        } else if (new->curr & (OFPPF_100MB_HD | OFPPF_100MB_FD)) {
+            speed = 100;
+        } else if (new->curr & (OFPPF_1GB_HD | OFPPF_1GB_FD)) {
+            speed = 1000;
+        } else if (new->curr & OFPPF_100MB_FD) {
+            speed = 10000;
+        }
+        stp_port_set_speed(p, speed);
     }
 }
 
index 5d4590f..1c8e134 100644 (file)
@@ -79,12 +79,9 @@ extern char serial_num;
                                 | (1 << OFPAT_SET_TP_SRC)   \
                                 | (1 << OFPAT_SET_TP_DST) )
 
-#define PORT_STATUS_BITS (OFPPFL_PORT_DOWN | OFPPFL_LINK_DOWN)
-#define PORT_FLAG_BITS (~PORT_STATUS_BITS)
-
 struct sw_port {
-    uint32_t flags;             /* Some subset of PORT_FLAG_BITS. */
-    uint32_t status;            /* Some subset of PORT_STATUS_BITS. */
+    uint32_t config;            /* Some subset of OFPPC_* flags. */
+    uint32_t state;             /* Some subset of OFPPS_* flags. */
     struct datapath *dp;
     struct netdev *netdev;
     struct list node; /* Element in datapath.ports. */
@@ -300,7 +297,7 @@ dp_run(struct datapath *dp)
 
         LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) {
             if (update_port_status(p)) {
-                send_port_status(p, OFPPR_MOD);
+                send_port_status(p, OFPPR_MODIFY);
             }
         }
 
@@ -527,7 +524,7 @@ output_all(struct datapath *dp, struct ofpbuf *buffer, int in_port, int flood)
         if (port_no(dp, p) == in_port) {
             continue;
         }
-        if (flood && p->flags & OFPPFL_NO_FLOOD) {
+        if (flood && p->config & OFPPC_NO_FLOOD) {
             continue;
         }
         if (prev_port != -1) {
@@ -549,7 +546,7 @@ output_packet(struct datapath *dp, struct ofpbuf *buffer, int out_port)
 {
     if (out_port >= 0 && out_port < OFPP_MAX) { 
         struct sw_port *p = &dp->ports[out_port];
-        if (p->netdev != NULL && !(p->status & OFPPFL_PORT_DOWN)) {
+        if (p->netdev != NULL && !(p->config & OFPPC_PORT_DOWN)) {
             if (!netdev_send(p->netdev, buffer)) {
                 p->tx_packets++;
                 p->tx_bytes += buffer->size;
@@ -660,10 +657,14 @@ static void fill_port_desc(struct datapath *dp, struct sw_port *p,
             sizeof desc->name);
     desc->name[sizeof desc->name - 1] = '\0';
     memcpy(desc->hw_addr, netdev_get_etheraddr(p->netdev), ETH_ADDR_LEN);
-    desc->flags = 0;
-    desc->features = htonl(netdev_get_features(p->netdev));
-    desc->speed = htonl(netdev_get_speed(p->netdev));
-    desc->flags = htonl(p->flags | p->status);
+    desc->config = htonl(p->config);
+    desc->state = htonl(p->state);
+    desc->curr = htonl(netdev_get_features(p->netdev, NETDEV_FEAT_CURRENT));
+    desc->supported = htonl(netdev_get_features(p->netdev, 
+                NETDEV_FEAT_SUPPORTED));
+    desc->advertised = htonl(netdev_get_features(p->netdev, 
+                NETDEV_FEAT_ADVERTISED));
+    desc->peer = htonl(netdev_get_features(p->netdev, NETDEV_FEAT_PEER));
 }
 
 static void
@@ -691,33 +692,31 @@ dp_send_features_reply(struct datapath *dp, const struct sender *sender)
 void
 dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm)
 {
-    const struct ofp_phy_port *opp = &opm->desc;
-    int port_no = ntohs(opp->port_no);
+    int port_no = ntohs(opm->port_no);
     if (port_no < OFPP_MAX) {
         struct sw_port *p = &dp->ports[port_no];
-        uint32_t flag_mask;
 
         /* Make sure the port id hasn't changed since this was sent */
-        if (!p || memcmp(opp->hw_addr, netdev_get_etheraddr(p->netdev),
+        if (!p || memcmp(opm->hw_addr, netdev_get_etheraddr(p->netdev),
                          ETH_ADDR_LEN) != 0) {
             return;
         }
 
 
-        flag_mask = ntohl(opm->mask) & PORT_FLAG_BITS;
-        if (flag_mask) {
-            p->flags &= ~flag_mask;
-            p->flags |= ntohl(opp->flags) & flag_mask;
+        if (opm->mask) {
+            uint32_t config_mask = ntohl(opm->mask);
+            p->config &= ~config_mask;
+            p->config |= ntohl(opm->config) & config_mask;
         }
 
-        if (opm->mask & htonl(OFPPFL_PORT_DOWN)) {
-            if ((opp->flags & htonl(OFPPFL_PORT_DOWN))
-                && (p->status & OFPPFL_PORT_DOWN) == 0) {
-                p->status |= OFPPFL_PORT_DOWN;
+        if (opm->mask & htonl(OFPPC_PORT_DOWN)) {
+            if ((opm->config & htonl(OFPPC_PORT_DOWN))
+                && (p->config & OFPPC_PORT_DOWN) == 0) {
+                p->config |= OFPPC_PORT_DOWN;
                 netdev_turn_flags_off(p->netdev, NETDEV_UP, true);
-            } else if ((opp->flags & htonl(OFPPFL_PORT_DOWN)) == 0
-                       && (p->status & OFPPFL_PORT_DOWN)) {
-                p->status &= ~OFPPFL_PORT_DOWN;
+            } else if ((opm->config & htonl(OFPPC_PORT_DOWN)) == 0
+                       && (p->config & OFPPC_PORT_DOWN)) {
+                p->config &= ~OFPPC_PORT_DOWN;
                 netdev_turn_flags_on(p->netdev, NETDEV_UP, true);
             }
         }
@@ -735,7 +734,8 @@ update_port_status(struct sw_port *p)
 {
     int retval;
     enum netdev_flags flags;
-    uint32_t orig_status = p->status;
+    uint32_t orig_config = p->config;
+    uint32_t orig_state = p->state;
 
     if (netdev_get_flags(p->netdev, &flags) < 0) {
         VLOG_WARN_RL(&rl, "could not get netdev flags for %s", 
@@ -743,9 +743,9 @@ update_port_status(struct sw_port *p)
         return 0;
     } else {
         if (flags & NETDEV_UP) {
-            p->status &= ~OFPPFL_PORT_DOWN;
+            p->config &= ~OFPPC_PORT_DOWN;
         } else {
-            p->status |= OFPPFL_PORT_DOWN;
+            p->config |= OFPPC_PORT_DOWN;
         } 
     }
 
@@ -753,12 +753,12 @@ update_port_status(struct sw_port *p)
      * error. */
     retval = netdev_get_link_status(p->netdev);
     if (retval == 1) {
-        p->status &= ~OFPPFL_LINK_DOWN;
+        p->state &= ~OFPPS_LINK_DOWN;
     } else if (retval == 0) {
-        p->status |= OFPPFL_LINK_DOWN;
+        p->state |= OFPPS_LINK_DOWN;
     } 
 
-    return (orig_status != p->status);
+    return ((orig_config != p->config) || (orig_state != p->state));
 }
 
 static void
@@ -858,9 +858,9 @@ int run_flow_through_tables(struct datapath *dp, struct ofpbuf *buffer,
         ofpbuf_delete(buffer);
         return 0;
     }
-       if (p && p->flags & (OFPPFL_NO_RECV | OFPPFL_NO_RECV_STP)
-        && p->flags & (!eth_addr_equals(key.flow.dl_dst, stp_eth_addr)
-                       ? OFPPFL_NO_RECV : OFPPFL_NO_RECV_STP)) {
+       if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP)
+        && p->config & (!eth_addr_equals(key.flow.dl_dst, stp_eth_addr)
+                       ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) {
                ofpbuf_delete(buffer);
                return 0;
        }
index 58e5e56..4a781c0 100644 (file)
@@ -1054,25 +1054,27 @@ do_mod_port(const struct settings *s, int argc, char *argv[])
     }
 
     opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request);
-    memcpy(&opm->desc, &osf->ports[port_idx], sizeof osf->ports[0]);
-    opm->mask = 0;
-    opm->desc.flags = 0;
+    opm->port_no = osf->ports[port_idx].port_no;
+    memcpy(opm->hw_addr, osf->ports[port_idx].hw_addr, sizeof opm->hw_addr);
+    opm->config = htonl(0);
+    opm->mask = htonl(0);
+    opm->advertise = htonl(0);
 
     printf("modifying port: %s\n", osf->ports[port_idx].name);
 
     if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) {
-        opm->mask |= htonl(OFPPFL_PORT_DOWN);
+        opm->mask |= htonl(OFPPC_PORT_DOWN);
     } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN, 
                 sizeof MOD_PORT_CMD_DOWN)) {
-        opm->mask |= htonl(OFPPFL_PORT_DOWN);
-        opm->desc.flags |= htonl(OFPPFL_PORT_DOWN);
+        opm->mask |= htonl(OFPPC_PORT_DOWN);
+        opm->config |= htonl(OFPPC_PORT_DOWN);
     } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD, 
                 sizeof MOD_PORT_CMD_FLOOD)) {
-        opm->mask |= htonl(OFPPFL_NO_FLOOD);
+        opm->mask |= htonl(OFPPC_NO_FLOOD);
     } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD, 
                 sizeof MOD_PORT_CMD_NOFLOOD)) {
-        opm->mask |= htonl(OFPPFL_NO_FLOOD);
-        opm->desc.flags |= htonl(OFPPFL_NO_FLOOD);
+        opm->mask |= htonl(OFPPC_NO_FLOOD);
+        opm->config |= htonl(OFPPC_NO_FLOOD);
     } else {
         ofp_fatal(0, "unknown mod-port command '%s'", argv[3]);
     }