import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@XmlElement
private String name;
+ /** The vlan. */
+ @XmlElement
+ private String dlVlan;
+
/** The network Source. */
@XmlElement
private String nwSrc;
public ContainerFlowConfig(String name, String srcIP, String dstIP, String proto, String srcPort,
String dstPort) {
this.name = name;
+ this.dlVlan = null;
this.nwSrc = srcIP;
this.nwDst = dstIP;
this.protocol = proto;
//this.unidirectional = false;
}
+ public ContainerFlowConfig(String name, String dlVlan, String srcIP, String dstIP, String proto, String srcPort,
+ String dstPort) {
+ this.name = name;
+ this.dlVlan = dlVlan;
+ this.nwSrc = srcIP;
+ this.nwDst = dstIP;
+ this.protocol = proto;
+ this.tpSrc = srcPort;
+ this.tpDst = dstPort;
+ }
+
public ContainerFlowConfig(ContainerFlowConfig containerFlowConfig) {
this.name = containerFlowConfig.name;
+ this.dlVlan = containerFlowConfig.dlVlan;
this.nwSrc = containerFlowConfig.nwSrc;
this.nwDst = containerFlowConfig.nwDst;
this.protocol = containerFlowConfig.protocol;
return name;
}
+ /**
+ * Returns the vlan id.
+ *
+ * @return the Vlan Id
+ */
+ public String getVlan() {
+ return (dlVlan == null || dlVlan.isEmpty()) ? null : dlVlan;
+ }
+
/**
* Returns the Source IP Address.
*
result = prime * result
+ ((protocol == null) ? 0 : protocol.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((dlVlan == null) ? 0 : dlVlan.hashCode());
result = prime * result + ((nwDst == null) ? 0 : nwDst.hashCode());
result = prime * result + ((tpDst == null) ? 0 : tpDst.hashCode());
result = prime * result + ((nwSrc == null) ? 0 : nwSrc.hashCode());
return false;
}
ContainerFlowConfig other = (ContainerFlowConfig) obj;
- if (matchName(other) && matchSrcIP(other)
+ if (matchName(other) && matchDlVlan(other) && matchSrcIP(other)
&& matchDstIP(other) && matchProtocol(other)
&& matchSrcPort(other) && matchDstPort(other)) {
return true;
return name.equals(flowSpec.name);
}
+ /**
+ * Match the set of these vlans with that of flowSpec's vlans.
+ *
+ * @param flowSpec
+ * Flow Specification
+ * @return true, if successful
+ */
+ private boolean matchDlVlan(ContainerFlowConfig flowSpec) {
+ if (dlVlan == flowSpec.dlVlan) {
+ return true;
+ }
+ if (dlVlan == null || flowSpec.dlVlan == null) {
+ return false;
+ }
+
+ return this.getVlanList().equals(flowSpec.getVlanList());
+ }
/**
* Match Source IP Address.
return this.tpDst.equals(flowSpec.tpDst);
}
+ /**
+ * Returns the vlan id number for all vlans specified
+ *
+ * @return the vlan id number for all vlans specified
+ */
+ public Set<Short> getVlanList() {
+ /*
+ * example: Vlan = "1,3,5-12"
+ * elemArray = ["1" "3" "5-12"]
+ * elem[2] = "5-12" --> limits = ["5" "12"]
+ * vlanList = [1 3 5 6 7 8 9 10 11 12]
+ */
+ Set<Short> vlanList = new HashSet<Short>();
+ try {
+ String[] elemArray = dlVlan.split(",");
+ for (String elem : elemArray) {
+ if (elem.contains("-")) {
+ String[] limits = elem.split("-");
+ for (short j = Short.valueOf(limits[0]); j <= Short.valueOf(limits[1]); j++) {
+ vlanList.add(Short.valueOf(j));
+ }
+ } else {
+ vlanList.add(Short.valueOf(elem));
+ }
+ }
+ } catch (NumberFormatException e) {
+
+ }
+ return vlanList;
+ }
+
/**
* Returns the Source IP Address mask length.
*
}
/**
- * Returns the protocol
+ * Get the IP protocol value
*
* @return the protocol
*/
public Short getProtoNum() {
- return protocol == null ? IPProtocols.ANY.shortValue() : IPProtocols.getProtocolNumberShort(protocol);
+ return protocol == null ? null : IPProtocols.getProtocolNumberShort(protocol);
}
/**
if (!hasValidName()) {
return new Status(StatusCode.BADREQUEST, "Invalid name");
}
- Status status = validateIPs();
+ Status status = validateVlan();
+ if (!status.isSuccess()) {
+ return status;
+ }
+ status = validateIPs();
if (!status.isSuccess()) {
return status;
}
if(!hasValidProtocol()) {
return new Status(StatusCode.BADREQUEST, "Invalid IP protocol");
}
+ if (!hasValidPorts()) {
+ return new Status(StatusCode.BADREQUEST, "Invalid Source or Destination Port");
+ }
if (this.getMatches().get(0).getMatches() == 0) {
return new Status(StatusCode.BADREQUEST, "Flow Spec is empty");
}
return (name != null && !name.isEmpty() && name.matches(regexName));
}
+ /**
+ * Validates the vlan number
+ *
+ * @return the result of the check as Status object
+ */
+ private Status validateVlan() {
+ if (dlVlan != null) {
+ short vlanId = 0;
+ try {
+ String[] elemArray = dlVlan.split(",");
+ for (String elem : elemArray) {
+ if (elem.contains("-")) {
+ String[] limits = elem.split("-");
+ if (Short.parseShort(limits[0]) < 0
+ || Short.parseShort(limits[0]) >= Short.parseShort(limits[1])
+ || Short.parseShort(limits[1]) > 0xfff) {
+ return new Status(StatusCode.BADREQUEST, "Invalid vlan id");
+ }
+ } else {
+ vlanId = Short.parseShort(elem);
+ if (vlanId < 0 || vlanId > 0xfff) {
+ return new Status(StatusCode.BADREQUEST, "Invalid vlan id");
+ }
+ }
+ }
+ } catch (NumberFormatException e) {
+ return new Status(StatusCode.BADREQUEST, "Invalid vlan id");
+ }
+ }
+ return new Status(StatusCode.SUCCESS);
+ }
+
/**
* Validates the network addresses, checks syntax and semantic
*
return new Status(StatusCode.SUCCESS);
}
+ /**
+ * Validate the protocol field. Either it can be a enum defined in IPProtocols.java
+ * or a valid IP proto value between 0 and 255, see:
+ * http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
+ * for more details.
+ *
+ * @return true if a valid protocol value
+ */
private boolean hasValidProtocol() {
- if (protocol != null && !protocol.isEmpty()) {
- return (this.getProtoNum() != 0 || protocol.equalsIgnoreCase("any"));
+ IPProtocols p = IPProtocols.fromString(protocol);
+ return p != null;
+ }
+
+ /**
+ *
+ * @param tpPort
+ * String representing the transport protocol port number
+ * @return true if tpPort contains a decimal value between 0 and 65535
+ */
+ private boolean hasValidPort(String tpPort) {
+ try {
+ int port = Integer.decode(tpPort);
+ return ((port >= 0) && (port <= 0xffff));
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Validate the transport protocol source and destination ports as
+ * entered by users.
+ *
+ * @return true if ports are defined and are in valid range
+ */
+ private boolean hasValidPorts() {
+ if (tpSrc !=null && !tpSrc.isEmpty()) {
+ if (!hasValidPort(tpSrc)) {
+ return false;
+ }
+ }
+
+ if (tpDst !=null && !tpDst.isEmpty()) {
+ return hasValidPort(tpDst);
}
return true;
}
+
/**
* Returns the matches.
- * If unidirectional flag is set, there will be only one match in the list
- * If unidirectional flag is unset there will be two matches in the list,
+ * If unidirectional flag is set, there will be only one match per vlan in the list
+ * If unidirectional flag is unset there will be two matches per vlan in the list,
* only if the specified flow has an intrinsic direction.
* For Ex. if the cFlow only has the protocol field configured, no matter
- * if unidirectional flag is set or not, only one match will be returned
+ * if unidirectional flag is set or not, only one match per vlan will be returned
* The client just has to iterate over the returned list
* @return the matches
*/
public List<Match> getMatches() {
List<Match> matches = new ArrayList<Match>();
+
+ if (this.dlVlan != null && !this.dlVlan.isEmpty()) {
+ for(Short vlan:getVlanList()){
+ Match match = getMatch(vlan);
+ matches.add(match);
+ }
+ }
+ else{
+ Match match = getMatch(null);
+ matches.add(match);
+ }
+
+ if (!ContainerFlowConfig.unidirectional) {
+ List<Match> forwardMatches = new ArrayList<Match>(matches);
+ for (Match match : forwardMatches) {
+ Match reverse = match.reverse();
+ if (!match.equals(reverse)) {
+ matches.add(reverse);
+ }
+ }
+ }
+
+ return matches;
+ }
+
+ private Match getMatch(Short vlan){
Match match = new Match();
+ if (vlan != null) {
+ match.setField(MatchType.DL_VLAN, vlan);
+ }
if (this.nwSrc != null && !this.nwSrc.trim().isEmpty()) {
String parts[] = this.nwSrc.split("/");
InetAddress ip = NetUtils.parseInetAddress(parts[0]);
mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
match.setField(MatchType.NW_DST, ip, mask);
}
- if (this.protocol != null && !this.protocol.trim().isEmpty() && !this.protocol.equalsIgnoreCase("any")) {
- match.setField(MatchType.NW_PROTO, IPProtocols
- .getProtocolNumberByte(this.protocol));
+ if (IPProtocols.fromString(this.protocol) != IPProtocols.ANY) {
+ match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(this.protocol));
}
if (this.tpSrc != null && !this.tpSrc.trim().isEmpty()) {
- Short srcPort = 0;
- try {
- srcPort = Short.parseShort(tpSrc);
- } catch (NumberFormatException e) {
- throw e;
- }
- match.setField(MatchType.TP_SRC, srcPort);
+ match.setField(MatchType.TP_SRC, Integer.valueOf(tpSrc).shortValue());
}
if (this.tpDst != null && !this.tpDst.trim().isEmpty()) {
- Short dstPort = 0;
- try {
- dstPort = Short.parseShort(tpDst);
- } catch (NumberFormatException e) {
- throw e;
- }
- match.setField(MatchType.TP_DST, dstPort);
- }
-
- matches.add(match);
- if(!ContainerFlowConfig.unidirectional) {
- Match reverse = match.reverse();
- if (!match.equals(reverse)) {
- matches.add(reverse);
- }
+ match.setField(MatchType.TP_DST, Integer.valueOf(tpDst).shortValue());
}
- return matches;
+ return match;
}
/*
*/
@Override
public String toString() {
- return "Container Flow={name:" + name + " nwSrc:" + nwSrc + " nwDst:" + nwDst + " " + "protocol:" + protocol
+ return "Container Flow={name:" + name + " dlVlan:" + dlVlan + " nwSrc:" + nwSrc + " nwDst:" + nwDst + " " + "protocol:" + protocol
+ " tpSrc:" + tpSrc + " tpDst:" + tpDst + "}";
}
}