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);
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;
}
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)
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
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 */
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);
}
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);
}
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;
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 */
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;
}
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;
}
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;
}
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? */
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);
/* 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
/* 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 {
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 {
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 {
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) {
#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>
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. */
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);
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));
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
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
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)
{
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
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:");
}
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 *,
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
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);
}
/ 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. */
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);
}
}
}
}
+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,
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;
}
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) {
}
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;
}
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);
}
/* 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;
}
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. */
}
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);
}
}
| (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. */
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);
}
}
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) {
{
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;
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
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);
}
}
{
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",
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;
}
}
* 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
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;
}
}
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]);
}