X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=4b2cbc90fa1f317f04a33a12199ae5f444a9589f;hb=ccbe50f8f61ac944eb965f67c570d79b6724c9cf;hp=d03bd9b37cdc2c1649ea269fe6f5e4fb5baed331;hpb=9e1fd49b0cf494315c82f27c651486ef82e83446;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index d03bd9b3..4b2cbc90 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1,5 +1,5 @@ /* - * 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"); @@ -196,7 +196,7 @@ static enum ofperr handle_flow_mod__(struct ofproto *, struct ofconn *, static uint64_t pick_datapath_id(const struct ofproto *); static uint64_t pick_fallback_dpid(void); static void ofproto_destroy__(struct ofproto *); -static void set_internal_devs_mtu(struct ofproto *); +static void update_mtu(struct ofproto *, struct ofport *); /* unixctl. */ static void ofproto_unixctl_init(void); @@ -387,6 +387,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type, hmap_init(&ofproto->deletions); ofproto->vlan_bitmap = NULL; ofproto->vlans_changed = false; + ofproto->min_mtu = INT_MAX; error = ofproto->ofproto_class->construct(ofproto); if (error) { @@ -663,8 +664,8 @@ ofproto_port_get_stp_status(struct ofproto *ofproto, uint16_t ofp_port, { 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; } @@ -1026,8 +1027,9 @@ process_port_change(struct ofproto *ofproto, int error, char *devname) int ofproto_run(struct ofproto *p) { + struct sset changed_netdevs; + const char *changed_netdev; struct ofport *ofport; - char *devname; int error; error = p->ofproto_class->run(p); @@ -1036,18 +1038,31 @@ ofproto_run(struct ofproto *p) } if (p->ofproto_class->port_poll) { + char *devname; + while ((error = p->ofproto_class->port_poll(p, &devname)) != EAGAIN) { process_port_change(p, error, devname); } } + /* Update OpenFlow port status for any port whose netdev has changed. + * + * Refreshing a given 'ofport' can cause an arbitrary ofport to be + * destroyed, so it's not safe to update ports directly from the + * HMAP_FOR_EACH loop, or even to use HMAP_FOR_EACH_SAFE. Instead, we + * need this two-phase approach. */ + sset_init(&changed_netdevs); HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { unsigned int change_seq = netdev_change_seq(ofport->netdev); if (ofport->change_seq != change_seq) { ofport->change_seq = change_seq; - update_port(p, netdev_get_name(ofport->netdev)); + sset_add(&changed_netdevs, netdev_get_name(ofport->netdev)); } } + SSET_FOR_EACH (changed_netdev, &changed_netdevs) { + update_port(p, changed_netdev); + } + sset_destroy(&changed_netdevs); switch (p->state) { case S_OPENFLOW: @@ -1457,7 +1472,6 @@ ofport_install(struct ofproto *p, { const char *netdev_name = netdev_get_name(netdev); struct ofport *ofport; - int dev_mtu; int error; /* Create ofport. */ @@ -1476,12 +1490,7 @@ ofport_install(struct ofproto *p, hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->ofp_port, 0)); shash_add(&p->port_by_name, netdev_name, ofport); - if (!netdev_get_mtu(netdev, &dev_mtu)) { - set_internal_devs_mtu(p); - ofport->mtu = dev_mtu; - } else { - ofport->mtu = 0; - } + update_mtu(p, ofport); /* Let the ofproto_class initialize its private data. */ error = p->ofproto_class->port_construct(ofport); @@ -1643,21 +1652,13 @@ update_port(struct ofproto *ofproto, const char *name) port = ofproto_get_port(ofproto, ofproto_port.ofp_port); if (port && !strcmp(netdev_get_name(port->netdev), name)) { struct netdev *old_netdev = port->netdev; - int dev_mtu; /* 'name' hasn't changed location. Any properties changed? */ if (!ofport_equal(&port->pp, &pp)) { ofport_modified(port, &pp); } - /* If this is a non-internal port and the MTU changed, check - * if the datapath's MTU needs to be updated. */ - if (strcmp(netdev_get_type(netdev), "internal") - && !netdev_get_mtu(netdev, &dev_mtu) - && port->mtu != dev_mtu) { - set_internal_devs_mtu(ofproto); - port->mtu = dev_mtu; - } + update_mtu(ofproto, port); /* Install the newly opened netdev in case it has changed. * Don't close the old netdev yet in case port_modified has to @@ -1744,19 +1745,44 @@ find_min_mtu(struct ofproto *p) return mtu ? mtu: ETH_PAYLOAD_MAX; } -/* Set the MTU of all datapath devices on 'p' to the minimum of the - * non-datapath ports. */ +/* Update MTU of all datapath devices on 'p' to the minimum of the + * non-datapath ports in event of 'port' added or changed. */ static void -set_internal_devs_mtu(struct ofproto *p) +update_mtu(struct ofproto *p, struct ofport *port) { struct ofport *ofport; - int mtu = find_min_mtu(p); + struct netdev *netdev = port->netdev; + int dev_mtu, old_min; + + if (netdev_get_mtu(netdev, &dev_mtu)) { + port->mtu = 0; + return; + } + if (!strcmp(netdev_get_type(port->netdev), "internal")) { + if (dev_mtu > p->min_mtu) { + if (!netdev_set_mtu(port->netdev, p->min_mtu)) { + dev_mtu = p->min_mtu; + } + } + port->mtu = dev_mtu; + return; + } + + /* For non-internal port find new min mtu. */ + old_min = p->min_mtu; + port->mtu = dev_mtu; + p->min_mtu = find_min_mtu(p); + if (p->min_mtu == old_min) { + return; + } HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { struct netdev *netdev = ofport->netdev; if (!strcmp(netdev_get_type(netdev), "internal")) { - netdev_set_mtu(netdev, mtu); + if (!netdev_set_mtu(netdev, p->min_mtu)) { + ofport->mtu = p->min_mtu; + } } } } @@ -1931,7 +1957,7 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc) } } 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)); @@ -2469,6 +2495,19 @@ ofproto_port_get_cfm_remote_mpids(const struct ofproto *ofproto, : -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) @@ -3052,7 +3091,7 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) 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