Add config validation for vRouter and PIM configs
Change-Id: I97ddf4f745a19df6998b15ae47ebde5aa5f46238
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PimInterfaceConfig.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PimInterfaceConfig.java
index 48969c3..63ceb36 100644
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PimInterfaceConfig.java
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PimInterfaceConfig.java
@@ -112,4 +112,20 @@
}
return Optional.of(Short.parseShort(node.path(OVERRIDE_INTERVAL).asText()));
}
+
+ @Override
+ public boolean isValid() {
+ if (!hasOnlyFields(INTERFACE_NAME, ENABLED, HELLO_INTERVAL, HOLD_TIME,
+ PRIORITY, PROPAGATION_DELAY, OVERRIDE_INTERVAL)) {
+ return false;
+ }
+
+ return isString(INTERFACE_NAME, FieldPresence.MANDATORY) &&
+ isBoolean(ENABLED, FieldPresence.MANDATORY) &&
+ isIntegralNumber(HELLO_INTERVAL, FieldPresence.OPTIONAL) &&
+ isIntegralNumber(HOLD_TIME, FieldPresence.OPTIONAL) &&
+ isIntegralNumber(PRIORITY, FieldPresence.OPTIONAL) &&
+ isIntegralNumber(PROPAGATION_DELAY, FieldPresence.OPTIONAL) &&
+ isIntegralNumber(OVERRIDE_INTERVAL, FieldPresence.OPTIONAL);
+ }
}
diff --git a/apps/routing-api/src/main/java/org/onosproject/routing/config/RouterConfig.java b/apps/routing-api/src/main/java/org/onosproject/routing/config/RouterConfig.java
index 9099019..dbd49ff 100644
--- a/apps/routing-api/src/main/java/org/onosproject/routing/config/RouterConfig.java
+++ b/apps/routing-api/src/main/java/org/onosproject/routing/config/RouterConfig.java
@@ -82,4 +82,19 @@
return interfaces;
}
+ @Override
+ public boolean isValid() {
+ if (!hasOnlyFields(INTERFACES, CP_CONNECT_POINT, OSPF_ENABLED, PIM_ENABLED)) {
+ return false;
+ }
+
+ JsonNode intfNode = object.path(INTERFACES);
+ if (!intfNode.isMissingNode() && !intfNode.isArray()) {
+ return false;
+ }
+
+ return isConnectPoint(CP_CONNECT_POINT, FieldPresence.MANDATORY) &&
+ isBoolean(OSPF_ENABLED, FieldPresence.OPTIONAL) &&
+ isBoolean(PIM_ENABLED, FieldPresence.OPTIONAL);
+ }
}
diff --git a/core/api/src/main/java/org/onosproject/net/config/Config.java b/core/api/src/main/java/org/onosproject/net/config/Config.java
index 0119e07..e287538 100644
--- a/core/api/src/main/java/org/onosproject/net/config/Config.java
+++ b/core/api/src/main/java/org/onosproject/net/config/Config.java
@@ -24,7 +24,9 @@
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
+import org.onosproject.net.ConnectPoint;
import java.util.Collection;
import java.util.List;
@@ -46,6 +48,9 @@
@Beta
public abstract class Config<S> {
+ private static final String TRUE_LITERAL = "true";
+ private static final String FALSE_LITERAL = "false";
+
protected S subject;
protected String key;
@@ -111,6 +116,8 @@
// isDecimal(path, [min, max])
// isMacAddress(path)
// isIpAddress(path)
+ // isIpPrefix(path)
+ // isConnectPoint(path)
return true;
}
@@ -424,6 +431,22 @@
}
/**
+ * Indicates whether the specified field of a particular node holds a valid
+ * MAC address.
+ *
+ * @param objectNode JSON node
+ * @param field JSON field name
+ * @param presence specifies if field is optional or mandatory
+ * @return true if valid; false otherwise
+ * @throws IllegalArgumentException if field is present, but not valid MAC
+ */
+ protected boolean isMacAddress(ObjectNode objectNode, String field, FieldPresence presence) {
+ JsonNode node = objectNode.path(field);
+ return isValid(node, presence, node.isTextual() &&
+ MacAddress.valueOf(node.asText()) != null);
+ }
+
+ /**
* Indicates whether the specified field holds a valid IP address.
*
* @param field JSON field name
@@ -439,16 +462,76 @@
* Indicates whether the specified field of a particular node holds a valid
* IP address.
*
- * @param node node from whom to access the field
+ * @param objectNode node from whom to access the field
* @param field JSON field name
* @param presence specifies if field is optional or mandatory
* @return true if valid; false otherwise
* @throws IllegalArgumentException if field is present, but not valid IP
*/
- protected boolean isIpAddress(ObjectNode node, String field, FieldPresence presence) {
- JsonNode innerNode = node.path(field);
- return isValid(innerNode, presence, innerNode.isTextual() &&
- IpAddress.valueOf(innerNode.asText()) != null);
+ protected boolean isIpAddress(ObjectNode objectNode, String field, FieldPresence presence) {
+ JsonNode node = objectNode.path(field);
+ return isValid(node, presence, node.isTextual() &&
+ IpAddress.valueOf(node.asText()) != null);
+ }
+
+ /**
+ * Indicates whether the specified field holds a valid IP prefix.
+ *
+ * @param field JSON field name
+ * @param presence specifies if field is optional or mandatory
+ * @return true if valid; false otherwise
+ * @throws IllegalArgumentException if field is present, but not valid IP
+ * prefix
+ */
+ protected boolean isIpPrefix(String field, FieldPresence presence) {
+ return isIpPrefix(object, field, presence);
+ }
+
+ /**
+ * Indicates whether the specified field of a particular node holds a valid
+ * IP prefix.
+ *
+ * @param objectNode node from whom to access the field
+ * @param field JSON field name
+ * @param presence specifies if field is optional or mandatory
+ * @return true if valid; false otherwise
+ * @throws IllegalArgumentException if field is present, but not valid IP
+ * prefix
+ */
+ protected boolean isIpPrefix(ObjectNode objectNode, String field, FieldPresence presence) {
+ JsonNode node = objectNode.path(field);
+ return isValid(node, presence, node.isTextual() &&
+ IpPrefix.valueOf(node.asText()) != null);
+ }
+
+ /**
+ * Indicates whether the specified field holds a valid connect point string.
+ *
+ * @param field JSON field name
+ * @param presence specifies if field is optional or mandatory
+ * @return true if valid; false otherwise
+ * @throws IllegalArgumentException if field is present, but not valid
+ * connect point string representation
+ */
+ protected boolean isConnectPoint(String field, FieldPresence presence) {
+ return isConnectPoint(object, field, presence);
+ }
+
+ /**
+ * Indicates whether the specified field of a particular node holds a valid
+ * connect point string.
+ *
+ * @param objectNode JSON node
+ * @param field JSON field name
+ * @param presence specifies if field is optional or mandatory
+ * @return true if valid; false otherwise
+ * @throws IllegalArgumentException if field is present, but not valid
+ * connect point string representation
+ */
+ protected boolean isConnectPoint(ObjectNode objectNode, String field, FieldPresence presence) {
+ JsonNode node = objectNode.path(field);
+ return isValid(node, presence, node.isTextual() &&
+ ConnectPoint.deviceConnectPoint(node.asText()) != null);
}
/**
@@ -458,10 +541,26 @@
* @param presence specifies if field is optional or mandatory
* @param pattern optional regex pattern
* @return true if valid; false otherwise
- * @throws IllegalArgumentException if field is present, but not valid MAC
+ * @throws IllegalArgumentException if field is present, but not valid string
*/
protected boolean isString(String field, FieldPresence presence, String... pattern) {
- JsonNode node = object.path(field);
+ return isString(object, field, presence, pattern);
+ }
+
+ /**
+ * Indicates whether the specified field on a particular node holds a valid
+ * string value.
+ *
+ * @param objectNode JSON node
+ * @param field JSON field name
+ * @param presence specifies if field is optional or mandatory
+ * @param pattern optional regex pattern
+ * @return true if valid; false otherwise
+ * @throws IllegalArgumentException if field is present, but not valid string
+ */
+ protected boolean isString(ObjectNode objectNode, String field,
+ FieldPresence presence, String... pattern) {
+ JsonNode node = objectNode.path(field);
return isValid(node, presence, node.isTextual() &&
(pattern.length > 0 && node.asText().matches(pattern[0]) || pattern.length < 1));
}
@@ -507,10 +606,29 @@
* @throws IllegalArgumentException if field is present, but not valid
*/
protected boolean isIntegralNumber(String field, FieldPresence presence, long... minMax) {
- JsonNode node = object.path(field);
- return isValid(node, presence, node.isIntegralNumber() &&
- (minMax.length > 0 && minMax[0] <= node.asLong() || minMax.length < 1) &&
- (minMax.length > 1 && minMax[1] > node.asLong() || minMax.length < 2));
+ return isIntegralNumber(object, field, presence, minMax);
+ }
+
+ /**
+ * Indicates whether the specified field of a particular node holds a valid
+ * integer.
+ *
+ * @param objectNode JSON node
+ * @param field JSON field name
+ * @param presence specifies if field is optional or mandatory
+ * @param minMax optional min/max values
+ * @return true if valid; false otherwise
+ * @throws IllegalArgumentException if field is present, but not valid
+ */
+ protected boolean isIntegralNumber(ObjectNode objectNode, String field,
+ FieldPresence presence, long... minMax) {
+ JsonNode node = objectNode.path(field);
+
+ return isValid(node, presence, n -> {
+ long number = (node.isIntegralNumber()) ? n.asLong() : Long.parseLong(n.asText());
+ return (minMax.length > 0 && minMax[0] <= number || minMax.length < 1) &&
+ (minMax.length > 1 && minMax[1] > number || minMax.length < 2);
+ });
}
/**
@@ -535,11 +653,35 @@
* @param field JSON field name
* @param presence specifies if field is optional or mandatory
* @return true if valid; false otherwise
- * @throws IllegalArgumentException if field is present, but not valid
*/
protected boolean isBoolean(String field, FieldPresence presence) {
- JsonNode node = object.path(field);
- return isValid(node, presence, node.isBoolean());
+ return isBoolean(object, field, presence);
+ }
+
+ /**
+ * Indicates whether the specified field of a particular node holds a valid
+ * boolean value.
+ *
+ * @param objectNode JSON object node
+ * @param field JSON field name
+ * @param presence specifies if field is optional or mandatory
+ * @return true if valid; false otherwise
+ */
+ protected boolean isBoolean(ObjectNode objectNode, String field, FieldPresence presence) {
+ JsonNode node = objectNode.path(field);
+ return isValid(node, presence, node.isBoolean() ||
+ (node.isTextual() && isBooleanString(node.asText())));
+ }
+
+ /**
+ * Indicates whether a string holds a boolean literal value.
+ *
+ * @param str string to test
+ * @return true if the string contains "true" or "false" (case insensitive),
+ * otherwise false
+ */
+ private boolean isBooleanString(String str) {
+ return str.equalsIgnoreCase(TRUE_LITERAL) || str.equalsIgnoreCase(FALSE_LITERAL);
}
/**
@@ -552,7 +694,30 @@
* @return true if the field is as expected
*/
private boolean isValid(JsonNode node, FieldPresence presence, boolean correctValue) {
+ return isValid(node, presence, n -> correctValue);
+ }
+
+ /**
+ * Indicates whether the node is present and of correct value or not
+ * mandatory and absent.
+ *
+ * @param node JSON node
+ * @param presence specified if field is optional or mandatory
+ * @param validationFunction function which can be used to verify if the
+ * node has the correct value
+ * @return true if the field is as expected
+ */
+ private boolean isValid(JsonNode node, FieldPresence presence,
+ Function<JsonNode, Boolean> validationFunction) {
boolean isMandatory = presence == FieldPresence.MANDATORY;
- return isMandatory && correctValue || !isMandatory && !node.isNull() || correctValue;
+ if (isMandatory && validationFunction.apply(node)) {
+ return true;
+ }
+
+ if (!isMandatory && (node.isNull() || node.isMissingNode())) {
+ return true;
+ }
+
+ return validationFunction.apply(node);
}
}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java b/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java
index 8d938ba..8903521 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java
@@ -22,6 +22,7 @@
import com.google.common.annotations.Beta;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.incubator.net.intf.Interface;
@@ -50,6 +51,31 @@
private static final String INTF_NULL_ERROR = "Interface cannot be null";
private static final String INTF_NAME_ERROR = "Interface must have a valid name";
+ @Override
+ public boolean isValid() {
+ for (JsonNode node : array) {
+ if (!hasOnlyFields((ObjectNode) node, NAME, IPS, MAC, VLAN)) {
+ return false;
+ }
+
+ ObjectNode obj = (ObjectNode) node;
+
+ if (!(isString(obj, NAME, FieldPresence.OPTIONAL) &&
+ isMacAddress(obj, MAC, FieldPresence.OPTIONAL) &&
+ isIntegralNumber(obj, VLAN, FieldPresence.OPTIONAL, 0, VlanId.MAX_VLAN))) {
+ return false;
+ }
+
+
+ for (JsonNode ipNode : node.path(IPS)) {
+ if (!ipNode.isTextual() || IpPrefix.valueOf(ipNode.asText()) == null) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
/**
* Retrieves all interfaces configured on this port.
*