-
-static void
-process_phy_port(struct lswitch *sw, struct rconn *rconn OVS_UNUSED,
- void *opp_)
-{
- const struct ofp_phy_port *opp = opp_;
- uint16_t port_no = ntohs(opp->port_no);
- if (sw->capabilities & OFPC_STP && port_no < STP_MAX_PORTS) {
- uint32_t config = ntohl(opp->config);
- uint32_t state = ntohl(opp->state);
- unsigned int *port_state = &sw->port_states[port_no];
- unsigned int new_port_state;
-
- if (!(config & (OFPPC_NO_STP | OFPPC_PORT_DOWN))
- && !(state & OFPPS_LINK_DOWN))
- {
- switch (state & OFPPS_STP_MASK) {
- case OFPPS_STP_LISTEN:
- new_port_state = P_LISTENING;
- break;
- case OFPPS_STP_LEARN:
- new_port_state = P_LEARNING;
- break;
- case OFPPS_STP_FORWARD:
- new_port_state = P_FORWARDING;
- break;
- case OFPPS_STP_BLOCK:
- new_port_state = P_BLOCKING;
- break;
- default:
- new_port_state = P_DISABLED;
- break;
- }
- } else {
- new_port_state = P_FORWARDING;
- }
- if (*port_state != new_port_state) {
- *port_state = new_port_state;
- schedule_query(sw, 1000);
- }
- }
-}
-
-static unsigned int
-get_port_state(const struct lswitch *sw, uint16_t port_no)
-{
- return (port_no >= STP_MAX_PORTS || !(sw->capabilities & OFPC_STP)
- ? P_FORWARDING
- : sw->port_states[port_no]);
-}
-
-static bool
-may_learn(const struct lswitch *sw, uint16_t port_no)
-{
- return get_port_state(sw, port_no) & (P_LEARNING | P_FORWARDING);
-}
-
-static bool
-may_recv(const struct lswitch *sw, uint16_t port_no, bool any_actions)
-{
- unsigned int state = get_port_state(sw, port_no);
- return !(any_actions
- ? state & (P_DISABLED | P_LISTENING | P_BLOCKING)
- : state & (P_DISABLED | P_LISTENING | P_BLOCKING | P_LEARNING));
-}
-
-static bool
-may_send(const struct lswitch *sw, uint16_t port_no)
-{
- return get_port_state(sw, port_no) & P_FORWARDING;
-}
-
-static void
-process_flow_stats(struct lswitch *sw, struct rconn *rconn,
- const struct ofp_flow_stats *ofs)
-{
- const char *end = (char *) ofs + ntohs(ofs->length);
- bool delete = false;
-
- /* Decide to delete the flow if it matches on an STP-disabled physical
- * port. But don't delete it if the flow just drops all received packets,
- * because that's a perfectly reasonable thing to do for disabled physical
- * ports. */
- if (!(ofs->match.wildcards & htonl(OFPFW_IN_PORT))) {
- if (!may_recv(sw, ntohs(ofs->match.in_port),
- end > (char *) ofs->actions)) {
- delete = true;
- sw->n_no_recv++;
- }
- }
-
- /* Decide to delete the flow if it forwards to an STP-disabled physical
- * port. */
- if (!delete) {
- const struct ofp_action_header *a;
- size_t len;
-
- for (a = ofs->actions; (char *) a < end; a += len / 8) {
- len = ntohs(a->len);
- if (len > end - (char *) a) {
- VLOG_DBG_RL(&rl, "%016llx: action exceeds available space "
- "(%zu > %td)",
- sw->datapath_id, len, end - (char *) a);
- break;
- } else if (len % 8) {
- VLOG_DBG_RL(&rl, "%016llx: action length (%zu) not multiple "
- "of 8 bytes", sw->datapath_id, len);
- break;
- }
-
- if (a->type == htons(OFPAT_OUTPUT)) {
- struct ofp_action_output *oao = (struct ofp_action_output *) a;
- if (!may_send(sw, ntohs(oao->port))) {
- delete = true;
- sw->n_no_send++;
- break;
- }
- }
- }
- }
-
- /* Delete the flow. */
- if (delete) {
- struct ofp_flow_mod *ofm;
- struct ofpbuf *b;
-
- ofm = make_openflow(offsetof(struct ofp_flow_mod, actions),
- OFPT_FLOW_MOD, &b);
- ofm->match = ofs->match;
- ofm->command = OFPFC_DELETE_STRICT;
- rconn_send(rconn, b, NULL);
- }
-}
-
-static void
-process_stats_reply(struct lswitch *sw, struct rconn *rconn, void *osr_)
-{
- struct ofp_stats_reply *osr = osr_;
- struct flow_stats_iterator i;
- const struct ofp_flow_stats *fs;
-
- if (sw->last_query == LLONG_MIN
- || osr->type != htons(OFPST_FLOW)
- || osr->header.xid != sw->query_xid) {
- return;
- }
- for (fs = flow_stats_first(&i, osr); fs; fs = flow_stats_next(&i)) {
- sw->n_flows++;
- process_flow_stats(sw, rconn, fs);
- }
- if (!(osr->flags & htons(OFPSF_REPLY_MORE))) {
- VLOG_DBG("%016llx: Deleted %d of %d received flows to "
- "implement STP, %d because of no-recv, %d because of "
- "no-send", sw->datapath_id,
- sw->n_no_recv + sw->n_no_send, sw->n_flows,
- sw->n_no_recv, sw->n_no_send);
- sw->last_query = LLONG_MIN;
- sw->last_reply = LLONG_MIN;
- } else {
- sw->last_reply = time_msec();
- }
-}
-