-static bool
-is_controller_rule(struct rule *rule)
-{
- /* If the only action is send to the controller then don't report
- * NetFlow expiration messages since it is just part of the control
- * logic for the network and not real traffic. */
-
- return (rule
- && rule->super
- && rule->super->n_actions == 1
- && action_outputs_to_port(&rule->super->actions[0],
- htons(OFPP_CONTROLLER)));
-}
-
-static void
-rule_post_uninstall(struct ofproto *ofproto, struct rule *rule)
-{
- struct rule *super = rule->super;
-
- rule_account(ofproto, rule, 0);
-
- if (ofproto->netflow && !is_controller_rule(rule)) {
- struct ofexpired expired;
- expired.flow = rule->cr.flow;
- expired.packet_count = rule->packet_count;
- expired.byte_count = rule->byte_count;
- expired.used = rule->used;
- netflow_expire(ofproto->netflow, &rule->nf_flow, &expired);
- }
- if (super) {
- super->packet_count += rule->packet_count;
- super->byte_count += rule->byte_count;
-
- /* Reset counters to prevent double counting if the rule ever gets
- * reinstalled. */
- rule->packet_count = 0;
- rule->byte_count = 0;
- rule->accounted_bytes = 0;
-
- netflow_flow_clear(&rule->nf_flow);
- }
-}
-\f
-static void
-queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn,
- struct rconn_packet_counter *counter)
-{
- update_openflow_length(msg);
- if (rconn_send(ofconn->rconn, msg, counter)) {
- ofpbuf_delete(msg);
- }
-}
-
-static void
-send_error(const struct ofconn *ofconn, const struct ofp_header *oh,
- int error, const void *data, size_t len)
-{
- struct ofpbuf *buf;
- struct ofp_error_msg *oem;
-
- if (!(error >> 16)) {
- VLOG_WARN_RL(&rl, "not sending bad error code %d to controller",
- error);
- return;
- }
-
- COVERAGE_INC(ofproto_error);
- oem = make_openflow_xid(len + sizeof *oem, OFPT_ERROR,
- oh ? oh->xid : 0, &buf);
- oem->type = htons((unsigned int) error >> 16);
- oem->code = htons(error & 0xffff);
- memcpy(oem->data, data, len);
- queue_tx(buf, ofconn, ofconn->reply_counter);
-}
-
-static void
-send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh,
- int error)
-{
- size_t oh_length = ntohs(oh->length);
- send_error(ofconn, oh, error, oh, MIN(oh_length, 64));
-}
-
-static void
-hton_ofp_phy_port(struct ofp_phy_port *opp)
-{
- opp->port_no = htons(opp->port_no);
- opp->config = htonl(opp->config);
- opp->state = htonl(opp->state);
- opp->curr = htonl(opp->curr);
- opp->advertised = htonl(opp->advertised);
- opp->supported = htonl(opp->supported);
- opp->peer = htonl(opp->peer);
-}
-
-static int
-handle_echo_request(struct ofconn *ofconn, struct ofp_header *oh)
-{
- struct ofp_header *rq = oh;
- queue_tx(make_echo_reply(rq), ofconn, ofconn->reply_counter);
- return 0;
-}
-
-static int
-handle_features_request(struct ofproto *p, struct ofconn *ofconn,
- struct ofp_header *oh)
-{
- struct ofp_switch_features *osf;
- struct ofpbuf *buf;
- struct ofport *port;
-
- osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, oh->xid, &buf);
- osf->datapath_id = htonll(p->datapath_id);
- osf->n_buffers = htonl(pktbuf_capacity());
- osf->n_tables = 2;
- osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS |
- OFPC_PORT_STATS | OFPC_ARP_MATCH_IP);
- osf->actions = htonl((1u << OFPAT_OUTPUT) |
- (1u << OFPAT_SET_VLAN_VID) |
- (1u << OFPAT_SET_VLAN_PCP) |
- (1u << OFPAT_STRIP_VLAN) |
- (1u << OFPAT_SET_DL_SRC) |
- (1u << OFPAT_SET_DL_DST) |
- (1u << OFPAT_SET_NW_SRC) |
- (1u << OFPAT_SET_NW_DST) |
- (1u << OFPAT_SET_NW_TOS) |
- (1u << OFPAT_SET_TP_SRC) |
- (1u << OFPAT_SET_TP_DST) |
- (1u << OFPAT_ENQUEUE));
-
- HMAP_FOR_EACH (port, hmap_node, &p->ports) {
- hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp));
- }
-
- queue_tx(buf, ofconn, ofconn->reply_counter);