add implementation of OFMatchV1 match, normalization
diff --git a/java_gen/templates/_imports.java b/java_gen/templates/_imports.java
index 2d93b22..7fd0719 100644
--- a/java_gen/templates/_imports.java
+++ b/java_gen/templates/_imports.java
@@ -17,3 +17,4 @@
 import org.jboss.netty.buffer.ChannelBuffers;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.Builder.java b/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
index 6570df8..769a687 100644
--- a/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
+++ b/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
@@ -1,71 +1,459 @@
+        @SuppressWarnings("unchecked")
+        @Override
+        public <F extends OFValueType<F>> F get(MatchField<F> field)
+                throws UnsupportedOperationException {
+            if (isFullyWildcarded(field))
+                return null;
 
-    @Override
-    public <F extends OFValueType<F>> F get(MatchField<F> field)
-            throws UnsupportedOperationException {
-        // FIXME yotam - please replace with real implementation
-        return null;
-    }
+            Object result;
+            switch (field.id) {
+                case IN_PORT:
+                    result = inPort;
+                    break;
+                case ETH_DST:
+                    result = ethDst;
+                    break;
+                case ETH_SRC:
+                    result = ethSrc;
+                    break;
+                case ETH_TYPE:
+                    result = ethType;
+                    break;
+                case VLAN_VID:
+                    result = vlanVid;
+                    break;
+                case VLAN_PCP:
+                    result = vlanPcp;
+                    break;
+                case IP_DSCP:
+                    result = ipDscp;
+                    break;
+                case IP_PROTO:
+                    result = ipProto;
+                    break;
+                case IPV4_SRC:
+                    result = ipv4Dst;
+                    break;
+                case IPV4_DST:
+                    result = ipv4Dst;
+                    break;
+                case TCP_SRC:
+                    result = ipv4Src;
+                    break;
+                case TCP_DST:
+                    result = tcpDst;
+                    break;
+                case UDP_SRC:
+                    result = tcpSrc;
+                    break;
+                case UDP_DST:
+                    result = tcpDst;
+                    break;
+                case SCTP_SRC:
+                    result = tcpSrc;
+                    break;
+                case SCTP_DST:
+                    result = tcpDst;
+                    break;
+                case ICMPV4_TYPE:
+                    result = tcpSrc;
+                    break;
+                case ICMPV4_CODE:
+                    result = tcpDst;
+                    break;
+                // NOT SUPPORTED:
+                default:
+                    throw new UnsupportedOperationException("OFMatch does not support matching on field " + field.getName());
+            }
+            return (F)result;
+        }
 
-    @Override
-    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
-            throws UnsupportedOperationException {
-        // FIXME yotam - please replace with real implementation
-        return null;
-    }
+        @SuppressWarnings("unchecked")
+        @Override
+        public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+                throws UnsupportedOperationException {
+            if (!isPartiallyMasked(field))
+                return null;
+            Object result;
+            switch (field.id) {
+                case IPV4_SRC:
+                    int srcBitMask = (-1) << (32 - getIpv4SrcCidrMaskLen());
+                    result = IPv4AddressWithMask.of(ipv4Src, IPv4Address.of(srcBitMask));
+                    break;
+                case IPV4_DST:
+                    int dstMaskedBits = Math.min(32, (wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT);
+                    int dstBitMask = (-1) << (32 - getIpv4DstCidrMaskLen());
 
-    @Override
-    public boolean supports(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
-    }
+                    result = IPv4AddressWithMask.of(ipv4Dst, IPv4Address.of(dstBitMask));
+                    break;
+                default:
+                    throw new UnsupportedOperationException("OFMatch does not support masked matching on field " + field.getName());
+            }
+            return (Masked<F>)result;
+        }
 
-    @Override
-    public boolean supportsMasked(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
-    }
+        @Override
+        public boolean supports(MatchField<?> field) {
+            switch (field.id) {
+                case IN_PORT:
+                case ETH_DST:
+                case ETH_SRC:
+                case ETH_TYPE:
+                case VLAN_VID:
+                case VLAN_PCP:
+                case IP_DSCP:
+                case IP_PROTO:
+                case IPV4_SRC:
+                case IPV4_DST:
+                case TCP_SRC:
+                case TCP_DST:
+                case UDP_SRC:
+                case UDP_DST:
+                case SCTP_SRC:
+                case SCTP_DST:
+                case ICMPV4_TYPE:
+                case ICMPV4_CODE:
+                    return true;
+                default:
+                    return false;
+            }
+        }
 
-    @Override
-    public boolean isExact(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
-    }
+        @Override
+        public boolean supportsMasked(MatchField<?> field) {
+            switch (field.id) {
+                case IPV4_SRC:
+                case IPV4_DST:
+                    return true;
+                default:
+                    return false;
+            }
+        }
 
-    @Override
-    public boolean isFullyWildcarded(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
-    }
+        @Override
+        public boolean isExact(MatchField<?> field) {
+            switch (field.id) {
+                case IN_PORT:
+                    return (this.wildcards & OFPFW_IN_PORT) == 0;
+                case ETH_DST:
+                    return (this.wildcards & OFPFW_DL_DST) == 0;
+                case ETH_SRC:
+                    return (this.wildcards & OFPFW_DL_SRC) == 0;
+                case ETH_TYPE:
+                    return (this.wildcards & OFPFW_DL_TYPE) == 0;
+                case VLAN_VID:
+                    return (this.wildcards & OFPFW_DL_VLAN) == 0;
+                case VLAN_PCP:
+                    return (this.wildcards & OFPFW_DL_VLAN_PCP) == 0;
+                case IP_DSCP:
+                    return (this.wildcards & OFPFW_NW_TOS) == 0;
+                case IP_PROTO:
+                    return (this.wildcards & OFPFW_NW_PROTO) == 0;
+                case IPV4_SRC:
+                    return this.getIpv4SrcCidrMaskLen() >= 32;
+                case IPV4_DST:
+                    return this.getIpv4DstCidrMaskLen() >= 32;
+                case TCP_SRC:
+                    return (this.wildcards & OFPFW_TP_SRC) == 0;
+                case TCP_DST:
+                    return (this.wildcards & OFPFW_TP_DST) == 0;
+                case UDP_SRC:
+                    return (this.wildcards & OFPFW_TP_SRC) == 0;
+                case UDP_DST:
+                    return (this.wildcards & OFPFW_TP_DST) == 0;
+                case SCTP_SRC:
+                    return (this.wildcards & OFPFW_TP_SRC) == 0;
+                case SCTP_DST:
+                    return (this.wildcards & OFPFW_TP_DST) == 0;
+                case ICMPV4_TYPE:
+                    return (this.wildcards & OFPFW_TP_SRC) == 0;
+                case ICMPV4_CODE:
+                    return (this.wildcards & OFPFW_TP_DST) == 0;
+                default:
+                    throw new UnsupportedOperationException("OFMatch does not support matching on field " + field.getName());
+            }
+        }
 
-    @Override
-    public boolean isPartiallyMasked(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
-    }
+        /**
+         * Parse this match's wildcard fields and return the number of significant
+         * bits in the IP destination field. NOTE: this returns the number of bits
+         * that are fixed, i.e., like CIDR, not the number of bits that are free
+         * like OpenFlow encodes.
+         *
+         * @return A number between 0 (matches all IPs) and 32 (exact match)
+         */
+        public int getIpv4DstCidrMaskLen() {
+            return Math.max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT),
+                            0);
+        }
 
-    @Override
-    public <F extends OFValueType<F>> Match.Builder setExact(
-            MatchField<F> field, F value) {
-        // FIXME yotam - please replace with real implementation
-        return null;
-    }
+        /**
+         * Parse this match's wildcard fields and return the number of significant
+         * bits in the IP destination field. NOTE: this returns the number of bits
+         * that are fixed, i.e., like CIDR, not the number of bits that are free
+         * like OpenFlow encodes.
+         *
+         * @return A number between 0 (matches all IPs) and 32 (exact match)
+         */
+        public int getIpv4SrcCidrMaskLen() {
+            return Math.max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT),
+                            0);
+        }
 
-    @Override
-    public <F extends OFValueType<F>> Match.Builder setMasked(
-            MatchField<F> field, F value, F mask) {
-        // FIXME yotam - please replace with real implementation
-        return null;
-    }
 
-    @Override
-    public <F extends OFValueType<F>> Match.Builder setMasked(
-            MatchField<F> field, Masked<F> valueWithMask) {
-        // FIXME yotam - please replace with real implementation
-        return null;
-    }
+        @Override
+        public boolean isFullyWildcarded(MatchField<?> field) {
+            switch (field.id) {
+                case IN_PORT:
+                    return (this.wildcards & OFPFW_IN_PORT) != 0;
+                case ETH_DST:
+                    return (this.wildcards & OFPFW_DL_DST) != 0;
+                case ETH_SRC:
+                    return (this.wildcards & OFPFW_DL_SRC) != 0;
+                case ETH_TYPE:
+                    return (this.wildcards & OFPFW_DL_TYPE) != 0;
+                case VLAN_VID:
+                    return (this.wildcards & OFPFW_DL_VLAN) != 0;
+                case VLAN_PCP:
+                    return (this.wildcards & OFPFW_DL_VLAN_PCP) != 0;
+                case IP_DSCP:
+                    return (this.wildcards & OFPFW_NW_TOS) != 0;
+                case IP_PROTO:
+                    return (this.wildcards & OFPFW_NW_PROTO) != 0;
+                case TCP_SRC:
+                    return (this.wildcards & OFPFW_TP_SRC) != 0;
+                case TCP_DST:
+                    return (this.wildcards & OFPFW_TP_DST) != 0;
+                case UDP_SRC:
+                    return (this.wildcards & OFPFW_TP_SRC) != 0;
+                case UDP_DST:
+                    return (this.wildcards & OFPFW_TP_DST) != 0;
+                case SCTP_SRC:
+                    return (this.wildcards & OFPFW_TP_SRC) != 0;
+                case SCTP_DST:
+                    return (this.wildcards & OFPFW_TP_DST) != 0;
+                case ICMPV4_TYPE:
+                    return (this.wildcards & OFPFW_TP_SRC) != 0;
+                case ICMPV4_CODE:
+                    return (this.wildcards & OFPFW_TP_DST) != 0;
+                case IPV4_SRC:
+                    return this.getIpv4SrcCidrMaskLen() <= 0;
+                case IPV4_DST:
+                    return this.getIpv4DstCidrMaskLen() <= 0;
+                default:
+                    throw new UnsupportedOperationException("OFMatch does not support matching on field " + field.getName());
+            }
+        }
 
