/*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
* Copyright (c) 2010 Jean Tourrilhes - HP-Labs.
*
* Licensed under the Apache License, Version 2.0 (the "License");
{
struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
if (!ofport) {
- VLOG_WARN("%s: cannot get STP status on nonexistent port %"PRIu16,
- ofproto->name, ofp_port);
+ VLOG_WARN_RL(&rl, "%s: cannot get STP status on nonexistent "
+ "port %"PRIu16, ofproto->name, ofp_port);
return ENODEV;
}
int
ofproto_run(struct ofproto *p)
{
+ struct sset changed_netdevs;
+ const char *changed_netdev;
struct ofport *ofport;
- char *devname;
int error;
error = p->ofproto_class->run(p);
}
if (p->ofproto_class->port_poll) {
+ char *devname;
+
while ((error = p->ofproto_class->port_poll(p, &devname)) != EAGAIN) {
process_port_change(p, error, devname);
}
}
+ /* Update OpenFlow port status for any port whose netdev has changed.
+ *
+ * Refreshing a given 'ofport' can cause an arbitrary ofport to be
+ * destroyed, so it's not safe to update ports directly from the
+ * HMAP_FOR_EACH loop, or even to use HMAP_FOR_EACH_SAFE. Instead, we
+ * need this two-phase approach. */
+ sset_init(&changed_netdevs);
HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
unsigned int change_seq = netdev_change_seq(ofport->netdev);
if (ofport->change_seq != change_seq) {
ofport->change_seq = change_seq;
- update_port(p, netdev_get_name(ofport->netdev));
+ sset_add(&changed_netdevs, netdev_get_name(ofport->netdev));
}
}
+ SSET_FOR_EACH (changed_netdev, &changed_netdevs) {
+ update_port(p, changed_netdev);
+ }
+ sset_destroy(&changed_netdevs);
switch (p->state) {
case S_OPENFLOW:
}
}
ofconn_set_invalid_ttl_to_controller(ofconn,
- (flags & OFPC_INVALID_TTL_TO_CONTROLLER));
+ (flags & OFPC_INVALID_TTL_TO_CONTROLLER));
ofconn_set_miss_send_len(ofconn, ntohs(osc->miss_send_len));
return 0;
}
+static enum ofperr
+handle_port_desc_stats_request(struct ofconn *ofconn,
+ const struct ofp_stats_msg *osm)
+{
+ struct ofproto *p = ofconn_get_ofproto(ofconn);
+ struct ofport *port;
+ struct list replies;
+
+ ofputil_start_stats_reply(osm, &replies);
+
+ HMAP_FOR_EACH (port, hmap_node, &p->ports) {
+ ofputil_append_port_desc_stats_reply(ofconn_get_protocol(ofconn),
+ &port->pp, &replies);
+ }
+
+ ofconn_send_replies(ofconn, &replies);
+ return 0;
+}
+
static void
calc_flow_duration__(long long int start, long long int now,
uint32_t *sec, uint32_t *nsec)
: -1);
}
+/* Checks the health of the CFM for 'ofp_port' within 'ofproto'. Returns an
+ * integer value between 0 and 100 to indicate the health of the port as a
+ * percentage which is the average of cfm health of all the remote_mpids or
+ * returns -1 if CFM is not enabled on 'ofport'. */
+int
+ofproto_port_get_cfm_health(const struct ofproto *ofproto, uint16_t ofp_port)
+{
+ struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
+ return (ofport && ofproto->ofproto_class->get_cfm_health
+ ? ofproto->ofproto_class->get_cfm_health(ofport)
+ : -1);
+}
+
static enum ofperr
handle_aggregate_stats_request(struct ofconn *ofconn,
const struct ofp_stats_msg *osm)
role = ntohl(nrr->role);
if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
&& role != NX_ROLE_SLAVE) {
- return OFPERR_NXBRC_BAD_ROLE;
+ return OFPERR_OFPRRFC_BAD_ROLE;
}
if (ofconn_get_role(ofconn) != role
case OFPUTIL_OFPST_QUEUE_REQUEST:
return handle_queue_stats_request(ofconn, msg->data);
+ case OFPUTIL_OFPST_PORT_DESC_REQUEST:
+ return handle_port_desc_stats_request(ofconn, msg->data);
+
case OFPUTIL_MSG_INVALID:
case OFPUTIL_OFPT_HELLO:
case OFPUTIL_OFPT_ERROR:
case OFPUTIL_OFPST_PORT_REPLY:
case OFPUTIL_OFPST_TABLE_REPLY:
case OFPUTIL_OFPST_AGGREGATE_REPLY:
+ case OFPUTIL_OFPST_PORT_DESC_REPLY:
case OFPUTIL_NXT_ROLE_REPLY:
case OFPUTIL_NXT_FLOW_REMOVED:
case OFPUTIL_NXT_PACKET_IN: