blob: c4cb6bca85428e93b6b52c45f8c63c3d33e5bf31 [file] [log] [blame]
@SuppressWarnings("unchecked")
@Override
public <F extends OFValueType<F>> F get(MatchField<F> field)
throws UnsupportedOperationException {
if (isFullyWildcarded(field))
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 ARP_OP:
result = ArpOpcode.of(ipProto.getIpProtocolNumber());
break;
case ARP_SPA:
result = ipv4Src;
break;
case ARP_TPA:
result = ipv4Dst;
break;
case IP_DSCP:
result = ipDscp;
break;
case IP_PROTO:
result = ipProto;
break;
case IPV4_SRC:
result = ipv4Src;
break;
case IPV4_DST:
result = ipv4Dst;
break;
case TCP_SRC:
result = tcpSrc;
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 {
if (!isPartiallyMasked(field))
return null;
Object result;
switch (field.id) {
case IPV4_SRC:
case ARP_SPA:
int srcBitMask = (-1) << (32 - getIpv4SrcCidrMaskLen());
result = IPv4AddressWithMask.of(ipv4Src, IPv4Address.of(srcBitMask));
break;
case IPV4_DST:
case ARP_TPA:
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) {
switch (field.id) {
case IN_PORT:
case ETH_DST:
case ETH_SRC:
case ETH_TYPE:
case VLAN_VID:
case VLAN_PCP:
case ARP_OP:
case ARP_SPA:
case ARP_TPA:
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) {
switch (field.id) {
case ARP_SPA:
case ARP_TPA:
case IPV4_SRC:
case IPV4_DST:
return true;
default:
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 ARP_OP:
return (this.wildcards & OFPFW_NW_PROTO) == 0;
case ARP_SPA:
return this.getIpv4SrcCidrMaskLen() >= 32;
case ARP_TPA:
return this.getIpv4DstCidrMaskLen() >= 32;
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) {
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 ARP_OP:
return (this.wildcards & OFPFW_NW_PROTO) != 0;
case ARP_SPA:
return this.getIpv4SrcCidrMaskLen() <= 0;
case ARP_TPA:
return this.getIpv4DstCidrMaskLen() <= 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) {
switch (field.id) {
case ARP_SPA:
case IPV4_SRC:
int srcCidrLen = getIpv4SrcCidrMaskLen();
return srcCidrLen > 0 && srcCidrLen < 32;
case ARP_TPA:
case IPV4_DST:
int dstCidrLen = getIpv4DstCidrMaskLen();
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.of(((ICMPv4Code)value).getCode()));
wildcards &= ~OFPFW_TP_DST;
break;
case ICMPV4_TYPE:
setTcpSrc(TransportPort.of(((ICMPv4Type)value).getType()));
wildcards &= ~OFPFW_TP_SRC;
break;
case IN_PORT:
setInPort((OFPort) value);
wildcards &= ~OFPFW_IN_PORT;
break;
case ARP_OP:
setIpProto(IpProtocol.of((short)((ArpOpcode)value).getOpcode()));
wildcards &= ~OFPFW_NW_PROTO;
break;
case ARP_TPA:
case IPV4_DST:
setIpv4Dst((IPv4Address) value);
wildcards &= ~OFPFW_NW_DST_MASK;
break;
case ARP_SPA:
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((OFVlanVidMatch) value);
wildcards &= ~OFPFW_DL_VLAN;
break;
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 ARP_SPA:
case ARP_TPA:
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 ARP_TPA:
case IPV4_DST:
setIpv4Dst(ip);
wildcards = (wildcards &~OFPFW_NW_DST_MASK) | (maskLen << OFPFW_NW_DST_SHIFT);
break;
case ARP_SPA:
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.of(0)); // NOTE: not 'NONE' -- that is 0xFF for ports
wildcards |= OFPFW_IN_PORT;
break;
case ARP_TPA:
case IPV4_DST:
setIpv4Dst(IPv4Address.NONE);
wildcards |= OFPFW_NW_DST_MASK;
break;
case ARP_SPA:
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(OFVlanVidMatch.NONE);
wildcards |= OFPFW_DL_VLAN;
break;
default:
throw new UnsupportedOperationException("OFMatch does not support matching on field " + field.getName());
}
return this;
}