-    @Override
-    public <F extends OFValueType<F>> Match.Builder wildcard(MatchField<F> field) {
-        // FIXME yotam - please replace with real implementation
-        return null;
-    }
+        @Override
+        public boolean isPartiallyMasked(MatchField<?> field) {
+            switch (field.id) {
+                case IPV4_SRC:
+                    int srcCidrLen = getIpv4SrcCidrMaskLen();
+                    return srcCidrLen > 0 && srcCidrLen < 32;
+                case IPV4_DST:
+                    int dstCidrLen = getIpv4SrcCidrMaskLen();
+                    return dstCidrLen > 0 && dstCidrLen < 32;
+                default:
+                    throw new UnsupportedOperationException("OFMatch does not support masked matching on field " + field.getName());
+            }
+        }
+
+        private final void initWildcards() {
+            if(!wildcardsSet) {
+            //:: if has_parent:
+                wildcards = parentMessage.wildcards;
+            //:: else:
+                wildcards = OFPFW_ALL;
+            //:: #endif
+                wildcardsSet = true;
+            }
+        }
+
+        @Override
+        public <F extends OFValueType<F>> Match.Builder setExact(MatchField<F> field,
+                F value) {
+            initWildcards();
+            Object val = value;
+            switch (field.id) {
+                case ETH_DST:
+                    setEthDst((MacAddress) value);
+                    wildcards &= ~OFPFW_DL_DST;
+                    break;
+                case ETH_SRC:
+                    setEthSrc((MacAddress) value);
+                    wildcards &= ~OFPFW_DL_SRC;
+                    break;
+                case ETH_TYPE:
+                    setEthType((EthType) value);
+                    wildcards &= ~OFPFW_DL_TYPE;
+                    break;
+                case ICMPV4_CODE:
+                    setTcpDst((TransportPort) value);
+                    wildcards &= ~OFPFW_TP_DST;
+                    break;
+                case ICMPV4_TYPE:
+                    setTcpSrc((TransportPort) value);
+                    wildcards &= ~OFPFW_TP_SRC;
+                    break;
+                case IN_PORT:
+                    setInPort((OFPort) value);
+                    wildcards &= ~OFPFW_IN_PORT;
+                    break;
+                case IPV4_DST:
+                    setIpv4Dst((IPv4Address) value);
+                    wildcards &= ~OFPFW_NW_DST_MASK;
+                    break;
+                case IPV4_SRC:
+                    setIpv4Src((IPv4Address) value);
+                    wildcards &= ~OFPFW_NW_SRC_MASK;
+                    break;
+                case IP_DSCP:
+                    setIpDscp((IpDscp) value);
+                    wildcards &= ~OFPFW_NW_TOS;
+                    break;
+                case IP_PROTO:
+                    setIpProto((IpProtocol) value);
+                    wildcards &= ~OFPFW_NW_PROTO;
+                    break;
+                case SCTP_DST:
+                    setTcpDst((TransportPort) value);
+                    wildcards &= ~OFPFW_TP_DST;
+                    break;
+                case SCTP_SRC:
+                    setTcpSrc((TransportPort) value);
+                    wildcards &= ~OFPFW_TP_SRC;
+                    break;
+                case TCP_DST:
+                    setTcpDst((TransportPort) value);
+                    wildcards &= ~OFPFW_TP_DST;
+                    break;
+                case TCP_SRC:
+                    setTcpSrc((TransportPort) value);
+                    wildcards &= ~OFPFW_TP_SRC;
+                    break;
+                case UDP_DST:
+                    setTcpDst((TransportPort) value);
+                    wildcards &= ~OFPFW_TP_DST;
+                    break;
+                case UDP_SRC:
+                    setTcpSrc((TransportPort) value);
+                    wildcards &= ~OFPFW_TP_SRC;
+                    break;
+                case VLAN_PCP:
+                    setVlanPcp((VlanPcp) value);
+                    wildcards &= ~OFPFW_DL_VLAN_PCP;
+                    break;
+                case VLAN_VID:
+                    setVlanVid((VlanVid) value);
+                    wildcards &= ~OFPFW_DL_VLAN;
+                default:
+                    throw new UnsupportedOperationException(
+                            "OFMatch does not support matching on field " + field.getName());
+            }
+            return this;
+        }
+
+        @Override
+        public <F extends OFValueType<F>> Match.Builder setMasked(MatchField<F> field,
+                F value, F mask) {
+            initWildcards();
+            switch (field.id) {
+                case IPV4_DST:
+                case IPV4_SRC:
+                    Object valObj = value;
+                    Object masObj = mask;
+                    IPv4Address ip = ((IPv4Address)valObj);
+                    int maskval = ((IPv4Address)masObj).getInt();
+                    if (Integer.bitCount(~maskval + 1) != 1)
+                        throw new UnsupportedOperationException("OFMatch only supports CIDR masks for IPv4");
+                    int maskLen = 32 - Integer.bitCount(maskval);
+                    switch(field.id) {
+                        case IPV4_DST:
+                            setIpv4Dst(ip);
+                            wildcards = (wildcards &~OFPFW_NW_DST_MASK) | (maskLen << OFPFW_NW_DST_SHIFT);
+                            break;
+                        case IPV4_SRC:
+                            setIpv4Src(ip);
+                            wildcards = (wildcards &~OFPFW_NW_SRC_MASK) | (maskLen << OFPFW_NW_SRC_SHIFT);
+                            break;
+                        default:
+                            // Cannot really get here
+                            break;
+                    }
+                    break;
+                default:
+                    throw new UnsupportedOperationException("OFMatch does not support masked matching on field " + field.getName());
+            }
+            return this;
+        }
+
+        @Override
+        public <F extends OFValueType<F>> Match.Builder setMasked(MatchField<F> field, Masked<F> valueWithMask)
+                                                                       throws UnsupportedOperationException {
+            return this.setMasked(field, valueWithMask.getValue(), valueWithMask.getMask());
+        }
+
+        @Override
+        public <F extends OFValueType<F>> Match.Builder wildcard(MatchField<F> field) {
+            initWildcards();
+            switch (field.id) {
+                case ETH_DST:
+                    setEthDst(MacAddress.NONE);
+                    wildcards |= OFPFW_DL_DST;
+                    break;
+                case ETH_SRC:
+                    setEthSrc(MacAddress.NONE);
+                    wildcards |= OFPFW_DL_SRC;
+                    break;
+                case ETH_TYPE:
+                    setEthType(EthType.NONE);
+                    wildcards |= OFPFW_DL_TYPE;
+                    break;
+                case ICMPV4_CODE:
+                case TCP_DST:
+                case UDP_DST:
+                case SCTP_DST:
+                    setTcpDst(TransportPort.NONE);
+                    wildcards |= OFPFW_TP_DST;
+                    break;
+                case ICMPV4_TYPE:
+                case TCP_SRC:
+                case UDP_SRC:
+                case SCTP_SRC:
+                    setTcpSrc(TransportPort.NONE);
+                    wildcards |= OFPFW_TP_SRC;
+                    break;
+                case IN_PORT:
+                    setInPort(OFPort.NONE);
+                    wildcards |= OFPFW_IN_PORT;
+                    break;
+                case IPV4_DST:
+                    setIpv4Dst(IPv4Address.NONE);
+                    wildcards |= OFPFW_NW_DST_MASK;
+                    break;
+                case IPV4_SRC:
+                    setIpv4Src(IPv4Address.NONE);
+                    wildcards |= OFPFW_NW_SRC_MASK;
+                    break;
+                case IP_DSCP:
+                    setIpDscp(IpDscp.NONE);
+                    wildcards |= OFPFW_NW_TOS;
+                    break;
+                case IP_PROTO:
+                    setIpProto(IpProtocol.NONE);
+                    wildcards |= OFPFW_NW_PROTO;
+                    break;
+                case VLAN_PCP:
+                    setVlanPcp(VlanPcp.NONE);
+                    wildcards |= OFPFW_DL_VLAN_PCP;
+                    break;
+                case VLAN_VID:
+                    setVlanVid(VlanVid.NONE);
+                    wildcards |= OFPFW_DL_VLAN;
+                    break;
+                default:
+                    throw new UnsupportedOperationException("OFMatch does not support matching on field " + field.getName());
+            }
+            return this;
+        }
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.Builder_normalize_clear_wildcards_stanza.java b/java_gen/templates/custom/OFMatchV1Ver10.Builder_normalize_clear_wildcards_stanza.java
new file mode 100644
index 0000000..56b5662
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV1Ver10.Builder_normalize_clear_wildcards_stanza.java
@@ -0,0 +1,53 @@
+            // normalize wildcard fields to mimic old OpenVSwitch behavior. When prerequisites for a field were not met
+            // e.g., eth_type is not set to 0x800, old OVS would set the value of the corresponding ignored fields (e.g.,
+            // ip_src, tcp_dst) to 0, AND ALSO SET THE WILDCARD to 0. It doesn't do that any more as of 1.1.2 and 1.4
+            if(ethType.equals(EthType.IPv4)) {
+                // IP
+                if(ipProto.equals(IpProtocol.IP_PROTO_TCP) || ipProto.equals(IpProtocol.IP_PROTO_UDP) || ipProto.equals(IpProtocol.IP_PROTO_ICMP)) {
+                    // fully speced, wildcards and all values are fine
+                    // normalize 32-63 ipv4 src 'mask' to a full bitmask
+                    if((wildcards & OFPFW_NW_SRC_ALL) != 0)
+                        wildcards |= OFPFW_NW_SRC_MASK;
+
+                    // normalize 32-63 ipv4 dst 'mask' to a full bitmask
+                    if((wildcards & OFPFW_NW_DST_ALL) != 0)
+                        wildcards |= OFPFW_NW_DST_MASK;
+
+                } else {
+                    // normalize 32-63 ipv4 src 'mask' to a full bitmask
+                    if((wildcards & OFPFW_NW_SRC_ALL) != 0)
+                        wildcards |= OFPFW_NW_SRC_MASK;
+
+                    // normalize 32-63 ipv4 dst 'mask' to a full bitmask
+                    if((wildcards & OFPFW_NW_DST_ALL) != 0)
+                        wildcards |= OFPFW_NW_DST_MASK;
+
+                    // not TCP/UDP/ICMP -> Clear TP wildcards for the wire
+                    wildcards &= ~(OFPFW_TP_SRC | OFPFW_TP_DST);
+                    tcpSrc = TransportPort.NONE;
+                    tcpDst = TransportPort.NONE;
+                }
+            } else if (ethType.equals(EthType.ARP)) {
+                // normalize 32-63 ipv4 src 'mask' to a full bitmask
+                if((wildcards & OFPFW_NW_SRC_ALL) != 0)
+                    wildcards |= OFPFW_NW_SRC_MASK;
+
+                // normalize 32-63 ipv4 dst 'mask' to a full bitmask
+                if((wildcards & OFPFW_NW_DST_ALL) != 0)
+                    wildcards |= OFPFW_NW_DST_MASK;
+
+                // ARP: clear NW_TOS / TP wildcards for the wire
+                wildcards &= ~( OFPFW_NW_TOS | OFPFW_TP_SRC | OFPFW_TP_DST);
+                ipDscp = IpDscp.NONE;
+                tcpSrc = TransportPort.NONE;
+                tcpDst = TransportPort.NONE;
+            } else {
+                // not even IP. Clear NW/TP wildcards for the wire
+                wildcards &= ~( OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_TP_SRC | OFPFW_TP_DST);
+                ipDscp = IpDscp.NONE;
+                ipProto = IpProtocol.NONE;
+                ipv4Src = IPv4Address.NONE;
+                ipv4Dst = IPv4Address.NONE;
+                tcpSrc = TransportPort.NONE;
+                tcpDst = TransportPort.NONE;
+            }
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.Builder_normalize_set_wildcards_stanza.java b/java_gen/templates/custom/OFMatchV1Ver10.Builder_normalize_set_wildcards_stanza.java
new file mode 100644
index 0000000..3545f55
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV1Ver10.Builder_normalize_set_wildcards_stanza.java
@@ -0,0 +1,53 @@
+            // normalize match fields according to current OpenVSwitch behavior. When prerequisites for a field are not met
+            // e.g., eth_type is not set to 0x800, OVS sets the value of corresponding ignored fields (e.g.,
+            // ip_src, tcp_dst) to 0, and sets the wildcard bit to 1.
+            if(ethType.equals(EthType.IPv4)) {
+                // IP
+                if(ipProto.equals(IpProtocol.IP_PROTO_TCP) || ipProto.equals(IpProtocol.IP_PROTO_UDP) || ipProto.equals(IpProtocol.IP_PROTO_ICMP)) {
+                    // fully speced, wildcards and all values are fine
+                    // normalize 32-63 ipv4 src 'mask' to a full bitmask
+                    if((wildcards & OFPFW_NW_SRC_ALL) != 0)
+                        wildcards |= OFPFW_NW_SRC_MASK;
+
+                    // normalize 32-63 ipv4 dst 'mask' to a full bitmask
+                    if((wildcards & OFPFW_NW_DST_ALL) != 0)
+                        wildcards |= OFPFW_NW_DST_MASK;
+
+                } else {
+                    // normalize 32-63 ipv4 src 'mask' to a full bitmask
+                    if((wildcards & OFPFW_NW_SRC_ALL) != 0)
+                        wildcards |= OFPFW_NW_SRC_MASK;
+
+                    // normalize 32-63 ipv4 dst 'mask' to a full bitmask
+                    if((wildcards & OFPFW_NW_DST_ALL) != 0)
+                        wildcards |= OFPFW_NW_DST_MASK;
+
+                    // not TCP/UDP/ICMP -> Clear TP wildcards for the wire
+                    wildcards |= (OFPFW_TP_SRC | OFPFW_TP_DST);
+                    tcpSrc = TransportPort.NONE;
+                    tcpDst = TransportPort.NONE;
+                }
+            } else if (ethType.equals(EthType.ARP)) {
+                // normalize 32-63 ipv4 src 'mask' to a full bitmask
+                if((wildcards & OFPFW_NW_SRC_ALL) != 0)
+                    wildcards |= OFPFW_NW_SRC_MASK;
+
+                // normalize 32-63 ipv4 dst 'mask' to a full bitmask
+                if((wildcards & OFPFW_NW_DST_ALL) != 0)
+                    wildcards |= OFPFW_NW_DST_MASK;
+
+                // ARP: clear NW_TOS / TP wildcards for the wire
+                wildcards |= ( OFPFW_NW_TOS | OFPFW_TP_SRC | OFPFW_TP_DST);
+                ipDscp = IpDscp.NONE;
+                tcpSrc = TransportPort.NONE;
+                tcpDst = TransportPort.NONE;
+            } else {
+                // not even IP. Clear NW/TP wildcards for the wire
+                wildcards |= ( OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_TP_SRC | OFPFW_TP_DST);
+                ipDscp = IpDscp.NONE;
+                ipProto = IpProtocol.NONE;
+                ipv4Src = IPv4Address.NONE;
+                ipv4Dst = IPv4Address.NONE;
+                tcpSrc = TransportPort.NONE;
+                tcpDst = TransportPort.NONE;
+            }
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.Builder_normalize_stanza.java b/java_gen/templates/custom/OFMatchV1Ver10.Builder_normalize_stanza.java
new file mode 100644
index 0000000..3050563
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV1Ver10.Builder_normalize_stanza.java
@@ -0,0 +1 @@
+//:: include("custom/%s.Builder_normalize_set_wildcards_stanza.java" % msg.name, msg=msg, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.Reader_normalize_stanza.java b/java_gen/templates/custom/OFMatchV1Ver10.Reader_normalize_stanza.java
new file mode 100644
index 0000000..1de18df
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV1Ver10.Reader_normalize_stanza.java
@@ -0,0 +1 @@
+//:: include("custom/%s.Builder_normalize_stanza.java" % msg.name, msg=msg, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.java b/java_gen/templates/custom/OFMatchV1Ver10.java
index ec7bfcc..7b1f110 100644
--- a/java_gen/templates/custom/OFMatchV1Ver10.java
+++ b/java_gen/templates/custom/OFMatchV1Ver10.java
@@ -1,44 +1,307 @@
+    final public static int OFPFW_ALL = ((1 << 22) - 1);
 
