}
}
+void
+normalize_match(struct ofp_match *m)
+{
+ enum { OFPFW_NW = OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_NW_PROTO };
+ enum { OFPFW_TP = OFPFW_TP_SRC | OFPFW_TP_DST };
+ uint32_t wc;
+
+ wc = ntohl(m->wildcards) & OFPFW_ALL;
+ if (wc & OFPFW_DL_TYPE) {
+ m->dl_type = 0;
+
+ /* Can't sensibly m on network or transport headers if the
+ * data link type is unknown. */
+ wc |= OFPFW_NW | OFPFW_TP;
+ m->nw_src = m->nw_dst = m->nw_proto = 0;
+ m->tp_src = m->tp_dst = 0;
+ } else if (m->dl_type == htons(ETH_TYPE_IP)) {
+ if (wc & OFPFW_NW_PROTO) {
+ m->nw_proto = 0;
+
+ /* Can't sensibly m on transport headers if the network
+ * protocol is unknown. */
+ wc |= OFPFW_TP;
+ m->tp_src = m->tp_dst = 0;
+ } else if (m->nw_proto == IPPROTO_TCP ||
+ m->nw_proto == IPPROTO_UDP ||
+ m->nw_proto == IPPROTO_ICMP) {
+ if (wc & OFPFW_TP_SRC) {
+ m->tp_src = 0;
+ }
+ if (wc & OFPFW_TP_DST) {
+ m->tp_dst = 0;
+ }
+ } else {
+ /* Transport layer fields will always be extracted as zeros, so we
+ * can do an exact-m on those values. */
+ wc &= ~OFPFW_TP;
+ m->tp_src = m->tp_dst = 0;
+ }
+ if (wc & OFPFW_NW_SRC_MASK) {
+ m->nw_src &= flow_nw_bits_to_mask(wc, OFPFW_NW_SRC_SHIFT);
+ }
+ if (wc & OFPFW_NW_DST_MASK) {
+ m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT);
+ }
+ } else {
+ /* Network and transport layer fields will always be extracted as
+ * zeros, so we can do an exact-m on those values. */
+ wc &= ~(OFPFW_NW | OFPFW_TP);
+ m->nw_proto = m->nw_src = m->nw_dst = 0;
+ m->tp_src = m->tp_dst = 0;
+ }
+ if (wc & OFPFW_DL_SRC) {
+ memset(m->dl_src, 0, sizeof m->dl_src);
+ }
+ if (wc & OFPFW_DL_DST) {
+ memset(m->dl_dst, 0, sizeof m->dl_dst);
+ }
+ m->wildcards = htonl(wc);
+}
+
void
vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
uint32_t ip, const char *name, bool reconnectable)