-int
-ofproto_send_packet(struct ofproto *p, const flow_t *flow,
- const union ofp_action *actions, size_t n_actions,
- const struct ofpbuf *packet)
-{
- struct odp_actions odp_actions;
- int error;
-
- error = xlate_actions(actions, n_actions, flow, p, packet, &odp_actions,
- NULL, NULL, NULL);
- if (error) {
- return error;
- }
-
- /* XXX Should we translate the dpif_execute() errno value into an OpenFlow
- * error code? */
- dpif_execute(p->dpif, flow->in_port, odp_actions.actions,
- odp_actions.n_actions, packet);
- return 0;
-}
-
-void
-ofproto_add_flow(struct ofproto *p,
- const flow_t *flow, uint32_t wildcards, unsigned int priority,
- const union ofp_action *actions, size_t n_actions,
- int idle_timeout)
-{
- struct rule *rule;
- rule = rule_create(p, NULL, actions, n_actions,
- idle_timeout >= 0 ? idle_timeout : 5 /* XXX */,
- 0, 0, false);
- cls_rule_from_flow(flow, wildcards, priority, &rule->cr);
- rule_insert(p, rule, NULL, 0);
-}
-
-void
-ofproto_delete_flow(struct ofproto *ofproto, const flow_t *flow,
- uint32_t wildcards, unsigned int priority)
-{
- struct rule *rule;
-
- rule = rule_from_cls_rule(classifier_find_rule_exactly(&ofproto->cls,
- flow, wildcards,
- priority));
- if (rule) {
- rule_remove(ofproto, rule);
- }
-}
-
-static void
-destroy_rule(struct cls_rule *rule_, void *ofproto_)
-{
- struct rule *rule = rule_from_cls_rule(rule_);
- struct ofproto *ofproto = ofproto_;
-
- /* Mark the flow as not installed, even though it might really be
- * installed, so that rule_remove() doesn't bother trying to uninstall it.
- * There is no point in uninstalling it individually since we are about to
- * blow away all the flows with dpif_flow_flush(). */
- rule->installed = false;
-
- rule_remove(ofproto, rule);
-}
-
-void
-ofproto_flush_flows(struct ofproto *ofproto)
-{
- COVERAGE_INC(ofproto_flush);
- classifier_for_each(&ofproto->cls, CLS_INC_ALL, destroy_rule, ofproto);
- dpif_flow_flush(ofproto->dpif);
- if (ofproto->in_band) {
- in_band_flushed(ofproto->in_band);
- }
- if (ofproto->fail_open) {
- fail_open_flushed(ofproto->fail_open);
- }
-}
-\f
-static void
-reinit_ports(struct ofproto *p)
-{
- struct svec devnames;
- struct ofport *ofport;
- struct odp_port *odp_ports;
- size_t n_odp_ports;
- size_t i;
-
- svec_init(&devnames);
- HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
- svec_add (&devnames, (char *) ofport->opp.name);
- }
- dpif_port_list(p->dpif, &odp_ports, &n_odp_ports);
- for (i = 0; i < n_odp_ports; i++) {
- svec_add (&devnames, odp_ports[i].devname);
- }
- free(odp_ports);
-
- svec_sort_unique(&devnames);
- for (i = 0; i < devnames.n; i++) {
- update_port(p, devnames.names[i]);
- }
- svec_destroy(&devnames);
-}
-
-static size_t
-refresh_port_group(struct ofproto *p, unsigned int group)
-{
- uint16_t *ports;
- size_t n_ports;
- struct ofport *port;
-
- assert(group == DP_GROUP_ALL || group == DP_GROUP_FLOOD);
-
- ports = xmalloc(hmap_count(&p->ports) * sizeof *ports);
- n_ports = 0;
- HMAP_FOR_EACH (port, hmap_node, &p->ports) {
- if (group == DP_GROUP_ALL || !(port->opp.config & OFPPC_NO_FLOOD)) {
- ports[n_ports++] = port->odp_port;
- }
- }
- dpif_port_group_set(p->dpif, group, ports, n_ports);
- free(ports);
-
- return n_ports;
-}
-
-static void
-refresh_port_groups(struct ofproto *p)
-{
- size_t n_flood = refresh_port_group(p, DP_GROUP_FLOOD);
- size_t n_all = refresh_port_group(p, DP_GROUP_ALL);
- if (p->sflow) {
- ofproto_sflow_set_group_sizes(p->sflow, n_flood, n_all);
- }
-}
-
-static struct ofport *
-make_ofport(const struct odp_port *odp_port)
-{
- struct netdev_options netdev_options;
- enum netdev_flags flags;
- struct ofport *ofport;
- struct netdev *netdev;
- bool carrier;
- int error;
-
- memset(&netdev_options, 0, sizeof netdev_options);
- netdev_options.name = odp_port->devname;
- netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
-
- error = netdev_open(&netdev_options, &netdev);
- if (error) {
- VLOG_WARN_RL(&rl, "ignoring port %s (%"PRIu16") because netdev %s "
- "cannot be opened (%s)",
- odp_port->devname, odp_port->port,
- odp_port->devname, strerror(error));
- return NULL;
- }
-
- ofport = xmalloc(sizeof *ofport);
- ofport->netdev = netdev;
- ofport->odp_port = odp_port->port;
- ofport->opp.port_no = odp_port_to_ofp_port(odp_port->port);
- netdev_get_etheraddr(netdev, ofport->opp.hw_addr);
- memcpy(ofport->opp.name, odp_port->devname,
- MIN(sizeof ofport->opp.name, sizeof odp_port->devname));
- ofport->opp.name[sizeof ofport->opp.name - 1] = '\0';
-
- netdev_get_flags(netdev, &flags);
- ofport->opp.config = flags & NETDEV_UP ? 0 : OFPPC_PORT_DOWN;
-
- netdev_get_carrier(netdev, &carrier);
- ofport->opp.state = carrier ? 0 : OFPPS_LINK_DOWN;
-
- netdev_get_features(netdev,
- &ofport->opp.curr, &ofport->opp.advertised,
- &ofport->opp.supported, &ofport->opp.peer);
- return ofport;
-}
-
-static bool
-ofport_conflicts(const struct ofproto *p, const struct odp_port *odp_port)
-{
- if (get_port(p, odp_port->port)) {
- VLOG_WARN_RL(&rl, "ignoring duplicate port %"PRIu16" in datapath",
- odp_port->port);
- return true;
- } else if (shash_find(&p->port_by_name, odp_port->devname)) {
- VLOG_WARN_RL(&rl, "ignoring duplicate device %s in datapath",
- odp_port->devname);
- return true;
- } else {
- return false;
- }
-}
-
-static int
-ofport_equal(const struct ofport *a_, const struct ofport *b_)
-{
- const struct ofp_phy_port *a = &a_->opp;
- const struct ofp_phy_port *b = &b_->opp;
-
- BUILD_ASSERT_DECL(sizeof *a == 48); /* Detect ofp_phy_port changes. */
- return (a->port_no == b->port_no
- && !memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr)
- && !strcmp((char *) a->name, (char *) b->name)
- && a->state == b->state
- && a->config == b->config
- && a->curr == b->curr
- && a->advertised == b->advertised
- && a->supported == b->supported
- && a->peer == b->peer);
-}
-
-static void
-send_port_status(struct ofproto *p, const struct ofport *ofport,
- uint8_t reason)
-{
- /* XXX Should limit the number of queued port status change messages. */
- struct ofconn *ofconn;
- LIST_FOR_EACH (ofconn, node, &p->all_conns) {
- struct ofp_port_status *ops;
- struct ofpbuf *b;
-
- if (!ofconn_receives_async_msgs(ofconn)) {
- continue;
- }
-
- ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &b);
- ops->reason = reason;
- ops->desc = ofport->opp;
- hton_ofp_phy_port(&ops->desc);
- queue_tx(b, ofconn, NULL);
- }
-}
-
-static void
-ofport_install(struct ofproto *p, struct ofport *ofport)
-{
- const char *netdev_name = (const char *) ofport->opp.name;
-
- netdev_monitor_add(p->netdev_monitor, ofport->netdev);
- hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->odp_port, 0));
- shash_add(&p->port_by_name, netdev_name, ofport);
- if (p->sflow) {
- ofproto_sflow_add_port(p->sflow, ofport->odp_port, netdev_name);
- }
-}
-
-static void
-ofport_remove(struct ofproto *p, struct ofport *ofport)
-{
- netdev_monitor_remove(p->netdev_monitor, ofport->netdev);
- hmap_remove(&p->ports, &ofport->hmap_node);
- shash_delete(&p->port_by_name,
- shash_find(&p->port_by_name, (char *) ofport->opp.name));
- if (p->sflow) {
- ofproto_sflow_del_port(p->sflow, ofport->odp_port);
- }
-}
-
-static void
-ofport_free(struct ofport *ofport)
-{
- if (ofport) {
- netdev_close(ofport->netdev);
- free(ofport);
- }
-}
-
-static struct ofport *
-get_port(const struct ofproto *ofproto, uint16_t odp_port)
-{
- struct ofport *port;
-
- HMAP_FOR_EACH_IN_BUCKET (port, hmap_node,
- hash_int(odp_port, 0), &ofproto->ports) {
- if (port->odp_port == odp_port) {
- return port;
- }
- }
- return NULL;
-}
-
-static void
-update_port(struct ofproto *p, const char *devname)
-{
- struct odp_port odp_port;
- struct ofport *old_ofport;
- struct ofport *new_ofport;
- int error;
-
- COVERAGE_INC(ofproto_update_port);
-
- /* Query the datapath for port information. */
- error = dpif_port_query_by_name(p->dpif, devname, &odp_port);
-
- /* Find the old ofport. */
- old_ofport = shash_find_data(&p->port_by_name, devname);
- if (!error) {
- if (!old_ofport) {
- /* There's no port named 'devname' but there might be a port with
- * the same port number. This could happen if a port is deleted
- * and then a new one added in its place very quickly, or if a port
- * is renamed. In the former case we want to send an OFPPR_DELETE
- * and an OFPPR_ADD, and in the latter case we want to send a
- * single OFPPR_MODIFY. We can distinguish the cases by comparing
- * the old port's ifindex against the new port, or perhaps less
- * reliably but more portably by comparing the old port's MAC
- * against the new port's MAC. However, this code isn't that smart
- * and always sends an OFPPR_MODIFY (XXX). */
- old_ofport = get_port(p, odp_port.port);
- }
- } else if (error != ENOENT && error != ENODEV) {
- VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error "
- "%s", strerror(error));
- return;
- }
-
- /* Create a new ofport. */
- new_ofport = !error ? make_ofport(&odp_port) : NULL;
-
- /* Eliminate a few pathological cases. */
- if (!old_ofport && !new_ofport) {
- return;
- } else if (old_ofport && new_ofport) {
- /* Most of the 'config' bits are OpenFlow soft state, but
- * OFPPC_PORT_DOWN is maintained the kernel. So transfer the OpenFlow
- * bits from old_ofport. (make_ofport() only sets OFPPC_PORT_DOWN and
- * leaves the other bits 0.) */
- new_ofport->opp.config |= old_ofport->opp.config & ~OFPPC_PORT_DOWN;
-
- if (ofport_equal(old_ofport, new_ofport)) {
- /* False alarm--no change. */
- ofport_free(new_ofport);
- return;
- }
- }
-
- /* Now deal with the normal cases. */
- if (old_ofport) {
- ofport_remove(p, old_ofport);
- }
- if (new_ofport) {
- ofport_install(p, new_ofport);
- }
- send_port_status(p, new_ofport ? new_ofport : old_ofport,
- (!old_ofport ? OFPPR_ADD
- : !new_ofport ? OFPPR_DELETE
- : OFPPR_MODIFY));
- ofport_free(old_ofport);
-
- /* Update port groups. */
- refresh_port_groups(p);
-}
-
-static int
-init_ports(struct ofproto *p)
-{
- struct odp_port *ports;
- size_t n_ports;
- size_t i;
- int error;
-
- error = dpif_port_list(p->dpif, &ports, &n_ports);
- if (error) {
- return error;
- }
-
- for (i = 0; i < n_ports; i++) {
- const struct odp_port *odp_port = &ports[i];
- if (!ofport_conflicts(p, odp_port)) {
- struct ofport *ofport = make_ofport(odp_port);
- if (ofport) {
- ofport_install(p, ofport);
- }
- }
- }
- free(ports);
- refresh_port_groups(p);
- return 0;
-}
-\f
-static struct ofconn *
-ofconn_create(struct ofproto *p, struct rconn *rconn, enum ofconn_type type)
-{
- struct ofconn *ofconn = xzalloc(sizeof *ofconn);
- ofconn->ofproto = p;
- list_push_back(&p->all_conns, &ofconn->node);
- ofconn->rconn = rconn;
- ofconn->type = type;
- ofconn->role = NX_ROLE_OTHER;
- ofconn->packet_in_counter = rconn_packet_counter_create ();
- ofconn->pktbuf = NULL;
- ofconn->miss_send_len = 0;
- ofconn->reply_counter = rconn_packet_counter_create ();
- return ofconn;
-}
-
-static void
-ofconn_destroy(struct ofconn *ofconn)
-{
- if (ofconn->type == OFCONN_PRIMARY) {
- hmap_remove(&ofconn->ofproto->controllers, &ofconn->hmap_node);
- }
- discovery_destroy(ofconn->discovery);
-
- list_remove(&ofconn->node);
- switch_status_unregister(ofconn->ss);
- rconn_destroy(ofconn->rconn);
- rconn_packet_counter_destroy(ofconn->packet_in_counter);
- rconn_packet_counter_destroy(ofconn->reply_counter);
- pktbuf_destroy(ofconn->pktbuf);
- free(ofconn);
-}
-
-static void
-ofconn_run(struct ofconn *ofconn, struct ofproto *p)
-{
- int iteration;
- size_t i;
-
- if (ofconn->discovery) {
- char *controller_name;
- if (rconn_is_connectivity_questionable(ofconn->rconn)) {
- discovery_question_connectivity(ofconn->discovery);
- }
- if (discovery_run(ofconn->discovery, &controller_name)) {
- if (controller_name) {
- char *ofconn_name = ofconn_make_name(p, controller_name);
- rconn_connect(ofconn->rconn, controller_name, ofconn_name);
- free(ofconn_name);
- } else {
- rconn_disconnect(ofconn->rconn);
- }
- }
- }
-
- for (i = 0; i < N_SCHEDULERS; i++) {
- pinsched_run(ofconn->schedulers[i], do_send_packet_in, ofconn);
- }
-
- rconn_run(ofconn->rconn);
-
- if (rconn_packet_counter_read (ofconn->reply_counter) < OFCONN_REPLY_MAX) {
- /* Limit the number of iterations to prevent other tasks from
- * starving. */
- for (iteration = 0; iteration < 50; iteration++) {
- struct ofpbuf *of_msg = rconn_recv(ofconn->rconn);
- if (!of_msg) {
- break;
- }
- if (p->fail_open) {
- fail_open_maybe_recover(p->fail_open);
- }
- handle_openflow(ofconn, p, of_msg);
- ofpbuf_delete(of_msg);
- }
- }