+    final public static int OFPFW_IN_PORT = 1 << 0; /* Switch input port. */
+    final public static int OFPFW_DL_VLAN = 1 << 1; /* VLAN id. */
+    final public static int OFPFW_DL_SRC = 1 << 2; /* Ethernet source address. */
+    final public static int OFPFW_DL_DST = 1 << 3; /*
+                                                    * Ethernet destination
+                                                    * address.
+                                                    */
+    final public static int OFPFW_DL_TYPE = 1 << 4; /* Ethernet frame type. */
+    final public static int OFPFW_NW_PROTO = 1 << 5; /* IP protocol. */
+    final public static int OFPFW_TP_SRC = 1 << 6; /* TCP/UDP source port. */
+    final public static int OFPFW_TP_DST = 1 << 7; /* TCP/UDP destination port. */
+
+    /*
+     * IP source address wildcard bit count. 0 is exact match, 1 ignores the
+     * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
+     * the entire field. This is the *opposite* of the usual convention where
+     * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded.
+     */
+    final public static int OFPFW_NW_SRC_SHIFT = 8;
+    final public static int OFPFW_NW_SRC_BITS = 6;
+    final public static int OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT;
+    final public static int OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT;
+
+    /* IP destination address wildcard bit count. Same format as source. */
+    final public static int OFPFW_NW_DST_SHIFT = 14;
+    final public static int OFPFW_NW_DST_BITS = 6;
+    final public static int OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT;
+    final public static int OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT;
+
+    final public static int OFPFW_DL_VLAN_PCP = 1 << 20; /* VLAN priority. */
+    final public static int OFPFW_NW_TOS = 1 << 21; /* IP ToS (DSCP field, 6bits) */
+
+    @SuppressWarnings("unchecked")
     @Override
     public <F extends OFValueType<F>> F get(MatchField<F> field)
             throws UnsupportedOperationException {
-        // FIXME yotam - please replace with real implementation
-        return null;
+        if (isFullyWildcarded(field))
+            return null;
+        if (!field.arePrerequisitesOK(this))
+            return null;
+
+        Object result;
+        switch (field.id) {
+            case IN_PORT:
+                result = inPort;
+                break;
+            case ETH_DST:
+                result = ethDst;
+                break;
+            case ETH_SRC:
+                result = ethSrc;
+                break;
+            case ETH_TYPE:
+                result = ethType;
+                break;
+            case VLAN_VID:
+                result = vlanVid;
+                break;
+            case VLAN_PCP:
+                result = vlanPcp;
+                break;
+            case IP_DSCP:
+                result = ipDscp;
+                break;
+            case IP_PROTO:
+                result = ipProto;
+                break;
+            case IPV4_SRC:
+                result = ipv4Dst;
+                break;
+            case IPV4_DST:
+                result = ipv4Dst;
+                break;
+            case TCP_SRC:
+                result = ipv4Src;
+                break;
+            case TCP_DST:
+                result = tcpDst;
+                break;
+            case UDP_SRC:
+                result = tcpSrc;
+                break;
+            case UDP_DST:
+                result = tcpDst;
+                break;
+            case SCTP_SRC:
+                result = tcpSrc;
+                break;
+            case SCTP_DST:
+                result = tcpDst;
+                break;
+            case ICMPV4_TYPE:
+                result = tcpSrc;
+                break;
+            case ICMPV4_CODE:
+                result = tcpDst;
+                break;
+            // NOT SUPPORTED:
+            default:
+                throw new UnsupportedOperationException("OFMatch does not support matching on field " + field.getName());
+        }
+        return (F)result;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
             throws UnsupportedOperationException {
-        // FIXME yotam - please replace with real implementation
-        return null;
+        if (!isPartiallyMasked(field))
+            return null;
+        if (!field.arePrerequisitesOK(this))
+            return null;
+        Object result;
+        switch (field.id) {
+            case IPV4_SRC:
+                int srcBitMask = (-1) << (32 - getIpv4SrcCidrMaskLen());
+                result = IPv4AddressWithMask.of(ipv4Src, IPv4Address.of(srcBitMask));
+                break;
+            case IPV4_DST:
+                int dstMaskedBits = Math.min(32, (wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT);
+                int dstBitMask = (-1) << (32 - getIpv4DstCidrMaskLen());
+
+                result = IPv4AddressWithMask.of(ipv4Dst, IPv4Address.of(dstBitMask));
+                break;
+            default:
+                throw new UnsupportedOperationException("OFMatch does not support masked matching on field " + field.getName());
+        }
+        return (Masked<F>)result;
     }
 
     @Override
     public boolean supports(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
+        switch (field.id) {
+            case IN_PORT:
+            case ETH_DST:
+            case ETH_SRC:
+            case ETH_TYPE:
+            case VLAN_VID:
+            case VLAN_PCP:
+            case IP_DSCP:
+            case IP_PROTO:
+            case IPV4_SRC:
+            case IPV4_DST:
+            case TCP_SRC:
+            case TCP_DST:
+            case UDP_SRC:
+            case UDP_DST:
+            case SCTP_SRC:
+            case SCTP_DST:
+            case ICMPV4_TYPE:
+            case ICMPV4_CODE:
+                return true;
+            default:
+                return false;
+        }
     }
 
     @Override
     public boolean supportsMasked(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
+        switch (field.id) {
+            case IPV4_SRC:
+            case IPV4_DST:
+                return true;
+            default:
+                return false;
+        }
     }
 
     @Override
     public boolean isExact(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
+        if (!field.arePrerequisitesOK(this))
+            return false;
+
+        switch (field.id) {
+            case IN_PORT:
+                return (this.wildcards & OFPFW_IN_PORT) == 0;
+            case ETH_DST:
+                return (this.wildcards & OFPFW_DL_DST) == 0;
+            case ETH_SRC:
+                return (this.wildcards & OFPFW_DL_SRC) == 0;
+            case ETH_TYPE:
+                return (this.wildcards & OFPFW_DL_TYPE) == 0;
+            case VLAN_VID:
+                return (this.wildcards & OFPFW_DL_VLAN) == 0;
+            case VLAN_PCP:
+                return (this.wildcards & OFPFW_DL_VLAN_PCP) == 0;
+            case IP_DSCP:
+                return (this.wildcards & OFPFW_NW_TOS) == 0;
+            case IP_PROTO:
+                return (this.wildcards & OFPFW_NW_PROTO) == 0;
+            case IPV4_SRC:
+                return this.getIpv4SrcCidrMaskLen() >= 32;
+            case IPV4_DST:
+                return this.getIpv4DstCidrMaskLen() >= 32;
+            case TCP_SRC:
+                return (this.wildcards & OFPFW_TP_SRC) == 0;
+            case TCP_DST:
+                return (this.wildcards & OFPFW_TP_DST) == 0;
+            case UDP_SRC:
+                return (this.wildcards & OFPFW_TP_SRC) == 0;
+            case UDP_DST:
+                return (this.wildcards & OFPFW_TP_DST) == 0;
+            case SCTP_SRC:
+                return (this.wildcards & OFPFW_TP_SRC) == 0;
+            case SCTP_DST:
+                return (this.wildcards & OFPFW_TP_DST) == 0;
+            case ICMPV4_TYPE:
+                return (this.wildcards & OFPFW_TP_SRC) == 0;
+            case ICMPV4_CODE:
+                return (this.wildcards & OFPFW_TP_DST) == 0;
+            default:
+                throw new UnsupportedOperationException("OFMatch does not support matching on field " + field.getName());
+        }
     }
 
+    /**
+     * Parse this match's wildcard fields and return the number of significant
+     * bits in the IP destination field. NOTE: this returns the number of bits
+     * that are fixed, i.e., like CIDR, not the number of bits that are free
+     * like OpenFlow encodes.
+     *
+     * @return A number between 0 (matches all IPs) and 32 (exact match)
+     */
+    public int getIpv4DstCidrMaskLen() {
+        return Math.max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT),
+                        0);
+    }
+
+    /**
+     * Parse this match's wildcard fields and return the number of significant
+     * bits in the IP destination field. NOTE: this returns the number of bits
+     * that are fixed, i.e., like CIDR, not the number of bits that are free
+     * like OpenFlow encodes.
+     *
+     * @return A number between 0 (matches all IPs) and 32 (exact match)
+     */
+    public int getIpv4SrcCidrMaskLen() {
+        return Math.max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT),
+                        0);
+    }
+
+
     @Override
     public boolean isFullyWildcarded(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
+        if (!field.arePrerequisitesOK(this))
+            return true;
+
+        switch (field.id) {
+            case IN_PORT:
+                return (this.wildcards & OFPFW_IN_PORT) != 0;
+            case ETH_DST:
+                return (this.wildcards & OFPFW_DL_DST) != 0;
+            case ETH_SRC:
+                return (this.wildcards & OFPFW_DL_SRC) != 0;
+            case ETH_TYPE:
+                return (this.wildcards & OFPFW_DL_TYPE) != 0;
+            case VLAN_VID:
+                return (this.wildcards & OFPFW_DL_VLAN) != 0;
+            case VLAN_PCP:
+                return (this.wildcards & OFPFW_DL_VLAN_PCP) != 0;
+            case IP_DSCP:
+                return (this.wildcards & OFPFW_NW_TOS) != 0;
+            case IP_PROTO:
+                return (this.wildcards & OFPFW_NW_PROTO) != 0;
+            case TCP_SRC:
+                return (this.wildcards & OFPFW_TP_SRC) != 0;
+            case TCP_DST:
+                return (this.wildcards & OFPFW_TP_DST) != 0;
+            case UDP_SRC:
+                return (this.wildcards & OFPFW_TP_SRC) != 0;
+            case UDP_DST:
+                return (this.wildcards & OFPFW_TP_DST) != 0;
+            case SCTP_SRC:
+                return (this.wildcards & OFPFW_TP_SRC) != 0;
+            case SCTP_DST:
+                return (this.wildcards & OFPFW_TP_DST) != 0;
+            case ICMPV4_TYPE:
+                return (this.wildcards & OFPFW_TP_SRC) != 0;
+            case ICMPV4_CODE:
+                return (this.wildcards & OFPFW_TP_DST) != 0;
+            case IPV4_SRC:
+                return this.getIpv4SrcCidrMaskLen() <= 0;
+            case IPV4_DST:
+                return this.getIpv4DstCidrMaskLen() <= 0;
+            default:
+                throw new UnsupportedOperationException("OFMatch does not support matching on field " + field.getName());
+        }
     }
 
     @Override
     public boolean isPartiallyMasked(MatchField<?> field) {
-        // FIXME yotam - please replace with real implementation
-        return false;
+        if (!field.arePrerequisitesOK(this))
+            return false;
+
+        switch (field.id) {
+            case IPV4_SRC:
+                int srcCidrLen = getIpv4SrcCidrMaskLen();
+                return srcCidrLen > 0 && srcCidrLen < 32;
+            case IPV4_DST:
+                int dstCidrLen = getIpv4SrcCidrMaskLen();
+                return dstCidrLen > 0 && dstCidrLen < 32;
+            default:
+                throw new UnsupportedOperationException("OFMatch does not support masked matching on field " + field.getName());
+        }
     }
