-}
-
-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_oh(const struct ofconn *ofconn, const struct ofp_header *oh,
- int error)
-{
- struct ofpbuf *buf = make_ofp_error_msg(error, oh);
- if (buf) {
- COVERAGE_INC(ofproto_error);
- queue_tx(buf, ofconn, ofconn->reply_counter);
- }
-}
-
-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 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(ofconn->ofproto->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, &ofconn->ofproto->ports) {
- hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp));
- }
-
- queue_tx(buf, ofconn, ofconn->reply_counter);
- return 0;
-}
-
-static int
-handle_get_config_request(struct ofconn *ofconn, struct ofp_header *oh)
-{
- struct ofpbuf *buf;
- struct ofp_switch_config *osc;
- uint16_t flags;
- bool drop_frags;
-
- /* Figure out flags. */
- dpif_get_drop_frags(ofconn->ofproto->dpif, &drop_frags);
- flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL;
-
- /* Send reply. */
- osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
- osc->flags = htons(flags);
- osc->miss_send_len = htons(ofconn->miss_send_len);
- queue_tx(buf, ofconn, ofconn->reply_counter);