/*
* Copyright (c) 2013 Big Switch Networks, Inc.
*
* Licensed under the Eclipse Public License, Version 1.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.sdnplatform.util;
import org.openflow.util.U32;
import org.sdnplatform.packet.IPv4;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IPV4Subnet implements Comparable<IPV4Subnet> {
protected static Logger logger = LoggerFactory.getLogger(IPV4Subnet.class);
public int address = 0;
/* The maskBits is number of prefix bits that are actually significant
* eg. maskBits = 24 translates to 255.255.255.0 or an inverted netmask of
* 0.0.0.255
*/
public short maskBits = 32;
public IPV4Subnet(int address, short maskBits) {
super();
this.address = address;
this.maskBits = checkMaskbits(maskBits);
}
public IPV4Subnet() {
super();
}
public IPV4Subnet(String subnet) {
String[] r = subnet.split("/");
try {
this.address = IPv4.toIPv4Address(r[0]);
if (r.length > 1) {
maskBits = Short.parseShort(r[1]);
}
} catch (Exception e) {
logger.error("Invalid IP subnet: " + subnet);
}
maskBits = checkMaskbits(maskBits);
}
/**
* Takes an inverted IP subnet mask and returns the masklen.
* eg. 0.0.0.255 and returns 24
* This is a basic bitcount function
* @param x The IP subnet mask
* @return The mask len
*/
public static short invertedMaskIpToLen(int x) {
x = ~x;
x = x - ((x >>> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >>> 2) & 0x33333333);
x = (x + (x >>> 4)) & 0x0f0f0f0f;
x = x + (x >>> 8);
x = x + (x >>> 16);
return (short) (x & 0x0000003f);
}
private short checkMaskbits(short mb) {
if (mb < 0) return 0;
if (mb > 32) return 32;
return mb;
}
/**
* Returns -1, 0, or +1 if this subnet is less than, equal or greater than the
* argument passed in. Should be an unsigned comparison where:
* - first we check which masked IP is greater
* eg. this = 192.168.2.0/24 > arg = 192.168.1.0/24
* eg. this = 192.0.0.0/8 > arg = 1.1.1.1/32
* - if masked integer values are equal then check for more specific masklengths
* eg. this = 192.168.2.0/25 > arg = 192.168.2.0/24
*/
@Override
public int compareTo(IPV4Subnet arg0) {
if (this == arg0) return 0;
this.maskBits = checkMaskbits(this.maskBits);
arg0.maskBits = checkMaskbits(arg0.maskBits);
long allfs = U32.f(~0);
Long v = U32.f( address & U32.t(~(allfs >> this.maskBits)) );
Long ov = U32.f( arg0.address & U32.t(~(allfs >> arg0.maskBits)) );
int c = v.compareTo(ov); // unsigned comparison by using longs
if (c == 0) {
if (this.maskBits < arg0.maskBits)
return -1;
else if (this.maskBits > arg0.maskBits)
return 1;
return 0;
}
return c;
}
/**
* Returns whether 'ip' is present in this IPV4 subnet
* @param ip The IP address to be checked
* @return true, if ip is present in this subnet
* false, otherwise
*/
public boolean contains(int ip) {
long allfs = U32.f(~0);
Long v = U32.f( address & U32.t(~(allfs >> maskBits)) );
Long ov = U32.f( ip & U32.t(~(allfs >> maskBits)) );
if (v.equals(ov)) {
return true;
} else {
return false;
}
}
}