diff --git a/java_gen/templates/of_class.java b/java_gen/templates/of_class.java
index d03ffbf..aa68d04 100644
--- a/java_gen/templates/of_class.java
+++ b/java_gen/templates/of_class.java
@@ -47,7 +47,9 @@
 //:: #endif
 
 //:: for prop in msg.data_members:
-    private final static ${prop.java_type.public_type} ${prop.default_name} = ${prop.default_value};
+    //:: if prop.default_value:
+        private final static ${prop.java_type.public_type} ${prop.default_name} = ${prop.default_value};
+    //:: #endif
 //:: #end
 
     // OF message fields
@@ -97,13 +99,27 @@
 
 //:: include("_field_accessors.java", msg=msg, generate_setters=True, builder=True, has_parent=True)
 
+
         @Override
         public ${msg.interface.name} build() {
+                //:: for prop in msg.data_members:
+                ${prop.java_type.public_type} ${prop.name} = this.${prop.name}Set ? this.${prop.name} : parentMessage.${prop.name};
+                //::    if not prop.is_nullable and not prop.java_type.is_primitive:
+                if(${prop.name} == null)
+                    throw new NullPointerException("Property ${prop.name} must not be null");
+                //::    #endif
+                //:: #endfor
+
+                //
+                //:: if os.path.exists("%s/custom/%s.Builder_normalize_stanza.java" % (template_dir, msg.name)):
+                //:: include("custom/%s.Builder_normalize_stanza.java" % msg.name, msg=msg, has_parent=False)
+                //:: #endif
                 return new ${impl_class}(
-                    ${",\n                      ".join(
-                         [ "this.{0}Set ? this.{0} : parentMessage.{0}".format(prop.name)
-                             for prop in msg.data_members])}
-                    );
+                //:: for i, prop in enumerate(msg.data_members):
+                //::    comma = "," if i < len(msg.data_members)-1 else ""
+                    ${prop.name}${comma}
+                //:: #endfor
+                );
         }
         //:: if os.path.exists("%s/custom/%s.Builder.java" % (template_dir, msg.name)):
         //:: include("custom/%s.Builder.java" % msg.name, msg=msg, has_parent=True)
@@ -122,10 +138,28 @@
 //
         @Override
         public ${msg.interface.name} build() {
+            //:: for prop in msg.data_members:
+            //::    if prop.default_value:
+            ${prop.java_type.public_type} ${prop.name} = this.${prop.name}Set ? this.${prop.name} : ${prop.default_name};
+            //:: else:
+            if(!this.${prop.name}Set)
+                throw new IllegalStateException("Property ${prop.name} doesn't have default value -- must be set");
+            //::    #endif
+            //::    if not prop.is_nullable and not prop.java_type.is_primitive:
+            if(${prop.name} == null)
+                throw new NullPointerException("Property ${prop.name} must not be null");
+            //::    #endif
+            //:: #endfor
+
+            //:: if os.path.exists("%s/custom/%s.Builder_normalize_stanza.java" % (template_dir, msg.name)):
+            //:: include("custom/%s.Builder_normalize_stanza.java" % msg.name, msg=msg, has_parent=False)
+            //:: #endif
+
             return new ${impl_class}(
-                ${",\n                      ".join(
-                     [ "this.{0}Set ? this.{0} : {1}.{2}".format(prop.name, impl_class, prop.default_name)
-                         for prop in msg.data_members])}
+                //:: for i, prop in enumerate(msg.data_members):
+                //::    comma = "," if i < len(msg.data_members)-1 else ""
+                    ${prop.name}${comma}
+                //:: #endfor
                 );
         }
         //:: if os.path.exists("%s/custom/%s.Builder.java" % (template_dir, msg.name)):
@@ -190,7 +224,10 @@
             //:: #endif
 
             //:: if msg.data_members:
-            return new ${impl_class}(
+            //:: if os.path.exists("%s/custom/%s.Reader_normalize_stanza.java" % (template_dir, msg.name)):
+            //:: include("custom/%s.Reader_normalize_stanza.java" % msg.name, msg=msg, has_parent=False)
+            //:: #endif
+             return new ${impl_class}(
                     ${",\n                      ".join(
                          [ prop.name for prop in msg.data_members])}
                     );